/* ******************************************************************************* * Copyright (C) 1997-2005, 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 ******************************************************************************* */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include "unicode/dtfmtsym.h" #include "unicode/smpdtfmt.h" #include "ucln_in.h" #include "mutex.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 24 /** * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All * locales use the same these unlocalized pattern characters. */ static const UChar gPatternChars[] = { // GyMdkHmsSEDFwWahKzYeugAZvcL 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, 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] = { {0x0000, 0x0000}, /* "" */ {0x0031, 0x0000}, /* "1" */ {0x0032, 0x0000}, /* "2" */ {0x0033, 0x0000}, /* "3" */ {0x0034, 0x0000}, /* "4" */ {0x0035, 0x0000}, /* "5" */ {0x0036, 0x0000}, /* "6" */ {0x0037, 0x0000} /* "7" */ }; // 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[5][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" */ }; /* Sizes for the last resort string arrays */ typedef enum LastResortSize { kMonthNum = 13, kMonthLen = 3, kDayNum = 8, kDayLen = 2, kAmPmNum = 2, kAmPmLen = 3, kEraNum = 2, kEraLen = 3, kZoneNum = 5, kZoneLen = 4 } LastResortSize; U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols) /** * These are the tags we expect to see in normal resource bundle files associated * with a locale and calendar */ const char gErasTag[]="eras"; const char gAbbreviatedTag[] = "abbreviated"; const char gMonthNamesTag[]="monthNames"; const char gDayNamesTag[]="dayNames"; const char gNamesWideTag[]="wide"; const char gNamesAbbrTag[]="abbreviated"; const char gNamesNarrowTag[]="narrow"; const char gNamesStandaloneTag[]="stand-alone"; const char gAmPmMarkersTag[]="AmPmMarkers"; /** * These are the tags we expect to see in time zone data resource bundle files * associated with a locale. */ const char gZoneStringsTag[]="zoneStrings"; const char gLocalPatternCharsTag[]="localPatternChars"; static UMTX LOCK; static UnicodeString bogus; /* * Keep this variable in synch with max length of display strings */ #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" /** * 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]; } //------------------------------------------------------ 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; disposeZoneStrings(); } void DateFormatSymbols::disposeZoneStrings() { if (fZoneStrings) { for (int32_t row=0; rowcount(); i++){ const UHashElement* elem = fZoneStringsHash->nextElement(i); UnicodeString* array = (UnicodeString*)(elem->value.pointer); delete[] array; } delete fZoneStringsHash; fZoneStringsHash = NULL; } if(fZoneIDEnumeration){ delete fZoneIDEnumeration; fZoneIDEnumeration = NULL; } ures_close(fResourceBundle); fResourceBundle = NULL; } UBool DateFormatSymbols::arrayCompare(const UnicodeString* array1, const UnicodeString* array2, int32_t count) { if (array1 == array2) return TRUE; while (count>0) { --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) { // 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)) { 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(hashCompare(fZoneStringsHash, 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 //if(stringEnumCompare(fZoneIDEnumeration, other.fZoneIDEnumeration)==FALSE){ // return FALSE; //} } // since fZoneStrings data member is deprecated .. and may not be initialized // so don't compare them // fZoneStringsRowCount == other.fZoneStringsRowCount && //fZoneStringsColCount == other.fZoneStringsColCount //if (fZoneStrings == other.fZoneStrings) return TRUE; // //for (int32_t row=0; rowinitZoneStringsArray(status); if(U_FAILURE(status)){ return NULL; } } rowCount = fZoneStringsRowCount; columnCount = fZoneStringsColCount; umtx_unlock(&LOCK); 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(); // 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); } //------------------------------------------------------ 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; fZoneStringsRowCount = 0; fZoneStringsColCount = 0; fZoneStrings = NULL; fZoneStringsHash = NULL; fZoneIDEnumeration = NULL; fResourceBundle = 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((char*)0, locale.getName(), &status); // 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); fLocalPatternChars = gPatternChars; } 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 ) { /* 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); // 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)); } // {sfb} fixed to handle 1-based weekdays weekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status); fWeekdaysCount = ures_getSize(weekdaysData); fWeekdays = new UnicodeString[fWeekdaysCount+1]; /* test for NULL */ if (fWeekdays == 0) { 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 *)); /* test for NULL */ if (fZoneStrings == 0) { 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]); if(fZoneStrings[i][5].length()==0){ fZoneStrings[i][5].setTo(strings[TIMEZONE_LONG_GENERIC]); }else{ fZoneStrings[i][6].setTo(strings[TIMEZONE_LONG_GENERIC]); } if(fZoneStrings[i][6].length()==0){ fZoneStrings[i][6].setTo(strings[TIMEZONE_LONG_GENERIC]); }else{ fZoneStrings[i][7].setTo(strings[TIMEZONE_LONG_GENERIC]); } i++; } } void DateFormatSymbols::initZoneStrings(UErrorCode &status){ if(U_FAILURE(status)){ return; } if(fZoneStringsHash != NULL){ return; } int32_t i; if(fResourceBundle != NULL){ static const UnicodeString solidus("/"); static const UnicodeString colon(":"); UResourceBundle zoneArray,zoneItem; ures_initStackObject(&zoneItem); ures_initStackObject(&zoneArray); fZoneStringsHash = new Hashtable(status); if(fZoneStringsHash==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } for(const UResourceBundle* rb = fResourceBundle; rb!=NULL; rb=ures_getParentBundle(rb)){ ures_getByKey(rb, gZoneStringsTag, &zoneArray, &status); if(U_FAILURE(status)){ break; } while(ures_hasNext(&zoneArray)){ UErrorCode tempStatus = U_ZERO_ERROR; UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); ures_getNextResource(&zoneArray, &zoneItem, &status); UnicodeString key(ures_getKey(&zoneItem)); 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)){ array[TIMEZONE_SHORT_STANDARD].setTo(str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(&zoneItem,UTZ_SHORT_GENERIC, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ array[TIMEZONE_SHORT_GENERIC].setTo(str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(&zoneItem,UTZ_SHORT_DAYLIGHT, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ array[TIMEZONE_SHORT_DAYLIGHT].setTo(str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(&zoneItem,UTZ_LONG_STANDARD, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ array[TIMEZONE_LONG_STANDARD].setTo(str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(&zoneItem,UTZ_LONG_GENERIC, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ array[TIMEZONE_LONG_GENERIC].setTo(str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(&zoneItem,UTZ_LONG_DAYLIGHT, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ array[TIMEZONE_LONG_DAYLIGHT].setTo(str, len); }else{ tempStatus = U_ZERO_ERROR; } str = ures_getStringByKeyWithFallback(&zoneItem,UTZ_EXEMPLAR_CITY, &len, &tempStatus); if(U_SUCCESS(tempStatus)){ array[TIMEZONE_EXEMPLAR_CITY].setTo(str, len); }else{ tempStatus = U_ZERO_ERROR; } // store the strings in hash fZoneStringsHash->put(key, array, status); } ures_close(&zoneItem); ures_close(&zoneArray); } 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 fZoneStringsHash = new Hashtable(status); if(fZoneStringsHash==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } UnicodeString* array = newUnicodeStringArray(UTZ_MAX_DISPLAY_STRINGS_LENGTH); if(fZoneStringsHash==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){ // This method should have a status parameter // but setZoneStrings API that calls this method does not have one // setZoneStrings API is unsafe and should be deprecated!! UErrorCode status = U_ZERO_ERROR; 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(status); if(U_FAILURE(status)){ return; } if(fZoneStringsHash==NULL){ status = U_MEMORY_ALLOCATION_ERROR; return; } 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; } 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(status); if(hash==NULL){ return NULL; } if(U_FAILURE(status)){ return NULL; } 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; } /** * compares 2 StringEnumerations */ UBool DateFormatSymbols::stringEnumCompare(StringEnumeration* e1, StringEnumeration* e2){ TimeZoneKeysEnumeration *enum1 = (TimeZoneKeysEnumeration*)e1; TimeZoneKeysEnumeration *enum2 = (TimeZoneKeysEnumeration*)e2; if(enum1==NULL || enum2==NULL){ return FALSE; } UErrorCode status = U_ZERO_ERROR; int32_t count1 = enum1->count(status); int32_t count2 = enum2->count(status); if(count1 != count2){ return FALSE; } int32_t pos1 = 0; int32_t pos2 = 0; const UnicodeString* str1 = NULL; const UnicodeString* str2 = NULL; while((str1 = enum1->snext(pos1, status))!=NULL){ str2 = enum2->snext(pos2, status); if(U_FAILURE(status)){ return FALSE; } if(*str1 != *str2){ // bail out at the first failure return FALSE; } } // if we reached here that means that the enumerations are equal return TRUE; } /** * compares 2 Hashtables */ UBool DateFormatSymbols::hashCompare(Hashtable* hash1, Hashtable* hash2){ if(hash1==NULL || hash2==NULL){ return FALSE; } int32_t count1 = hash1->count(); int32_t count2 = hash2->count(); if(count1!=count2){ return FALSE; } int32_t pos1=-1; for(int32_t i=0; inextElement(pos1); UnicodeString* key1 = (UnicodeString*) elem1->key.pointer; UnicodeString* array1 = (UnicodeString*) elem1->value.pointer; UnicodeString* array2 = (UnicodeString*)hash2->get(*key1); 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; } 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); } } } } 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; } UnicodeString* strings = (UnicodeString*)fZoneStringsHash->get(zid); if(strings != NULL){ for(int32_t j=0; jsnext(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]); zid.setTo(*myKey); return; } } } } } U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ //eof