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