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
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 * 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
isEmpty(void)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
getID(UnicodeString & result)161 inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
162 return result.setTo(fId);
163 }
164
getString(UnicodeString & result)165 inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
166 return result.setTo(fStr);
167 }
168
isStandard(void)169 inline UBool ZoneStringInfo::isStandard(void) const {
170 return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
171 }
172
isDaylight(void)173 inline UBool ZoneStringInfo::isDaylight(void) const {
174 return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
175 }
176
isGeneric(void)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&
getLongStandard(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getLongDaylight(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getLongGenericNonLocation(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getLongGenericPartialLocation(const UnicodeString & tzid,UDate date,UnicodeString & result)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&
getShortStandard(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getShortDaylight(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getShortGenericNonLocation(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getShortGenericPartialLocation(const UnicodeString & tzid,UDate date,UBool commonlyUsedOnly,UnicodeString & result)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&
getGenericLocation(const UnicodeString & tzid,UnicodeString & result)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
isShortFormatCommonlyUsed(void)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