+// © 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
#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"
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"
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,
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);
}
*/
TransliteratorIDParser::SingleID*
TransliteratorIDParser::parseSingleID(const UnicodeString& id, int32_t& pos,
- int32_t dir) {
+ int32_t dir, UErrorCode& status) {
int32_t start = 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) {
} 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) {
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;
}
// Assemble return results
SingleID* single = specsToID(specs, FORWARD);
- single->filter = specs->filter;
+ if (single != NULL) {
+ single->filter = specs->filter;
+ }
delete specs;
return single;
}
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;
delete (TransliteratorIDParser::SingleID*) obj;
}
-static void U_CALLCONV _deleteTransliterator(void* obj) {
+static void U_CALLCONV _deleteTransliteratorTrIDPars(void* obj) {
delete (Transliterator*) obj;
}
U_CDECL_END
UBool sawDelimiter = TRUE;
for (;;) {
- SingleID* single = parseSingleID(id, pos, dir);
+ SingleID* single = parseSingleID(id, pos, dir, ec);
if (single == NULL) {
break;
}
* 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()) {
// 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;
list.removeAllElements();
if (U_SUCCESS(ec)) {
- list.setDeleter(_deleteTransliterator);
+ list.setDeleter(_deleteTransliteratorTrIDPars);
while (tlist.size() > 0) {
t = (Transliterator*) tlist.orphanElementAt(0);
}
}
- delete insert; // Clean up in case of failure
list.setDeleter(save);
- return insertIndex;
}
/**
UnicodeString& target,
UnicodeString& variant,
UBool& isSourcePresent) {
- source = ANY;
+ source.setTo(ANY, 3);
target.truncate(0);
variant.truncate(0);
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);
}
/**
*/
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);
}
}
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;
// 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);
* '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);
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) {
}
/**
- * 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);
}
/**
delete SPECIAL_INVERSES;
SPECIAL_INVERSES = NULL;
}
- umtx_destroy(&LOCK);
+ gSpecialInversesInitOnce.reset();
}
U_NAMESPACE_END