X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b75a7d8f3b4adbae880cab104ce2c6a50eee4db2..249c4c5ea9376c24572daf9c2effa7484a282f14:/icuSources/i18n/tridpars.cpp diff --git a/icuSources/i18n/tridpars.cpp b/icuSources/i18n/tridpars.cpp index 33c5b263..b2766364 100644 --- a/icuSources/i18n/tridpars.cpp +++ b/icuSources/i18n/tridpars.cpp @@ -1,6 +1,8 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /* ********************************************************************** -* Copyright (c) 2002-2003, International Business Machines Corporation +* Copyright (c) 2002-2014, International Business Machines Corporation * and others. All Rights Reserved. ********************************************************************** * Date Name Description @@ -15,6 +17,8 @@ #include "tridpars.h" #include "hash.h" #include "mutex.h" +#include "transreg.h" +#include "uassert.h" #include "ucln_in.h" #include "unicode/parsepos.h" #include "unicode/translit.h" @@ -33,7 +37,7 @@ static const UChar VARIANT_SEP = 0x002F; // / static const UChar OPEN_REV = 0x0028; // ( static const UChar CLOSE_REV = 0x0029; // ) -static const UChar EMPTY[] = {0}; // "" +//static const UChar EMPTY[] = {0}; // "" static const UChar ANY[] = {65,110,121,0}; // "Any" static const UChar ANY_NULL[] = {65,110,121,45,78,117,108,108,0}; // "Any-Null" @@ -41,11 +45,12 @@ static const int32_t FORWARD = UTRANS_FORWARD; static const int32_t REVERSE = UTRANS_REVERSE; static Hashtable* SPECIAL_INVERSES = NULL; +static UInitOnce gSpecialInversesInitOnce = U_INITONCE_INITIALIZER; /** * The mutex controlling access to SPECIAL_INVERSES */ -static UMTX LOCK = 0; +static UMutex LOCK = U_MUTEX_INITIALIZER; TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString& t, const UnicodeString& v, UBool sawS, @@ -72,7 +77,7 @@ TransliteratorIDParser::SingleID::SingleID(const UnicodeString& c, const Unicode Transliterator* TransliteratorIDParser::SingleID::createInstance() { Transliterator* t; if (basicID.length() == 0) { - t = createBasicInstance(ANY_NULL, &canonID); + t = createBasicInstance(UnicodeString(TRUE, ANY_NULL, 8), &canonID); } else { t = createBasicInstance(basicID, &canonID); } @@ -105,7 +110,7 @@ Transliterator* TransliteratorIDParser::SingleID::createInstance() { */ TransliteratorIDParser::SingleID* TransliteratorIDParser::parseSingleID(const UnicodeString& id, int32_t& pos, - int32_t dir) { + int32_t dir, UErrorCode& status) { int32_t start = pos; @@ -146,6 +151,13 @@ TransliteratorIDParser::parseSingleID(const UnicodeString& id, int32_t& pos, if (dir == FORWARD) { SingleID* b = specsToID(specsB, FORWARD); single = specsToID(specsA, FORWARD); + // Null pointers check + if (b == NULL || single == NULL) { + delete b; + delete single; + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } single->canonID.append(OPEN_REV) .append(b->canonID).append(CLOSE_REV); if (specsA != NULL) { @@ -155,6 +167,13 @@ TransliteratorIDParser::parseSingleID(const UnicodeString& id, int32_t& pos, } else { SingleID* a = specsToID(specsA, FORWARD); single = specsToID(specsB, FORWARD); + // Check for null pointer. + if (a == NULL || single == NULL) { + delete a; + delete single; + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } single->canonID.append(OPEN_REV) .append(a->canonID).append(CLOSE_REV); if (specsB != NULL) { @@ -167,11 +186,16 @@ TransliteratorIDParser::parseSingleID(const UnicodeString& id, int32_t& pos, if (dir == FORWARD) { single = specsToID(specsA, FORWARD); } else { - single = specsToSpecialInverse(*specsA); + single = specsToSpecialInverse(*specsA, status); if (single == NULL) { single = specsToID(specsA, REVERSE); } } + // Check for NULL pointer + if (single == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } single->filter = specsA->filter; } @@ -203,7 +227,9 @@ TransliteratorIDParser::parseFilterID(const UnicodeString& id, int32_t& pos) { // Assemble return results SingleID* single = specsToID(specs, FORWARD); - single->filter = specs->filter; + if (single != NULL) { + single->filter = specs->filter; + } delete specs; return single; } @@ -251,7 +277,7 @@ UnicodeSet* TransliteratorIDParser::parseGlobalFilter(const UnicodeString& id, i if (UnicodeSet::resemblesPattern(id, pos)) { ParsePosition ppos(pos); UErrorCode ec = U_ZERO_ERROR; - filter = new UnicodeSet(id, ppos, USET_IGNORE_SPACE, ec); + filter = new UnicodeSet(id, ppos, USET_IGNORE_SPACE, NULL, ec); /* test for NULL */ if (filter == 0) { pos = start; @@ -301,7 +327,7 @@ static void U_CALLCONV _deleteSingleID(void* obj) { delete (TransliteratorIDParser::SingleID*) obj; } -static void U_CALLCONV _deleteTransliterator(void* obj) { +static void U_CALLCONV _deleteTransliteratorTrIDPars(void* obj) { delete (Transliterator*) obj; } U_CDECL_END @@ -360,7 +386,7 @@ UBool TransliteratorIDParser::parseCompoundID(const UnicodeString& id, int32_t d UBool sawDelimiter = TRUE; for (;;) { - SingleID* single = parseSingleID(id, pos, dir); + SingleID* single = parseSingleID(id, pos, dir, ec); if (single == NULL) { break; } @@ -437,41 +463,23 @@ UBool TransliteratorIDParser::parseCompoundID(const UnicodeString& id, int32_t d * the reverse. THIS MAY RESULT IN AN EMPTY VECTOR. Convert * SingleID entries to actual transliterators. * - * Also, optionally, insert the given transliterator at the given - * position. This effectively happens before anything else. - * * @param list vector of SingleID objects. On exit, vector * of one or more Transliterators. - * @param insert Transliterator to insert, or NULL if none. - * Adopted. - * @param insertIndex index from 0..list.size()-1, at which - * to place 'insert', or -1 if none. * @return new value of insertIndex. The index will shift if * there are empty items, like "(Lower)", with indices less than * insertIndex. */ -int32_t TransliteratorIDParser::instantiateList(UVector& list, - Transliterator* insert, - int32_t insertIndex, +void TransliteratorIDParser::instantiateList(UVector& list, UErrorCode& ec) { UVector tlist(ec); if (U_FAILURE(ec)) { goto RETURN; } - tlist.setDeleter(_deleteTransliterator); + tlist.setDeleter(_deleteTransliteratorTrIDPars); Transliterator* t; int32_t i; for (i=0; i<=list.size(); ++i) { // [sic]: i<=list.size() - if (insertIndex == i) { - insertIndex = tlist.size(); - tlist.addElement(insert, ec); - if (U_FAILURE(ec)) { - goto RETURN; - } - insert = NULL; - } - // We run the loop too long by one, so we can // do an insert after the last element if (i==list.size()) { @@ -495,7 +503,7 @@ int32_t TransliteratorIDParser::instantiateList(UVector& list, // An empty list is equivalent to a NULL transliterator. if (tlist.size() == 0) { - t = createBasicInstance(ANY_NULL, NULL); + t = createBasicInstance(UnicodeString(TRUE, ANY_NULL, 8), NULL); if (t == NULL) { // Should never happen ec = U_INTERNAL_TRANSLITERATOR_ERROR; @@ -512,7 +520,7 @@ int32_t TransliteratorIDParser::instantiateList(UVector& list, list.removeAllElements(); if (U_SUCCESS(ec)) { - list.setDeleter(_deleteTransliterator); + list.setDeleter(_deleteTransliteratorTrIDPars); while (tlist.size() > 0) { t = (Transliterator*) tlist.orphanElementAt(0); @@ -525,9 +533,7 @@ int32_t TransliteratorIDParser::instantiateList(UVector& list, } } - delete insert; // Clean up in case of failure list.setDeleter(save); - return insertIndex; } /** @@ -546,7 +552,7 @@ void TransliteratorIDParser::IDtoSTV(const UnicodeString& id, UnicodeString& target, UnicodeString& variant, UBool& isSourcePresent) { - source = ANY; + source.setTo(ANY, 3); target.truncate(0); variant.truncate(0); @@ -595,12 +601,16 @@ void TransliteratorIDParser::STVtoID(const UnicodeString& source, UnicodeString& id) { id = source; if (id.length() == 0) { - id = ANY; + id.setTo(ANY, 3); } id.append(TARGET_SEP).append(target); if (variant.length() != 0) { id.append(VARIANT_SEP).append(variant); } + // NUL-terminate the ID string for getTerminatedBuffer. + // This prevents valgrind and Purify warnings. + id.append((UChar)0); + id.truncate(id.length()-1); } /** @@ -637,21 +647,33 @@ void TransliteratorIDParser::STVtoID(const UnicodeString& source, */ void TransliteratorIDParser::registerSpecialInverse(const UnicodeString& target, const UnicodeString& inverseTarget, - UBool bidirectional) { - init(); + UBool bidirectional, + UErrorCode &status) { + umtx_initOnce(gSpecialInversesInitOnce, init, status); + if (U_FAILURE(status)) { + return; + } // If target == inverseTarget then force bidirectional => FALSE if (bidirectional && 0==target.caseCompare(inverseTarget, U_FOLD_CASE_DEFAULT)) { bidirectional = FALSE; } - umtx_init(&LOCK); Mutex lock(&LOCK); - UErrorCode ec = U_ZERO_ERROR; - SPECIAL_INVERSES->put(target, new UnicodeString(inverseTarget), ec); + UnicodeString *tempus = new UnicodeString(inverseTarget); // Used for null pointer check before usage. + if (tempus == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + SPECIAL_INVERSES->put(target, tempus, status); if (bidirectional) { - SPECIAL_INVERSES->put(inverseTarget, new UnicodeString(target), ec); + tempus = new UnicodeString(target); + if (tempus == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + SPECIAL_INVERSES->put(inverseTarget, tempus, status); } } @@ -705,7 +727,7 @@ TransliteratorIDParser::parseFilterID(const UnicodeString& id, int32_t& pos, ParsePosition ppos(pos); UErrorCode ec = U_ZERO_ERROR; - UnicodeSet set(id, ppos, USET_IGNORE_SPACE, ec); + UnicodeSet set(id, ppos, USET_IGNORE_SPACE, NULL, ec); if (U_FAILURE(ec)) { pos = start; return NULL; @@ -774,11 +796,11 @@ TransliteratorIDParser::parseFilterID(const UnicodeString& id, int32_t& pos, // Empty source or target defaults to ANY UBool sawSource = TRUE; if (source.length() == 0) { - source = ANY; + source.setTo(ANY, 3); sawSource = FALSE; } if (target.length() == 0) { - target = ANY; + target.setTo(ANY, 3); } return new Specs(source, target, variant, sawSource, filter); @@ -830,15 +852,17 @@ TransliteratorIDParser::specsToID(const Specs* specs, int32_t dir) { * 'filter' field of NULL. */ TransliteratorIDParser::SingleID* -TransliteratorIDParser::specsToSpecialInverse(const Specs& specs) { - if (0!=specs.source.caseCompare(ANY, U_FOLD_CASE_DEFAULT)) { +TransliteratorIDParser::specsToSpecialInverse(const Specs& specs, UErrorCode &status) { + if (0!=specs.source.caseCompare(ANY, 3, U_FOLD_CASE_DEFAULT)) { + return NULL; + } + umtx_initOnce(gSpecialInversesInitOnce, init, status); + if (U_FAILURE(status)) { return NULL; } - init(); UnicodeString* inverseTarget; - umtx_init(&LOCK); umtx_lock(&LOCK); inverseTarget = (UnicodeString*) SPECIAL_INVERSES->get(specs.target); umtx_unlock(&LOCK); @@ -852,11 +876,11 @@ TransliteratorIDParser::specsToSpecialInverse(const Specs& specs) { buf.append(specs.filter); } if (specs.sawSource) { - buf.append(ANY).append(TARGET_SEP); + buf.append(ANY, 3).append(TARGET_SEP); } buf.append(*inverseTarget); - UnicodeString basicID(ANY); + UnicodeString basicID(TRUE, ANY, 3); basicID.append(TARGET_SEP).append(*inverseTarget); if (specs.variant.length() != 0) { @@ -878,26 +902,18 @@ Transliterator* TransliteratorIDParser::createBasicInstance(const UnicodeString& } /** - * Initialize static memory. + * Initialize static memory. Called through umtx_initOnce only. */ -void TransliteratorIDParser::init() { - if (SPECIAL_INVERSES != NULL) { - return; - } - - Hashtable* special_inverses = new Hashtable(TRUE); - special_inverses->setValueDeleter(uhash_deleteUnicodeString); +void U_CALLCONV TransliteratorIDParser::init(UErrorCode &status) { + U_ASSERT(SPECIAL_INVERSES == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_TRANSLITERATOR, utrans_transliterator_cleanup); - umtx_init(&LOCK); - umtx_lock(&LOCK); + SPECIAL_INVERSES = new Hashtable(TRUE, status); if (SPECIAL_INVERSES == NULL) { - SPECIAL_INVERSES = special_inverses; - special_inverses = NULL; + status = U_MEMORY_ALLOCATION_ERROR; + return; } - umtx_unlock(&LOCK); - delete special_inverses; - - ucln_i18n_registerCleanup(); + SPECIAL_INVERSES->setValueDeleter(uprv_deleteUObject); } /** @@ -908,7 +924,7 @@ void TransliteratorIDParser::cleanup() { delete SPECIAL_INVERSES; SPECIAL_INVERSES = NULL; } - umtx_destroy(&LOCK); + gSpecialInversesInitOnce.reset(); } U_NAMESPACE_END