// Copyright (C) 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************************* * Copyright (C) 1997-2016, 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/localpointer.h" #include "unicode/dtfmtsym.h" #include "unicode/smpdtfmt.h" #include "unicode/msgfmt.h" #include "unicode/numsys.h" #include "unicode/tznames.h" #include "cpputils.h" #include "umutex.h" #include "cmemory.h" #include "cstring.h" #include "charstr.h" #include "dt_impl.h" #include "locbased.h" #include "gregoimp.h" #include "hash.h" #include "uassert.h" #include "uresimp.h" #include "ureslocs.h" #include "uvector.h" #include "shareddateformatsymbols.h" #include "unicode/calendar.h" #include "unifiedcache.h" // ***************************************************************************** // class DateFormatSymbols // ***************************************************************************** /** * These are static arrays we use only in the case where we have no * resource data. */ #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR #define PATTERN_CHARS_LEN 38 #else #define PATTERN_CHARS_LEN 37 #endif /** * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All * locales use the same these unlocalized pattern characters. */ static const UChar gPatternChars[] = { // if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR: // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB: // else: // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB 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, 0x56, 0x55, 0x4F, 0x58, 0x78, 0x72, 0x62, 0x42, #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR 0x3a, #endif 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" */ }; /* 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, kGmtHourNum = 4, kGmtHourLen = 10 } LastResortSize; U_NAMESPACE_BEGIN SharedDateFormatSymbols::~SharedDateFormatSymbols() { } template<> U_I18N_API const SharedDateFormatSymbols * LocaleCacheKey::createObject( const void * /*unusedContext*/, UErrorCode &status) const { char type[256]; Calendar::getCalendarTypeFromLocale(fLoc, type, UPRV_LENGTHOF(type), status); if (U_FAILURE(status)) { return NULL; } SharedDateFormatSymbols *shared = new SharedDateFormatSymbols(fLoc, type, status); if (shared == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } if (U_FAILURE(status)) { delete shared; return NULL; } shared->addRef(); return shared; } 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 gCalendarTag[]="calendar"; static const char gGregorianTag[]="gregorian"; static const char gErasTag[]="eras"; static const char gCyclicNameSetsTag[]="cyclicNameSets"; static const char gNameSetYearsTag[]="years"; static const char gNameSetZodiacsTag[]="zodiacs"; static const char gMonthNamesTag[]="monthNames"; static const char gMonthPatternsTag[]="monthPatterns"; static const char gDayNamesTag[]="dayNames"; static const char gNamesWideTag[]="wide"; static const char gNamesAbbrTag[]="abbreviated"; static const char gNamesShortTag[]="short"; static const char gNamesNarrowTag[]="narrow"; static const char gNamesAllTag[]="all"; static const char gNamesFormatTag[]="format"; static const char gNamesStandaloneTag[]="stand-alone"; static const char gNamesNumericTag[]="numeric"; static const char gAmPmMarkersTag[]="AmPmMarkers"; static const char gAmPmMarkersAbbrTag[]="AmPmMarkersAbbr"; static const char gAmPmMarkersNarrowTag[]="AmPmMarkersNarrow"; static const char gQuartersTag[]="quarters"; static const char gNumberElementsTag[]="NumberElements"; static const char gSymbolsTag[]="symbols"; static const char gTimeSeparatorTag[]="timeSeparator"; static const char gDayPeriodTag[]="dayPeriod"; // static const char gZoneStringsTag[]="zoneStrings"; // static const char gLocalPatternCharsTag[]="localPatternChars"; static const char gContextTransformsTag[]="contextTransforms"; static UMutex LOCK = U_MUTEX_INITIALIZER; /** * 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 * U_EXPORT2 DateFormatSymbols::createForLocale( const Locale& locale, UErrorCode &status) { const SharedDateFormatSymbols *shared = NULL; UnifiedCache::getByLocale(locale, shared, status); if (U_FAILURE(status)) { return NULL; } DateFormatSymbols *result = new DateFormatSymbols(shared->get()); shared->removeRef(); if (result == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } return result; } 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() and initializeData(), 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; i= 0; i--) { delete[] fZoneStrings[i]; } uprv_free(fZoneStrings); fZoneStrings = NULL; } } /** * Copy all of the other's data to this. */ void DateFormatSymbols::copyData(const DateFormatSymbols& other) { UErrorCode status = U_ZERO_ERROR; U_LOCALE_BASED(locBased, *this); locBased.setLocaleIDs( other.getLocale(ULOC_VALID_LOCALE, status), other.getLocale(ULOC_ACTUAL_LOCALE, status)); assignArray(fEras, fErasCount, other.fEras, other.fErasCount); assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount); assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount); assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount); assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount); assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount); assignArray(fStandaloneMonths, fStandaloneMonthsCount, other.fStandaloneMonths, other.fStandaloneMonthsCount); assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, other.fStandaloneShortMonths, other.fStandaloneShortMonthsCount); assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, other.fStandaloneNarrowMonths, other.fStandaloneNarrowMonthsCount); assignArray(fWeekdays, fWeekdaysCount, other.fWeekdays, other.fWeekdaysCount); assignArray(fShortWeekdays, fShortWeekdaysCount, other.fShortWeekdays, other.fShortWeekdaysCount); assignArray(fShorterWeekdays, fShorterWeekdaysCount, other.fShorterWeekdays, other.fShorterWeekdaysCount); assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount); assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, other.fStandaloneWeekdays, other.fStandaloneWeekdaysCount); assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, other.fStandaloneShortWeekdays, other.fStandaloneShortWeekdaysCount); assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, other.fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdaysCount); assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount); assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount); assignArray(fNarrowAmPms, fNarrowAmPmsCount, other.fNarrowAmPms, other.fNarrowAmPmsCount ); fTimeSeparator.fastCopyFrom(other.fTimeSeparator); // fastCopyFrom() - see assignArray comments assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount); assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount); assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount); assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount); assignArray(fWideDayPeriods, fWideDayPeriodsCount, other.fWideDayPeriods, other.fWideDayPeriodsCount); assignArray(fNarrowDayPeriods, fNarrowDayPeriodsCount, other.fNarrowDayPeriods, other.fNarrowDayPeriodsCount); assignArray(fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount, other.fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriodsCount); assignArray(fStandaloneWideDayPeriods, fStandaloneWideDayPeriodsCount, other.fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriodsCount); assignArray(fStandaloneNarrowDayPeriods, fStandaloneNarrowDayPeriodsCount, other.fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriodsCount); assignArray(fStandaloneAbbreviatedDayPeriods, fStandaloneAbbreviatedDayPeriodsCount, other.fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriodsCount); if (other.fLeapMonthPatterns != NULL) { assignArray(fLeapMonthPatterns, fLeapMonthPatternsCount, other.fLeapMonthPatterns, other.fLeapMonthPatternsCount); } else { fLeapMonthPatterns = NULL; fLeapMonthPatternsCount = 0; } if (other.fShortYearNames != NULL) { assignArray(fShortYearNames, fShortYearNamesCount, other.fShortYearNames, other.fShortYearNamesCount); } else { fShortYearNames = NULL; fShortYearNamesCount = 0; } if (other.fShortZodiacNames != NULL) { assignArray(fShortZodiacNames, fShortZodiacNamesCount, other.fShortZodiacNames, other.fShortZodiacNamesCount); } else { fShortZodiacNames = NULL; fShortZodiacNamesCount = 0; } if (other.fZoneStrings != NULL) { fZoneStringsColCount = other.fZoneStringsColCount; fZoneStringsRowCount = other.fZoneStringsRowCount; createZoneStrings((const UnicodeString**)other.fZoneStrings); } else { fZoneStrings = NULL; fZoneStringsColCount = 0; fZoneStringsRowCount = 0; } fZSFLocale = other.fZSFLocale; // Other zone strings data is created on demand fLocaleZoneStrings = NULL; // fastCopyFrom() - see assignArray comments fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars); uprv_memcpy(fCapitalization, other.fCapitalization, sizeof(fCapitalization)); } /** * Assignment operator. */ DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other) { dispose(); copyData(other); return *this; } DateFormatSymbols::~DateFormatSymbols() { dispose(); } void DateFormatSymbols::dispose() { delete[] fEras; delete[] fEraNames; delete[] fNarrowEras; delete[] fMonths; delete[] fShortMonths; delete[] fNarrowMonths; delete[] fStandaloneMonths; delete[] fStandaloneShortMonths; delete[] fStandaloneNarrowMonths; delete[] fWeekdays; delete[] fShortWeekdays; delete[] fShorterWeekdays; delete[] fNarrowWeekdays; delete[] fStandaloneWeekdays; delete[] fStandaloneShortWeekdays; delete[] fStandaloneShorterWeekdays; delete[] fStandaloneNarrowWeekdays; delete[] fAmPms; delete[] fNarrowAmPms; delete[] fQuarters; delete[] fShortQuarters; delete[] fStandaloneQuarters; delete[] fStandaloneShortQuarters; delete[] fLeapMonthPatterns; delete[] fShortYearNames; delete[] fShortZodiacNames; delete[] fAbbreviatedDayPeriods; delete[] fWideDayPeriods; delete[] fNarrowDayPeriods; delete[] fStandaloneAbbreviatedDayPeriods; delete[] fStandaloneWideDayPeriods; delete[] fStandaloneNarrowDayPeriods; disposeZoneStrings(); } void DateFormatSymbols::disposeZoneStrings() { if (fZoneStrings) { for (int32_t row = 0; row < fZoneStringsRowCount; ++row) { delete[] fZoneStrings[row]; } uprv_free(fZoneStrings); } if (fLocaleZoneStrings) { for (int32_t row = 0; row < fZoneStringsRowCount; ++row) { delete[] fLocaleZoneStrings[row]; } uprv_free(fLocaleZoneStrings); } fZoneStrings = NULL; fLocaleZoneStrings = NULL; fZoneStringsRowCount = 0; fZoneStringsColCount = 0; } 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 && fNarrowErasCount == other.fNarrowErasCount && fMonthsCount == other.fMonthsCount && fShortMonthsCount == other.fShortMonthsCount && fNarrowMonthsCount == other.fNarrowMonthsCount && fStandaloneMonthsCount == other.fStandaloneMonthsCount && fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount && fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount && fWeekdaysCount == other.fWeekdaysCount && fShortWeekdaysCount == other.fShortWeekdaysCount && fShorterWeekdaysCount == other.fShorterWeekdaysCount && fNarrowWeekdaysCount == other.fNarrowWeekdaysCount && fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount && fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount && fStandaloneShorterWeekdaysCount == other.fStandaloneShorterWeekdaysCount && fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount && fAmPmsCount == other.fAmPmsCount && fNarrowAmPmsCount == other.fNarrowAmPmsCount && fQuartersCount == other.fQuartersCount && fShortQuartersCount == other.fShortQuartersCount && fStandaloneQuartersCount == other.fStandaloneQuartersCount && fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount && fLeapMonthPatternsCount == other.fLeapMonthPatternsCount && fShortYearNamesCount == other.fShortYearNamesCount && fShortZodiacNamesCount == other.fShortZodiacNamesCount && fAbbreviatedDayPeriodsCount == other.fAbbreviatedDayPeriodsCount && fWideDayPeriodsCount == other.fWideDayPeriodsCount && fNarrowDayPeriodsCount == other.fNarrowDayPeriodsCount && fStandaloneAbbreviatedDayPeriodsCount == other.fStandaloneAbbreviatedDayPeriodsCount && fStandaloneWideDayPeriodsCount == other.fStandaloneWideDayPeriodsCount && fStandaloneNarrowDayPeriodsCount == other.fStandaloneNarrowDayPeriodsCount && (uprv_memcmp(fCapitalization, other.fCapitalization, sizeof(fCapitalization))==0)) { // Now compare the arrays themselves if (arrayCompare(fEras, other.fEras, fErasCount) && arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) && arrayCompare(fNarrowEras, other.fNarrowEras, fNarrowErasCount) && 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(fShorterWeekdays, other.fShorterWeekdays, fShorterWeekdaysCount) && arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) && arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) && arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) && arrayCompare(fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount) && arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) && arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) && arrayCompare(fNarrowAmPms, other.fNarrowAmPms, fNarrowAmPmsCount) && fTimeSeparator == other.fTimeSeparator && arrayCompare(fQuarters, other.fQuarters, fQuartersCount) && arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) && arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) && arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) && arrayCompare(fLeapMonthPatterns, other.fLeapMonthPatterns, fLeapMonthPatternsCount) && arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount) && arrayCompare(fShortZodiacNames, other.fShortZodiacNames, fShortZodiacNamesCount) && arrayCompare(fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount) && arrayCompare(fWideDayPeriods, other.fWideDayPeriods, fWideDayPeriodsCount) && arrayCompare(fNarrowDayPeriods, other.fNarrowDayPeriods, fNarrowDayPeriodsCount) && arrayCompare(fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriods, fStandaloneAbbreviatedDayPeriodsCount) && arrayCompare(fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriods, fStandaloneWideDayPeriodsCount) && arrayCompare(fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriods, fStandaloneWideDayPeriodsCount)) { // Compare the contents of fZoneStrings if (fZoneStrings == NULL && other.fZoneStrings == NULL) { if (fZSFLocale == other.fZSFLocale) { return TRUE; } } else if (fZoneStrings != NULL && other.fZoneStrings != NULL) { if (fZoneStringsRowCount == other.fZoneStringsRowCount && fZoneStringsColCount == other.fZoneStringsColCount) { UBool cmpres = TRUE; for (int32_t i = 0; (i < fZoneStringsRowCount) && cmpres; i++) { cmpres = arrayCompare(fZoneStrings[i], other.fZoneStrings[i], fZoneStringsColCount); } return cmpres; } } return FALSE; } } 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::getNarrowEras(int32_t &count) const { count = fNarrowErasCount; return fNarrowEras; } 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 : case SHORT : // no month data for this, defaults to 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 : case SHORT : // no month data for this, defaults to 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 SHORT : count = fShorterWeekdaysCount; returnValue = fShorterWeekdays; 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 SHORT : count = fStandaloneShorterWeekdaysCount; returnValue = fStandaloneShorterWeekdays; 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 : case SHORT : // no quarter data for this, defaults to 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 : case SHORT : // no quarter data for this, defaults to 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; } UnicodeString& DateFormatSymbols::getTimeSeparatorString(UnicodeString& result) const { // fastCopyFrom() - see assignArray comments return result.fastCopyFrom(fTimeSeparator); } const UnicodeString* DateFormatSymbols::getAmPmStrings(int32_t &count) const { count = fAmPmsCount; return fAmPms; } const UnicodeString* DateFormatSymbols::getLeapMonthPatterns(int32_t &count) const { count = fLeapMonthPatternsCount; return fLeapMonthPatterns; } const UnicodeString* DateFormatSymbols::getYearNames(int32_t& count, DtContextType /*ignored*/, DtWidthType /*ignored*/) const { count = fShortYearNamesCount; return fShortYearNames; } void DateFormatSymbols::setYearNames(const UnicodeString* yearNames, int32_t count, DtContextType context, DtWidthType width) { if (context == FORMAT && width == ABBREVIATED) { if (fShortYearNames) { delete[] fShortYearNames; } fShortYearNames = newUnicodeStringArray(count); uprv_arrayCopy(yearNames, fShortYearNames, count); fShortYearNamesCount = count; } } const UnicodeString* DateFormatSymbols::getZodiacNames(int32_t& count, DtContextType /*ignored*/, DtWidthType /*ignored*/) const { count = fShortZodiacNamesCount; return fShortZodiacNames; } void DateFormatSymbols::setZodiacNames(const UnicodeString* zodiacNames, int32_t count, DtContextType context, DtWidthType width) { if (context == FORMAT && width == ABBREVIATED) { if (fShortZodiacNames) { delete[] fShortZodiacNames; } fShortZodiacNames = newUnicodeStringArray(count); uprv_arrayCopy(zodiacNames, fShortZodiacNames, count); fShortZodiacNamesCount = count; } } //------------------------------------------------------ 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::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count) { // delete the old list if we own it if (fNarrowEras) delete[] fNarrowEras; // we always own the new list, which we create here (we duplicate rather // than adopting the list passed in) fNarrowEras = newUnicodeStringArray(count); uprv_arrayCopy(narrowErasArray,fNarrowEras, count); fNarrowErasCount = 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; default : 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; default : 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 SHORT : if (fShorterWeekdays) delete[] fShorterWeekdays; fShorterWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fShorterWeekdays, count); fShorterWeekdaysCount = 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 SHORT : if (fStandaloneShorterWeekdays) delete[] fStandaloneShorterWeekdays; fStandaloneShorterWeekdays = newUnicodeStringArray(count); uprv_arrayCopy(weekdaysArray, fStandaloneShorterWeekdays, count); fStandaloneShorterWeekdaysCount = 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; default : 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; default : 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; } void DateFormatSymbols::setTimeSeparatorString(const UnicodeString& newTimeSeparator) { fTimeSeparator = newTimeSeparator; } const UnicodeString** DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const { const UnicodeString **result = NULL; umtx_lock(&LOCK); if (fZoneStrings == NULL) { if (fLocaleZoneStrings == NULL) { ((DateFormatSymbols*)this)->initZoneStringsArray(); } result = (const UnicodeString**)fLocaleZoneStrings; } else { result = (const UnicodeString**)fZoneStrings; } rowCount = fZoneStringsRowCount; columnCount = fZoneStringsColCount; umtx_unlock(&LOCK); return result; } // For now, we include all zones #define ZONE_SET UCAL_ZONE_TYPE_ANY // This code must be called within a synchronized block void DateFormatSymbols::initZoneStringsArray(void) { if (fZoneStrings != NULL || fLocaleZoneStrings != NULL) { return; } UErrorCode status = U_ZERO_ERROR; StringEnumeration *tzids = NULL; UnicodeString ** zarray = NULL; TimeZoneNames *tzNames = NULL; int32_t rows = 0; static const UTimeZoneNameType TYPES[] = { UTZNM_LONG_STANDARD, UTZNM_SHORT_STANDARD, UTZNM_LONG_DAYLIGHT, UTZNM_SHORT_DAYLIGHT }; static const int32_t NUM_TYPES = 4; do { // dummy do-while tzids = TimeZone::createTimeZoneIDEnumeration(ZONE_SET, NULL, NULL, status); rows = tzids->count(status); if (U_FAILURE(status)) { break; } // Allocate array int32_t size = rows * sizeof(UnicodeString*); zarray = (UnicodeString**)uprv_malloc(size); if (zarray == NULL) { status = U_MEMORY_ALLOCATION_ERROR; break; } uprv_memset(zarray, 0, size); tzNames = TimeZoneNames::createInstance(fZSFLocale, status); tzNames->loadAllDisplayNames(status); if (U_FAILURE(status)) { break; } const UnicodeString *tzid; int32_t i = 0; UDate now = Calendar::getNow(); UnicodeString tzDispName; while ((tzid = tzids->snext(status))) { if (U_FAILURE(status)) { break; } zarray[i] = new UnicodeString[5]; if (zarray[i] == NULL) { status = U_MEMORY_ALLOCATION_ERROR; break; } zarray[i][0].setTo(*tzid); tzNames->getDisplayNames(*tzid, TYPES, NUM_TYPES, now, zarray[i]+1, status); i++; } } while (FALSE); if (U_FAILURE(status)) { if (zarray) { for (int32_t i = 0; i < rows; i++) { if (zarray[i]) { delete[] zarray[i]; } } uprv_free(zarray); zarray = NULL; } } if (tzNames) { delete tzNames; } if (tzids) { delete tzids; } fLocaleZoneStrings = zarray; fZoneStringsRowCount = rows; fZoneStringsColCount = 1 + NUM_TYPES; } 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); } //------------------------------------------------------ const UChar * U_EXPORT2 DateFormatSymbols::getPatternUChars(void) { return gPatternChars; } UDateFormatField U_EXPORT2 DateFormatSymbols::getPatternCharIndex(UChar c) { const UChar *p = u_strchr(gPatternChars, c); if (p == NULL) { return UDAT_FIELD_COUNT; } else { return static_cast(p - gPatternChars); } } static const uint64_t kNumericFieldsAlways = ((uint64_t)1 << UDAT_YEAR_FIELD) | // y ((uint64_t)1 << UDAT_DATE_FIELD) | // d ((uint64_t)1 << UDAT_HOUR_OF_DAY1_FIELD) | // k ((uint64_t)1 << UDAT_HOUR_OF_DAY0_FIELD) | // H ((uint64_t)1 << UDAT_MINUTE_FIELD) | // m ((uint64_t)1 << UDAT_SECOND_FIELD) | // s ((uint64_t)1 << UDAT_FRACTIONAL_SECOND_FIELD) | // S ((uint64_t)1 << UDAT_DAY_OF_YEAR_FIELD) | // D ((uint64_t)1 << UDAT_DAY_OF_WEEK_IN_MONTH_FIELD) | // F ((uint64_t)1 << UDAT_WEEK_OF_YEAR_FIELD) | // w ((uint64_t)1 << UDAT_WEEK_OF_MONTH_FIELD) | // W ((uint64_t)1 << UDAT_HOUR1_FIELD) | // h ((uint64_t)1 << UDAT_HOUR0_FIELD) | // K ((uint64_t)1 << UDAT_YEAR_WOY_FIELD) | // Y ((uint64_t)1 << UDAT_EXTENDED_YEAR_FIELD) | // u ((uint64_t)1 << UDAT_JULIAN_DAY_FIELD) | // g ((uint64_t)1 << UDAT_MILLISECONDS_IN_DAY_FIELD) | // A ((uint64_t)1 << UDAT_RELATED_YEAR_FIELD); // r static const uint64_t kNumericFieldsForCount12 = ((uint64_t)1 << UDAT_MONTH_FIELD) | // M or MM ((uint64_t)1 << UDAT_DOW_LOCAL_FIELD) | // e or ee ((uint64_t)1 << UDAT_STANDALONE_DAY_FIELD) | // c or cc ((uint64_t)1 << UDAT_STANDALONE_MONTH_FIELD) | // L or LL ((uint64_t)1 << UDAT_QUARTER_FIELD) | // Q or QQ ((uint64_t)1 << UDAT_STANDALONE_QUARTER_FIELD); // q or qq UBool U_EXPORT2 DateFormatSymbols::isNumericField(UDateFormatField f, int32_t count) { if (f == UDAT_FIELD_COUNT) { return FALSE; } uint64_t flag = ((uint64_t)1 << f); return ((kNumericFieldsAlways & flag) != 0 || ((kNumericFieldsForCount12 & flag) != 0 && count < 3)); } UBool U_EXPORT2 DateFormatSymbols::isNumericPatternChar(UChar c, int32_t count) { return isNumericField(getPatternCharIndex(c), count); } //------------------------------------------------------ UnicodeString& DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const { // fastCopyFrom() - see assignArray comments return result.fastCopyFrom(fLocalPatternChars); } //------------------------------------------------------ void DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars) { fLocalPatternChars = newLocalPatternChars; } //------------------------------------------------------ namespace { // Constants declarations static const UChar kCalendarAliasPrefixUChar[] = { SOLIDUS, CAP_L, CAP_O, CAP_C, CAP_A, CAP_L, CAP_E, SOLIDUS, LOW_C, LOW_A, LOW_L, LOW_E, LOW_N, LOW_D, LOW_A, LOW_R, SOLIDUS }; static const UChar kGregorianTagUChar[] = { LOW_G, LOW_R, LOW_E, LOW_G, LOW_O, LOW_R, LOW_I, LOW_A, LOW_N }; static const UChar kVariantTagUChar[] = { PERCENT, LOW_V, LOW_A, LOW_R, LOW_I, LOW_A, LOW_N, LOW_T }; static const UChar kLeapTagUChar[] = { LOW_L, LOW_E, LOW_A, LOW_P }; static const UChar kCyclicNameSetsTagUChar[] = { LOW_C, LOW_Y, LOW_C, LOW_L, LOW_I, LOW_C, CAP_N, LOW_A, LOW_M, LOW_E, CAP_S, LOW_E, LOW_T, LOW_S }; static const UChar kYearsTagUChar[] = { SOLIDUS, LOW_Y, LOW_E, LOW_A, LOW_R, LOW_S }; static const UChar kZodiacsUChar[] = { SOLIDUS, LOW_Z, LOW_O, LOW_D, LOW_I, LOW_A, LOW_C, LOW_S }; static const UChar kDayPartsTagUChar[] = { SOLIDUS, LOW_D, LOW_A, LOW_Y, CAP_P, LOW_A, LOW_R, LOW_T, LOW_S }; static const UChar kFormatTagUChar[] = { SOLIDUS, LOW_F, LOW_O, LOW_R, LOW_M, LOW_A, LOW_T }; static const UChar kAbbrTagUChar[] = { SOLIDUS, LOW_A, LOW_B, LOW_B, LOW_R, LOW_E, LOW_V, LOW_I, LOW_A, LOW_T, LOW_E, LOW_D }; // ResourceSink to enumerate all calendar resources struct CalendarDataSink : public ResourceSink { // Enum which specifies the type of alias received, or no alias enum AliasType { SAME_CALENDAR, DIFFERENT_CALENDAR, GREGORIAN, NONE }; // Data structures to store resources from the current resource bundle Hashtable arrays; Hashtable arraySizes; Hashtable maps; /** * Whenever there are aliases, the same object will be added twice to 'map'. * To avoid double deletion, 'maps' won't take ownership of the objects. Instead, * 'mapRefs' will own them and will delete them when CalendarDataSink is deleted. */ UVector mapRefs; // Paths and the aliases they point to UVector aliasPathPairs; // Current and next calendar resource table which should be loaded UnicodeString currentCalendarType; UnicodeString nextCalendarType; // Resources to visit when enumerating fallback calendars LocalPointer resourcesToVisit; // Alias' relative path populated whenever an alias is read UnicodeString aliasRelativePath; // Initializes CalendarDataSink with default values CalendarDataSink(UErrorCode& status) : arrays(FALSE, status), arraySizes(FALSE, status), maps(FALSE, status), mapRefs(deleteHashtable, NULL, 10, status), aliasPathPairs(uprv_deleteUObject, uhash_compareUnicodeString, status), currentCalendarType(), nextCalendarType(), resourcesToVisit(NULL), aliasRelativePath() { if (U_FAILURE(status)) { return; } } virtual ~CalendarDataSink(); // Configure the CalendarSink to visit all the resources void visitAllResources() { resourcesToVisit.adoptInstead(NULL); } // Actions to be done before enumerating void preEnumerate(const UnicodeString &calendarType) { currentCalendarType = calendarType; nextCalendarType.setToBogus(); aliasPathPairs.removeAllElements(); } virtual void put(const char *key, ResourceValue &value, UBool, UErrorCode &errorCode) { if (U_FAILURE(errorCode)) { return; } U_ASSERT(!currentCalendarType.isEmpty()); // Stores the resources to visit on the next calendar. LocalPointer resourcesToVisitNext(NULL); ResourceTable calendarData = value.getTable(errorCode); if (U_FAILURE(errorCode)) { return; } // Enumerate all resources for this calendar for (int i = 0; calendarData.getKeyAndValue(i, key, value); i++) { UnicodeString keyUString(key, -1, US_INV); // == Handle aliases == AliasType aliasType = processAliasFromValue(keyUString, value, errorCode); if (U_FAILURE(errorCode)) { return; } if (aliasType == GREGORIAN) { // Ignore aliases to the gregorian calendar, all of its resources will be loaded anyway. continue; } else if (aliasType == DIFFERENT_CALENDAR) { // Whenever an alias to the next calendar (except gregorian) is encountered, register the // calendar type it's pointing to if (resourcesToVisitNext.isNull()) { resourcesToVisitNext .adoptInsteadAndCheckErrorCode(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, errorCode), errorCode); if (U_FAILURE(errorCode)) { return; } } LocalPointer aliasRelativePathCopy(new UnicodeString(aliasRelativePath), errorCode); resourcesToVisitNext->addElement(aliasRelativePathCopy.getAlias(), errorCode); if (U_FAILURE(errorCode)) { return; } // Only release ownership after resourcesToVisitNext takes it (no error happened): aliasRelativePathCopy.orphan(); continue; } else if (aliasType == SAME_CALENDAR) { // Register same-calendar alias if (arrays.get(aliasRelativePath) == NULL && maps.get(aliasRelativePath) == NULL) { LocalPointer aliasRelativePathCopy(new UnicodeString(aliasRelativePath), errorCode); aliasPathPairs.addElement(aliasRelativePathCopy.getAlias(), errorCode); if (U_FAILURE(errorCode)) { return; } // Only release ownership after aliasPathPairs takes it (no error happened): aliasRelativePathCopy.orphan(); LocalPointer keyUStringCopy(new UnicodeString(keyUString), errorCode); aliasPathPairs.addElement(keyUStringCopy.getAlias(), errorCode); if (U_FAILURE(errorCode)) { return; } // Only release ownership after aliasPathPairs takes it (no error happened): keyUStringCopy.orphan(); } continue; } // Only visit the resources that were referenced by an alias on the previous calendar // (AmPmMarkersAbbr is an exception). if (!resourcesToVisit.isNull() && !resourcesToVisit->isEmpty() && !resourcesToVisit->contains(&keyUString) && uprv_strcmp(key, gAmPmMarkersAbbrTag) != 0) { continue; } // == Handle data == if (uprv_strcmp(key, gAmPmMarkersTag) == 0 || uprv_strcmp(key, gAmPmMarkersAbbrTag) == 0 || uprv_strcmp(key, gAmPmMarkersNarrowTag) == 0) { if (arrays.get(keyUString) == NULL) { ResourceArray resourceArray = value.getArray(errorCode); int32_t arraySize = resourceArray.getSize(); LocalArray stringArray(new UnicodeString[arraySize], errorCode); value.getStringArray(stringArray.getAlias(), arraySize, errorCode); arrays.put(keyUString, stringArray.orphan(), errorCode); arraySizes.puti(keyUString, arraySize, errorCode); if (U_FAILURE(errorCode)) { return; } } } else if (uprv_strcmp(key, gErasTag) == 0 || uprv_strcmp(key, gDayNamesTag) == 0 || uprv_strcmp(key, gMonthNamesTag) == 0 || uprv_strcmp(key, gQuartersTag) == 0 || uprv_strcmp(key, gDayPeriodTag) == 0 || uprv_strcmp(key, gMonthPatternsTag) == 0 || uprv_strcmp(key, gCyclicNameSetsTag) == 0) { processResource(keyUString, key, value, errorCode); } } // Apply same-calendar aliases UBool modified; do { modified = false; for (int32_t i = 0; i < aliasPathPairs.size();) { UBool mod = false; UnicodeString *alias = (UnicodeString*)aliasPathPairs[i]; UnicodeString *aliasArray; Hashtable *aliasMap; if ((aliasArray = (UnicodeString*)arrays.get(*alias)) != NULL) { // Clone the array int32_t aliasArraySize = arraySizes.geti(*alias); LocalArray aliasArrayCopy(new UnicodeString[aliasArraySize], errorCode); if (U_FAILURE(errorCode)) { return; } uprv_arrayCopy(aliasArray, aliasArrayCopy.getAlias(), aliasArraySize); // Put the array on the 'arrays' map UnicodeString *path = (UnicodeString*)aliasPathPairs[i + 1]; arrays.put(*path, aliasArrayCopy.orphan(), errorCode); arraySizes.puti(*path, aliasArraySize, errorCode); if (U_FAILURE(errorCode)) { return; } mod = true; } else if ((aliasMap = (Hashtable*)maps.get(*alias)) != NULL) { UnicodeString *path = (UnicodeString*)aliasPathPairs[i + 1]; maps.put(*path, aliasMap, errorCode); if (U_FAILURE(errorCode)) { return; } mod = true; } if (mod) { aliasPathPairs.removeElementAt(i + 1); aliasPathPairs.removeElementAt(i); modified = true; } else { i += 2; } } } while (modified && !aliasPathPairs.isEmpty()); // Set the resources to visit on the next calendar if (!resourcesToVisitNext.isNull()) { resourcesToVisit.moveFrom(resourcesToVisitNext); } } // Process the nested resource bundle tables void processResource(UnicodeString &path, const char *key, ResourceValue &value, UErrorCode &errorCode) { if (U_FAILURE(errorCode)) return; ResourceTable table = value.getTable(errorCode); if (U_FAILURE(errorCode)) return; Hashtable* stringMap = NULL; // Iterate over all the elements of the table and add them to the map for (int i = 0; table.getKeyAndValue(i, key, value); i++) { UnicodeString keyUString(key, -1, US_INV); // Ignore '%variant' keys if (keyUString.endsWith(kVariantTagUChar, UPRV_LENGTHOF(kVariantTagUChar))) { continue; } // == Handle String elements == if (value.getType() == URES_STRING) { // We are on a leaf, store the map elements into the stringMap if (i == 0) { LocalPointer stringMapPtr(new Hashtable(FALSE, errorCode), errorCode); stringMap = stringMapPtr.getAlias(); maps.put(path, stringMap, errorCode); // mapRefs will take ownership of 'stringMap': mapRefs.addElement(stringMap, errorCode); if (U_FAILURE(errorCode)) { return; } // Only release ownership after mapRefs takes it (no error happened): stringMapPtr.orphan(); stringMap->setValueDeleter(uprv_deleteUObject); } U_ASSERT(stringMap != NULL); int32_t valueStringSize; const UChar *valueString = value.getString(valueStringSize, errorCode); if (U_FAILURE(errorCode)) { return; } LocalPointer valueUString(new UnicodeString(TRUE, valueString, valueStringSize), errorCode); stringMap->put(keyUString, valueUString.orphan(), errorCode); if (U_FAILURE(errorCode)) { return; } continue; } U_ASSERT(stringMap == NULL); // Store the current path's length and append the current key to the path. int32_t pathLength = path.length(); path.append(SOLIDUS).append(keyUString); // In cyclicNameSets ignore everything but years/format/abbreviated // and zodiacs/format/abbreviated if (path.startsWith(kCyclicNameSetsTagUChar, UPRV_LENGTHOF(kCyclicNameSetsTagUChar))) { UBool skip = TRUE; int32_t startIndex = UPRV_LENGTHOF(kCyclicNameSetsTagUChar); int32_t length = 0; if (startIndex == path.length() || path.compare(startIndex, (length = UPRV_LENGTHOF(kZodiacsUChar)), kZodiacsUChar, 0, UPRV_LENGTHOF(kZodiacsUChar)) == 0 || path.compare(startIndex, (length = UPRV_LENGTHOF(kYearsTagUChar)), kYearsTagUChar, 0, UPRV_LENGTHOF(kYearsTagUChar)) == 0 || path.compare(startIndex, (length = UPRV_LENGTHOF(kDayPartsTagUChar)), kDayPartsTagUChar, 0, UPRV_LENGTHOF(kDayPartsTagUChar)) == 0) { startIndex += length; length = 0; if (startIndex == path.length() || path.compare(startIndex, (length = UPRV_LENGTHOF(kFormatTagUChar)), kFormatTagUChar, 0, UPRV_LENGTHOF(kFormatTagUChar)) == 0) { startIndex += length; length = 0; if (startIndex == path.length() || path.compare(startIndex, (length = UPRV_LENGTHOF(kAbbrTagUChar)), kAbbrTagUChar, 0, UPRV_LENGTHOF(kAbbrTagUChar)) == 0) { skip = FALSE; } } } if (skip) { // Drop the latest key on the path and continue path.retainBetween(0, pathLength); continue; } } // == Handle aliases == if (arrays.get(path) != NULL || maps.get(path) != NULL) { // Drop the latest key on the path and continue path.retainBetween(0, pathLength); continue; } AliasType aliasType = processAliasFromValue(path, value, errorCode); if (U_FAILURE(errorCode)) { return; } if (aliasType == SAME_CALENDAR) { // Store the alias path and the current path on aliasPathPairs LocalPointer aliasRelativePathCopy(new UnicodeString(aliasRelativePath), errorCode); aliasPathPairs.addElement(aliasRelativePathCopy.getAlias(), errorCode); if (U_FAILURE(errorCode)) { return; } // Only release ownership after aliasPathPairs takes it (no error happened): aliasRelativePathCopy.orphan(); LocalPointer pathCopy(new UnicodeString(path), errorCode); aliasPathPairs.addElement(pathCopy.getAlias(), errorCode); if (U_FAILURE(errorCode)) { return; } // Only release ownership after aliasPathPairs takes it (no error happened): pathCopy.orphan(); // Drop the latest key on the path and continue path.retainBetween(0, pathLength); continue; } U_ASSERT(aliasType == NONE); // == Handle data == if (value.getType() == URES_ARRAY) { // We are on a leaf, store the array ResourceArray rDataArray = value.getArray(errorCode); int32_t dataArraySize = rDataArray.getSize(); LocalArray dataArray(new UnicodeString[dataArraySize], errorCode); value.getStringArray(dataArray.getAlias(), dataArraySize, errorCode); arrays.put(path, dataArray.orphan(), errorCode); arraySizes.puti(path, dataArraySize, errorCode); if (U_FAILURE(errorCode)) { return; } } else if (value.getType() == URES_TABLE) { // We are not on a leaf, recursively process the subtable. processResource(path, key, value, errorCode); if (U_FAILURE(errorCode)) { return; } } // Drop the latest key on the path path.retainBetween(0, pathLength); } } // Populates an AliasIdentifier with the alias information contained on the UResource.Value. AliasType processAliasFromValue(UnicodeString ¤tRelativePath, ResourceValue &value, UErrorCode &errorCode) { if (U_FAILURE(errorCode)) { return NONE; } if (value.getType() == URES_ALIAS) { int32_t aliasPathSize; const UChar* aliasPathUChar = value.getAliasString(aliasPathSize, errorCode); if (U_FAILURE(errorCode)) { return NONE; } UnicodeString aliasPath(aliasPathUChar, aliasPathSize); const int32_t aliasPrefixLength = UPRV_LENGTHOF(kCalendarAliasPrefixUChar); if (aliasPath.startsWith(kCalendarAliasPrefixUChar, aliasPrefixLength) && aliasPath.length() > aliasPrefixLength) { int32_t typeLimit = aliasPath.indexOf(SOLIDUS, aliasPrefixLength); if (typeLimit > aliasPrefixLength) { const UnicodeString aliasCalendarType = aliasPath.tempSubStringBetween(aliasPrefixLength, typeLimit); aliasRelativePath.setTo(aliasPath, typeLimit + 1, aliasPath.length()); if (currentCalendarType == aliasCalendarType && currentRelativePath != aliasRelativePath) { // If we have an alias to the same calendar, the path to the resource must be different return SAME_CALENDAR; } else if (currentCalendarType != aliasCalendarType && currentRelativePath == aliasRelativePath) { // If we have an alias to a different calendar, the path to the resource must be the same if (aliasCalendarType.compare(kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)) == 0) { return GREGORIAN; } else if (nextCalendarType.isBogus()) { nextCalendarType = aliasCalendarType; return DIFFERENT_CALENDAR; } else if (nextCalendarType == aliasCalendarType) { return DIFFERENT_CALENDAR; } } } } errorCode = U_INTERNAL_PROGRAM_ERROR; return NONE; } return NONE; } // Deleter function to be used by 'arrays' static void U_CALLCONV deleteUnicodeStringArray(void *uArray) { delete[] static_cast(uArray); } // Deleter function to be used by 'maps' static void U_CALLCONV deleteHashtable(void *table) { delete static_cast(table); } }; // Virtual destructors have to be defined out of line CalendarDataSink::~CalendarDataSink() { arrays.setValueDeleter(deleteUnicodeStringArray); } } //------------------------------------------------------ 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; } } } static void initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, UErrorCode &status) { if (U_SUCCESS(status)) { UnicodeString keyUString(key.data(), -1, US_INV); UnicodeString* array = static_cast(sink.arrays.get(keyUString)); if (array != NULL) { length = sink.arraySizes.geti(keyUString); *field = array; // DateFormatSymbols takes ownership of the array: sink.arrays.remove(keyUString); } else { length = 0; status = U_MISSING_RESOURCE_ERROR; } } } static void initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, int32_t arrayOffset, UErrorCode &status) { if (U_SUCCESS(status)) { UnicodeString keyUString(key.data(), -1, US_INV); UnicodeString* array = static_cast(sink.arrays.get(keyUString)); if (array != NULL) { int32_t arrayLength = sink.arraySizes.geti(keyUString); length = arrayLength + arrayOffset; *field = new UnicodeString[length]; if (*field == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return; } uprv_arrayCopy(array, 0, *field, arrayOffset, arrayLength); } else { length = 0; status = U_MISSING_RESOURCE_ERROR; } } } static void initLeapMonthPattern(UnicodeString *field, int32_t index, CalendarDataSink &sink, CharString &path, UErrorCode &status) { field[index].remove(); if (U_SUCCESS(status)) { UnicodeString pathUString(path.data(), -1, US_INV); Hashtable *leapMonthTable = static_cast(sink.maps.get(pathUString)); if (leapMonthTable != NULL) { UnicodeString leapLabel(FALSE, kLeapTagUChar, UPRV_LENGTHOF(kLeapTagUChar)); UnicodeString *leapMonthPattern = static_cast(leapMonthTable->get(leapLabel)); if (leapMonthPattern != NULL) { field[index].fastCopyFrom(*leapMonthPattern); } else { field[index].setToBogus(); } return; } status = U_MISSING_RESOURCE_ERROR; } } static CharString &buildResourcePath(CharString &path, const char* segment1, UErrorCode &errorCode) { return path.clear().append(segment1, -1, errorCode); } static CharString &buildResourcePath(CharString &path, const char* segment1, const char* segment2, UErrorCode &errorCode) { return buildResourcePath(path, segment1, errorCode).append('/', errorCode) .append(segment2, -1, errorCode); } static CharString &buildResourcePath(CharString &path, const char* segment1, const char* segment2, const char* segment3, UErrorCode &errorCode) { return buildResourcePath(path, segment1, segment2, errorCode).append('/', errorCode) .append(segment3, -1, errorCode); } static CharString &buildResourcePath(CharString &path, const char* segment1, const char* segment2, const char* segment3, const char* segment4, UErrorCode &errorCode) { return buildResourcePath(path, segment1, segment2, segment3, errorCode).append('/', errorCode) .append(segment4, -1, errorCode); } typedef struct { const char * usageTypeName; DateFormatSymbols::ECapitalizationContextUsageType usageTypeEnumValue; } ContextUsageTypeNameToEnumValue; static const ContextUsageTypeNameToEnumValue contextUsageTypeMap[] = { // Entries must be sorted by usageTypeName; entry with NULL name terminates list. { "day-format-except-narrow", DateFormatSymbols::kCapContextUsageDayFormat }, { "day-narrow", DateFormatSymbols::kCapContextUsageDayNarrow }, { "day-standalone-except-narrow", DateFormatSymbols::kCapContextUsageDayStandalone }, { "era-abbr", DateFormatSymbols::kCapContextUsageEraAbbrev }, { "era-name", DateFormatSymbols::kCapContextUsageEraWide }, { "era-narrow", DateFormatSymbols::kCapContextUsageEraNarrow }, { "metazone-long", DateFormatSymbols::kCapContextUsageMetazoneLong }, { "metazone-short", DateFormatSymbols::kCapContextUsageMetazoneShort }, { "month-format-except-narrow", DateFormatSymbols::kCapContextUsageMonthFormat }, { "month-narrow", DateFormatSymbols::kCapContextUsageMonthNarrow }, { "month-standalone-except-narrow", DateFormatSymbols::kCapContextUsageMonthStandalone }, { "zone-long", DateFormatSymbols::kCapContextUsageZoneLong }, { "zone-short", DateFormatSymbols::kCapContextUsageZoneShort }, { NULL, (DateFormatSymbols::ECapitalizationContextUsageType)0 }, }; // Resource keys to look up localized strings for day periods. // The first one must be midnight and the second must be noon, so that their indices coincide // with the am/pm field. Formatting and parsing code for day periods relies on this coincidence. static const char *dayPeriodKeys[] = {"midnight", "noon", "morning1", "afternoon1", "evening1", "night1", "morning2", "afternoon2", "evening2", "night2"}; UnicodeString* loadDayPeriodStrings(CalendarDataSink &sink, CharString &path, int32_t &stringCount, UErrorCode &status) { if (U_FAILURE(status)) { return NULL; } UnicodeString pathUString(path.data(), -1, US_INV); Hashtable* map = static_cast(sink.maps.get(pathUString)); stringCount = UPRV_LENGTHOF(dayPeriodKeys); UnicodeString *strings = new UnicodeString[stringCount]; if (strings == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } if (map != NULL) { for (int32_t i = 0; i < stringCount; ++i) { UnicodeString dayPeriodKey(dayPeriodKeys[i], -1, US_INV); UnicodeString *dayPeriod = static_cast(map->get(dayPeriodKey)); if (dayPeriod != NULL) { strings[i].fastCopyFrom(*dayPeriod); } else { strings[i].setToBogus(); } } } else { for (int32_t i = 0; i < stringCount; i++) { strings[i].setToBogus(); } } return strings; } void DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData) { int32_t len = 0; /* In case something goes wrong, initialize all of the data to NULL. */ fEras = NULL; fErasCount = 0; fEraNames = NULL; fEraNamesCount = 0; fNarrowEras = NULL; fNarrowErasCount = 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; fShorterWeekdays = NULL; fShorterWeekdaysCount=0; fNarrowWeekdays = NULL; fNarrowWeekdaysCount=0; fStandaloneWeekdays = NULL; fStandaloneWeekdaysCount=0; fStandaloneShortWeekdays = NULL; fStandaloneShortWeekdaysCount=0; fStandaloneShorterWeekdays = NULL; fStandaloneShorterWeekdaysCount=0; fStandaloneNarrowWeekdays = NULL; fStandaloneNarrowWeekdaysCount=0; fAmPms = NULL; fAmPmsCount=0; fNarrowAmPms = NULL; fNarrowAmPmsCount=0; fTimeSeparator.setToBogus(); fQuarters = NULL; fQuartersCount = 0; fShortQuarters = NULL; fShortQuartersCount = 0; fStandaloneQuarters = NULL; fStandaloneQuartersCount = 0; fStandaloneShortQuarters = NULL; fStandaloneShortQuartersCount = 0; fLeapMonthPatterns = NULL; fLeapMonthPatternsCount = 0; fShortYearNames = NULL; fShortYearNamesCount = 0; fShortZodiacNames = NULL; fShortZodiacNamesCount = 0; fZoneStringsRowCount = 0; fZoneStringsColCount = 0; fZoneStrings = NULL; fLocaleZoneStrings = NULL; fAbbreviatedDayPeriods = NULL; fAbbreviatedDayPeriodsCount = 0; fWideDayPeriods = NULL; fWideDayPeriodsCount = 0; fNarrowDayPeriods = NULL; fNarrowDayPeriodsCount = 0; fStandaloneAbbreviatedDayPeriods = NULL; fStandaloneAbbreviatedDayPeriodsCount = 0; fStandaloneWideDayPeriods = NULL; fStandaloneWideDayPeriodsCount = 0; fStandaloneNarrowDayPeriods = NULL; fStandaloneNarrowDayPeriodsCount = 0; uprv_memset(fCapitalization, 0, sizeof(fCapitalization)); // We need to preserve the requested locale for // lazy ZoneStringFormat instantiation. ZoneStringFormat // is region sensitive, thus, bundle locale bundle's locale // is not sufficient. fZSFLocale = locale; if (U_FAILURE(status)) return; // Create a CalendarDataSink to process this data and the resouce bundles CalendarDataSink calendarSink(status); UResourceBundle *rb = ures_open(NULL, locale.getBaseName(), &status); UResourceBundle *cb = ures_getByKey(rb, gCalendarTag, NULL, &status); if (U_FAILURE(status)) return; // Iterate over the resource bundle data following the fallbacks through different calendar types UnicodeString calendarType((type != NULL && *type != '\0')? type : gGregorianTag, -1, US_INV); while (!calendarType.isBogus()) { CharString calendarTypeBuffer; calendarTypeBuffer.appendInvariantChars(calendarType, status); if (U_FAILURE(status)) { return; } const char *calendarTypeCArray = calendarTypeBuffer.data(); // Enumerate this calendar type. If the calendar is not found fallback to gregorian UErrorCode oldStatus = status; UResourceBundle *ctb = ures_getByKeyWithFallback(cb, calendarTypeCArray, NULL, &status); if (status == U_MISSING_RESOURCE_ERROR) { ures_close(ctb); if (uprv_strcmp(calendarTypeCArray, gGregorianTag) != 0) { calendarType.setTo(FALSE, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)); calendarSink.visitAllResources(); status = oldStatus; continue; } return; } calendarSink.preEnumerate(calendarType); ures_getAllItemsWithFallback(ctb, "", calendarSink, status); ures_close(ctb); if (U_FAILURE(status)) break; // Stop loading when gregorian was loaded if (uprv_strcmp(calendarTypeCArray, gGregorianTag) == 0) { break; } // Get the next calendar type to process from the sink calendarType = calendarSink.nextCalendarType; // Gregorian is always the last fallback if (calendarType.isBogus()) { calendarType.setTo(FALSE, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)); calendarSink.visitAllResources(); } } // CharString object to build paths CharString path; // Load Leap Month Patterns UErrorCode tempStatus = status; fLeapMonthPatterns = newUnicodeStringArray(kMonthPatternsCount); if (fLeapMonthPatterns) { initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatWide, calendarSink, buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesWideTag, tempStatus), tempStatus); initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatAbbrev, calendarSink, buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus); initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatNarrow, calendarSink, buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesNarrowTag, tempStatus), tempStatus); initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneWide, calendarSink, buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesWideTag, tempStatus), tempStatus); initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneAbbrev, calendarSink, buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesAbbrTag, tempStatus), tempStatus); initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneNarrow, calendarSink, buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesNarrowTag, tempStatus), tempStatus); initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternNumeric, calendarSink, buildResourcePath(path, gMonthPatternsTag, gNamesNumericTag, gNamesAllTag, tempStatus), tempStatus); if (U_SUCCESS(tempStatus)) { // Hack to fix bad C inheritance for dangi monthPatterns (OK in J); this should be handled by aliases in root, but isn't. // The ordering of the following statements is important. if (fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].isEmpty()) { fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]); }; if (fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].isEmpty()) { fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].setTo(fLeapMonthPatterns[kLeapMonthPatternStandaloneNarrow]); }; if (fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].isEmpty()) { fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]); }; if (fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].isEmpty()) { fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev]); }; // end of hack fLeapMonthPatternsCount = kMonthPatternsCount; } else { delete[] fLeapMonthPatterns; fLeapMonthPatterns = NULL; } } // Load cyclic names sets tempStatus = status; initField(&fShortYearNames, fShortYearNamesCount, calendarSink, buildResourcePath(path, gCyclicNameSetsTag, gNameSetYearsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus); initField(&fShortZodiacNames, fShortZodiacNamesCount, calendarSink, buildResourcePath(path, gCyclicNameSetsTag, gNameSetZodiacsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus); // Load context transforms and capitalization tempStatus = U_ZERO_ERROR; UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &tempStatus); if (U_SUCCESS(tempStatus)) { UResourceBundle *contextTransforms = ures_getByKeyWithFallback(localeBundle, gContextTransformsTag, NULL, &tempStatus); if (U_SUCCESS(tempStatus)) { UResourceBundle *contextTransformUsage; while ( (contextTransformUsage = ures_getNextResource(contextTransforms, NULL, &tempStatus)) != NULL ) { const int32_t * intVector = ures_getIntVector(contextTransformUsage, &len, &status); if (U_SUCCESS(tempStatus) && intVector != NULL && len >= 2) { const char* usageType = ures_getKey(contextTransformUsage); if (usageType != NULL) { const ContextUsageTypeNameToEnumValue * typeMapPtr = contextUsageTypeMap; int32_t compResult = 0; // linear search; list is short and we cannot be sure that bsearch is available while ( typeMapPtr->usageTypeName != NULL && (compResult = uprv_strcmp(usageType, typeMapPtr->usageTypeName)) > 0 ) { ++typeMapPtr; } if (typeMapPtr->usageTypeName != NULL && compResult == 0) { fCapitalization[typeMapPtr->usageTypeEnumValue][0] = intVector[0]; fCapitalization[typeMapPtr->usageTypeEnumValue][1] = intVector[1]; } } } tempStatus = U_ZERO_ERROR; ures_close(contextTransformUsage); } ures_close(contextTransforms); } tempStatus = U_ZERO_ERROR; const LocalPointer numberingSystem( NumberingSystem::createInstance(locale, tempStatus), tempStatus); if (U_SUCCESS(tempStatus)) { // These functions all fail gracefully if passed NULL pointers and // do nothing unless U_SUCCESS(tempStatus), so it's only necessary // to check for errors once after all calls are made. const LocalUResourceBundlePointer numberElementsData(ures_getByKeyWithFallback( localeBundle, gNumberElementsTag, NULL, &tempStatus)); const LocalUResourceBundlePointer nsNameData(ures_getByKeyWithFallback( numberElementsData.getAlias(), numberingSystem->getName(), NULL, &tempStatus)); const LocalUResourceBundlePointer symbolsData(ures_getByKeyWithFallback( nsNameData.getAlias(), gSymbolsTag, NULL, &tempStatus)); fTimeSeparator = ures_getUnicodeStringByKey( symbolsData.getAlias(), gTimeSeparatorTag, &tempStatus); if (U_FAILURE(tempStatus)) { fTimeSeparator.setToBogus(); } } ures_close(localeBundle); } if (fTimeSeparator.isBogus()) { fTimeSeparator.setTo(DateFormatSymbols::DEFAULT_TIME_SEPARATOR); } // Load day periods fWideDayPeriods = loadDayPeriodStrings(calendarSink, buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesWideTag, status), fWideDayPeriodsCount, status); fNarrowDayPeriods = loadDayPeriodStrings(calendarSink, buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesNarrowTag, status), fNarrowDayPeriodsCount, status); fAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink, buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesAbbrTag, status), fAbbreviatedDayPeriodsCount, status); fStandaloneWideDayPeriods = loadDayPeriodStrings(calendarSink, buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesWideTag, status), fStandaloneWideDayPeriodsCount, status); fStandaloneNarrowDayPeriods = loadDayPeriodStrings(calendarSink, buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesNarrowTag, status), fStandaloneNarrowDayPeriodsCount, status); fStandaloneAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink, buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesAbbrTag, status), fStandaloneAbbreviatedDayPeriodsCount, status); U_LOCALE_BASED(locBased, *this); // 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(cb, ULOC_VALID_LOCALE, &status), ures_getLocaleByType(cb, ULOC_ACTUAL_LOCALE, &status)); // Load eras initField(&fEras, fErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesAbbrTag, status), status); UErrorCode oldStatus = status; initField(&fEraNames, fEraNamesCount, calendarSink, buildResourcePath(path, gErasTag, gNamesWideTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3 status = oldStatus; assignArray(fEraNames, fEraNamesCount, fEras, fErasCount); } // current ICU4J falls back to abbreviated if narrow eras are missing, so we will too oldStatus = status; initField(&fNarrowEras, fNarrowErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesNarrowTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3 status = oldStatus; assignArray(fNarrowEras, fNarrowErasCount, fEras, fErasCount); } // Load month names initField(&fMonths, fMonthsCount, calendarSink, buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesWideTag, status), status); initField(&fShortMonths, fShortMonthsCount, calendarSink, buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesAbbrTag, status), status); initField(&fStandaloneMonths, fStandaloneMonthsCount, calendarSink, buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide not available, use format/wide */ status = U_ZERO_ERROR; assignArray(fStandaloneMonths, fStandaloneMonthsCount, fMonths, fMonthsCount); } initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calendarSink, buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated not available, use format/abbreviated */ status = U_ZERO_ERROR; assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, fShortMonths, fShortMonthsCount); } UErrorCode narrowMonthsEC = status; UErrorCode standaloneNarrowMonthsEC = status; initField(&fNarrowMonths, fNarrowMonthsCount, calendarSink, buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesNarrowTag, narrowMonthsEC), narrowMonthsEC); initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calendarSink, buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, narrowMonthsEC), standaloneNarrowMonthsEC); if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC != U_MISSING_RESOURCE_ERROR) { // If format/narrow not available, use standalone/narrow assignArray(fNarrowMonths, fNarrowMonthsCount, fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount); } else if (narrowMonthsEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) { // If standalone/narrow not availabe, use format/narrow assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fNarrowMonths, fNarrowMonthsCount); } else if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) { // If neither is available, use format/abbreviated assignArray(fNarrowMonths, fNarrowMonthsCount, fShortMonths, fShortMonthsCount); assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fShortMonths, fShortMonthsCount); } // Load AM/PM markers initField(&fAmPms, fAmPmsCount, calendarSink, buildResourcePath(path, gAmPmMarkersTag, status), status); initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink, buildResourcePath(path, gAmPmMarkersNarrowTag, status), status); // Load quarters initField(&fQuarters, fQuartersCount, calendarSink, buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesWideTag, status), status); initField(&fShortQuarters, fShortQuartersCount, calendarSink, buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesAbbrTag, status), status); initField(&fStandaloneQuarters, fStandaloneQuartersCount, calendarSink, buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status); if(status == U_MISSING_RESOURCE_ERROR) { status = U_ZERO_ERROR; assignArray(fStandaloneQuarters, fStandaloneQuartersCount, fQuarters, fQuartersCount); } initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calendarSink, buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status); if(status == U_MISSING_RESOURCE_ERROR) { status = U_ZERO_ERROR; assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, fShortQuarters, fShortQuartersCount); } // 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); // Format wide weekdays -> fWeekdays // {sfb} fixed to handle 1-based weekdays initField(&fWeekdays, fWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesWideTag, status), 1, status); // Format abbreviated weekdays -> fShortWeekdays initField(&fShortWeekdays, fShortWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesAbbrTag, status), 1, status); // Format short weekdays -> fShorterWeekdays (fall back to abbreviated) initField(&fShorterWeekdays, fShorterWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesShortTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) { status = U_ZERO_ERROR; assignArray(fShorterWeekdays, fShorterWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); } // Stand-alone wide weekdays -> fStandaloneWeekdays initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide is not available, use format/wide */ status = U_ZERO_ERROR; assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, fWeekdays, fWeekdaysCount); } // Stand-alone abbreviated weekdays -> fStandaloneShortWeekdays initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated is not available, use format/abbreviated */ status = U_ZERO_ERROR; assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); } // Stand-alone short weekdays -> fStandaloneShorterWeekdays (fall back to format abbreviated) initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesShortTag, status), 1, status); if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/short is not available, use format/short */ status = U_ZERO_ERROR; assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, fShorterWeekdays, fShorterWeekdaysCount); } // Format narrow weekdays -> fNarrowWeekdays UErrorCode narrowWeeksEC = status; initField(&fNarrowWeekdays, fNarrowWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesNarrowTag, status), 1, narrowWeeksEC); // Stand-alone narrow weekdays -> fStandaloneNarrowWeekdays UErrorCode standaloneNarrowWeeksEC = status; initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), 1, standaloneNarrowWeeksEC); if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC != U_MISSING_RESOURCE_ERROR) { // If format/narrow not available, use standalone/narrow assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount); } else if (narrowWeeksEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR) { // If standalone/narrow not available, use format/narrow assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fNarrowWeekdays, fNarrowWeekdaysCount); } else if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR ) { // If neither is available, use format/abbreviated assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); } // Last resort fallback in case previous data wasn't loaded 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; //TODO(fabalbon): make sure we are storing las resort data for all fields in here. initField(&fEras, fErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status); initField(&fEraNames, fEraNamesCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status); initField(&fNarrowEras, fNarrowErasCount, (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(&fShorterWeekdays, fShorterWeekdaysCount, (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(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, (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(&fNarrowAmPms, fNarrowAmPmsCount, (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); } } // Close resources ures_close(cb); ures_close(rb); } Locale DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const { U_LOCALE_BASED(locBased, *this); return locBased.getLocale(type, status); } U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ //eof