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