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