tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dtfmtsym.cpp (113951B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 1997-2016, International Business Machines Corporation and    *
      6 * others. All Rights Reserved.                                                *
      7 *******************************************************************************
      8 *
      9 * File DTFMTSYM.CPP
     10 *
     11 * Modification History:
     12 *
     13 *   Date        Name        Description
     14 *   02/19/97    aliu        Converted from java.
     15 *   07/21/98    stephen     Added getZoneIndex
     16 *                            Changed weekdays/short weekdays to be one-based
     17 *   06/14/99    stephen     Removed SimpleDateFormat::fgTimeZoneDataSuffix
     18 *   11/16/99    weiv        Added 'Y' and 'e' to fgPatternChars
     19 *   03/27/00    weiv        Keeping resource bundle around!
     20 *   06/30/05    emmons      Added eraNames, narrow month/day, standalone context
     21 *   10/12/05    emmons      Added setters for eraNames, month/day by width/context
     22 *******************************************************************************
     23 */
     24 
     25 #include <utility>
     26 
     27 #include "unicode/utypes.h"
     28 
     29 #if !UCONFIG_NO_FORMATTING
     30 #include "unicode/ustring.h"
     31 #include "unicode/localpointer.h"
     32 #include "unicode/dtfmtsym.h"
     33 #include "unicode/errorcode.h"
     34 #include "unicode/smpdtfmt.h"
     35 #include "unicode/msgfmt.h"
     36 #include "unicode/numsys.h"
     37 #include "unicode/tznames.h"
     38 #include "cpputils.h"
     39 #include "umutex.h"
     40 #include "cmemory.h"
     41 #include "cstring.h"
     42 #include "charstr.h"
     43 #include "erarules.h"
     44 #include "dt_impl.h"
     45 #include "locbased.h"
     46 #include "gregoimp.h"
     47 #include "hash.h"
     48 #include "uassert.h"
     49 #include "uresimp.h"
     50 #include "ureslocs.h"
     51 #include "uvector.h"
     52 #include "shareddateformatsymbols.h"
     53 #include "unicode/calendar.h"
     54 #include "unifiedcache.h"
     55 
     56 // *****************************************************************************
     57 // class DateFormatSymbols
     58 // *****************************************************************************
     59 
     60 /**
     61 * These are static arrays we use only in the case where we have no
     62 * resource data.
     63 */
     64 
     65 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
     66 #define PATTERN_CHARS_LEN 38
     67 #else
     68 #define PATTERN_CHARS_LEN 37
     69 #endif
     70 
     71 /**
     72 * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
     73 * locales use the same these unlocalized pattern characters.
     74 */
     75 static const char16_t gPatternChars[] = {
     76    // if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR:
     77    //   GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:
     78    // else:
     79    //   GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB
     80 
     81    0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
     82    0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
     83    0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56,
     84    0x55, 0x4F, 0x58, 0x78, 0x72, 0x62, 0x42,
     85 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
     86    0x3a,
     87 #endif
     88    0
     89 };
     90 
     91 /**
     92 * Map of each ASCII character to its corresponding index in the table above if
     93 * it is a pattern character and -1 otherwise.
     94 */
     95 static const int8_t gLookupPatternChars[] = {
     96        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     97    //
     98        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     99    //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
    100        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    101 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
    102    //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
    103        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1,
    104 #else
    105    //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
    106        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    107 #endif
    108    //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
    109        -1, 22, 36, -1, 10,  9, 11,  0,  5, -1, -1, 16, 26,  2, -1, 31,
    110    //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
    111        -1, 27, -1,  8, -1, 30, 29, 13, 32, 18, 23, -1, -1, -1, -1, -1,
    112    //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
    113        -1, 14, 35, 25,  3, 19, -1, 21, 15, -1, -1,  4, -1,  6, -1, -1,
    114    //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
    115        -1, 28, 34,  7, -1, 20, 24, 12, 33,  1, 17, -1, -1, -1, -1, -1
    116 };
    117 
    118 //------------------------------------------------------
    119 // Strings of last resort.  These are only used if we have no resource
    120 // files.  They aren't designed for actual use, just for backup.
    121 
    122 // These are the month names and abbreviations of last resort.
    123 static const char16_t gLastResortMonthNames[13][3] =
    124 {
    125    {0x0030, 0x0031, 0x0000}, /* "01" */
    126    {0x0030, 0x0032, 0x0000}, /* "02" */
    127    {0x0030, 0x0033, 0x0000}, /* "03" */
    128    {0x0030, 0x0034, 0x0000}, /* "04" */
    129    {0x0030, 0x0035, 0x0000}, /* "05" */
    130    {0x0030, 0x0036, 0x0000}, /* "06" */
    131    {0x0030, 0x0037, 0x0000}, /* "07" */
    132    {0x0030, 0x0038, 0x0000}, /* "08" */
    133    {0x0030, 0x0039, 0x0000}, /* "09" */
    134    {0x0031, 0x0030, 0x0000}, /* "10" */
    135    {0x0031, 0x0031, 0x0000}, /* "11" */
    136    {0x0031, 0x0032, 0x0000}, /* "12" */
    137    {0x0031, 0x0033, 0x0000}  /* "13" */
    138 };
    139 
    140 // These are the weekday names and abbreviations of last resort.
    141 static const char16_t gLastResortDayNames[8][2] =
    142 {
    143    {0x0030, 0x0000}, /* "0" */
    144    {0x0031, 0x0000}, /* "1" */
    145    {0x0032, 0x0000}, /* "2" */
    146    {0x0033, 0x0000}, /* "3" */
    147    {0x0034, 0x0000}, /* "4" */
    148    {0x0035, 0x0000}, /* "5" */
    149    {0x0036, 0x0000}, /* "6" */
    150    {0x0037, 0x0000}  /* "7" */
    151 };
    152 
    153 // These are the quarter names and abbreviations of last resort.
    154 static const char16_t gLastResortQuarters[4][2] =
    155 {
    156    {0x0031, 0x0000}, /* "1" */
    157    {0x0032, 0x0000}, /* "2" */
    158    {0x0033, 0x0000}, /* "3" */
    159    {0x0034, 0x0000}, /* "4" */
    160 };
    161 
    162 // These are the am/pm and BC/AD markers of last resort.
    163 static const char16_t gLastResortAmPmMarkers[2][3] =
    164 {
    165    {0x0041, 0x004D, 0x0000}, /* "AM" */
    166    {0x0050, 0x004D, 0x0000}  /* "PM" */
    167 };
    168 
    169 static const char16_t gLastResortEras[2][3] =
    170 {
    171    {0x0042, 0x0043, 0x0000}, /* "BC" */
    172    {0x0041, 0x0044, 0x0000}  /* "AD" */
    173 };
    174 
    175 /* Sizes for the last resort string arrays */
    176 typedef enum LastResortSize {
    177    kMonthNum = 13,
    178    kMonthLen = 3,
    179 
    180    kDayNum = 8,
    181    kDayLen = 2,
    182 
    183    kAmPmNum = 2,
    184    kAmPmLen = 3,
    185 
    186    kQuarterNum = 4,
    187    kQuarterLen = 2,
    188 
    189    kEraNum = 2,
    190    kEraLen = 3,
    191 
    192    kZoneNum = 5,
    193    kZoneLen = 4,
    194 
    195    kGmtHourNum = 4,
    196    kGmtHourLen = 10
    197 } LastResortSize;
    198 
    199 U_NAMESPACE_BEGIN
    200 
    201 SharedDateFormatSymbols::~SharedDateFormatSymbols() {
    202 }
    203 
    204 template<> U_I18N_API
    205 const SharedDateFormatSymbols *
    206        LocaleCacheKey<SharedDateFormatSymbols>::createObject(
    207                const void * /*unusedContext*/, UErrorCode &status) const {
    208    char type[256];
    209    Calendar::getCalendarTypeFromLocale(fLoc, type, UPRV_LENGTHOF(type), status);
    210    if (U_FAILURE(status)) {
    211        return nullptr;
    212    }
    213    SharedDateFormatSymbols *shared
    214            = new SharedDateFormatSymbols(fLoc, type, status);
    215    if (shared == nullptr) {
    216        status = U_MEMORY_ALLOCATION_ERROR;
    217        return nullptr;
    218    }
    219    if (U_FAILURE(status)) {
    220        delete shared;
    221        return nullptr;
    222    }
    223    shared->addRef();
    224    return shared;
    225 }
    226 
    227 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)
    228 
    229 #define kSUPPLEMENTAL "supplementalData"
    230 
    231 /**
    232 * These are the tags we expect to see in normal resource bundle files associated
    233 * with a locale and calendar
    234 */
    235 static const char gCalendarTag[]="calendar";
    236 static const char gGregorianTag[]="gregorian";
    237 static const char gErasTag[]="eras";
    238 static const char gCyclicNameSetsTag[]="cyclicNameSets";
    239 static const char gNameSetYearsTag[]="years";
    240 static const char gNameSetZodiacsTag[]="zodiacs";
    241 static const char gMonthNamesTag[]="monthNames";
    242 static const char gMonthPatternsTag[]="monthPatterns";
    243 static const char gDayNamesTag[]="dayNames";
    244 static const char gNamesWideTag[]="wide";
    245 static const char gNamesAbbrTag[]="abbreviated";
    246 static const char gNamesShortTag[]="short";
    247 static const char gNamesNarrowTag[]="narrow";
    248 static const char gNamesAllTag[]="all";
    249 static const char gNamesFormatTag[]="format";
    250 static const char gNamesStandaloneTag[]="stand-alone";
    251 static const char gNamesNumericTag[]="numeric";
    252 static const char gAmPmMarkersTag[]="AmPmMarkers";
    253 static const char gAmPmMarkersAbbrTag[]="AmPmMarkersAbbr";
    254 static const char gAmPmMarkersNarrowTag[]="AmPmMarkersNarrow";
    255 static const char gQuartersTag[]="quarters";
    256 static const char gNumberElementsTag[]="NumberElements";
    257 static const char gSymbolsTag[]="symbols";
    258 static const char gTimeSeparatorTag[]="timeSeparator";
    259 static const char gDayPeriodTag[]="dayPeriod";
    260 
    261 // static const char gZoneStringsTag[]="zoneStrings";
    262 
    263 // static const char gLocalPatternCharsTag[]="localPatternChars";
    264 
    265 static const char gContextTransformsTag[]="contextTransforms";
    266 
    267 /**
    268 * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly.
    269 * Work around this.
    270 */
    271 static inline UnicodeString* newUnicodeStringArray(size_t count) {
    272    return new UnicodeString[count ? count : 1];
    273 }
    274 
    275 //------------------------------------------------------
    276 
    277 DateFormatSymbols * U_EXPORT2
    278 DateFormatSymbols::createForLocale(
    279        const Locale& locale, UErrorCode &status) {
    280    const SharedDateFormatSymbols *shared = nullptr;
    281    UnifiedCache::getByLocale(locale, shared, status);
    282    if (U_FAILURE(status)) {
    283        return nullptr;
    284    }
    285    DateFormatSymbols *result = new DateFormatSymbols(shared->get());
    286    shared->removeRef();
    287    if (result == nullptr) {
    288        status = U_MEMORY_ALLOCATION_ERROR;
    289        return nullptr;
    290    }
    291    return result;
    292 }
    293 
    294 DateFormatSymbols::DateFormatSymbols(const Locale& locale,
    295                                     UErrorCode& status)
    296    : UObject()
    297 {
    298  initializeData(locale, nullptr,  status);
    299 }
    300 
    301 DateFormatSymbols::DateFormatSymbols(UErrorCode& status)
    302    : UObject()
    303 {
    304  initializeData(Locale::getDefault(), nullptr, status, true);
    305 }
    306 
    307 
    308 DateFormatSymbols::DateFormatSymbols(const Locale& locale,
    309                                     const char *type,
    310                                     UErrorCode& status)
    311    : UObject()
    312 {
    313  initializeData(locale, type,  status);
    314 }
    315 
    316 DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status)
    317    : UObject()
    318 {
    319  initializeData(Locale::getDefault(), type, status, true);
    320 }
    321 
    322 DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other)
    323    : UObject(other)
    324 {
    325    copyData(other);
    326 }
    327 
    328 void
    329 DateFormatSymbols::assignArray(UnicodeString*& dstArray,
    330                               int32_t& dstCount,
    331                               const UnicodeString* srcArray,
    332                               int32_t srcCount)
    333 {
    334    // assignArray() is only called by copyData() and initializeData(), which in turn
    335    // implements the copy constructor and the assignment operator.
    336    // All strings in a DateFormatSymbols object are created in one of the following
    337    // three ways that all allow to safely use UnicodeString::fastCopyFrom():
    338    // - readonly-aliases from resource bundles
    339    // - readonly-aliases or allocated strings from constants
    340    // - safely cloned strings (with owned buffers) from setXYZ() functions
    341    //
    342    // Note that this is true for as long as DateFormatSymbols can be constructed
    343    // only from a locale bundle or set via the cloning API,
    344    // *and* for as long as all the strings are in *private* fields, preventing
    345    // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()).
    346    if(srcArray == nullptr) {
    347        // Do not attempt to copy bogus input (which will crash).
    348        // Note that this assignArray method already had the potential to return a null dstArray;
    349        // see handling below for "if(dstArray != nullptr)".
    350        dstCount = 0;
    351        dstArray = nullptr;
    352        return;
    353    }
    354    dstCount = srcCount;
    355    dstArray = newUnicodeStringArray(srcCount);
    356    if(dstArray != nullptr) {
    357        int32_t i;
    358        for(i=0; i<srcCount; ++i) {
    359            dstArray[i].fastCopyFrom(srcArray[i]);
    360        }
    361    }
    362 }
    363 
    364 /**
    365 * Create a copy, in fZoneStrings, of the given zone strings array.  The
    366 * member variables fZoneStringsRowCount and fZoneStringsColCount should
    367 * be set already by the caller.
    368 */
    369 void
    370 DateFormatSymbols::createZoneStrings(const UnicodeString *const * otherStrings)
    371 {
    372    int32_t row, col;
    373    UBool failed = false;
    374 
    375    fZoneStrings = static_cast<UnicodeString**>(uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString*)));
    376    if (fZoneStrings != nullptr) {
    377        for (row=0; row<fZoneStringsRowCount; ++row)
    378        {
    379            fZoneStrings[row] = newUnicodeStringArray(fZoneStringsColCount);
    380            if (fZoneStrings[row] == nullptr) {
    381                failed = true;
    382                break;
    383            }
    384            for (col=0; col<fZoneStringsColCount; ++col) {
    385                // fastCopyFrom() - see assignArray comments
    386                fZoneStrings[row][col].fastCopyFrom(otherStrings[row][col]);
    387            }
    388        }
    389    }
    390    // If memory allocation failed, roll back and delete fZoneStrings
    391    if (failed) {
    392        for (int i = row; i >= 0; i--) {
    393            delete[] fZoneStrings[i];
    394        }
    395        uprv_free(fZoneStrings);
    396        fZoneStrings = nullptr;
    397    }
    398 }
    399 
    400 /**
    401 * Copy all of the other's data to this.
    402 */
    403 void
    404 DateFormatSymbols::copyData(const DateFormatSymbols& other) {
    405    validLocale = other.validLocale;
    406    actualLocale = other.actualLocale;
    407    assignArray(fEras, fErasCount, other.fEras, other.fErasCount);
    408    assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount);
    409    assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount);
    410    assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount);
    411    assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount);
    412    assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount);
    413    assignArray(fStandaloneMonths, fStandaloneMonthsCount, other.fStandaloneMonths, other.fStandaloneMonthsCount);
    414    assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, other.fStandaloneShortMonths, other.fStandaloneShortMonthsCount);
    415    assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, other.fStandaloneNarrowMonths, other.fStandaloneNarrowMonthsCount);
    416    assignArray(fWeekdays, fWeekdaysCount, other.fWeekdays, other.fWeekdaysCount);
    417    assignArray(fShortWeekdays, fShortWeekdaysCount, other.fShortWeekdays, other.fShortWeekdaysCount);
    418    assignArray(fShorterWeekdays, fShorterWeekdaysCount, other.fShorterWeekdays, other.fShorterWeekdaysCount);
    419    assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount);
    420    assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, other.fStandaloneWeekdays, other.fStandaloneWeekdaysCount);
    421    assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, other.fStandaloneShortWeekdays, other.fStandaloneShortWeekdaysCount);
    422    assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, other.fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdaysCount);
    423    assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount);
    424    assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount);
    425    assignArray(fWideAmPms, fWideAmPmsCount, other.fWideAmPms, other.fWideAmPmsCount );
    426    assignArray(fNarrowAmPms, fNarrowAmPmsCount, other.fNarrowAmPms, other.fNarrowAmPmsCount );
    427    fTimeSeparator.fastCopyFrom(other.fTimeSeparator);  // fastCopyFrom() - see assignArray comments
    428    assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount);
    429    assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
    430    assignArray(fNarrowQuarters, fNarrowQuartersCount, other.fNarrowQuarters, other.fNarrowQuartersCount);
    431    assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
    432    assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
    433    assignArray(fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, other.fStandaloneNarrowQuarters, other.fStandaloneNarrowQuartersCount);
    434    assignArray(fWideDayPeriods, fWideDayPeriodsCount,
    435                other.fWideDayPeriods, other.fWideDayPeriodsCount);
    436    assignArray(fNarrowDayPeriods, fNarrowDayPeriodsCount,
    437                other.fNarrowDayPeriods, other.fNarrowDayPeriodsCount);
    438    assignArray(fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount,
    439                other.fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriodsCount);
    440    assignArray(fStandaloneWideDayPeriods, fStandaloneWideDayPeriodsCount,
    441                other.fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriodsCount);
    442    assignArray(fStandaloneNarrowDayPeriods, fStandaloneNarrowDayPeriodsCount,
    443                other.fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriodsCount);
    444    assignArray(fStandaloneAbbreviatedDayPeriods, fStandaloneAbbreviatedDayPeriodsCount,
    445                other.fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriodsCount);
    446    if (other.fLeapMonthPatterns != nullptr) {
    447        assignArray(fLeapMonthPatterns, fLeapMonthPatternsCount, other.fLeapMonthPatterns, other.fLeapMonthPatternsCount);
    448    } else {
    449        fLeapMonthPatterns = nullptr;
    450        fLeapMonthPatternsCount = 0;
    451    }
    452    if (other.fShortYearNames != nullptr) {
    453        assignArray(fShortYearNames, fShortYearNamesCount, other.fShortYearNames, other.fShortYearNamesCount);
    454    } else {
    455        fShortYearNames = nullptr;
    456        fShortYearNamesCount = 0;
    457    }
    458    if (other.fShortZodiacNames != nullptr) {
    459        assignArray(fShortZodiacNames, fShortZodiacNamesCount, other.fShortZodiacNames, other.fShortZodiacNamesCount);
    460    } else {
    461        fShortZodiacNames = nullptr;
    462        fShortZodiacNamesCount = 0;
    463    }
    464 
    465    if (other.fZoneStrings != nullptr) {
    466        fZoneStringsColCount = other.fZoneStringsColCount;
    467        fZoneStringsRowCount = other.fZoneStringsRowCount;
    468        createZoneStrings((const UnicodeString**)other.fZoneStrings);
    469 
    470    } else {
    471        fZoneStrings = nullptr;
    472        fZoneStringsColCount = 0;
    473        fZoneStringsRowCount = 0;
    474    }
    475    fZSFLocale = other.fZSFLocale;
    476    // Other zone strings data is created on demand
    477    fLocaleZoneStrings = nullptr;
    478 
    479    // fastCopyFrom() - see assignArray comments
    480    fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
    481 
    482    uprv_memcpy(fCapitalization, other.fCapitalization, sizeof(fCapitalization));
    483 }
    484 
    485 /**
    486 * Assignment operator.
    487 */
    488 DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
    489 {
    490    if (this == &other) { return *this; }  // self-assignment: no-op
    491    dispose();
    492    copyData(other);
    493 
    494    return *this;
    495 }
    496 
    497 DateFormatSymbols::~DateFormatSymbols()
    498 {
    499    dispose();
    500 }
    501 
    502 void DateFormatSymbols::dispose()
    503 {
    504    delete[] fEras;
    505    delete[] fEraNames;
    506    delete[] fNarrowEras;
    507    delete[] fMonths;
    508    delete[] fShortMonths;
    509    delete[] fNarrowMonths;
    510    delete[] fStandaloneMonths;
    511    delete[] fStandaloneShortMonths;
    512    delete[] fStandaloneNarrowMonths;
    513    delete[] fWeekdays;
    514    delete[] fShortWeekdays;
    515    delete[] fShorterWeekdays;
    516    delete[] fNarrowWeekdays;
    517    delete[] fStandaloneWeekdays;
    518    delete[] fStandaloneShortWeekdays;
    519    delete[] fStandaloneShorterWeekdays;
    520    delete[] fStandaloneNarrowWeekdays;
    521    delete[] fAmPms;
    522    delete[] fWideAmPms;
    523    delete[] fNarrowAmPms;
    524    delete[] fQuarters;
    525    delete[] fShortQuarters;
    526    delete[] fNarrowQuarters;
    527    delete[] fStandaloneQuarters;
    528    delete[] fStandaloneShortQuarters;
    529    delete[] fStandaloneNarrowQuarters;
    530    delete[] fLeapMonthPatterns;
    531    delete[] fShortYearNames;
    532    delete[] fShortZodiacNames;
    533    delete[] fAbbreviatedDayPeriods;
    534    delete[] fWideDayPeriods;
    535    delete[] fNarrowDayPeriods;
    536    delete[] fStandaloneAbbreviatedDayPeriods;
    537    delete[] fStandaloneWideDayPeriods;
    538    delete[] fStandaloneNarrowDayPeriods;
    539 
    540    actualLocale = Locale::getRoot();
    541    validLocale = Locale::getRoot();
    542    disposeZoneStrings();
    543 }
    544 
    545 void DateFormatSymbols::disposeZoneStrings()
    546 {
    547    if (fZoneStrings) {
    548        for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
    549            delete[] fZoneStrings[row];
    550        }
    551        uprv_free(fZoneStrings);
    552    }
    553    if (fLocaleZoneStrings) {
    554        for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
    555            delete[] fLocaleZoneStrings[row];
    556        }
    557        uprv_free(fLocaleZoneStrings);
    558    }
    559 
    560    fZoneStrings = nullptr;
    561    fLocaleZoneStrings = nullptr;
    562    fZoneStringsRowCount = 0;
    563    fZoneStringsColCount = 0;
    564 }
    565 
    566 UBool
    567 DateFormatSymbols::arrayCompare(const UnicodeString* array1,
    568                                const UnicodeString* array2,
    569                                int32_t count)
    570 {
    571    if (array1 == array2) return true;
    572    while (count>0)
    573    {
    574        --count;
    575        if (array1[count] != array2[count]) return false;
    576    }
    577    return true;
    578 }
    579 
    580 bool
    581 DateFormatSymbols::operator==(const DateFormatSymbols& other) const
    582 {
    583    // First do cheap comparisons
    584    if (this == &other) {
    585        return true;
    586    }
    587    if (fErasCount == other.fErasCount &&
    588        fEraNamesCount == other.fEraNamesCount &&
    589        fNarrowErasCount == other.fNarrowErasCount &&
    590        fMonthsCount == other.fMonthsCount &&
    591        fShortMonthsCount == other.fShortMonthsCount &&
    592        fNarrowMonthsCount == other.fNarrowMonthsCount &&
    593        fStandaloneMonthsCount == other.fStandaloneMonthsCount &&
    594        fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount &&
    595        fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount &&
    596        fWeekdaysCount == other.fWeekdaysCount &&
    597        fShortWeekdaysCount == other.fShortWeekdaysCount &&
    598        fShorterWeekdaysCount == other.fShorterWeekdaysCount &&
    599        fNarrowWeekdaysCount == other.fNarrowWeekdaysCount &&
    600        fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount &&
    601        fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount &&
    602        fStandaloneShorterWeekdaysCount == other.fStandaloneShorterWeekdaysCount &&
    603        fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount &&
    604        fAmPmsCount == other.fAmPmsCount &&
    605        fWideAmPmsCount == other.fWideAmPmsCount &&
    606        fNarrowAmPmsCount == other.fNarrowAmPmsCount &&
    607        fQuartersCount == other.fQuartersCount &&
    608        fShortQuartersCount == other.fShortQuartersCount &&
    609        fNarrowQuartersCount == other.fNarrowQuartersCount &&
    610        fStandaloneQuartersCount == other.fStandaloneQuartersCount &&
    611        fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount &&
    612        fStandaloneNarrowQuartersCount == other.fStandaloneNarrowQuartersCount &&
    613        fLeapMonthPatternsCount == other.fLeapMonthPatternsCount &&
    614        fShortYearNamesCount == other.fShortYearNamesCount &&
    615        fShortZodiacNamesCount == other.fShortZodiacNamesCount &&
    616        fAbbreviatedDayPeriodsCount == other.fAbbreviatedDayPeriodsCount &&
    617        fWideDayPeriodsCount == other.fWideDayPeriodsCount &&
    618        fNarrowDayPeriodsCount == other.fNarrowDayPeriodsCount &&
    619        fStandaloneAbbreviatedDayPeriodsCount == other.fStandaloneAbbreviatedDayPeriodsCount &&
    620        fStandaloneWideDayPeriodsCount == other.fStandaloneWideDayPeriodsCount &&
    621        fStandaloneNarrowDayPeriodsCount == other.fStandaloneNarrowDayPeriodsCount &&
    622        (uprv_memcmp(fCapitalization, other.fCapitalization, sizeof(fCapitalization))==0))
    623    {
    624        // Now compare the arrays themselves
    625        if (arrayCompare(fEras, other.fEras, fErasCount) &&
    626            arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) &&
    627            arrayCompare(fNarrowEras, other.fNarrowEras, fNarrowErasCount) &&
    628            arrayCompare(fMonths, other.fMonths, fMonthsCount) &&
    629            arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) &&
    630            arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) &&
    631            arrayCompare(fStandaloneMonths, other.fStandaloneMonths, fStandaloneMonthsCount) &&
    632            arrayCompare(fStandaloneShortMonths, other.fStandaloneShortMonths, fStandaloneShortMonthsCount) &&
    633            arrayCompare(fStandaloneNarrowMonths, other.fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount) &&
    634            arrayCompare(fWeekdays, other.fWeekdays, fWeekdaysCount) &&
    635            arrayCompare(fShortWeekdays, other.fShortWeekdays, fShortWeekdaysCount) &&
    636            arrayCompare(fShorterWeekdays, other.fShorterWeekdays, fShorterWeekdaysCount) &&
    637            arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) &&
    638            arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) &&
    639            arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) &&
    640            arrayCompare(fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount) &&
    641            arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) &&
    642            arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) &&
    643            arrayCompare(fWideAmPms, other.fWideAmPms, fWideAmPmsCount) &&
    644            arrayCompare(fNarrowAmPms, other.fNarrowAmPms, fNarrowAmPmsCount) &&
    645            fTimeSeparator == other.fTimeSeparator &&
    646            arrayCompare(fQuarters, other.fQuarters, fQuartersCount) &&
    647            arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) &&
    648            arrayCompare(fNarrowQuarters, other.fNarrowQuarters, fNarrowQuartersCount) &&
    649            arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
    650            arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) &&
    651            arrayCompare(fStandaloneNarrowQuarters, other.fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount) &&
    652            arrayCompare(fLeapMonthPatterns, other.fLeapMonthPatterns, fLeapMonthPatternsCount) &&
    653            arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount) &&
    654            arrayCompare(fShortZodiacNames, other.fShortZodiacNames, fShortZodiacNamesCount) &&
    655            arrayCompare(fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount) &&
    656            arrayCompare(fWideDayPeriods, other.fWideDayPeriods, fWideDayPeriodsCount) &&
    657            arrayCompare(fNarrowDayPeriods, other.fNarrowDayPeriods, fNarrowDayPeriodsCount) &&
    658            arrayCompare(fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriods,
    659                         fStandaloneAbbreviatedDayPeriodsCount) &&
    660            arrayCompare(fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriods,
    661                         fStandaloneWideDayPeriodsCount) &&
    662            arrayCompare(fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriods,
    663                         fStandaloneWideDayPeriodsCount))
    664        {
    665            // Compare the contents of fZoneStrings
    666            if (fZoneStrings == nullptr && other.fZoneStrings == nullptr) {
    667                if (fZSFLocale == other.fZSFLocale) {
    668                    return true;
    669                }
    670            } else if (fZoneStrings != nullptr && other.fZoneStrings != nullptr) {
    671                if (fZoneStringsRowCount == other.fZoneStringsRowCount
    672                    && fZoneStringsColCount == other.fZoneStringsColCount) {
    673                    bool cmpres = true;
    674                    for (int32_t i = 0; (i < fZoneStringsRowCount) && cmpres; i++) {
    675                        cmpres = arrayCompare(fZoneStrings[i], other.fZoneStrings[i], fZoneStringsColCount);
    676                    }
    677                    return cmpres;
    678                }
    679            }
    680            return false;
    681        }
    682    }
    683    return false;
    684 }
    685 
    686 //------------------------------------------------------
    687 
    688 const UnicodeString*
    689 DateFormatSymbols::getEras(int32_t &count) const
    690 {
    691    count = fErasCount;
    692    return fEras;
    693 }
    694 
    695 const UnicodeString*
    696 DateFormatSymbols::getEraNames(int32_t &count) const
    697 {
    698    count = fEraNamesCount;
    699    return fEraNames;
    700 }
    701 
    702 const UnicodeString*
    703 DateFormatSymbols::getNarrowEras(int32_t &count) const
    704 {
    705    count = fNarrowErasCount;
    706    return fNarrowEras;
    707 }
    708 
    709 const UnicodeString*
    710 DateFormatSymbols::getMonths(int32_t &count) const
    711 {
    712    count = fMonthsCount;
    713    return fMonths;
    714 }
    715 
    716 const UnicodeString*
    717 DateFormatSymbols::getShortMonths(int32_t &count) const
    718 {
    719    count = fShortMonthsCount;
    720    return fShortMonths;
    721 }
    722 
    723 const UnicodeString*
    724 DateFormatSymbols::getMonths(int32_t &count, DtContextType context, DtWidthType width ) const
    725 {
    726    UnicodeString *returnValue = nullptr;
    727 
    728    switch (context) {
    729    case FORMAT :
    730        switch(width) {
    731        case WIDE :
    732            count = fMonthsCount;
    733            returnValue = fMonths;
    734            break;
    735        case ABBREVIATED :
    736        case SHORT : // no month data for this, defaults to ABBREVIATED
    737            count = fShortMonthsCount;
    738            returnValue = fShortMonths;
    739            break;
    740        case NARROW :
    741            count = fNarrowMonthsCount;
    742            returnValue = fNarrowMonths;
    743            break;
    744        case DT_WIDTH_COUNT :
    745            break;
    746        }
    747        break;
    748    case STANDALONE :
    749        switch(width) {
    750        case WIDE :
    751            count = fStandaloneMonthsCount;
    752            returnValue = fStandaloneMonths;
    753            break;
    754        case ABBREVIATED :
    755        case SHORT : // no month data for this, defaults to ABBREVIATED
    756            count = fStandaloneShortMonthsCount;
    757            returnValue = fStandaloneShortMonths;
    758            break;
    759        case NARROW :
    760            count = fStandaloneNarrowMonthsCount;
    761            returnValue = fStandaloneNarrowMonths;
    762            break;
    763        case DT_WIDTH_COUNT :
    764            break;
    765        }
    766        break;
    767    case DT_CONTEXT_COUNT :
    768        break;
    769    }
    770    return returnValue;
    771 }
    772 
    773 const UnicodeString*
    774 DateFormatSymbols::getWeekdays(int32_t &count) const
    775 {
    776    count = fWeekdaysCount;
    777    return fWeekdays;
    778 }
    779 
    780 const UnicodeString*
    781 DateFormatSymbols::getShortWeekdays(int32_t &count) const
    782 {
    783    count = fShortWeekdaysCount;
    784    return fShortWeekdays;
    785 }
    786 
    787 const UnicodeString*
    788 DateFormatSymbols::getWeekdays(int32_t &count, DtContextType context, DtWidthType width) const
    789 {
    790    UnicodeString *returnValue = nullptr;
    791    switch (context) {
    792    case FORMAT :
    793        switch(width) {
    794            case WIDE :
    795                count = fWeekdaysCount;
    796                returnValue = fWeekdays;
    797                break;
    798            case ABBREVIATED :
    799                count = fShortWeekdaysCount;
    800                returnValue = fShortWeekdays;
    801                break;
    802            case SHORT :
    803                count = fShorterWeekdaysCount;
    804                returnValue = fShorterWeekdays;
    805                break;
    806            case NARROW :
    807                count = fNarrowWeekdaysCount;
    808                returnValue = fNarrowWeekdays;
    809                break;
    810            case DT_WIDTH_COUNT :
    811                break;
    812        }
    813        break;
    814    case STANDALONE :
    815        switch(width) {
    816            case WIDE :
    817                count = fStandaloneWeekdaysCount;
    818                returnValue = fStandaloneWeekdays;
    819                break;
    820            case ABBREVIATED :
    821                count = fStandaloneShortWeekdaysCount;
    822                returnValue = fStandaloneShortWeekdays;
    823                break;
    824            case SHORT :
    825                count = fStandaloneShorterWeekdaysCount;
    826                returnValue = fStandaloneShorterWeekdays;
    827                break;
    828            case NARROW :
    829                count = fStandaloneNarrowWeekdaysCount;
    830                returnValue = fStandaloneNarrowWeekdays;
    831                break;
    832            case DT_WIDTH_COUNT :
    833                break;
    834        }
    835        break;
    836    case DT_CONTEXT_COUNT :
    837        break;
    838    }
    839    return returnValue;
    840 }
    841 
    842 const UnicodeString*
    843 DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthType width ) const
    844 {
    845    UnicodeString *returnValue = nullptr;
    846 
    847    switch (context) {
    848    case FORMAT :
    849        switch(width) {
    850        case WIDE :
    851            count = fQuartersCount;
    852            returnValue = fQuarters;
    853            break;
    854        case ABBREVIATED :
    855        case SHORT : // no quarter data for this, defaults to ABBREVIATED
    856            count = fShortQuartersCount;
    857            returnValue = fShortQuarters;
    858            break;
    859        case NARROW :
    860            count = fNarrowQuartersCount;
    861            returnValue = fNarrowQuarters;
    862            break;
    863        case DT_WIDTH_COUNT :
    864            break;
    865        }
    866        break;
    867    case STANDALONE :
    868        switch(width) {
    869        case WIDE :
    870            count = fStandaloneQuartersCount;
    871            returnValue = fStandaloneQuarters;
    872            break;
    873        case ABBREVIATED :
    874        case SHORT : // no quarter data for this, defaults to ABBREVIATED
    875            count = fStandaloneShortQuartersCount;
    876            returnValue = fStandaloneShortQuarters;
    877            break;
    878        case NARROW :
    879            count = fStandaloneNarrowQuartersCount;
    880            returnValue = fStandaloneNarrowQuarters;
    881            break;
    882        case DT_WIDTH_COUNT :
    883            break;
    884        }
    885        break;
    886    case DT_CONTEXT_COUNT :
    887        break;
    888    }
    889    return returnValue;
    890 }
    891 
    892 UnicodeString&
    893 DateFormatSymbols::getTimeSeparatorString(UnicodeString& result) const
    894 {
    895    // fastCopyFrom() - see assignArray comments
    896    return result.fastCopyFrom(fTimeSeparator);
    897 }
    898 
    899 const UnicodeString*
    900 DateFormatSymbols::getAmPmStrings(int32_t &count) const
    901 {
    902    return getAmPmStrings(count, FORMAT, ABBREVIATED);
    903 }
    904 
    905 const UnicodeString*
    906 DateFormatSymbols::getAmPmStrings(int32_t &count, DtContextType /*ignored*/, DtWidthType width) const
    907 {
    908    UnicodeString* const* srcArray;
    909    int32_t const* srcCount;
    910    switch (width) {
    911    case WIDE:
    912        srcArray = &fWideAmPms;
    913        srcCount = &fWideAmPmsCount;
    914        break;
    915    case NARROW:
    916        srcArray = &fNarrowAmPms;
    917        srcCount = &fNarrowAmPmsCount;
    918        break;
    919    case ABBREVIATED:
    920    default:
    921        srcArray = &fAmPms;
    922        srcCount = &fAmPmsCount;
    923        break;
    924    }
    925 
    926    count = *srcCount;
    927    return *srcArray;
    928 }
    929 
    930 const UnicodeString*
    931 DateFormatSymbols::getLeapMonthPatterns(int32_t &count) const
    932 {
    933    count = fLeapMonthPatternsCount;
    934    return fLeapMonthPatterns;
    935 }
    936 
    937 const UnicodeString*
    938 DateFormatSymbols::getYearNames(int32_t& count,
    939                                DtContextType /*ignored*/, DtWidthType /*ignored*/) const
    940 {
    941    count = fShortYearNamesCount;
    942    return fShortYearNames;
    943 }
    944 
    945 void
    946 DateFormatSymbols::setYearNames(const UnicodeString* yearNames, int32_t count,
    947                                DtContextType context, DtWidthType width)
    948 {
    949    if (context == FORMAT && width == ABBREVIATED) {
    950        delete[] fShortYearNames;
    951        fShortYearNames = newUnicodeStringArray(count);
    952        uprv_arrayCopy(yearNames, fShortYearNames, count);
    953        fShortYearNamesCount = count;
    954    }
    955 }
    956 
    957 const UnicodeString*
    958 DateFormatSymbols::getZodiacNames(int32_t& count,
    959                                DtContextType /*ignored*/, DtWidthType /*ignored*/) const
    960 {
    961    count = fShortZodiacNamesCount;
    962    return fShortZodiacNames;
    963 }
    964 
    965 void
    966 DateFormatSymbols::setZodiacNames(const UnicodeString* zodiacNames, int32_t count,
    967                                DtContextType context, DtWidthType width)
    968 {
    969    if (context == FORMAT && width == ABBREVIATED) {
    970        delete[] fShortZodiacNames;
    971        fShortZodiacNames = newUnicodeStringArray(count);
    972        uprv_arrayCopy(zodiacNames, fShortZodiacNames, count);
    973        fShortZodiacNamesCount = count;
    974    }
    975 }
    976 
    977 //------------------------------------------------------
    978 
    979 void
    980 DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count)
    981 {
    982    // delete the old list if we own it
    983    delete[] fEras;
    984 
    985    // we always own the new list, which we create here (we duplicate rather
    986    // than adopting the list passed in)
    987    fEras = newUnicodeStringArray(count);
    988    uprv_arrayCopy(erasArray,fEras,  count);
    989    fErasCount = count;
    990 }
    991 
    992 void
    993 DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count)
    994 {
    995    // delete the old list if we own it
    996    delete[] fEraNames;
    997 
    998    // we always own the new list, which we create here (we duplicate rather
    999    // than adopting the list passed in)
   1000    fEraNames = newUnicodeStringArray(count);
   1001    uprv_arrayCopy(eraNamesArray,fEraNames,  count);
   1002    fEraNamesCount = count;
   1003 }
   1004 
   1005 void
   1006 DateFormatSymbols::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count)
   1007 {
   1008    // delete the old list if we own it
   1009    delete[] fNarrowEras;
   1010 
   1011    // we always own the new list, which we create here (we duplicate rather
   1012    // than adopting the list passed in)
   1013    fNarrowEras = newUnicodeStringArray(count);
   1014    uprv_arrayCopy(narrowErasArray,fNarrowEras,  count);
   1015    fNarrowErasCount = count;
   1016 }
   1017 
   1018 void
   1019 DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count)
   1020 {
   1021    // delete the old list if we own it
   1022    delete[] fMonths;
   1023 
   1024    // we always own the new list, which we create here (we duplicate rather
   1025    // than adopting the list passed in)
   1026    fMonths = newUnicodeStringArray(count);
   1027    uprv_arrayCopy( monthsArray,fMonths,count);
   1028    fMonthsCount = count;
   1029 }
   1030 
   1031 void
   1032 DateFormatSymbols::setShortMonths(const UnicodeString* shortMonthsArray, int32_t count)
   1033 {
   1034    // delete the old list if we own it
   1035    delete[] fShortMonths;
   1036 
   1037    // we always own the new list, which we create here (we duplicate rather
   1038    // than adopting the list passed in)
   1039    fShortMonths = newUnicodeStringArray(count);
   1040    uprv_arrayCopy(shortMonthsArray,fShortMonths,  count);
   1041    fShortMonthsCount = count;
   1042 }
   1043 
   1044 void
   1045 DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, DtContextType context, DtWidthType width)
   1046 {
   1047    // delete the old list if we own it
   1048    // we always own the new list, which we create here (we duplicate rather
   1049    // than adopting the list passed in)
   1050 
   1051    switch (context) {
   1052    case FORMAT :
   1053        switch (width) {
   1054        case WIDE :
   1055            delete[] fMonths;
   1056            fMonths = newUnicodeStringArray(count);
   1057            uprv_arrayCopy( monthsArray,fMonths,count);
   1058            fMonthsCount = count;
   1059            break;
   1060        case ABBREVIATED :
   1061            delete[] fShortMonths;
   1062            fShortMonths = newUnicodeStringArray(count);
   1063            uprv_arrayCopy( monthsArray,fShortMonths,count);
   1064            fShortMonthsCount = count;
   1065            break;
   1066        case NARROW :
   1067            delete[] fNarrowMonths;
   1068            fNarrowMonths = newUnicodeStringArray(count);
   1069            uprv_arrayCopy( monthsArray,fNarrowMonths,count);
   1070            fNarrowMonthsCount = count;
   1071            break;
   1072        default :
   1073            break;
   1074        }
   1075        break;
   1076    case STANDALONE :
   1077        switch (width) {
   1078        case WIDE :
   1079            delete[] fStandaloneMonths;
   1080            fStandaloneMonths = newUnicodeStringArray(count);
   1081            uprv_arrayCopy( monthsArray,fStandaloneMonths,count);
   1082            fStandaloneMonthsCount = count;
   1083            break;
   1084        case ABBREVIATED :
   1085            delete[] fStandaloneShortMonths;
   1086            fStandaloneShortMonths = newUnicodeStringArray(count);
   1087            uprv_arrayCopy( monthsArray,fStandaloneShortMonths,count);
   1088            fStandaloneShortMonthsCount = count;
   1089            break;
   1090        case NARROW :
   1091            delete[] fStandaloneNarrowMonths;
   1092            fStandaloneNarrowMonths = newUnicodeStringArray(count);
   1093            uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count);
   1094            fStandaloneNarrowMonthsCount = count;
   1095            break;
   1096        default :
   1097            break;
   1098        }
   1099        break;
   1100    case DT_CONTEXT_COUNT :
   1101        break;
   1102    }
   1103 }
   1104 
   1105 void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count)
   1106 {
   1107    // delete the old list if we own it
   1108    delete[] fWeekdays;
   1109 
   1110    // we always own the new list, which we create here (we duplicate rather
   1111    // than adopting the list passed in)
   1112    fWeekdays = newUnicodeStringArray(count);
   1113    uprv_arrayCopy(weekdaysArray,fWeekdays,count);
   1114    fWeekdaysCount = count;
   1115 }
   1116 
   1117 void
   1118 DateFormatSymbols::setShortWeekdays(const UnicodeString* shortWeekdaysArray, int32_t count)
   1119 {
   1120    // delete the old list if we own it
   1121    delete[] fShortWeekdays;
   1122 
   1123    // we always own the new list, which we create here (we duplicate rather
   1124    // than adopting the list passed in)
   1125    fShortWeekdays = newUnicodeStringArray(count);
   1126    uprv_arrayCopy(shortWeekdaysArray, fShortWeekdays, count);
   1127    fShortWeekdaysCount = count;
   1128 }
   1129 
   1130 void
   1131 DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count, DtContextType context, DtWidthType width)
   1132 {
   1133    // delete the old list if we own it
   1134    // we always own the new list, which we create here (we duplicate rather
   1135    // than adopting the list passed in)
   1136 
   1137    switch (context) {
   1138    case FORMAT :
   1139        switch (width) {
   1140        case WIDE :
   1141            delete[] fWeekdays;
   1142            fWeekdays = newUnicodeStringArray(count);
   1143            uprv_arrayCopy(weekdaysArray, fWeekdays, count);
   1144            fWeekdaysCount = count;
   1145            break;
   1146        case ABBREVIATED :
   1147            delete[] fShortWeekdays;
   1148            fShortWeekdays = newUnicodeStringArray(count);
   1149            uprv_arrayCopy(weekdaysArray, fShortWeekdays, count);
   1150            fShortWeekdaysCount = count;
   1151            break;
   1152        case SHORT :
   1153            delete[] fShorterWeekdays;
   1154            fShorterWeekdays = newUnicodeStringArray(count);
   1155            uprv_arrayCopy(weekdaysArray, fShorterWeekdays, count);
   1156            fShorterWeekdaysCount = count;
   1157            break;
   1158        case NARROW :
   1159            delete[] fNarrowWeekdays;
   1160            fNarrowWeekdays = newUnicodeStringArray(count);
   1161            uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count);
   1162            fNarrowWeekdaysCount = count;
   1163            break;
   1164        case DT_WIDTH_COUNT :
   1165            break;
   1166        }
   1167        break;
   1168    case STANDALONE :
   1169        switch (width) {
   1170        case WIDE :
   1171            delete[] fStandaloneWeekdays;
   1172            fStandaloneWeekdays = newUnicodeStringArray(count);
   1173            uprv_arrayCopy(weekdaysArray, fStandaloneWeekdays, count);
   1174            fStandaloneWeekdaysCount = count;
   1175            break;
   1176        case ABBREVIATED :
   1177            delete[] fStandaloneShortWeekdays;
   1178            fStandaloneShortWeekdays = newUnicodeStringArray(count);
   1179            uprv_arrayCopy(weekdaysArray, fStandaloneShortWeekdays, count);
   1180            fStandaloneShortWeekdaysCount = count;
   1181            break;
   1182        case SHORT :
   1183            delete[] fStandaloneShorterWeekdays;
   1184            fStandaloneShorterWeekdays = newUnicodeStringArray(count);
   1185            uprv_arrayCopy(weekdaysArray, fStandaloneShorterWeekdays, count);
   1186            fStandaloneShorterWeekdaysCount = count;
   1187            break;
   1188        case NARROW :
   1189            delete[] fStandaloneNarrowWeekdays;
   1190            fStandaloneNarrowWeekdays = newUnicodeStringArray(count);
   1191            uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count);
   1192            fStandaloneNarrowWeekdaysCount = count;
   1193            break;
   1194        case DT_WIDTH_COUNT :
   1195            break;
   1196        }
   1197        break;
   1198    case DT_CONTEXT_COUNT :
   1199        break;
   1200    }
   1201 }
   1202 
   1203 void
   1204 DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count, DtContextType context, DtWidthType width)
   1205 {
   1206    // delete the old list if we own it
   1207    // we always own the new list, which we create here (we duplicate rather
   1208    // than adopting the list passed in)
   1209 
   1210    switch (context) {
   1211    case FORMAT :
   1212        switch (width) {
   1213        case WIDE :
   1214            delete[] fQuarters;
   1215            fQuarters = newUnicodeStringArray(count);
   1216            uprv_arrayCopy( quartersArray,fQuarters,count);
   1217            fQuartersCount = count;
   1218            break;
   1219        case ABBREVIATED :
   1220            delete[] fShortQuarters;
   1221            fShortQuarters = newUnicodeStringArray(count);
   1222            uprv_arrayCopy( quartersArray,fShortQuarters,count);
   1223            fShortQuartersCount = count;
   1224            break;
   1225        case NARROW :
   1226            delete[] fNarrowQuarters;
   1227            fNarrowQuarters = newUnicodeStringArray(count);
   1228            uprv_arrayCopy( quartersArray,fNarrowQuarters,count);
   1229            fNarrowQuartersCount = count;
   1230            break;
   1231        default :
   1232            break;
   1233        }
   1234        break;
   1235    case STANDALONE :
   1236        switch (width) {
   1237        case WIDE :
   1238            delete[] fStandaloneQuarters;
   1239            fStandaloneQuarters = newUnicodeStringArray(count);
   1240            uprv_arrayCopy( quartersArray,fStandaloneQuarters,count);
   1241            fStandaloneQuartersCount = count;
   1242            break;
   1243        case ABBREVIATED :
   1244            delete[] fStandaloneShortQuarters;
   1245            fStandaloneShortQuarters = newUnicodeStringArray(count);
   1246            uprv_arrayCopy( quartersArray,fStandaloneShortQuarters,count);
   1247            fStandaloneShortQuartersCount = count;
   1248            break;
   1249        case NARROW :
   1250            delete[] fStandaloneNarrowQuarters;
   1251            fStandaloneNarrowQuarters = newUnicodeStringArray(count);
   1252            uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count);
   1253            fStandaloneNarrowQuartersCount = count;
   1254            break;
   1255        default :
   1256            break;
   1257        }
   1258        break;
   1259    case DT_CONTEXT_COUNT :
   1260        break;
   1261    }
   1262 }
   1263 
   1264 void
   1265 DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count)
   1266 {
   1267    setAmPmStrings(amPmsArray, count, FORMAT, ABBREVIATED);
   1268 }
   1269 
   1270 void
   1271 DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count, DtContextType /*ignored*/, DtWidthType width)
   1272 {
   1273    UnicodeString** targetArray;
   1274    int32_t* targetCount;
   1275    switch (width) {
   1276    case WIDE:
   1277        targetArray = &fWideAmPms;
   1278        targetCount = &fWideAmPmsCount;
   1279        break;
   1280    case NARROW:
   1281        targetArray = &fNarrowAmPms;
   1282        targetCount = &fNarrowAmPmsCount;
   1283        break;
   1284    case ABBREVIATED:
   1285    default:
   1286        targetArray = &fAmPms;
   1287        targetCount = &fAmPmsCount;
   1288        break;
   1289    }
   1290 
   1291    // delete the old list if we own it
   1292    delete[] *targetArray;
   1293 
   1294    // we always own the new list, which we create here (we duplicate rather
   1295    // than adopting the list passed in)
   1296    *targetArray = newUnicodeStringArray(count);
   1297    uprv_arrayCopy(amPmsArray,*targetArray,count);
   1298    *targetCount = count;
   1299 }
   1300 
   1301 void
   1302 DateFormatSymbols::setTimeSeparatorString(const UnicodeString& newTimeSeparator)
   1303 {
   1304    fTimeSeparator = newTimeSeparator;
   1305 }
   1306 
   1307 const UnicodeString**
   1308 DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
   1309 {
   1310    const UnicodeString **result = nullptr;
   1311    static UMutex LOCK;
   1312 
   1313    umtx_lock(&LOCK);
   1314    if (fZoneStrings == nullptr) {
   1315        if (fLocaleZoneStrings == nullptr) {
   1316            const_cast<DateFormatSymbols*>(this)->initZoneStringsArray();
   1317        }
   1318        result = (const UnicodeString**)fLocaleZoneStrings;
   1319    } else {
   1320        result = (const UnicodeString**)fZoneStrings;
   1321    }
   1322    rowCount = fZoneStringsRowCount;
   1323    columnCount = fZoneStringsColCount;
   1324    umtx_unlock(&LOCK);
   1325 
   1326    return result;
   1327 }
   1328 
   1329 // For now, we include all zones
   1330 #define ZONE_SET UCAL_ZONE_TYPE_ANY
   1331 
   1332 // This code must be called within a synchronized block
   1333 void
   1334 DateFormatSymbols::initZoneStringsArray() {
   1335    if (fZoneStrings != nullptr || fLocaleZoneStrings != nullptr) {
   1336        return;
   1337    }
   1338 
   1339    UErrorCode status = U_ZERO_ERROR;
   1340 
   1341    StringEnumeration *tzids = nullptr;
   1342    UnicodeString ** zarray = nullptr;
   1343    TimeZoneNames *tzNames = nullptr;
   1344    int32_t rows = 0;
   1345 
   1346    static const UTimeZoneNameType TYPES[] = {
   1347        UTZNM_LONG_STANDARD, UTZNM_SHORT_STANDARD,
   1348        UTZNM_LONG_DAYLIGHT, UTZNM_SHORT_DAYLIGHT
   1349    };
   1350    static const int32_t NUM_TYPES = 4;
   1351 
   1352    do { // dummy do-while
   1353 
   1354        tzids = TimeZone::createTimeZoneIDEnumeration(ZONE_SET, nullptr, nullptr, status);
   1355        rows = tzids->count(status);
   1356        if (U_FAILURE(status)) {
   1357            break;
   1358        }
   1359 
   1360        // Allocate array
   1361        int32_t size = rows * sizeof(UnicodeString*);
   1362        zarray = static_cast<UnicodeString**>(uprv_malloc(size));
   1363        if (zarray == nullptr) {
   1364            status = U_MEMORY_ALLOCATION_ERROR;
   1365            break;
   1366        }
   1367        uprv_memset(zarray, 0, size);
   1368 
   1369        tzNames = TimeZoneNames::createInstance(fZSFLocale, status);
   1370        tzNames->loadAllDisplayNames(status);
   1371        if (U_FAILURE(status)) { break; }
   1372 
   1373        const UnicodeString *tzid;
   1374        int32_t i = 0;
   1375        UDate now = Calendar::getNow();
   1376        UnicodeString tzDispName;
   1377 
   1378        while ((tzid = tzids->snext(status)) != nullptr) {
   1379            if (U_FAILURE(status)) {
   1380                break;
   1381            }
   1382 
   1383            zarray[i] = new UnicodeString[5];
   1384            if (zarray[i] == nullptr) {
   1385                status = U_MEMORY_ALLOCATION_ERROR;
   1386                break;
   1387            }
   1388 
   1389            zarray[i][0].setTo(*tzid);
   1390            tzNames->getDisplayNames(*tzid, TYPES, NUM_TYPES, now, zarray[i]+1, status);
   1391            i++;
   1392        }
   1393 
   1394    } while (false);
   1395 
   1396    if (U_FAILURE(status)) {
   1397        if (zarray) {
   1398            for (int32_t i = 0; i < rows; i++) {
   1399                if (zarray[i]) {
   1400                    delete[] zarray[i];
   1401                }
   1402            }
   1403            uprv_free(zarray);
   1404            zarray = nullptr;
   1405        }
   1406    }
   1407 
   1408    delete tzNames;
   1409    delete tzids;
   1410 
   1411    fLocaleZoneStrings = zarray;
   1412    fZoneStringsRowCount = rows;
   1413    fZoneStringsColCount = 1 + NUM_TYPES;
   1414 }
   1415 
   1416 void
   1417 DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount)
   1418 {
   1419    // since deleting a 2-d array is a pain in the butt, we offload that task to
   1420    // a separate function
   1421    disposeZoneStrings();
   1422    // we always own the new list, which we create here (we duplicate rather
   1423    // than adopting the list passed in)
   1424    fZoneStringsRowCount = rowCount;
   1425    fZoneStringsColCount = columnCount;
   1426    createZoneStrings(const_cast<const UnicodeString**>(strings));
   1427 }
   1428 
   1429 //------------------------------------------------------
   1430 
   1431 const char16_t * U_EXPORT2
   1432 DateFormatSymbols::getPatternUChars()
   1433 {
   1434    return gPatternChars;
   1435 }
   1436 
   1437 UDateFormatField U_EXPORT2
   1438 DateFormatSymbols::getPatternCharIndex(char16_t c) {
   1439    if (c >= UPRV_LENGTHOF(gLookupPatternChars)) {
   1440        return UDAT_FIELD_COUNT;
   1441    }
   1442    const auto idx = gLookupPatternChars[c];
   1443    return idx == -1 ? UDAT_FIELD_COUNT : static_cast<UDateFormatField>(idx);
   1444 }
   1445 
   1446 static const uint64_t kNumericFieldsAlways =
   1447    (static_cast<uint64_t>(1) << UDAT_YEAR_FIELD) |                 // y
   1448    (static_cast<uint64_t>(1) << UDAT_DATE_FIELD) |                 // d
   1449    (static_cast<uint64_t>(1) << UDAT_HOUR_OF_DAY1_FIELD) |         // k
   1450    (static_cast<uint64_t>(1) << UDAT_HOUR_OF_DAY0_FIELD) |         // H
   1451    (static_cast<uint64_t>(1) << UDAT_MINUTE_FIELD) |               // m
   1452    (static_cast<uint64_t>(1) << UDAT_SECOND_FIELD) |               // s
   1453    (static_cast<uint64_t>(1) << UDAT_FRACTIONAL_SECOND_FIELD) |    // S
   1454    (static_cast<uint64_t>(1) << UDAT_DAY_OF_YEAR_FIELD) |          // D
   1455    (static_cast<uint64_t>(1) << UDAT_DAY_OF_WEEK_IN_MONTH_FIELD) | // F
   1456    (static_cast<uint64_t>(1) << UDAT_WEEK_OF_YEAR_FIELD) |         // w
   1457    (static_cast<uint64_t>(1) << UDAT_WEEK_OF_MONTH_FIELD) |        // W
   1458    (static_cast<uint64_t>(1) << UDAT_HOUR1_FIELD) |                // h
   1459    (static_cast<uint64_t>(1) << UDAT_HOUR0_FIELD) |                // K
   1460    (static_cast<uint64_t>(1) << UDAT_YEAR_WOY_FIELD) |             // Y
   1461    (static_cast<uint64_t>(1) << UDAT_EXTENDED_YEAR_FIELD) |        // u
   1462    (static_cast<uint64_t>(1) << UDAT_JULIAN_DAY_FIELD) |           // g
   1463    (static_cast<uint64_t>(1) << UDAT_MILLISECONDS_IN_DAY_FIELD) |  // A
   1464    (static_cast<uint64_t>(1) << UDAT_RELATED_YEAR_FIELD);          // r
   1465 
   1466 static const uint64_t kNumericFieldsForCount12 =
   1467    (static_cast<uint64_t>(1) << UDAT_MONTH_FIELD) |             // M or MM
   1468    (static_cast<uint64_t>(1) << UDAT_DOW_LOCAL_FIELD) |         // e or ee
   1469    (static_cast<uint64_t>(1) << UDAT_STANDALONE_DAY_FIELD) |    // c or cc
   1470    (static_cast<uint64_t>(1) << UDAT_STANDALONE_MONTH_FIELD) |  // L or LL
   1471    (static_cast<uint64_t>(1) << UDAT_QUARTER_FIELD) |           // Q or QQ
   1472    (static_cast<uint64_t>(1) << UDAT_STANDALONE_QUARTER_FIELD); // q or qq
   1473 
   1474 UBool U_EXPORT2
   1475 DateFormatSymbols::isNumericField(UDateFormatField f, int32_t count) {
   1476    if (f == UDAT_FIELD_COUNT) {
   1477        return false;
   1478    }
   1479    uint64_t flag = static_cast<uint64_t>(1) << f;
   1480    return ((kNumericFieldsAlways & flag) != 0 || ((kNumericFieldsForCount12 & flag) != 0 && count < 3));
   1481 }
   1482 
   1483 UBool U_EXPORT2
   1484 DateFormatSymbols::isNumericPatternChar(char16_t c, int32_t count) {
   1485    return isNumericField(getPatternCharIndex(c), count);
   1486 }
   1487 
   1488 //------------------------------------------------------
   1489 
   1490 UnicodeString&
   1491 DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const
   1492 {
   1493    // fastCopyFrom() - see assignArray comments
   1494    return result.fastCopyFrom(fLocalPatternChars);
   1495 }
   1496 
   1497 //------------------------------------------------------
   1498 
   1499 void
   1500 DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars)
   1501 {
   1502    fLocalPatternChars = newLocalPatternChars;
   1503 }
   1504 
   1505 //------------------------------------------------------
   1506 
   1507 namespace {
   1508 
   1509 // Constants declarations
   1510 const char16_t kCalendarAliasPrefixUChar[] = {
   1511    SOLIDUS, CAP_L, CAP_O, CAP_C, CAP_A, CAP_L, CAP_E, SOLIDUS,
   1512    LOW_C, LOW_A, LOW_L, LOW_E, LOW_N, LOW_D, LOW_A, LOW_R, SOLIDUS
   1513 };
   1514 const char16_t kGregorianTagUChar[] = {
   1515    LOW_G, LOW_R, LOW_E, LOW_G, LOW_O, LOW_R, LOW_I, LOW_A, LOW_N
   1516 };
   1517 const char16_t kVariantTagUChar[] = {
   1518    PERCENT, LOW_V, LOW_A, LOW_R, LOW_I, LOW_A, LOW_N, LOW_T
   1519 };
   1520 const char16_t kLeapTagUChar[] = {
   1521    LOW_L, LOW_E, LOW_A, LOW_P
   1522 };
   1523 const char16_t kCyclicNameSetsTagUChar[] = {
   1524    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
   1525 };
   1526 const char16_t kYearsTagUChar[] = {
   1527    SOLIDUS, LOW_Y, LOW_E, LOW_A, LOW_R, LOW_S
   1528 };
   1529 const char16_t kZodiacsUChar[] = {
   1530    SOLIDUS, LOW_Z, LOW_O, LOW_D, LOW_I, LOW_A, LOW_C, LOW_S
   1531 };
   1532 const char16_t kDayPartsTagUChar[] = {
   1533    SOLIDUS, LOW_D, LOW_A, LOW_Y, CAP_P, LOW_A, LOW_R, LOW_T, LOW_S
   1534 };
   1535 const char16_t kFormatTagUChar[] = {
   1536    SOLIDUS, LOW_F, LOW_O, LOW_R, LOW_M, LOW_A, LOW_T
   1537 };
   1538 const char16_t kAbbrTagUChar[] = {
   1539    SOLIDUS, LOW_A, LOW_B, LOW_B, LOW_R, LOW_E, LOW_V, LOW_I, LOW_A, LOW_T, LOW_E, LOW_D
   1540 };
   1541 
   1542 // ResourceSink to enumerate all calendar resources
   1543 struct CalendarDataSink : public ResourceSink {
   1544 
   1545    // Enum which specifies the type of alias received, or no alias
   1546    enum AliasType {
   1547        SAME_CALENDAR,
   1548        DIFFERENT_CALENDAR,
   1549        GREGORIAN,
   1550        NONE
   1551    };
   1552 
   1553    // Data structures to store resources from the current resource bundle
   1554    Hashtable arrays;
   1555    Hashtable arraySizes;
   1556    Hashtable maps;
   1557    /** 
   1558     * Whenever there are aliases, the same object will be added twice to 'map'.
   1559     * To avoid double deletion, 'maps' won't take ownership of the objects. Instead,
   1560     * 'mapRefs' will own them and will delete them when CalendarDataSink is deleted.
   1561     */
   1562    MemoryPool<Hashtable> mapRefs;
   1563 
   1564    // Paths and the aliases they point to
   1565    UVector aliasPathPairs;
   1566 
   1567    // Current and next calendar resource table which should be loaded
   1568    UnicodeString currentCalendarType;
   1569    UnicodeString nextCalendarType;
   1570 
   1571    // Resources to visit when enumerating fallback calendars
   1572    LocalPointer<UVector> resourcesToVisit;
   1573 
   1574    // Alias' relative path populated whenever an alias is read
   1575    UnicodeString aliasRelativePath;
   1576 
   1577    // Initializes CalendarDataSink with default values
   1578    CalendarDataSink(UErrorCode& status)
   1579    :   arrays(false, status), arraySizes(false, status), maps(false, status),
   1580        mapRefs(),
   1581        aliasPathPairs(uprv_deleteUObject, uhash_compareUnicodeString, status),
   1582        currentCalendarType(), nextCalendarType(),
   1583        resourcesToVisit(nullptr), aliasRelativePath() {
   1584        if (U_FAILURE(status)) { return; }
   1585    }
   1586    virtual ~CalendarDataSink();
   1587 
   1588    // Configure the CalendarSink to visit all the resources
   1589    void visitAllResources() {
   1590        resourcesToVisit.adoptInstead(nullptr);
   1591    }
   1592 
   1593    // Actions to be done before enumerating
   1594    void preEnumerate(const UnicodeString &calendarType) {
   1595        currentCalendarType = calendarType;
   1596        nextCalendarType.setToBogus();
   1597        aliasPathPairs.removeAllElements();
   1598    }
   1599 
   1600    virtual void put(const char *key, ResourceValue &value, UBool, UErrorCode &errorCode) override {
   1601        if (U_FAILURE(errorCode)) { return; }
   1602        U_ASSERT(!currentCalendarType.isEmpty());
   1603 
   1604        // Stores the resources to visit on the next calendar.
   1605        LocalPointer<UVector> resourcesToVisitNext(nullptr);
   1606        ResourceTable calendarData = value.getTable(errorCode);
   1607        if (U_FAILURE(errorCode)) { return; }
   1608 
   1609        // Enumerate all resources for this calendar
   1610        for (int i = 0; calendarData.getKeyAndValue(i, key, value); i++) {
   1611            UnicodeString keyUString(key, -1, US_INV);
   1612 
   1613            // == Handle aliases ==
   1614            AliasType aliasType = processAliasFromValue(keyUString, value, errorCode);
   1615            if (U_FAILURE(errorCode)) { return; }
   1616            if (aliasType == GREGORIAN) {
   1617                // Ignore aliases to the gregorian calendar, all of its resources will be loaded anyway.
   1618                continue;
   1619 
   1620            } else if (aliasType == DIFFERENT_CALENDAR) {
   1621                // Whenever an alias to the next calendar (except gregorian) is encountered, register the
   1622                // calendar type it's pointing to
   1623                if (resourcesToVisitNext.isNull()) {
   1624                    resourcesToVisitNext
   1625                        .adoptInsteadAndCheckErrorCode(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, errorCode),
   1626                                                       errorCode);
   1627                    if (U_FAILURE(errorCode)) { return; }
   1628                }
   1629                LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
   1630                resourcesToVisitNext->adoptElement(aliasRelativePathCopy.orphan(), errorCode);
   1631                if (U_FAILURE(errorCode)) { return; }
   1632                continue;
   1633 
   1634            } else if (aliasType == SAME_CALENDAR) {
   1635                // Register same-calendar alias
   1636                if (arrays.get(aliasRelativePath) == nullptr && maps.get(aliasRelativePath) == nullptr) {
   1637                    LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
   1638                    aliasPathPairs.adoptElement(aliasRelativePathCopy.orphan(), errorCode);
   1639                    if (U_FAILURE(errorCode)) { return; }
   1640                    LocalPointer<UnicodeString> keyUStringCopy(keyUString.clone(), errorCode);
   1641                    aliasPathPairs.adoptElement(keyUStringCopy.orphan(), errorCode);
   1642                    if (U_FAILURE(errorCode)) { return; }
   1643                }
   1644                continue;
   1645            }
   1646 
   1647            // Only visit the resources that were referenced by an alias on the previous calendar
   1648            // (AmPmMarkersAbbr is an exception).
   1649            if (!resourcesToVisit.isNull() && !resourcesToVisit->isEmpty() && !resourcesToVisit->contains(&keyUString)
   1650                && uprv_strcmp(key, gAmPmMarkersAbbrTag) != 0) { continue; }
   1651 
   1652            // == Handle data ==
   1653            if (uprv_strcmp(key, gAmPmMarkersTag) == 0
   1654                || uprv_strcmp(key, gAmPmMarkersAbbrTag) == 0
   1655                || uprv_strcmp(key, gAmPmMarkersNarrowTag) == 0) {
   1656                if (arrays.get(keyUString) == nullptr) {
   1657                    ResourceArray resourceArray = value.getArray(errorCode);
   1658                    int32_t arraySize = resourceArray.getSize();
   1659                    LocalArray<UnicodeString> stringArray(new UnicodeString[arraySize], errorCode);
   1660                    value.getStringArray(stringArray.getAlias(), arraySize, errorCode);
   1661                    arrays.put(keyUString, stringArray.orphan(), errorCode);
   1662                    arraySizes.puti(keyUString, arraySize, errorCode);
   1663                    if (U_FAILURE(errorCode)) { return; }
   1664                }
   1665            } else if (uprv_strcmp(key, gErasTag) == 0
   1666                       || uprv_strcmp(key, gDayNamesTag) == 0
   1667                       || uprv_strcmp(key, gMonthNamesTag) == 0
   1668                       || uprv_strcmp(key, gQuartersTag) == 0
   1669                       || uprv_strcmp(key, gDayPeriodTag) == 0
   1670                       || uprv_strcmp(key, gMonthPatternsTag) == 0
   1671                       || uprv_strcmp(key, gCyclicNameSetsTag) == 0) {
   1672                processResource(keyUString, key, value, errorCode);
   1673            }
   1674        }
   1675 
   1676        // Apply same-calendar aliases
   1677        UBool modified;
   1678        do {
   1679            modified = false;
   1680            for (int32_t i = 0; i < aliasPathPairs.size();) {
   1681                UBool mod = false;
   1682                UnicodeString* alias = static_cast<UnicodeString*>(aliasPathPairs[i]);
   1683                UnicodeString *aliasArray;
   1684                Hashtable *aliasMap;
   1685                if ((aliasArray = static_cast<UnicodeString*>(arrays.get(*alias))) != nullptr) {
   1686                    UnicodeString* path = static_cast<UnicodeString*>(aliasPathPairs[i + 1]);
   1687                    if (arrays.get(*path) == nullptr) {
   1688                        // Clone the array
   1689                        int32_t aliasArraySize = arraySizes.geti(*alias);
   1690                        LocalArray<UnicodeString> aliasArrayCopy(new UnicodeString[aliasArraySize], errorCode);
   1691                        if (U_FAILURE(errorCode)) { return; }
   1692                        uprv_arrayCopy(aliasArray, aliasArrayCopy.getAlias(), aliasArraySize);
   1693                        // Put the array on the 'arrays' map
   1694                        arrays.put(*path, aliasArrayCopy.orphan(), errorCode);
   1695                        arraySizes.puti(*path, aliasArraySize, errorCode);
   1696                    }
   1697                    if (U_FAILURE(errorCode)) { return; }
   1698                    mod = true;
   1699                } else if ((aliasMap = static_cast<Hashtable*>(maps.get(*alias))) != nullptr) {
   1700                    UnicodeString* path = static_cast<UnicodeString*>(aliasPathPairs[i + 1]);
   1701                    if (maps.get(*path) == nullptr) {
   1702                        maps.put(*path, aliasMap, errorCode);
   1703                    }
   1704                    if (U_FAILURE(errorCode)) { return; }
   1705                    mod = true;
   1706                }
   1707                if (mod) {
   1708                    aliasPathPairs.removeElementAt(i + 1);
   1709                    aliasPathPairs.removeElementAt(i);
   1710                    modified = true;
   1711                } else {
   1712                    i += 2;
   1713                }
   1714            }
   1715        } while (modified && !aliasPathPairs.isEmpty());
   1716 
   1717        // Set the resources to visit on the next calendar
   1718        if (!resourcesToVisitNext.isNull()) {
   1719            resourcesToVisit = std::move(resourcesToVisitNext);
   1720        }
   1721    }
   1722 
   1723    // Process the nested resource bundle tables
   1724    void processResource(UnicodeString &path, const char *key, ResourceValue &value, UErrorCode &errorCode) {
   1725        if (U_FAILURE(errorCode)) return;
   1726 
   1727        ResourceTable table = value.getTable(errorCode);
   1728        if (U_FAILURE(errorCode)) return;
   1729        Hashtable* stringMap = nullptr;
   1730 
   1731        // Iterate over all the elements of the table and add them to the map
   1732        for (int i = 0; table.getKeyAndValue(i, key, value); i++) {
   1733            UnicodeString keyUString(key, -1, US_INV);
   1734 
   1735            // Ignore '%variant' keys
   1736            if (keyUString.endsWith(kVariantTagUChar, UPRV_LENGTHOF(kVariantTagUChar))) {
   1737                continue;
   1738            }
   1739 
   1740            // == Handle String elements ==
   1741            if (value.getType() == URES_STRING) {
   1742                // We are on a leaf, store the map elements into the stringMap
   1743                if (i == 0) {
   1744                    // mapRefs will keep ownership of 'stringMap':
   1745                    stringMap = mapRefs.create(false, errorCode);
   1746                    if (stringMap == nullptr) {
   1747                        errorCode = U_MEMORY_ALLOCATION_ERROR;
   1748                        return;
   1749                    }
   1750                    maps.put(path, stringMap, errorCode);
   1751                    if (U_FAILURE(errorCode)) { return; }
   1752                    stringMap->setValueDeleter(uprv_deleteUObject);
   1753                }
   1754                U_ASSERT(stringMap != nullptr);
   1755                int32_t valueStringSize;
   1756                const char16_t *valueString = value.getString(valueStringSize, errorCode);
   1757                if (U_FAILURE(errorCode)) { return; }
   1758                LocalPointer<UnicodeString> valueUString(new UnicodeString(true, valueString, valueStringSize), errorCode);
   1759                stringMap->put(keyUString, valueUString.orphan(), errorCode);
   1760                if (U_FAILURE(errorCode)) { return; }
   1761                continue;
   1762            }
   1763            U_ASSERT(stringMap == nullptr);
   1764 
   1765            // Store the current path's length and append the current key to the path.
   1766            int32_t pathLength = path.length();
   1767            path.append(SOLIDUS).append(keyUString);
   1768 
   1769            // In cyclicNameSets ignore everything but years/format/abbreviated
   1770            // and zodiacs/format/abbreviated
   1771            if (path.startsWith(kCyclicNameSetsTagUChar, UPRV_LENGTHOF(kCyclicNameSetsTagUChar))) {
   1772                UBool skip = true;
   1773                int32_t startIndex = UPRV_LENGTHOF(kCyclicNameSetsTagUChar);
   1774                int32_t length = 0;
   1775                if (startIndex == path.length()
   1776                    || path.compare(startIndex, (length = UPRV_LENGTHOF(kZodiacsUChar)), kZodiacsUChar, 0, UPRV_LENGTHOF(kZodiacsUChar)) == 0
   1777                    || path.compare(startIndex, (length = UPRV_LENGTHOF(kYearsTagUChar)), kYearsTagUChar, 0, UPRV_LENGTHOF(kYearsTagUChar)) == 0
   1778                    || path.compare(startIndex, (length = UPRV_LENGTHOF(kDayPartsTagUChar)), kDayPartsTagUChar, 0, UPRV_LENGTHOF(kDayPartsTagUChar)) == 0) {
   1779                    startIndex += length;
   1780                    length = 0;
   1781                    if (startIndex == path.length()
   1782                        || path.compare(startIndex, (length = UPRV_LENGTHOF(kFormatTagUChar)), kFormatTagUChar, 0, UPRV_LENGTHOF(kFormatTagUChar)) == 0) {
   1783                        startIndex += length;
   1784                        length = 0;
   1785                        if (startIndex == path.length()
   1786                            || path.compare(startIndex, (length = UPRV_LENGTHOF(kAbbrTagUChar)), kAbbrTagUChar, 0, UPRV_LENGTHOF(kAbbrTagUChar)) == 0) {
   1787                            skip = false;
   1788                        }
   1789                    }
   1790                }
   1791                if (skip) {
   1792                    // Drop the latest key on the path and continue
   1793                    path.retainBetween(0, pathLength);
   1794                    continue;
   1795                }
   1796            }
   1797 
   1798            // == Handle aliases ==
   1799            if (arrays.get(path) != nullptr || maps.get(path) != nullptr) {
   1800                // Drop the latest key on the path and continue
   1801                path.retainBetween(0, pathLength);
   1802                continue;
   1803            }
   1804 
   1805            AliasType aliasType = processAliasFromValue(path, value, errorCode);
   1806            if (U_FAILURE(errorCode)) { return; }
   1807            if (aliasType == SAME_CALENDAR) {
   1808                // Store the alias path and the current path on aliasPathPairs
   1809                LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
   1810                aliasPathPairs.adoptElement(aliasRelativePathCopy.orphan(), errorCode);
   1811                if (U_FAILURE(errorCode)) { return; }
   1812                LocalPointer<UnicodeString> pathCopy(path.clone(), errorCode);
   1813                aliasPathPairs.adoptElement(pathCopy.orphan(), errorCode);
   1814                if (U_FAILURE(errorCode)) { return; }
   1815 
   1816                // Drop the latest key on the path and continue
   1817                path.retainBetween(0, pathLength);
   1818                continue;
   1819            }
   1820            U_ASSERT(aliasType == NONE);
   1821 
   1822            // == Handle data ==
   1823            if (value.getType() == URES_ARRAY) {
   1824                // We are on a leaf, store the array
   1825                ResourceArray rDataArray = value.getArray(errorCode);
   1826                int32_t dataArraySize = rDataArray.getSize();
   1827                LocalArray<UnicodeString> dataArray(new UnicodeString[dataArraySize], errorCode);
   1828                value.getStringArray(dataArray.getAlias(), dataArraySize, errorCode);
   1829                arrays.put(path, dataArray.orphan(), errorCode);
   1830                arraySizes.puti(path, dataArraySize, errorCode);
   1831                if (U_FAILURE(errorCode)) { return; }
   1832            } else if (value.getType() == URES_TABLE) {
   1833                // We are not on a leaf, recursively process the subtable.
   1834                processResource(path, key, value, errorCode);
   1835                if (U_FAILURE(errorCode)) { return; }
   1836            }
   1837 
   1838            // Drop the latest key on the path
   1839            path.retainBetween(0, pathLength);
   1840        }
   1841    }
   1842 
   1843    // Populates an AliasIdentifier with the alias information contained on the UResource.Value.
   1844    AliasType processAliasFromValue(UnicodeString &currentRelativePath, ResourceValue &value,
   1845                                    UErrorCode &errorCode) {
   1846        if (U_FAILURE(errorCode)) { return NONE; }
   1847 
   1848        if (value.getType() == URES_ALIAS) {
   1849            int32_t aliasPathSize;
   1850            const char16_t* aliasPathUChar = value.getAliasString(aliasPathSize, errorCode);
   1851            if (U_FAILURE(errorCode)) { return NONE; }
   1852            UnicodeString aliasPath(aliasPathUChar, aliasPathSize);
   1853            const int32_t aliasPrefixLength = UPRV_LENGTHOF(kCalendarAliasPrefixUChar);
   1854            if (aliasPath.startsWith(kCalendarAliasPrefixUChar, aliasPrefixLength)
   1855                && aliasPath.length() > aliasPrefixLength) {
   1856                int32_t typeLimit = aliasPath.indexOf(SOLIDUS, aliasPrefixLength);
   1857                if (typeLimit > aliasPrefixLength) {
   1858                    const UnicodeString aliasCalendarType =
   1859                        aliasPath.tempSubStringBetween(aliasPrefixLength, typeLimit);
   1860                    aliasRelativePath.setTo(aliasPath, typeLimit + 1, aliasPath.length());
   1861 
   1862                    if (currentCalendarType == aliasCalendarType
   1863                        && currentRelativePath != aliasRelativePath) {
   1864                        // If we have an alias to the same calendar, the path to the resource must be different
   1865                        return SAME_CALENDAR;
   1866 
   1867                    } else if (currentCalendarType != aliasCalendarType
   1868                               && currentRelativePath == aliasRelativePath) {
   1869                        // If we have an alias to a different calendar, the path to the resource must be the same
   1870                        if (aliasCalendarType.compare(kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)) == 0) {
   1871                            return GREGORIAN;
   1872                        } else if (nextCalendarType.isBogus()) {
   1873                            nextCalendarType = aliasCalendarType;
   1874                            return DIFFERENT_CALENDAR;
   1875                        } else if (nextCalendarType == aliasCalendarType) {
   1876                            return DIFFERENT_CALENDAR;
   1877                        }
   1878                    }
   1879                }
   1880            }
   1881            errorCode = U_INTERNAL_PROGRAM_ERROR;
   1882            return NONE;
   1883        }
   1884        return NONE;
   1885    }
   1886 
   1887    // Deleter function to be used by 'arrays'
   1888    static void U_CALLCONV deleteUnicodeStringArray(void *uArray) {
   1889        delete[] static_cast<UnicodeString *>(uArray);
   1890    }
   1891 };
   1892 // Virtual destructors have to be defined out of line
   1893 CalendarDataSink::~CalendarDataSink() {
   1894    arrays.setValueDeleter(deleteUnicodeStringArray);
   1895 }
   1896 }
   1897 
   1898 //------------------------------------------------------
   1899 
   1900 static void
   1901 initField(UnicodeString **field, int32_t& length, const char16_t *data, LastResortSize numStr, LastResortSize strLen, UErrorCode &status) {
   1902    if (U_SUCCESS(status)) {
   1903        length = numStr;
   1904        *field = newUnicodeStringArray(static_cast<size_t>(numStr));
   1905        if (*field) {
   1906            for(int32_t i = 0; i<length; i++) {
   1907                // readonly aliases - all "data" strings are constant
   1908                // -1 as length for variable-length strings (gLastResortDayNames[0] is empty)
   1909                (*(field) + i)->setTo(true, data + (i * (static_cast<int32_t>(strLen))), -1);
   1910            }
   1911        }
   1912        else {
   1913            length = 0;
   1914            status = U_MEMORY_ALLOCATION_ERROR;
   1915        }
   1916    }
   1917 }
   1918 
   1919 static void
   1920 initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, UErrorCode &status) {
   1921    if (U_SUCCESS(status)) {
   1922        UnicodeString keyUString(key.data(), -1, US_INV);
   1923        UnicodeString* array = static_cast<UnicodeString*>(sink.arrays.get(keyUString));
   1924 
   1925        if (array != nullptr) {
   1926            length = sink.arraySizes.geti(keyUString);
   1927            *field = array;
   1928            // DateFormatSymbols takes ownership of the array:
   1929            sink.arrays.remove(keyUString);
   1930        } else {
   1931            length = 0;
   1932            status = U_MISSING_RESOURCE_ERROR;
   1933        }
   1934    }
   1935 }
   1936 
   1937 static void
   1938 initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, int32_t arrayOffset, UErrorCode &status) {
   1939    if (U_SUCCESS(status)) {
   1940        UnicodeString keyUString(key.data(), -1, US_INV);
   1941        UnicodeString* array = static_cast<UnicodeString*>(sink.arrays.get(keyUString));
   1942 
   1943        if (array != nullptr) {
   1944            int32_t arrayLength = sink.arraySizes.geti(keyUString);
   1945            length = arrayLength + arrayOffset;
   1946            *field = new UnicodeString[length];
   1947            if (*field == nullptr) {
   1948                status = U_MEMORY_ALLOCATION_ERROR;
   1949                return;
   1950            }
   1951            uprv_arrayCopy(array, 0, *field, arrayOffset, arrayLength);
   1952        } else {
   1953            length = 0;
   1954            status = U_MISSING_RESOURCE_ERROR;
   1955        }
   1956    }
   1957 }
   1958 
   1959 static void
   1960 initEras(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, const UResourceBundle *ctebPtr, const char* eraWidth, int32_t maxEra, UErrorCode &status) {
   1961    if (U_SUCCESS(status)) {
   1962        length = 0;
   1963        UnicodeString keyUString(key.data(), -1, US_INV);
   1964        Hashtable *eraNamesTable = static_cast<Hashtable*>(sink.maps.get(keyUString));
   1965 
   1966        if (eraNamesTable != nullptr) {
   1967            UErrorCode resStatus = U_ZERO_ERROR;
   1968            LocalUResourceBundlePointer ctewb(ures_getByKeyWithFallback(ctebPtr, eraWidth, nullptr, &resStatus));
   1969            const UResourceBundle *ctewbPtr = (U_SUCCESS(resStatus))? ctewb.getAlias() : nullptr;
   1970            *field = new UnicodeString[maxEra + 1];
   1971            if (*field == nullptr) {
   1972                status = U_MEMORY_ALLOCATION_ERROR;
   1973                return;
   1974            }
   1975            length = maxEra + 1;
   1976            for (int32_t eraCode = 0; eraCode <= maxEra; eraCode++) {
   1977                char eraCodeStr[12]; // T_CString_integerToString is documented to generate at most 12 bytes including nul terminator
   1978                int32_t eraCodeStrLen = T_CString_integerToString(eraCodeStr, eraCode, 10);
   1979                UnicodeString eraCodeKey = UnicodeString(eraCodeStr, eraCodeStrLen, US_INV);
   1980                UnicodeString *eraName = static_cast<UnicodeString*>(eraNamesTable->get(eraCodeKey));
   1981                (*field)[eraCode].remove();
   1982                if (eraName != nullptr) {
   1983                    // Get eraName from map (created by CalendarSink)
   1984                    (*field)[eraCode].fastCopyFrom(*eraName);
   1985                } else if (ctewbPtr != nullptr) {
   1986                    // Try filling in missing items from parent locale(s)
   1987                    resStatus = U_ZERO_ERROR;
   1988                    LocalUResourceBundlePointer ctewkb(ures_getByKeyWithFallback(ctewbPtr, eraCodeStr, nullptr, &resStatus));
   1989                    if (U_SUCCESS(resStatus)) {
   1990                        int32_t eraNameLen;
   1991                        const UChar* eraNamePtr = ures_getString(ctewkb.getAlias(), &eraNameLen, &resStatus);
   1992                        if (U_SUCCESS(resStatus)) {
   1993                            (*field)[eraCode].setTo(false, eraNamePtr, eraNameLen);
   1994                        }
   1995                    }
   1996                }
   1997            }
   1998            return;
   1999        }
   2000        status = U_MISSING_RESOURCE_ERROR;
   2001    }
   2002 }
   2003 
   2004 static void
   2005 initLeapMonthPattern(UnicodeString *field, int32_t index, CalendarDataSink &sink, CharString &path, UErrorCode &status) {
   2006    field[index].remove();
   2007    if (U_SUCCESS(status)) {
   2008        UnicodeString pathUString(path.data(), -1, US_INV);
   2009        Hashtable *leapMonthTable = static_cast<Hashtable*>(sink.maps.get(pathUString));
   2010        if (leapMonthTable != nullptr) {
   2011            UnicodeString leapLabel(false, kLeapTagUChar, UPRV_LENGTHOF(kLeapTagUChar));
   2012            UnicodeString *leapMonthPattern = static_cast<UnicodeString*>(leapMonthTable->get(leapLabel));
   2013            if (leapMonthPattern != nullptr) {
   2014                field[index].fastCopyFrom(*leapMonthPattern);
   2015            } else {
   2016                field[index].setToBogus();
   2017            }
   2018            return;
   2019        }
   2020        status = U_MISSING_RESOURCE_ERROR;
   2021    }
   2022 }
   2023 
   2024 static CharString
   2025 &buildResourcePath(CharString &path, const char* segment1, UErrorCode &errorCode) {
   2026    return path.clear().append(segment1, -1, errorCode);
   2027 }
   2028 
   2029 static CharString
   2030 &buildResourcePath(CharString &path, const char* segment1, const char* segment2,
   2031                   UErrorCode &errorCode) {
   2032    return buildResourcePath(path, segment1, errorCode).append('/', errorCode)
   2033                                                       .append(segment2, -1, errorCode);
   2034 }
   2035 
   2036 static CharString
   2037 &buildResourcePath(CharString &path, const char* segment1, const char* segment2,
   2038                   const char* segment3, UErrorCode &errorCode) {
   2039    return buildResourcePath(path, segment1, segment2, errorCode).append('/', errorCode)
   2040                                                                 .append(segment3, -1, errorCode);
   2041 }
   2042 
   2043 static CharString
   2044 &buildResourcePath(CharString &path, const char* segment1, const char* segment2,
   2045                   const char* segment3, const char* segment4, UErrorCode &errorCode) {
   2046    return buildResourcePath(path, segment1, segment2, segment3, errorCode).append('/', errorCode)
   2047                                                                           .append(segment4, -1, errorCode);
   2048 }
   2049 
   2050 typedef struct {
   2051    const char * usageTypeName;
   2052    DateFormatSymbols::ECapitalizationContextUsageType usageTypeEnumValue;
   2053 } ContextUsageTypeNameToEnumValue;
   2054 
   2055 static const ContextUsageTypeNameToEnumValue contextUsageTypeMap[] = {
   2056   // Entries must be sorted by usageTypeName; entry with nullptr name terminates list.
   2057    { "day-format-except-narrow", DateFormatSymbols::kCapContextUsageDayFormat },
   2058    { "day-narrow",     DateFormatSymbols::kCapContextUsageDayNarrow },
   2059    { "day-standalone-except-narrow", DateFormatSymbols::kCapContextUsageDayStandalone },
   2060    { "era-abbr",       DateFormatSymbols::kCapContextUsageEraAbbrev },
   2061    { "era-name",       DateFormatSymbols::kCapContextUsageEraWide },
   2062    { "era-narrow",     DateFormatSymbols::kCapContextUsageEraNarrow },
   2063    { "metazone-long",  DateFormatSymbols::kCapContextUsageMetazoneLong },
   2064    { "metazone-short", DateFormatSymbols::kCapContextUsageMetazoneShort },
   2065    { "month-format-except-narrow", DateFormatSymbols::kCapContextUsageMonthFormat },
   2066    { "month-narrow",   DateFormatSymbols::kCapContextUsageMonthNarrow },
   2067    { "month-standalone-except-narrow", DateFormatSymbols::kCapContextUsageMonthStandalone },
   2068    { "zone-long",      DateFormatSymbols::kCapContextUsageZoneLong },
   2069    { "zone-short",     DateFormatSymbols::kCapContextUsageZoneShort },
   2070    { nullptr, static_cast<DateFormatSymbols::ECapitalizationContextUsageType>(0) },
   2071 };
   2072 
   2073 // Resource keys to look up localized strings for day periods.
   2074 // The first one must be midnight and the second must be noon, so that their indices coincide
   2075 // with the am/pm field. Formatting and parsing code for day periods relies on this coincidence.
   2076 static const char *dayPeriodKeys[] = {"midnight", "noon",
   2077                         "morning1", "afternoon1", "evening1", "night1",
   2078                         "morning2", "afternoon2", "evening2", "night2"};
   2079 
   2080 UnicodeString* loadDayPeriodStrings(CalendarDataSink &sink, CharString &path,
   2081                                    int32_t &stringCount,  UErrorCode &status) {
   2082    if (U_FAILURE(status)) { return nullptr; }
   2083 
   2084    UnicodeString pathUString(path.data(), -1, US_INV);
   2085    Hashtable* map = static_cast<Hashtable*>(sink.maps.get(pathUString));
   2086 
   2087    stringCount = UPRV_LENGTHOF(dayPeriodKeys);
   2088    UnicodeString *strings = new UnicodeString[stringCount];
   2089    if (strings == nullptr) {
   2090        status = U_MEMORY_ALLOCATION_ERROR;
   2091        return nullptr;
   2092    }
   2093 
   2094    if (map != nullptr) {
   2095        for (int32_t i = 0; i < stringCount; ++i) {
   2096            UnicodeString dayPeriodKey(dayPeriodKeys[i], -1, US_INV);
   2097            UnicodeString *dayPeriod = static_cast<UnicodeString*>(map->get(dayPeriodKey));
   2098            if (dayPeriod != nullptr) {
   2099                strings[i].fastCopyFrom(*dayPeriod);
   2100            } else {
   2101                strings[i].setToBogus();
   2102            }
   2103        }
   2104    } else {
   2105        for (int32_t i = 0; i < stringCount; i++) {
   2106            strings[i].setToBogus();
   2107        }
   2108    }
   2109    return strings;
   2110 }
   2111 
   2112 
   2113 void
   2114 DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData)
   2115 {
   2116    int32_t len = 0;
   2117    /* In case something goes wrong, initialize all of the data to nullptr. */
   2118    fEras = nullptr;
   2119    fErasCount = 0;
   2120    fEraNames = nullptr;
   2121    fEraNamesCount = 0;
   2122    fNarrowEras = nullptr;
   2123    fNarrowErasCount = 0;
   2124    fMonths = nullptr;
   2125    fMonthsCount=0;
   2126    fShortMonths = nullptr;
   2127    fShortMonthsCount=0;
   2128    fNarrowMonths = nullptr;
   2129    fNarrowMonthsCount=0;
   2130    fStandaloneMonths = nullptr;
   2131    fStandaloneMonthsCount=0;
   2132    fStandaloneShortMonths = nullptr;
   2133    fStandaloneShortMonthsCount=0;
   2134    fStandaloneNarrowMonths = nullptr;
   2135    fStandaloneNarrowMonthsCount=0;
   2136    fWeekdays = nullptr;
   2137    fWeekdaysCount=0;
   2138    fShortWeekdays = nullptr;
   2139    fShortWeekdaysCount=0;
   2140    fShorterWeekdays = nullptr;
   2141    fShorterWeekdaysCount=0;
   2142    fNarrowWeekdays = nullptr;
   2143    fNarrowWeekdaysCount=0;
   2144    fStandaloneWeekdays = nullptr;
   2145    fStandaloneWeekdaysCount=0;
   2146    fStandaloneShortWeekdays = nullptr;
   2147    fStandaloneShortWeekdaysCount=0;
   2148    fStandaloneShorterWeekdays = nullptr;
   2149    fStandaloneShorterWeekdaysCount=0;
   2150    fStandaloneNarrowWeekdays = nullptr;
   2151    fStandaloneNarrowWeekdaysCount=0;
   2152    fAmPms = nullptr;
   2153    fAmPmsCount=0;
   2154    fWideAmPms = nullptr;
   2155    fWideAmPmsCount=0;
   2156    fNarrowAmPms = nullptr;
   2157    fNarrowAmPmsCount=0;
   2158    fTimeSeparator.setToBogus();
   2159    fQuarters = nullptr;
   2160    fQuartersCount = 0;
   2161    fShortQuarters = nullptr;
   2162    fShortQuartersCount = 0;
   2163    fNarrowQuarters = nullptr;
   2164    fNarrowQuartersCount = 0;
   2165    fStandaloneQuarters = nullptr;
   2166    fStandaloneQuartersCount = 0;
   2167    fStandaloneShortQuarters = nullptr;
   2168    fStandaloneShortQuartersCount = 0;
   2169    fStandaloneNarrowQuarters = nullptr;
   2170    fStandaloneNarrowQuartersCount = 0;
   2171    fLeapMonthPatterns = nullptr;
   2172    fLeapMonthPatternsCount = 0;
   2173    fShortYearNames = nullptr;
   2174    fShortYearNamesCount = 0;
   2175    fShortZodiacNames = nullptr;
   2176    fShortZodiacNamesCount = 0;
   2177    fZoneStringsRowCount = 0;
   2178    fZoneStringsColCount = 0;
   2179    fZoneStrings = nullptr;
   2180    fLocaleZoneStrings = nullptr;
   2181    fAbbreviatedDayPeriods = nullptr;
   2182    fAbbreviatedDayPeriodsCount = 0;
   2183    fWideDayPeriods = nullptr;
   2184    fWideDayPeriodsCount = 0;
   2185    fNarrowDayPeriods = nullptr;
   2186    fNarrowDayPeriodsCount = 0;
   2187    fStandaloneAbbreviatedDayPeriods = nullptr;
   2188    fStandaloneAbbreviatedDayPeriodsCount = 0;
   2189    fStandaloneWideDayPeriods = nullptr;
   2190    fStandaloneWideDayPeriodsCount = 0;
   2191    fStandaloneNarrowDayPeriods = nullptr;
   2192    fStandaloneNarrowDayPeriodsCount = 0;
   2193    uprv_memset(fCapitalization, 0, sizeof(fCapitalization));
   2194 
   2195    // We need to preserve the requested locale for
   2196    // lazy ZoneStringFormat instantiation.  ZoneStringFormat
   2197    // is region sensitive, thus, bundle locale bundle's locale
   2198    // is not sufficient.
   2199    fZSFLocale = locale;
   2200 
   2201    if (U_FAILURE(status)) return;
   2202 
   2203    // Create a CalendarDataSink to process this data and the resource bundles
   2204    CalendarDataSink calendarSink(status);
   2205    LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getBaseName(), &status));
   2206    LocalUResourceBundlePointer cb(ures_getByKey(rb.getAlias(), gCalendarTag, nullptr, &status));
   2207 
   2208    if (U_FAILURE(status)) return;
   2209 
   2210    // Iterate over the resource bundle data following the fallbacks through different calendar types
   2211    UnicodeString calendarType((type != nullptr && *type != '\0')? type : gGregorianTag, -1, US_INV);
   2212    while (!calendarType.isBogus()) {
   2213        CharString calendarTypeBuffer;
   2214        calendarTypeBuffer.appendInvariantChars(calendarType, status);
   2215        if (U_FAILURE(status)) { return; }
   2216        const char *calendarTypeCArray = calendarTypeBuffer.data();
   2217 
   2218        // Enumerate this calendar type. If the calendar is not found fallback to gregorian
   2219        UErrorCode oldStatus = status;
   2220        LocalUResourceBundlePointer ctb(ures_getByKeyWithFallback(cb.getAlias(), calendarTypeCArray, nullptr, &status));
   2221        if (status == U_MISSING_RESOURCE_ERROR) {
   2222            if (uprv_strcmp(calendarTypeCArray, gGregorianTag) != 0) {
   2223                calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar));
   2224                calendarSink.visitAllResources();
   2225                status = oldStatus;
   2226                continue;
   2227            }
   2228            return;
   2229        }
   2230 
   2231        calendarSink.preEnumerate(calendarType);
   2232        ures_getAllItemsWithFallback(ctb.getAlias(), "", calendarSink, status);
   2233        if (U_FAILURE(status)) break;
   2234 
   2235        // Stop loading when gregorian was loaded
   2236        if (uprv_strcmp(calendarTypeCArray, gGregorianTag) == 0) {
   2237            break;
   2238        }
   2239 
   2240        // Get the next calendar type to process from the sink
   2241        calendarType = calendarSink.nextCalendarType;
   2242 
   2243        // Gregorian is always the last fallback
   2244        if (calendarType.isBogus()) {
   2245            calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar));
   2246            calendarSink.visitAllResources();
   2247        }
   2248    }
   2249 
   2250    // CharString object to build paths
   2251    CharString path;
   2252 
   2253    // Load Leap Month Patterns
   2254    UErrorCode tempStatus = status;
   2255    fLeapMonthPatterns = newUnicodeStringArray(kMonthPatternsCount);
   2256    if (fLeapMonthPatterns) {
   2257        initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatWide, calendarSink,
   2258                             buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesWideTag, tempStatus), tempStatus);
   2259        initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatAbbrev, calendarSink,
   2260                             buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus);
   2261        initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatNarrow, calendarSink,
   2262                             buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesNarrowTag, tempStatus), tempStatus);
   2263        initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneWide, calendarSink,
   2264                             buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesWideTag, tempStatus), tempStatus);
   2265        initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneAbbrev, calendarSink,
   2266                             buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesAbbrTag, tempStatus), tempStatus);
   2267        initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneNarrow, calendarSink,
   2268                             buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesNarrowTag, tempStatus), tempStatus);
   2269        initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternNumeric, calendarSink,
   2270                             buildResourcePath(path, gMonthPatternsTag, gNamesNumericTag, gNamesAllTag, tempStatus), tempStatus);
   2271        if (U_SUCCESS(tempStatus)) {
   2272            // Hack to fix bad C inheritance for dangi monthPatterns (OK in J); this should be handled by aliases in root, but isn't.
   2273            // The ordering of the following statements is important.
   2274            if (fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].isEmpty()) {
   2275                fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
   2276            }
   2277            if (fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].isEmpty()) {
   2278                fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].setTo(fLeapMonthPatterns[kLeapMonthPatternStandaloneNarrow]);
   2279            }
   2280            if (fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].isEmpty()) {
   2281                fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
   2282            }
   2283            if (fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].isEmpty()) {
   2284                fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev]);
   2285            }
   2286            // end of hack
   2287            fLeapMonthPatternsCount = kMonthPatternsCount;
   2288        } else {
   2289            delete[] fLeapMonthPatterns;
   2290            fLeapMonthPatterns = nullptr;
   2291        }
   2292    }
   2293 
   2294    // Load cyclic names sets
   2295    tempStatus = status;
   2296    initField(&fShortYearNames, fShortYearNamesCount, calendarSink,
   2297              buildResourcePath(path, gCyclicNameSetsTag, gNameSetYearsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus);
   2298    initField(&fShortZodiacNames, fShortZodiacNamesCount, calendarSink,
   2299              buildResourcePath(path, gCyclicNameSetsTag, gNameSetZodiacsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus);
   2300 
   2301    // Load context transforms and capitalization
   2302    tempStatus = U_ZERO_ERROR;
   2303    LocalUResourceBundlePointer localeBundle(ures_open(nullptr, locale.getName(), &tempStatus));
   2304    if (U_SUCCESS(tempStatus)) {
   2305        LocalUResourceBundlePointer contextTransforms(ures_getByKeyWithFallback(localeBundle.getAlias(), gContextTransformsTag, nullptr, &tempStatus));
   2306        if (U_SUCCESS(tempStatus)) {
   2307            for (LocalUResourceBundlePointer contextTransformUsage;
   2308                 contextTransformUsage.adoptInstead(ures_getNextResource(contextTransforms.getAlias(), nullptr, &tempStatus)),
   2309                 contextTransformUsage.isValid();) {
   2310                const int32_t * intVector = ures_getIntVector(contextTransformUsage.getAlias(), &len, &status);
   2311                if (U_SUCCESS(tempStatus) && intVector != nullptr && len >= 2) {
   2312                    const char* usageType = ures_getKey(contextTransformUsage.getAlias());
   2313                    if (usageType != nullptr) {
   2314                        const ContextUsageTypeNameToEnumValue * typeMapPtr = contextUsageTypeMap;
   2315                        int32_t compResult = 0;
   2316                        // linear search; list is short and we cannot be sure that bsearch is available
   2317                        while ( typeMapPtr->usageTypeName != nullptr && (compResult = uprv_strcmp(usageType, typeMapPtr->usageTypeName)) > 0 ) {
   2318                            ++typeMapPtr;
   2319                        }
   2320                        if (typeMapPtr->usageTypeName != nullptr && compResult == 0) {
   2321                            fCapitalization[typeMapPtr->usageTypeEnumValue][0] = static_cast<UBool>(intVector[0]);
   2322                            fCapitalization[typeMapPtr->usageTypeEnumValue][1] = static_cast<UBool>(intVector[1]);
   2323                        }
   2324                    }
   2325                }
   2326                tempStatus = U_ZERO_ERROR;
   2327            }
   2328        }
   2329 
   2330        tempStatus = U_ZERO_ERROR;
   2331        const LocalPointer<NumberingSystem> numberingSystem(
   2332                NumberingSystem::createInstance(locale, tempStatus), tempStatus);
   2333        if (U_SUCCESS(tempStatus)) {
   2334            // These functions all fail gracefully if passed nullptr pointers and
   2335            // do nothing unless U_SUCCESS(tempStatus), so it's only necessary
   2336            // to check for errors once after all calls are made.
   2337            const LocalUResourceBundlePointer numberElementsData(ures_getByKeyWithFallback(
   2338                    localeBundle.getAlias(), gNumberElementsTag, nullptr, &tempStatus));
   2339            const LocalUResourceBundlePointer nsNameData(ures_getByKeyWithFallback(
   2340                    numberElementsData.getAlias(), numberingSystem->getName(), nullptr, &tempStatus));
   2341            const LocalUResourceBundlePointer symbolsData(ures_getByKeyWithFallback(
   2342                    nsNameData.getAlias(), gSymbolsTag, nullptr, &tempStatus));
   2343            fTimeSeparator = ures_getUnicodeStringByKey(
   2344                    symbolsData.getAlias(), gTimeSeparatorTag, &tempStatus);
   2345            if (U_FAILURE(tempStatus)) {
   2346                fTimeSeparator.setToBogus();
   2347            }
   2348        }
   2349 
   2350    }
   2351 
   2352    if (fTimeSeparator.isBogus()) {
   2353        fTimeSeparator.setTo(DateFormatSymbols::DEFAULT_TIME_SEPARATOR);
   2354    }
   2355 
   2356    // Load day periods
   2357    fAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink,
   2358                            buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesAbbrTag, status),
   2359                            fAbbreviatedDayPeriodsCount, status);
   2360 
   2361    fWideDayPeriods = loadDayPeriodStrings(calendarSink,
   2362                            buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesWideTag, status),
   2363                            fWideDayPeriodsCount, status);
   2364    fNarrowDayPeriods = loadDayPeriodStrings(calendarSink,
   2365                            buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesNarrowTag, status),
   2366                            fNarrowDayPeriodsCount, status);
   2367 
   2368    fStandaloneAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink,
   2369                            buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesAbbrTag, status),
   2370                            fStandaloneAbbreviatedDayPeriodsCount, status);
   2371 
   2372    fStandaloneWideDayPeriods = loadDayPeriodStrings(calendarSink,
   2373                            buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesWideTag, status),
   2374                            fStandaloneWideDayPeriodsCount, status);
   2375    fStandaloneNarrowDayPeriods = loadDayPeriodStrings(calendarSink,
   2376                            buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesNarrowTag, status),
   2377                            fStandaloneNarrowDayPeriodsCount, status);
   2378 
   2379    // Fill in for missing/bogus items (dayPeriods are a map so single items might be missing)
   2380    if (U_SUCCESS(status)) {
   2381        for (int32_t dpidx = 0; dpidx < fAbbreviatedDayPeriodsCount; ++dpidx) {
   2382            if (dpidx < fWideDayPeriodsCount && fWideDayPeriods != nullptr && fWideDayPeriods[dpidx].isBogus()) {
   2383                fWideDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
   2384            }
   2385            if (dpidx < fNarrowDayPeriodsCount && fNarrowDayPeriods != nullptr && fNarrowDayPeriods[dpidx].isBogus()) {
   2386                fNarrowDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
   2387            }
   2388            if (dpidx < fStandaloneAbbreviatedDayPeriodsCount && fStandaloneAbbreviatedDayPeriods != nullptr && fStandaloneAbbreviatedDayPeriods[dpidx].isBogus()) {
   2389                fStandaloneAbbreviatedDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
   2390            }
   2391            if (dpidx < fStandaloneWideDayPeriodsCount && fStandaloneWideDayPeriods != nullptr && fStandaloneWideDayPeriods[dpidx].isBogus()) {
   2392                fStandaloneWideDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]);
   2393            }
   2394            if (dpidx < fStandaloneNarrowDayPeriodsCount && fStandaloneNarrowDayPeriods != nullptr && fStandaloneNarrowDayPeriods[dpidx].isBogus()) {
   2395                fStandaloneNarrowDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]);
   2396            }
   2397        }
   2398    }
   2399 
   2400    // if we make it to here, the resource data is cool, and we can get everything out
   2401    // of it that we need except for the time-zone and localized-pattern data, which
   2402    // are stored in a separate file
   2403    validLocale = Locale(ures_getLocaleByType(cb.getAlias(), ULOC_VALID_LOCALE, &status));
   2404    actualLocale = Locale(ures_getLocaleByType(cb.getAlias(), ULOC_ACTUAL_LOCALE, &status));
   2405 
   2406    // Era setup
   2407    if (type == nullptr) {
   2408        type = "gregorian";
   2409    }
   2410    LocalPointer<EraRules> eraRules(EraRules::createInstance(type, false, status));
   2411    int32_t maxEra = (U_SUCCESS(status))? eraRules->getMaxEraCode(): 0;
   2412    UErrorCode resStatus = U_ZERO_ERROR;
   2413    LocalUResourceBundlePointer ctpb(ures_getByKeyWithFallback(cb.getAlias(), type, nullptr, &resStatus));
   2414    LocalUResourceBundlePointer cteb(ures_getByKeyWithFallback(ctpb.getAlias(), gErasTag, nullptr, &resStatus));
   2415    const UResourceBundle *ctebPtr = (U_SUCCESS(resStatus))? cteb.getAlias() : nullptr;
   2416    // Load eras
   2417    initEras(&fEras, fErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesAbbrTag, status),
   2418            ctebPtr, gNamesAbbrTag, maxEra, status);
   2419    UErrorCode oldStatus = status;
   2420    initEras(&fEraNames, fEraNamesCount, calendarSink, buildResourcePath(path, gErasTag, gNamesWideTag, status),
   2421            ctebPtr, gNamesWideTag, maxEra, status);
   2422    if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3
   2423        status = oldStatus;
   2424        assignArray(fEraNames, fEraNamesCount, fEras, fErasCount);
   2425    }
   2426    // current ICU4J falls back to abbreviated if narrow eras are missing, so we will too
   2427    oldStatus = status;
   2428    initEras(&fNarrowEras, fNarrowErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesNarrowTag, status),
   2429            ctebPtr, gNamesNarrowTag, maxEra, status);
   2430    if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3
   2431        status = oldStatus;
   2432        assignArray(fNarrowEras, fNarrowErasCount, fEras, fErasCount);
   2433    }
   2434 
   2435    // Load month names
   2436    initField(&fMonths, fMonthsCount, calendarSink,
   2437              buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesWideTag, status), status);
   2438    initField(&fShortMonths, fShortMonthsCount, calendarSink,
   2439              buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesAbbrTag, status), status);
   2440    initField(&fStandaloneMonths, fStandaloneMonthsCount, calendarSink,
   2441              buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status);
   2442    if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide not available, use format/wide */
   2443        status = U_ZERO_ERROR;
   2444        assignArray(fStandaloneMonths, fStandaloneMonthsCount, fMonths, fMonthsCount);
   2445    }
   2446    initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calendarSink,
   2447              buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
   2448    if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated not available, use format/abbreviated */
   2449        status = U_ZERO_ERROR;
   2450        assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, fShortMonths, fShortMonthsCount);
   2451    }
   2452 
   2453    UErrorCode narrowMonthsEC = status;
   2454    UErrorCode standaloneNarrowMonthsEC = status;
   2455    initField(&fNarrowMonths, fNarrowMonthsCount, calendarSink,
   2456              buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesNarrowTag, narrowMonthsEC), narrowMonthsEC);
   2457    initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calendarSink,
   2458              buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, narrowMonthsEC), standaloneNarrowMonthsEC);
   2459    if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC != U_MISSING_RESOURCE_ERROR) {
   2460        // If format/narrow not available, use standalone/narrow
   2461        assignArray(fNarrowMonths, fNarrowMonthsCount, fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount);
   2462    } else if (narrowMonthsEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) {
   2463        // If standalone/narrow not available, use format/narrow
   2464        assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fNarrowMonths, fNarrowMonthsCount);
   2465    } else if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) {
   2466        // If neither is available, use format/abbreviated
   2467        assignArray(fNarrowMonths, fNarrowMonthsCount, fShortMonths, fShortMonthsCount);
   2468        assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fShortMonths, fShortMonthsCount);
   2469    }
   2470 
   2471    // Load AM/PM markers.
   2472    ErrorCode ampmStatus;
   2473    initField(&fAmPms, fAmPmsCount, calendarSink,
   2474              buildResourcePath(path, gAmPmMarkersAbbrTag, ampmStatus), ampmStatus);
   2475    if (ampmStatus.isFailure()) {
   2476        // No-op: fall back to last-resort names, which are pre-populated
   2477    }
   2478    ampmStatus.reset();
   2479    initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
   2480              buildResourcePath(path, gAmPmMarkersNarrowTag, ampmStatus), ampmStatus);
   2481    if (ampmStatus.isFailure()) {
   2482        // Narrow falls back to Abbreviated
   2483        assignArray(fNarrowAmPms, fNarrowAmPmsCount, fAmPms, fAmPmsCount);
   2484    }
   2485    ampmStatus.reset();
   2486    initField(&fWideAmPms, fWideAmPmsCount, calendarSink,
   2487              buildResourcePath(path, gAmPmMarkersTag, ampmStatus), ampmStatus);
   2488    if (ampmStatus.isFailure()) {
   2489        // Wide falls back to Abbreviated
   2490        assignArray(fWideAmPms, fWideAmPmsCount, fAmPms, fAmPmsCount);
   2491    }
   2492    ampmStatus.reset();
   2493 
   2494    // Load quarters
   2495    initField(&fQuarters, fQuartersCount, calendarSink,
   2496              buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesWideTag, status), status);
   2497    initField(&fShortQuarters, fShortQuartersCount, calendarSink,
   2498              buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesAbbrTag, status), status);
   2499    if(status == U_MISSING_RESOURCE_ERROR) {
   2500        status = U_ZERO_ERROR;
   2501        assignArray(fShortQuarters, fShortQuartersCount, fQuarters, fQuartersCount);
   2502    }
   2503 
   2504    initField(&fStandaloneQuarters, fStandaloneQuartersCount, calendarSink,
   2505              buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status);
   2506    if(status == U_MISSING_RESOURCE_ERROR) {
   2507        status = U_ZERO_ERROR;
   2508        assignArray(fStandaloneQuarters, fStandaloneQuartersCount, fQuarters, fQuartersCount);
   2509    }
   2510    initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calendarSink,
   2511              buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
   2512    if(status == U_MISSING_RESOURCE_ERROR) {
   2513        status = U_ZERO_ERROR;
   2514        assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, fShortQuarters, fShortQuartersCount);
   2515    }
   2516 
   2517    // unlike the fields above, narrow format quarters fall back on narrow standalone quarters
   2518    initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, calendarSink,
   2519              buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
   2520    initField(&fNarrowQuarters, fNarrowQuartersCount, calendarSink,
   2521              buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesNarrowTag, status), status);
   2522    if(status == U_MISSING_RESOURCE_ERROR) {
   2523        status = U_ZERO_ERROR;
   2524        assignArray(fNarrowQuarters, fNarrowQuartersCount, fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount);
   2525    }
   2526    
   2527    // ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597)
   2528    /*
   2529    // fastCopyFrom()/setTo() - see assignArray comments
   2530    resStr = ures_getStringByKey(fResourceBundle, gLocalPatternCharsTag, &len, &status);
   2531    fLocalPatternChars.setTo(true, resStr, len);
   2532    // If the locale data does not include new pattern chars, use the defaults
   2533    // TODO: Consider making this an error, since this may add conflicting characters.
   2534    if (len < PATTERN_CHARS_LEN) {
   2535        fLocalPatternChars.append(UnicodeString(true, &gPatternChars[len], PATTERN_CHARS_LEN-len));
   2536    }
   2537    */
   2538    fLocalPatternChars.setTo(true, gPatternChars, PATTERN_CHARS_LEN);
   2539 
   2540    // Format wide weekdays -> fWeekdays
   2541    // {sfb} fixed to handle 1-based weekdays
   2542    initField(&fWeekdays, fWeekdaysCount, calendarSink,
   2543              buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesWideTag, status), 1, status);
   2544 
   2545    // Format abbreviated weekdays -> fShortWeekdays
   2546    initField(&fShortWeekdays, fShortWeekdaysCount, calendarSink,
   2547              buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesAbbrTag, status), 1, status);
   2548 
   2549    // Format short weekdays -> fShorterWeekdays (fall back to abbreviated)
   2550    initField(&fShorterWeekdays, fShorterWeekdaysCount, calendarSink,
   2551              buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesShortTag, status), 1, status);
   2552    if (status == U_MISSING_RESOURCE_ERROR) {
   2553        status = U_ZERO_ERROR;
   2554        assignArray(fShorterWeekdays, fShorterWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
   2555    }
   2556 
   2557    // Stand-alone wide weekdays -> fStandaloneWeekdays
   2558    initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, calendarSink,
   2559              buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status), 1, status);
   2560    if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide is not available, use format/wide */
   2561        status = U_ZERO_ERROR;
   2562        assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, fWeekdays, fWeekdaysCount);
   2563    }
   2564 
   2565    // Stand-alone abbreviated weekdays -> fStandaloneShortWeekdays
   2566    initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, calendarSink,
   2567              buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), 1, status);
   2568    if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated is not available, use format/abbreviated */
   2569        status = U_ZERO_ERROR;
   2570        assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
   2571    }
   2572 
   2573    // Stand-alone short weekdays -> fStandaloneShorterWeekdays (fall back to format abbreviated)
   2574    initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, calendarSink,
   2575              buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesShortTag, status), 1, status);
   2576    if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/short is not available, use format/short */
   2577        status = U_ZERO_ERROR;
   2578        assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, fShorterWeekdays, fShorterWeekdaysCount);
   2579    }
   2580 
   2581    // Format narrow weekdays -> fNarrowWeekdays
   2582    UErrorCode narrowWeeksEC = status;
   2583    initField(&fNarrowWeekdays, fNarrowWeekdaysCount, calendarSink,
   2584              buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesNarrowTag, status), 1, narrowWeeksEC);
   2585    // Stand-alone narrow weekdays -> fStandaloneNarrowWeekdays
   2586    UErrorCode standaloneNarrowWeeksEC = status;
   2587    initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, calendarSink,
   2588              buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), 1, standaloneNarrowWeeksEC);
   2589 
   2590    if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC != U_MISSING_RESOURCE_ERROR) {
   2591        // If format/narrow not available, use standalone/narrow
   2592        assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount);
   2593    } else if (narrowWeeksEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR) {
   2594        // If standalone/narrow not available, use format/narrow
   2595        assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fNarrowWeekdays, fNarrowWeekdaysCount);
   2596    } else if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR ) {
   2597        // If neither is available, use format/abbreviated
   2598        assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
   2599        assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
   2600    }
   2601 
   2602    // Last resort fallback in case previous data wasn't loaded
   2603    if (U_FAILURE(status))
   2604    {
   2605        if (useLastResortData)
   2606        {
   2607            // Handle the case in which there is no resource data present.
   2608            // We don't have to generate usable patterns in this situation;
   2609            // we just need to produce something that will be semi-intelligible
   2610            // in most locales.
   2611 
   2612            status = U_USING_FALLBACK_WARNING;
   2613            //TODO(fabalbon): make sure we are storing las resort data for all fields in here.
   2614            initField(&fEras, fErasCount, reinterpret_cast<const char16_t*>(gLastResortEras), kEraNum, kEraLen, status);
   2615            initField(&fEraNames, fEraNamesCount, reinterpret_cast<const char16_t*>(gLastResortEras), kEraNum, kEraLen, status);
   2616            initField(&fNarrowEras, fNarrowErasCount, reinterpret_cast<const char16_t*>(gLastResortEras), kEraNum, kEraLen, status);
   2617            initField(&fMonths, fMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
   2618            initField(&fShortMonths, fShortMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
   2619            initField(&fNarrowMonths, fNarrowMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
   2620            initField(&fStandaloneMonths, fStandaloneMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
   2621            initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
   2622            initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
   2623            initField(&fWeekdays, fWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2624            initField(&fShortWeekdays, fShortWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2625            initField(&fShorterWeekdays, fShorterWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2626            initField(&fNarrowWeekdays, fNarrowWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2627            initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2628            initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2629            initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2630            initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
   2631            initField(&fAmPms, fAmPmsCount, reinterpret_cast<const char16_t*>(gLastResortAmPmMarkers), kAmPmNum, kAmPmLen, status);
   2632            initField(&fNarrowAmPms, fNarrowAmPmsCount, reinterpret_cast<const char16_t*>(gLastResortAmPmMarkers), kAmPmNum, kAmPmLen, status);
   2633            initField(&fQuarters, fQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
   2634            initField(&fShortQuarters, fShortQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
   2635            initField(&fNarrowQuarters, fNarrowQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
   2636            initField(&fStandaloneQuarters, fStandaloneQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
   2637            initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
   2638            initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
   2639            fLocalPatternChars.setTo(true, gPatternChars, PATTERN_CHARS_LEN);
   2640        }
   2641    }
   2642 }
   2643 
   2644 Locale
   2645 DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
   2646    return LocaleBased::getLocale(validLocale, actualLocale, type, status);
   2647 }
   2648 
   2649 U_NAMESPACE_END
   2650 
   2651 #endif /* #if !UCONFIG_NO_FORMATTING */
   2652 
   2653 //eof