Bug Summary

File:root/firefox-clang/intl/icu/source/i18n/dtfmtsym.cpp
Warning:line 1786, column 58
Although the value stored to 'length' is used in the enclosing expression, the value is never actually read from 'length'

Annotated Source Code

Press '?' to see keyboard shortcuts

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