Index: icu46/source/i18n/uspoof_impl.cpp |
=================================================================== |
--- icu46/source/i18n/uspoof_impl.cpp (revision 0) |
+++ icu46/source/i18n/uspoof_impl.cpp (revision 0) |
@@ -0,0 +1,964 @@ |
+/* |
+********************************************************************** |
+* Copyright (C) 2008-2010, International Business Machines |
+* Corporation and others. All Rights Reserved. |
+********************************************************************** |
+*/ |
+ |
+#include "unicode/utypes.h" |
+#include "unicode/uspoof.h" |
+#include "unicode/unorm.h" |
+#include "unicode/uchar.h" |
+#include "unicode/uniset.h" |
+#include "utrie2.h" |
+#include "cmemory.h" |
+#include "cstring.h" |
+#include "udatamem.h" |
+#include "umutex.h" |
+#include "udataswp.h" |
+#include "uassert.h" |
+#include "uspoof_impl.h" |
+ |
+#if !UCONFIG_NO_NORMALIZATION |
+ |
+ |
+U_NAMESPACE_BEGIN |
+ |
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl) |
+ |
+SpoofImpl::SpoofImpl(SpoofData *data, UErrorCode &status) : |
+ fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) , fAllowedLocales(NULL) { |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ fMagic = USPOOF_MAGIC; |
+ fSpoofData = data; |
+ fChecks = USPOOF_ALL_CHECKS; |
+ UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff); |
+ if (allowedCharsSet == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ } |
+ allowedCharsSet->freeze(); |
+ fAllowedCharsSet = allowedCharsSet; |
+ fAllowedLocales = uprv_strdup(""); |
+} |
+ |
+ |
+SpoofImpl::SpoofImpl() { |
+ fMagic = USPOOF_MAGIC; |
+ fSpoofData = NULL; |
+ fChecks = USPOOF_ALL_CHECKS; |
+ UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff); |
+ allowedCharsSet->freeze(); |
+ fAllowedCharsSet = allowedCharsSet; |
+ fAllowedLocales = uprv_strdup(""); |
+} |
+ |
+ |
+// Copy Constructor, used by the user level clone() function. |
+SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) : |
+ fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) { |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ fMagic = src.fMagic; |
+ fChecks = src.fChecks; |
+ if (src.fSpoofData != NULL) { |
+ fSpoofData = src.fSpoofData->addReference(); |
+ } |
+ fCheckMask = src.fCheckMask; |
+ fAllowedCharsSet = static_cast<const UnicodeSet *>(src.fAllowedCharsSet->clone()); |
+ if (fAllowedCharsSet == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ } |
+ fAllowedLocales = uprv_strdup(src.fAllowedLocales); |
+} |
+ |
+SpoofImpl::~SpoofImpl() { |
+ fMagic = 0; // head off application errors by preventing use of |
+ // of deleted objects. |
+ if (fSpoofData != NULL) { |
+ fSpoofData->removeReference(); // Will delete if refCount goes to zero. |
+ } |
+ delete fAllowedCharsSet; |
+ uprv_free((void *)fAllowedLocales); |
+} |
+ |
+// |
+// Incoming parameter check on Status and the SpoofChecker object |
+// received from the C API. |
+// |
+const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return NULL; |
+ } |
+ if (sc == NULL) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return NULL; |
+ }; |
+ SpoofImpl *This = (SpoofImpl *)sc; |
+ if (This->fMagic != USPOOF_MAGIC || |
+ This->fSpoofData == NULL) { |
+ status = U_INVALID_FORMAT_ERROR; |
+ return NULL; |
+ } |
+ if (!SpoofData::validateDataVersion(This->fSpoofData->fRawData, status)) { |
+ return NULL; |
+ } |
+ return This; |
+} |
+ |
+SpoofImpl *SpoofImpl::validateThis(USpoofChecker *sc, UErrorCode &status) { |
+ return const_cast<SpoofImpl *> |
+ (SpoofImpl::validateThis(const_cast<const USpoofChecker *>(sc), status)); |
+} |
+ |
+ |
+ |
+//-------------------------------------------------------------------------------------- |
+// |
+// confusableLookup() This is the heart of the confusable skeleton generation |
+// implementation. |
+// |
+// Given a source character, produce the corresponding |
+// replacement character(s) |
+// |
+//--------------------------------------------------------------------------------------- |
+int32_t SpoofImpl::confusableLookup(UChar32 inChar, int32_t tableMask, UChar *destBuf) const { |
+ |
+ // Binary search the spoof data key table for the inChar |
+ int32_t *low = fSpoofData->fCFUKeys; |
+ int32_t *mid = NULL; |
+ int32_t *limit = low + fSpoofData->fRawData->fCFUKeysSize; |
+ UChar32 midc; |
+ do { |
+ int32_t delta = ((int32_t)(limit-low))/2; |
+ mid = low + delta; |
+ midc = *mid & 0x1fffff; |
+ if (inChar == midc) { |
+ goto foundChar; |
+ } else if (inChar < midc) { |
+ limit = mid; |
+ } else { |
+ low = mid; |
+ } |
+ } while (low < limit-1); |
+ mid = low; |
+ midc = *mid & 0x1fffff; |
+ if (inChar != midc) { |
+ // Char not found. It maps to itself. |
+ int i = 0; |
+ U16_APPEND_UNSAFE(destBuf, i, inChar) |
+ return i; |
+ } |
+ foundChar: |
+ int32_t keyFlags = *mid & 0xff000000; |
+ if ((keyFlags & tableMask) == 0) { |
+ // We found the right key char, but the entry doesn't pertain to the |
+ // table we need. See if there is an adjacent key that does |
+ if (keyFlags & USPOOF_KEY_MULTIPLE_VALUES) { |
+ int32_t *altMid; |
+ for (altMid = mid-1; (*altMid&0x00ffffff) == inChar; altMid--) { |
+ keyFlags = *altMid & 0xff000000; |
+ if (keyFlags & tableMask) { |
+ mid = altMid; |
+ goto foundKey; |
+ } |
+ } |
+ for (altMid = mid+1; (*altMid&0x00ffffff) == inChar; altMid++) { |
+ keyFlags = *altMid & 0xff000000; |
+ if (keyFlags & tableMask) { |
+ mid = altMid; |
+ goto foundKey; |
+ } |
+ } |
+ } |
+ // No key entry for this char & table. |
+ // The input char maps to itself. |
+ int i = 0; |
+ U16_APPEND_UNSAFE(destBuf, i, inChar) |
+ return i; |
+ } |
+ |
+ foundKey: |
+ int32_t stringLen = USPOOF_KEY_LENGTH_FIELD(keyFlags) + 1; |
+ int32_t keyTableIndex = (int32_t)(mid - fSpoofData->fCFUKeys); |
+ |
+ // Value is either a UChar (for strings of length 1) or |
+ // an index into the string table (for longer strings) |
+ uint16_t value = fSpoofData->fCFUValues[keyTableIndex]; |
+ if (stringLen == 1) { |
+ destBuf[0] = value; |
+ return 1; |
+ } |
+ |
+ // String length of 4 from the above lookup is used for all strings of length >= 4. |
+ // For these, get the real length from the string lengths table, |
+ // which maps string table indexes to lengths. |
+ // All strings of the same length are stored contiguously in the string table. |
+ // 'value' from the lookup above is the starting index for the desired string. |
+ |
+ int32_t ix; |
+ if (stringLen == 4) { |
+ int32_t stringLengthsLimit = fSpoofData->fRawData->fCFUStringLengthsSize; |
+ for (ix = 0; ix < stringLengthsLimit; ix++) { |
+ if (fSpoofData->fCFUStringLengths[ix].fLastString >= value) { |
+ stringLen = fSpoofData->fCFUStringLengths[ix].fStrLength; |
+ break; |
+ } |
+ } |
+ U_ASSERT(ix < stringLengthsLimit); |
+ } |
+ |
+ U_ASSERT(value + stringLen < fSpoofData->fRawData->fCFUStringTableLen); |
+ UChar *src = &fSpoofData->fCFUStrings[value]; |
+ for (ix=0; ix<stringLen; ix++) { |
+ destBuf[ix] = src[ix]; |
+ } |
+ return stringLen; |
+} |
+ |
+ |
+//--------------------------------------------------------------------------------------- |
+// |
+// wholeScriptCheck() |
+// |
+// Input text is already normalized to NFKD |
+// Return the set of scripts, each of which can represent something that is |
+// confusable with the input text. The script of the input text |
+// is included; input consisting of characters from a single script will |
+// always produce a result consisting of a set containing that script. |
+// |
+//--------------------------------------------------------------------------------------- |
+void SpoofImpl::wholeScriptCheck( |
+ const UChar *text, int32_t length, ScriptSet *result, UErrorCode &status) const { |
+ |
+ int32_t inputIdx = 0; |
+ UChar32 c; |
+ |
+ UTrie2 *table = |
+ (fChecks & USPOOF_ANY_CASE) ? fSpoofData->fAnyCaseTrie : fSpoofData->fLowerCaseTrie; |
+ result->setAll(); |
+ while (inputIdx < length) { |
+ U16_NEXT(text, inputIdx, length, c); |
+ uint32_t index = utrie2_get32(table, c); |
+ if (index == 0) { |
+ // No confusables in another script for this char. |
+ // TODO: we should change the data to have sets with just the single script |
+ // bit for the script of this char. Gets rid of this special case. |
+ // Until then, grab the script from the char and intersect it with the set. |
+ UScriptCode cpScript = uscript_getScript(c, &status); |
+ U_ASSERT(cpScript > USCRIPT_INHERITED); |
+ result->intersect(cpScript); |
+ } else if (index == 1) { |
+ // Script == Common or Inherited. Nothing to do. |
+ } else { |
+ result->intersect(fSpoofData->fScriptSets[index]); |
+ } |
+ } |
+} |
+ |
+ |
+void SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) { |
+ UnicodeSet allowedChars; |
+ UnicodeSet *tmpSet = NULL; |
+ const char *locStart = localesList; |
+ const char *locEnd = NULL; |
+ const char *localesListEnd = localesList + uprv_strlen(localesList); |
+ int32_t localeListCount = 0; // Number of locales provided by caller. |
+ |
+ // Loop runs once per locale from the localesList, a comma separated list of locales. |
+ do { |
+ locEnd = uprv_strchr(locStart, ','); |
+ if (locEnd == NULL) { |
+ locEnd = localesListEnd; |
+ } |
+ while (*locStart == ' ') { |
+ locStart++; |
+ } |
+ const char *trimmedEnd = locEnd-1; |
+ while (trimmedEnd > locStart && *trimmedEnd == ' ') { |
+ trimmedEnd--; |
+ } |
+ if (trimmedEnd <= locStart) { |
+ break; |
+ } |
+ const char *locale = uprv_strndup(locStart, (int32_t)(trimmedEnd + 1 - locStart)); |
+ localeListCount++; |
+ |
+ // We have one locale from the locales list. |
+ // Add the script chars for this locale to the accumulating set of allowed chars. |
+ // If the locale is no good, we will be notified back via status. |
+ addScriptChars(locale, &allowedChars, status); |
+ uprv_free((void *)locale); |
+ if (U_FAILURE(status)) { |
+ break; |
+ } |
+ locStart = locEnd + 1; |
+ } while (locStart < localesListEnd); |
+ |
+ // If our caller provided an empty list of locales, we disable the allowed characters checking |
+ if (localeListCount == 0) { |
+ uprv_free((void *)fAllowedLocales); |
+ fAllowedLocales = uprv_strdup(""); |
+ tmpSet = new UnicodeSet(0, 0x10ffff); |
+ if (fAllowedLocales == NULL || tmpSet == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ return; |
+ } |
+ tmpSet->freeze(); |
+ delete fAllowedCharsSet; |
+ fAllowedCharsSet = tmpSet; |
+ fCheckMask &= ~USPOOF_CHAR_LIMIT; |
+ return; |
+ } |
+ |
+ |
+ // Add all common and inherited characters to the set of allowed chars. |
+ UnicodeSet tempSet; |
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_COMMON, status); |
+ allowedChars.addAll(tempSet); |
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_INHERITED, status); |
+ allowedChars.addAll(tempSet); |
+ |
+ // If anything went wrong, we bail out without changing |
+ // the state of the spoof checker. |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ |
+ // Store the updated spoof checker state. |
+ tmpSet = static_cast<UnicodeSet *>(allowedChars.clone()); |
+ const char *tmpLocalesList = uprv_strdup(localesList); |
+ if (tmpSet == NULL || tmpLocalesList == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ return; |
+ } |
+ uprv_free((void *)fAllowedLocales); |
+ fAllowedLocales = tmpLocalesList; |
+ tmpSet->freeze(); |
+ delete fAllowedCharsSet; |
+ fAllowedCharsSet = tmpSet; |
+ fCheckMask |= USPOOF_CHAR_LIMIT; |
+} |
+ |
+ |
+const char * SpoofImpl::getAllowedLocales(UErrorCode &/*status*/) { |
+ return fAllowedLocales; |
+} |
+ |
+ |
+// Given a locale (a language), add all the characters from all of the scripts used with that language |
+// to the allowedChars UnicodeSet |
+ |
+void SpoofImpl::addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status) { |
+ UScriptCode scripts[30]; |
+ |
+ int32_t numScripts = uscript_getCode(locale, scripts, sizeof(scripts)/sizeof(UScriptCode), &status); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ if (status == U_USING_DEFAULT_WARNING) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return; |
+ } |
+ UnicodeSet tmpSet; |
+ int32_t i; |
+ for (i=0; i<numScripts; i++) { |
+ tmpSet.applyIntPropertyValue(UCHAR_SCRIPT, scripts[i], status); |
+ allowedChars->addAll(tmpSet); |
+ } |
+} |
+ |
+ |
+int32_t SpoofImpl::scriptScan |
+ (const UChar *text, int32_t length, int32_t &pos, UErrorCode &status) const { |
+ if (U_FAILURE(status)) { |
+ return 0; |
+ } |
+ int32_t inputIdx = 0; |
+ UChar32 c; |
+ int32_t scriptCount = 0; |
+ UScriptCode lastScript = USCRIPT_INVALID_CODE; |
+ UScriptCode sc = USCRIPT_INVALID_CODE; |
+ while ((inputIdx < length || length == -1) && scriptCount < 2) { |
+ U16_NEXT(text, inputIdx, length, c); |
+ if (c == 0 && length == -1) { |
+ break; |
+ } |
+ sc = uscript_getScript(c, &status); |
+ if (sc == USCRIPT_COMMON || sc == USCRIPT_INHERITED || sc == USCRIPT_UNKNOWN) { |
+ continue; |
+ } |
+ if (sc != lastScript) { |
+ scriptCount++; |
+ lastScript = sc; |
+ } |
+ } |
+ if (scriptCount == 2) { |
+ pos = inputIdx; |
+ } |
+ return scriptCount; |
+} |
+ |
+ |
+// Convert a text format hex number. Utility function used by builder code. Static. |
+// Input: UChar *string text. Output: a UChar32 |
+// Input has been pre-checked, and will have no non-hex chars. |
+// The number must fall in the code point range of 0..0x10ffff |
+// Static Function. |
+UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return 0; |
+ } |
+ U_ASSERT(limit-start > 0); |
+ uint32_t val = 0; |
+ int i; |
+ for (i=start; i<limit; i++) { |
+ int digitVal = s[i] - 0x30; |
+ if (digitVal>9) { |
+ digitVal = 0xa + (s[i] - 0x41); // Upper Case 'A' |
+ } |
+ if (digitVal>15) { |
+ digitVal = 0xa + (s[i] - 0x61); // Lower Case 'a' |
+ } |
+ U_ASSERT(digitVal <= 0xf); |
+ val <<= 4; |
+ val += digitVal; |
+ } |
+ if (val > 0x10ffff) { |
+ status = U_PARSE_ERROR; |
+ val = 0; |
+ } |
+ return (UChar32)val; |
+} |
+ |
+ |
+ |
+//---------------------------------------------------------------------------------------------- |
+// |
+// class SpoofData Implementation |
+// |
+//---------------------------------------------------------------------------------------------- |
+ |
+ |
+UBool SpoofData::validateDataVersion(const SpoofDataHeader *rawData, UErrorCode &status) { |
+ if (U_FAILURE(status) || |
+ rawData == NULL || |
+ rawData->fMagic != USPOOF_MAGIC || |
+ rawData->fFormatVersion[0] > 1 || |
+ rawData->fFormatVersion[1] > 0) { |
+ status = U_INVALID_FORMAT_ERROR; |
+ return FALSE; |
+ } |
+ return TRUE; |
+} |
+ |
+// |
+// SpoofData::getDefault() - return a wrapper around the spoof data that is |
+// baked into the default ICU data. |
+// |
+SpoofData *SpoofData::getDefault(UErrorCode &status) { |
+ // TODO: Cache it. Lazy create, keep until cleanup. |
+ |
+ UDataMemory *udm = udata_open(NULL, "cfu", "confusables", &status); |
+ if (U_FAILURE(status)) { |
+ return NULL; |
+ } |
+ SpoofData *This = new SpoofData(udm, status); |
+ if (U_FAILURE(status)) { |
+ delete This; |
+ return NULL; |
+ } |
+ if (This == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ } |
+ return This; |
+} |
+ |
+ |
+SpoofData::SpoofData(UDataMemory *udm, UErrorCode &status) |
+{ |
+ reset(); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ fRawData = reinterpret_cast<SpoofDataHeader *> |
+ ((char *)(udm->pHeader) + udm->pHeader->dataHeader.headerSize); |
+ fUDM = udm; |
+ validateDataVersion(fRawData, status); |
+ initPtrs(status); |
+} |
+ |
+ |
+SpoofData::SpoofData(const void *data, int32_t length, UErrorCode &status) |
+{ |
+ reset(); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ if ((size_t)length < sizeof(SpoofDataHeader)) { |
+ status = U_INVALID_FORMAT_ERROR; |
+ return; |
+ } |
+ void *ncData = const_cast<void *>(data); |
+ fRawData = static_cast<SpoofDataHeader *>(ncData); |
+ if (length < fRawData->fLength) { |
+ status = U_INVALID_FORMAT_ERROR; |
+ return; |
+ } |
+ validateDataVersion(fRawData, status); |
+ initPtrs(status); |
+} |
+ |
+ |
+// Spoof Data constructor for use from data builder. |
+// Initializes a new, empty data area that will be populated later. |
+SpoofData::SpoofData(UErrorCode &status) { |
+ reset(); |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ fDataOwned = true; |
+ fRefCount = 1; |
+ |
+ // The spoof header should already be sized to be a multiple of 16 bytes. |
+ // Just in case it's not, round it up. |
+ uint32_t initialSize = (sizeof(SpoofDataHeader) + 15) & ~15; |
+ U_ASSERT(initialSize == sizeof(SpoofDataHeader)); |
+ |
+ fRawData = static_cast<SpoofDataHeader *>(uprv_malloc(initialSize)); |
+ fMemLimit = initialSize; |
+ if (fRawData == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ return; |
+ } |
+ uprv_memset(fRawData, 0, initialSize); |
+ |
+ fRawData->fMagic = USPOOF_MAGIC; |
+ fRawData->fFormatVersion[0] = 1; |
+ fRawData->fFormatVersion[1] = 0; |
+ fRawData->fFormatVersion[2] = 0; |
+ fRawData->fFormatVersion[3] = 0; |
+ initPtrs(status); |
+} |
+ |
+// reset() - initialize all fields. |
+// Should be updated if any new fields are added. |
+// Called by constructors to put things in a known initial state. |
+void SpoofData::reset() { |
+ fRawData = NULL; |
+ fDataOwned = FALSE; |
+ fUDM = NULL; |
+ fMemLimit = 0; |
+ fRefCount = 1; |
+ fCFUKeys = NULL; |
+ fCFUValues = NULL; |
+ fCFUStringLengths = NULL; |
+ fCFUStrings = NULL; |
+ fAnyCaseTrie = NULL; |
+ fLowerCaseTrie = NULL; |
+ fScriptSets = NULL; |
+} |
+ |
+ |
+// SpoofData::initPtrs() |
+// Initialize the pointers to the various sections of the raw data. |
+// |
+// This function is used both during the Trie building process (multiple |
+// times, as the individual data sections are added), and |
+// during the opening of a Spoof Checker from prebuilt data. |
+// |
+// The pointers for non-existent data sections (identified by an offset of 0) |
+// are set to NULL. |
+// |
+// Note: During building the data, adding each new data section |
+// reallocs the raw data area, which likely relocates it, which |
+// in turn requires reinitializing all of the pointers into it, hence |
+// multiple calls to this function during building. |
+// |
+void SpoofData::initPtrs(UErrorCode &status) { |
+ fCFUKeys = NULL; |
+ fCFUValues = NULL; |
+ fCFUStringLengths = NULL; |
+ fCFUStrings = NULL; |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ if (fRawData->fCFUKeys != 0) { |
+ fCFUKeys = (int32_t *)((char *)fRawData + fRawData->fCFUKeys); |
+ } |
+ if (fRawData->fCFUStringIndex != 0) { |
+ fCFUValues = (uint16_t *)((char *)fRawData + fRawData->fCFUStringIndex); |
+ } |
+ if (fRawData->fCFUStringLengths != 0) { |
+ fCFUStringLengths = (SpoofStringLengthsElement *)((char *)fRawData + fRawData->fCFUStringLengths); |
+ } |
+ if (fRawData->fCFUStringTable != 0) { |
+ fCFUStrings = (UChar *)((char *)fRawData + fRawData->fCFUStringTable); |
+ } |
+ |
+ if (fAnyCaseTrie == NULL && fRawData->fAnyCaseTrie != 0) { |
+ fAnyCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS, |
+ (char *)fRawData + fRawData->fAnyCaseTrie, fRawData->fAnyCaseTrieLength, NULL, &status); |
+ } |
+ if (fLowerCaseTrie == NULL && fRawData->fLowerCaseTrie != 0) { |
+ fLowerCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS, |
+ (char *)fRawData + fRawData->fLowerCaseTrie, fRawData->fLowerCaseTrieLength, NULL, &status); |
+ } |
+ |
+ if (fRawData->fScriptSets != 0) { |
+ fScriptSets = (ScriptSet *)((char *)fRawData + fRawData->fScriptSets); |
+ } |
+} |
+ |
+ |
+SpoofData::~SpoofData() { |
+ utrie2_close(fAnyCaseTrie); |
+ fAnyCaseTrie = NULL; |
+ utrie2_close(fLowerCaseTrie); |
+ fLowerCaseTrie = NULL; |
+ if (fDataOwned) { |
+ uprv_free(fRawData); |
+ } |
+ fRawData = NULL; |
+ if (fUDM != NULL) { |
+ udata_close(fUDM); |
+ } |
+ fUDM = NULL; |
+} |
+ |
+ |
+void SpoofData::removeReference() { |
+ if (umtx_atomic_dec(&fRefCount) == 0) { |
+ delete this; |
+ } |
+} |
+ |
+ |
+SpoofData *SpoofData::addReference() { |
+ umtx_atomic_inc(&fRefCount); |
+ return this; |
+} |
+ |
+ |
+void *SpoofData::reserveSpace(int32_t numBytes, UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return NULL; |
+ } |
+ if (!fDataOwned) { |
+ U_ASSERT(FALSE); |
+ status = U_INTERNAL_PROGRAM_ERROR; |
+ return NULL; |
+ } |
+ |
+ numBytes = (numBytes + 15) & ~15; // Round up to a multiple of 16 |
+ uint32_t returnOffset = fMemLimit; |
+ fMemLimit += numBytes; |
+ fRawData = static_cast<SpoofDataHeader *>(uprv_realloc(fRawData, fMemLimit)); |
+ fRawData->fLength = fMemLimit; |
+ uprv_memset((char *)fRawData + returnOffset, 0, numBytes); |
+ initPtrs(status); |
+ return (char *)fRawData + returnOffset; |
+} |
+ |
+ |
+//---------------------------------------------------------------------------- |
+// |
+// ScriptSet implementation |
+// |
+//---------------------------------------------------------------------------- |
+ScriptSet::ScriptSet() { |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ bits[i] = 0; |
+ } |
+} |
+ |
+ScriptSet::~ScriptSet() { |
+} |
+ |
+UBool ScriptSet::operator == (const ScriptSet &other) { |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ if (bits[i] != other.bits[i]) { |
+ return FALSE; |
+ } |
+ } |
+ return TRUE; |
+} |
+ |
+void ScriptSet::Union(UScriptCode script) { |
+ uint32_t index = script / 32; |
+ uint32_t bit = 1 << (script & 31); |
+ U_ASSERT(index < sizeof(bits)*4); |
+ bits[index] |= bit; |
+} |
+ |
+ |
+void ScriptSet::Union(const ScriptSet &other) { |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ bits[i] |= other.bits[i]; |
+ } |
+} |
+ |
+void ScriptSet::intersect(const ScriptSet &other) { |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ bits[i] &= other.bits[i]; |
+ } |
+} |
+ |
+void ScriptSet::intersect(UScriptCode script) { |
+ uint32_t index = script / 32; |
+ uint32_t bit = 1 << (script & 31); |
+ U_ASSERT(index < sizeof(bits)*4); |
+ uint32_t i; |
+ for (i=0; i<index; i++) { |
+ bits[i] = 0; |
+ } |
+ bits[index] &= bit; |
+ for (i=index+1; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ bits[i] = 0; |
+ } |
+} |
+ |
+ |
+ScriptSet & ScriptSet::operator =(const ScriptSet &other) { |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ bits[i] = other.bits[i]; |
+ } |
+ return *this; |
+} |
+ |
+ |
+void ScriptSet::setAll() { |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ bits[i] = 0xffffffffu; |
+ } |
+} |
+ |
+ |
+void ScriptSet::resetAll() { |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ bits[i] = 0; |
+ } |
+} |
+ |
+int32_t ScriptSet::countMembers() { |
+ // This bit counter is good for sparse numbers of '1's, which is |
+ // very much the case that we will usually have. |
+ int32_t count = 0; |
+ for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) { |
+ uint32_t x = bits[i]; |
+ while (x > 0) { |
+ count++; |
+ x &= (x - 1); // and off the least significant one bit. |
+ } |
+ } |
+ return count; |
+} |
+ |
+ |
+ |
+//----------------------------------------------------------------------------- |
+// |
+// NFKDBuffer Implementation. |
+// |
+//----------------------------------------------------------------------------- |
+ |
+NFKDBuffer::NFKDBuffer(const UChar *text, int32_t length, UErrorCode &status) { |
+ fNormalizedText = NULL; |
+ fNormalizedTextLength = 0; |
+ fOriginalText = text; |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ fNormalizedText = fSmallBuf; |
+ fNormalizedTextLength = unorm_normalize( |
+ text, length, UNORM_NFKD, 0, fNormalizedText, USPOOF_STACK_BUFFER_SIZE, &status); |
+ if (status == U_BUFFER_OVERFLOW_ERROR) { |
+ status = U_ZERO_ERROR; |
+ fNormalizedText = (UChar *)uprv_malloc((fNormalizedTextLength+1)*sizeof(UChar)); |
+ if (fNormalizedText == NULL) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ } else { |
+ fNormalizedTextLength = unorm_normalize(text, length, UNORM_NFKD, 0, |
+ fNormalizedText, fNormalizedTextLength+1, &status); |
+ } |
+ } |
+} |
+ |
+ |
+NFKDBuffer::~NFKDBuffer() { |
+ if (fNormalizedText != fSmallBuf) { |
+ uprv_free(fNormalizedText); |
+ } |
+ fNormalizedText = 0; |
+} |
+ |
+const UChar *NFKDBuffer::getBuffer() { |
+ return fNormalizedText; |
+} |
+ |
+int32_t NFKDBuffer::getLength() { |
+ return fNormalizedTextLength; |
+} |
+ |
+ |
+ |
+ |
+ |
+U_NAMESPACE_END |
+ |
+U_NAMESPACE_USE |
+ |
+//----------------------------------------------------------------------------- |
+// |
+// uspoof_swap - byte swap and char encoding swap of spoof data |
+// |
+//----------------------------------------------------------------------------- |
+U_CAPI int32_t U_EXPORT2 |
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData, |
+ UErrorCode *status) { |
+ |
+ if (status == NULL || U_FAILURE(*status)) { |
+ return 0; |
+ } |
+ if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) { |
+ *status=U_ILLEGAL_ARGUMENT_ERROR; |
+ return 0; |
+ } |
+ |
+ // |
+ // Check that the data header is for spoof data. |
+ // (Header contents are defined in gencfu.cpp) |
+ // |
+ const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4); |
+ if(!( pInfo->dataFormat[0]==0x43 && /* dataFormat="Cfu " */ |
+ pInfo->dataFormat[1]==0x66 && |
+ pInfo->dataFormat[2]==0x75 && |
+ pInfo->dataFormat[3]==0x20 && |
+ pInfo->formatVersion[0]==1 )) { |
+ udata_printError(ds, "uspoof_swap(): data format %02x.%02x.%02x.%02x " |
+ "(format version %02x %02x %02x %02x) is not recognized\n", |
+ pInfo->dataFormat[0], pInfo->dataFormat[1], |
+ pInfo->dataFormat[2], pInfo->dataFormat[3], |
+ pInfo->formatVersion[0], pInfo->formatVersion[1], |
+ pInfo->formatVersion[2], pInfo->formatVersion[3]); |
+ *status=U_UNSUPPORTED_ERROR; |
+ return 0; |
+ } |
+ |
+ // |
+ // Swap the data header. (This is the generic ICU Data Header, not the uspoof Specific |
+ // header). This swap also conveniently gets us |
+ // the size of the ICU d.h., which lets us locate the start |
+ // of the uspoof specific data. |
+ // |
+ int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status); |
+ |
+ |
+ // |
+ // Get the Spoof Data Header, and check that it appears to be OK. |
+ // |
+ // |
+ const uint8_t *inBytes =(const uint8_t *)inData+headerSize; |
+ SpoofDataHeader *spoofDH = (SpoofDataHeader *)inBytes; |
+ if (ds->readUInt32(spoofDH->fMagic) != USPOOF_MAGIC || |
+ ds->readUInt32(spoofDH->fLength) < sizeof(SpoofDataHeader)) |
+ { |
+ udata_printError(ds, "uspoof_swap(): Spoof Data header is invalid.\n"); |
+ *status=U_UNSUPPORTED_ERROR; |
+ return 0; |
+ } |
+ |
+ // |
+ // Prefight operation? Just return the size |
+ // |
+ int32_t spoofDataLength = ds->readUInt32(spoofDH->fLength); |
+ int32_t totalSize = headerSize + spoofDataLength; |
+ if (length < 0) { |
+ return totalSize; |
+ } |
+ |
+ // |
+ // Check that length passed in is consistent with length from Spoof data header. |
+ // |
+ if (length < totalSize) { |
+ udata_printError(ds, "uspoof_swap(): too few bytes (%d after ICU Data header) for spoof data.\n", |
+ spoofDataLength); |
+ *status=U_INDEX_OUTOFBOUNDS_ERROR; |
+ return 0; |
+ } |
+ |
+ |
+ // |
+ // Swap the Data. Do the data itself first, then the Spoof Data Header, because |
+ // we need to reference the header to locate the data, and an |
+ // inplace swap of the header leaves it unusable. |
+ // |
+ uint8_t *outBytes = (uint8_t *)outData + headerSize; |
+ SpoofDataHeader *outputDH = (SpoofDataHeader *)outBytes; |
+ |
+ int32_t sectionStart; |
+ int32_t sectionLength; |
+ |
+ // |
+ // If not swapping in place, zero out the output buffer before starting. |
+ // Gaps may exist between the individual sections, and these must be zeroed in |
+ // the output buffer. The simplest way to do that is to just zero the whole thing. |
+ // |
+ if (inBytes != outBytes) { |
+ uprv_memset(outBytes, 0, spoofDataLength); |
+ } |
+ |
+ // Confusables Keys Section (fCFUKeys) |
+ sectionStart = ds->readUInt32(spoofDH->fCFUKeys); |
+ sectionLength = ds->readUInt32(spoofDH->fCFUKeysSize) * 4; |
+ ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status); |
+ |
+ // String Index Section |
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringIndex); |
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringIndexSize) * 2; |
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status); |
+ |
+ // String Table Section |
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringTable); |
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringTableLen) * 2; |
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status); |
+ |
+ // String Lengths Section |
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringLengths); |
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringLengthsSize) * 4; |
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status); |
+ |
+ // Any Case Trie |
+ sectionStart = ds->readUInt32(spoofDH->fAnyCaseTrie); |
+ sectionLength = ds->readUInt32(spoofDH->fAnyCaseTrieLength); |
+ utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status); |
+ |
+ // Lower Case Trie |
+ sectionStart = ds->readUInt32(spoofDH->fLowerCaseTrie); |
+ sectionLength = ds->readUInt32(spoofDH->fLowerCaseTrieLength); |
+ utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status); |
+ |
+ // Script Sets. The data is an array of int32_t |
+ sectionStart = ds->readUInt32(spoofDH->fScriptSets); |
+ sectionLength = ds->readUInt32(spoofDH->fScriptSetsLength) * sizeof(ScriptSet); |
+ ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status); |
+ |
+ // And, last, swap the header itself. |
+ // int32_t fMagic // swap this |
+ // uint8_t fFormatVersion[4] // Do not swap this, just copy |
+ // int32_t fLength and all the rest // Swap the rest, all is 32 bit stuff. |
+ // |
+ uint32_t magic = ds->readUInt32(spoofDH->fMagic); |
+ ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic); |
+ uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion)); |
+ // swap starting at fLength |
+ ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8 /* minus magic and fFormatVersion[4] */, &outputDH->fLength, status); |
+ |
+ return totalSize; |
+} |
+ |
+#endif |
+ |
+ |
Property changes on: icu46/source/i18n/uspoof_impl.cpp |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |