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