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
hasValues()49 inline UBool CharacterNode::hasValues() const {
50 return (UBool)(fValues != NULL);
51 }
52
countValues()53 inline int32_t CharacterNode::countValues() const {
54 return
55 fValues == NULL ? 0 :
56 !fHasValuesVector ? 1 :
57 ((const UVector *)fValues)->size();
58 }
59
getValue(int32_t index)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 struct 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
getID(UnicodeString & result)204 inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
205 return result.setTo(fId, -1);
206 }
207
getString(UnicodeString & result)208 inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
209 return result.setTo(fStr, -1);
210 }
211
isStandard(void)212 inline UBool ZoneStringInfo::isStandard(void) const {
213 return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
214 }
215
isDaylight(void)216 inline UBool ZoneStringInfo::isDaylight(void) const {
217 return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
218 }
219
isGeneric(void)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&
getLongStandard(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getLongDaylight(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getLongGenericNonLocation(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getLongGenericPartialLocation(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getShortStandard(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getShortDaylight(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getShortGenericNonLocation(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getShortGenericPartialLocation(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getGenericLocation(const UnicodeString & tzid,UnicodeString & result)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
isShortFormatCommonlyUsed(void)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