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