]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/tridpars.cpp
ICU-62141.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / tridpars.cpp
index 33c5b263fb5dda02f76e99258f8ef935f5b45378..b27663649ad257b587fb694f4d37e36ef6174157 100644 (file)
@@ -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