1 /* 2 ******************************************************************************* 3 * Copyright (C) 2007-2010, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 #ifndef ZSTRFMT_H 8 #define ZSTRFMT_H 9 10 #include "unicode/utypes.h" 11 12 #if !UCONFIG_NO_FORMATTING 13 14 #include "unicode/unistr.h" 15 #include "unicode/calendar.h" 16 #include "uhash.h" 17 #include "uvector.h" 18 19 U_NAMESPACE_BEGIN 20 21 /* 22 * Character node used by TextTrieMap 23 */ 24 struct CharacterNode { 25 // No constructor or destructor. 26 // We malloc and free an uninitalized array of CharacterNode objects 27 // and clear and delete them ourselves. 28 29 void clear(); 30 void deleteValues(); 31 32 void addValue(void *value, UErrorCode &status); 33 inline UBool hasValues() const; 34 inline int32_t countValues() const; 35 inline const void *getValue(int32_t index) const; 36 37 void *fValues; // Union of one single value vs. UVector of values. 38 UChar fCharacter; // UTF-16 code unit. 39 uint16_t fFirstChild; // 0 if no children. 40 uint16_t fNextSibling; // 0 terminates the list. 41 UBool fHasValuesVector; 42 UBool fPadding; 43 44 // No value: fValues == NULL and fHasValuesVector == FALSE 45 // One value: fValues == value and fHasValuesVector == FALSE 46 // >=2 values: fValues == UVector of values and fHasValuesVector == TRUE 47 }; 48 49 inline UBool CharacterNode::hasValues() const { 50 return (UBool)(fValues != NULL); 51 } 52 53 inline int32_t CharacterNode::countValues() const { 54 return 55 fValues == NULL ? 0 : 56 !fHasValuesVector ? 1 : 57 ((const UVector *)fValues)->size(); 58 } 59 60 inline const void *CharacterNode::getValue(int32_t index) const { 61 if (!fHasValuesVector) { 62 return fValues; // Assume index == 0. 63 } else { 64 return ((const UVector *)fValues)->elementAt(index); 65 } 66 } 67 68 /* 69 * Search result handler callback interface used by TextTrieMap search. 70 */ 71 class TextTrieMapSearchResultHandler : public UMemory { 72 public: 73 virtual UBool handleMatch(int32_t matchLength, 74 const CharacterNode *node, UErrorCode& status) = 0; 75 virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning 76 }; 77 78 79 /* 80 * ZSFStringPool Pool of (UChar *) strings. Provides for sharing of repeated 81 * strings within ZoneStringFormats. 82 */ 83 class ZSFStringPoolChunk; 84 class ZSFStringPool: public UMemory { 85 public: 86 ZSFStringPool(UErrorCode &status); 87 ~ZSFStringPool(); 88 89 /* Get the pooled string that is equal to the supplied string s. 90 * Copy the string into the pool if it is not already present. 91 * 92 * Life time of the returned string is that of the pool. 93 */ 94 const UChar *get(const UChar *s, UErrorCode &status); 95 96 /* Get the pooled string that is equal to the supplied string s. 97 * Copy the string into the pool if it is not already present. 98 */ 99 const UChar *get(const UnicodeString &s, UErrorCode &status); 100 101 /* Adopt a string into the pool, without copying it. 102 * Used for strings from resource bundles, which will persist without copying. 103 */ 104 const UChar *adopt(const UChar *s, UErrorCode &status); 105 106 /* Freeze the string pool. Discards the hash table that is used 107 * for looking up a string. All pointers to pooled strings remain valid. 108 */ 109 void freeze(); 110 111 private: 112 ZSFStringPoolChunk *fChunks; 113 UHashtable *fHash; 114 }; 115 116 117 /** 118 * TextTrieMap is a trie implementation for supporting 119 * fast prefix match for the string key. 120 */ 121 class TextTrieMap : public UMemory { 122 public: 123 TextTrieMap(UBool ignoreCase); 124 virtual ~TextTrieMap(); 125 126 void put(const UnicodeString &key, void *value, ZSFStringPool &sp, UErrorCode &status); 127 void search(const UnicodeString &text, int32_t start, 128 TextTrieMapSearchResultHandler *handler, UErrorCode& status) const; 129 int32_t isEmpty() const; 130 131 private: 132 UBool fIgnoreCase; 133 CharacterNode *fNodes; 134 int32_t fNodesCapacity; 135 int32_t fNodesCount; 136 137 UVector *fLazyContents; 138 UBool fIsEmpty; 139 140 UBool growNodes(); 141 CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status); 142 CharacterNode* getChildNode(CharacterNode *parent, UChar c) const; 143 144 void putImpl(const UnicodeString &key, void *value, UErrorCode &status); 145 void buildTrie(UErrorCode &status); 146 void search(CharacterNode *node, const UnicodeString &text, int32_t start, 147 int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const; 148 }; 149 150 151 // Name types, these bit flag are used for zone string lookup 152 enum TimeZoneTranslationType { 153 LOCATION = 0x0001, 154 GENERIC_LONG = 0x0002, 155 GENERIC_SHORT = 0x0004, 156 STANDARD_LONG = 0x0008, 157 STANDARD_SHORT = 0x0010, 158 DAYLIGHT_LONG = 0x0020, 159 DAYLIGHT_SHORT = 0x0040 160 }; 161 162 // Name type index, these constants are used for index in the zone strings array. 163 enum TimeZoneTranslationTypeIndex { 164 ZSIDX_LOCATION = 0, 165 ZSIDX_LONG_STANDARD, 166 ZSIDX_SHORT_STANDARD, 167 ZSIDX_LONG_DAYLIGHT, 168 ZSIDX_SHORT_DAYLIGHT, 169 ZSIDX_LONG_GENERIC, 170 ZSIDX_SHORT_GENERIC, 171 172 ZSIDX_COUNT 173 }; 174 175 class MessageFormat; 176 177 178 /* 179 * ZoneStringInfo is a class holding a localized zone string 180 * information. 181 */ 182 class ZoneStringInfo : public UMemory { 183 public: 184 virtual ~ZoneStringInfo(); 185 186 inline UnicodeString& getID(UnicodeString &result) const; 187 inline UnicodeString& getString(UnicodeString &result) const; 188 inline UBool isStandard(void) const; 189 inline UBool isDaylight(void) const; 190 inline UBool isGeneric(void) const; 191 192 private: 193 friend class ZoneStringFormat; 194 friend class ZoneStringSearchResultHandler; 195 196 ZoneStringInfo(const UnicodeString &id, const UnicodeString &str, 197 TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status); 198 199 const UChar *fId; 200 const UChar *fStr; 201 TimeZoneTranslationType fType; 202 }; 203 204 inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const { 205 return result.setTo(fId, -1); 206 } 207 208 inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const { 209 return result.setTo(fStr, -1); 210 } 211 212 inline UBool ZoneStringInfo::isStandard(void) const { 213 return (fType == STANDARD_LONG || fType == STANDARD_SHORT); 214 } 215 216 inline UBool ZoneStringInfo::isDaylight(void) const { 217 return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT); 218 } 219 220 inline UBool ZoneStringInfo::isGeneric(void) const { 221 return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT); 222 } 223 224 class SafeZoneStringFormatPtr; 225 226 class ZoneStringFormat : public UMemory { 227 public: 228 ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status); 229 ZoneStringFormat(const Locale& locale, UErrorCode &status); 230 virtual ~ZoneStringFormat(); 231 232 /* Gets zone string format from cache if available, create it if not cached. */ 233 static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status); 234 235 /* 236 * Create a snapshot of old zone strings array for the given date 237 */ 238 UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const; 239 240 /* TODO: There is no implementation for this function. Delete declaration? */ 241 const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const; 242 243 UnicodeString& getSpecificLongString(const Calendar &cal, 244 UnicodeString &result, UErrorCode &status) const; 245 246 UnicodeString& getSpecificShortString(const Calendar &cal, 247 UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const; 248 249 UnicodeString& getGenericLongString(const Calendar &cal, 250 UnicodeString &result, UErrorCode &status) const; 251 252 UnicodeString& getGenericShortString(const Calendar &cal, 253 UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const; 254 255 UnicodeString& getGenericLocationString(const Calendar &cal, 256 UnicodeString &result, UErrorCode &status) const; 257 258 const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start, 259 int32_t &matchLength, UErrorCode &status) const; 260 const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start, 261 int32_t &matchLength, UErrorCode &status) const; 262 const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start, 263 int32_t &matchLength, UErrorCode &status) const; 264 const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start, 265 int32_t &matchLength, UErrorCode &status) const; 266 const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start, 267 int32_t &matchLength, UErrorCode &status) const; 268 269 // Following APIs are not used by SimpleDateFormat, but public for testing purpose 270 inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date, 271 UnicodeString &result) const; 272 inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date, 273 UnicodeString &result) const; 274 inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date, 275 UnicodeString &result) const; 276 inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date, 277 UnicodeString &result) const; 278 inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 279 UnicodeString &result) const; 280 inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 281 UnicodeString &result) const; 282 inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 283 UnicodeString &result) const; 284 inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 285 UnicodeString &result) const; 286 inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const; 287 288 private: 289 Locale fLocale; 290 UHashtable *fTzidToStrings; 291 UHashtable *fMzidToStrings; 292 293 TextTrieMap fZoneStringsTrie; 294 ZSFStringPool fStringPool; 295 296 UResourceBundle *fZoneStringsArray; 297 UResourceBundle *fMetazoneItem; 298 UResourceBundle *fZoneItem; 299 300 UBool fIsFullyLoaded; 301 302 void loadZone(const UnicodeString &utzid, UErrorCode &status); 303 void addSingleZone(UnicodeString &utzid, UErrorCode &status); 304 void loadFull(UErrorCode &status); 305 306 307 /* 308 * Private method to get a zone string except generic partial location types. 309 */ 310 UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date, 311 UBool commonlyUsedOnly, UnicodeString& result) const; 312 313 /* 314 * Private method to get a generic string, with fallback logic involved, 315 * that is, 316 * 317 * 1. If a generic non-location string is avaiable for the zone, return it. 318 * 2. If a generic non-location string is associated with a metazone and 319 * the zone never use daylight time around the given date, use the standard 320 * string (if available). 321 * 322 * Note: In CLDR1.5.1, the same localization is used for generic and standard. 323 * In this case, we do not use the standard string and do the rest. 324 * 325 * 3. If a generic non-location string is associated with a metazone and 326 * the offset at the given time is different from the preferred zone for the 327 * current locale, then return the generic partial location string (if avaiable) 328 * 4. If a generic non-location string is not available, use generic location 329 * string. 330 */ 331 UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly, 332 UnicodeString &result, UErrorCode &status) const; 333 334 /* 335 * Private method to get a generic partial location string 336 */ 337 UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort, 338 UDate date, UBool commonlyUsedOnly, UnicodeString &result) const; 339 340 /* 341 * Find a prefix matching time zone for the given zone string types. 342 * @param text The text contains a time zone string 343 * @param start The start index within the text 344 * @param types The bit mask representing a set of requested types 345 * @param matchLength Receives the match length 346 * @param status 347 * @return If any zone string matched for the requested types, returns a 348 * ZoneStringInfo for the longest match. If no matches are found for 349 * the requested types, returns a ZoneStringInfo for the longest match 350 * for any other types. If nothing matches at all, returns null. 351 */ 352 const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types, 353 int32_t &matchLength, UErrorCode &status) const; 354 const ZoneStringInfo* subFind(const UnicodeString &text, int32_t start, int32_t types, 355 int32_t &matchLength, UErrorCode &status) const; 356 357 UnicodeString& getRegion(UnicodeString ®ion) const; 358 359 static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status); 360 static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status); 361 const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key); 362 static UBool isCommonlyUsed(const UResourceBundle *zoneitem); 363 static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale, 364 UnicodeString &displayCountry); 365 }; 366 367 inline UnicodeString& 368 ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date, 369 UnicodeString &result) const { 370 return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result); 371 } 372 373 inline UnicodeString& 374 ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date, 375 UnicodeString &result) const { 376 return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result); 377 } 378 379 inline UnicodeString& 380 ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date, 381 UnicodeString &result) const { 382 return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result); 383 } 384 385 inline UnicodeString& 386 ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date, 387 UnicodeString &result) const { 388 return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result); 389 } 390 391 inline UnicodeString& 392 ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 393 UnicodeString &result) const { 394 return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result); 395 } 396 397 inline UnicodeString& 398 ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 399 UnicodeString &result) const { 400 return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result); 401 } 402 403 inline UnicodeString& 404 ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 405 UnicodeString &result) const { 406 return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result); 407 } 408 409 inline UnicodeString& 410 ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 411 UnicodeString &result) const { 412 return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result); 413 } 414 415 inline UnicodeString& 416 ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const { 417 return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result); 418 } 419 420 421 /* 422 * ZoneStrings is a container of localized zone strings used by ZoneStringFormat 423 */ 424 class ZoneStrings : public UMemory { 425 public: 426 ZoneStrings(UnicodeString *strings, 427 int32_t stringsCount, 428 UBool commonlyUsed, 429 UnicodeString **genericPartialLocationStrings, 430 int32_t genericRowCount, 431 int32_t genericColCount, 432 ZSFStringPool &sp, 433 UErrorCode &status); 434 virtual ~ZoneStrings(); 435 436 UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const; 437 inline UBool isShortFormatCommonlyUsed(void) const; 438 UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort, 439 UBool commonlyUsedOnly, UnicodeString &result) const; 440 441 private: 442 const UChar **fStrings; 443 int32_t fStringsCount; 444 UBool fIsCommonlyUsed; 445 const UChar * **fGenericPartialLocationStrings; 446 int32_t fGenericPartialLocationRowCount; 447 int32_t fGenericPartialLocationColCount; 448 }; 449 450 inline UBool 451 ZoneStrings::isShortFormatCommonlyUsed(void) const { 452 return fIsCommonlyUsed; 453 } 454 455 /* 456 * ZoneStringSearchResultHandler is an implementation of 457 * TextTrieMapSearchHandler. This class is used by ZoneStringFormat 458 * for collecting search results for localized zone strings. 459 */ 460 class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler { 461 public: 462 ZoneStringSearchResultHandler(UErrorCode &status); 463 virtual ~ZoneStringSearchResultHandler(); 464 465 virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status); 466 int32_t countMatches(void); 467 const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength); 468 void clear(void); 469 470 private: 471 UVector fResults; 472 int32_t fMatchLen[ZSIDX_COUNT]; 473 }; 474 475 476 /* 477 * ZoneStringFormat cache implementation 478 */ 479 class ZSFCacheEntry : public UMemory { 480 public: 481 ~ZSFCacheEntry(); 482 483 void delRef(void); 484 const ZoneStringFormat* getZoneStringFormat(void); 485 486 private: 487 friend class ZSFCache; 488 489 ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next); 490 491 Locale fLocale; 492 ZoneStringFormat *fZoneStringFormat; 493 ZSFCacheEntry *fNext; 494 int32_t fRefCount; 495 }; 496 497 class SafeZoneStringFormatPtr : public UMemory { 498 public: 499 ~SafeZoneStringFormatPtr(); 500 const ZoneStringFormat* get() const; 501 502 private: 503 friend class ZSFCache; 504 505 SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry); 506 507 ZSFCacheEntry *fCacheEntry; 508 }; 509 510 class ZSFCache : public UMemory { 511 public: 512 ZSFCache(int32_t capacity); 513 ~ZSFCache(); 514 515 SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status); 516 517 private: 518 int32_t fCapacity; 519 ZSFCacheEntry *fFirst; 520 }; 521 522 U_NAMESPACE_END 523 524 #endif /* #if !UCONFIG_NO_FORMATTING */ 525 526 #endif // ZSTRFMT_H 527