Home | History | Annotate | Download | only in i18n
      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 &region) 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