/* ******************************************************************************* * Copyright (C) 1997-2007, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * * File DTFMTSYM.CPP * * Modification History: * * Date Name Description * 02/19/97 aliu Converted from java. * 07/21/98 stephen Added getZoneIndex * Changed weekdays/short weekdays to be one-based * 06/14/99 stephen Removed SimpleDateFormat::fgTimeZoneDataSuffix * 11/16/99 weiv Added 'Y' and 'e' to fgPatternChars * 03/27/00 weiv Keeping resource bundle around! * 06/30/05 emmons Added eraNames, narrow month/day, standalone context * 10/12/05 emmons Added setters for eraNames, month/day by width/context ******************************************************************************* */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include "unicode/ustring.h" #include "unicode/dtfmtsym.h" #include "unicode/smpdtfmt.h" #include "cpputils.h" #include "ucln_in.h" #include "umutex.h" #include "cmemory.h" #include "cstring.h" #include "locbased.h" #include "gregoimp.h" #include "hash.h" #include "uresimp.h" // ***************************************************************************** // class DateFormatSymbols // ***************************************************************************** /** * These are static arrays we use only in the case where we have no * resource data. */ #define PATTERN_CHARS_LEN 29 /** * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All * locales use the same these unlocalized pattern characters. */ static const UChar gPatternChars[] = { // GyMdkHmsSEDFwWahKzYeugAZvcLQq 0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45, 0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65, 0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0 }; /* length of an array */ #define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0])) //------------------------------------------------------ // Strings of last resort. These are only used if we have no resource // files. They aren't designed for actual use, just for backup. // These are the month names and abbreviations of last resort. static const UChar gLastResortMonthNames[13][3] = { {0x0030, 0x0031, 0x0000}, /* "01" */ {0x0030, 0x0032, 0x0000}, /* "02" */ {0x0030, 0x0033, 0x0000}, /* "03" */ {0x0030, 0x0034, 0x0000}, /* "04" */ {0x0030, 0x0035, 0x0000}, /* "05" */ {0x0030, 0x0036, 0x0000}, /* "06" */ {0x0030, 0x0037, 0x0000}, /* "07" */ {0x0030, 0x0038, 0x0000}, /* "08" */ {0x0030, 0x0039, 0x0000}, /* "09" */ {0x0031, 0x0030, 0x0000}, /* "10" */ {0x0031, 0x0031, 0x0000}, /* "11" */ {0x0031, 0x0032, 0x0000}, /* "12" */ {0x0031, 0x0033, 0x0000} /* "13" */ }; // These are the weekday names and abbreviations of last resort. static const UChar gLastResortDayNames[8][2] = { {0x0030, 0x0000}, /* "0" */ {0x0031, 0x0000}, /* "1" */ {0x0032, 0x0000}, /* "2" */ {0x0033, 0x0000}, /* "3" */ {0x0034, 0x0000}, /* "4" */ {0x0035, 0x0000}, /* "5" */ {0x0036, 0x0000}, /* "6" */ {0x0037, 0x0000} /* "7" */ }; // These are the quarter names and abbreviations of last resort. static const UChar gLastResortQuarters[4][2] = { {0x0031, 0x0000}, /* "1" */ {0x0032, 0x0000}, /* "2" */ {0x0033, 0x0000}, /* "3" */ {0x0034, 0x0000}, /* "4" */ }; // These are the am/pm and BC/AD markers of last resort. static const UChar gLastResortAmPmMarkers[2][3] = { {0x0041, 0x004D, 0x0000}, /* "AM" */ {0x0050, 0x004D, 0x0000} /* "PM" */ }; static const UChar gLastResortEras[2][3] = { {0x0042, 0x0043, 0x0000}, /* "BC" */ {0x0041, 0x0044, 0x0000} /* "AD" */ }; // These are the zone strings of last resort. static const UChar gLastResortZoneStrings[7][4] = { {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */ {0x0047, 0x004D, 0x0054, 0x0000} /* "GMT" */ }; /* Sizes for the last resort string arrays */ typedef enum LastResortSize { kMonthNum = 13, kMonthLen = 3, kDayNum = 8, kDayLen = 2, kAmPmNum = 2, kAmPmLen = 3, kQuarterNum = 4, kQuarterLen = 2, kEraNum = 2, kEraLen = 3, kZoneNum = 5, kZoneLen = 4 } LastResortSize; U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols) #define kSUPPLEMENTAL "supplementalData" /** * These are the tags we expect to see in normal resource bundle files associated * with a locale and calendar */ static const char gErasTag[]="eras"; static const char gAbbreviatedTag[] = "abbreviated"; static const char gMonthNamesTag[]="monthNames"; static const char gDayNamesTag[]="dayNames"; static const char gNamesWideTag[]="wide"; static const char gNamesAbbrTag[]="abbreviated"; static const char gNamesNarrowTag[]="narrow"; static const char gNamesStandaloneTag[]="stand-alone"; static const char gAmPmMarkersTag[]="AmPmMarkers"; static const char gQuartersTag[]="quarters"; static const char gMaptimezonesTag[]="mapTimezones"; static const char gMetazonesTag[]="metazones"; /** * These are the tags we expect to see in time zone data resource bundle files * associated with a locale. */ static const char gZoneStringsTag[]="zoneStrings"; static const char gLocalPatternCharsTag[]="localPatternChars"; static UMTX LOCK; /* * Keep this variable in synch with max length of display strings */ #define ZID_KEY_MAX 128 #define UTZ_MAX_DISPLAY_STRINGS_LENGTH 7 #define UTZ_SHORT_GENERIC "sg" #define UTZ_SHORT_STANDARD "ss" #define UTZ_SHORT_DAYLIGHT "sd" #define UTZ_LONG_GENERIC "lg" #define UTZ_LONG_STANDARD "ls" #define UTZ_LONG_DAYLIGHT "ld" #define UTZ_EXEMPLAR_CITY "ec" #define UTZ_USES_METAZONE "um" /** * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly. * Work around this. */ static inline UnicodeString* newUnicodeStringArray(size_t count) { return new UnicodeString[count ? count : 1]; } U_CDECL_BEGIN static void deleteUnicodeStringArray(void* obj) { delete[] (UnicodeString*)obj; } U_CDECL_END //------------------------------------------------------ DateFormatSymbols::DateFormatSymbols(const Locale& locale, UErrorCode& status) : UObject() { initializeData(locale, NULL, status); } DateFormatSymbols::DateFormatSymbols(UErrorCode& status) : UObject() { initializeData(Locale::getDefault(), NULL, status, TRUE); } DateFormatSymbols::DateFormatSymbols(const Locale& locale, const char *type, UErrorCode& status) : UObject() { initializeData(locale, type, status); } DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status) : UObject() { initializeData(Locale::getDefault(), type, status, TRUE); } DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other) : UObject(other) { copyData(other); } void DateFormatSymbols::assignArray(UnicodeString*& dstArray, int32_t& dstCount, const UnicodeString* srcArray, int32_t srcCount) { // assignArray() is only called by copyData(), which in turn implements the // copy constructor and the assignment operator. // All strings in a DateFormatSymbols object are created in one of the following // three ways that all allow to safely use UnicodeString::fastCopyFrom(): // - readonly-aliases from resource bundles // - readonly-aliases or allocated strings from constants // - safely cloned strings (with owned buffers) from setXYZ() functions // // Note that this is true for as long as DateFormatSymbols can be constructed // only from a locale bundle or set via the cloning API, // *and* for as long as all the strings are in *private* fields, preventing // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()). dstCount = srcCount; dstArray = newUnicodeStringArray(srcCount); if(dstArray != NULL) { int32_t i; for(i=0; iclone(); }else{ UErrorCode status =U_ZERO_ERROR; fResourceBundle = ures_clone(other.fResourceBundle, &status); // TODO: what should be done in case of error? } // fastCopyFrom() - see assignArray comments fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars); } /** * Assignment operator. */ DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other) { dispose(); copyData(other); return *this; } DateFormatSymbols::~DateFormatSymbols() { dispose(); } void DateFormatSymbols::dispose() { if (fEras) delete[] fEras; if (fEraNames) delete[] fEraNames; if (fMonths) delete[] fMonths; if (fShortMonths) delete[] fShortMonths; if (fNarrowMonths) delete[] fNarrowMonths; if (fStandaloneMonths) delete[] fStandaloneMonths; if (fStandaloneShortMonths) delete[] fStandaloneShortMonths; if (fStandaloneNarrowMonths) delete[] fStandaloneNarrowMonths; if (fWeekdays) delete[] fWeekdays; if (fShortWeekdays) delete[] fShortWeekdays; if (fNarrowWeekdays) delete[] fNarrowWeekdays; if (fStandaloneWeekdays) delete[] fStandaloneWeekdays; if (fStandaloneShortWeekdays) delete[] fStandaloneShortWeekdays; if (fStandaloneNarrowWeekdays) delete[] fStandaloneNarrowWeekdays; if (fAmPms) delete[] fAmPms; if (fQuarters) delete[] fQuarters; if (fShortQuarters) delete[] fShortQuarters; if (fStandaloneQuarters) delete[] fStandaloneQuarters; if (fStandaloneShortQuarters) delete[] fStandaloneShortQuarters; disposeZoneStrings(); } void DateFormatSymbols::disposeZoneStrings() { if (fZoneStrings) { for (int32_t row=0; row0) { --count; if (array1[count] != array2[count]) return FALSE; } return TRUE; } UBool DateFormatSymbols::operator==(const DateFormatSymbols& other) const { // First do cheap comparisons if (this == &other) { return TRUE; } if (fErasCount == other.fErasCount && fEraNamesCount == other.fEraNamesCount && fMonthsCount == other.fMonthsCount && fShortMonthsCount == other.fShortMonthsCount && fNarrowMonthsCount == other.fNarrowMonthsCount && fStandaloneMonthsCount == other.fStandaloneMonthsCount && fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount && fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount && fWeekdaysCount == other.fWeekdaysCount && fShortWeekdaysCount == other.fShortWeekdaysCount && fNarrowWeekdaysCount == other.fNarrowWeekdaysCount && fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount && fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount && fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount && fAmPmsCount == other.fAmPmsCount && fQuartersCount == other.fQuartersCount && fShortQuartersCount == other.fShortQuartersCount && fStandaloneQuartersCount == other.fStandaloneQuartersCount && fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount) { // Now compare the arrays themselves if (arrayCompare(fEras, other.fEras, fErasCount) && arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) && arrayCompare(fMonths, other.fMonths, fMonthsCount) && arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) && arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) && arrayCompare(fStandaloneMonths, other.fStandaloneMonths, fStandaloneMonthsCount) && arrayCompare(fStandaloneShortMonths, other.fStandaloneShortMonths, fStandaloneShortMonthsCount) && arrayCompare(fStandaloneNarrowMonths, other.fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount) && arrayCompare(fWeekdays, other.fWeekdays, fWeekdaysCount) && arrayCompare(fShortWeekdays, other.fShortWeekdays, fShortWeekdaysCount) && arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) && arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) && arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) && arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) && arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) && arrayCompare(fQuarters, other.fQuarters, fQuartersCount) && arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) && arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) && arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount)) { if(fZoneStringsHash == NULL || other.fZoneStringsHash == NULL){ // fZoneStringsHash is not initialized compare the resource bundles if(ures_equal(fResourceBundle, other.fResourceBundle)== FALSE){ return FALSE; } }else{ if(fZoneStringsHash->equals(*other.fZoneStringsHash) == FALSE){ return FALSE; } // we always make sure that we update the enumeration when the hash is // updated. So we can be sure that once we compare the hashes the // enumerations are also equal } // since fZoneStrings data member is deprecated .. and may not be initialized // so don't compare them return TRUE; } } return FALSE; } //------------------------------------------------------ const UnicodeString* DateFormatSymbols::getEras(int32_t &count) const { count = fErasCount; return fEras; } const UnicodeString* DateFormatSymbols::getEraNames(int32_t &count) const { count = fEraNamesCount; return fEraNames; } const UnicodeString* DateFormatSymbols::getMonths(int32_t &count) const { count = fMonthsCount; return fMonths; } const UnicodeString* DateFormatSymbols::getShortMonths(int32_t &count) const { count = fShortMonthsCount; return fShortMonths; } const UnicodeString* DateFormatSymbols::getMonths(int32_t &count, DtContextType context, DtWidthType width ) const { UnicodeString *returnValue = NULL; switch (context) { case FORMAT : switch(width) { case WIDE : count = fMonthsCount; returnValue = fMonths; break; case ABBREVIATED : count = fShortMonthsCount; returnValue = fShortMonths; break; case NARROW : count = fNarrowMonthsCount; returnValue = fNarrowMonths; break; case DT_WIDTH_COUNT : break; } break; case STANDALONE : switch(width) { case WIDE : count = fStandaloneMonthsCount; returnValue = fStandaloneMonths; break; case ABBREVIATED : count = fStandaloneShortMonthsCount; returnValue = fStandaloneShortMonths; break; case NARROW : count = fStandaloneNarrowMonthsCount; returnValue = fStandaloneNarrowMonths; break; case DT_WIDTH_COUNT : break; } break; case DT_CONTEXT_COUNT : break; } return returnValue; } const UnicodeString* DateFormatSymbols::getWeekdays(int32_t &count) const { count = fWeekdaysCount; return fWeekdays; } const UnicodeString* DateFormatSymbols::getShortWeekdays(int32_t &count) const { count = fShortWeekdaysCount; return fShortWeekdays; } const UnicodeString* DateFormatSymbols::getWeekdays(int32_t &count, DtContextType context, DtWidthType width) const { UnicodeString *returnValue = NULL; switch (context) { case FORMAT : switch(width) { case WIDE : count = fWeekdaysCount; returnValue = fWeekdays; break; case ABBREVIATED : count = fShortWeekdaysCount; returnValue = fShortWeekdays; break; case NARROW : count = fNarrowWeekdaysCount; returnValue = fNarrowWeekdays; break; case DT_WIDTH_COUNT : break; } break; case STANDALONE : switch(width) { case WIDE : count = fStandaloneWeekdaysCount; returnValue = fStandaloneWeekdays; break; case ABBREVIATED : count = fStandaloneShortWeekdaysCount; returnValue = fStandaloneShortWeekdays; break; case NARROW : count = fStandaloneNarrowWeekdaysCount; returnValue = fStandaloneNarrowWeekdays; break; case DT_WIDTH_COUNT : break; } break; case DT_CONTEXT_COUNT : break; } return returnValue; } const UnicodeString* DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthType width ) const { UnicodeString *returnValue = NULL; switch (context) { case FORMAT : switch(width) { case WIDE : count = fQuartersCount; returnValue = fQuarters; break; case ABBREVIATED : count = fShortQuartersCount; returnValue = fShortQuarters; break; case NARROW : count = 0; returnValue = NULL; break; case DT_WIDTH_COUNT : break; } break; case STANDALONE : switch(width) { case WIDE : count = fStandaloneQuartersCount; returnValue = fStandaloneQuarters; break; case ABBREVIATED : count = fStandaloneShortQuartersCount; returnValue = fStandaloneShortQuarters; break; case NARROW : count = 0; returnValue = NULL; break; case DT_WIDTH_COUNT : break; } break; case DT_CONTEXT_COUNT : break; } return returnValue; } const UnicodeString* DateFormatSymbols::getAmPmStrings(int32_t &count) const { count = fAmPmsCount; return fAmPms; } //------------------------------------------------------ void DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count) { // delete the old list if we own it if (fEras) delete[] fEras; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fEras = newUnicodeStringArray(count); uprv_arrayCopy(erasArray,fEras, count); fErasCount = count; } void DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count) { // delete the old list if we own it if (fEraNames) delete[] fEraNames; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fEraNames = newUnicodeStringArray(count); uprv_arrayCopy(eraNamesArray,fEraNames, count); fEraNamesCount = count; } void DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count) { // delete the old list if we own it if (fMonths) delete[] fMonths; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fMonths = newUnicodeStringArray(count); uprv_arrayCopy( monthsArray,fMonths,count); fMonthsCount = count; } void DateFormatSymbols::setShortMonths(const UnicodeString* shortMonthsArray, int32_t count) { // delete the old list if we own it if (fShortMonths) delete[] fShortMonths; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fShortMonths = newUnicodeStringArray(count); uprv_arrayCopy(shortMonthsArray,fShortMonths, count); fShortMonthsCount = count; } void DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, DtContextType context, DtWidthType width) { // delete the old list if we own it // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) switch (context) { case FORMAT : switch (width) { case WIDE : if (fMonths) delete[] fMonths; fMonths = newUnicodeStringArray(count); uprv_arrayCopy( monthsArray,fMonths,count); fMonthsCount = count; break; case ABBREVIATED : if (fShortMonths) delete[] fShortMonths; fShortMonths = newUnicodeStringArray(count); uprv_arrayCopy( monthsArray,fShortMonths,count); fShortMonthsCount = count; break; case NARROW : if (fNarrowMonths) delete[] fNarrowMonths; fNarrowMonths = newUnicodeStringArray(count); uprv_arrayCopy( monthsArray,fNarrowMonths,count); fNarrowMonthsCount = count; break; case DT_WIDTH_COUNT : break; } break; case STANDALONE : switch (width) { case WIDE : if (fStandaloneMonths) delete[] fStandaloneMonths; fStandaloneMonths = newUnicodeStringArray(count); uprv_arrayCopy( monthsArray,fStandaloneMonths,count); fStandaloneMonthsCount = count; break; case ABBREVIATED : if (fStandaloneShortMonths) delete[] fStandaloneShortMonths; fStandaloneShortMonths = newUnicodeStringArray(count); uprv_arrayCopy( monthsArray,fStandaloneShortMonths,count); fStandaloneShortMonthsCount = count; break; case NARROW : if (fStandaloneNarrowMonths) delete[] fStandaloneNarrowMonths; fStandaloneNarrowMonths = newUnicodeStringArray(count); uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count); fStandaloneNarrowMonthsCount = count; break; case DT_WIDTH_COUNT : break; } break; case DT_CONTEXT_COUNT : break; } } void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count) { // delete the old list if we own it if (fWeekdays) delete[] fWeekdays; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray,fWeekdays,count); fWeekdaysCount = count; } void DateFormatSymbols::setShortWeekdays(const UnicodeString* shortWeekdaysArray, int32_t count) { // delete the old list if we own it if (fShortWeekdays) delete[] fShortWeekdays; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fShortWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(shortWeekdaysArray, fShortWeekdays, count); fShortWeekdaysCount = count; } void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count, DtContextType context, DtWidthType width) { // delete the old list if we own it // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) switch (context) { case FORMAT : switch (width) { case WIDE : if (fWeekdays) delete[] fWeekdays; fWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fWeekdays, count); fWeekdaysCount = count; break; case ABBREVIATED : if (fShortWeekdays) delete[] fShortWeekdays; fShortWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fShortWeekdays, count); fShortWeekdaysCount = count; break; case NARROW : if (fNarrowWeekdays) delete[] fNarrowWeekdays; fNarrowWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count); fNarrowWeekdaysCount = count; break; case DT_WIDTH_COUNT : break; } break; case STANDALONE : switch (width) { case WIDE : if (fStandaloneWeekdays) delete[] fStandaloneWeekdays; fStandaloneWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fStandaloneWeekdays, count); fStandaloneWeekdaysCount = count; break; case ABBREVIATED : if (fStandaloneShortWeekdays) delete[] fStandaloneShortWeekdays; fStandaloneShortWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fStandaloneShortWeekdays, count); fStandaloneShortWeekdaysCount = count; break; case NARROW : if (fStandaloneNarrowWeekdays) delete[] fStandaloneNarrowWeekdays; fStandaloneNarrowWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count); fStandaloneNarrowWeekdaysCount = count; break; case DT_WIDTH_COUNT : break; } break; case DT_CONTEXT_COUNT : break; } } void DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count, DtContextType context, DtWidthType width) { // delete the old list if we own it // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) switch (context) { case FORMAT : switch (width) { case WIDE : if (fQuarters) delete[] fQuarters; fQuarters = newUnicodeStringArray(count); uprv_arrayCopy( quartersArray,fQuarters,count); fQuartersCount = count; break; case ABBREVIATED : if (fShortQuarters) delete[] fShortQuarters; fShortQuarters = newUnicodeStringArray(count); uprv_arrayCopy( quartersArray,fShortQuarters,count); fShortQuartersCount = count; break; case NARROW : /* if (fNarrowQuarters) delete[] fNarrowQuarters; fNarrowQuarters = newUnicodeStringArray(count); uprv_arrayCopy( quartersArray,fNarrowQuarters,count); fNarrowQuartersCount = count; */ break; case DT_WIDTH_COUNT : break; } break; case STANDALONE : switch (width) { case WIDE : if (fStandaloneQuarters) delete[] fStandaloneQuarters; fStandaloneQuarters = newUnicodeStringArray(count); uprv_arrayCopy( quartersArray,fStandaloneQuarters,count); fStandaloneQuartersCount = count; break; case ABBREVIATED : if (fStandaloneShortQuarters) delete[] fStandaloneShortQuarters; fStandaloneShortQuarters = newUnicodeStringArray(count); uprv_arrayCopy( quartersArray,fStandaloneShortQuarters,count); fStandaloneShortQuartersCount = count; break; case NARROW : /* if (fStandaloneNarrowQuarters) delete[] fStandaloneNarrowQuarters; fStandaloneNarrowQuarters = newUnicodeStringArray(count); uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count); fStandaloneNarrowQuartersCount = count; */ break; case DT_WIDTH_COUNT : break; } break; case DT_CONTEXT_COUNT : break; } } void DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count) { // delete the old list if we own it if (fAmPms) delete[] fAmPms; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fAmPms = newUnicodeStringArray(count); uprv_arrayCopy(amPmsArray,fAmPms,count); fAmPmsCount = count; } //------------------------------------------------------ const UnicodeString** DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const { umtx_lock(&LOCK); UErrorCode status = U_ZERO_ERROR; if(fZoneStrings==NULL){ // cast away const to get around the problem for lazy initialization ((DateFormatSymbols*)this)->initZoneStringsArray(status); } rowCount = fZoneStringsRowCount; columnCount = fZoneStringsColCount; umtx_unlock(&LOCK); if(U_FAILURE(status)){ rowCount = 0; columnCount = 0; return NULL; } return (const UnicodeString**)fZoneStrings; // Compiler requires cast } void DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount) { // since deleting a 2-d array is a pain in the butt, we offload that task to // a separate function disposeZoneStrings(); UErrorCode status = U_ZERO_ERROR; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fZoneStringsRowCount = rowCount; fZoneStringsColCount = columnCount; createZoneStrings((const UnicodeString**)strings); initZoneStrings((const UnicodeString**)strings, rowCount,columnCount, status); } //------------------------------------------------------ const UChar * U_EXPORT2 DateFormatSymbols::getPatternUChars(void) { return gPatternChars; } //------------------------------------------------------ UnicodeString& DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const { // fastCopyFrom() - see assignArray comments return result.fastCopyFrom(fLocalPatternChars); } //------------------------------------------------------ void DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars) { fLocalPatternChars = newLocalPatternChars; } //------------------------------------------------------ static void initField(UnicodeString **field, int32_t& length, const UResourceBundle *data, UErrorCode &status) { if (U_SUCCESS(status)) { int32_t strLen = 0; length = ures_getSize(data); *field = newUnicodeStringArray(length); if (*field) { for(int32_t i = 0; isetTo(TRUE, resStr, strLen); } } else { length = 0; status = U_MEMORY_ALLOCATION_ERROR; } } } static void initField(UnicodeString **field, int32_t& length, const UChar *data, LastResortSize numStr, LastResortSize strLen, UErrorCode &status) { if (U_SUCCESS(status)) { length = numStr; *field = newUnicodeStringArray((size_t)numStr); if (*field) { for(int32_t i = 0; isetTo(TRUE, data+(i*((int32_t)strLen)), -1); } } else { length = 0; status = U_MEMORY_ALLOCATION_ERROR; } } } void DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData) { int32_t i; int32_t len = 0; const UChar *resStr; /* In case something goes wrong, initialize all of the data to NULL. */ fEras = NULL; fErasCount = 0; fEraNames = NULL; fEraNamesCount = 0; fMonths = NULL; fMonthsCount=0; fShortMonths = NULL; fShortMonthsCount=0; fNarrowMonths = NULL; fNarrowMonthsCount=0; fStandaloneMonths = NULL; fStandaloneMonthsCount=0; fStandaloneShortMonths = NULL; fStandaloneShortMonthsCount=0; fStandaloneNarrowMonths = NULL; fStandaloneNarrowMonthsCount=0; fWeekdays = NULL; fWeekdaysCount=0; fShortWeekdays = NULL; fShortWeekdaysCount=0; fNarrowWeekdays = NULL; fNarrowWeekdaysCount=0; fStandaloneWeekdays = NULL; fStandaloneWeekdaysCount=0; fStandaloneShortWeekdays = NULL; fStandaloneShortWeekdaysCount=0; fStandaloneNarrowWeekdays = NULL; fStandaloneNarrowWeekdaysCount=0; fAmPms = NULL; fAmPmsCount=0; fQuarters = NULL; fQuartersCount = 0; fShortQuarters = NULL; fShortQuartersCount = 0; fStandaloneQuarters = NULL; fStandaloneQuartersCount = 0; fStandaloneShortQuarters = NULL; fStandaloneShortQuartersCount = 0; fZoneStringsRowCount = 0; fZoneStringsColCount = 0; fZoneStrings = NULL; fZoneStringsHash = NULL; fZoneIDEnumeration = NULL; fResourceBundle = NULL; fCountry = NULL; if (U_FAILURE(status)) return; /** * Retrieve the string arrays we need from the resource bundle file. * We cast away const here, but that's okay; we won't delete any of * these. */ CalendarData calData(locale, type, status); fResourceBundle = ures_open(NULL, locale.getName(), &status); fCountry = locale.getCountry(); // load the first data item UResourceBundle *erasMain = calData.getByKey(gErasTag, status); UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status); UErrorCode oldStatus = status; UResourceBundle *eraNames = ures_getByKeyWithFallback(erasMain, gNamesWideTag, NULL, &status); if ( status == U_MISSING_RESOURCE_ERROR ) { // Workaround because eras/wide was omitted from CLDR 1.3 status = oldStatus; eraNames = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status); } UResourceBundle *lsweekdaysData = NULL; // Data closed by calData UResourceBundle *weekdaysData = NULL; // Data closed by calData UResourceBundle *narrowWeekdaysData = NULL; // Data closed by calData UResourceBundle *standaloneWeekdaysData = NULL; // Data closed by calData UResourceBundle *standaloneShortWeekdaysData = NULL; // Data closed by calData UResourceBundle *standaloneNarrowWeekdaysData = NULL; // Data closed by calData U_LOCALE_BASED(locBased, *this); if (U_FAILURE(status)) { if (useLastResortData) { // Handle the case in which there is no resource data present. // We don't have to generate usable patterns in this situation; // we just need to produce something that will be semi-intelligible // in most locales. status = U_USING_FALLBACK_WARNING; initField(&fEras, fErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status); initField(&fEraNames, fEraNamesCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status); initField(&fMonths, fMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fShortMonths, fShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fNarrowMonths, fNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fStandaloneMonths, fStandaloneMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fWeekdays, fWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status); initField(&fShortWeekdays, fShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status); initField(&fNarrowWeekdays, fNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status); initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status); initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status); initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status); initField(&fAmPms, fAmPmsCount, (const UChar *)gLastResortAmPmMarkers, kAmPmNum, kAmPmLen, status); initField(&fQuarters, fQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status); initField(&fShortQuarters, fShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status); initField(&fStandaloneQuarters, fStandaloneQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status); initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status); fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN); } goto cleanup; } // if we make it to here, the resource data is cool, and we can get everything out // of it that we need except for the time-zone and localized-pattern data, which // are stored in a separate file locBased.setLocaleIDs(ures_getLocaleByType(eras, ULOC_VALID_LOCALE, &status), ures_getLocaleByType(eras, ULOC_ACTUAL_LOCALE, &status)); initField(&fEras, fErasCount, eras, status); initField(&fEraNames, fEraNamesCount, eraNames, status); initField(&fMonths, fMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status); initField(&fShortMonths, fShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status); initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status); if(status == U_MISSING_RESOURCE_ERROR) { status = U_ZERO_ERROR; initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status); } if ( status == U_MISSING_RESOURCE_ERROR ) { /* If format/narrow not available, use format/abbreviated */ status = U_ZERO_ERROR; initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status); } initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status); if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/wide not available, use format/wide */ status = U_ZERO_ERROR; initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status); } initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status); if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/abbreviated not available, use format/abbreviated */ status = U_ZERO_ERROR; initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status); } initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status); if ( status == U_MISSING_RESOURCE_ERROR ) { /* if standalone/narrow not availabe, try format/narrow */ status = U_ZERO_ERROR; initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status); if ( status == U_MISSING_RESOURCE_ERROR ) { /* if still not there, use format/abbreviated */ status = U_ZERO_ERROR; initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status); } } initField(&fAmPms, fAmPmsCount, calData.getByKey(gAmPmMarkersTag, status), status); initField(&fQuarters, fQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status); initField(&fShortQuarters, fShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status); initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status); if(status == U_MISSING_RESOURCE_ERROR) { status = U_ZERO_ERROR; initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status); } initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status); if(status == U_MISSING_RESOURCE_ERROR) { status = U_ZERO_ERROR; initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status); } // ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597) /* // fastCopyFrom()/setTo() - see assignArray comments resStr = ures_getStringByKey(fResourceBundle, gLocalPatternCharsTag, &len, &status); fLocalPatternChars.setTo(TRUE, resStr, len); // If the locale data does not include new pattern chars, use the defaults // TODO: Consider making this an error, since this may add conflicting characters. if (len < PATTERN_CHARS_LEN) { fLocalPatternChars.append(UnicodeString(TRUE, &gPatternChars[len], PATTERN_CHARS_LEN-len)); } */ fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN); // {sfb} fixed to handle 1-based weekdays weekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status); fWeekdaysCount = ures_getSize(weekdaysData); fWeekdays = new UnicodeString[fWeekdaysCount+1]; /* pin the blame on system. If we cannot get a chunk of memory .. the system is dying!*/ if (fWeekdays == NULL) { status = U_MEMORY_ALLOCATION_ERROR; goto cleanup; } // leave fWeekdays[0] empty for(i = 0; i= 0) { return result; } // Do a search through the equivalency group for the given ID int32_t n = TimeZone::countEquivalentIDs(ID); if (n > 1) { int32_t i; for (i=0; i= 0) { return equivResult; } } } } return -1; } /** * Lookup the given ID. Do NOT do an equivalency search. */ int32_t DateFormatSymbols::_getZoneIndex(const UnicodeString& ID) const { for(int32_t index = 0; index < fZoneStringsRowCount; index++) { if (0 == ID.caseCompare(fZoneStrings[index][0], 0)) { return index; } } return -1; } Locale DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const { U_LOCALE_BASED(locBased, *this); return locBased.getLocale(type, status); } class TimeZoneKeysEnumeration : public StringEnumeration { private: UnicodeString* strings; int32_t length; int32_t current; int32_t capacity; TimeZoneKeysEnumeration(UnicodeString* oldStrs, int32_t count){ strings = newUnicodeStringArray(count); if(strings==NULL){ return; } capacity = count; current = 0; for(length = 0; lengthcount(status); fZoneStringsColCount = 8; fZoneStrings = (UnicodeString **)uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString *)); /* if we can't get a chunk of heap then the system is going down. Pin the blame on system*/ if (fZoneStrings == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return; } const UnicodeString *zid = NULL; TimeZoneKeysEnumeration *keys = (TimeZoneKeysEnumeration*) fZoneIDEnumeration; int32_t pos = 0; int32_t i = 0; while((zid=keys->snext(pos,status))!=NULL){ *(fZoneStrings+i) = newUnicodeStringArray(fZoneStringsColCount); /* test for NULL */ if ((*(fZoneStrings+i)) == 0) { status = U_MEMORY_ALLOCATION_ERROR; return; } UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(*zid); fZoneStrings[i][0].setTo(*zid); fZoneStrings[i][1].setTo(strings[TIMEZONE_LONG_STANDARD]); fZoneStrings[i][2].setTo(strings[TIMEZONE_SHORT_STANDARD]); fZoneStrings[i][3].setTo(strings[TIMEZONE_LONG_DAYLIGHT]); fZoneStrings[i][4].setTo(strings[TIMEZONE_SHORT_DAYLIGHT]); fZoneStrings[i][5].setTo(strings[TIMEZONE_EXEMPLAR_CITY]); fZoneStrings[i][6].setTo(strings[TIMEZONE_LONG_GENERIC]); fZoneStrings[i][7].setTo(strings[TIMEZONE_SHORT_GENERIC]); i++; } } U_CDECL_BEGIN static UBool U_CALLCONV compareTZHashValues(const UHashTok val1, const UHashTok val2){ const UnicodeString* array1 = (UnicodeString*) val1.pointer; const UnicodeString* array2 = (UnicodeString*) val2.pointer; if(array1==array2){ return TRUE; } if(array1==NULL || array2==NULL){ return FALSE; } for(int32_t j=0; j< UTZ_MAX_DISPLAY_STRINGS_LENGTH; j++){ if(array1[j] != array2[j]){ return FALSE; } } return TRUE; } U_CDECL_END void DateFormatSymbols::initZoneStrings(UErrorCode &status){ if(U_FAILURE(status)){ return; } if(fZoneStringsHash != NULL){ return; } int32_t i; fZoneStringsHash = new Hashtable(uhash_compareUnicodeString, compareTZHashValues, status); if(fZoneStringsHash==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } fZoneStringsHash->setValueDeleter(deleteUnicodeStringArray); if(fResourceBundle != NULL){ UnicodeString solidus = UNICODE_STRING_SIMPLE("/"); UnicodeString colon = UNICODE_STRING_SIMPLE(":"); UResourceBundle *zoneArray, *zoneItem; for(const UResourceBundle* rb = fResourceBundle; rb!=NULL; rb=ures_getParentBundle(rb)){ zoneArray = ures_getByKey(rb, gZoneStringsTag, NULL, &status); if(U_FAILURE(status)){ break; } while(ures_hasNext(zoneArray)){ UErrorCode tempStatus = U_ZERO_ERROR; zoneItem = ures_getNextResource(zoneArray, NULL, &status); UnicodeString key(ures_getKey(zoneItem), -1, US_INV); if (key.indexOf(colon) == -1) { ures_close(zoneItem); continue; } UnicodeString* strArray = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); key.findAndReplace(colon, solidus); int32_t len = 0; //fetch the strings with fine grained fallback const UChar* str = ures_getStringByKeyWithFallback(zoneItem,UTZ_SHORT_STANDARD, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_SHORT_STANDARD].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(zoneItem,UTZ_SHORT_GENERIC, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_SHORT_GENERIC].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(zoneItem,UTZ_SHORT_DAYLIGHT, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_SHORT_DAYLIGHT].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(zoneItem,UTZ_LONG_STANDARD, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_LONG_STANDARD].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(zoneItem,UTZ_LONG_GENERIC, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_LONG_GENERIC].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(zoneItem,UTZ_LONG_DAYLIGHT, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_LONG_DAYLIGHT].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(zoneItem,UTZ_EXEMPLAR_CITY, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_EXEMPLAR_CITY].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } // store the strings in hash fZoneStringsHash->put(key, strArray, status); ures_close(zoneItem); } ures_close(zoneArray); } // Need to make sure that all zoneStrings in root are covered as well, otherwise metazone lookups won't // work properly UResourceBundle* root_res = ures_open(NULL, "", &status); zoneArray = ures_getByKey(root_res, gZoneStringsTag, NULL, &status); if (U_SUCCESS(status)) { while(ures_hasNext(zoneArray)){ UErrorCode tempStatus = U_ZERO_ERROR; zoneItem = ures_getNextResource(zoneArray, NULL, &status); UnicodeString key(ures_getKey(zoneItem), -1, US_INV); if ( key.indexOf(colon) == -1 ) { ures_close(zoneItem); continue; } key.findAndReplace(colon, solidus); // Don't step on anything that is already there UnicodeString* existingArray = (UnicodeString*)fZoneStringsHash->get(key); if(existingArray != NULL){ ures_close(zoneItem); continue; } UnicodeString* strArray = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); int32_t len = 0; const UChar *str = ures_getStringByKeyWithFallback(zoneItem,UTZ_EXEMPLAR_CITY, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ strArray[TIMEZONE_EXEMPLAR_CITY].setTo(TRUE, str, len); }else{ tempStatus = U_ZERO_ERROR; } // store the strings in hash fZoneStringsHash->put(key, strArray, status); ures_close(zoneItem); } ures_close(zoneArray); ures_close(root_res); } int32_t length = fZoneStringsHash->count(); TimeZoneKeysEnumeration* keysEnum = new TimeZoneKeysEnumeration(length, status); fZoneIDEnumeration = keysEnum; if(fZoneIDEnumeration==NULL){ delete fZoneStringsHash; fZoneStringsHash = NULL; status = U_MEMORY_ALLOCATION_ERROR; return; } int32_t pos=-1; const UnicodeString* key; const UHashElement* elem = NULL; while((elem = fZoneStringsHash->nextElement(pos))!= NULL){ const UHashTok keyTok = elem->key; key = (const UnicodeString*)keyTok.pointer; keysEnum->put(*key, status); } }else{ //last resort strings UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); if(array==NULL){ delete fZoneStringsHash; status = U_MEMORY_ALLOCATION_ERROR; return; } int32_t length = ARRAY_LENGTH(gLastResortZoneStrings); UnicodeString key(gLastResortZoneStrings[0]); TimeZoneKeysEnumeration* keysEnum = new TimeZoneKeysEnumeration(length, status); fZoneIDEnumeration = keysEnum; if(fZoneIDEnumeration==NULL){ delete fZoneStringsHash; delete[] array; fZoneStringsHash = NULL; status = U_MEMORY_ALLOCATION_ERROR; return; } keysEnum->put(key, status); int32_t j=1; for(i=0; i< length; ){ array[i++].setTo(gLastResortZoneStrings[j++]); } fZoneStringsHash->put(key, array, status); } } void DateFormatSymbols::initZoneStrings(const UnicodeString** strings, int32_t rowCount, int32_t columnCount, UErrorCode& status){ if(strings==NULL || rowCount<0 || columnCount<0){ status = U_ILLEGAL_ARGUMENT_ERROR; return; } TimeZoneKeysEnumeration* keysEnum = new TimeZoneKeysEnumeration(rowCount, status); fZoneIDEnumeration = keysEnum; if(U_FAILURE(status)){ return; } if(fZoneIDEnumeration==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } fZoneStringsHash = new Hashtable(uhash_compareUnicodeString, compareTZHashValues, status); if(U_FAILURE(status)){ return; } if(fZoneStringsHash==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } fZoneStringsHash->setValueDeleter(deleteUnicodeStringArray); for (int32_t row=0; rowput(key, status); UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); if(array==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } for (int32_t col=1; colput(strings[row][0], array, status); } } } UnicodeString& DateFormatSymbols::getZoneString(const UnicodeString &zid, const TimeZoneTranslationType type, UnicodeString &result, UErrorCode &status){ if(fZoneStringsHash == NULL){ //lazy initialization initZoneStrings(status); } if(U_FAILURE(status)){ return result; } UnicodeString* stringsArray = (UnicodeString*)fZoneStringsHash->get(zid); if(stringsArray != NULL){ result.setTo(stringsArray[type],0); } return result; } UnicodeString& DateFormatSymbols::getMetazoneString(const UnicodeString &zid, const TimeZoneTranslationType type, Calendar &cal, UnicodeString &result, UErrorCode &status) { UErrorCode tempStatus = U_ZERO_ERROR; int32_t len; // Get the appropriate metazone mapping from the resource bundles char usesMetazoneKey[ZID_KEY_MAX]; char zidkey[ZID_KEY_MAX]; uprv_strcpy(usesMetazoneKey,gZoneStringsTag); uprv_strcat(usesMetazoneKey,"/"); len = zid.length(); len = (len >= (ZID_KEY_MAX-1) ? ZID_KEY_MAX-1 : len); u_UCharsToChars(zid.getBuffer(), zidkey, len); zidkey[len] = 0; // NULL terminate // Replace / with : for zid len = (int32_t)uprv_strlen(zidkey); for (int i = 0; i < len; i++) { if (zidkey[i] == '/') { zidkey[i] = ':'; } } uprv_strcat(usesMetazoneKey,zidkey); uprv_strcat(usesMetazoneKey,"/"); uprv_strcat(usesMetazoneKey,UTZ_USES_METAZONE); UResourceBundle *um = ures_getByKeyWithFallback(fResourceBundle, usesMetazoneKey, NULL, &tempStatus); if (U_FAILURE(tempStatus)) { return result; } UnicodeString* stringsArray = (UnicodeString*)fZoneStringsHash->get(zid); if(stringsArray != NULL){ SimpleDateFormat df(UNICODE_STRING_SIMPLE("yyyy-MM-dd HH:mm"), Locale(""),tempStatus); TimeZone *tz = TimeZone::createTimeZone(zid); df.setTimeZone(*tz); delete tz; UnicodeString theTime; df.format(cal.getTime(tempStatus),theTime); while (ures_hasNext(um)) { UResourceBundle *mz = ures_getNextResource(um,NULL,&status); const UChar *mz_name = ures_getStringByIndex(mz,0,&len,&status); const UChar *mz_from = ures_getStringByIndex(mz,1,&len,&status); const UChar *mz_to = ures_getStringByIndex(mz,2,&len,&status); ures_close(mz); if(U_FAILURE(status)){ break; } if (mz_name[0] != 0 && UnicodeString(TRUE, mz_from, -1) <= theTime && UnicodeString(TRUE, mz_to, -1) > theTime ) { UnicodeString mzid(UNICODE_STRING_SIMPLE("meta/")); mzid += mz_name; getZoneString(mzid,type,result,status); break; } } } ures_close(um); return result; } StringEnumeration* DateFormatSymbols::createZoneStringIDs(UErrorCode &status){ if(U_FAILURE(status)){ return NULL; } if(fZoneStringsHash == NULL){ //lazy initialization initZoneStrings(status); } return fZoneIDEnumeration->clone(); } /** * Sets timezone strings. * @draft ICU 3.6 */ void DateFormatSymbols::setZoneString(const UnicodeString &zid, const TimeZoneTranslationType type, const UnicodeString &value, UErrorCode &status){ if(fZoneStringsHash == NULL){ //lazy initialization initZoneStrings(status); } if(U_FAILURE(status)){ return; } UnicodeString* stringsArray = (UnicodeString*)fZoneStringsHash->get(zid); if(stringsArray != NULL){ stringsArray[type].setTo(value); }else{ stringsArray = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); if(stringsArray==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } stringsArray[type].setTo(value); fZoneStringsHash->put(zid, stringsArray, status); TimeZoneKeysEnumeration* keys = (TimeZoneKeysEnumeration*) fZoneIDEnumeration; keys->put(zid, status); } } Hashtable* DateFormatSymbols::createZoneStringsHash(const Hashtable* otherHash){ UErrorCode status = U_ZERO_ERROR; Hashtable* hash = new Hashtable(uhash_compareUnicodeString, compareTZHashValues, status); if(hash==NULL){ return NULL; } if(U_FAILURE(status)){ return NULL; } hash->setValueDeleter(deleteUnicodeStringArray); int32_t pos = -1; const UHashElement* elem = NULL; // walk through the hash table and create a deep clone while((elem = otherHash->nextElement(pos))!= NULL){ const UHashTok otherKeyTok = elem->key; const UHashTok otherValueTok = elem->value; UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer; UnicodeString* otherArray = (UnicodeString*)otherValueTok.pointer; UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); if(array==NULL){ return NULL; } UnicodeString key(*otherKey); for(int32_t i=0; iput(key, array, status); if(U_FAILURE(status)){ delete[] array; return NULL; } } return hash; } UnicodeString& DateFormatSymbols::getZoneID(const UnicodeString& zid, UnicodeString& result, UErrorCode& status){ if(fZoneStringsHash == NULL){ initZoneStrings(status); } if(U_FAILURE(status)){ return result; } UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(zid); if (strings != NULL) { return result.setTo(zid,0); } // Do a search through the equivalency group for the given ID int32_t n = TimeZone::countEquivalentIDs(zid); if (n > 1) { int32_t i; for (i=0; iget(equivID); if (strings != NULL) { return result.setTo(equivID,0); } } } }else{ result.setTo(zid); } return result; } void DateFormatSymbols::getZoneType(const UnicodeString& zid, const UnicodeString& text, int32_t start, TimeZoneTranslationType& type, UnicodeString& value, UErrorCode& status){ if(fZoneStringsHash == NULL){ initZoneStrings(status); } if(U_FAILURE(status)){ return; } type = TIMEZONE_COUNT; UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(zid); if(strings != NULL){ for(int32_t j=0; j0 && text.caseCompare(start, strings[j].length(), strings[j], 0)==0){ type = (TimeZoneTranslationType)j; value.setTo(strings[j]); return; } } } } void DateFormatSymbols::findZoneIDTypeValue( UnicodeString& zid, const UnicodeString& text, int32_t start, TimeZoneTranslationType& type, UnicodeString& value, UErrorCode& status){ if(fZoneStringsHash == NULL){ initZoneStrings(status); } if(U_FAILURE(status)){ return; } const UnicodeString* myKey = NULL; int32_t pos = 0; TimeZoneKeysEnumeration *keys = (TimeZoneKeysEnumeration*)fZoneIDEnumeration; while( (myKey=keys->snext(pos, status))!= NULL){ UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(*myKey); if(strings != NULL){ for(int32_t j=0; j0 && text.caseCompare(start, strings[j].length(), strings[j], 0)==0){ type = (TimeZoneTranslationType)j; value.setTo(strings[j]); if (myKey->startsWith(UNICODE_STRING_SIMPLE("meta"))) { zid.setTo(resolveParsedMetazone(*myKey)); } else zid.setTo(*myKey); return; } } } } } UnicodeString DateFormatSymbols::resolveParsedMetazone( const UnicodeString& zid ) { UErrorCode status = U_ZERO_ERROR; UResourceBundle* supplementalDataBundle = ures_openDirect(NULL, kSUPPLEMENTAL, &status); UResourceBundle* mapTz = ures_getByKey(supplementalDataBundle, gMaptimezonesTag, NULL, &status); if(U_FAILURE(status)){ ures_close(supplementalDataBundle); return UNICODE_STRING_SIMPLE("Etc/GMT"); } UResourceBundle* metazoneMap = ures_getByKey(mapTz, gMetazonesTag, NULL, &status); char mzMapKey[ZID_KEY_MAX+4]; int32_t len = zid.length(); len = (len >= (ZID_KEY_MAX-1) ? ZID_KEY_MAX-1 : len); u_UCharsToChars(zid.getBuffer(), mzMapKey, len); mzMapKey[len] = 0; // NULL terminate for (int i = 0; i < len; i++) { if (mzMapKey[i] == '/') { mzMapKey[i] = ':'; } } uprv_strcat(mzMapKey,"_"); uprv_strcat(mzMapKey,fCountry); int32_t len2; const UChar* resStr = ures_getStringByKey(metazoneMap, mzMapKey, &len2, &status); // If we can't find a territory-specific metazone mapping, then use the generic one // which is the metazone name followed by _001 if(U_FAILURE(status)){ status = U_ZERO_ERROR; mzMapKey[len] = 0; uprv_strcat(mzMapKey,"_001"); resStr = ures_getStringByKey(metazoneMap, mzMapKey, &len2, &status); } ures_close(metazoneMap); ures_close(mapTz); ures_close(supplementalDataBundle); if(U_SUCCESS(status)){ return resStr; } else { return UNICODE_STRING_SIMPLE("Etc/GMT"); } } U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ //eof