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