1 /* 2 ********************************************************************** 3 * Copyright (c) 2001-2008, International Business Machines 4 * Corporation and others. All Rights Reserved. 5 ********************************************************************** 6 * Date Name Description 7 * 08/10/2001 aliu Creation. 8 ********************************************************************** 9 */ 10 #ifndef _TRANSREG_H 11 #define _TRANSREG_H 12 13 #include "unicode/utypes.h" 14 15 #if !UCONFIG_NO_TRANSLITERATION 16 17 #include "unicode/uobject.h" 18 #include "unicode/translit.h" 19 #include "hash.h" 20 #include "uvector.h" 21 22 U_NAMESPACE_BEGIN 23 24 class TransliteratorEntry; 25 class TransliteratorSpec; 26 class UnicodeString; 27 28 //------------------------------------------------------------------ 29 // TransliteratorAlias 30 //------------------------------------------------------------------ 31 32 /** 33 * A TransliteratorAlias object is returned by get() if the given ID 34 * actually translates into something else. The caller then invokes 35 * the create() method on the alias to create the actual 36 * transliterator, and deletes the alias. 37 * 38 * Why all the shenanigans? To prevent circular calls between 39 * the registry code and the transliterator code that deadlocks. 40 */ 41 class TransliteratorAlias : public UMemory { 42 public: 43 /** 44 * Construct a simple alias (type == SIMPLE) 45 * @param aliasID the given id. 46 */ 47 TransliteratorAlias(const UnicodeString& aliasID, const UnicodeSet* compoundFilter); 48 49 /** 50 * Construct a compound RBT alias (type == COMPOUND) 51 */ 52 TransliteratorAlias(const UnicodeString& ID, const UnicodeString& idBlocks, 53 UVector* adoptedTransliterators, 54 const UnicodeSet* compoundFilter); 55 56 /** 57 * Construct a rules alias (type = RULES) 58 */ 59 TransliteratorAlias(const UnicodeString& theID, 60 const UnicodeString& rules, 61 UTransDirection dir); 62 63 ~TransliteratorAlias(); 64 65 /** 66 * The whole point of create() is that the caller must invoke 67 * it when the registry mutex is NOT held, to prevent deadlock. 68 * It may only be called once. 69 * 70 * Note: Only call create() if isRuleBased() returns FALSE. 71 * 72 * This method must be called *outside* of the TransliteratorRegistry 73 * mutex. 74 */ 75 Transliterator* create(UParseError&, UErrorCode&); 76 77 /** 78 * Return TRUE if this alias is rule-based. If so, the caller 79 * must call parse() on it, then call TransliteratorRegistry::reget(). 80 */ 81 UBool isRuleBased() const; 82 83 /** 84 * If isRuleBased() returns TRUE, then the caller must call this 85 * method, followed by TransliteratorRegistry::reget(). The latter 86 * method must be called inside the TransliteratorRegistry mutex. 87 * 88 * Note: Only call parse() if isRuleBased() returns TRUE. 89 * 90 * This method must be called *outside* of the TransliteratorRegistry 91 * mutex, because it can instantiate Transliterators embedded in 92 * the rules via the "&Latin-Arabic()" syntax. 93 */ 94 void parse(TransliteratorParser& parser, 95 UParseError& pe, UErrorCode& ec) const; 96 97 private: 98 // We actually come in three flavors: 99 // 1. Simple alias 100 // Here aliasID is the alias string. Everything else is 101 // null, zero, empty. 102 // 2. CompoundRBT 103 // Here ID is the ID, aliasID is the idBlock, trans is the 104 // contained RBT, and idSplitPoint is the offet in aliasID 105 // where the contained RBT goes. compoundFilter is the 106 // compound filter, and it is _not_ owned. 107 // 3. Rules 108 // Here ID is the ID, aliasID is the rules string. 109 // idSplitPoint is the UTransDirection. 110 UnicodeString ID; 111 UnicodeString aliasesOrRules; 112 UVector* transes; // owned 113 const UnicodeSet* compoundFilter; // alias 114 UTransDirection direction; 115 enum { SIMPLE, COMPOUND, RULES } type; 116 117 TransliteratorAlias(const TransliteratorAlias &other); // forbid copying of this class 118 TransliteratorAlias &operator=(const TransliteratorAlias &other); // forbid copying of this class 119 }; 120 121 122 /** 123 * A registry of system transliterators. This is the data structure 124 * that implements the mapping between transliterator IDs and the data 125 * or function pointers used to create the corresponding 126 * transliterators. There is one instance of the registry that is 127 * created statically. 128 * 129 * The registry consists of a dynamic component -- a hashtable -- and 130 * a static component -- locale resource bundles. The dynamic store 131 * is semantically overlaid on the static store, so the static mapping 132 * can be dynamically overridden. 133 * 134 * This is an internal class that is only used by Transliterator. 135 * Transliterator maintains one static instance of this class and 136 * delegates all registry-related operations to it. 137 * 138 * @author Alan Liu 139 */ 140 class TransliteratorRegistry : public UMemory { 141 142 public: 143 144 /** 145 * Contructor 146 * @param status Output param set to success/failure code. 147 */ 148 TransliteratorRegistry(UErrorCode& status); 149 150 /** 151 * Nonvirtual destructor -- this class is not subclassable. 152 */ 153 ~TransliteratorRegistry(); 154 155 //------------------------------------------------------------------ 156 // Basic public API 157 //------------------------------------------------------------------ 158 159 /** 160 * Given a simple ID (forward direction, no inline filter, not 161 * compound) attempt to instantiate it from the registry. Return 162 * 0 on failure. 163 * 164 * Return a non-NULL aliasReturn value if the ID points to an alias. 165 * We cannot instantiate it ourselves because the alias may contain 166 * filters or compounds, which we do not understand. Caller should 167 * make aliasReturn NULL before calling. 168 * @param ID the given ID 169 * @param aliasReturn output param to receive TransliteratorAlias; 170 * should be NULL on entry 171 * @param parseError Struct to recieve information on position 172 * of error if an error is encountered 173 * @param status Output param set to success/failure code. 174 */ 175 Transliterator* get(const UnicodeString& ID, 176 TransliteratorAlias*& aliasReturn, 177 UErrorCode& status); 178 179 /** 180 * The caller must call this after calling get(), if [a] calling get() 181 * returns an alias, and [b] the alias is rule based. In that 182 * situation the caller must call alias->parse() to do the parsing 183 * OUTSIDE THE REGISTRY MUTEX, then call this method to retry 184 * instantiating the transliterator. 185 * 186 * Note: Another alias might be returned by this method. 187 * 188 * This method (like all public methods of this class) must be called 189 * from within the TransliteratorRegistry mutex. 190 * 191 * @param aliasReturn output param to receive TransliteratorAlias; 192 * should be NULL on entry 193 */ 194 Transliterator* reget(const UnicodeString& ID, 195 TransliteratorParser& parser, 196 TransliteratorAlias*& aliasReturn, 197 UErrorCode& status); 198 199 /** 200 * Register a prototype (adopted). This adds an entry to the 201 * dynamic store, or replaces an existing entry. Any entry in the 202 * underlying static locale resource store is masked. 203 */ 204 void put(Transliterator* adoptedProto, 205 UBool visible, 206 UErrorCode& ec); 207 208 /** 209 * Register an ID and a factory function pointer. This adds an 210 * entry to the dynamic store, or replaces an existing entry. Any 211 * entry in the underlying static locale resource store is masked. 212 */ 213 void put(const UnicodeString& ID, 214 Transliterator::Factory factory, 215 Transliterator::Token context, 216 UBool visible, 217 UErrorCode& ec); 218 219 /** 220 * Register an ID and a resource name. This adds an entry to the 221 * dynamic store, or replaces an existing entry. Any entry in the 222 * underlying static locale resource store is masked. 223 */ 224 void put(const UnicodeString& ID, 225 const UnicodeString& resourceName, 226 UTransDirection dir, 227 UBool readonlyResourceAlias, 228 UBool visible, 229 UErrorCode& ec); 230 231 /** 232 * Register an ID and an alias ID. This adds an entry to the 233 * dynamic store, or replaces an existing entry. Any entry in the 234 * underlying static locale resource store is masked. 235 */ 236 void put(const UnicodeString& ID, 237 const UnicodeString& alias, 238 UBool readonlyAliasAlias, 239 UBool visible, 240 UErrorCode& ec); 241 242 /** 243 * Unregister an ID. This removes an entry from the dynamic store 244 * if there is one. The static locale resource store is 245 * unaffected. 246 * @param ID the given ID. 247 */ 248 void remove(const UnicodeString& ID); 249 250 //------------------------------------------------------------------ 251 // Public ID and spec management 252 //------------------------------------------------------------------ 253 254 /** 255 * Return a StringEnumeration over the IDs currently registered 256 * with the system. 257 * @internal 258 */ 259 StringEnumeration* getAvailableIDs() const; 260 261 /** 262 * == OBSOLETE - remove in ICU 3.4 == 263 * Return the number of IDs currently registered with the system. 264 * To retrieve the actual IDs, call getAvailableID(i) with 265 * i from 0 to countAvailableIDs() - 1. 266 * @return the number of IDs currently registered with the system. 267 * @internal 268 */ 269 int32_t countAvailableIDs(void) const; 270 271 /** 272 * == OBSOLETE - remove in ICU 3.4 == 273 * Return the index-th available ID. index must be between 0 274 * and countAvailableIDs() - 1, inclusive. If index is out of 275 * range, the result of getAvailableID(0) is returned. 276 * @param index the given index. 277 * @return the index-th available ID. index must be between 0 278 * and countAvailableIDs() - 1, inclusive. If index is out of 279 * range, the result of getAvailableID(0) is returned. 280 * @internal 281 */ 282 const UnicodeString& getAvailableID(int32_t index) const; 283 284 /** 285 * Return the number of registered source specifiers. 286 * @return the number of registered source specifiers. 287 */ 288 int32_t countAvailableSources(void) const; 289 290 /** 291 * Return a registered source specifier. 292 * @param index which specifier to return, from 0 to n-1, where 293 * n = countAvailableSources() 294 * @param result fill-in paramter to receive the source specifier. 295 * If index is out of range, result will be empty. 296 * @return reference to result 297 */ 298 UnicodeString& getAvailableSource(int32_t index, 299 UnicodeString& result) const; 300 301 /** 302 * Return the number of registered target specifiers for a given 303 * source specifier. 304 * @param source the given source specifier. 305 * @return the number of registered target specifiers for a given 306 * source specifier. 307 */ 308 int32_t countAvailableTargets(const UnicodeString& source) const; 309 310 /** 311 * Return a registered target specifier for a given source. 312 * @param index which specifier to return, from 0 to n-1, where 313 * n = countAvailableTargets(source) 314 * @param source the source specifier 315 * @param result fill-in paramter to receive the target specifier. 316 * If source is invalid or if index is out of range, result will 317 * be empty. 318 * @return reference to result 319 */ 320 UnicodeString& getAvailableTarget(int32_t index, 321 const UnicodeString& source, 322 UnicodeString& result) const; 323 324 /** 325 * Return the number of registered variant specifiers for a given 326 * source-target pair. There is always at least one variant: If 327 * just source-target is registered, then the single variant 328 * NO_VARIANT is returned. If source-target/variant is registered 329 * then that variant is returned. 330 * @param source the source specifiers 331 * @param target the target specifiers 332 * @return the number of registered variant specifiers for a given 333 * source-target pair. 334 */ 335 int32_t countAvailableVariants(const UnicodeString& source, 336 const UnicodeString& target) const; 337 338 /** 339 * Return a registered variant specifier for a given source-target 340 * pair. If NO_VARIANT is one of the variants, then it will be 341 * at index 0. 342 * @param index which specifier to return, from 0 to n-1, where 343 * n = countAvailableVariants(source, target) 344 * @param source the source specifier 345 * @param target the target specifier 346 * @param result fill-in paramter to receive the variant 347 * specifier. If source is invalid or if target is invalid or if 348 * index is out of range, result will be empty. 349 * @return reference to result 350 */ 351 UnicodeString& getAvailableVariant(int32_t index, 352 const UnicodeString& source, 353 const UnicodeString& target, 354 UnicodeString& result) const; 355 356 private: 357 358 //---------------------------------------------------------------- 359 // Private implementation 360 //---------------------------------------------------------------- 361 362 TransliteratorEntry* find(const UnicodeString& ID); 363 364 TransliteratorEntry* find(UnicodeString& source, 365 UnicodeString& target, 366 UnicodeString& variant); 367 368 TransliteratorEntry* findInDynamicStore(const TransliteratorSpec& src, 369 const TransliteratorSpec& trg, 370 const UnicodeString& variant) const; 371 372 TransliteratorEntry* findInStaticStore(const TransliteratorSpec& src, 373 const TransliteratorSpec& trg, 374 const UnicodeString& variant); 375 376 static TransliteratorEntry* findInBundle(const TransliteratorSpec& specToOpen, 377 const TransliteratorSpec& specToFind, 378 const UnicodeString& variant, 379 UTransDirection direction); 380 381 void registerEntry(const UnicodeString& source, 382 const UnicodeString& target, 383 const UnicodeString& variant, 384 TransliteratorEntry* adopted, 385 UBool visible); 386 387 void registerEntry(const UnicodeString& ID, 388 TransliteratorEntry* adopted, 389 UBool visible); 390 391 void registerEntry(const UnicodeString& ID, 392 const UnicodeString& source, 393 const UnicodeString& target, 394 const UnicodeString& variant, 395 TransliteratorEntry* adopted, 396 UBool visible); 397 398 void registerSTV(const UnicodeString& source, 399 const UnicodeString& target, 400 const UnicodeString& variant); 401 402 void removeSTV(const UnicodeString& source, 403 const UnicodeString& target, 404 const UnicodeString& variant); 405 406 Transliterator* instantiateEntry(const UnicodeString& ID, 407 TransliteratorEntry *entry, 408 TransliteratorAlias*& aliasReturn, 409 UErrorCode& status); 410 411 /** 412 * A StringEnumeration over the registered IDs in this object. 413 */ 414 class Enumeration : public StringEnumeration { 415 public: 416 Enumeration(const TransliteratorRegistry& reg); 417 virtual ~Enumeration(); 418 virtual int32_t count(UErrorCode& status) const; 419 virtual const UnicodeString* snext(UErrorCode& status); 420 virtual void reset(UErrorCode& status); 421 static UClassID U_EXPORT2 getStaticClassID(); 422 virtual UClassID getDynamicClassID() const; 423 private: 424 int32_t index; 425 const TransliteratorRegistry& reg; 426 }; 427 friend class Enumeration; 428 429 private: 430 431 /** 432 * Dynamic registry mapping full IDs to Entry objects. This 433 * contains both public and internal entities. The visibility is 434 * controlled by whether an entry is listed in availableIDs and 435 * specDAG or not. 436 */ 437 Hashtable registry; 438 439 /** 440 * DAG of visible IDs by spec. Hashtable: source => (Hashtable: 441 * target => (UVector: variant)) The UVector of variants is never 442 * empty. For a source-target with no variant, the special 443 * variant NO_VARIANT (the empty string) is stored in slot zero of 444 * the UVector. 445 */ 446 Hashtable specDAG; 447 448 /** 449 * Vector of public full IDs. 450 */ 451 UVector availableIDs; 452 453 TransliteratorRegistry(const TransliteratorRegistry &other); // forbid copying of this class 454 TransliteratorRegistry &operator=(const TransliteratorRegistry &other); // forbid copying of this class 455 }; 456 457 U_NAMESPACE_END 458 459 #endif /* #if !UCONFIG_NO_TRANSLITERATION */ 460 461 #endif 462 //eof 463