• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &region) 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