/* ******************************************************************************* * Copyright (C) 2007-2010, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ #ifndef ZSTRFMT_H #define ZSTRFMT_H #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include "unicode/unistr.h" #include "unicode/calendar.h" #include "uhash.h" #include "uvector.h" U_NAMESPACE_BEGIN /* * Character node used by TextTrieMap */ struct CharacterNode { // No constructor or destructor. // We malloc and free an uninitalized array of CharacterNode objects // and clear and delete them ourselves. void clear(); void deleteValues(); void addValue(void *value, UErrorCode &status); inline UBool hasValues() const; inline int32_t countValues() const; inline const void *getValue(int32_t index) const; void *fValues; // Union of one single value vs. UVector of values. UChar fCharacter; // UTF-16 code unit. uint16_t fFirstChild; // 0 if no children. uint16_t fNextSibling; // 0 terminates the list. UBool fHasValuesVector; UBool fPadding; // No value: fValues == NULL and fHasValuesVector == FALSE // One value: fValues == value and fHasValuesVector == FALSE // >=2 values: fValues == UVector of values and fHasValuesVector == TRUE }; inline UBool CharacterNode::hasValues() const { return (UBool)(fValues != NULL); } inline int32_t CharacterNode::countValues() const { return fValues == NULL ? 0 : !fHasValuesVector ? 1 : ((const UVector *)fValues)->size(); } inline const void *CharacterNode::getValue(int32_t index) const { if (!fHasValuesVector) { return fValues; // Assume index == 0. } else { return ((const UVector *)fValues)->elementAt(index); } } /* * Search result handler callback interface used by TextTrieMap search. */ class TextTrieMapSearchResultHandler : public UMemory { public: virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode& status) = 0; virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning }; /* * ZSFStringPool Pool of (UChar *) strings. Provides for sharing of repeated * strings within ZoneStringFormats. */ class ZSFStringPoolChunk; class ZSFStringPool: public UMemory { public: ZSFStringPool(UErrorCode &status); ~ZSFStringPool(); /* Get the pooled string that is equal to the supplied string s. * Copy the string into the pool if it is not already present. * * Life time of the returned string is that of the pool. */ const UChar *get(const UChar *s, UErrorCode &status); /* Get the pooled string that is equal to the supplied string s. * Copy the string into the pool if it is not already present. */ const UChar *get(const UnicodeString &s, UErrorCode &status); /* Adopt a string into the pool, without copying it. * Used for strings from resource bundles, which will persist without copying. */ const UChar *adopt(const UChar *s, UErrorCode &status); /* Freeze the string pool. Discards the hash table that is used * for looking up a string. All pointers to pooled strings remain valid. */ void freeze(); private: ZSFStringPoolChunk *fChunks; UHashtable *fHash; }; /** * TextTrieMap is a trie implementation for supporting * fast prefix match for the string key. */ class TextTrieMap : public UMemory { public: TextTrieMap(UBool ignoreCase); virtual ~TextTrieMap(); void put(const UnicodeString &key, void *value, ZSFStringPool &sp, UErrorCode &status); void search(const UnicodeString &text, int32_t start, TextTrieMapSearchResultHandler *handler, UErrorCode& status) const; int32_t isEmpty() const; private: UBool fIgnoreCase; CharacterNode *fNodes; int32_t fNodesCapacity; int32_t fNodesCount; UVector *fLazyContents; UBool fIsEmpty; UBool growNodes(); CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status); CharacterNode* getChildNode(CharacterNode *parent, UChar c) const; void putImpl(const UnicodeString &key, void *value, UErrorCode &status); void buildTrie(UErrorCode &status); void search(CharacterNode *node, const UnicodeString &text, int32_t start, int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const; }; // Name types, these bit flag are used for zone string lookup enum TimeZoneTranslationType { LOCATION = 0x0001, GENERIC_LONG = 0x0002, GENERIC_SHORT = 0x0004, STANDARD_LONG = 0x0008, STANDARD_SHORT = 0x0010, DAYLIGHT_LONG = 0x0020, DAYLIGHT_SHORT = 0x0040 }; // Name type index, these constants are used for index in the zone strings array. enum TimeZoneTranslationTypeIndex { ZSIDX_LOCATION = 0, ZSIDX_LONG_STANDARD, ZSIDX_SHORT_STANDARD, ZSIDX_LONG_DAYLIGHT, ZSIDX_SHORT_DAYLIGHT, ZSIDX_LONG_GENERIC, ZSIDX_SHORT_GENERIC, ZSIDX_COUNT }; class MessageFormat; /* * ZoneStringInfo is a class holding a localized zone string * information. */ class ZoneStringInfo : public UMemory { public: virtual ~ZoneStringInfo(); inline UnicodeString& getID(UnicodeString &result) const; inline UnicodeString& getString(UnicodeString &result) const; inline UBool isStandard(void) const; inline UBool isDaylight(void) const; inline UBool isGeneric(void) const; private: friend class ZoneStringFormat; friend class ZoneStringSearchResultHandler; ZoneStringInfo(const UnicodeString &id, const UnicodeString &str, TimeZoneTranslationType type, ZSFStringPool &sp, UErrorCode &status); const UChar *fId; const UChar *fStr; TimeZoneTranslationType fType; }; inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const { return result.setTo(fId, -1); } inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const { return result.setTo(fStr, -1); } inline UBool ZoneStringInfo::isStandard(void) const { return (fType == STANDARD_LONG || fType == STANDARD_SHORT); } inline UBool ZoneStringInfo::isDaylight(void) const { return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT); } inline UBool ZoneStringInfo::isGeneric(void) const { return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT); } class SafeZoneStringFormatPtr; class ZoneStringFormat : public UMemory { public: ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status); ZoneStringFormat(const Locale& locale, UErrorCode &status); virtual ~ZoneStringFormat(); /* Gets zone string format from cache if available, create it if not cached. */ static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status); /* * Create a snapshot of old zone strings array for the given date */ UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const; /* TODO: There is no implementation for this function. Delete declaration? */ const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const; UnicodeString& getSpecificLongString(const Calendar &cal, UnicodeString &result, UErrorCode &status) const; UnicodeString& getSpecificShortString(const Calendar &cal, UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const; UnicodeString& getGenericLongString(const Calendar &cal, UnicodeString &result, UErrorCode &status) const; UnicodeString& getGenericShortString(const Calendar &cal, UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const; UnicodeString& getGenericLocationString(const Calendar &cal, UnicodeString &result, UErrorCode &status) const; const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start, int32_t &matchLength, UErrorCode &status) const; const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start, int32_t &matchLength, UErrorCode &status) const; const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start, int32_t &matchLength, UErrorCode &status) const; const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start, int32_t &matchLength, UErrorCode &status) const; const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start, int32_t &matchLength, UErrorCode &status) const; // Following APIs are not used by SimpleDateFormat, but public for testing purpose inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date, UnicodeString &result) const; inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date, UnicodeString &result) const; inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date, UnicodeString &result) const; inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date, UnicodeString &result) const; inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const; inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const; inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const; inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const; inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const; private: Locale fLocale; UHashtable *fTzidToStrings; UHashtable *fMzidToStrings; TextTrieMap fZoneStringsTrie; ZSFStringPool fStringPool; UResourceBundle *fZoneStringsArray; UResourceBundle *fMetazoneItem; UResourceBundle *fZoneItem; UBool fIsFullyLoaded; void loadZone(const UnicodeString &utzid, UErrorCode &status); void addSingleZone(UnicodeString &utzid, UErrorCode &status); void loadFull(UErrorCode &status); /* * Private method to get a zone string except generic partial location types. */ UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date, UBool commonlyUsedOnly, UnicodeString& result) const; /* * Private method to get a generic string, with fallback logic involved, * that is, * * 1. If a generic non-location string is avaiable for the zone, return it. * 2. If a generic non-location string is associated with a metazone and * the zone never use daylight time around the given date, use the standard * string (if available). * * Note: In CLDR1.5.1, the same localization is used for generic and standard. * In this case, we do not use the standard string and do the rest. * * 3. If a generic non-location string is associated with a metazone and * the offset at the given time is different from the preferred zone for the * current locale, then return the generic partial location string (if avaiable) * 4. If a generic non-location string is not available, use generic location * string. */ UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const; /* * Private method to get a generic partial location string */ UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const; /* * Find a prefix matching time zone for the given zone string types. * @param text The text contains a time zone string * @param start The start index within the text * @param types The bit mask representing a set of requested types * @param matchLength Receives the match length * @param status * @return If any zone string matched for the requested types, returns a * ZoneStringInfo for the longest match. If no matches are found for * the requested types, returns a ZoneStringInfo for the longest match * for any other types. If nothing matches at all, returns null. */ const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types, int32_t &matchLength, UErrorCode &status) const; const ZoneStringInfo* subFind(const UnicodeString &text, int32_t start, int32_t types, int32_t &matchLength, UErrorCode &status) const; UnicodeString& getRegion(UnicodeString ®ion) const; static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status); static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status); const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key); static UBool isCommonlyUsed(const UResourceBundle *zoneitem); static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale, UnicodeString &displayCountry); }; inline UnicodeString& ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date, UnicodeString &result) const { return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result); } inline UnicodeString& ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date, UnicodeString &result) const { return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result); } inline UnicodeString& ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date, UnicodeString &result) const { return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result); } inline UnicodeString& ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date, UnicodeString &result) const { return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result); } inline UnicodeString& ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const { return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result); } inline UnicodeString& ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const { return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result); } inline UnicodeString& ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const { return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result); } inline UnicodeString& ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly, UnicodeString &result) const { return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result); } inline UnicodeString& ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const { return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result); } /* * ZoneStrings is a container of localized zone strings used by ZoneStringFormat */ class ZoneStrings : public UMemory { public: ZoneStrings(UnicodeString *strings, int32_t stringsCount, UBool commonlyUsed, UnicodeString **genericPartialLocationStrings, int32_t genericRowCount, int32_t genericColCount, ZSFStringPool &sp, UErrorCode &status); virtual ~ZoneStrings(); UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const; inline UBool isShortFormatCommonlyUsed(void) const; UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort, UBool commonlyUsedOnly, UnicodeString &result) const; private: const UChar **fStrings; int32_t fStringsCount; UBool fIsCommonlyUsed; const UChar * **fGenericPartialLocationStrings; int32_t fGenericPartialLocationRowCount; int32_t fGenericPartialLocationColCount; }; inline UBool ZoneStrings::isShortFormatCommonlyUsed(void) const { return fIsCommonlyUsed; } /* * ZoneStringSearchResultHandler is an implementation of * TextTrieMapSearchHandler. This class is used by ZoneStringFormat * for collecting search results for localized zone strings. */ class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler { public: ZoneStringSearchResultHandler(UErrorCode &status); virtual ~ZoneStringSearchResultHandler(); virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status); int32_t countMatches(void); const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength); void clear(void); private: UVector fResults; int32_t fMatchLen[ZSIDX_COUNT]; }; /* * ZoneStringFormat cache implementation */ class ZSFCacheEntry : public UMemory { public: ~ZSFCacheEntry(); void delRef(void); const ZoneStringFormat* getZoneStringFormat(void); private: friend class ZSFCache; ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next); Locale fLocale; ZoneStringFormat *fZoneStringFormat; ZSFCacheEntry *fNext; int32_t fRefCount; }; class SafeZoneStringFormatPtr : public UMemory { public: ~SafeZoneStringFormatPtr(); const ZoneStringFormat* get() const; private: friend class ZSFCache; SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry); ZSFCacheEntry *fCacheEntry; }; class ZSFCache : public UMemory { public: ZSFCache(int32_t capacity); ~ZSFCache(); SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status); private: int32_t fCapacity; ZSFCacheEntry *fFirst; }; U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ #endif // ZSTRFMT_H