Home | History | Annotate | Download | only in i18n
      1 /*
      2 **********************************************************************
      3 *   Copyright (c) 2001-2008, International Business Machines
      4 *   Corporation and others.  All Rights Reserved.
      5 **********************************************************************
      6 *   Date        Name        Description
      7 *   08/10/2001  aliu        Creation.
      8 **********************************************************************
      9 */
     10 
     11 #include "unicode/utypes.h"
     12 
     13 #if !UCONFIG_NO_TRANSLITERATION
     14 
     15 #include "unicode/translit.h"
     16 #include "unicode/resbund.h"
     17 #include "unicode/uniset.h"
     18 #include "unicode/uscript.h"
     19 #include "rbt.h"
     20 #include "cpdtrans.h"
     21 #include "nultrans.h"
     22 #include "transreg.h"
     23 #include "rbt_data.h"
     24 #include "rbt_pars.h"
     25 #include "tridpars.h"
     26 #include "charstr.h"
     27 #include "uassert.h"
     28 #include "locutil.h"
     29 
     30 // Enable the following symbol to add debugging code that tracks the
     31 // allocation, deletion, and use of Entry objects.  BoundsChecker has
     32 // reported dangling pointer errors with these objects, but I have
     33 // been unable to confirm them.  I suspect BoundsChecker is getting
     34 // confused with pointers going into and coming out of a UHashtable,
     35 // despite the hinting code that is designed to help it.
     36 // #define DEBUG_MEM
     37 #ifdef DEBUG_MEM
     38 #include <stdio.h>
     39 #endif
     40 
     41 // UChar constants
     42 static const UChar LOCALE_SEP  = 95; // '_'
     43 //static const UChar ID_SEP      = 0x002D; /*-*/
     44 //static const UChar VARIANT_SEP = 0x002F; // '/'
     45 
     46 // String constants
     47 static const UChar NO_VARIANT[] = { 0 }; // empty string
     48 static const UChar ANY[] = { 65, 110, 121, 0 }; // Any
     49 
     50 /**
     51  * Resource bundle key for the RuleBasedTransliterator rule.
     52  */
     53 //static const char RB_RULE[] = "Rule";
     54 
     55 U_NAMESPACE_BEGIN
     56 
     57 //------------------------------------------------------------------
     58 // Alias
     59 //------------------------------------------------------------------
     60 
     61 TransliteratorAlias::TransliteratorAlias(const UnicodeString& theAliasID,
     62                                          const UnicodeSet* cpdFilter) :
     63     ID(),
     64     aliasesOrRules(theAliasID),
     65     transes(0),
     66     compoundFilter(cpdFilter),
     67     direction(UTRANS_FORWARD),
     68     type(TransliteratorAlias::SIMPLE) {
     69 }
     70 
     71 TransliteratorAlias::TransliteratorAlias(const UnicodeString& theID,
     72                                          const UnicodeString& idBlocks,
     73                                          UVector* adoptedTransliterators,
     74                                          const UnicodeSet* cpdFilter) :
     75     ID(theID),
     76     aliasesOrRules(idBlocks),
     77     transes(adoptedTransliterators),
     78     compoundFilter(cpdFilter),
     79     direction(UTRANS_FORWARD),
     80     type(TransliteratorAlias::COMPOUND) {
     81 }
     82 
     83 TransliteratorAlias::TransliteratorAlias(const UnicodeString& theID,
     84                                          const UnicodeString& rules,
     85                                          UTransDirection dir) :
     86     ID(theID),
     87     aliasesOrRules(rules),
     88     transes(0),
     89     compoundFilter(0),
     90     direction(dir),
     91     type(TransliteratorAlias::RULES) {
     92 }
     93 
     94 TransliteratorAlias::~TransliteratorAlias() {
     95     delete transes;
     96 }
     97 
     98 
     99 Transliterator* TransliteratorAlias::create(UParseError& pe,
    100                                             UErrorCode& ec) {
    101     if (U_FAILURE(ec)) {
    102         return 0;
    103     }
    104     Transliterator *t = NULL;
    105     switch (type) {
    106     case SIMPLE:
    107         t = Transliterator::createInstance(aliasesOrRules, UTRANS_FORWARD, pe, ec);
    108         if(U_FAILURE(ec)){
    109             return 0;
    110         }
    111         if (compoundFilter != 0)
    112             t->adoptFilter((UnicodeSet*)compoundFilter->clone());
    113         break;
    114     case COMPOUND:
    115         {
    116             // the total number of transliterators in the compound is the total number of anonymous transliterators
    117             // plus the total number of ID blocks-- we start by assuming the list begins and ends with an ID
    118             // block and that each pair anonymous transliterators has an ID block between them.  Then we go back
    119             // to see whether there really are ID blocks at the beginning and end (by looking for U+FFFF, which
    120             // marks the position where an anonymous transliterator goes) and adjust accordingly
    121             int32_t anonymousRBTs = transes->size();
    122             int32_t transCount = anonymousRBTs * 2 + 1;
    123             if (!aliasesOrRules.isEmpty() && aliasesOrRules[0] == (UChar)(0xffff))
    124                 --transCount;
    125             if (aliasesOrRules.length() >= 2 && aliasesOrRules[aliasesOrRules.length() - 1] == (UChar)(0xffff))
    126                 --transCount;
    127             UnicodeString noIDBlock((UChar)(0xffff));
    128             noIDBlock += ((UChar)(0xffff));
    129             int32_t pos = aliasesOrRules.indexOf(noIDBlock);
    130             while (pos >= 0) {
    131                 --transCount;
    132                 pos = aliasesOrRules.indexOf(noIDBlock, pos + 1);
    133             }
    134 
    135             UVector transliterators(ec);
    136             UnicodeString idBlock;
    137             int32_t blockSeparatorPos = aliasesOrRules.indexOf((UChar)(0xffff));
    138             while (blockSeparatorPos >= 0) {
    139                 aliasesOrRules.extract(0, blockSeparatorPos, idBlock);
    140                 aliasesOrRules.remove(0, blockSeparatorPos + 1);
    141                 if (!idBlock.isEmpty())
    142                     transliterators.addElement(Transliterator::createInstance(idBlock, UTRANS_FORWARD, pe, ec), ec);
    143                 if (!transes->isEmpty())
    144                     transliterators.addElement(transes->orphanElementAt(0), ec);
    145                 blockSeparatorPos = aliasesOrRules.indexOf((UChar)(0xffff));
    146             }
    147             if (!aliasesOrRules.isEmpty())
    148                 transliterators.addElement(Transliterator::createInstance(aliasesOrRules, UTRANS_FORWARD, pe, ec), ec);
    149             while (!transes->isEmpty())
    150                 transliterators.addElement(transes->orphanElementAt(0), ec);
    151 
    152             if (U_SUCCESS(ec)) {
    153                 t = new CompoundTransliterator(ID, transliterators,
    154                     (compoundFilter ? (UnicodeSet*)(compoundFilter->clone()) : 0),
    155                     anonymousRBTs, pe, ec);
    156                 if (t == 0) {
    157                     ec = U_MEMORY_ALLOCATION_ERROR;
    158                     return 0;
    159                 }
    160             } else {
    161                 for (int32_t i = 0; i < transliterators.size(); i++)
    162                     delete (Transliterator*)(transliterators.elementAt(i));
    163             }
    164         }
    165         break;
    166     case RULES:
    167         U_ASSERT(FALSE); // don't call create() if isRuleBased() returns TRUE!
    168         break;
    169     }
    170     return t;
    171 }
    172 
    173 UBool TransliteratorAlias::isRuleBased() const {
    174     return type == RULES;
    175 }
    176 
    177 void TransliteratorAlias::parse(TransliteratorParser& parser,
    178                                 UParseError& pe, UErrorCode& ec) const {
    179     U_ASSERT(type == RULES);
    180     if (U_FAILURE(ec)) {
    181         return;
    182     }
    183 
    184     parser.parse(aliasesOrRules, direction, pe, ec);
    185 }
    186 
    187 //----------------------------------------------------------------------
    188 // class TransliteratorSpec
    189 //----------------------------------------------------------------------
    190 
    191 /**
    192  * A TransliteratorSpec is a string specifying either a source or a target.  In more
    193  * general terms, it may also specify a variant, but we only use the
    194  * Spec class for sources and targets.
    195  *
    196  * A Spec may be a locale or a script.  If it is a locale, it has a
    197  * fallback chain that goes xx_YY_ZZZ -> xx_YY -> xx -> ssss, where
    198  * ssss is the script mapping of xx_YY_ZZZ.  The Spec API methods
    199  * hasFallback(), next(), and reset() iterate over this fallback
    200  * sequence.
    201  *
    202  * The Spec class canonicalizes itself, so the locale is put into
    203  * canonical form, or the script is transformed from an abbreviation
    204  * to a full name.
    205  */
    206 class TransliteratorSpec : public UMemory {
    207  public:
    208     TransliteratorSpec(const UnicodeString& spec);
    209     ~TransliteratorSpec();
    210 
    211     const UnicodeString& get() const;
    212     UBool hasFallback() const;
    213     const UnicodeString& next();
    214     void reset();
    215 
    216     UBool isLocale() const;
    217     ResourceBundle& getBundle() const;
    218 
    219     operator const UnicodeString&() const { return get(); }
    220     const UnicodeString& getTop() const { return top; }
    221 
    222  private:
    223     void setupNext();
    224 
    225     UnicodeString top;
    226     UnicodeString spec;
    227     UnicodeString nextSpec;
    228     UnicodeString scriptName;
    229     UBool isSpecLocale; // TRUE if spec is a locale
    230     UBool isNextLocale; // TRUE if nextSpec is a locale
    231     ResourceBundle* res;
    232 
    233     TransliteratorSpec(const TransliteratorSpec &other); // forbid copying of this class
    234     TransliteratorSpec &operator=(const TransliteratorSpec &other); // forbid copying of this class
    235 };
    236 
    237 TransliteratorSpec::TransliteratorSpec(const UnicodeString& theSpec)
    238 : top(theSpec),
    239   res(0)
    240 {
    241     UErrorCode status = U_ZERO_ERROR;
    242     CharString topch(theSpec);
    243     Locale topLoc("");
    244     LocaleUtility::initLocaleFromName(theSpec, topLoc);
    245     if (!topLoc.isBogus()) {
    246         res = new ResourceBundle(U_ICUDATA_TRANSLIT, topLoc, status);
    247         /* test for NULL */
    248         if (res == 0) {
    249             return;
    250         }
    251         if (U_FAILURE(status) || status == U_USING_DEFAULT_WARNING) {
    252             delete res;
    253             res = 0;
    254         }
    255     }
    256 
    257     // Canonicalize script name -or- do locale->script mapping
    258     status = U_ZERO_ERROR;
    259     static const int32_t capacity = 10;
    260     UScriptCode script[capacity]={USCRIPT_INVALID_CODE};
    261     int32_t num = uscript_getCode(topch,script,capacity, &status);
    262     if (num > 0 && script[0] != USCRIPT_INVALID_CODE) {
    263         scriptName = UnicodeString(uscript_getName(script[0]), -1, US_INV);
    264     }
    265 
    266     // Canonicalize top
    267     if (res != 0) {
    268         // Canonicalize locale name
    269         UnicodeString locStr;
    270         LocaleUtility::initNameFromLocale(topLoc, locStr);
    271         if (!locStr.isBogus()) {
    272             top = locStr;
    273         }
    274     } else if (scriptName.length() != 0) {
    275         // We are a script; use canonical name
    276         top = scriptName;
    277     }
    278 
    279     // assert(spec != top);
    280     reset();
    281 }
    282 
    283 TransliteratorSpec::~TransliteratorSpec() {
    284     delete res;
    285 }
    286 
    287 UBool TransliteratorSpec::hasFallback() const {
    288     return nextSpec.length() != 0;
    289 }
    290 
    291 void TransliteratorSpec::reset() {
    292     if (spec != top) {
    293         spec = top;
    294         isSpecLocale = (res != 0);
    295         setupNext();
    296     }
    297 }
    298 
    299 void TransliteratorSpec::setupNext() {
    300     isNextLocale = FALSE;
    301     if (isSpecLocale) {
    302         nextSpec = spec;
    303         int32_t i = nextSpec.lastIndexOf(LOCALE_SEP);
    304         // If i == 0 then we have _FOO, so we fall through
    305         // to the scriptName.
    306         if (i > 0) {
    307             nextSpec.truncate(i);
    308             isNextLocale = TRUE;
    309         } else {
    310             nextSpec = scriptName; // scriptName may be empty
    311         }
    312     } else {
    313         // spec is a script, so we are at the end
    314         nextSpec.truncate(0);
    315     }
    316 }
    317 
    318 // Protocol:
    319 // for(const UnicodeString& s(spec.get());
    320 //     spec.hasFallback(); s(spec.next())) { ...
    321 
    322 const UnicodeString& TransliteratorSpec::next() {
    323     spec = nextSpec;
    324     isSpecLocale = isNextLocale;
    325     setupNext();
    326     return spec;
    327 }
    328 
    329 const UnicodeString& TransliteratorSpec::get() const {
    330     return spec;
    331 }
    332 
    333 UBool TransliteratorSpec::isLocale() const {
    334     return isSpecLocale;
    335 }
    336 
    337 ResourceBundle& TransliteratorSpec::getBundle() const {
    338     return *res;
    339 }
    340 
    341 //----------------------------------------------------------------------
    342 
    343 #ifdef DEBUG_MEM
    344 
    345 // Vector of Entry pointers currently in use
    346 static UVector* DEBUG_entries = NULL;
    347 
    348 static void DEBUG_setup() {
    349     if (DEBUG_entries == NULL) {
    350         UErrorCode ec = U_ZERO_ERROR;
    351         DEBUG_entries = new UVector(ec);
    352     }
    353 }
    354 
    355 // Caller must call DEBUG_setup first.  Return index of given Entry,
    356 // if it is in use (not deleted yet), or -1 if not found.
    357 static int DEBUG_findEntry(TransliteratorEntry* e) {
    358     for (int i=0; i<DEBUG_entries->size(); ++i) {
    359         if (e == (TransliteratorEntry*) DEBUG_entries->elementAt(i)) {
    360             return i;
    361         }
    362     }
    363     return -1;
    364 }
    365 
    366 // Track object creation
    367 static void DEBUG_newEntry(TransliteratorEntry* e) {
    368     DEBUG_setup();
    369     if (DEBUG_findEntry(e) >= 0) {
    370         // This should really never happen unless the heap is broken
    371         printf("ERROR DEBUG_newEntry duplicate new pointer %08X\n", e);
    372         return;
    373     }
    374     UErrorCode ec = U_ZERO_ERROR;
    375     DEBUG_entries->addElement(e, ec);
    376 }
    377 
    378 // Track object deletion
    379 static void DEBUG_delEntry(TransliteratorEntry* e) {
    380     DEBUG_setup();
    381     int i = DEBUG_findEntry(e);
    382     if (i < 0) {
    383         printf("ERROR DEBUG_delEntry possible double deletion %08X\n", e);
    384         return;
    385     }
    386     DEBUG_entries->removeElementAt(i);
    387 }
    388 
    389 // Track object usage
    390 static void DEBUG_useEntry(TransliteratorEntry* e) {
    391     if (e == NULL) return;
    392     DEBUG_setup();
    393     int i = DEBUG_findEntry(e);
    394     if (i < 0) {
    395         printf("ERROR DEBUG_useEntry possible dangling pointer %08X\n", e);
    396     }
    397 }
    398 
    399 #else
    400 // If we're not debugging then make these macros into NOPs
    401 #define DEBUG_newEntry(x)
    402 #define DEBUG_delEntry(x)
    403 #define DEBUG_useEntry(x)
    404 #endif
    405 
    406 //----------------------------------------------------------------------
    407 // class Entry
    408 //----------------------------------------------------------------------
    409 
    410 /**
    411  * The Entry object stores objects of different types and
    412  * singleton objects as placeholders for rule-based transliterators to
    413  * be built as needed.  Instances of this struct can be placeholders,
    414  * can represent prototype transliterators to be cloned, or can
    415  * represent TransliteratorData objects.  We don't support storing
    416  * classes in the registry because we don't have the rtti infrastructure
    417  * for it.  We could easily add this if there is a need for it in the
    418  * future.
    419  */
    420 class TransliteratorEntry : public UMemory {
    421 public:
    422     enum Type {
    423         RULES_FORWARD,
    424         RULES_REVERSE,
    425         LOCALE_RULES,
    426         PROTOTYPE,
    427         RBT_DATA,
    428         COMPOUND_RBT,
    429         ALIAS,
    430         FACTORY,
    431         NONE // Only used for uninitialized entries
    432     } entryType;
    433     // NOTE: stringArg cannot go inside the union because
    434     // it has a copy constructor
    435     UnicodeString stringArg; // For RULES_*, ALIAS, COMPOUND_RBT
    436     int32_t intArg; // For COMPOUND_RBT, LOCALE_RULES
    437     UnicodeSet* compoundFilter; // For COMPOUND_RBT
    438     union {
    439         Transliterator* prototype; // For PROTOTYPE
    440         TransliterationRuleData* data; // For RBT_DATA
    441         UVector* dataVector;    // For COMPOUND_RBT
    442         struct {
    443             Transliterator::Factory function;
    444             Transliterator::Token   context;
    445         } factory; // For FACTORY
    446     } u;
    447     TransliteratorEntry();
    448     ~TransliteratorEntry();
    449     void adoptPrototype(Transliterator* adopted);
    450     void setFactory(Transliterator::Factory factory,
    451                     Transliterator::Token context);
    452 
    453 private:
    454 
    455     TransliteratorEntry(const TransliteratorEntry &other); // forbid copying of this class
    456     TransliteratorEntry &operator=(const TransliteratorEntry &other); // forbid copying of this class
    457 };
    458 
    459 TransliteratorEntry::TransliteratorEntry() {
    460     u.prototype = 0;
    461     compoundFilter = NULL;
    462     entryType = NONE;
    463     DEBUG_newEntry(this);
    464 }
    465 
    466 TransliteratorEntry::~TransliteratorEntry() {
    467     DEBUG_delEntry(this);
    468     if (entryType == PROTOTYPE) {
    469         delete u.prototype;
    470     } else if (entryType == RBT_DATA) {
    471         // The data object is shared between instances of RBT.  The
    472         // entry object owns it.  It should only be deleted when the
    473         // transliterator component is being cleaned up.  Doing so
    474         // invalidates any RBTs that the user has instantiated.
    475         delete u.data;
    476     } else if (entryType == COMPOUND_RBT) {
    477         while (u.dataVector != NULL && !u.dataVector->isEmpty())
    478             delete (TransliterationRuleData*)u.dataVector->orphanElementAt(0);
    479         delete u.dataVector;
    480     }
    481     delete compoundFilter;
    482 }
    483 
    484 void TransliteratorEntry::adoptPrototype(Transliterator* adopted) {
    485     if (entryType == PROTOTYPE) {
    486         delete u.prototype;
    487     }
    488     entryType = PROTOTYPE;
    489     u.prototype = adopted;
    490 }
    491 
    492 void TransliteratorEntry::setFactory(Transliterator::Factory factory,
    493                        Transliterator::Token context) {
    494     if (entryType == PROTOTYPE) {
    495         delete u.prototype;
    496     }
    497     entryType = FACTORY;
    498     u.factory.function = factory;
    499     u.factory.context = context;
    500 }
    501 
    502 // UObjectDeleter for Hashtable::setValueDeleter
    503 U_CDECL_BEGIN
    504 static void U_CALLCONV
    505 deleteEntry(void* obj) {
    506     delete (TransliteratorEntry*) obj;
    507 }
    508 U_CDECL_END
    509 
    510 //----------------------------------------------------------------------
    511 // class TransliteratorRegistry: Basic public API
    512 //----------------------------------------------------------------------
    513 
    514 TransliteratorRegistry::TransliteratorRegistry(UErrorCode& status) :
    515     registry(TRUE, status),
    516     specDAG(TRUE, status),
    517     availableIDs(status)
    518 {
    519     registry.setValueDeleter(deleteEntry);
    520     availableIDs.setDeleter(uhash_deleteUnicodeString);
    521     availableIDs.setComparer(uhash_compareCaselessUnicodeString);
    522     specDAG.setValueDeleter(uhash_deleteHashtable);
    523 }
    524 
    525 TransliteratorRegistry::~TransliteratorRegistry() {
    526     // Through the magic of C++, everything cleans itself up
    527 }
    528 
    529 Transliterator* TransliteratorRegistry::get(const UnicodeString& ID,
    530                                             TransliteratorAlias*& aliasReturn,
    531                                             UErrorCode& status) {
    532     U_ASSERT(aliasReturn == NULL);
    533     TransliteratorEntry *entry = find(ID);
    534     return (entry == 0) ? 0
    535         : instantiateEntry(ID, entry, aliasReturn, status);
    536 }
    537 
    538 Transliterator* TransliteratorRegistry::reget(const UnicodeString& ID,
    539                                               TransliteratorParser& parser,
    540                                               TransliteratorAlias*& aliasReturn,
    541                                               UErrorCode& status) {
    542     U_ASSERT(aliasReturn == NULL);
    543     TransliteratorEntry *entry = find(ID);
    544 
    545     if (entry == 0) {
    546         // We get to this point if there are two threads, one of which
    547         // is instantiating an ID, and another of which is removing
    548         // the same ID from the registry, and the timing is just right.
    549         return 0;
    550     }
    551 
    552     // The usage model for the caller is that they will first call
    553     // reg->get() inside the mutex, they'll get back an alias, they call
    554     // alias->isRuleBased(), and if they get TRUE, they call alias->parse()
    555     // outside the mutex, then reg->reget() inside the mutex again.  A real
    556     // mess, but it gets things working for ICU 3.0. [alan].
    557 
    558     // Note: It's possible that in between the caller calling
    559     // alias->parse() and reg->reget(), that another thread will have
    560     // called reg->reget(), and the entry will already have been fixed up.
    561     // We have to detect this so we don't stomp over existing entry
    562     // data members and potentially leak memory (u.data and compoundFilter).
    563 
    564     if (entry->entryType == TransliteratorEntry::RULES_FORWARD ||
    565         entry->entryType == TransliteratorEntry::RULES_REVERSE ||
    566         entry->entryType == TransliteratorEntry::LOCALE_RULES) {
    567 
    568         if (parser.idBlockVector.isEmpty() && parser.dataVector.isEmpty()) {
    569             entry->u.data = 0;
    570             entry->entryType = TransliteratorEntry::ALIAS;
    571             entry->stringArg = UNICODE_STRING_SIMPLE("Any-NULL");
    572         }
    573         else if (parser.idBlockVector.isEmpty() && parser.dataVector.size() == 1) {
    574             entry->u.data = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
    575             entry->entryType = TransliteratorEntry::RBT_DATA;
    576         }
    577         else if (parser.idBlockVector.size() == 1 && parser.dataVector.isEmpty()) {
    578             entry->stringArg = *(UnicodeString*)(parser.idBlockVector.elementAt(0));
    579             entry->compoundFilter = parser.orphanCompoundFilter();
    580             entry->entryType = TransliteratorEntry::ALIAS;
    581         }
    582         else {
    583             entry->entryType = TransliteratorEntry::COMPOUND_RBT;
    584             entry->compoundFilter = parser.orphanCompoundFilter();
    585             entry->u.dataVector = new UVector(status);
    586             entry->stringArg.remove();
    587 
    588             int32_t limit = parser.idBlockVector.size();
    589             if (parser.dataVector.size() > limit)
    590                 limit = parser.dataVector.size();
    591 
    592             for (int32_t i = 0; i < limit; i++) {
    593                 if (i < parser.idBlockVector.size()) {
    594                     UnicodeString* idBlock = (UnicodeString*)parser.idBlockVector.elementAt(i);
    595                     if (!idBlock->isEmpty())
    596                         entry->stringArg += *idBlock;
    597                 }
    598                 if (!parser.dataVector.isEmpty()) {
    599                     TransliterationRuleData* data = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
    600                     entry->u.dataVector->addElement(data, status);
    601                     entry->stringArg += (UChar)0xffff;  // use U+FFFF to mark position of RBTs in ID block
    602                 }
    603             }
    604         }
    605     }
    606 
    607     Transliterator *t =
    608         instantiateEntry(ID, entry, aliasReturn, status);
    609     return t;
    610 }
    611 
    612 void TransliteratorRegistry::put(Transliterator* adoptedProto,
    613                                  UBool visible,
    614                                  UErrorCode& ec)
    615 {
    616     TransliteratorEntry *entry = new TransliteratorEntry();
    617     if (entry == NULL) {
    618         ec = U_MEMORY_ALLOCATION_ERROR;
    619         return;
    620     }
    621     entry->adoptPrototype(adoptedProto);
    622     registerEntry(adoptedProto->getID(), entry, visible);
    623 }
    624 
    625 void TransliteratorRegistry::put(const UnicodeString& ID,
    626                                  Transliterator::Factory factory,
    627                                  Transliterator::Token context,
    628                                  UBool visible,
    629                                  UErrorCode& ec) {
    630     TransliteratorEntry *entry = new TransliteratorEntry();
    631     if (entry == NULL) {
    632         ec = U_MEMORY_ALLOCATION_ERROR;
    633         return;
    634     }
    635     entry->setFactory(factory, context);
    636     registerEntry(ID, entry, visible);
    637 }
    638 
    639 void TransliteratorRegistry::put(const UnicodeString& ID,
    640                                  const UnicodeString& resourceName,
    641                                  UTransDirection dir,
    642                                  UBool readonlyResourceAlias,
    643                                  UBool visible,
    644                                  UErrorCode& ec) {
    645     TransliteratorEntry *entry = new TransliteratorEntry();
    646     if (entry == NULL) {
    647         ec = U_MEMORY_ALLOCATION_ERROR;
    648         return;
    649     }
    650     entry->entryType = (dir == UTRANS_FORWARD) ? TransliteratorEntry::RULES_FORWARD
    651         : TransliteratorEntry::RULES_REVERSE;
    652     if (readonlyResourceAlias) {
    653         entry->stringArg.setTo(TRUE, resourceName.getBuffer(), -1);
    654     }
    655     else {
    656         entry->stringArg = resourceName;
    657     }
    658     registerEntry(ID, entry, visible);
    659 }
    660 
    661 void TransliteratorRegistry::put(const UnicodeString& ID,
    662                                  const UnicodeString& alias,
    663                                  UBool readonlyAliasAlias,
    664                                  UBool visible,
    665                                  UErrorCode& /*ec*/) {
    666     TransliteratorEntry *entry = new TransliteratorEntry();
    667     // Null pointer check
    668     if (entry != NULL) {
    669         entry->entryType = TransliteratorEntry::ALIAS;
    670         if (readonlyAliasAlias) {
    671             entry->stringArg.setTo(TRUE, alias.getBuffer(), -1);
    672         }
    673         else {
    674             entry->stringArg = alias;
    675         }
    676         registerEntry(ID, entry, visible);
    677     }
    678 }
    679 
    680 void TransliteratorRegistry::remove(const UnicodeString& ID) {
    681     UnicodeString source, target, variant;
    682     UBool sawSource;
    683     TransliteratorIDParser::IDtoSTV(ID, source, target, variant, sawSource);
    684     // Only need to do this if ID.indexOf('-') < 0
    685     UnicodeString id;
    686     TransliteratorIDParser::STVtoID(source, target, variant, id);
    687     registry.remove(id);
    688     removeSTV(source, target, variant);
    689     availableIDs.removeElement((void*) &id);
    690 }
    691 
    692 //----------------------------------------------------------------------
    693 // class TransliteratorRegistry: Public ID and spec management
    694 //----------------------------------------------------------------------
    695 
    696 /**
    697  * == OBSOLETE - remove in ICU 3.4 ==
    698  * Return the number of IDs currently registered with the system.
    699  * To retrieve the actual IDs, call getAvailableID(i) with
    700  * i from 0 to countAvailableIDs() - 1.
    701  */
    702 int32_t TransliteratorRegistry::countAvailableIDs(void) const {
    703     return availableIDs.size();
    704 }
    705 
    706 /**
    707  * == OBSOLETE - remove in ICU 3.4 ==
    708  * Return the index-th available ID.  index must be between 0
    709  * and countAvailableIDs() - 1, inclusive.  If index is out of
    710  * range, the result of getAvailableID(0) is returned.
    711  */
    712 const UnicodeString& TransliteratorRegistry::getAvailableID(int32_t index) const {
    713     if (index < 0 || index >= availableIDs.size()) {
    714         index = 0;
    715     }
    716     return *(const UnicodeString*) availableIDs[index];
    717 }
    718 
    719 StringEnumeration* TransliteratorRegistry::getAvailableIDs() const {
    720     return new Enumeration(*this);
    721 }
    722 
    723 int32_t TransliteratorRegistry::countAvailableSources(void) const {
    724     return specDAG.count();
    725 }
    726 
    727 UnicodeString& TransliteratorRegistry::getAvailableSource(int32_t index,
    728                                                           UnicodeString& result) const {
    729     int32_t pos = -1;
    730     const UHashElement *e = 0;
    731     while (index-- >= 0) {
    732         e = specDAG.nextElement(pos);
    733         if (e == 0) {
    734             break;
    735         }
    736     }
    737     if (e == 0) {
    738         result.truncate(0);
    739     } else {
    740         result = *(UnicodeString*) e->key.pointer;
    741     }
    742     return result;
    743 }
    744 
    745 int32_t TransliteratorRegistry::countAvailableTargets(const UnicodeString& source) const {
    746     Hashtable *targets = (Hashtable*) specDAG.get(source);
    747     return (targets == 0) ? 0 : targets->count();
    748 }
    749 
    750 UnicodeString& TransliteratorRegistry::getAvailableTarget(int32_t index,
    751                                                           const UnicodeString& source,
    752                                                           UnicodeString& result) const {
    753     Hashtable *targets = (Hashtable*) specDAG.get(source);
    754     if (targets == 0) {
    755         result.truncate(0); // invalid source
    756         return result;
    757     }
    758     int32_t pos = -1;
    759     const UHashElement *e = 0;
    760     while (index-- >= 0) {
    761         e = targets->nextElement(pos);
    762         if (e == 0) {
    763             break;
    764         }
    765     }
    766     if (e == 0) {
    767         result.truncate(0); // invalid index
    768     } else {
    769         result = *(UnicodeString*) e->key.pointer;
    770     }
    771     return result;
    772 }
    773 
    774 int32_t TransliteratorRegistry::countAvailableVariants(const UnicodeString& source,
    775                                                        const UnicodeString& target) const {
    776     Hashtable *targets = (Hashtable*) specDAG.get(source);
    777     if (targets == 0) {
    778         return 0;
    779     }
    780     UVector *variants = (UVector*) targets->get(target);
    781     // variants may be 0 if the source/target are invalid
    782     return (variants == 0) ? 0 : variants->size();
    783 }
    784 
    785 UnicodeString& TransliteratorRegistry::getAvailableVariant(int32_t index,
    786                                                            const UnicodeString& source,
    787                                                            const UnicodeString& target,
    788                                                            UnicodeString& result) const {
    789     Hashtable *targets = (Hashtable*) specDAG.get(source);
    790     if (targets == 0) {
    791         result.truncate(0); // invalid source
    792         return result;
    793     }
    794     UVector *variants = (UVector*) targets->get(target);
    795     if (variants == 0) {
    796         result.truncate(0); // invalid target
    797         return result;
    798     }
    799     UnicodeString *v = (UnicodeString*) variants->elementAt(index);
    800     if (v == 0) {
    801         result.truncate(0); // invalid index
    802     } else {
    803         result = *v;
    804     }
    805     return result;
    806 }
    807 
    808 //----------------------------------------------------------------------
    809 // class TransliteratorRegistry::Enumeration
    810 //----------------------------------------------------------------------
    811 
    812 TransliteratorRegistry::Enumeration::Enumeration(const TransliteratorRegistry& _reg) :
    813     index(0), reg(_reg) {
    814 }
    815 
    816 TransliteratorRegistry::Enumeration::~Enumeration() {
    817 }
    818 
    819 int32_t TransliteratorRegistry::Enumeration::count(UErrorCode& /*status*/) const {
    820     return reg.availableIDs.size();
    821 }
    822 
    823 const UnicodeString* TransliteratorRegistry::Enumeration::snext(UErrorCode& status) {
    824     // This is sloppy but safe -- if we get out of sync with the underlying
    825     // registry, we will still return legal strings, but they might not
    826     // correspond to the snapshot at construction time.  So there could be
    827     // duplicate IDs or omitted IDs if insertions or deletions occur in one
    828     // thread while another is iterating.  To be more rigorous, add a timestamp,
    829     // which is incremented with any modification, and validate this iterator
    830     // against the timestamp at construction time.  This probably isn't worth
    831     // doing as long as there is some possibility of removing this code in favor
    832     // of some new code based on Doug's service framework.
    833     if (U_FAILURE(status)) {
    834         return NULL;
    835     }
    836     int32_t n = reg.availableIDs.size();
    837     if (index > n) {
    838         status = U_ENUM_OUT_OF_SYNC_ERROR;
    839     }
    840     // index == n is okay -- this means we've reached the end
    841     if (index < n) {
    842         // Copy the string! This avoids lifetime problems.
    843         unistr = *(const UnicodeString*)reg.availableIDs[index++];
    844         return &unistr;
    845     } else {
    846         return NULL;
    847     }
    848 }
    849 
    850 void TransliteratorRegistry::Enumeration::reset(UErrorCode& /*status*/) {
    851     index = 0;
    852 }
    853 
    854 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TransliteratorRegistry::Enumeration)
    855 
    856 //----------------------------------------------------------------------
    857 // class TransliteratorRegistry: internal
    858 //----------------------------------------------------------------------
    859 
    860 /**
    861  * Convenience method.  Calls 6-arg registerEntry().
    862  */
    863 void TransliteratorRegistry::registerEntry(const UnicodeString& source,
    864                                            const UnicodeString& target,
    865                                            const UnicodeString& variant,
    866                                            TransliteratorEntry* adopted,
    867                                            UBool visible) {
    868     UnicodeString ID;
    869     UnicodeString s(source);
    870     if (s.length() == 0) {
    871         s = ANY;
    872     }
    873     TransliteratorIDParser::STVtoID(source, target, variant, ID);
    874     registerEntry(ID, s, target, variant, adopted, visible);
    875 }
    876 
    877 /**
    878  * Convenience method.  Calls 6-arg registerEntry().
    879  */
    880 void TransliteratorRegistry::registerEntry(const UnicodeString& ID,
    881                                            TransliteratorEntry* adopted,
    882                                            UBool visible) {
    883     UnicodeString source, target, variant;
    884     UBool sawSource;
    885     TransliteratorIDParser::IDtoSTV(ID, source, target, variant, sawSource);
    886     // Only need to do this if ID.indexOf('-') < 0
    887     UnicodeString id;
    888     TransliteratorIDParser::STVtoID(source, target, variant, id);
    889     registerEntry(id, source, target, variant, adopted, visible);
    890 }
    891 
    892 /**
    893  * Register an entry object (adopted) with the given ID, source,
    894  * target, and variant strings.
    895  */
    896 void TransliteratorRegistry::registerEntry(const UnicodeString& ID,
    897                                            const UnicodeString& source,
    898                                            const UnicodeString& target,
    899                                            const UnicodeString& variant,
    900                                            TransliteratorEntry* adopted,
    901                                            UBool visible) {
    902     UErrorCode status = U_ZERO_ERROR;
    903     registry.put(ID, adopted, status);
    904     if (visible) {
    905         registerSTV(source, target, variant);
    906         if (!availableIDs.contains((void*) &ID)) {
    907             UnicodeString *newID = (UnicodeString *)ID.clone();
    908             // Check to make sure newID was created.
    909             if (newID != NULL) {
    910 	            // NUL-terminate the ID string
    911 	            newID->getTerminatedBuffer();
    912 	            availableIDs.addElement(newID, status);
    913             }
    914         }
    915     } else {
    916         removeSTV(source, target, variant);
    917         availableIDs.removeElement((void*) &ID);
    918     }
    919 }
    920 
    921 /**
    922  * Register a source-target/variant in the specDAG.  Variant may be
    923  * empty, but source and target must not be.  If variant is empty then
    924  * the special variant NO_VARIANT is stored in slot zero of the
    925  * UVector of variants.
    926  */
    927 void TransliteratorRegistry::registerSTV(const UnicodeString& source,
    928                                          const UnicodeString& target,
    929                                          const UnicodeString& variant) {
    930     // assert(source.length() > 0);
    931     // assert(target.length() > 0);
    932     UErrorCode status = U_ZERO_ERROR;
    933     Hashtable *targets = (Hashtable*) specDAG.get(source);
    934     if (targets == 0) {
    935         targets = new Hashtable(TRUE, status);
    936         if (U_FAILURE(status) || targets == 0) {
    937             return;
    938         }
    939         targets->setValueDeleter(uhash_deleteUVector);
    940         specDAG.put(source, targets, status);
    941     }
    942     UVector *variants = (UVector*) targets->get(target);
    943     if (variants == 0) {
    944         variants = new UVector(uhash_deleteUnicodeString,
    945                                uhash_compareCaselessUnicodeString, status);
    946         if (variants == 0) {
    947             return;
    948         }
    949         targets->put(target, variants, status);
    950     }
    951     // assert(NO_VARIANT == "");
    952     // We add the variant string.  If it is the special "no variant"
    953     // string, that is, the empty string, we add it at position zero.
    954     if (!variants->contains((void*) &variant)) {
    955     	UnicodeString *tempus; // Used for null pointer check.
    956         if (variant.length() > 0) {
    957         	tempus = new UnicodeString(variant);
    958         	if (tempus != NULL) {
    959         		variants->addElement(tempus, status);
    960         	}
    961         } else {
    962         	tempus = new UnicodeString(NO_VARIANT) ;
    963         	if (tempus != NULL) {
    964         		variants->insertElementAt(tempus, 0, status);
    965         	}
    966         }
    967     }
    968 }
    969 
    970 /**
    971  * Remove a source-target/variant from the specDAG.
    972  */
    973 void TransliteratorRegistry::removeSTV(const UnicodeString& source,
    974                                        const UnicodeString& target,
    975                                        const UnicodeString& variant) {
    976     // assert(source.length() > 0);
    977     // assert(target.length() > 0);
    978 //    UErrorCode status = U_ZERO_ERROR;
    979     Hashtable *targets = (Hashtable*) specDAG.get(source);
    980     if (targets == 0) {
    981         return; // should never happen for valid s-t/v
    982     }
    983     UVector *variants = (UVector*) targets->get(target);
    984     if (variants == 0) {
    985         return; // should never happen for valid s-t/v
    986     }
    987     variants->removeElement((void*) &variant);
    988     if (variants->size() == 0) {
    989         targets->remove(target); // should delete variants
    990         if (targets->count() == 0) {
    991             specDAG.remove(source); // should delete targets
    992         }
    993     }
    994 }
    995 
    996 /**
    997  * Attempt to find a source-target/variant in the dynamic registry
    998  * store.  Return 0 on failure.
    999  *
   1000  * Caller does NOT own returned object.
   1001  */
   1002 TransliteratorEntry* TransliteratorRegistry::findInDynamicStore(const TransliteratorSpec& src,
   1003                                                   const TransliteratorSpec& trg,
   1004                                                   const UnicodeString& variant) const {
   1005     UnicodeString ID;
   1006     TransliteratorIDParser::STVtoID(src, trg, variant, ID);
   1007     TransliteratorEntry *e = (TransliteratorEntry*) registry.get(ID);
   1008     DEBUG_useEntry(e);
   1009     return e;
   1010 }
   1011 
   1012 /**
   1013  * Attempt to find a source-target/variant in the static locale
   1014  * resource store.  Do not perform fallback.  Return 0 on failure.
   1015  *
   1016  * On success, create a new entry object, register it in the dynamic
   1017  * store, and return a pointer to it, but do not make it public --
   1018  * just because someone requested something, we do not expand the
   1019  * available ID list (or spec DAG).
   1020  *
   1021  * Caller does NOT own returned object.
   1022  */
   1023 TransliteratorEntry* TransliteratorRegistry::findInStaticStore(const TransliteratorSpec& src,
   1024                                                  const TransliteratorSpec& trg,
   1025                                                  const UnicodeString& variant) {
   1026     TransliteratorEntry* entry = 0;
   1027     if (src.isLocale()) {
   1028         entry = findInBundle(src, trg, variant, UTRANS_FORWARD);
   1029     } else if (trg.isLocale()) {
   1030         entry = findInBundle(trg, src, variant, UTRANS_REVERSE);
   1031     }
   1032 
   1033     // If we found an entry, store it in the Hashtable for next
   1034     // time.
   1035     if (entry != 0) {
   1036         registerEntry(src.getTop(), trg.getTop(), variant, entry, FALSE);
   1037     }
   1038 
   1039     return entry;
   1040 }
   1041 
   1042 // As of 2.0, resource bundle keys cannot contain '_'
   1043 static const UChar TRANSLITERATE_TO[] = {84,114,97,110,115,108,105,116,101,114,97,116,101,84,111,0}; // "TransliterateTo"
   1044 
   1045 static const UChar TRANSLITERATE_FROM[] = {84,114,97,110,115,108,105,116,101,114,97,116,101,70,114,111,109,0}; // "TransliterateFrom"
   1046 
   1047 static const UChar TRANSLITERATE[] = {84,114,97,110,115,108,105,116,101,114,97,116,101,0}; // "Transliterate"
   1048 
   1049 /**
   1050  * Attempt to find an entry in a single resource bundle.  This is
   1051  * a one-sided lookup.  findInStaticStore() performs up to two such
   1052  * lookups, one for the source, and one for the target.
   1053  *
   1054  * Do not perform fallback.  Return 0 on failure.
   1055  *
   1056  * On success, create a new Entry object, populate it, and return it.
   1057  * The caller owns the returned object.
   1058  */
   1059 TransliteratorEntry* TransliteratorRegistry::findInBundle(const TransliteratorSpec& specToOpen,
   1060                                             const TransliteratorSpec& specToFind,
   1061                                             const UnicodeString& variant,
   1062                                             UTransDirection direction)
   1063 {
   1064     UnicodeString utag;
   1065     UnicodeString resStr;
   1066     int32_t pass;
   1067 
   1068     for (pass=0; pass<2; ++pass) {
   1069         utag.truncate(0);
   1070         // First try either TransliteratorTo_xxx or
   1071         // TransliterateFrom_xxx, then try the bidirectional
   1072         // Transliterate_xxx.  This precedence order is arbitrary
   1073         // but must be consistent and documented.
   1074         if (pass == 0) {
   1075             utag.append(direction == UTRANS_FORWARD ?
   1076                         TRANSLITERATE_TO : TRANSLITERATE_FROM);
   1077         } else {
   1078             utag.append(TRANSLITERATE);
   1079         }
   1080         UnicodeString s(specToFind.get());
   1081         utag.append(s.toUpper(""));
   1082         CharString tag(utag);
   1083 
   1084         UErrorCode status = U_ZERO_ERROR;
   1085         ResourceBundle subres(specToOpen.getBundle().get(tag, status));
   1086         if (U_FAILURE(status) || status == U_USING_DEFAULT_WARNING) {
   1087             continue;
   1088         }
   1089 
   1090         s.truncate(0);
   1091         if (specToOpen.get() != LocaleUtility::initNameFromLocale(subres.getLocale(), s)) {
   1092             continue;
   1093         }
   1094 
   1095         if (variant.length() != 0) {
   1096             CharString var(variant);
   1097             status = U_ZERO_ERROR;
   1098             resStr = subres.getStringEx(var, status);
   1099             if (U_SUCCESS(status)) {
   1100                 // Exit loop successfully
   1101                 break;
   1102             }
   1103         }
   1104 
   1105         else {
   1106             // Variant is empty, which means match the first variant listed.
   1107             status = U_ZERO_ERROR;
   1108             resStr = subres.getStringEx(1, status);
   1109             if (U_SUCCESS(status)) {
   1110                 // Exit loop successfully
   1111                 break;
   1112             }
   1113         }
   1114     }
   1115 
   1116     if (pass==2) {
   1117         // Failed
   1118         return NULL;
   1119     }
   1120 
   1121     // We have succeeded in loading a string from the locale
   1122     // resources.  Create a new registry entry to hold it and return it.
   1123     TransliteratorEntry *entry = new TransliteratorEntry();
   1124     if (entry != 0) {
   1125         // The direction is always forward for the
   1126         // TransliterateTo_xxx and TransliterateFrom_xxx
   1127         // items; those are unidirectional forward rules.
   1128         // For the bidirectional Transliterate_xxx items,
   1129         // the direction is the value passed in to this
   1130         // function.
   1131         int32_t dir = (pass == 0) ? UTRANS_FORWARD : direction;
   1132         entry->entryType = TransliteratorEntry::LOCALE_RULES;
   1133         entry->stringArg = resStr;
   1134         entry->intArg = dir;
   1135     }
   1136 
   1137     return entry;
   1138 }
   1139 
   1140 /**
   1141  * Convenience method.  Calls 3-arg find().
   1142  */
   1143 TransliteratorEntry* TransliteratorRegistry::find(const UnicodeString& ID) {
   1144     UnicodeString source, target, variant;
   1145     UBool sawSource;
   1146     TransliteratorIDParser::IDtoSTV(ID, source, target, variant, sawSource);
   1147     return find(source, target, variant);
   1148 }
   1149 
   1150 /**
   1151  * Top-level find method.  Attempt to find a source-target/variant in
   1152  * either the dynamic or the static (locale resource) store.  Perform
   1153  * fallback.
   1154  *
   1155  * Lookup sequence for ss_SS_SSS-tt_TT_TTT/v:
   1156  *
   1157  *   ss_SS_SSS-tt_TT_TTT/v -- in hashtable
   1158  *   ss_SS_SSS-tt_TT_TTT/v -- in ss_SS_SSS (no fallback)
   1159  *
   1160  *     repeat with t = tt_TT_TTT, tt_TT, tt, and tscript
   1161  *
   1162  *     ss_SS_SSS-t/ *
   1163  *     ss_SS-t/ *
   1164  *     ss-t/ *
   1165  *     sscript-t/ *
   1166  *
   1167  * Here * matches the first variant listed.
   1168  *
   1169  * Caller does NOT own returned object.  Return 0 on failure.
   1170  */
   1171 TransliteratorEntry* TransliteratorRegistry::find(UnicodeString& source,
   1172                                     UnicodeString& target,
   1173                                     UnicodeString& variant) {
   1174 
   1175     TransliteratorSpec src(source);
   1176     TransliteratorSpec trg(target);
   1177     TransliteratorEntry* entry;
   1178 
   1179     if (variant.length() != 0) {
   1180 
   1181         // Seek exact match in hashtable
   1182         entry = findInDynamicStore(src, trg, variant);
   1183         if (entry != 0) {
   1184             return entry;
   1185         }
   1186 
   1187         // Seek exact match in locale resources
   1188         entry = findInStaticStore(src, trg, variant);
   1189         if (entry != 0) {
   1190             return entry;
   1191         }
   1192     }
   1193 
   1194     for (;;) {
   1195         src.reset();
   1196         for (;;) {
   1197             // Seek match in hashtable
   1198             entry = findInDynamicStore(src, trg, NO_VARIANT);
   1199             if (entry != 0) {
   1200                 return entry;
   1201             }
   1202 
   1203             // Seek match in locale resources
   1204             entry = findInStaticStore(src, trg, NO_VARIANT);
   1205             if (entry != 0) {
   1206                 return entry;
   1207             }
   1208             if (!src.hasFallback()) {
   1209                 break;
   1210             }
   1211             src.next();
   1212         }
   1213         if (!trg.hasFallback()) {
   1214             break;
   1215         }
   1216         trg.next();
   1217     }
   1218 
   1219     return 0;
   1220 }
   1221 
   1222 /**
   1223  * Given an Entry object, instantiate it.  Caller owns result.  Return
   1224  * 0 on failure.
   1225  *
   1226  * Return a non-empty aliasReturn value if the ID points to an alias.
   1227  * We cannot instantiate it ourselves because the alias may contain
   1228  * filters or compounds, which we do not understand.  Caller should
   1229  * make aliasReturn empty before calling.
   1230  *
   1231  * The entry object is assumed to reside in the dynamic store.  It may be
   1232  * modified.
   1233  */
   1234 Transliterator* TransliteratorRegistry::instantiateEntry(const UnicodeString& ID,
   1235                                                          TransliteratorEntry *entry,
   1236                                                          TransliteratorAlias* &aliasReturn,
   1237                                                          UErrorCode& status) {
   1238     Transliterator *t = 0;
   1239     U_ASSERT(aliasReturn == 0);
   1240 
   1241     switch (entry->entryType) {
   1242     case TransliteratorEntry::RBT_DATA:
   1243         t = new RuleBasedTransliterator(ID, entry->u.data);
   1244         if (t == 0) {
   1245             status = U_MEMORY_ALLOCATION_ERROR;
   1246         }
   1247         return t;
   1248     case TransliteratorEntry::PROTOTYPE:
   1249         t = entry->u.prototype->clone();
   1250         if (t == 0) {
   1251             status = U_MEMORY_ALLOCATION_ERROR;
   1252         }
   1253         return t;
   1254     case TransliteratorEntry::ALIAS:
   1255         aliasReturn = new TransliteratorAlias(entry->stringArg, entry->compoundFilter);
   1256         if (aliasReturn == 0) {
   1257             status = U_MEMORY_ALLOCATION_ERROR;
   1258         }
   1259         return 0;
   1260     case TransliteratorEntry::FACTORY:
   1261         t = entry->u.factory.function(ID, entry->u.factory.context);
   1262         if (t == 0) {
   1263             status = U_MEMORY_ALLOCATION_ERROR;
   1264         }
   1265         return t;
   1266     case TransliteratorEntry::COMPOUND_RBT:
   1267         {
   1268             UVector* rbts = new UVector(entry->u.dataVector->size(), status);
   1269             // Check for null pointer
   1270             if (rbts == NULL) {
   1271             	status = U_MEMORY_ALLOCATION_ERROR;
   1272             	return NULL;
   1273             }
   1274             int32_t passNumber = 1;
   1275             for (int32_t i = 0; U_SUCCESS(status) && i < entry->u.dataVector->size(); i++) {
   1276                 Transliterator* t = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + (passNumber++),
   1277                     (TransliterationRuleData*)(entry->u.dataVector->elementAt(i)), FALSE);
   1278                 if (t == 0)
   1279                     status = U_MEMORY_ALLOCATION_ERROR;
   1280                 else
   1281                     rbts->addElement(t, status);
   1282             }
   1283             if (U_FAILURE(status)) {
   1284                 delete rbts;
   1285                 return 0;
   1286             }
   1287             aliasReturn = new TransliteratorAlias(ID, entry->stringArg, rbts, entry->compoundFilter);
   1288         }
   1289         if (aliasReturn == 0) {
   1290             status = U_MEMORY_ALLOCATION_ERROR;
   1291         }
   1292         return 0;
   1293     case TransliteratorEntry::LOCALE_RULES:
   1294         aliasReturn = new TransliteratorAlias(ID, entry->stringArg,
   1295                                               (UTransDirection) entry->intArg);
   1296         if (aliasReturn == 0) {
   1297             status = U_MEMORY_ALLOCATION_ERROR;
   1298         }
   1299         return 0;
   1300     case TransliteratorEntry::RULES_FORWARD:
   1301     case TransliteratorEntry::RULES_REVERSE:
   1302         // Process the rule data into a TransliteratorRuleData object,
   1303         // and possibly also into an ::id header and/or footer.  Then
   1304         // we modify the registry with the parsed data and retry.
   1305         {
   1306             TransliteratorParser parser(status);
   1307 
   1308             // We use the file name, taken from another resource bundle
   1309             // 2-d array at static init time, as a locale language.  We're
   1310             // just using the locale mechanism to map through to a file
   1311             // name; this in no way represents an actual locale.
   1312             //CharString ch(entry->stringArg);
   1313             //UResourceBundle *bundle = ures_openDirect(0, ch, &status);
   1314             UnicodeString rules = entry->stringArg;
   1315             //ures_close(bundle);
   1316 
   1317             //if (U_FAILURE(status)) {
   1318                 // We have a failure of some kind.  Remove the ID from the
   1319                 // registry so we don't keep trying.  NOTE: This will throw off
   1320                 // anyone who is, at the moment, trying to iterate over the
   1321                 // available IDs.  That's acceptable since we should never
   1322                 // really get here except under installation, configuration,
   1323                 // or unrecoverable run time memory failures.
   1324             //    remove(ID);
   1325             //} else {
   1326 
   1327                 // If the status indicates a failure, then we don't have any
   1328                 // rules -- there is probably an installation error.  The list
   1329                 // in the root locale should correspond to all the installed
   1330                 // transliterators; if it lists something that's not
   1331                 // installed, we'll get an error from ResourceBundle.
   1332                 aliasReturn = new TransliteratorAlias(ID, rules,
   1333                     ((entry->entryType == TransliteratorEntry::RULES_REVERSE) ?
   1334                      UTRANS_REVERSE : UTRANS_FORWARD));
   1335                 if (aliasReturn == 0) {
   1336                     status = U_MEMORY_ALLOCATION_ERROR;
   1337                 }
   1338             //}
   1339         }
   1340         return 0;
   1341     default:
   1342         U_ASSERT(FALSE); // can't get here
   1343         return 0;
   1344     }
   1345 }
   1346 U_NAMESPACE_END
   1347 
   1348 #endif /* #if !UCONFIG_NO_TRANSLITERATION */
   1349 
   1350 //eof
   1351