1 /* 2 ******************************************************************************* 3 * Copyright (C) 2007-2008, 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 "hash.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 * TextTrieMap is a trie implementation for supporting 80 * fast prefix match for the string key. 81 */ 82 class TextTrieMap : public UMemory { 83 public: 84 TextTrieMap(UBool ignoreCase); 85 virtual ~TextTrieMap(); 86 87 void put(const UnicodeString &key, void *value, UErrorCode &status); 88 void search(const UnicodeString &text, int32_t start, 89 TextTrieMapSearchResultHandler *handler, UErrorCode& status) const; 90 inline int32_t isEmpty() const; 91 92 private: 93 UBool fIgnoreCase; 94 CharacterNode *fNodes; 95 int32_t fNodesCapacity; 96 int32_t fNodesCount; 97 98 UBool growNodes(); 99 CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status); 100 CharacterNode* getChildNode(CharacterNode *parent, UChar c) const; 101 102 void search(CharacterNode *node, const UnicodeString &text, int32_t start, 103 int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const; 104 }; 105 106 inline UChar32 TextTrieMap::isEmpty(void) const { 107 return fNodes == NULL; 108 } 109 110 // Name types, these bit flag are used for zone string lookup 111 enum TimeZoneTranslationType { 112 LOCATION = 0x0001, 113 GENERIC_LONG = 0x0002, 114 GENERIC_SHORT = 0x0004, 115 STANDARD_LONG = 0x0008, 116 STANDARD_SHORT = 0x0010, 117 DAYLIGHT_LONG = 0x0020, 118 DAYLIGHT_SHORT = 0x0040 119 }; 120 121 // Name type index, these constants are used for index in the zone strings array. 122 enum TimeZoneTranslationTypeIndex { 123 ZSIDX_LOCATION = 0, 124 ZSIDX_LONG_STANDARD, 125 ZSIDX_SHORT_STANDARD, 126 ZSIDX_LONG_DAYLIGHT, 127 ZSIDX_SHORT_DAYLIGHT, 128 ZSIDX_LONG_GENERIC, 129 ZSIDX_SHORT_GENERIC, 130 131 ZSIDX_COUNT 132 }; 133 134 class MessageFormat; 135 136 /* 137 * ZoneStringInfo is a class holding a localized zone string 138 * information. 139 */ 140 class ZoneStringInfo : public UMemory { 141 public: 142 virtual ~ZoneStringInfo(); 143 144 inline UnicodeString& getID(UnicodeString &result) const; 145 inline UnicodeString& getString(UnicodeString &result) const; 146 inline UBool isStandard(void) const; 147 inline UBool isDaylight(void) const; 148 inline UBool isGeneric(void) const; 149 150 private: 151 friend class ZoneStringFormat; 152 friend class ZoneStringSearchResultHandler; 153 154 ZoneStringInfo(const UnicodeString &id, const UnicodeString &str, TimeZoneTranslationType type); 155 156 UnicodeString fId; 157 UnicodeString fStr; 158 TimeZoneTranslationType fType; 159 }; 160 161 inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const { 162 return result.setTo(fId); 163 } 164 165 inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const { 166 return result.setTo(fStr); 167 } 168 169 inline UBool ZoneStringInfo::isStandard(void) const { 170 return (fType == STANDARD_LONG || fType == STANDARD_SHORT); 171 } 172 173 inline UBool ZoneStringInfo::isDaylight(void) const { 174 return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT); 175 } 176 177 inline UBool ZoneStringInfo::isGeneric(void) const { 178 return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT); 179 } 180 181 class SafeZoneStringFormatPtr; 182 183 class ZoneStringFormat : public UMemory { 184 public: 185 ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status); 186 ZoneStringFormat(const Locale& locale, UErrorCode &status); 187 virtual ~ZoneStringFormat(); 188 189 static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status); 190 191 /* 192 * Create a snapshot of old zone strings array for the given date 193 */ 194 UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const; 195 196 const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const; 197 198 UnicodeString& getSpecificLongString(const Calendar &cal, 199 UnicodeString &result, UErrorCode &status) const; 200 201 UnicodeString& getSpecificShortString(const Calendar &cal, 202 UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const; 203 204 UnicodeString& getGenericLongString(const Calendar &cal, 205 UnicodeString &result, UErrorCode &status) const; 206 207 UnicodeString& getGenericShortString(const Calendar &cal, 208 UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const; 209 210 UnicodeString& getGenericLocationString(const Calendar &cal, 211 UnicodeString &result, UErrorCode &status) const; 212 213 const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start, 214 int32_t &matchLength, UErrorCode &status) const; 215 const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start, 216 int32_t &matchLength, UErrorCode &status) const; 217 const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start, 218 int32_t &matchLength, UErrorCode &status) const; 219 const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start, 220 int32_t &matchLength, UErrorCode &status) const; 221 const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start, 222 int32_t &matchLength, UErrorCode &status) const; 223 224 // Following APIs are not used by SimpleDateFormat, but public for testing purpose 225 inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date, 226 UnicodeString &result) const; 227 inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date, 228 UnicodeString &result) const; 229 inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date, 230 UnicodeString &result) const; 231 inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date, 232 UnicodeString &result) const; 233 inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 234 UnicodeString &result) const; 235 inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 236 UnicodeString &result) const; 237 inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 238 UnicodeString &result) const; 239 inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 240 UnicodeString &result) const; 241 inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const; 242 243 private: 244 Locale fLocale; 245 Hashtable fTzidToStrings; 246 Hashtable fMzidToStrings; 247 TextTrieMap fZoneStringsTrie; 248 249 /* 250 * Private method to get a zone string except generic partial location types. 251 */ 252 UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date, 253 UBool commonlyUsedOnly, UnicodeString& result) const; 254 255 /* 256 * Private method to get a generic string, with fallback logic involved, 257 * that is, 258 * 259 * 1. If a generic non-location string is avaiable for the zone, return it. 260 * 2. If a generic non-location string is associated with a metazone and 261 * the zone never use daylight time around the given date, use the standard 262 * string (if available). 263 * 264 * Note: In CLDR1.5.1, the same localization is used for generic and standard. 265 * In this case, we do not use the standard string and do the rest. 266 * 267 * 3. If a generic non-location string is associated with a metazone and 268 * the offset at the given time is different from the preferred zone for the 269 * current locale, then return the generic partial location string (if avaiable) 270 * 4. If a generic non-location string is not available, use generic location 271 * string. 272 */ 273 UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly, 274 UnicodeString &result, UErrorCode &status) const; 275 276 /* 277 * Private method to get a generic partial location string 278 */ 279 UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort, 280 UDate date, UBool commonlyUsedOnly, UnicodeString &result) const; 281 282 /* 283 * Find a prefix matching time zone for the given zone string types. 284 * @param text The text contains a time zone string 285 * @param start The start index within the text 286 * @param types The bit mask representing a set of requested types 287 * @param matchLength Receives the match length 288 * @param status 289 * @return If any zone string matched for the requested types, returns a 290 * ZoneStringInfo for the longest match. If no matches are found for 291 * the requested types, returns a ZoneStringInfo for the longest match 292 * for any other types. If nothing matches at all, returns null. 293 */ 294 const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types, 295 int32_t &matchLength, UErrorCode &status) const; 296 297 UnicodeString& getRegion(UnicodeString ®ion) const; 298 299 static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status); 300 static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status); 301 static const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key); 302 static UBool isCommonlyUsed(const UResourceBundle *zoneitem); 303 static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale, 304 UnicodeString &displayCountry); 305 }; 306 307 inline UnicodeString& 308 ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date, 309 UnicodeString &result) const { 310 return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result); 311 } 312 313 inline UnicodeString& 314 ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date, 315 UnicodeString &result) const { 316 return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result); 317 } 318 319 inline UnicodeString& 320 ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date, 321 UnicodeString &result) const { 322 return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result); 323 } 324 325 inline UnicodeString& 326 ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date, 327 UnicodeString &result) const { 328 return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result); 329 } 330 331 inline UnicodeString& 332 ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 333 UnicodeString &result) const { 334 return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result); 335 } 336 337 inline UnicodeString& 338 ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 339 UnicodeString &result) const { 340 return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result); 341 } 342 343 inline UnicodeString& 344 ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 345 UnicodeString &result) const { 346 return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result); 347 } 348 349 inline UnicodeString& 350 ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, 351 UnicodeString &result) const { 352 return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result); 353 } 354 355 inline UnicodeString& 356 ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const { 357 return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result); 358 } 359 360 361 /* 362 * ZooneStrings is a container of localized zone strings used by ZoneStringFormat 363 */ 364 class ZoneStrings : public UMemory { 365 public: 366 ZoneStrings(UnicodeString *strings, int32_t stringsCount, UBool commonlyUsed, 367 UnicodeString **genericPartialLocationStrings, int32_t genericRowCount, int32_t genericColCount); 368 virtual ~ZoneStrings(); 369 370 UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const; 371 inline UBool isShortFormatCommonlyUsed(void) const; 372 UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort, 373 UBool commonlyUsedOnly, UnicodeString &result) const; 374 375 private: 376 UnicodeString *fStrings; 377 int32_t fStringsCount; 378 UBool fIsCommonlyUsed; 379 UnicodeString **fGenericPartialLocationStrings; 380 int32_t fGenericPartialLocationRowCount; 381 int32_t fGenericPartialLocationColCount; 382 }; 383 384 inline UBool 385 ZoneStrings::isShortFormatCommonlyUsed(void) const { 386 return fIsCommonlyUsed; 387 } 388 389 /* 390 * ZoneStringSearchResultHandler is an implementation of 391 * TextTrieMapSearchHandler. This class is used by ZoneStringFormat 392 * for collecting search results for localized zone strings. 393 */ 394 class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler { 395 public: 396 ZoneStringSearchResultHandler(UErrorCode &status); 397 virtual ~ZoneStringSearchResultHandler(); 398 399 virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status); 400 int32_t countMatches(void); 401 const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength); 402 void clear(void); 403 404 private: 405 UVector fResults; 406 int32_t fMatchLen[ZSIDX_COUNT]; 407 }; 408 409 410 /* 411 * ZoneStringFormat cache implementation 412 */ 413 class ZSFCacheEntry : public UMemory { 414 public: 415 ~ZSFCacheEntry(); 416 417 void delRef(void); 418 const ZoneStringFormat* getZoneStringFormat(void); 419 420 private: 421 friend class ZSFCache; 422 423 ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next); 424 425 Locale fLocale; 426 ZoneStringFormat *fZoneStringFormat; 427 ZSFCacheEntry *fNext; 428 int32_t fRefCount; 429 }; 430 431 class SafeZoneStringFormatPtr : public UMemory { 432 public: 433 ~SafeZoneStringFormatPtr(); 434 const ZoneStringFormat* get() const; 435 436 private: 437 friend class ZSFCache; 438 439 SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry); 440 441 ZSFCacheEntry *fCacheEntry; 442 }; 443 444 class ZSFCache : public UMemory { 445 public: 446 ZSFCache(int32_t capacity); 447 ~ZSFCache(); 448 449 SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status); 450 451 private: 452 int32_t fCapacity; 453 ZSFCacheEntry *fFirst; 454 }; 455 456 U_NAMESPACE_END 457 458 #endif /* #if !UCONFIG_NO_FORMATTING */ 459 460 #endif // ZSTRFMT_H 461