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