• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **********************************************************************
3 *   Copyright (C) 2008-2013, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 **********************************************************************
6 */
7 
8 #include "unicode/utypes.h"
9 #include "unicode/uspoof.h"
10 #include "unicode/uchar.h"
11 #include "unicode/uniset.h"
12 #include "unicode/utf16.h"
13 #include "utrie2.h"
14 #include "cmemory.h"
15 #include "cstring.h"
16 #include "identifier_info.h"
17 #include "scriptset.h"
18 #include "udatamem.h"
19 #include "umutex.h"
20 #include "udataswp.h"
21 #include "uassert.h"
22 #include "uspoof_impl.h"
23 
24 #if !UCONFIG_NO_NORMALIZATION
25 
26 
27 U_NAMESPACE_BEGIN
28 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)29 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)
30 
31 SpoofImpl::SpoofImpl(SpoofData *data, UErrorCode &status) :
32         fMagic(0), fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) ,
33         fAllowedLocales(NULL), fCachedIdentifierInfo(NULL) {
34     if (U_FAILURE(status)) {
35         return;
36     }
37     fSpoofData = data;
38     fRestrictionLevel = USPOOF_HIGHLY_RESTRICTIVE;
39 
40     UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
41     allowedCharsSet->freeze();
42     fAllowedCharsSet = allowedCharsSet;
43     fAllowedLocales  = uprv_strdup("");
44     if (fAllowedCharsSet == NULL || fAllowedLocales == NULL) {
45         status = U_MEMORY_ALLOCATION_ERROR;
46         return;
47     }
48     fMagic = USPOOF_MAGIC;
49 }
50 
51 
SpoofImpl()52 SpoofImpl::SpoofImpl() :
53         fMagic(USPOOF_MAGIC), fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) ,
54         fAllowedLocales(NULL), fCachedIdentifierInfo(NULL) {
55     UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
56     allowedCharsSet->freeze();
57     fAllowedCharsSet = allowedCharsSet;
58     fAllowedLocales  = uprv_strdup("");
59     fRestrictionLevel = USPOOF_HIGHLY_RESTRICTIVE;
60 }
61 
62 
63 // Copy Constructor, used by the user level clone() function.
SpoofImpl(const SpoofImpl & src,UErrorCode & status)64 SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status)  :
65         fMagic(0), fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) ,
66         fAllowedLocales(NULL), fCachedIdentifierInfo(NULL) {
67     if (U_FAILURE(status)) {
68         return;
69     }
70     fMagic = src.fMagic;
71     fChecks = src.fChecks;
72     if (src.fSpoofData != NULL) {
73         fSpoofData = src.fSpoofData->addReference();
74     }
75     fAllowedCharsSet = static_cast<const UnicodeSet *>(src.fAllowedCharsSet->clone());
76     if (fAllowedCharsSet == NULL) {
77         status = U_MEMORY_ALLOCATION_ERROR;
78     }
79     fAllowedLocales = uprv_strdup(src.fAllowedLocales);
80     fRestrictionLevel = src.fRestrictionLevel;
81 }
82 
~SpoofImpl()83 SpoofImpl::~SpoofImpl() {
84     fMagic = 0;                // head off application errors by preventing use of
85                                //    of deleted objects.
86     if (fSpoofData != NULL) {
87         fSpoofData->removeReference();   // Will delete if refCount goes to zero.
88     }
89     delete fAllowedCharsSet;
90     uprv_free((void *)fAllowedLocales);
91     delete fCachedIdentifierInfo;
92 }
93 
94 //
95 //  Incoming parameter check on Status and the SpoofChecker object
96 //    received from the C API.
97 //
validateThis(const USpoofChecker * sc,UErrorCode & status)98 const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) {
99     if (U_FAILURE(status)) {
100         return NULL;
101     }
102     if (sc == NULL) {
103         status = U_ILLEGAL_ARGUMENT_ERROR;
104         return NULL;
105     }
106     SpoofImpl *This = (SpoofImpl *)sc;
107     if (This->fMagic != USPOOF_MAGIC ||
108         This->fSpoofData == NULL) {
109         status = U_INVALID_FORMAT_ERROR;
110         return NULL;
111     }
112     if (!SpoofData::validateDataVersion(This->fSpoofData->fRawData, status)) {
113         return NULL;
114     }
115     return This;
116 }
117 
validateThis(USpoofChecker * sc,UErrorCode & status)118 SpoofImpl *SpoofImpl::validateThis(USpoofChecker *sc, UErrorCode &status) {
119     return const_cast<SpoofImpl *>
120         (SpoofImpl::validateThis(const_cast<const USpoofChecker *>(sc), status));
121 }
122 
123 
124 
125 //--------------------------------------------------------------------------------------
126 //
127 //  confusableLookup()    This is the heart of the confusable skeleton generation
128 //                        implementation.
129 //
130 //                        Given a source character, produce the corresponding
131 //                        replacement character(s), appending them to the dest string.
132 //
133 //---------------------------------------------------------------------------------------
confusableLookup(UChar32 inChar,int32_t tableMask,UnicodeString & dest) const134 int32_t SpoofImpl::confusableLookup(UChar32 inChar, int32_t tableMask, UnicodeString &dest) const {
135 
136     // Binary search the spoof data key table for the inChar
137     int32_t  *low   = fSpoofData->fCFUKeys;
138     int32_t  *mid   = NULL;
139     int32_t  *limit = low + fSpoofData->fRawData->fCFUKeysSize;
140     UChar32   midc;
141     do {
142         int32_t delta = ((int32_t)(limit-low))/2;
143         mid = low + delta;
144         midc = *mid & 0x1fffff;
145         if (inChar == midc) {
146             goto foundChar;
147         } else if (inChar < midc) {
148             limit = mid;
149         } else {
150             low = mid;
151         }
152     } while (low < limit-1);
153     mid = low;
154     midc = *mid & 0x1fffff;
155     if (inChar != midc) {
156         // Char not found.  It maps to itself.
157         int i = 0;
158         dest.append(inChar);
159         return i;
160     }
161   foundChar:
162     int32_t keyFlags = *mid & 0xff000000;
163     if ((keyFlags & tableMask) == 0) {
164         // We found the right key char, but the entry doesn't pertain to the
165         //  table we need.  See if there is an adjacent key that does
166         if (keyFlags & USPOOF_KEY_MULTIPLE_VALUES) {
167             int32_t *altMid;
168             for (altMid = mid-1; (*altMid&0x00ffffff) == inChar; altMid--) {
169                 keyFlags = *altMid & 0xff000000;
170                 if (keyFlags & tableMask) {
171                     mid = altMid;
172                     goto foundKey;
173                 }
174             }
175             for (altMid = mid+1; (*altMid&0x00ffffff) == inChar; altMid++) {
176                 keyFlags = *altMid & 0xff000000;
177                 if (keyFlags & tableMask) {
178                     mid = altMid;
179                     goto foundKey;
180                 }
181             }
182         }
183         // No key entry for this char & table.
184         // The input char maps to itself.
185         int i = 0;
186         dest.append(inChar);
187         return i;
188     }
189 
190   foundKey:
191     int32_t  stringLen = USPOOF_KEY_LENGTH_FIELD(keyFlags) + 1;
192     int32_t keyTableIndex = (int32_t)(mid - fSpoofData->fCFUKeys);
193 
194     // Value is either a UChar  (for strings of length 1) or
195     //                 an index into the string table (for longer strings)
196     uint16_t value = fSpoofData->fCFUValues[keyTableIndex];
197     if (stringLen == 1) {
198         dest.append((UChar)value);
199         return 1;
200     }
201 
202     // String length of 4 from the above lookup is used for all strings of length >= 4.
203     // For these, get the real length from the string lengths table,
204     //   which maps string table indexes to lengths.
205     //   All strings of the same length are stored contiguously in the string table.
206     //   'value' from the lookup above is the starting index for the desired string.
207 
208     int32_t ix;
209     if (stringLen == 4) {
210         int32_t stringLengthsLimit = fSpoofData->fRawData->fCFUStringLengthsSize;
211         for (ix = 0; ix < stringLengthsLimit; ix++) {
212             if (fSpoofData->fCFUStringLengths[ix].fLastString >= value) {
213                 stringLen = fSpoofData->fCFUStringLengths[ix].fStrLength;
214                 break;
215             }
216         }
217         U_ASSERT(ix < stringLengthsLimit);
218     }
219 
220     U_ASSERT(value + stringLen <= fSpoofData->fRawData->fCFUStringTableLen);
221     UChar *src = &fSpoofData->fCFUStrings[value];
222     dest.append(src, stringLen);
223     return stringLen;
224 }
225 
226 
227 //---------------------------------------------------------------------------------------
228 //
229 //  wholeScriptCheck()
230 //
231 //      Input text is already normalized to NFD
232 //      Return the set of scripts, each of which can represent something that is
233 //             confusable with the input text.  The script of the input text
234 //             is included; input consisting of characters from a single script will
235 //             always produce a result consisting of a set containing that script.
236 //
237 //---------------------------------------------------------------------------------------
wholeScriptCheck(const UnicodeString & text,ScriptSet * result,UErrorCode & status) const238 void SpoofImpl::wholeScriptCheck(
239         const UnicodeString &text, ScriptSet *result, UErrorCode &status) const {
240 
241     UTrie2 *table =
242         (fChecks & USPOOF_ANY_CASE) ? fSpoofData->fAnyCaseTrie : fSpoofData->fLowerCaseTrie;
243     result->setAll();
244     int32_t length = text.length();
245     for (int32_t inputIdx=0; inputIdx < length;) {
246         UChar32 c = text.char32At(inputIdx);
247         inputIdx += U16_LENGTH(c);
248         uint32_t index = utrie2_get32(table, c);
249         if (index == 0) {
250             // No confusables in another script for this char.
251             // TODO:  we should change the data to have sets with just the single script
252             //        bit for the script of this char.  Gets rid of this special case.
253             //        Until then, grab the script from the char and intersect it with the set.
254             UScriptCode cpScript = uscript_getScript(c, &status);
255             U_ASSERT(cpScript > USCRIPT_INHERITED);
256             result->intersect(cpScript, status);
257         } else if (index == 1) {
258             // Script == Common or Inherited.  Nothing to do.
259         } else {
260             result->intersect(fSpoofData->fScriptSets[index]);
261         }
262     }
263 }
264 
265 
setAllowedLocales(const char * localesList,UErrorCode & status)266 void SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) {
267     UnicodeSet    allowedChars;
268     UnicodeSet    *tmpSet = NULL;
269     const char    *locStart = localesList;
270     const char    *locEnd = NULL;
271     const char    *localesListEnd = localesList + uprv_strlen(localesList);
272     int32_t        localeListCount = 0;   // Number of locales provided by caller.
273 
274     // Loop runs once per locale from the localesList, a comma separated list of locales.
275     do {
276         locEnd = uprv_strchr(locStart, ',');
277         if (locEnd == NULL) {
278             locEnd = localesListEnd;
279         }
280         while (*locStart == ' ') {
281             locStart++;
282         }
283         const char *trimmedEnd = locEnd-1;
284         while (trimmedEnd > locStart && *trimmedEnd == ' ') {
285             trimmedEnd--;
286         }
287         if (trimmedEnd <= locStart) {
288             break;
289         }
290         const char *locale = uprv_strndup(locStart, (int32_t)(trimmedEnd + 1 - locStart));
291         localeListCount++;
292 
293         // We have one locale from the locales list.
294         // Add the script chars for this locale to the accumulating set of allowed chars.
295         // If the locale is no good, we will be notified back via status.
296         addScriptChars(locale, &allowedChars, status);
297         uprv_free((void *)locale);
298         if (U_FAILURE(status)) {
299             break;
300         }
301         locStart = locEnd + 1;
302     } while (locStart < localesListEnd);
303 
304     // If our caller provided an empty list of locales, we disable the allowed characters checking
305     if (localeListCount == 0) {
306         uprv_free((void *)fAllowedLocales);
307         fAllowedLocales = uprv_strdup("");
308         tmpSet = new UnicodeSet(0, 0x10ffff);
309         if (fAllowedLocales == NULL || tmpSet == NULL) {
310             status = U_MEMORY_ALLOCATION_ERROR;
311             return;
312         }
313         tmpSet->freeze();
314         delete fAllowedCharsSet;
315         fAllowedCharsSet = tmpSet;
316         fChecks &= ~USPOOF_CHAR_LIMIT;
317         return;
318     }
319 
320 
321     // Add all common and inherited characters to the set of allowed chars.
322     UnicodeSet tempSet;
323     tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_COMMON, status);
324     allowedChars.addAll(tempSet);
325     tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_INHERITED, status);
326     allowedChars.addAll(tempSet);
327 
328     // If anything went wrong, we bail out without changing
329     // the state of the spoof checker.
330     if (U_FAILURE(status)) {
331         return;
332     }
333 
334     // Store the updated spoof checker state.
335     tmpSet = static_cast<UnicodeSet *>(allowedChars.clone());
336     const char *tmpLocalesList = uprv_strdup(localesList);
337     if (tmpSet == NULL || tmpLocalesList == NULL) {
338         status = U_MEMORY_ALLOCATION_ERROR;
339         return;
340     }
341     uprv_free((void *)fAllowedLocales);
342     fAllowedLocales = tmpLocalesList;
343     tmpSet->freeze();
344     delete fAllowedCharsSet;
345     fAllowedCharsSet = tmpSet;
346     fChecks |= USPOOF_CHAR_LIMIT;
347 }
348 
349 
getAllowedLocales(UErrorCode &)350 const char * SpoofImpl::getAllowedLocales(UErrorCode &/*status*/) {
351     return fAllowedLocales;
352 }
353 
354 
355 // Given a locale (a language), add all the characters from all of the scripts used with that language
356 // to the allowedChars UnicodeSet
357 
addScriptChars(const char * locale,UnicodeSet * allowedChars,UErrorCode & status)358 void SpoofImpl::addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status) {
359     UScriptCode scripts[30];
360 
361     int32_t numScripts = uscript_getCode(locale, scripts, sizeof(scripts)/sizeof(UScriptCode), &status);
362     if (U_FAILURE(status)) {
363         return;
364     }
365     if (status == U_USING_DEFAULT_WARNING) {
366         status = U_ILLEGAL_ARGUMENT_ERROR;
367         return;
368     }
369     UnicodeSet tmpSet;
370     int32_t    i;
371     for (i=0; i<numScripts; i++) {
372         tmpSet.applyIntPropertyValue(UCHAR_SCRIPT, scripts[i], status);
373         allowedChars->addAll(tmpSet);
374     }
375 }
376 
377 
378 // Convert a text format hex number.  Utility function used by builder code.  Static.
379 // Input: UChar *string text.  Output: a UChar32
380 // Input has been pre-checked, and will have no non-hex chars.
381 // The number must fall in the code point range of 0..0x10ffff
382 // Static Function.
ScanHex(const UChar * s,int32_t start,int32_t limit,UErrorCode & status)383 UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status) {
384     if (U_FAILURE(status)) {
385         return 0;
386     }
387     U_ASSERT(limit-start > 0);
388     uint32_t val = 0;
389     int i;
390     for (i=start; i<limit; i++) {
391         int digitVal = s[i] - 0x30;
392         if (digitVal>9) {
393             digitVal = 0xa + (s[i] - 0x41);  // Upper Case 'A'
394         }
395         if (digitVal>15) {
396             digitVal = 0xa + (s[i] - 0x61);  // Lower Case 'a'
397         }
398         U_ASSERT(digitVal <= 0xf);
399         val <<= 4;
400         val += digitVal;
401     }
402     if (val > 0x10ffff) {
403         status = U_PARSE_ERROR;
404         val = 0;
405     }
406     return (UChar32)val;
407 }
408 
409 // IdentifierInfo Cache. IdentifierInfo objects are somewhat expensive to create.
410 //                       Maintain a one-element cache, which is sufficient to avoid repeatedly
411 //                       creating new ones unless we get multi-thread concurrency in spoof
412 //                       check operations, which should be statistically uncommon.
413 
414 // These functions are used in place of new & delete of an IdentifierInfo.
415 // They will recycle the IdentifierInfo when possible.
416 // They are logically const, and used within const functions that must be thread safe.
getIdentifierInfo(UErrorCode & status) const417 IdentifierInfo *SpoofImpl::getIdentifierInfo(UErrorCode &status) const {
418     IdentifierInfo *returnIdInfo = NULL;
419     if (U_FAILURE(status)) {
420         return returnIdInfo;
421     }
422     SpoofImpl *nonConstThis = const_cast<SpoofImpl *>(this);
423     {
424         Mutex m;
425         returnIdInfo = nonConstThis->fCachedIdentifierInfo;
426         nonConstThis->fCachedIdentifierInfo = NULL;
427     }
428     if (returnIdInfo == NULL) {
429         returnIdInfo = new IdentifierInfo(status);
430         if (U_SUCCESS(status) && returnIdInfo == NULL) {
431             status = U_MEMORY_ALLOCATION_ERROR;
432         }
433         if (U_FAILURE(status) && returnIdInfo != NULL) {
434             delete returnIdInfo;
435             returnIdInfo = NULL;
436         }
437     }
438     return returnIdInfo;
439 }
440 
441 
releaseIdentifierInfo(IdentifierInfo * idInfo) const442 void SpoofImpl::releaseIdentifierInfo(IdentifierInfo *idInfo) const {
443     if (idInfo != NULL) {
444         SpoofImpl *nonConstThis = const_cast<SpoofImpl *>(this);
445         {
446             Mutex m;
447             if (nonConstThis->fCachedIdentifierInfo == NULL) {
448                 nonConstThis->fCachedIdentifierInfo = idInfo;
449                 idInfo = NULL;
450             }
451         }
452         delete idInfo;
453     }
454 }
455 
456 
457 
458 
459 //----------------------------------------------------------------------------------------------
460 //
461 //   class SpoofData Implementation
462 //
463 //----------------------------------------------------------------------------------------------
464 
465 
validateDataVersion(const SpoofDataHeader * rawData,UErrorCode & status)466 UBool SpoofData::validateDataVersion(const SpoofDataHeader *rawData, UErrorCode &status) {
467     if (U_FAILURE(status) ||
468         rawData == NULL ||
469         rawData->fMagic != USPOOF_MAGIC ||
470         rawData->fFormatVersion[0] > 1 ||
471         rawData->fFormatVersion[1] > 0) {
472             status = U_INVALID_FORMAT_ERROR;
473             return FALSE;
474     }
475     return TRUE;
476 }
477 
478 //
479 //  SpoofData::getDefault() - return a wrapper around the spoof data that is
480 //                           baked into the default ICU data.
481 //
getDefault(UErrorCode & status)482 SpoofData *SpoofData::getDefault(UErrorCode &status) {
483     // TODO:  Cache it.  Lazy create, keep until cleanup.
484 
485     UDataMemory *udm = udata_open(NULL, "cfu", "confusables", &status);
486     if (U_FAILURE(status)) {
487         return NULL;
488     }
489     SpoofData *This = new SpoofData(udm, status);
490     if (U_FAILURE(status)) {
491         delete This;
492         return NULL;
493     }
494     if (This == NULL) {
495         status = U_MEMORY_ALLOCATION_ERROR;
496     }
497     return This;
498 }
499 
500 
SpoofData(UDataMemory * udm,UErrorCode & status)501 SpoofData::SpoofData(UDataMemory *udm, UErrorCode &status)
502 {
503     reset();
504     if (U_FAILURE(status)) {
505         return;
506     }
507     fRawData = reinterpret_cast<SpoofDataHeader *>
508                    ((char *)(udm->pHeader) + udm->pHeader->dataHeader.headerSize);
509     fUDM = udm;
510     validateDataVersion(fRawData, status);
511     initPtrs(status);
512 }
513 
514 
SpoofData(const void * data,int32_t length,UErrorCode & status)515 SpoofData::SpoofData(const void *data, int32_t length, UErrorCode &status)
516 {
517     reset();
518     if (U_FAILURE(status)) {
519         return;
520     }
521     if ((size_t)length < sizeof(SpoofDataHeader)) {
522         status = U_INVALID_FORMAT_ERROR;
523         return;
524     }
525     void *ncData = const_cast<void *>(data);
526     fRawData = static_cast<SpoofDataHeader *>(ncData);
527     if (length < fRawData->fLength) {
528         status = U_INVALID_FORMAT_ERROR;
529         return;
530     }
531     validateDataVersion(fRawData, status);
532     initPtrs(status);
533 }
534 
535 
536 // Spoof Data constructor for use from data builder.
537 //   Initializes a new, empty data area that will be populated later.
SpoofData(UErrorCode & status)538 SpoofData::SpoofData(UErrorCode &status) {
539     reset();
540     if (U_FAILURE(status)) {
541         return;
542     }
543     fDataOwned = true;
544     fRefCount = 1;
545 
546     // The spoof header should already be sized to be a multiple of 16 bytes.
547     // Just in case it's not, round it up.
548     uint32_t initialSize = (sizeof(SpoofDataHeader) + 15) & ~15;
549     U_ASSERT(initialSize == sizeof(SpoofDataHeader));
550 
551     fRawData = static_cast<SpoofDataHeader *>(uprv_malloc(initialSize));
552     fMemLimit = initialSize;
553     if (fRawData == NULL) {
554         status = U_MEMORY_ALLOCATION_ERROR;
555         return;
556     }
557     uprv_memset(fRawData, 0, initialSize);
558 
559     fRawData->fMagic = USPOOF_MAGIC;
560     fRawData->fFormatVersion[0] = 1;
561     fRawData->fFormatVersion[1] = 0;
562     fRawData->fFormatVersion[2] = 0;
563     fRawData->fFormatVersion[3] = 0;
564     initPtrs(status);
565 }
566 
567 // reset() - initialize all fields.
568 //           Should be updated if any new fields are added.
569 //           Called by constructors to put things in a known initial state.
reset()570 void SpoofData::reset() {
571    fRawData = NULL;
572    fDataOwned = FALSE;
573    fUDM      = NULL;
574    fMemLimit = 0;
575    fRefCount = 1;
576    fCFUKeys = NULL;
577    fCFUValues = NULL;
578    fCFUStringLengths = NULL;
579    fCFUStrings = NULL;
580    fAnyCaseTrie = NULL;
581    fLowerCaseTrie = NULL;
582    fScriptSets = NULL;
583 }
584 
585 
586 //  SpoofData::initPtrs()
587 //            Initialize the pointers to the various sections of the raw data.
588 //
589 //            This function is used both during the Trie building process (multiple
590 //            times, as the individual data sections are added), and
591 //            during the opening of a Spoof Checker from prebuilt data.
592 //
593 //            The pointers for non-existent data sections (identified by an offset of 0)
594 //            are set to NULL.
595 //
596 //            Note:  During building the data, adding each new data section
597 //            reallocs the raw data area, which likely relocates it, which
598 //            in turn requires reinitializing all of the pointers into it, hence
599 //            multiple calls to this function during building.
600 //
initPtrs(UErrorCode & status)601 void SpoofData::initPtrs(UErrorCode &status) {
602     fCFUKeys = NULL;
603     fCFUValues = NULL;
604     fCFUStringLengths = NULL;
605     fCFUStrings = NULL;
606     if (U_FAILURE(status)) {
607         return;
608     }
609     if (fRawData->fCFUKeys != 0) {
610         fCFUKeys = (int32_t *)((char *)fRawData + fRawData->fCFUKeys);
611     }
612     if (fRawData->fCFUStringIndex != 0) {
613         fCFUValues = (uint16_t *)((char *)fRawData + fRawData->fCFUStringIndex);
614     }
615     if (fRawData->fCFUStringLengths != 0) {
616         fCFUStringLengths = (SpoofStringLengthsElement *)((char *)fRawData + fRawData->fCFUStringLengths);
617     }
618     if (fRawData->fCFUStringTable != 0) {
619         fCFUStrings = (UChar *)((char *)fRawData + fRawData->fCFUStringTable);
620     }
621 
622     if (fAnyCaseTrie ==  NULL && fRawData->fAnyCaseTrie != 0) {
623         fAnyCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
624             (char *)fRawData + fRawData->fAnyCaseTrie, fRawData->fAnyCaseTrieLength, NULL, &status);
625     }
626     if (fLowerCaseTrie ==  NULL && fRawData->fLowerCaseTrie != 0) {
627         fLowerCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
628             (char *)fRawData + fRawData->fLowerCaseTrie, fRawData->fLowerCaseTrieLength, NULL, &status);
629     }
630 
631     if (fRawData->fScriptSets != 0) {
632         fScriptSets = (ScriptSet *)((char *)fRawData + fRawData->fScriptSets);
633     }
634 }
635 
636 
~SpoofData()637 SpoofData::~SpoofData() {
638     utrie2_close(fAnyCaseTrie);
639     fAnyCaseTrie = NULL;
640     utrie2_close(fLowerCaseTrie);
641     fLowerCaseTrie = NULL;
642     if (fDataOwned) {
643         uprv_free(fRawData);
644     }
645     fRawData = NULL;
646     if (fUDM != NULL) {
647         udata_close(fUDM);
648     }
649     fUDM = NULL;
650 }
651 
652 
removeReference()653 void SpoofData::removeReference() {
654     if (umtx_atomic_dec(&fRefCount) == 0) {
655         delete this;
656     }
657 }
658 
659 
addReference()660 SpoofData *SpoofData::addReference() {
661     umtx_atomic_inc(&fRefCount);
662     return this;
663 }
664 
665 
reserveSpace(int32_t numBytes,UErrorCode & status)666 void *SpoofData::reserveSpace(int32_t numBytes,  UErrorCode &status) {
667     if (U_FAILURE(status)) {
668         return NULL;
669     }
670     if (!fDataOwned) {
671         U_ASSERT(FALSE);
672         status = U_INTERNAL_PROGRAM_ERROR;
673         return NULL;
674     }
675 
676     numBytes = (numBytes + 15) & ~15;   // Round up to a multiple of 16
677     uint32_t returnOffset = fMemLimit;
678     fMemLimit += numBytes;
679     fRawData = static_cast<SpoofDataHeader *>(uprv_realloc(fRawData, fMemLimit));
680     fRawData->fLength = fMemLimit;
681     uprv_memset((char *)fRawData + returnOffset, 0, numBytes);
682     initPtrs(status);
683     return (char *)fRawData + returnOffset;
684 }
685 
686 
687 U_NAMESPACE_END
688 
689 U_NAMESPACE_USE
690 
691 //-----------------------------------------------------------------------------
692 //
693 //  uspoof_swap   -  byte swap and char encoding swap of spoof data
694 //
695 //-----------------------------------------------------------------------------
696 U_CAPI int32_t U_EXPORT2
uspoof_swap(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * status)697 uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
698            UErrorCode *status) {
699 
700     if (status == NULL || U_FAILURE(*status)) {
701         return 0;
702     }
703     if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
704         *status=U_ILLEGAL_ARGUMENT_ERROR;
705         return 0;
706     }
707 
708     //
709     //  Check that the data header is for spoof data.
710     //    (Header contents are defined in gencfu.cpp)
711     //
712     const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4);
713     if(!(  pInfo->dataFormat[0]==0x43 &&   /* dataFormat="Cfu " */
714            pInfo->dataFormat[1]==0x66 &&
715            pInfo->dataFormat[2]==0x75 &&
716            pInfo->dataFormat[3]==0x20 &&
717            pInfo->formatVersion[0]==1  )) {
718         udata_printError(ds, "uspoof_swap(): data format %02x.%02x.%02x.%02x "
719                              "(format version %02x %02x %02x %02x) is not recognized\n",
720                          pInfo->dataFormat[0], pInfo->dataFormat[1],
721                          pInfo->dataFormat[2], pInfo->dataFormat[3],
722                          pInfo->formatVersion[0], pInfo->formatVersion[1],
723                          pInfo->formatVersion[2], pInfo->formatVersion[3]);
724         *status=U_UNSUPPORTED_ERROR;
725         return 0;
726     }
727 
728     //
729     // Swap the data header.  (This is the generic ICU Data Header, not the uspoof Specific
730     //                         header).  This swap also conveniently gets us
731     //                         the size of the ICU d.h., which lets us locate the start
732     //                         of the uspoof specific data.
733     //
734     int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
735 
736 
737     //
738     // Get the Spoof Data Header, and check that it appears to be OK.
739     //
740     //
741     const uint8_t   *inBytes =(const uint8_t *)inData+headerSize;
742     SpoofDataHeader *spoofDH = (SpoofDataHeader *)inBytes;
743     if (ds->readUInt32(spoofDH->fMagic)   != USPOOF_MAGIC ||
744         ds->readUInt32(spoofDH->fLength)  <  sizeof(SpoofDataHeader))
745     {
746         udata_printError(ds, "uspoof_swap(): Spoof Data header is invalid.\n");
747         *status=U_UNSUPPORTED_ERROR;
748         return 0;
749     }
750 
751     //
752     // Prefight operation?  Just return the size
753     //
754     int32_t spoofDataLength = ds->readUInt32(spoofDH->fLength);
755     int32_t totalSize = headerSize + spoofDataLength;
756     if (length < 0) {
757         return totalSize;
758     }
759 
760     //
761     // Check that length passed in is consistent with length from Spoof data header.
762     //
763     if (length < totalSize) {
764         udata_printError(ds, "uspoof_swap(): too few bytes (%d after ICU Data header) for spoof data.\n",
765                             spoofDataLength);
766         *status=U_INDEX_OUTOFBOUNDS_ERROR;
767         return 0;
768         }
769 
770 
771     //
772     // Swap the Data.  Do the data itself first, then the Spoof Data Header, because
773     //                 we need to reference the header to locate the data, and an
774     //                 inplace swap of the header leaves it unusable.
775     //
776     uint8_t          *outBytes = (uint8_t *)outData + headerSize;
777     SpoofDataHeader  *outputDH = (SpoofDataHeader *)outBytes;
778 
779     int32_t   sectionStart;
780     int32_t   sectionLength;
781 
782     //
783     // If not swapping in place, zero out the output buffer before starting.
784     //    Gaps may exist between the individual sections, and these must be zeroed in
785     //    the output buffer.  The simplest way to do that is to just zero the whole thing.
786     //
787     if (inBytes != outBytes) {
788         uprv_memset(outBytes, 0, spoofDataLength);
789     }
790 
791     // Confusables Keys Section   (fCFUKeys)
792     sectionStart  = ds->readUInt32(spoofDH->fCFUKeys);
793     sectionLength = ds->readUInt32(spoofDH->fCFUKeysSize) * 4;
794     ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
795 
796     // String Index Section
797     sectionStart  = ds->readUInt32(spoofDH->fCFUStringIndex);
798     sectionLength = ds->readUInt32(spoofDH->fCFUStringIndexSize) * 2;
799     ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
800 
801     // String Table Section
802     sectionStart  = ds->readUInt32(spoofDH->fCFUStringTable);
803     sectionLength = ds->readUInt32(spoofDH->fCFUStringTableLen) * 2;
804     ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
805 
806     // String Lengths Section
807     sectionStart  = ds->readUInt32(spoofDH->fCFUStringLengths);
808     sectionLength = ds->readUInt32(spoofDH->fCFUStringLengthsSize) * 4;
809     ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
810 
811     // Any Case Trie
812     sectionStart  = ds->readUInt32(spoofDH->fAnyCaseTrie);
813     sectionLength = ds->readUInt32(spoofDH->fAnyCaseTrieLength);
814     utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
815 
816     // Lower Case Trie
817     sectionStart  = ds->readUInt32(spoofDH->fLowerCaseTrie);
818     sectionLength = ds->readUInt32(spoofDH->fLowerCaseTrieLength);
819     utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
820 
821     // Script Sets.  The data is an array of int32_t
822     sectionStart  = ds->readUInt32(spoofDH->fScriptSets);
823     sectionLength = ds->readUInt32(spoofDH->fScriptSetsLength) * sizeof(ScriptSet);
824     ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
825 
826     // And, last, swap the header itself.
827     //   int32_t   fMagic             // swap this
828     //   uint8_t   fFormatVersion[4]  // Do not swap this, just copy
829     //   int32_t   fLength and all the rest       // Swap the rest, all is 32 bit stuff.
830     //
831     uint32_t magic = ds->readUInt32(spoofDH->fMagic);
832     ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic);
833 
834     if (outputDH->fFormatVersion != spoofDH->fFormatVersion) {
835         uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion));
836     }
837     // swap starting at fLength
838     ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8 /* minus magic and fFormatVersion[4] */, &outputDH->fLength, status);
839 
840     return totalSize;
841 }
842 
843 #endif
844 
845 
846