/src/icu/source/i18n/dtptngen.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // © 2016 and later: Unicode, Inc. and others.  | 
2  |  | // License & terms of use: http://www.unicode.org/copyright.html  | 
3  |  | /*  | 
4  |  | *******************************************************************************  | 
5  |  | * Copyright (C) 2007-2016, International Business Machines Corporation and  | 
6  |  | * others. All Rights Reserved.  | 
7  |  | *******************************************************************************  | 
8  |  | *  | 
9  |  | * File DTPTNGEN.CPP  | 
10  |  | *  | 
11  |  | *******************************************************************************  | 
12  |  | */  | 
13  |  |  | 
14  |  | #include "unicode/utypes.h"  | 
15  |  | #if !UCONFIG_NO_FORMATTING  | 
16  |  |  | 
17  |  | #include "unicode/datefmt.h"  | 
18  |  | #include "unicode/decimfmt.h"  | 
19  |  | #include "unicode/dtfmtsym.h"  | 
20  |  | #include "unicode/dtptngen.h"  | 
21  |  | #include "unicode/localpointer.h"  | 
22  |  | #include "unicode/simpleformatter.h"  | 
23  |  | #include "unicode/smpdtfmt.h"  | 
24  |  | #include "unicode/udat.h"  | 
25  |  | #include "unicode/udatpg.h"  | 
26  |  | #include "unicode/uniset.h"  | 
27  |  | #include "unicode/uloc.h"  | 
28  |  | #include "unicode/ures.h"  | 
29  |  | #include "unicode/ustring.h"  | 
30  |  | #include "unicode/rep.h"  | 
31  |  | #include "unicode/region.h"  | 
32  |  | #include "cpputils.h"  | 
33  |  | #include "mutex.h"  | 
34  |  | #include "umutex.h"  | 
35  |  | #include "cmemory.h"  | 
36  |  | #include "cstring.h"  | 
37  |  | #include "locbased.h"  | 
38  |  | #include "hash.h"  | 
39  |  | #include "uhash.h"  | 
40  |  | #include "uresimp.h"  | 
41  |  | #include "dtptngen_impl.h"  | 
42  |  | #include "ucln_in.h"  | 
43  |  | #include "charstr.h"  | 
44  |  | #include "uassert.h"  | 
45  |  |  | 
46  |  | #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY  | 
47  |  | /**  | 
48  |  |  * If we are on EBCDIC, use an iterator which will  | 
49  |  |  * traverse the bundles in ASCII order.  | 
50  |  |  */  | 
51  |  | #define U_USE_ASCII_BUNDLE_ITERATOR  | 
52  |  | #define U_SORT_ASCII_BUNDLE_ITERATOR  | 
53  |  | #endif  | 
54  |  |  | 
55  |  | #if defined(U_USE_ASCII_BUNDLE_ITERATOR)  | 
56  |  |  | 
57  |  | #include "unicode/ustring.h"  | 
58  |  | #include "uarrsort.h"  | 
59  |  |  | 
60  |  | struct UResAEntry { | 
61  |  |     UChar *key;  | 
62  |  |     UResourceBundle *item;  | 
63  |  | };  | 
64  |  |  | 
65  |  | struct UResourceBundleAIterator { | 
66  |  |     UResourceBundle  *bund;  | 
67  |  |     UResAEntry *entries;  | 
68  |  |     int32_t num;  | 
69  |  |     int32_t cursor;  | 
70  |  | };  | 
71  |  |  | 
72  |  | /* Must be C linkage to pass function pointer to the sort function */  | 
73  |  |  | 
74  |  | U_CDECL_BEGIN  | 
75  |  |  | 
76  |  | static int32_t U_CALLCONV  | 
77  |  | ures_a_codepointSort(const void *context, const void *left, const void *right) { | 
78  |  |     //CompareContext *cmp=(CompareContext *)context;  | 
79  |  |     return u_strcmp(((const UResAEntry *)left)->key,  | 
80  |  |                     ((const UResAEntry *)right)->key);  | 
81  |  | }  | 
82  |  |  | 
83  |  | U_CDECL_END  | 
84  |  |  | 
85  |  | static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund, UErrorCode *status) { | 
86  |  |     if(U_FAILURE(*status)) { | 
87  |  |         return;  | 
88  |  |     }  | 
89  |  |     aiter->bund = bund;  | 
90  |  |     aiter->num = ures_getSize(aiter->bund);  | 
91  |  |     aiter->cursor = 0;  | 
92  |  | #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)  | 
93  |  |     aiter->entries = nullptr;  | 
94  |  | #else  | 
95  |  |     aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num);  | 
96  |  |     for(int i=0;i<aiter->num;i++) { | 
97  |  |         aiter->entries[i].item = ures_getByIndex(aiter->bund, i, nullptr, status);  | 
98  |  |         const char *akey = ures_getKey(aiter->entries[i].item);  | 
99  |  |         int32_t len = uprv_strlen(akey)+1;  | 
100  |  |         aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar));  | 
101  |  |         u_charsToUChars(akey, aiter->entries[i].key, len);  | 
102  |  |     }  | 
103  |  |     uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, nullptr, TRUE, status);  | 
104  |  | #endif  | 
105  |  | }  | 
106  |  |  | 
107  |  | static void ures_a_close(UResourceBundleAIterator *aiter) { | 
108  |  | #if defined(U_SORT_ASCII_BUNDLE_ITERATOR)  | 
109  |  |     for(int i=0;i<aiter->num;i++) { | 
110  |  |         uprv_free(aiter->entries[i].key);  | 
111  |  |         ures_close(aiter->entries[i].item);  | 
112  |  |     }  | 
113  |  | #endif  | 
114  |  | }  | 
115  |  |  | 
116  |  | static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_t *len, const char **key, UErrorCode *err) { | 
117  |  | #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)  | 
118  |  |     return ures_getNextString(aiter->bund, len, key, err);  | 
119  |  | #else  | 
120  |  |     if(U_FAILURE(*err)) return nullptr;  | 
121  |  |     UResourceBundle *item = aiter->entries[aiter->cursor].item;  | 
122  |  |     const UChar* ret = ures_getString(item, len, err);  | 
123  |  |     *key = ures_getKey(item);  | 
124  |  |     aiter->cursor++;  | 
125  |  |     return ret;  | 
126  |  | #endif  | 
127  |  | }  | 
128  |  |  | 
129  |  |  | 
130  |  | #endif  | 
131  |  |  | 
132  |  |  | 
133  |  | U_NAMESPACE_BEGIN  | 
134  |  |  | 
135  |  | // *****************************************************************************  | 
136  |  | // class DateTimePatternGenerator  | 
137  |  | // *****************************************************************************  | 
138  |  | static const UChar Canonical_Items[] = { | 
139  |  |     // GyQMwWEDFdaHmsSv  | 
140  |  |     CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_E,  | 
141  |  |     CAP_D, CAP_F, LOW_D, LOW_A, // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J  | 
142  |  |     CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0  | 
143  |  | };  | 
144  |  |  | 
145  |  | static const dtTypeElem dtTypes[] = { | 
146  |  |     // patternChar, field, type, minLen, weight  | 
147  |  |     {CAP_G, UDATPG_ERA_FIELD, DT_SHORT, 1, 3,}, | 
148  |  |     {CAP_G, UDATPG_ERA_FIELD, DT_LONG,  4, 0}, | 
149  |  |     {CAP_G, UDATPG_ERA_FIELD, DT_NARROW, 5, 0}, | 
150  |  |  | 
151  |  |     {LOW_Y, UDATPG_YEAR_FIELD, DT_NUMERIC, 1, 20}, | 
152  |  |     {CAP_Y, UDATPG_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 20}, | 
153  |  |     {LOW_U, UDATPG_YEAR_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 20}, | 
154  |  |     {LOW_R, UDATPG_YEAR_FIELD, DT_NUMERIC + 3*DT_DELTA, 1, 20}, | 
155  |  |     {CAP_U, UDATPG_YEAR_FIELD, DT_SHORT, 1, 3}, | 
156  |  |     {CAP_U, UDATPG_YEAR_FIELD, DT_LONG, 4, 0}, | 
157  |  |     {CAP_U, UDATPG_YEAR_FIELD, DT_NARROW, 5, 0}, | 
158  |  |  | 
159  |  |     {CAP_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC, 1, 2}, | 
160  |  |     {CAP_Q, UDATPG_QUARTER_FIELD, DT_SHORT, 3, 0}, | 
161  |  |     {CAP_Q, UDATPG_QUARTER_FIELD, DT_LONG, 4, 0}, | 
162  |  |     {CAP_Q, UDATPG_QUARTER_FIELD, DT_NARROW, 5, 0}, | 
163  |  |     {LOW_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, | 
164  |  |     {LOW_Q, UDATPG_QUARTER_FIELD, DT_SHORT - DT_DELTA, 3, 0}, | 
165  |  |     {LOW_Q, UDATPG_QUARTER_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
166  |  |     {LOW_Q, UDATPG_QUARTER_FIELD, DT_NARROW - DT_DELTA, 5, 0}, | 
167  |  |  | 
168  |  |     {CAP_M, UDATPG_MONTH_FIELD, DT_NUMERIC, 1, 2}, | 
169  |  |     {CAP_M, UDATPG_MONTH_FIELD, DT_SHORT, 3, 0}, | 
170  |  |     {CAP_M, UDATPG_MONTH_FIELD, DT_LONG, 4, 0}, | 
171  |  |     {CAP_M, UDATPG_MONTH_FIELD, DT_NARROW, 5, 0}, | 
172  |  |     {CAP_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, | 
173  |  |     {CAP_L, UDATPG_MONTH_FIELD, DT_SHORT - DT_DELTA, 3, 0}, | 
174  |  |     {CAP_L, UDATPG_MONTH_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
175  |  |     {CAP_L, UDATPG_MONTH_FIELD, DT_NARROW - DT_DELTA, 5, 0}, | 
176  |  |     {LOW_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 1}, | 
177  |  |  | 
178  |  |     {LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2}, | 
179  |  |  | 
180  |  |     {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC, 1, 0}, | 
181  |  |  | 
182  |  |     {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORT, 1, 3}, | 
183  |  |     {CAP_E, UDATPG_WEEKDAY_FIELD, DT_LONG, 4, 0}, | 
184  |  |     {CAP_E, UDATPG_WEEKDAY_FIELD, DT_NARROW, 5, 0}, | 
185  |  |     {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORTER, 6, 0}, | 
186  |  |     {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 2}, | 
187  |  |     {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORT - 2*DT_DELTA, 3, 0}, | 
188  |  |     {LOW_C, UDATPG_WEEKDAY_FIELD, DT_LONG - 2*DT_DELTA, 4, 0}, | 
189  |  |     {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NARROW - 2*DT_DELTA, 5, 0}, | 
190  |  |     {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORTER - 2*DT_DELTA, 6, 0}, | 
191  |  |     {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // LOW_E is currently not used in CLDR data, should not be canonical | 
192  |  |     {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORT - DT_DELTA, 3, 0}, | 
193  |  |     {LOW_E, UDATPG_WEEKDAY_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
194  |  |     {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NARROW - DT_DELTA, 5, 0}, | 
195  |  |     {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORTER - DT_DELTA, 6, 0}, | 
196  |  |  | 
197  |  |     {LOW_D, UDATPG_DAY_FIELD, DT_NUMERIC, 1, 2}, | 
198  |  |     {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 20}, // really internal use, so we don't care | 
199  |  |  | 
200  |  |     {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC, 1, 3}, | 
201  |  |  | 
202  |  |     {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC, 1, 0}, | 
203  |  |  | 
204  |  |     {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 3}, | 
205  |  |     {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_LONG, 4, 0}, | 
206  |  |     {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_NARROW, 5, 0}, | 
207  |  |     {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - DT_DELTA, 1, 3}, | 
208  |  |     {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
209  |  |     {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - DT_DELTA, 5, 0}, | 
210  |  |     // b needs to be closer to a than to B, so we make this 3*DT_DELTA  | 
211  |  |     {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - 3*DT_DELTA, 1, 3}, | 
212  |  |     {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - 3*DT_DELTA, 4, 0}, | 
213  |  |     {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - 3*DT_DELTA, 5, 0}, | 
214  |  |  | 
215  |  |     {CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour | 
216  |  |     {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2}, // 24 hour | 
217  |  |     {LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour | 
218  |  |     {CAP_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // 12 hour | 
219  |  |     // The C code has had versions of the following 3, keep & update. Should not need these, but...  | 
220  |  |     // Without these, certain tests using e.g. staticGetSkeleton fail because j/J in patterns  | 
221  |  |     // get skipped instead of mapped to the right hour chars, for example in  | 
222  |  |     //   DateFormatTest::TestPatternFromSkeleton  | 
223  |  |     //   IntlTestDateTimePatternGeneratorAPI:: testStaticGetSkeleton  | 
224  |  |     //   DateIntervalFormatTest::testTicket11985  | 
225  |  |     // Need to investigate better handling of jJC replacement e.g. in staticGetSkeleton.  | 
226  |  |     {CAP_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 5*DT_DELTA, 1, 2}, // 12/24 hour no AM/PM | 
227  |  |     {LOW_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 6*DT_DELTA, 1, 6}, // 12/24 hour | 
228  |  |     {CAP_C, UDATPG_HOUR_FIELD, DT_NUMERIC + 7*DT_DELTA, 1, 6}, // 12/24 hour with preferred dayPeriods for 12 | 
229  |  |  | 
230  |  |     {LOW_M, UDATPG_MINUTE_FIELD, DT_NUMERIC, 1, 2}, | 
231  |  |  | 
232  |  |     {LOW_S, UDATPG_SECOND_FIELD, DT_NUMERIC, 1, 2}, | 
233  |  |     {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000}, | 
234  |  |  | 
235  |  |     {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC, 1, 1000}, | 
236  |  |  | 
237  |  |     {LOW_V, UDATPG_ZONE_FIELD, DT_SHORT - 2*DT_DELTA, 1, 0}, | 
238  |  |     {LOW_V, UDATPG_ZONE_FIELD, DT_LONG - 2*DT_DELTA, 4, 0}, | 
239  |  |     {LOW_Z, UDATPG_ZONE_FIELD, DT_SHORT, 1, 3}, | 
240  |  |     {LOW_Z, UDATPG_ZONE_FIELD, DT_LONG, 4, 0}, | 
241  |  |     {CAP_Z, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 3}, | 
242  |  |     {CAP_Z, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
243  |  |     {CAP_Z, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 5, 0}, | 
244  |  |     {CAP_O, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0}, | 
245  |  |     {CAP_O, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
246  |  |     {CAP_V, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0}, | 
247  |  |     {CAP_V, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 2, 0}, | 
248  |  |     {CAP_V, UDATPG_ZONE_FIELD, DT_LONG-1 - DT_DELTA, 3, 0}, | 
249  |  |     {CAP_V, UDATPG_ZONE_FIELD, DT_LONG-2 - DT_DELTA, 4, 0}, | 
250  |  |     {CAP_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0}, | 
251  |  |     {CAP_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0}, | 
252  |  |     {CAP_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
253  |  |     {LOW_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0}, | 
254  |  |     {LOW_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0}, | 
255  |  |     {LOW_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, | 
256  |  |  | 
257  |  |     {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[] | 
258  |  |  };  | 
259  |  |  | 
260  |  | static const char* const CLDR_FIELD_APPEND[] = { | 
261  |  |     "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week",  | 
262  |  |     "*", "*", "Day", "*", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J  | 
263  |  |     "Hour", "Minute", "Second", "*", "Timezone"  | 
264  |  | };  | 
265  |  |  | 
266  |  | static const char* const CLDR_FIELD_NAME[UDATPG_FIELD_COUNT] = { | 
267  |  |     "era", "year", "quarter", "month", "week", "weekOfMonth", "weekday",  | 
268  |  |     "dayOfYear", "weekdayOfMonth", "day", "dayperiod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J  | 
269  |  |     "hour", "minute", "second", "*", "zone"  | 
270  |  | };  | 
271  |  |  | 
272  |  | static const char* const CLDR_FIELD_WIDTH[] = { // [UDATPG_WIDTH_COUNT] | 
273  |  |     "", "-short", "-narrow"  | 
274  |  | };  | 
275  |  |  | 
276  |  | // TODO(ticket:13619): remove when definition uncommented in dtptngen.h.  | 
277  |  | static const int32_t UDATPG_WIDTH_COUNT = UDATPG_NARROW + 1;  | 
278  |  | static constexpr UDateTimePGDisplayWidth UDATPG_WIDTH_APPENDITEM = UDATPG_WIDE;  | 
279  |  | static constexpr int32_t UDATPG_FIELD_KEY_MAX = 24; // max length of CLDR field tag (type + width)  | 
280  |  |  | 
281  |  | // For appendItems  | 
282  |  | static const UChar UDATPG_ItemFormat[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A, | 
283  |  |     0x20, 0x7B, 0x31, 0x7D, 0x2524, 0};  // {0} \u251C{2}: {1}\u2524 | 
284  |  |  | 
285  |  | //static const UChar repeatedPatterns[6]={CAP_G, CAP_E, LOW_Z, LOW_V, CAP_Q, 0}; // "GEzvQ" | 
286  |  |  | 
287  |  | static const char DT_DateTimePatternsTag[]="DateTimePatterns";  | 
288  |  | static const char DT_DateTimeCalendarTag[]="calendar";  | 
289  |  | static const char DT_DateTimeGregorianTag[]="gregorian";  | 
290  |  | static const char DT_DateTimeAppendItemsTag[]="appendItems";  | 
291  |  | static const char DT_DateTimeFieldsTag[]="fields";  | 
292  |  | static const char DT_DateTimeAvailableFormatsTag[]="availableFormats";  | 
293  |  | //static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);  | 
294  |  |  | 
295  |  | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator)  | 
296  |  | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration)  | 
297  |  | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration)  | 
298  |  |  | 
299  |  | DateTimePatternGenerator*  U_EXPORT2  | 
300  | 0  | DateTimePatternGenerator::createInstance(UErrorCode& status) { | 
301  | 0  |     return createInstance(Locale::getDefault(), status);  | 
302  | 0  | }  | 
303  |  |  | 
304  |  | DateTimePatternGenerator* U_EXPORT2  | 
305  | 0  | DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) { | 
306  | 0  |     if (U_FAILURE(status)) { | 
307  | 0  |         return nullptr;  | 
308  | 0  |     }  | 
309  | 0  |     LocalPointer<DateTimePatternGenerator> result(  | 
310  | 0  |             new DateTimePatternGenerator(locale, status), status);  | 
311  | 0  |     return U_SUCCESS(status) ? result.orphan() : nullptr;  | 
312  | 0  | }  | 
313  |  |  | 
314  |  | DateTimePatternGenerator* U_EXPORT2  | 
315  | 0  | DateTimePatternGenerator::createInstanceNoStdPat(const Locale& locale, UErrorCode& status) { | 
316  | 0  |     if (U_FAILURE(status)) { | 
317  | 0  |         return nullptr;  | 
318  | 0  |     }  | 
319  | 0  |     LocalPointer<DateTimePatternGenerator> result(  | 
320  | 0  |             new DateTimePatternGenerator(locale, status, true), status);  | 
321  | 0  |     return U_SUCCESS(status) ? result.orphan() : nullptr;  | 
322  | 0  | }  | 
323  |  |  | 
324  |  | DateTimePatternGenerator*  U_EXPORT2  | 
325  | 0  | DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) { | 
326  | 0  |     if (U_FAILURE(status)) { | 
327  | 0  |         return nullptr;  | 
328  | 0  |     }  | 
329  | 0  |     LocalPointer<DateTimePatternGenerator> result(  | 
330  | 0  |             new DateTimePatternGenerator(status), status);  | 
331  | 0  |     return U_SUCCESS(status) ? result.orphan() : nullptr;  | 
332  | 0  | }  | 
333  |  |  | 
334  |  | DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) :  | 
335  | 0  |     skipMatcher(nullptr),  | 
336  | 0  |     fAvailableFormatKeyHash(nullptr),  | 
337  | 0  |     fDefaultHourFormatChar(0),  | 
338  | 0  |     internalErrorCode(U_ZERO_ERROR)  | 
339  | 0  | { | 
340  | 0  |     fp = new FormatParser();  | 
341  | 0  |     dtMatcher = new DateTimeMatcher();  | 
342  | 0  |     distanceInfo = new DistanceInfo();  | 
343  | 0  |     patternMap = new PatternMap();  | 
344  | 0  |     if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) { | 
345  | 0  |         internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;  | 
346  | 0  |     }  | 
347  | 0  | }  | 
348  |  |  | 
349  |  | DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status, UBool skipStdPatterns) :  | 
350  | 0  |     skipMatcher(nullptr),  | 
351  | 0  |     fAvailableFormatKeyHash(nullptr),  | 
352  | 0  |     fDefaultHourFormatChar(0),  | 
353  | 0  |     internalErrorCode(U_ZERO_ERROR)  | 
354  | 0  | { | 
355  | 0  |     fp = new FormatParser();  | 
356  | 0  |     dtMatcher = new DateTimeMatcher();  | 
357  | 0  |     distanceInfo = new DistanceInfo();  | 
358  | 0  |     patternMap = new PatternMap();  | 
359  | 0  |     if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) { | 
360  | 0  |         internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;  | 
361  | 0  |     }  | 
362  | 0  |     else { | 
363  | 0  |         initData(locale, status, skipStdPatterns);  | 
364  | 0  |     }  | 
365  | 0  | }  | 
366  |  |  | 
367  |  | DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) :  | 
368  | 0  |     UObject(),  | 
369  | 0  |     skipMatcher(nullptr),  | 
370  | 0  |     fAvailableFormatKeyHash(nullptr),  | 
371  | 0  |     fDefaultHourFormatChar(0),  | 
372  | 0  |     internalErrorCode(U_ZERO_ERROR)  | 
373  | 0  | { | 
374  | 0  |     fp = new FormatParser();  | 
375  | 0  |     dtMatcher = new DateTimeMatcher();  | 
376  | 0  |     distanceInfo = new DistanceInfo();  | 
377  | 0  |     patternMap = new PatternMap();  | 
378  | 0  |     if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) { | 
379  | 0  |         internalErrorCode = U_MEMORY_ALLOCATION_ERROR;  | 
380  | 0  |     }  | 
381  | 0  |     *this=other;  | 
382  | 0  | }  | 
383  |  |  | 
384  |  | DateTimePatternGenerator&  | 
385  | 0  | DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) { | 
386  |  |     // reflexive case  | 
387  | 0  |     if (&other == this) { | 
388  | 0  |         return *this;  | 
389  | 0  |     }  | 
390  | 0  |     internalErrorCode = other.internalErrorCode;  | 
391  | 0  |     pLocale = other.pLocale;  | 
392  | 0  |     fDefaultHourFormatChar = other.fDefaultHourFormatChar;  | 
393  | 0  |     *fp = *(other.fp);  | 
394  | 0  |     dtMatcher->copyFrom(other.dtMatcher->skeleton);  | 
395  | 0  |     *distanceInfo = *(other.distanceInfo);  | 
396  | 0  |     dateTimeFormat = other.dateTimeFormat;  | 
397  | 0  |     decimal = other.decimal;  | 
398  |  |     // NUL-terminate for the C API.  | 
399  | 0  |     dateTimeFormat.getTerminatedBuffer();  | 
400  | 0  |     decimal.getTerminatedBuffer();  | 
401  | 0  |     delete skipMatcher;  | 
402  | 0  |     if ( other.skipMatcher == nullptr ) { | 
403  | 0  |         skipMatcher = nullptr;  | 
404  | 0  |     }  | 
405  | 0  |     else { | 
406  | 0  |         skipMatcher = new DateTimeMatcher(*other.skipMatcher);  | 
407  | 0  |         if (skipMatcher == nullptr)  | 
408  | 0  |         { | 
409  | 0  |             internalErrorCode = U_MEMORY_ALLOCATION_ERROR;  | 
410  | 0  |             return *this;  | 
411  | 0  |         }  | 
412  | 0  |     }  | 
413  | 0  |     for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) { | 
414  | 0  |         appendItemFormats[i] = other.appendItemFormats[i];  | 
415  | 0  |         appendItemFormats[i].getTerminatedBuffer(); // NUL-terminate for the C API.  | 
416  | 0  |         for (int32_t j=0; j< UDATPG_WIDTH_COUNT; ++j ) { | 
417  | 0  |             fieldDisplayNames[i][j] = other.fieldDisplayNames[i][j];  | 
418  | 0  |             fieldDisplayNames[i][j].getTerminatedBuffer(); // NUL-terminate for the C API.  | 
419  | 0  |         }  | 
420  | 0  |     }  | 
421  | 0  |     patternMap->copyFrom(*other.patternMap, internalErrorCode);  | 
422  | 0  |     copyHashtable(other.fAvailableFormatKeyHash, internalErrorCode);  | 
423  | 0  |     return *this;  | 
424  | 0  | }  | 
425  |  |  | 
426  |  |  | 
427  |  | bool  | 
428  | 0  | DateTimePatternGenerator::operator==(const DateTimePatternGenerator& other) const { | 
429  | 0  |     if (this == &other) { | 
430  | 0  |         return TRUE;  | 
431  | 0  |     }  | 
432  | 0  |     if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) &&  | 
433  | 0  |         (dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) { | 
434  | 0  |         for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) { | 
435  | 0  |             if (appendItemFormats[i] != other.appendItemFormats[i]) { | 
436  | 0  |                 return FALSE;  | 
437  | 0  |             }  | 
438  | 0  |             for (int32_t j=0; j< UDATPG_WIDTH_COUNT; ++j ) { | 
439  | 0  |                 if (fieldDisplayNames[i][j] != other.fieldDisplayNames[i][j]) { | 
440  | 0  |                     return FALSE;  | 
441  | 0  |                 }  | 
442  | 0  |             }  | 
443  | 0  |         }  | 
444  | 0  |         return TRUE;  | 
445  | 0  |     }  | 
446  | 0  |     else { | 
447  | 0  |         return FALSE;  | 
448  | 0  |     }  | 
449  | 0  | }  | 
450  |  |  | 
451  |  | bool  | 
452  | 0  | DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) const { | 
453  | 0  |     return  !operator==(other);  | 
454  | 0  | }  | 
455  |  |  | 
456  | 0  | DateTimePatternGenerator::~DateTimePatternGenerator() { | 
457  | 0  |     if (fAvailableFormatKeyHash!=nullptr) { | 
458  | 0  |         delete fAvailableFormatKeyHash;  | 
459  | 0  |     }  | 
460  |  | 
  | 
461  | 0  |     if (fp != nullptr) delete fp;  | 
462  | 0  |     if (dtMatcher != nullptr) delete dtMatcher;  | 
463  | 0  |     if (distanceInfo != nullptr) delete distanceInfo;  | 
464  | 0  |     if (patternMap != nullptr) delete patternMap;  | 
465  | 0  |     if (skipMatcher != nullptr) delete skipMatcher;  | 
466  | 0  | }  | 
467  |  |  | 
468  |  | namespace { | 
469  |  |  | 
470  |  | UInitOnce initOnce = U_INITONCE_INITIALIZER;  | 
471  |  | UHashtable *localeToAllowedHourFormatsMap = nullptr;  | 
472  |  |  | 
473  |  | // Value deleter for hashmap.  | 
474  | 0  | U_CFUNC void U_CALLCONV deleteAllowedHourFormats(void *ptr) { | 
475  | 0  |     uprv_free(ptr);  | 
476  | 0  | }  | 
477  |  |  | 
478  |  | // Close hashmap at cleanup.  | 
479  | 0  | U_CFUNC UBool U_CALLCONV allowedHourFormatsCleanup() { | 
480  | 0  |     uhash_close(localeToAllowedHourFormatsMap);  | 
481  | 0  |     return TRUE;  | 
482  | 0  | }  | 
483  |  |  | 
484  |  | enum AllowedHourFormat{ | 
485  |  |     ALLOWED_HOUR_FORMAT_UNKNOWN = -1,  | 
486  |  |     ALLOWED_HOUR_FORMAT_h,  | 
487  |  |     ALLOWED_HOUR_FORMAT_H,  | 
488  |  |     ALLOWED_HOUR_FORMAT_K,  // Added ICU-20383, used by JP  | 
489  |  |     ALLOWED_HOUR_FORMAT_k,  // Added ICU-20383, not currently used  | 
490  |  |     ALLOWED_HOUR_FORMAT_hb,  | 
491  |  |     ALLOWED_HOUR_FORMAT_hB,  | 
492  |  |     ALLOWED_HOUR_FORMAT_Kb, // Added ICU-20383, not currently used  | 
493  |  |     ALLOWED_HOUR_FORMAT_KB, // Added ICU-20383, not currently used  | 
494  |  |     // ICU-20383 The following are unlikely and not currently used  | 
495  |  |     ALLOWED_HOUR_FORMAT_Hb,  | 
496  |  |     ALLOWED_HOUR_FORMAT_HB  | 
497  |  | };  | 
498  |  |  | 
499  |  | }  // namespace  | 
500  |  |  | 
501  |  | void  | 
502  | 0  | DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status, UBool skipStdPatterns) { | 
503  |  |     //const char *baseLangName = locale.getBaseName(); // unused  | 
504  |  | 
  | 
505  | 0  |     skipMatcher = nullptr;  | 
506  | 0  |     fAvailableFormatKeyHash=nullptr;  | 
507  | 0  |     addCanonicalItems(status);  | 
508  | 0  |     if (!skipStdPatterns) { // skip to prevent circular dependency when called from SimpleDateFormat::construct | 
509  | 0  |         addICUPatterns(locale, status);  | 
510  | 0  |     }  | 
511  | 0  |     addCLDRData(locale, status);  | 
512  | 0  |     setDateTimeFromCalendar(locale, status);  | 
513  | 0  |     setDecimalSymbols(locale, status);  | 
514  | 0  |     umtx_initOnce(initOnce, loadAllowedHourFormatsData, status);  | 
515  | 0  |     getAllowedHourFormats(locale, status);  | 
516  |  |     // If any of the above methods failed then the object is in an invalid state.  | 
517  | 0  |     internalErrorCode = status;  | 
518  | 0  | } // DateTimePatternGenerator::initData  | 
519  |  |  | 
520  |  | namespace { | 
521  |  |  | 
522  |  | struct AllowedHourFormatsSink : public ResourceSink { | 
523  |  |     // Initialize sub-sinks.  | 
524  | 0  |     AllowedHourFormatsSink() {} | 
525  |  |     virtual ~AllowedHourFormatsSink();  | 
526  |  |  | 
527  |  |     virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,  | 
528  | 0  |                      UErrorCode &errorCode) { | 
529  | 0  |         ResourceTable timeData = value.getTable(errorCode);  | 
530  | 0  |         if (U_FAILURE(errorCode)) { return; } | 
531  | 0  |         for (int32_t i = 0; timeData.getKeyAndValue(i, key, value); ++i) { | 
532  | 0  |             const char *regionOrLocale = key;  | 
533  | 0  |             ResourceTable formatList = value.getTable(errorCode);  | 
534  | 0  |             if (U_FAILURE(errorCode)) { return; } | 
535  |  |             // below we construct a list[] that has an entry for the "preferred" value at [0],  | 
536  |  |             // followed by 1 or more entries for the "allowed" values, terminated with an  | 
537  |  |             // entry for ALLOWED_HOUR_FORMAT_UNKNOWN (not included in length below)  | 
538  | 0  |             LocalMemory<int32_t> list;  | 
539  | 0  |             int32_t length = 0;  | 
540  | 0  |             int32_t preferredFormat = ALLOWED_HOUR_FORMAT_UNKNOWN;  | 
541  | 0  |             for (int32_t j = 0; formatList.getKeyAndValue(j, key, value); ++j) { | 
542  | 0  |                 if (uprv_strcmp(key, "allowed") == 0) { | 
543  | 0  |                     if (value.getType() == URES_STRING) { | 
544  | 0  |                         length = 2; // 1 preferred to add later, 1 allowed to add now  | 
545  | 0  |                         if (list.allocateInsteadAndReset(length + 1) == nullptr) { | 
546  | 0  |                             errorCode = U_MEMORY_ALLOCATION_ERROR;  | 
547  | 0  |                             return;  | 
548  | 0  |                         }  | 
549  | 0  |                         list[1] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));  | 
550  | 0  |                     }  | 
551  | 0  |                     else { | 
552  | 0  |                         ResourceArray allowedFormats = value.getArray(errorCode);  | 
553  | 0  |                         length = allowedFormats.getSize() + 1; // 1 preferred, getSize allowed  | 
554  | 0  |                         if (list.allocateInsteadAndReset(length + 1) == nullptr) { | 
555  | 0  |                             errorCode = U_MEMORY_ALLOCATION_ERROR;  | 
556  | 0  |                             return;  | 
557  | 0  |                         }  | 
558  | 0  |                         for (int32_t k = 1; k < length; ++k) { | 
559  | 0  |                             allowedFormats.getValue(k-1, value);  | 
560  | 0  |                             list[k] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));  | 
561  | 0  |                         }  | 
562  | 0  |                     }  | 
563  | 0  |                 } else if (uprv_strcmp(key, "preferred") == 0) { | 
564  | 0  |                     preferredFormat = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));  | 
565  | 0  |                 }  | 
566  | 0  |             }  | 
567  | 0  |             if (length > 1) { | 
568  | 0  |                 list[0] = (preferredFormat!=ALLOWED_HOUR_FORMAT_UNKNOWN)? preferredFormat: list[1];  | 
569  | 0  |             } else { | 
570  |  |                 // fallback handling for missing data  | 
571  | 0  |                 length = 2; // 1 preferred, 1 allowed  | 
572  | 0  |                 if (list.allocateInsteadAndReset(length + 1) == nullptr) { | 
573  | 0  |                     errorCode = U_MEMORY_ALLOCATION_ERROR;  | 
574  | 0  |                     return;  | 
575  | 0  |                 }  | 
576  | 0  |                 list[0] = (preferredFormat!=ALLOWED_HOUR_FORMAT_UNKNOWN)? preferredFormat: ALLOWED_HOUR_FORMAT_H;  | 
577  | 0  |                 list[1] = list[0];  | 
578  | 0  |             }  | 
579  | 0  |             list[length] = ALLOWED_HOUR_FORMAT_UNKNOWN;  | 
580  |  |             // At this point list[] will have at least two non-ALLOWED_HOUR_FORMAT_UNKNOWN entries,  | 
581  |  |             // followed by ALLOWED_HOUR_FORMAT_UNKNOWN.  | 
582  | 0  |             uhash_put(localeToAllowedHourFormatsMap, const_cast<char *>(regionOrLocale), list.orphan(), &errorCode);  | 
583  | 0  |             if (U_FAILURE(errorCode)) { return; } | 
584  | 0  |         }  | 
585  | 0  |     }  | 
586  |  |  | 
587  | 0  |     AllowedHourFormat getHourFormatFromUnicodeString(const UnicodeString &s) { | 
588  | 0  |         if (s.length() == 1) { | 
589  | 0  |             if (s[0] == LOW_H) { return ALLOWED_HOUR_FORMAT_h; } | 
590  | 0  |             if (s[0] == CAP_H) { return ALLOWED_HOUR_FORMAT_H; } | 
591  | 0  |             if (s[0] == CAP_K) { return ALLOWED_HOUR_FORMAT_K; } | 
592  | 0  |             if (s[0] == LOW_K) { return ALLOWED_HOUR_FORMAT_k; } | 
593  | 0  |         } else if (s.length() == 2) { | 
594  | 0  |             if (s[0] == LOW_H && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_hb; } | 
595  | 0  |             if (s[0] == LOW_H && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_hB; } | 
596  | 0  |             if (s[0] == CAP_K && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_Kb; } | 
597  | 0  |             if (s[0] == CAP_K && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_KB; } | 
598  | 0  |             if (s[0] == CAP_H && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_Hb; } | 
599  | 0  |             if (s[0] == CAP_H && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_HB; } | 
600  | 0  |         }  | 
601  |  |  | 
602  | 0  |         return ALLOWED_HOUR_FORMAT_UNKNOWN;  | 
603  | 0  |     }  | 
604  |  | };  | 
605  |  |  | 
606  |  | }  // namespace  | 
607  |  |  | 
608  |  | AllowedHourFormatsSink::~AllowedHourFormatsSink() {} | 
609  |  |  | 
610  | 0  | U_CFUNC void U_CALLCONV DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) { | 
611  | 0  |     if (U_FAILURE(status)) { return; } | 
612  | 0  |     localeToAllowedHourFormatsMap = uhash_open(  | 
613  | 0  |         uhash_hashChars, uhash_compareChars, nullptr, &status);  | 
614  | 0  |     if (U_FAILURE(status)) { return; } | 
615  |  |  | 
616  | 0  |     uhash_setValueDeleter(localeToAllowedHourFormatsMap, deleteAllowedHourFormats);  | 
617  | 0  |     ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);  | 
618  |  | 
  | 
619  | 0  |     LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));  | 
620  | 0  |     if (U_FAILURE(status)) { return; } | 
621  |  |  | 
622  | 0  |     AllowedHourFormatsSink sink;  | 
623  |  |     // TODO: Currently in the enumeration each table allocates a new array.  | 
624  |  |     // Try to reduce the number of memory allocations. Consider storing a  | 
625  |  |     // UVector32 with the concatenation of all of the sub-arrays, put the start index  | 
626  |  |     // into the hashmap, store 6 single-value sub-arrays right at the beginning of the  | 
627  |  |     // vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime  | 
628  |  |     // object. Remember to clean up the vector, too.  | 
629  | 0  |     ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status);      | 
630  | 0  | }  | 
631  |  |  | 
632  | 0  | static int32_t* getAllowedHourFormatsLangCountry(const char* language, const char* country, UErrorCode& status) { | 
633  | 0  |     CharString langCountry;  | 
634  | 0  |     langCountry.append(language, status);  | 
635  | 0  |     langCountry.append('_', status); | 
636  | 0  |     langCountry.append(country, status);  | 
637  |  | 
  | 
638  | 0  |     int32_t* allowedFormats;  | 
639  | 0  |     allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, langCountry.data());  | 
640  | 0  |     if (allowedFormats == nullptr) { | 
641  | 0  |         allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, const_cast<char *>(country));  | 
642  | 0  |     }  | 
643  |  | 
  | 
644  | 0  |     return allowedFormats;  | 
645  | 0  | }  | 
646  |  |  | 
647  | 0  | void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErrorCode &status) { | 
648  | 0  |     if (U_FAILURE(status)) { return; } | 
649  |  |  | 
650  | 0  |     const char *language = locale.getLanguage();  | 
651  | 0  |     const char *country = locale.getCountry();  | 
652  | 0  |     Locale maxLocale;  // must be here for correct lifetime  | 
653  | 0  |     if (*language == '\0' || *country == '\0') { | 
654  | 0  |         maxLocale = locale;  | 
655  | 0  |         UErrorCode localStatus = U_ZERO_ERROR;  | 
656  | 0  |         maxLocale.addLikelySubtags(localStatus);  | 
657  | 0  |         if (U_SUCCESS(localStatus)) { | 
658  | 0  |             language = maxLocale.getLanguage();  | 
659  | 0  |             country = maxLocale.getCountry();  | 
660  | 0  |         }  | 
661  | 0  |     }  | 
662  | 0  |     if (*language == '\0') { | 
663  |  |         // Unexpected, but fail gracefully  | 
664  | 0  |         language = "und";  | 
665  | 0  |     }  | 
666  | 0  |     if (*country == '\0') { | 
667  | 0  |         country = "001";  | 
668  | 0  |     }  | 
669  |  | 
  | 
670  | 0  |     int32_t* allowedFormats = getAllowedHourFormatsLangCountry(language, country, status);  | 
671  |  |  | 
672  |  |     // We need to check if there is an hour cycle on locale  | 
673  | 0  |     char buffer[8];  | 
674  | 0  |     int32_t count = locale.getKeywordValue("hours", buffer, sizeof(buffer), status); | 
675  |  | 
  | 
676  | 0  |     fDefaultHourFormatChar = 0;  | 
677  | 0  |     if (U_SUCCESS(status) && count > 0) { | 
678  | 0  |         if(uprv_strcmp(buffer, "h24") == 0) { | 
679  | 0  |             fDefaultHourFormatChar = LOW_K;  | 
680  | 0  |         } else if(uprv_strcmp(buffer, "h23") == 0) { | 
681  | 0  |             fDefaultHourFormatChar = CAP_H;  | 
682  | 0  |         } else if(uprv_strcmp(buffer, "h12") == 0) { | 
683  | 0  |             fDefaultHourFormatChar = LOW_H;  | 
684  | 0  |         } else if(uprv_strcmp(buffer, "h11") == 0) { | 
685  | 0  |             fDefaultHourFormatChar = CAP_K;  | 
686  | 0  |         }  | 
687  | 0  |     }  | 
688  |  |  | 
689  |  |     // Check if the region has an alias  | 
690  | 0  |     if (allowedFormats == nullptr) { | 
691  | 0  |         UErrorCode localStatus = U_ZERO_ERROR;  | 
692  | 0  |         const Region* region = Region::getInstance(country, localStatus);  | 
693  | 0  |         if (U_SUCCESS(localStatus)) { | 
694  | 0  |             country = region->getRegionCode(); // the real region code  | 
695  | 0  |             allowedFormats = getAllowedHourFormatsLangCountry(language, country, status);  | 
696  | 0  |         }  | 
697  | 0  |     }  | 
698  |  | 
  | 
699  | 0  |     if (allowedFormats != nullptr) {  // Lookup is successful | 
700  |  |         // Here allowedFormats points to a list consisting of key for preferredFormat,  | 
701  |  |         // followed by one or more keys for allowedFormats, then followed by ALLOWED_HOUR_FORMAT_UNKNOWN.  | 
702  | 0  |         if (!fDefaultHourFormatChar) { | 
703  | 0  |             switch (allowedFormats[0]) { | 
704  | 0  |                 case ALLOWED_HOUR_FORMAT_h: fDefaultHourFormatChar = LOW_H; break;  | 
705  | 0  |                 case ALLOWED_HOUR_FORMAT_H: fDefaultHourFormatChar = CAP_H; break;  | 
706  | 0  |                 case ALLOWED_HOUR_FORMAT_K: fDefaultHourFormatChar = CAP_K; break;  | 
707  | 0  |                 case ALLOWED_HOUR_FORMAT_k: fDefaultHourFormatChar = LOW_K; break;  | 
708  | 0  |                 default: fDefaultHourFormatChar = CAP_H; break;  | 
709  | 0  |             }  | 
710  | 0  |         }  | 
711  |  |  | 
712  | 0  |         for (int32_t i = 0; i < UPRV_LENGTHOF(fAllowedHourFormats); ++i) { | 
713  | 0  |             fAllowedHourFormats[i] = allowedFormats[i + 1];  | 
714  | 0  |             if (fAllowedHourFormats[i] == ALLOWED_HOUR_FORMAT_UNKNOWN) { | 
715  | 0  |                 break;  | 
716  | 0  |             }  | 
717  | 0  |         }  | 
718  | 0  |     } else {  // Lookup failed, twice | 
719  | 0  |         if (!fDefaultHourFormatChar) { | 
720  | 0  |             fDefaultHourFormatChar = CAP_H;  | 
721  | 0  |         }  | 
722  | 0  |         fAllowedHourFormats[0] = ALLOWED_HOUR_FORMAT_H;  | 
723  | 0  |         fAllowedHourFormats[1] = ALLOWED_HOUR_FORMAT_UNKNOWN;  | 
724  | 0  |     }  | 
725  | 0  | }  | 
726  |  |  | 
727  |  | UDateFormatHourCycle  | 
728  | 0  | DateTimePatternGenerator::getDefaultHourCycle(UErrorCode& status) const { | 
729  | 0  |     if (U_FAILURE(status)) { | 
730  | 0  |         return UDAT_HOUR_CYCLE_23;  | 
731  | 0  |     }  | 
732  | 0  |     if (fDefaultHourFormatChar == 0) { | 
733  |  |         // We need to return something, but the caller should ignore it  | 
734  |  |         // anyways since the returned status is a failure.  | 
735  | 0  |         status = U_UNSUPPORTED_ERROR;  | 
736  | 0  |         return UDAT_HOUR_CYCLE_23;  | 
737  | 0  |     }  | 
738  | 0  |     switch (fDefaultHourFormatChar) { | 
739  | 0  |         case CAP_K:  | 
740  | 0  |             return UDAT_HOUR_CYCLE_11;  | 
741  | 0  |         case LOW_H:  | 
742  | 0  |             return UDAT_HOUR_CYCLE_12;  | 
743  | 0  |         case CAP_H:  | 
744  | 0  |             return UDAT_HOUR_CYCLE_23;  | 
745  | 0  |         case LOW_K:  | 
746  | 0  |             return UDAT_HOUR_CYCLE_24;  | 
747  | 0  |         default:  | 
748  | 0  |             UPRV_UNREACHABLE;  | 
749  | 0  |     }  | 
750  | 0  | }  | 
751  |  |  | 
752  |  | UnicodeString  | 
753  |  | DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode&  | 
754  | 0  | /*status*/) { | 
755  | 0  |     FormatParser fp2;  | 
756  | 0  |     DateTimeMatcher matcher;  | 
757  | 0  |     PtnSkeleton localSkeleton;  | 
758  | 0  |     matcher.set(pattern, &fp2, localSkeleton);  | 
759  | 0  |     return localSkeleton.getSkeleton();  | 
760  | 0  | }  | 
761  |  |  | 
762  |  | UnicodeString  | 
763  |  | DateTimePatternGenerator::staticGetSkeleton(  | 
764  | 0  |         const UnicodeString& pattern, UErrorCode& /*status*/) { | 
765  | 0  |     FormatParser fp;  | 
766  | 0  |     DateTimeMatcher matcher;  | 
767  | 0  |     PtnSkeleton localSkeleton;  | 
768  | 0  |     matcher.set(pattern, &fp, localSkeleton);  | 
769  | 0  |     return localSkeleton.getSkeleton();  | 
770  | 0  | }  | 
771  |  |  | 
772  |  | UnicodeString  | 
773  | 0  | DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) { | 
774  | 0  |     FormatParser fp2;  | 
775  | 0  |     DateTimeMatcher matcher;  | 
776  | 0  |     PtnSkeleton localSkeleton;  | 
777  | 0  |     matcher.set(pattern, &fp2, localSkeleton);  | 
778  | 0  |     return localSkeleton.getBaseSkeleton();  | 
779  | 0  | }  | 
780  |  |  | 
781  |  | UnicodeString  | 
782  |  | DateTimePatternGenerator::staticGetBaseSkeleton(  | 
783  | 0  |         const UnicodeString& pattern, UErrorCode& /*status*/) { | 
784  | 0  |     FormatParser fp;  | 
785  | 0  |     DateTimeMatcher matcher;  | 
786  | 0  |     PtnSkeleton localSkeleton;  | 
787  | 0  |     matcher.set(pattern, &fp, localSkeleton);  | 
788  | 0  |     return localSkeleton.getBaseSkeleton();  | 
789  | 0  | }  | 
790  |  |  | 
791  |  | void  | 
792  | 0  | DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& status) { | 
793  | 0  |     if (U_FAILURE(status)) { return; } | 
794  | 0  |     UnicodeString dfPattern;  | 
795  | 0  |     UnicodeString conflictingString;  | 
796  | 0  |     DateFormat* df;  | 
797  |  |  | 
798  |  |     // Load with ICU patterns  | 
799  | 0  |     for (int32_t i=DateFormat::kFull; i<=DateFormat::kShort; i++) { | 
800  | 0  |         DateFormat::EStyle style = (DateFormat::EStyle)i;  | 
801  | 0  |         df = DateFormat::createDateInstance(style, locale);  | 
802  | 0  |         SimpleDateFormat* sdf;  | 
803  | 0  |         if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) { | 
804  | 0  |             sdf->toPattern(dfPattern);  | 
805  | 0  |             addPattern(dfPattern, FALSE, conflictingString, status);  | 
806  | 0  |         }  | 
807  |  |         // TODO Maybe we should return an error when the date format isn't simple.  | 
808  | 0  |         delete df;  | 
809  | 0  |         if (U_FAILURE(status)) { return; } | 
810  |  |  | 
811  | 0  |         df = DateFormat::createTimeInstance(style, locale);  | 
812  | 0  |         if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) { | 
813  | 0  |             sdf->toPattern(dfPattern);  | 
814  | 0  |             addPattern(dfPattern, FALSE, conflictingString, status);  | 
815  |  |  | 
816  |  |             // TODO: C++ and Java are inconsistent (see #12568).  | 
817  |  |             // C++ uses MEDIUM, but Java uses SHORT.  | 
818  | 0  |             if ( i==DateFormat::kShort && !dfPattern.isEmpty() ) { | 
819  | 0  |                 consumeShortTimePattern(dfPattern, status);  | 
820  | 0  |             }  | 
821  | 0  |         }  | 
822  |  |         // TODO Maybe we should return an error when the date format isn't simple.  | 
823  | 0  |         delete df;  | 
824  | 0  |         if (U_FAILURE(status)) { return; } | 
825  | 0  |     }  | 
826  | 0  | }  | 
827  |  |  | 
828  |  | void  | 
829  | 0  | DateTimePatternGenerator::hackTimes(const UnicodeString& hackPattern, UErrorCode& status)  { | 
830  | 0  |     UnicodeString conflictingString;  | 
831  |  | 
  | 
832  | 0  |     fp->set(hackPattern);  | 
833  | 0  |     UnicodeString mmss;  | 
834  | 0  |     UBool gotMm=FALSE;  | 
835  | 0  |     for (int32_t i=0; i<fp->itemNumber; ++i) { | 
836  | 0  |         UnicodeString field = fp->items[i];  | 
837  | 0  |         if ( fp->isQuoteLiteral(field) ) { | 
838  | 0  |             if ( gotMm ) { | 
839  | 0  |                UnicodeString quoteLiteral;  | 
840  | 0  |                fp->getQuoteLiteral(quoteLiteral, &i);  | 
841  | 0  |                mmss += quoteLiteral;  | 
842  | 0  |             }  | 
843  | 0  |         }  | 
844  | 0  |         else { | 
845  | 0  |             if (fp->isPatternSeparator(field) && gotMm) { | 
846  | 0  |                 mmss+=field;  | 
847  | 0  |             }  | 
848  | 0  |             else { | 
849  | 0  |                 UChar ch=field.charAt(0);  | 
850  | 0  |                 if (ch==LOW_M) { | 
851  | 0  |                     gotMm=TRUE;  | 
852  | 0  |                     mmss+=field;  | 
853  | 0  |                 }  | 
854  | 0  |                 else { | 
855  | 0  |                     if (ch==LOW_S) { | 
856  | 0  |                         if (!gotMm) { | 
857  | 0  |                             break;  | 
858  | 0  |                         }  | 
859  | 0  |                         mmss+= field;  | 
860  | 0  |                         addPattern(mmss, FALSE, conflictingString, status);  | 
861  | 0  |                         break;  | 
862  | 0  |                     }  | 
863  | 0  |                     else { | 
864  | 0  |                         if (gotMm || ch==LOW_Z || ch==CAP_Z || ch==LOW_V || ch==CAP_V) { | 
865  | 0  |                             break;  | 
866  | 0  |                         }  | 
867  | 0  |                     }  | 
868  | 0  |                 }  | 
869  | 0  |             }  | 
870  | 0  |         }  | 
871  | 0  |     }  | 
872  | 0  | }  | 
873  |  |  | 
874  | 0  | #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)  | 
875  |  |  | 
876  |  | void  | 
877  | 0  | DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& destination, UErrorCode& err) { | 
878  | 0  |     destination.clear().append(DT_DateTimeGregorianTag, -1, err); // initial default  | 
879  | 0  |     if ( U_SUCCESS(err) ) { | 
880  | 0  |         UErrorCode localStatus = U_ZERO_ERROR;  | 
881  | 0  |         char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];  | 
882  |  |         // obtain a locale that always has the calendar key value that should be used  | 
883  | 0  |         ures_getFunctionalEquivalent(  | 
884  | 0  |             localeWithCalendarKey,  | 
885  | 0  |             ULOC_LOCALE_IDENTIFIER_CAPACITY,  | 
886  | 0  |             nullptr,  | 
887  | 0  |             "calendar",  | 
888  | 0  |             "calendar",  | 
889  | 0  |             locale.getName(),  | 
890  | 0  |             nullptr,  | 
891  | 0  |             FALSE,  | 
892  | 0  |             &localStatus);  | 
893  | 0  |         localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination  | 
894  |  |         // now get the calendar key value from that locale  | 
895  | 0  |         char calendarType[ULOC_KEYWORDS_CAPACITY];  | 
896  | 0  |         int32_t calendarTypeLen = uloc_getKeywordValue(  | 
897  | 0  |             localeWithCalendarKey,  | 
898  | 0  |             "calendar",  | 
899  | 0  |             calendarType,  | 
900  | 0  |             ULOC_KEYWORDS_CAPACITY,  | 
901  | 0  |             &localStatus);  | 
902  |  |         // If the input locale was invalid, don't fail with missing resource error, instead  | 
903  |  |         // continue with default of Gregorian.  | 
904  | 0  |         if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) { | 
905  | 0  |             err = localStatus;  | 
906  | 0  |             return;  | 
907  | 0  |         }  | 
908  | 0  |         if (calendarTypeLen > 0 && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { | 
909  | 0  |             destination.clear().append(calendarType, -1, err);  | 
910  | 0  |             if (U_FAILURE(err)) { return; } | 
911  | 0  |         }  | 
912  | 0  |     }  | 
913  | 0  | }  | 
914  |  |  | 
915  |  | void  | 
916  |  | DateTimePatternGenerator::consumeShortTimePattern(const UnicodeString& shortTimePattern,  | 
917  | 0  |         UErrorCode& status) { | 
918  | 0  |     if (U_FAILURE(status)) { return; } | 
919  |  |     // ICU-20383 No longer set fDefaultHourFormatChar to the hour format character from  | 
920  |  |     // this pattern; instead it is set from localeToAllowedHourFormatsMap which now  | 
921  |  |     // includes entries for both preferred and allowed formats.  | 
922  |  |  | 
923  |  |     // HACK for hh:ss  | 
924  | 0  |     hackTimes(shortTimePattern, status);  | 
925  | 0  | }  | 
926  |  |  | 
927  |  | struct DateTimePatternGenerator::AppendItemFormatsSink : public ResourceSink { | 
928  |  |  | 
929  |  |     // Destination for data, modified via setters.  | 
930  |  |     DateTimePatternGenerator& dtpg;  | 
931  |  |  | 
932  | 0  |     AppendItemFormatsSink(DateTimePatternGenerator& _dtpg) : dtpg(_dtpg) {} | 
933  |  |     virtual ~AppendItemFormatsSink();  | 
934  |  |  | 
935  |  |     virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,  | 
936  | 0  |             UErrorCode &errorCode) { | 
937  | 0  |         ResourceTable itemsTable = value.getTable(errorCode);  | 
938  | 0  |         if (U_FAILURE(errorCode)) { return; } | 
939  | 0  |         for (int32_t i = 0; itemsTable.getKeyAndValue(i, key, value); ++i) { | 
940  | 0  |             UDateTimePatternField field = dtpg.getAppendFormatNumber(key);  | 
941  | 0  |             if (field == UDATPG_FIELD_COUNT) { continue; } | 
942  | 0  |             const UnicodeString& valueStr = value.getUnicodeString(errorCode);  | 
943  | 0  |             if (dtpg.getAppendItemFormat(field).isEmpty() && !valueStr.isEmpty()) { | 
944  | 0  |                 dtpg.setAppendItemFormat(field, valueStr);  | 
945  | 0  |             }  | 
946  | 0  |         }  | 
947  | 0  |     }  | 
948  |  |  | 
949  | 0  |     void fillInMissing() { | 
950  | 0  |         UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, UPRV_LENGTHOF(UDATPG_ItemFormat)-1);  // Read-only alias.  | 
951  | 0  |         for (int32_t i = 0; i < UDATPG_FIELD_COUNT; i++) { | 
952  | 0  |             UDateTimePatternField field = (UDateTimePatternField)i;  | 
953  | 0  |             if (dtpg.getAppendItemFormat(field).isEmpty()) { | 
954  | 0  |                 dtpg.setAppendItemFormat(field, defaultItemFormat);  | 
955  | 0  |             }  | 
956  | 0  |         }  | 
957  | 0  |     }  | 
958  |  | };  | 
959  |  |  | 
960  |  | struct DateTimePatternGenerator::AppendItemNamesSink : public ResourceSink { | 
961  |  |  | 
962  |  |     // Destination for data, modified via setters.  | 
963  |  |     DateTimePatternGenerator& dtpg;  | 
964  |  |  | 
965  | 0  |     AppendItemNamesSink(DateTimePatternGenerator& _dtpg) : dtpg(_dtpg) {} | 
966  |  |     virtual ~AppendItemNamesSink();  | 
967  |  |  | 
968  |  |     virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,  | 
969  | 0  |             UErrorCode &errorCode) { | 
970  | 0  |         ResourceTable itemsTable = value.getTable(errorCode);  | 
971  | 0  |         if (U_FAILURE(errorCode)) { return; } | 
972  | 0  |         for (int32_t i = 0; itemsTable.getKeyAndValue(i, key, value); ++i) { | 
973  | 0  |             UDateTimePGDisplayWidth width;  | 
974  | 0  |             UDateTimePatternField field = dtpg.getFieldAndWidthIndices(key, &width);  | 
975  | 0  |             if (field == UDATPG_FIELD_COUNT) { continue; } | 
976  | 0  |             ResourceTable detailsTable = value.getTable(errorCode);  | 
977  | 0  |             if (U_FAILURE(errorCode)) { return; } | 
978  | 0  |             for (int32_t j = 0; detailsTable.getKeyAndValue(j, key, value); ++j) { | 
979  | 0  |                 if (uprv_strcmp(key, "dn") != 0) { continue; } | 
980  | 0  |                 const UnicodeString& valueStr = value.getUnicodeString(errorCode);  | 
981  | 0  |                 if (dtpg.getFieldDisplayName(field,width).isEmpty() && !valueStr.isEmpty()) { | 
982  | 0  |                     dtpg.setFieldDisplayName(field,width,valueStr);  | 
983  | 0  |                 }  | 
984  | 0  |                 break;  | 
985  | 0  |             }  | 
986  | 0  |         }  | 
987  | 0  |     }  | 
988  |  |  | 
989  | 0  |     void fillInMissing() { | 
990  | 0  |         for (int32_t i = 0; i < UDATPG_FIELD_COUNT; i++) { | 
991  | 0  |             UnicodeString& valueStr = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, UDATPG_WIDE);  | 
992  | 0  |             if (valueStr.isEmpty()) { | 
993  | 0  |                 valueStr = CAP_F;  | 
994  | 0  |                 U_ASSERT(i < 20);  | 
995  | 0  |                 if (i < 10) { | 
996  |  |                     // F0, F1, ..., F9  | 
997  | 0  |                     valueStr += (UChar)(i+0x30);  | 
998  | 0  |                 } else { | 
999  |  |                     // F10, F11, ...  | 
1000  | 0  |                     valueStr += (UChar)0x31;  | 
1001  | 0  |                     valueStr += (UChar)(i-10 + 0x30);  | 
1002  | 0  |                 }  | 
1003  |  |                 // NUL-terminate for the C API.  | 
1004  | 0  |                 valueStr.getTerminatedBuffer();  | 
1005  | 0  |             }  | 
1006  | 0  |             for (int32_t j = 1; j < UDATPG_WIDTH_COUNT; j++) { | 
1007  | 0  |                 UnicodeString& valueStr2 = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)j);  | 
1008  | 0  |                 if (valueStr2.isEmpty()) { | 
1009  | 0  |                     valueStr2 = dtpg.getFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)(j-1));  | 
1010  | 0  |                 }  | 
1011  | 0  |             }  | 
1012  | 0  |         }  | 
1013  | 0  |     }  | 
1014  |  | };  | 
1015  |  |  | 
1016  |  | struct DateTimePatternGenerator::AvailableFormatsSink : public ResourceSink { | 
1017  |  |  | 
1018  |  |     // Destination for data, modified via setters.  | 
1019  |  |     DateTimePatternGenerator& dtpg;  | 
1020  |  |  | 
1021  |  |     // Temporary variable, required for calling addPatternWithSkeleton.  | 
1022  |  |     UnicodeString conflictingPattern;  | 
1023  |  |  | 
1024  | 0  |     AvailableFormatsSink(DateTimePatternGenerator& _dtpg) : dtpg(_dtpg) {} | 
1025  |  |     virtual ~AvailableFormatsSink();  | 
1026  |  |  | 
1027  |  |     virtual void put(const char *key, ResourceValue &value, UBool isRoot,  | 
1028  | 0  |             UErrorCode &errorCode) { | 
1029  | 0  |         ResourceTable itemsTable = value.getTable(errorCode);  | 
1030  | 0  |         if (U_FAILURE(errorCode)) { return; } | 
1031  | 0  |         for (int32_t i = 0; itemsTable.getKeyAndValue(i, key, value); ++i) { | 
1032  | 0  |             const UnicodeString formatKey(key, -1, US_INV);  | 
1033  | 0  |             if (!dtpg.isAvailableFormatSet(formatKey) ) { | 
1034  | 0  |                 dtpg.setAvailableFormat(formatKey, errorCode);  | 
1035  |  |                 // Add pattern with its associated skeleton. Override any duplicate  | 
1036  |  |                 // derived from std patterns, but not a previous availableFormats entry:  | 
1037  | 0  |                 const UnicodeString& formatValue = value.getUnicodeString(errorCode);  | 
1038  | 0  |                 conflictingPattern.remove();  | 
1039  | 0  |                 dtpg.addPatternWithSkeleton(formatValue, &formatKey, !isRoot, conflictingPattern, errorCode);  | 
1040  | 0  |             }  | 
1041  | 0  |         }  | 
1042  | 0  |     }  | 
1043  |  | };  | 
1044  |  |  | 
1045  |  | // Virtual destructors must be defined out of line.  | 
1046  | 0  | DateTimePatternGenerator::AppendItemFormatsSink::~AppendItemFormatsSink() {} | 
1047  | 0  | DateTimePatternGenerator::AppendItemNamesSink::~AppendItemNamesSink() {} | 
1048  | 0  | DateTimePatternGenerator::AvailableFormatsSink::~AvailableFormatsSink() {} | 
1049  |  |  | 
1050  |  | void  | 
1051  | 0  | DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& errorCode) { | 
1052  | 0  |     if (U_FAILURE(errorCode)) { return; } | 
1053  | 0  |     UnicodeString rbPattern, value, field;  | 
1054  | 0  |     CharString path;  | 
1055  |  | 
  | 
1056  | 0  |     LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &errorCode));  | 
1057  | 0  |     if (U_FAILURE(errorCode)) { return; } | 
1058  |  |  | 
1059  | 0  |     CharString calendarTypeToUse; // to be filled in with the type to use, if all goes well  | 
1060  | 0  |     getCalendarTypeToUse(locale, calendarTypeToUse, errorCode);  | 
1061  | 0  |     if (U_FAILURE(errorCode)) { return; } | 
1062  |  |  | 
1063  |  |     // Local err to ignore resource not found exceptions  | 
1064  | 0  |     UErrorCode err = U_ZERO_ERROR;  | 
1065  |  |  | 
1066  |  |     // Load append item formats.  | 
1067  | 0  |     AppendItemFormatsSink appendItemFormatsSink(*this);  | 
1068  | 0  |     path.clear()  | 
1069  | 0  |         .append(DT_DateTimeCalendarTag, errorCode)  | 
1070  | 0  |         .append('/', errorCode) | 
1071  | 0  |         .append(calendarTypeToUse, errorCode)  | 
1072  | 0  |         .append('/', errorCode) | 
1073  | 0  |         .append(DT_DateTimeAppendItemsTag, errorCode); // i.e., calendar/xxx/appendItems  | 
1074  | 0  |     if (U_FAILURE(errorCode)) { return; } | 
1075  | 0  |     ures_getAllItemsWithFallback(rb.getAlias(), path.data(), appendItemFormatsSink, err);  | 
1076  | 0  |     appendItemFormatsSink.fillInMissing();  | 
1077  |  |  | 
1078  |  |     // Load CLDR item names.  | 
1079  | 0  |     err = U_ZERO_ERROR;  | 
1080  | 0  |     AppendItemNamesSink appendItemNamesSink(*this);  | 
1081  | 0  |     ures_getAllItemsWithFallback(rb.getAlias(), DT_DateTimeFieldsTag, appendItemNamesSink, err);  | 
1082  | 0  |     appendItemNamesSink.fillInMissing();  | 
1083  |  |  | 
1084  |  |     // Load the available formats from CLDR.  | 
1085  | 0  |     err = U_ZERO_ERROR;  | 
1086  | 0  |     initHashtable(errorCode);  | 
1087  | 0  |     if (U_FAILURE(errorCode)) { return; } | 
1088  | 0  |     AvailableFormatsSink availableFormatsSink(*this);  | 
1089  | 0  |     path.clear()  | 
1090  | 0  |         .append(DT_DateTimeCalendarTag, errorCode)  | 
1091  | 0  |         .append('/', errorCode) | 
1092  | 0  |         .append(calendarTypeToUse, errorCode)  | 
1093  | 0  |         .append('/', errorCode) | 
1094  | 0  |         .append(DT_DateTimeAvailableFormatsTag, errorCode); // i.e., calendar/xxx/availableFormats  | 
1095  | 0  |     if (U_FAILURE(errorCode)) { return; } | 
1096  | 0  |     ures_getAllItemsWithFallback(rb.getAlias(), path.data(), availableFormatsSink, err);  | 
1097  | 0  | }  | 
1098  |  |  | 
1099  |  | void  | 
1100  | 0  | DateTimePatternGenerator::initHashtable(UErrorCode& err) { | 
1101  | 0  |     if (U_FAILURE(err)) { return; } | 
1102  | 0  |     if (fAvailableFormatKeyHash!=nullptr) { | 
1103  | 0  |         return;  | 
1104  | 0  |     }  | 
1105  | 0  |     LocalPointer<Hashtable> hash(new Hashtable(FALSE, err), err);  | 
1106  | 0  |     if (U_SUCCESS(err)) { | 
1107  | 0  |         fAvailableFormatKeyHash = hash.orphan();  | 
1108  | 0  |     }  | 
1109  | 0  | }  | 
1110  |  |  | 
1111  |  | void  | 
1112  | 0  | DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value) { | 
1113  | 0  |     appendItemFormats[field] = value;  | 
1114  |  |     // NUL-terminate for the C API.  | 
1115  | 0  |     appendItemFormats[field].getTerminatedBuffer();  | 
1116  | 0  | }  | 
1117  |  |  | 
1118  |  | const UnicodeString&  | 
1119  | 0  | DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const { | 
1120  | 0  |     return appendItemFormats[field];  | 
1121  | 0  | }  | 
1122  |  |  | 
1123  |  | void  | 
1124  | 0  | DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) { | 
1125  | 0  |     setFieldDisplayName(field, UDATPG_WIDTH_APPENDITEM, value);  | 
1126  | 0  | }  | 
1127  |  |  | 
1128  |  | const UnicodeString&  | 
1129  | 0  | DateTimePatternGenerator::getAppendItemName(UDateTimePatternField field) const { | 
1130  | 0  |     return fieldDisplayNames[field][UDATPG_WIDTH_APPENDITEM];  | 
1131  | 0  | }  | 
1132  |  |  | 
1133  |  | void  | 
1134  | 0  | DateTimePatternGenerator::setFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width, const UnicodeString& value) { | 
1135  | 0  |     fieldDisplayNames[field][width] = value;  | 
1136  |  |     // NUL-terminate for the C API.  | 
1137  | 0  |     fieldDisplayNames[field][width].getTerminatedBuffer();  | 
1138  | 0  | }  | 
1139  |  |  | 
1140  |  | UnicodeString  | 
1141  | 0  | DateTimePatternGenerator::getFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width) const { | 
1142  | 0  |     return fieldDisplayNames[field][width];  | 
1143  | 0  | }  | 
1144  |  |  | 
1145  |  | UnicodeString&  | 
1146  | 0  | DateTimePatternGenerator::getMutableFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width) { | 
1147  | 0  |     return fieldDisplayNames[field][width];  | 
1148  | 0  | }  | 
1149  |  |  | 
1150  |  | void  | 
1151  | 0  | DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) { | 
1152  | 0  |     value = SINGLE_QUOTE;  | 
1153  | 0  |     value += fieldDisplayNames[field][UDATPG_WIDTH_APPENDITEM];  | 
1154  | 0  |     value += SINGLE_QUOTE;  | 
1155  | 0  | }  | 
1156  |  |  | 
1157  |  | UnicodeString  | 
1158  | 0  | DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErrorCode& status) { | 
1159  | 0  |     return getBestPattern(patternForm, UDATPG_MATCH_NO_OPTIONS, status);  | 
1160  | 0  | }  | 
1161  |  |  | 
1162  |  | UnicodeString  | 
1163  | 0  | DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, UErrorCode& status) { | 
1164  | 0  |     if (U_FAILURE(status)) { | 
1165  | 0  |         return UnicodeString();  | 
1166  | 0  |     }  | 
1167  | 0  |     if (U_FAILURE(internalErrorCode)) { | 
1168  | 0  |         status = internalErrorCode;  | 
1169  | 0  |         return UnicodeString();  | 
1170  | 0  |     }  | 
1171  | 0  |     const UnicodeString *bestPattern = nullptr;  | 
1172  | 0  |     UnicodeString dtFormat;  | 
1173  | 0  |     UnicodeString resultPattern;  | 
1174  | 0  |     int32_t flags = kDTPGNoFlags;  | 
1175  |  | 
  | 
1176  | 0  |     int32_t dateMask=(1<<UDATPG_DAYPERIOD_FIELD) - 1;  | 
1177  | 0  |     int32_t timeMask=(1<<UDATPG_FIELD_COUNT) - 1 - dateMask;  | 
1178  |  |  | 
1179  |  |     // Replace hour metacharacters 'j', 'C' and 'J', set flags as necessary  | 
1180  | 0  |     UnicodeString patternFormMapped = mapSkeletonMetacharacters(patternForm, &flags, status);  | 
1181  | 0  |     if (U_FAILURE(status)) { | 
1182  | 0  |         return UnicodeString();  | 
1183  | 0  |     }  | 
1184  |  |  | 
1185  | 0  |     resultPattern.remove();  | 
1186  | 0  |     dtMatcher->set(patternFormMapped, fp);  | 
1187  | 0  |     const PtnSkeleton* specifiedSkeleton = nullptr;  | 
1188  | 0  |     bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, status, &specifiedSkeleton);  | 
1189  | 0  |     if (U_FAILURE(status)) { | 
1190  | 0  |         return UnicodeString();  | 
1191  | 0  |     }  | 
1192  |  |  | 
1193  | 0  |     if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) { | 
1194  | 0  |         resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, flags, options);  | 
1195  |  | 
  | 
1196  | 0  |         return resultPattern;  | 
1197  | 0  |     }  | 
1198  | 0  |     int32_t neededFields = dtMatcher->getFieldMask();  | 
1199  | 0  |     UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, status, options);  | 
1200  | 0  |     UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, status, options);  | 
1201  | 0  |     if (U_FAILURE(status)) { | 
1202  | 0  |         return UnicodeString();  | 
1203  | 0  |     }  | 
1204  | 0  |     if (datePattern.length()==0) { | 
1205  | 0  |         if (timePattern.length()==0) { | 
1206  | 0  |             resultPattern.remove();  | 
1207  | 0  |         }  | 
1208  | 0  |         else { | 
1209  | 0  |             return timePattern;  | 
1210  | 0  |         }  | 
1211  | 0  |     }  | 
1212  | 0  |     if (timePattern.length()==0) { | 
1213  | 0  |         return datePattern;  | 
1214  | 0  |     }  | 
1215  | 0  |     resultPattern.remove();  | 
1216  | 0  |     status = U_ZERO_ERROR;  | 
1217  | 0  |     dtFormat=getDateTimeFormat();  | 
1218  | 0  |     SimpleFormatter(dtFormat, 2, 2, status).format(timePattern, datePattern, resultPattern, status);  | 
1219  | 0  |     return resultPattern;  | 
1220  | 0  | }  | 
1221  |  |  | 
1222  |  | /*  | 
1223  |  |  * Map a skeleton that may have metacharacters jJC to one without, by replacing  | 
1224  |  |  * the metacharacters with locale-appropriate fields of h/H/k/K and of a/b/B  | 
1225  |  |  * (depends on fDefaultHourFormatChar and fAllowedHourFormats being set, which in  | 
1226  |  |  * turn depends on initData having been run). This method also updates the flags  | 
1227  |  |  * as necessary. Returns the updated skeleton.  | 
1228  |  |  */  | 
1229  |  | UnicodeString  | 
1230  | 0  | DateTimePatternGenerator::mapSkeletonMetacharacters(const UnicodeString& patternForm, int32_t* flags, UErrorCode& status) { | 
1231  | 0  |     UnicodeString patternFormMapped;  | 
1232  | 0  |     patternFormMapped.remove();  | 
1233  | 0  |     UBool inQuoted = FALSE;  | 
1234  | 0  |     int32_t patPos, patLen = patternForm.length();  | 
1235  | 0  |     for (patPos = 0; patPos < patLen; patPos++) { | 
1236  | 0  |         UChar patChr = patternForm.charAt(patPos);  | 
1237  | 0  |         if (patChr == SINGLE_QUOTE) { | 
1238  | 0  |             inQuoted = !inQuoted;  | 
1239  | 0  |         } else if (!inQuoted) { | 
1240  |  |             // Handle special mappings for 'j' and 'C' in which fields lengths  | 
1241  |  |             // 1,3,5 => hour field length 1  | 
1242  |  |             // 2,4,6 => hour field length 2  | 
1243  |  |             // 1,2 => abbreviated dayPeriod (field length 1..3)  | 
1244  |  |             // 3,4 => long dayPeriod (field length 4)  | 
1245  |  |             // 5,6 => narrow dayPeriod (field length 5)  | 
1246  | 0  |             if (patChr == LOW_J || patChr == CAP_C) { | 
1247  | 0  |                 int32_t extraLen = 0; // 1 less than total field length  | 
1248  | 0  |                 while (patPos+1 < patLen && patternForm.charAt(patPos+1)==patChr) { | 
1249  | 0  |                     extraLen++;  | 
1250  | 0  |                     patPos++;  | 
1251  | 0  |                 }  | 
1252  | 0  |                 int32_t hourLen = 1 + (extraLen & 1);  | 
1253  | 0  |                 int32_t dayPeriodLen = (extraLen < 2)? 1: 3 + (extraLen >> 1);  | 
1254  | 0  |                 UChar hourChar = LOW_H;  | 
1255  | 0  |                 UChar dayPeriodChar = LOW_A;  | 
1256  | 0  |                 if (patChr == LOW_J) { | 
1257  | 0  |                     hourChar = fDefaultHourFormatChar;  | 
1258  | 0  |                 } else { | 
1259  | 0  |                     AllowedHourFormat bestAllowed;  | 
1260  | 0  |                     if (fAllowedHourFormats[0] != ALLOWED_HOUR_FORMAT_UNKNOWN) { | 
1261  | 0  |                         bestAllowed = (AllowedHourFormat)fAllowedHourFormats[0];  | 
1262  | 0  |                     } else { | 
1263  | 0  |                         status = U_INVALID_FORMAT_ERROR;  | 
1264  | 0  |                         return UnicodeString();  | 
1265  | 0  |                     }  | 
1266  | 0  |                     if (bestAllowed == ALLOWED_HOUR_FORMAT_H || bestAllowed == ALLOWED_HOUR_FORMAT_HB || bestAllowed == ALLOWED_HOUR_FORMAT_Hb) { | 
1267  | 0  |                         hourChar = CAP_H;  | 
1268  | 0  |                     } else if (bestAllowed == ALLOWED_HOUR_FORMAT_K || bestAllowed == ALLOWED_HOUR_FORMAT_KB || bestAllowed == ALLOWED_HOUR_FORMAT_Kb) { | 
1269  | 0  |                         hourChar = CAP_K;  | 
1270  | 0  |                     } else if (bestAllowed == ALLOWED_HOUR_FORMAT_k) { | 
1271  | 0  |                         hourChar = LOW_K;  | 
1272  | 0  |                     }  | 
1273  |  |                     // in #13183 just add b/B to skeleton, no longer need to set special flags  | 
1274  | 0  |                     if (bestAllowed == ALLOWED_HOUR_FORMAT_HB || bestAllowed == ALLOWED_HOUR_FORMAT_hB || bestAllowed == ALLOWED_HOUR_FORMAT_KB) { | 
1275  | 0  |                         dayPeriodChar = CAP_B;  | 
1276  | 0  |                     } else if (bestAllowed == ALLOWED_HOUR_FORMAT_Hb || bestAllowed == ALLOWED_HOUR_FORMAT_hb || bestAllowed == ALLOWED_HOUR_FORMAT_Kb) { | 
1277  | 0  |                         dayPeriodChar = LOW_B;  | 
1278  | 0  |                     }  | 
1279  | 0  |                 }  | 
1280  | 0  |                 if (hourChar==CAP_H || hourChar==LOW_K) { | 
1281  | 0  |                     dayPeriodLen = 0;  | 
1282  | 0  |                 }  | 
1283  | 0  |                 while (dayPeriodLen-- > 0) { | 
1284  | 0  |                     patternFormMapped.append(dayPeriodChar);  | 
1285  | 0  |                 }  | 
1286  | 0  |                 while (hourLen-- > 0) { | 
1287  | 0  |                     patternFormMapped.append(hourChar);  | 
1288  | 0  |                 }  | 
1289  | 0  |             } else if (patChr == CAP_J) { | 
1290  |  |                 // Get pattern for skeleton with H, then replace H or k  | 
1291  |  |                 // with fDefaultHourFormatChar (if different)  | 
1292  | 0  |                 patternFormMapped.append(CAP_H);  | 
1293  | 0  |                 *flags |= kDTPGSkeletonUsesCapJ;  | 
1294  | 0  |             } else { | 
1295  | 0  |                 patternFormMapped.append(patChr);  | 
1296  | 0  |             }  | 
1297  | 0  |         }  | 
1298  | 0  |     }  | 
1299  | 0  |     return patternFormMapped;  | 
1300  | 0  | }  | 
1301  |  |  | 
1302  |  | UnicodeString  | 
1303  |  | DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,  | 
1304  |  |                                             const UnicodeString& skeleton,  | 
1305  | 0  |                                             UErrorCode& status) { | 
1306  | 0  |     return replaceFieldTypes(pattern, skeleton, UDATPG_MATCH_NO_OPTIONS, status);  | 
1307  | 0  | }  | 
1308  |  |  | 
1309  |  | UnicodeString  | 
1310  |  | DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,  | 
1311  |  |                                             const UnicodeString& skeleton,  | 
1312  |  |                                             UDateTimePatternMatchOptions options,  | 
1313  | 0  |                                             UErrorCode& status) { | 
1314  | 0  |     if (U_FAILURE(status)) { | 
1315  | 0  |         return UnicodeString();  | 
1316  | 0  |     }  | 
1317  | 0  |     if (U_FAILURE(internalErrorCode)) { | 
1318  | 0  |         status = internalErrorCode;  | 
1319  | 0  |         return UnicodeString();  | 
1320  | 0  |     }  | 
1321  | 0  |     dtMatcher->set(skeleton, fp);  | 
1322  | 0  |     UnicodeString result = adjustFieldTypes(pattern, nullptr, kDTPGNoFlags, options);  | 
1323  | 0  |     return result;  | 
1324  | 0  | }  | 
1325  |  |  | 
1326  |  | void  | 
1327  | 0  | DateTimePatternGenerator::setDecimal(const UnicodeString& newDecimal) { | 
1328  | 0  |     this->decimal = newDecimal;  | 
1329  |  |     // NUL-terminate for the C API.  | 
1330  | 0  |     this->decimal.getTerminatedBuffer();  | 
1331  | 0  | }  | 
1332  |  |  | 
1333  |  | const UnicodeString&  | 
1334  | 0  | DateTimePatternGenerator::getDecimal() const { | 
1335  | 0  |     return decimal;  | 
1336  | 0  | }  | 
1337  |  |  | 
1338  |  | void  | 
1339  | 0  | DateTimePatternGenerator::addCanonicalItems(UErrorCode& status) { | 
1340  | 0  |     if (U_FAILURE(status)) { return; } | 
1341  | 0  |     UnicodeString  conflictingPattern;  | 
1342  |  | 
  | 
1343  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; i++) { | 
1344  | 0  |         if (Canonical_Items[i] > 0) { | 
1345  | 0  |             addPattern(UnicodeString(Canonical_Items[i]), FALSE, conflictingPattern, status);  | 
1346  | 0  |         }  | 
1347  | 0  |         if (U_FAILURE(status)) { return; } | 
1348  | 0  |     }  | 
1349  | 0  | }  | 
1350  |  |  | 
1351  |  | void  | 
1352  | 0  | DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) { | 
1353  | 0  |     dateTimeFormat = dtFormat;  | 
1354  |  |     // NUL-terminate for the C API.  | 
1355  | 0  |     dateTimeFormat.getTerminatedBuffer();  | 
1356  | 0  | }  | 
1357  |  |  | 
1358  |  | const UnicodeString&  | 
1359  | 0  | DateTimePatternGenerator::getDateTimeFormat() const { | 
1360  | 0  |     return dateTimeFormat;  | 
1361  | 0  | }  | 
1362  |  |  | 
1363  |  | void  | 
1364  | 0  | DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) { | 
1365  | 0  |     if (U_FAILURE(status)) { return; } | 
1366  |  |  | 
1367  | 0  |     const UChar *resStr;  | 
1368  | 0  |     int32_t resStrLen = 0;  | 
1369  |  | 
  | 
1370  | 0  |     LocalPointer<Calendar> fCalendar(Calendar::createInstance(locale, status), status);  | 
1371  | 0  |     if (U_FAILURE(status)) { return; } | 
1372  |  |  | 
1373  | 0  |     LocalUResourceBundlePointer calData(ures_open(nullptr, locale.getBaseName(), &status));  | 
1374  | 0  |     if (U_FAILURE(status)) { return; } | 
1375  | 0  |     ures_getByKey(calData.getAlias(), DT_DateTimeCalendarTag, calData.getAlias(), &status);  | 
1376  | 0  |     if (U_FAILURE(status)) { return; } | 
1377  |  |  | 
1378  | 0  |     LocalUResourceBundlePointer dateTimePatterns;  | 
1379  | 0  |     if (fCalendar->getType() != nullptr && *fCalendar->getType() != '\0'  | 
1380  | 0  |             && uprv_strcmp(fCalendar->getType(), DT_DateTimeGregorianTag) != 0) { | 
1381  | 0  |         dateTimePatterns.adoptInstead(ures_getByKeyWithFallback(calData.getAlias(), fCalendar->getType(),  | 
1382  | 0  |                                                                 nullptr, &status));  | 
1383  | 0  |         ures_getByKeyWithFallback(dateTimePatterns.getAlias(), DT_DateTimePatternsTag,  | 
1384  | 0  |                                   dateTimePatterns.getAlias(), &status);  | 
1385  | 0  |     }  | 
1386  |  | 
  | 
1387  | 0  |     if (dateTimePatterns.isNull() || status == U_MISSING_RESOURCE_ERROR) { | 
1388  | 0  |         status = U_ZERO_ERROR;  | 
1389  | 0  |         dateTimePatterns.adoptInstead(ures_getByKeyWithFallback(calData.getAlias(), DT_DateTimeGregorianTag,  | 
1390  | 0  |                                                                 dateTimePatterns.orphan(), &status));  | 
1391  | 0  |         ures_getByKeyWithFallback(dateTimePatterns.getAlias(), DT_DateTimePatternsTag,  | 
1392  | 0  |                                   dateTimePatterns.getAlias(), &status);  | 
1393  | 0  |     }  | 
1394  | 0  |     if (U_FAILURE(status)) { return; } | 
1395  |  |  | 
1396  | 0  |     if (ures_getSize(dateTimePatterns.getAlias()) <= DateFormat::kDateTime)  | 
1397  | 0  |     { | 
1398  | 0  |         status = U_INVALID_FORMAT_ERROR;  | 
1399  | 0  |         return;  | 
1400  | 0  |     }  | 
1401  | 0  |     resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), (int32_t)DateFormat::kDateTime, &resStrLen, &status);  | 
1402  | 0  |     setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen));  | 
1403  | 0  | }  | 
1404  |  |  | 
1405  |  | void  | 
1406  | 0  | DateTimePatternGenerator::setDecimalSymbols(const Locale& locale, UErrorCode& status) { | 
1407  | 0  |     DecimalFormatSymbols dfs = DecimalFormatSymbols(locale, status);  | 
1408  | 0  |     if(U_SUCCESS(status)) { | 
1409  | 0  |         decimal = dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);  | 
1410  |  |         // NUL-terminate for the C API.  | 
1411  | 0  |         decimal.getTerminatedBuffer();  | 
1412  | 0  |     }  | 
1413  | 0  | }  | 
1414  |  |  | 
1415  |  | UDateTimePatternConflict  | 
1416  |  | DateTimePatternGenerator::addPattern(  | 
1417  |  |     const UnicodeString& pattern,  | 
1418  |  |     UBool override,  | 
1419  |  |     UnicodeString &conflictingPattern,  | 
1420  |  |     UErrorCode& status)  | 
1421  | 0  | { | 
1422  | 0  |     if (U_FAILURE(internalErrorCode)) { | 
1423  | 0  |         status = internalErrorCode;  | 
1424  | 0  |         return UDATPG_NO_CONFLICT;  | 
1425  | 0  |     }  | 
1426  |  |  | 
1427  | 0  |     return addPatternWithSkeleton(pattern, nullptr, override, conflictingPattern, status);  | 
1428  | 0  | }  | 
1429  |  |  | 
1430  |  | // For DateTimePatternGenerator::addPatternWithSkeleton -  | 
1431  |  | // If skeletonToUse is specified, then an availableFormats entry is being added. In this case:  | 
1432  |  | // 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern.  | 
1433  |  | // 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified  | 
1434  |  | // (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override  | 
1435  |  | // parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual  | 
1436  |  | // specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was  | 
1437  |  | // derived (i.e. entries derived from the standard date/time patters for the specified locale).  | 
1438  |  | // 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a  | 
1439  |  | // specified skeleton (which sets a new field in the PtnElem in the PatternMap).  | 
1440  |  | UDateTimePatternConflict  | 
1441  |  | DateTimePatternGenerator::addPatternWithSkeleton(  | 
1442  |  |     const UnicodeString& pattern,  | 
1443  |  |     const UnicodeString* skeletonToUse,  | 
1444  |  |     UBool override,  | 
1445  |  |     UnicodeString& conflictingPattern,  | 
1446  |  |     UErrorCode& status)  | 
1447  | 0  | { | 
1448  | 0  |     if (U_FAILURE(internalErrorCode)) { | 
1449  | 0  |         status = internalErrorCode;  | 
1450  | 0  |         return UDATPG_NO_CONFLICT;  | 
1451  | 0  |     }  | 
1452  |  |  | 
1453  | 0  |     UnicodeString basePattern;  | 
1454  | 0  |     PtnSkeleton   skeleton;  | 
1455  | 0  |     UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;  | 
1456  |  | 
  | 
1457  | 0  |     DateTimeMatcher matcher;  | 
1458  | 0  |     if ( skeletonToUse == nullptr ) { | 
1459  | 0  |         matcher.set(pattern, fp, skeleton);  | 
1460  | 0  |         matcher.getBasePattern(basePattern);  | 
1461  | 0  |     } else { | 
1462  | 0  |         matcher.set(*skeletonToUse, fp, skeleton); // no longer trims skeleton fields to max len 3, per #7930  | 
1463  | 0  |         matcher.getBasePattern(basePattern); // or perhaps instead: basePattern = *skeletonToUse;  | 
1464  | 0  |     }  | 
1465  |  |     // We only care about base conflicts - and replacing the pattern associated with a base - if:  | 
1466  |  |     // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous  | 
1467  |  |     // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or  | 
1468  |  |     // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen  | 
1469  |  |     // if we are getting here from a subsequent call to addPattern).  | 
1470  |  |     // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking  | 
1471  |  |     // availableFormats items from root, which should not override any previous entry with the same base.  | 
1472  | 0  |     UBool entryHadSpecifiedSkeleton;  | 
1473  | 0  |     const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton);  | 
1474  | 0  |     if (duplicatePattern != nullptr && (!entryHadSpecifiedSkeleton || (skeletonToUse != nullptr && !override))) { | 
1475  | 0  |         conflictingStatus = UDATPG_BASE_CONFLICT;  | 
1476  | 0  |         conflictingPattern = *duplicatePattern;  | 
1477  | 0  |         if (!override) { | 
1478  | 0  |             return conflictingStatus;  | 
1479  | 0  |         }  | 
1480  | 0  |     }  | 
1481  |  |     // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats  | 
1482  |  |     // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with  | 
1483  |  |     // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for  | 
1484  |  |     // the previously-specified conflicting item.  | 
1485  | 0  |     const PtnSkeleton* entrySpecifiedSkeleton = nullptr;  | 
1486  | 0  |     duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton);  | 
1487  | 0  |     if (duplicatePattern != nullptr ) { | 
1488  | 0  |         conflictingStatus = UDATPG_CONFLICT;  | 
1489  | 0  |         conflictingPattern = *duplicatePattern;  | 
1490  | 0  |         if (!override || (skeletonToUse != nullptr && entrySpecifiedSkeleton != nullptr)) { | 
1491  | 0  |             return conflictingStatus;  | 
1492  | 0  |         }  | 
1493  | 0  |     }  | 
1494  | 0  |     patternMap->add(basePattern, skeleton, pattern, skeletonToUse != nullptr, status);  | 
1495  | 0  |     if(U_FAILURE(status)) { | 
1496  | 0  |         return conflictingStatus;  | 
1497  | 0  |     }  | 
1498  |  |  | 
1499  | 0  |     return UDATPG_NO_CONFLICT;  | 
1500  | 0  | }  | 
1501  |  |  | 
1502  |  |  | 
1503  |  | UDateTimePatternField  | 
1504  | 0  | DateTimePatternGenerator::getAppendFormatNumber(const char* field) const { | 
1505  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { | 
1506  | 0  |         if (uprv_strcmp(CLDR_FIELD_APPEND[i], field)==0) { | 
1507  | 0  |             return (UDateTimePatternField)i;  | 
1508  | 0  |         }  | 
1509  | 0  |     }  | 
1510  | 0  |     return UDATPG_FIELD_COUNT;  | 
1511  | 0  | }  | 
1512  |  |  | 
1513  |  | UDateTimePatternField  | 
1514  | 0  | DateTimePatternGenerator::getFieldAndWidthIndices(const char* key, UDateTimePGDisplayWidth* widthP) const { | 
1515  | 0  |     char cldrFieldKey[UDATPG_FIELD_KEY_MAX + 1];  | 
1516  | 0  |     uprv_strncpy(cldrFieldKey, key, UDATPG_FIELD_KEY_MAX);  | 
1517  | 0  |     cldrFieldKey[UDATPG_FIELD_KEY_MAX]=0; // ensure termination  | 
1518  | 0  |     *widthP = UDATPG_WIDE;  | 
1519  | 0  |     char* hyphenPtr = uprv_strchr(cldrFieldKey, '-');  | 
1520  | 0  |     if (hyphenPtr) { | 
1521  | 0  |         for (int32_t i=UDATPG_WIDTH_COUNT-1; i>0; --i) { | 
1522  | 0  |             if (uprv_strcmp(CLDR_FIELD_WIDTH[i], hyphenPtr)==0) { | 
1523  | 0  |                 *widthP=(UDateTimePGDisplayWidth)i;  | 
1524  | 0  |                 break;  | 
1525  | 0  |             }  | 
1526  | 0  |         }  | 
1527  | 0  |         *hyphenPtr = 0; // now delete width portion of key  | 
1528  | 0  |     }  | 
1529  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { | 
1530  | 0  |         if (uprv_strcmp(CLDR_FIELD_NAME[i],cldrFieldKey)==0) { | 
1531  | 0  |             return (UDateTimePatternField)i;  | 
1532  | 0  |         }  | 
1533  | 0  |     }  | 
1534  | 0  |     return UDATPG_FIELD_COUNT;  | 
1535  | 0  | }  | 
1536  |  |  | 
1537  |  | const UnicodeString*  | 
1538  |  | DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source,  | 
1539  |  |                                      int32_t includeMask,  | 
1540  |  |                                      DistanceInfo* missingFields,  | 
1541  |  |                                      UErrorCode &status,  | 
1542  | 0  |                                      const PtnSkeleton** specifiedSkeletonPtr) { | 
1543  | 0  |     int32_t bestDistance = 0x7fffffff;  | 
1544  | 0  |     int32_t bestMissingFieldMask = -1;  | 
1545  | 0  |     DistanceInfo tempInfo;  | 
1546  | 0  |     const UnicodeString *bestPattern=nullptr;  | 
1547  | 0  |     const PtnSkeleton* specifiedSkeleton=nullptr;  | 
1548  |  | 
  | 
1549  | 0  |     PatternMapIterator it(status);  | 
1550  | 0  |     if (U_FAILURE(status)) { return nullptr; } | 
1551  |  |  | 
1552  | 0  |     for (it.set(*patternMap); it.hasNext(); ) { | 
1553  | 0  |         DateTimeMatcher trial = it.next();  | 
1554  | 0  |         if (trial.equals(skipMatcher)) { | 
1555  | 0  |             continue;  | 
1556  | 0  |         }  | 
1557  | 0  |         int32_t distance=source.getDistance(trial, includeMask, tempInfo);  | 
1558  |  |         // Because we iterate over a map the order is undefined. Can change between implementations,  | 
1559  |  |         // versions, and will very likely be different between Java and C/C++.  | 
1560  |  |         // So if we have patterns with the same distance we also look at the missingFieldMask,  | 
1561  |  |         // and we favour the smallest one. Because the field is a bitmask this technically means we  | 
1562  |  |         // favour differences in the "least significant fields". For example we prefer the one with differences  | 
1563  |  |         // in seconds field vs one with difference in the hours field.  | 
1564  | 0  |         if (distance<bestDistance || (distance==bestDistance && bestMissingFieldMask<tempInfo.missingFieldMask)) { | 
1565  | 0  |             bestDistance=distance;  | 
1566  | 0  |             bestMissingFieldMask=tempInfo.missingFieldMask;  | 
1567  | 0  |             bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr(), &specifiedSkeleton);  | 
1568  | 0  |             missingFields->setTo(tempInfo);  | 
1569  | 0  |             if (distance==0) { | 
1570  | 0  |                 break;  | 
1571  | 0  |             }  | 
1572  | 0  |         }  | 
1573  | 0  |     }  | 
1574  |  |  | 
1575  |  |     // If the best raw match had a specified skeleton and that skeleton was requested by the caller,  | 
1576  |  |     // then return it too. This generally happens when the caller needs to pass that skeleton  | 
1577  |  |     // through to adjustFieldTypes so the latter can do a better job.  | 
1578  | 0  |     if (bestPattern && specifiedSkeletonPtr) { | 
1579  | 0  |         *specifiedSkeletonPtr = specifiedSkeleton;  | 
1580  | 0  |     }  | 
1581  | 0  |     return bestPattern;  | 
1582  | 0  | }  | 
1583  |  |  | 
1584  |  | UnicodeString  | 
1585  |  | DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,  | 
1586  |  |                                            const PtnSkeleton* specifiedSkeleton,  | 
1587  |  |                                            int32_t flags,  | 
1588  | 0  |                                            UDateTimePatternMatchOptions options) { | 
1589  | 0  |     UnicodeString newPattern;  | 
1590  | 0  |     fp->set(pattern);  | 
1591  | 0  |     for (int32_t i=0; i < fp->itemNumber; i++) { | 
1592  | 0  |         UnicodeString field = fp->items[i];  | 
1593  | 0  |         if ( fp->isQuoteLiteral(field) ) { | 
1594  |  | 
  | 
1595  | 0  |             UnicodeString quoteLiteral;  | 
1596  | 0  |             fp->getQuoteLiteral(quoteLiteral, &i);  | 
1597  | 0  |             newPattern += quoteLiteral;  | 
1598  | 0  |         }  | 
1599  | 0  |         else { | 
1600  | 0  |             if (fp->isPatternSeparator(field)) { | 
1601  | 0  |                 newPattern+=field;  | 
1602  | 0  |                 continue;  | 
1603  | 0  |             }  | 
1604  | 0  |             int32_t canonicalIndex = fp->getCanonicalIndex(field);  | 
1605  | 0  |             if (canonicalIndex < 0) { | 
1606  | 0  |                 newPattern+=field;  | 
1607  | 0  |                 continue;  // don't adjust  | 
1608  | 0  |             }  | 
1609  | 0  |             const dtTypeElem *row = &dtTypes[canonicalIndex];  | 
1610  | 0  |             int32_t typeValue = row->field;  | 
1611  |  |  | 
1612  |  |             // handle day periods - with #13183, no longer need special handling here, integrated with normal types  | 
1613  |  | 
  | 
1614  | 0  |             if ((flags & kDTPGFixFractionalSeconds) != 0 && typeValue == UDATPG_SECOND_FIELD) { | 
1615  | 0  |                 field += decimal;  | 
1616  | 0  |                 dtMatcher->skeleton.original.appendFieldTo(UDATPG_FRACTIONAL_SECOND_FIELD, field);  | 
1617  | 0  |             } else if (dtMatcher->skeleton.type[typeValue]!=0) { | 
1618  |  |                     // Here:  | 
1619  |  |                     // - "reqField" is the field from the originally requested skeleton after replacement  | 
1620  |  |                     // of metacharacters 'j', 'C' and 'J', with length "reqFieldLen".  | 
1621  |  |                     // - "field" is the field from the found pattern.  | 
1622  |  |                     //  | 
1623  |  |                     // The adjusted field should consist of characters from the originally requested  | 
1624  |  |                     // skeleton, except in the case of UDATPG_MONTH_FIELD or  | 
1625  |  |                     // UDATPG_WEEKDAY_FIELD or UDATPG_YEAR_FIELD, in which case it should consist  | 
1626  |  |                     // of characters from the found pattern. In some cases of UDATPG_HOUR_FIELD,  | 
1627  |  |                     // there is adjustment following the "defaultHourFormatChar". There is explanation  | 
1628  |  |                     // how it is done below.  | 
1629  |  |                     //  | 
1630  |  |                     // The length of the adjusted field (adjFieldLen) should match that in the originally  | 
1631  |  |                     // requested skeleton, except that in the following cases the length of the adjusted field  | 
1632  |  |                     // should match that in the found pattern (i.e. the length of this pattern field should  | 
1633  |  |                     // not be adjusted):  | 
1634  |  |                     // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is  | 
1635  |  |                     //    not set (ticket #7180). Note, we may want to implement a similar change for other  | 
1636  |  |                     //    numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for  | 
1637  |  |                     //    field length, but options bits can be used to override this.  | 
1638  |  |                     // 2. There is a specified skeleton for the found pattern and one of the following is true:  | 
1639  |  |                     //    a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen.  | 
1640  |  |                     //    b) The pattern field is numeric and the skeleton field is not, or vice versa.  | 
1641  |  | 
  | 
1642  | 0  |                     UChar reqFieldChar = dtMatcher->skeleton.original.getFieldChar(typeValue);  | 
1643  | 0  |                     int32_t reqFieldLen = dtMatcher->skeleton.original.getFieldLength(typeValue);  | 
1644  | 0  |                     if (reqFieldChar == CAP_E && reqFieldLen < 3)  | 
1645  | 0  |                         reqFieldLen = 3; // 1-3 for E are equivalent to 3 for c,e  | 
1646  | 0  |                     int32_t adjFieldLen = reqFieldLen;  | 
1647  | 0  |                     if ( (typeValue==UDATPG_HOUR_FIELD && (options & UDATPG_MATCH_HOUR_FIELD_LENGTH)==0) ||  | 
1648  | 0  |                          (typeValue==UDATPG_MINUTE_FIELD && (options & UDATPG_MATCH_MINUTE_FIELD_LENGTH)==0) ||  | 
1649  | 0  |                          (typeValue==UDATPG_SECOND_FIELD && (options & UDATPG_MATCH_SECOND_FIELD_LENGTH)==0) ) { | 
1650  | 0  |                          adjFieldLen = field.length();  | 
1651  | 0  |                     } else if (specifiedSkeleton && reqFieldChar != LOW_C && reqFieldChar != LOW_E) { | 
1652  |  |                         // (we skip this section for 'c' and 'e' because unlike the other characters considered in this function,  | 
1653  |  |                         // they have no minimum field length-- 'E' and 'EE' are equivalent to 'EEE', but 'e' and 'ee' are not  | 
1654  |  |                         // equivalent to 'eee' -- see the entries for "week day" in  | 
1655  |  |                         // https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table for more info)  | 
1656  | 0  |                         int32_t skelFieldLen = specifiedSkeleton->original.getFieldLength(typeValue);  | 
1657  | 0  |                         UBool patFieldIsNumeric = (row->type > 0);  | 
1658  | 0  |                         UBool skelFieldIsNumeric = (specifiedSkeleton->type[typeValue] > 0);  | 
1659  | 0  |                         if (skelFieldLen == reqFieldLen || (patFieldIsNumeric && !skelFieldIsNumeric) || (skelFieldIsNumeric && !patFieldIsNumeric)) { | 
1660  |  |                             // don't adjust the field length in the found pattern  | 
1661  | 0  |                             adjFieldLen = field.length();  | 
1662  | 0  |                         }  | 
1663  | 0  |                     }  | 
1664  | 0  |                     UChar c = (typeValue!= UDATPG_HOUR_FIELD  | 
1665  | 0  |                             && typeValue!= UDATPG_MONTH_FIELD  | 
1666  | 0  |                             && typeValue!= UDATPG_WEEKDAY_FIELD  | 
1667  | 0  |                             && (typeValue!= UDATPG_YEAR_FIELD || reqFieldChar==CAP_Y))  | 
1668  | 0  |                             ? reqFieldChar  | 
1669  | 0  |                             : field.charAt(0);  | 
1670  | 0  |                     if (c == CAP_E && adjFieldLen < 3) { | 
1671  | 0  |                         c = LOW_E;  | 
1672  | 0  |                     }  | 
1673  | 0  |                     if (typeValue == UDATPG_HOUR_FIELD && fDefaultHourFormatChar != 0) { | 
1674  |  |                         // The adjustment here is required to match spec (https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-hour).  | 
1675  |  |                         // It is necessary to match the hour-cycle preferred by the Locale.  | 
1676  |  |                         // Given that, we need to do the following adjustments:  | 
1677  |  |                         // 1. When hour-cycle is h11 it should replace 'h' by 'K'.  | 
1678  |  |                         // 2. When hour-cycle is h23 it should replace 'H' by 'k'.  | 
1679  |  |                         // 3. When hour-cycle is h24 it should replace 'k' by 'H'.  | 
1680  |  |                         // 4. When hour-cycle is h12 it should replace 'K' by 'h'.  | 
1681  |  | 
  | 
1682  | 0  |                         if ((flags & kDTPGSkeletonUsesCapJ) != 0 || reqFieldChar == fDefaultHourFormatChar) { | 
1683  | 0  |                             c = fDefaultHourFormatChar;  | 
1684  | 0  |                         } else if (reqFieldChar == LOW_H && fDefaultHourFormatChar == CAP_K) { | 
1685  | 0  |                             c = CAP_K;  | 
1686  | 0  |                         } else if (reqFieldChar == CAP_H && fDefaultHourFormatChar == LOW_K) { | 
1687  | 0  |                             c = LOW_K;  | 
1688  | 0  |                         } else if (reqFieldChar == LOW_K && fDefaultHourFormatChar == CAP_H) { | 
1689  | 0  |                             c = CAP_H;  | 
1690  | 0  |                         } else if (reqFieldChar == CAP_K && fDefaultHourFormatChar == LOW_H) { | 
1691  | 0  |                             c = LOW_H;  | 
1692  | 0  |                         }  | 
1693  | 0  |                     }  | 
1694  |  | 
  | 
1695  | 0  |                     field.remove();  | 
1696  | 0  |                     for (int32_t j=adjFieldLen; j>0; --j) { | 
1697  | 0  |                         field += c;  | 
1698  | 0  |                     }  | 
1699  | 0  |             }  | 
1700  | 0  |             newPattern+=field;  | 
1701  | 0  |         }  | 
1702  | 0  |     }  | 
1703  | 0  |     return newPattern;  | 
1704  | 0  | }  | 
1705  |  |  | 
1706  |  | UnicodeString  | 
1707  | 0  | DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UErrorCode &status, UDateTimePatternMatchOptions options) { | 
1708  | 0  |     if (U_FAILURE(status)) { | 
1709  | 0  |         return UnicodeString();  | 
1710  | 0  |     }  | 
1711  | 0  |     UnicodeString  resultPattern, tempPattern;  | 
1712  | 0  |     const UnicodeString* tempPatternPtr;  | 
1713  | 0  |     int32_t lastMissingFieldMask=0;  | 
1714  | 0  |     if (missingFields!=0) { | 
1715  | 0  |         resultPattern=UnicodeString();  | 
1716  | 0  |         const PtnSkeleton* specifiedSkeleton=nullptr;  | 
1717  | 0  |         tempPatternPtr = getBestRaw(*dtMatcher, missingFields, distanceInfo, status, &specifiedSkeleton);  | 
1718  | 0  |         if (U_FAILURE(status)) { | 
1719  | 0  |             return UnicodeString();  | 
1720  | 0  |         }  | 
1721  | 0  |         tempPattern = *tempPatternPtr;  | 
1722  | 0  |         resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);  | 
1723  | 0  |         if ( distanceInfo->missingFieldMask==0 ) { | 
1724  | 0  |             return resultPattern;  | 
1725  | 0  |         }  | 
1726  | 0  |         while (distanceInfo->missingFieldMask!=0) { // precondition: EVERY single field must work! | 
1727  | 0  |             if ( lastMissingFieldMask == distanceInfo->missingFieldMask ) { | 
1728  | 0  |                 break;  // cannot find the proper missing field  | 
1729  | 0  |             }  | 
1730  | 0  |             if (((distanceInfo->missingFieldMask & UDATPG_SECOND_AND_FRACTIONAL_MASK)==UDATPG_FRACTIONAL_MASK) &&  | 
1731  | 0  |                 ((missingFields & UDATPG_SECOND_AND_FRACTIONAL_MASK) == UDATPG_SECOND_AND_FRACTIONAL_MASK)) { | 
1732  | 0  |                 resultPattern = adjustFieldTypes(resultPattern, specifiedSkeleton, flags | kDTPGFixFractionalSeconds, options);  | 
1733  | 0  |                 distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK;  | 
1734  | 0  |                 continue;  | 
1735  | 0  |             }  | 
1736  | 0  |             int32_t startingMask = distanceInfo->missingFieldMask;  | 
1737  | 0  |             tempPatternPtr = getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, status, &specifiedSkeleton);  | 
1738  | 0  |             if (U_FAILURE(status)) { | 
1739  | 0  |                 return UnicodeString();  | 
1740  | 0  |             }  | 
1741  | 0  |             tempPattern = *tempPatternPtr;  | 
1742  | 0  |             tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);  | 
1743  | 0  |             int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;  | 
1744  | 0  |             int32_t topField=getTopBitNumber(foundMask);  | 
1745  |  | 
  | 
1746  | 0  |             if (appendItemFormats[topField].length() != 0) { | 
1747  | 0  |                 UnicodeString appendName;  | 
1748  | 0  |                 getAppendName((UDateTimePatternField)topField, appendName);  | 
1749  | 0  |                 const UnicodeString *values[3] = { | 
1750  | 0  |                     &resultPattern,  | 
1751  | 0  |                     &tempPattern,  | 
1752  | 0  |                     &appendName  | 
1753  | 0  |                 };  | 
1754  | 0  |                 SimpleFormatter(appendItemFormats[topField], 2, 3, status).  | 
1755  | 0  |                     formatAndReplace(values, 3, resultPattern, nullptr, 0, status);  | 
1756  | 0  |             }  | 
1757  | 0  |             lastMissingFieldMask = distanceInfo->missingFieldMask;  | 
1758  | 0  |         }  | 
1759  | 0  |     }  | 
1760  | 0  |     return resultPattern;  | 
1761  | 0  | }  | 
1762  |  |  | 
1763  |  | int32_t  | 
1764  | 0  | DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) const { | 
1765  | 0  |     if ( foundMask==0 ) { | 
1766  | 0  |         return 0;  | 
1767  | 0  |     }  | 
1768  | 0  |     int32_t i=0;  | 
1769  | 0  |     while (foundMask!=0) { | 
1770  | 0  |         foundMask >>=1;  | 
1771  | 0  |         ++i;  | 
1772  | 0  |     }  | 
1773  | 0  |     if (i-1 >UDATPG_ZONE_FIELD) { | 
1774  | 0  |         return UDATPG_ZONE_FIELD;  | 
1775  | 0  |     }  | 
1776  | 0  |     else  | 
1777  | 0  |         return i-1;  | 
1778  | 0  | }  | 
1779  |  |  | 
1780  |  | void  | 
1781  |  | DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err)  | 
1782  | 0  | { | 
1783  | 0  |     fAvailableFormatKeyHash->puti(key, 1, err);  | 
1784  | 0  | }  | 
1785  |  |  | 
1786  |  | UBool  | 
1787  | 0  | DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const { | 
1788  | 0  |     return (UBool)(fAvailableFormatKeyHash->geti(key) == 1);  | 
1789  | 0  | }  | 
1790  |  |  | 
1791  |  | void  | 
1792  | 0  | DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) { | 
1793  | 0  |     if (other == nullptr || U_FAILURE(status)) { | 
1794  | 0  |         return;  | 
1795  | 0  |     }  | 
1796  | 0  |     if (fAvailableFormatKeyHash != nullptr) { | 
1797  | 0  |         delete fAvailableFormatKeyHash;  | 
1798  | 0  |         fAvailableFormatKeyHash = nullptr;  | 
1799  | 0  |     }  | 
1800  | 0  |     initHashtable(status);  | 
1801  | 0  |     if(U_FAILURE(status)){ | 
1802  | 0  |         return;  | 
1803  | 0  |     }  | 
1804  | 0  |     int32_t pos = UHASH_FIRST;  | 
1805  | 0  |     const UHashElement* elem = nullptr;  | 
1806  |  |     // walk through the hash table and create a deep clone  | 
1807  | 0  |     while((elem = other->nextElement(pos))!= nullptr){ | 
1808  | 0  |         const UHashTok otherKeyTok = elem->key;  | 
1809  | 0  |         UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;  | 
1810  | 0  |         fAvailableFormatKeyHash->puti(*otherKey, 1, status);  | 
1811  | 0  |         if(U_FAILURE(status)){ | 
1812  | 0  |             return;  | 
1813  | 0  |         }  | 
1814  | 0  |     }  | 
1815  | 0  | }  | 
1816  |  |  | 
1817  |  | StringEnumeration*  | 
1818  | 0  | DateTimePatternGenerator::getSkeletons(UErrorCode& status) const { | 
1819  | 0  |     if (U_FAILURE(status)) { | 
1820  | 0  |         return nullptr;  | 
1821  | 0  |     }  | 
1822  | 0  |     if (U_FAILURE(internalErrorCode)) { | 
1823  | 0  |         status = internalErrorCode;  | 
1824  | 0  |         return nullptr;  | 
1825  | 0  |     }  | 
1826  | 0  |     LocalPointer<StringEnumeration> skeletonEnumerator(  | 
1827  | 0  |         new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status), status);  | 
1828  |  | 
  | 
1829  | 0  |     return U_SUCCESS(status) ? skeletonEnumerator.orphan() : nullptr;  | 
1830  | 0  | }  | 
1831  |  |  | 
1832  |  | const UnicodeString&  | 
1833  | 0  | DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) const { | 
1834  | 0  |     PtnElem *curElem;  | 
1835  |  | 
  | 
1836  | 0  |     if (skeleton.length() ==0) { | 
1837  | 0  |         return emptyString;  | 
1838  | 0  |     }  | 
1839  | 0  |     curElem = patternMap->getHeader(skeleton.charAt(0));  | 
1840  | 0  |     while ( curElem != nullptr ) { | 
1841  | 0  |         if ( curElem->skeleton->getSkeleton()==skeleton ) { | 
1842  | 0  |             return curElem->pattern;  | 
1843  | 0  |         }  | 
1844  | 0  |         curElem = curElem->next.getAlias();  | 
1845  | 0  |     }  | 
1846  | 0  |     return emptyString;  | 
1847  | 0  | }  | 
1848  |  |  | 
1849  |  | StringEnumeration*  | 
1850  | 0  | DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const { | 
1851  | 0  |     if (U_FAILURE(status)) { | 
1852  | 0  |         return nullptr;  | 
1853  | 0  |     }  | 
1854  | 0  |     if (U_FAILURE(internalErrorCode)) { | 
1855  | 0  |         status = internalErrorCode;  | 
1856  | 0  |         return nullptr;  | 
1857  | 0  |     }  | 
1858  | 0  |     LocalPointer<StringEnumeration> baseSkeletonEnumerator(  | 
1859  | 0  |         new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status), status);  | 
1860  |  | 
  | 
1861  | 0  |     return U_SUCCESS(status) ? baseSkeletonEnumerator.orphan() : nullptr;  | 
1862  | 0  | }  | 
1863  |  |  | 
1864  |  | StringEnumeration*  | 
1865  | 0  | DateTimePatternGenerator::getRedundants(UErrorCode& status) { | 
1866  | 0  |     if (U_FAILURE(status)) { return nullptr; } | 
1867  | 0  |     if (U_FAILURE(internalErrorCode)) { | 
1868  | 0  |         status = internalErrorCode;  | 
1869  | 0  |         return nullptr;  | 
1870  | 0  |     }  | 
1871  | 0  |     LocalPointer<StringEnumeration> output(new DTRedundantEnumeration(), status);  | 
1872  | 0  |     if (U_FAILURE(status)) { return nullptr; } | 
1873  | 0  |     const UnicodeString *pattern;  | 
1874  | 0  |     PatternMapIterator it(status);  | 
1875  | 0  |     if (U_FAILURE(status)) { return nullptr; } | 
1876  |  |  | 
1877  | 0  |     for (it.set(*patternMap); it.hasNext(); ) { | 
1878  | 0  |         DateTimeMatcher current = it.next();  | 
1879  | 0  |         pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton()));  | 
1880  | 0  |         if ( isCanonicalItem(*pattern) ) { | 
1881  | 0  |             continue;  | 
1882  | 0  |         }  | 
1883  | 0  |         if ( skipMatcher == nullptr ) { | 
1884  | 0  |             skipMatcher = new DateTimeMatcher(current);  | 
1885  | 0  |             if (skipMatcher == nullptr) { | 
1886  | 0  |                 status = U_MEMORY_ALLOCATION_ERROR;  | 
1887  | 0  |                 return nullptr;  | 
1888  | 0  |             }  | 
1889  | 0  |         }  | 
1890  | 0  |         else { | 
1891  | 0  |             *skipMatcher = current;  | 
1892  | 0  |         }  | 
1893  | 0  |         UnicodeString trial = getBestPattern(current.getPattern(), status);  | 
1894  | 0  |         if (U_FAILURE(status)) { return nullptr; } | 
1895  | 0  |         if (trial == *pattern) { | 
1896  | 0  |             ((DTRedundantEnumeration *)output.getAlias())->add(*pattern, status);  | 
1897  | 0  |             if (U_FAILURE(status)) { return nullptr; } | 
1898  | 0  |         }  | 
1899  | 0  |         if (current.equals(skipMatcher)) { | 
1900  | 0  |             continue;  | 
1901  | 0  |         }  | 
1902  | 0  |     }  | 
1903  | 0  |     return output.orphan();  | 
1904  | 0  | }  | 
1905  |  |  | 
1906  |  | UBool  | 
1907  | 0  | DateTimePatternGenerator::isCanonicalItem(const UnicodeString& item) const { | 
1908  | 0  |     if ( item.length() != 1 ) { | 
1909  | 0  |         return FALSE;  | 
1910  | 0  |     }  | 
1911  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { | 
1912  | 0  |         if (item.charAt(0)==Canonical_Items[i]) { | 
1913  | 0  |             return TRUE;  | 
1914  | 0  |         }  | 
1915  | 0  |     }  | 
1916  | 0  |     return FALSE;  | 
1917  | 0  | }  | 
1918  |  |  | 
1919  |  |  | 
1920  |  | DateTimePatternGenerator*  | 
1921  | 0  | DateTimePatternGenerator::clone() const { | 
1922  | 0  |     return new DateTimePatternGenerator(*this);  | 
1923  | 0  | }  | 
1924  |  |  | 
1925  | 0  | PatternMap::PatternMap() { | 
1926  | 0  |    for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { | 
1927  | 0  |        boot[i] = nullptr;  | 
1928  | 0  |    }  | 
1929  | 0  |    isDupAllowed = TRUE;  | 
1930  | 0  | }  | 
1931  |  |  | 
1932  |  | void  | 
1933  | 0  | PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) { | 
1934  | 0  |     if (U_FAILURE(status)) { | 
1935  | 0  |         return;  | 
1936  | 0  |     }  | 
1937  | 0  |     this->isDupAllowed = other.isDupAllowed;  | 
1938  | 0  |     for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) { | 
1939  | 0  |         PtnElem *curElem, *otherElem, *prevElem=nullptr;  | 
1940  | 0  |         otherElem = other.boot[bootIndex];  | 
1941  | 0  |         while (otherElem != nullptr) { | 
1942  | 0  |             LocalPointer<PtnElem> newElem(new PtnElem(otherElem->basePattern, otherElem->pattern), status);  | 
1943  | 0  |             if (U_FAILURE(status)) { | 
1944  | 0  |                 return; // out of memory  | 
1945  | 0  |             }  | 
1946  | 0  |             newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(*(otherElem->skeleton)), status);  | 
1947  | 0  |             if (U_FAILURE(status)) { | 
1948  | 0  |                 return; // out of memory  | 
1949  | 0  |             }  | 
1950  | 0  |             newElem->skeletonWasSpecified = otherElem->skeletonWasSpecified;  | 
1951  |  |  | 
1952  |  |             // Release ownership from the LocalPointer of the PtnElem object.  | 
1953  |  |             // The PtnElem will now be owned by either the boot (for the first entry in the linked-list)  | 
1954  |  |             // or owned by the previous PtnElem object in the linked-list.  | 
1955  | 0  |             curElem = newElem.orphan();  | 
1956  |  | 
  | 
1957  | 0  |             if (this->boot[bootIndex] == nullptr) { | 
1958  | 0  |                 this->boot[bootIndex] = curElem;  | 
1959  | 0  |             } else { | 
1960  | 0  |                 if (prevElem != nullptr) { | 
1961  | 0  |                     prevElem->next.adoptInstead(curElem);  | 
1962  | 0  |                 } else { | 
1963  | 0  |                     UPRV_UNREACHABLE;  | 
1964  | 0  |                 }  | 
1965  | 0  |             }  | 
1966  | 0  |             prevElem = curElem;  | 
1967  | 0  |             otherElem = otherElem->next.getAlias();  | 
1968  | 0  |         }  | 
1969  |  | 
  | 
1970  | 0  |     }  | 
1971  | 0  | }  | 
1972  |  |  | 
1973  |  | PtnElem*  | 
1974  | 0  | PatternMap::getHeader(UChar baseChar) const { | 
1975  | 0  |     PtnElem* curElem;  | 
1976  |  | 
  | 
1977  | 0  |     if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) { | 
1978  | 0  |          curElem = boot[baseChar-CAP_A];  | 
1979  | 0  |     }  | 
1980  | 0  |     else { | 
1981  | 0  |         if ( (baseChar >=LOW_A) && (baseChar <= LOW_Z) ) { | 
1982  | 0  |             curElem = boot[26+baseChar-LOW_A];  | 
1983  | 0  |         }  | 
1984  | 0  |         else { | 
1985  | 0  |             return nullptr;  | 
1986  | 0  |         }  | 
1987  | 0  |     }  | 
1988  | 0  |     return curElem;  | 
1989  | 0  | }  | 
1990  |  |  | 
1991  | 0  | PatternMap::~PatternMap() { | 
1992  | 0  |    for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { | 
1993  | 0  |        if (boot[i] != nullptr ) { | 
1994  | 0  |            delete boot[i];  | 
1995  | 0  |            boot[i] = nullptr;  | 
1996  | 0  |        }  | 
1997  | 0  |    }  | 
1998  | 0  | }  // PatternMap destructor  | 
1999  |  |  | 
2000  |  | void  | 
2001  |  | PatternMap::add(const UnicodeString& basePattern,  | 
2002  |  |                 const PtnSkeleton& skeleton,  | 
2003  |  |                 const UnicodeString& value,// mapped pattern value  | 
2004  |  |                 UBool skeletonWasSpecified,  | 
2005  | 0  |                 UErrorCode &status) { | 
2006  | 0  |     UChar baseChar = basePattern.charAt(0);  | 
2007  | 0  |     PtnElem *curElem, *baseElem;  | 
2008  | 0  |     status = U_ZERO_ERROR;  | 
2009  |  |  | 
2010  |  |     // the baseChar must be A-Z or a-z  | 
2011  | 0  |     if ((baseChar >= CAP_A) && (baseChar <= CAP_Z)) { | 
2012  | 0  |         baseElem = boot[baseChar-CAP_A];  | 
2013  | 0  |     }  | 
2014  | 0  |     else { | 
2015  | 0  |         if ((baseChar >=LOW_A) && (baseChar <= LOW_Z)) { | 
2016  | 0  |             baseElem = boot[26+baseChar-LOW_A];  | 
2017  | 0  |          }  | 
2018  | 0  |          else { | 
2019  | 0  |              status = U_ILLEGAL_CHARACTER;  | 
2020  | 0  |              return;  | 
2021  | 0  |          }  | 
2022  | 0  |     }  | 
2023  |  |  | 
2024  | 0  |     if (baseElem == nullptr) { | 
2025  | 0  |         LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);  | 
2026  | 0  |         if (U_FAILURE(status)) { | 
2027  | 0  |             return; // out of memory  | 
2028  | 0  |         }  | 
2029  | 0  |         newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);  | 
2030  | 0  |         if (U_FAILURE(status)) { | 
2031  | 0  |             return; // out of memory  | 
2032  | 0  |         }  | 
2033  | 0  |         newElem->skeletonWasSpecified = skeletonWasSpecified;  | 
2034  | 0  |         if (baseChar >= LOW_A) { | 
2035  | 0  |             boot[26 + (baseChar - LOW_A)] = newElem.orphan(); // the boot array now owns the PtnElem.  | 
2036  | 0  |         }  | 
2037  | 0  |         else { | 
2038  | 0  |             boot[baseChar - CAP_A] = newElem.orphan(); // the boot array now owns the PtnElem.  | 
2039  | 0  |         }  | 
2040  | 0  |     }  | 
2041  | 0  |     if ( baseElem != nullptr ) { | 
2042  | 0  |         curElem = getDuplicateElem(basePattern, skeleton, baseElem);  | 
2043  |  | 
  | 
2044  | 0  |         if (curElem == nullptr) { | 
2045  |  |             // add new element to the list.  | 
2046  | 0  |             curElem = baseElem;  | 
2047  | 0  |             while( curElem -> next != nullptr )  | 
2048  | 0  |             { | 
2049  | 0  |                 curElem = curElem->next.getAlias();  | 
2050  | 0  |             }  | 
2051  |  | 
  | 
2052  | 0  |             LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);  | 
2053  | 0  |             if (U_FAILURE(status)) { | 
2054  | 0  |                 return; // out of memory  | 
2055  | 0  |             }  | 
2056  | 0  |             newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);  | 
2057  | 0  |             if (U_FAILURE(status)) { | 
2058  | 0  |                 return; // out of memory  | 
2059  | 0  |             }  | 
2060  | 0  |             newElem->skeletonWasSpecified = skeletonWasSpecified;  | 
2061  | 0  |             curElem->next.adoptInstead(newElem.orphan());  | 
2062  | 0  |             curElem = curElem->next.getAlias();  | 
2063  | 0  |         }  | 
2064  | 0  |         else { | 
2065  |  |             // Pattern exists in the list already.  | 
2066  | 0  |             if ( !isDupAllowed ) { | 
2067  | 0  |                 return;  | 
2068  | 0  |             }  | 
2069  |  |             // Overwrite the value.  | 
2070  | 0  |             curElem->pattern = value;  | 
2071  |  |             // It was a bug that we were not doing the following previously,  | 
2072  |  |             // though that bug hid other problems by making things partly work.  | 
2073  | 0  |             curElem->skeletonWasSpecified = skeletonWasSpecified;  | 
2074  | 0  |         }  | 
2075  | 0  |     }  | 
2076  | 0  | }  // PatternMap::add  | 
2077  |  |  | 
2078  |  | // Find the pattern from the given basePattern string.  | 
2079  |  | const UnicodeString *  | 
2080  | 0  | PatternMap::getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const { // key to search for | 
2081  | 0  |    PtnElem *curElem;  | 
2082  |  | 
  | 
2083  | 0  |    if ((curElem=getHeader(basePattern.charAt(0)))==nullptr) { | 
2084  | 0  |        return nullptr;  // no match  | 
2085  | 0  |    }  | 
2086  |  |  | 
2087  | 0  |    do  { | 
2088  | 0  |        if ( basePattern.compare(curElem->basePattern)==0 ) { | 
2089  | 0  |           skeletonWasSpecified = curElem->skeletonWasSpecified;  | 
2090  | 0  |           return &(curElem->pattern);  | 
2091  | 0  |        }  | 
2092  | 0  |        curElem = curElem->next.getAlias();  | 
2093  | 0  |    } while (curElem != nullptr);  | 
2094  |  |  | 
2095  | 0  |    return nullptr;  | 
2096  | 0  | }  // PatternMap::getFromBasePattern  | 
2097  |  |  | 
2098  |  |  | 
2099  |  | // Find the pattern from the given skeleton.  | 
2100  |  | // At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL),  | 
2101  |  | // the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw)  | 
2102  |  | // and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the  | 
2103  |  | // optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),  | 
2104  |  | // for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.  | 
2105  |  | const UnicodeString *  | 
2106  | 0  | PatternMap::getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) const { // key to search for | 
2107  | 0  |    PtnElem *curElem;  | 
2108  |  | 
  | 
2109  | 0  |    if (specifiedSkeletonPtr) { | 
2110  | 0  |        *specifiedSkeletonPtr = nullptr;  | 
2111  | 0  |    }  | 
2112  |  |  | 
2113  |  |    // find boot entry  | 
2114  | 0  |    UChar baseChar = skeleton.getFirstChar();  | 
2115  | 0  |    if ((curElem=getHeader(baseChar))==nullptr) { | 
2116  | 0  |        return nullptr;  // no match  | 
2117  | 0  |    }  | 
2118  |  |  | 
2119  | 0  |    do  { | 
2120  | 0  |        UBool equal;  | 
2121  | 0  |        if (specifiedSkeletonPtr != nullptr) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original | 
2122  | 0  |            equal = curElem->skeleton->original == skeleton.original;  | 
2123  | 0  |        } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal | 
2124  | 0  |            equal = curElem->skeleton->baseOriginal == skeleton.baseOriginal;  | 
2125  | 0  |        }  | 
2126  | 0  |        if (equal) { | 
2127  | 0  |            if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) { | 
2128  | 0  |                *specifiedSkeletonPtr = curElem->skeleton.getAlias();  | 
2129  | 0  |            }  | 
2130  | 0  |            return &(curElem->pattern);  | 
2131  | 0  |        }  | 
2132  | 0  |        curElem = curElem->next.getAlias();  | 
2133  | 0  |    } while (curElem != nullptr);  | 
2134  |  |  | 
2135  | 0  |    return nullptr;  | 
2136  | 0  | }  | 
2137  |  |  | 
2138  |  | UBool  | 
2139  | 0  | PatternMap::equals(const PatternMap& other) const { | 
2140  | 0  |     if ( this==&other ) { | 
2141  | 0  |         return TRUE;  | 
2142  | 0  |     }  | 
2143  | 0  |     for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) { | 
2144  | 0  |         if (boot[bootIndex] == other.boot[bootIndex]) { | 
2145  | 0  |             continue;  | 
2146  | 0  |         }  | 
2147  | 0  |         if ((boot[bootIndex] == nullptr) || (other.boot[bootIndex] == nullptr)) { | 
2148  | 0  |             return FALSE;  | 
2149  | 0  |         }  | 
2150  | 0  |         PtnElem *otherElem = other.boot[bootIndex];  | 
2151  | 0  |         PtnElem *myElem = boot[bootIndex];  | 
2152  | 0  |         while ((otherElem != nullptr) || (myElem != nullptr)) { | 
2153  | 0  |             if ( myElem == otherElem ) { | 
2154  | 0  |                 break;  | 
2155  | 0  |             }  | 
2156  | 0  |             if ((otherElem == nullptr) || (myElem == nullptr)) { | 
2157  | 0  |                 return FALSE;  | 
2158  | 0  |             }  | 
2159  | 0  |             if ( (myElem->basePattern != otherElem->basePattern) ||  | 
2160  | 0  |                  (myElem->pattern != otherElem->pattern) ) { | 
2161  | 0  |                 return FALSE;  | 
2162  | 0  |             }  | 
2163  | 0  |             if ((myElem->skeleton.getAlias() != otherElem->skeleton.getAlias()) &&  | 
2164  | 0  |                 !myElem->skeleton->equals(*(otherElem->skeleton))) { | 
2165  | 0  |                 return FALSE;  | 
2166  | 0  |             }  | 
2167  | 0  |             myElem = myElem->next.getAlias();  | 
2168  | 0  |             otherElem = otherElem->next.getAlias();  | 
2169  | 0  |         }  | 
2170  | 0  |     }  | 
2171  | 0  |     return TRUE;  | 
2172  | 0  | }  | 
2173  |  |  | 
2174  |  | // find any key existing in the mapping table already.  | 
2175  |  | // return TRUE if there is an existing key, otherwise return FALSE.  | 
2176  |  | PtnElem*  | 
2177  |  | PatternMap::getDuplicateElem(  | 
2178  |  |             const UnicodeString &basePattern,  | 
2179  |  |             const PtnSkeleton &skeleton,  | 
2180  | 0  |             PtnElem *baseElem) { | 
2181  | 0  |    PtnElem *curElem;  | 
2182  |  | 
  | 
2183  | 0  |    if ( baseElem == nullptr ) { | 
2184  | 0  |          return nullptr;  | 
2185  | 0  |    }  | 
2186  | 0  |    else { | 
2187  | 0  |          curElem = baseElem;  | 
2188  | 0  |    }  | 
2189  | 0  |    do { | 
2190  | 0  |      if ( basePattern.compare(curElem->basePattern)==0 ) { | 
2191  | 0  |          UBool isEqual = TRUE;  | 
2192  | 0  |          for (int32_t i = 0; i < UDATPG_FIELD_COUNT; ++i) { | 
2193  | 0  |             if (curElem->skeleton->type[i] != skeleton.type[i] ) { | 
2194  | 0  |                 isEqual = FALSE;  | 
2195  | 0  |                 break;  | 
2196  | 0  |             }  | 
2197  | 0  |         }  | 
2198  | 0  |         if (isEqual) { | 
2199  | 0  |             return curElem;  | 
2200  | 0  |         }  | 
2201  | 0  |      }  | 
2202  | 0  |      curElem = curElem->next.getAlias();  | 
2203  | 0  |    } while( curElem != nullptr );  | 
2204  |  |  | 
2205  |  |    // end of the list  | 
2206  | 0  |    return nullptr;  | 
2207  |  | 
  | 
2208  | 0  | }  // PatternMap::getDuplicateElem  | 
2209  |  |  | 
2210  | 0  | DateTimeMatcher::DateTimeMatcher(void) { | 
2211  | 0  | }  | 
2212  |  |  | 
2213  | 0  | DateTimeMatcher::~DateTimeMatcher() {} | 
2214  |  |  | 
2215  | 0  | DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) { | 
2216  | 0  |     copyFrom(other.skeleton);  | 
2217  | 0  | }  | 
2218  |  |  | 
2219  | 0  | DateTimeMatcher& DateTimeMatcher::operator=(const DateTimeMatcher& other) { | 
2220  | 0  |     copyFrom(other.skeleton);  | 
2221  | 0  |     return *this;  | 
2222  | 0  | }  | 
2223  |  |  | 
2224  |  |  | 
2225  |  | void  | 
2226  | 0  | DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) { | 
2227  | 0  |     PtnSkeleton localSkeleton;  | 
2228  | 0  |     return set(pattern, fp, localSkeleton);  | 
2229  | 0  | }  | 
2230  |  |  | 
2231  |  | void  | 
2232  | 0  | DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeletonResult) { | 
2233  | 0  |     int32_t i;  | 
2234  | 0  |     for (i=0; i<UDATPG_FIELD_COUNT; ++i) { | 
2235  | 0  |         skeletonResult.type[i] = NONE;  | 
2236  | 0  |     }  | 
2237  | 0  |     skeletonResult.original.clear();  | 
2238  | 0  |     skeletonResult.baseOriginal.clear();  | 
2239  | 0  |     skeletonResult.addedDefaultDayPeriod = FALSE;  | 
2240  |  | 
  | 
2241  | 0  |     fp->set(pattern);  | 
2242  | 0  |     for (i=0; i < fp->itemNumber; i++) { | 
2243  | 0  |         const UnicodeString& value = fp->items[i];  | 
2244  |  |         // don't skip 'a' anymore, dayPeriod handled specially below  | 
2245  |  | 
  | 
2246  | 0  |         if ( fp->isQuoteLiteral(value) ) { | 
2247  | 0  |             UnicodeString quoteLiteral;  | 
2248  | 0  |             fp->getQuoteLiteral(quoteLiteral, &i);  | 
2249  | 0  |             continue;  | 
2250  | 0  |         }  | 
2251  | 0  |         int32_t canonicalIndex = fp->getCanonicalIndex(value);  | 
2252  | 0  |         if (canonicalIndex < 0) { | 
2253  | 0  |             continue;  | 
2254  | 0  |         }  | 
2255  | 0  |         const dtTypeElem *row = &dtTypes[canonicalIndex];  | 
2256  | 0  |         int32_t field = row->field;  | 
2257  | 0  |         skeletonResult.original.populate(field, value);  | 
2258  | 0  |         UChar repeatChar = row->patternChar;  | 
2259  | 0  |         int32_t repeatCount = row->minLen;  | 
2260  | 0  |         skeletonResult.baseOriginal.populate(field, repeatChar, repeatCount);  | 
2261  | 0  |         int16_t subField = row->type;  | 
2262  | 0  |         if (row->type > 0) { | 
2263  | 0  |             U_ASSERT(value.length() < INT16_MAX);  | 
2264  | 0  |             subField += static_cast<int16_t>(value.length());  | 
2265  | 0  |         }  | 
2266  | 0  |         skeletonResult.type[field] = subField;  | 
2267  | 0  |     }  | 
2268  |  |  | 
2269  |  |     // #20739, we have a skeleton with minutes and milliseconds, but no seconds  | 
2270  |  |     //  | 
2271  |  |     // Theoretically we would need to check and fix all fields with "gaps":  | 
2272  |  |     // for example year-day (no month), month-hour (no day), and so on, All the possible field combinations.  | 
2273  |  |     // Plus some smartness: year + hour => should we add month, or add day-of-year?  | 
2274  |  |     // What about month + day-of-week, or month + am/pm indicator.  | 
2275  |  |     // I think beyond a certain point we should not try to fix bad developer input and try guessing what they mean.  | 
2276  |  |     // Garbage in, garbage out.  | 
2277  | 0  |     if (!skeletonResult.original.isFieldEmpty(UDATPG_MINUTE_FIELD)  | 
2278  | 0  |         && !skeletonResult.original.isFieldEmpty(UDATPG_FRACTIONAL_SECOND_FIELD)  | 
2279  | 0  |         && skeletonResult.original.isFieldEmpty(UDATPG_SECOND_FIELD)) { | 
2280  |  |         // Force the use of seconds  | 
2281  | 0  |         for (i = 0; dtTypes[i].patternChar != 0; i++) { | 
2282  | 0  |             if (dtTypes[i].field == UDATPG_SECOND_FIELD) { | 
2283  |  |                 // first entry for UDATPG_SECOND_FIELD  | 
2284  | 0  |                 skeletonResult.original.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);  | 
2285  | 0  |                 skeletonResult.baseOriginal.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);  | 
2286  |  |                 // We add value.length, same as above, when type is first initialized.  | 
2287  |  |                 // The value we want to "fake" here is "s", and 1 means "s".length()  | 
2288  | 0  |                 int16_t subField = dtTypes[i].type;  | 
2289  | 0  |                 skeletonResult.type[UDATPG_SECOND_FIELD] = (subField > 0) ? subField + 1 : subField;  | 
2290  | 0  |                 break;  | 
2291  | 0  |             }  | 
2292  | 0  |         }  | 
2293  | 0  |     }  | 
2294  |  |  | 
2295  |  |     // #13183, handle special behavior for day period characters (a, b, B)  | 
2296  | 0  |     if (!skeletonResult.original.isFieldEmpty(UDATPG_HOUR_FIELD)) { | 
2297  | 0  |         if (skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==LOW_H || skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==CAP_K) { | 
2298  |  |             // We have a skeleton with 12-hour-cycle format  | 
2299  | 0  |             if (skeletonResult.original.isFieldEmpty(UDATPG_DAYPERIOD_FIELD)) { | 
2300  |  |                 // But we do not have a day period in the skeleton; add the default DAYPERIOD (currently "a")  | 
2301  | 0  |                 for (i = 0; dtTypes[i].patternChar != 0; i++) { | 
2302  | 0  |                     if ( dtTypes[i].field == UDATPG_DAYPERIOD_FIELD ) { | 
2303  |  |                         // first entry for UDATPG_DAYPERIOD_FIELD  | 
2304  | 0  |                         skeletonResult.original.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);  | 
2305  | 0  |                         skeletonResult.baseOriginal.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);  | 
2306  | 0  |                         skeletonResult.type[UDATPG_DAYPERIOD_FIELD] = dtTypes[i].type;  | 
2307  | 0  |                         skeletonResult.addedDefaultDayPeriod = TRUE;  | 
2308  | 0  |                         break;  | 
2309  | 0  |                     }  | 
2310  | 0  |                 }  | 
2311  | 0  |             }  | 
2312  | 0  |         } else { | 
2313  |  |             // Skeleton has 24-hour-cycle hour format and has dayPeriod, delete dayPeriod (i.e. ignore it)  | 
2314  | 0  |             skeletonResult.original.clearField(UDATPG_DAYPERIOD_FIELD);  | 
2315  | 0  |             skeletonResult.baseOriginal.clearField(UDATPG_DAYPERIOD_FIELD);  | 
2316  | 0  |             skeletonResult.type[UDATPG_DAYPERIOD_FIELD] = NONE;  | 
2317  | 0  |         }  | 
2318  | 0  |     }  | 
2319  | 0  |     copyFrom(skeletonResult);  | 
2320  | 0  | }  | 
2321  |  |  | 
2322  |  | void  | 
2323  | 0  | DateTimeMatcher::getBasePattern(UnicodeString &result ) { | 
2324  | 0  |     result.remove(); // Reset the result first.  | 
2325  | 0  |     skeleton.baseOriginal.appendTo(result);  | 
2326  | 0  | }  | 
2327  |  |  | 
2328  |  | UnicodeString  | 
2329  | 0  | DateTimeMatcher::getPattern() { | 
2330  | 0  |     UnicodeString result;  | 
2331  | 0  |     return skeleton.original.appendTo(result);  | 
2332  | 0  | }  | 
2333  |  |  | 
2334  |  | int32_t  | 
2335  | 0  | DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const { | 
2336  | 0  |     int32_t result = 0;  | 
2337  | 0  |     distanceInfo.clear();  | 
2338  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { | 
2339  | 0  |         int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i];  | 
2340  | 0  |         int32_t otherType = other.skeleton.type[i];  | 
2341  | 0  |         if (myType==otherType) { | 
2342  | 0  |             continue;  | 
2343  | 0  |         }  | 
2344  | 0  |         if (myType==0) {// and other is not | 
2345  | 0  |             result += EXTRA_FIELD;  | 
2346  | 0  |             distanceInfo.addExtra(i);  | 
2347  | 0  |         }  | 
2348  | 0  |         else { | 
2349  | 0  |             if (otherType==0) { | 
2350  | 0  |                 result += MISSING_FIELD;  | 
2351  | 0  |                 distanceInfo.addMissing(i);  | 
2352  | 0  |             }  | 
2353  | 0  |             else { | 
2354  | 0  |                 result += abs(myType - otherType);  | 
2355  | 0  |             }  | 
2356  | 0  |         }  | 
2357  |  | 
  | 
2358  | 0  |     }  | 
2359  | 0  |     return result;  | 
2360  | 0  | }  | 
2361  |  |  | 
2362  |  | void  | 
2363  | 0  | DateTimeMatcher::copyFrom(const PtnSkeleton& newSkeleton) { | 
2364  | 0  |     skeleton.copyFrom(newSkeleton);  | 
2365  | 0  | }  | 
2366  |  |  | 
2367  |  | void  | 
2368  | 0  | DateTimeMatcher::copyFrom() { | 
2369  |  |     // same as clear  | 
2370  | 0  |     skeleton.clear();  | 
2371  | 0  | }  | 
2372  |  |  | 
2373  |  | UBool  | 
2374  | 0  | DateTimeMatcher::equals(const DateTimeMatcher* other) const { | 
2375  | 0  |     if (other==nullptr) { return FALSE; } | 
2376  | 0  |     return skeleton.original == other->skeleton.original;  | 
2377  | 0  | }  | 
2378  |  |  | 
2379  |  | int32_t  | 
2380  | 0  | DateTimeMatcher::getFieldMask() const { | 
2381  | 0  |     int32_t result = 0;  | 
2382  |  | 
  | 
2383  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { | 
2384  | 0  |         if (skeleton.type[i]!=0) { | 
2385  | 0  |             result |= (1<<i);  | 
2386  | 0  |         }  | 
2387  | 0  |     }  | 
2388  | 0  |     return result;  | 
2389  | 0  | }  | 
2390  |  |  | 
2391  |  | PtnSkeleton*  | 
2392  | 0  | DateTimeMatcher::getSkeletonPtr() { | 
2393  | 0  |     return &skeleton;  | 
2394  | 0  | }  | 
2395  |  |  | 
2396  | 0  | FormatParser::FormatParser () { | 
2397  | 0  |     status = START;  | 
2398  | 0  |     itemNumber = 0;  | 
2399  | 0  | }  | 
2400  |  |  | 
2401  |  |  | 
2402  | 0  | FormatParser::~FormatParser () { | 
2403  | 0  | }  | 
2404  |  |  | 
2405  |  |  | 
2406  |  | // Find the next token with the starting position and length  | 
2407  |  | // Note: the startPos may  | 
2408  |  | FormatParser::TokenStatus  | 
2409  | 0  | FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) { | 
2410  | 0  |     int32_t curLoc = startPos;  | 
2411  | 0  |     if ( curLoc >= pattern.length()) { | 
2412  | 0  |         return DONE;  | 
2413  | 0  |     }  | 
2414  |  |     // check the current char is between A-Z or a-z  | 
2415  | 0  |     do { | 
2416  | 0  |         UChar c=pattern.charAt(curLoc);  | 
2417  | 0  |         if ( (c>=CAP_A && c<=CAP_Z) || (c>=LOW_A && c<=LOW_Z) ) { | 
2418  | 0  |            curLoc++;  | 
2419  | 0  |         }  | 
2420  | 0  |         else { | 
2421  | 0  |                startPos = curLoc;  | 
2422  | 0  |                *len=1;  | 
2423  | 0  |                return ADD_TOKEN;  | 
2424  | 0  |         }  | 
2425  |  |  | 
2426  | 0  |         if ( pattern.charAt(curLoc)!= pattern.charAt(startPos) ) { | 
2427  | 0  |             break;  // not the same token  | 
2428  | 0  |         }  | 
2429  | 0  |     } while(curLoc <= pattern.length());  | 
2430  | 0  |     *len = curLoc-startPos;  | 
2431  | 0  |     return ADD_TOKEN;  | 
2432  | 0  | }  | 
2433  |  |  | 
2434  |  | void  | 
2435  | 0  | FormatParser::set(const UnicodeString& pattern) { | 
2436  | 0  |     int32_t startPos = 0;  | 
2437  | 0  |     TokenStatus result = START;  | 
2438  | 0  |     int32_t len = 0;  | 
2439  | 0  |     itemNumber = 0;  | 
2440  |  | 
  | 
2441  | 0  |     do { | 
2442  | 0  |         result = setTokens( pattern, startPos, &len );  | 
2443  | 0  |         if ( result == ADD_TOKEN )  | 
2444  | 0  |         { | 
2445  | 0  |             items[itemNumber++] = UnicodeString(pattern, startPos, len );  | 
2446  | 0  |             startPos += len;  | 
2447  | 0  |         }  | 
2448  | 0  |         else { | 
2449  | 0  |             break;  | 
2450  | 0  |         }  | 
2451  | 0  |     } while (result==ADD_TOKEN && itemNumber < MAX_DT_TOKEN);  | 
2452  | 0  | }  | 
2453  |  |  | 
2454  |  | int32_t  | 
2455  | 0  | FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) { | 
2456  | 0  |     int32_t len = s.length();  | 
2457  | 0  |     if (len == 0) { | 
2458  | 0  |         return -1;  | 
2459  | 0  |     }  | 
2460  | 0  |     UChar ch = s.charAt(0);  | 
2461  |  |  | 
2462  |  |     // Verify that all are the same character.  | 
2463  | 0  |     for (int32_t l = 1; l < len; l++) { | 
2464  | 0  |         if (ch != s.charAt(l)) { | 
2465  | 0  |             return -1;  | 
2466  | 0  |         }  | 
2467  | 0  |     }  | 
2468  | 0  |     int32_t i = 0;  | 
2469  | 0  |     int32_t bestRow = -1;  | 
2470  | 0  |     while (dtTypes[i].patternChar != 0x0000) { | 
2471  | 0  |         if ( dtTypes[i].patternChar != ch ) { | 
2472  | 0  |             ++i;  | 
2473  | 0  |             continue;  | 
2474  | 0  |         }  | 
2475  | 0  |         bestRow = i;  | 
2476  | 0  |         if (dtTypes[i].patternChar != dtTypes[i+1].patternChar) { | 
2477  | 0  |             return i;  | 
2478  | 0  |         }  | 
2479  | 0  |         if (dtTypes[i+1].minLen <= len) { | 
2480  | 0  |             ++i;  | 
2481  | 0  |             continue;  | 
2482  | 0  |         }  | 
2483  | 0  |         return i;  | 
2484  | 0  |     }  | 
2485  | 0  |     return strict ? -1 : bestRow;  | 
2486  | 0  | }  | 
2487  |  |  | 
2488  |  | UBool  | 
2489  | 0  | FormatParser::isQuoteLiteral(const UnicodeString& s) { | 
2490  | 0  |     return (UBool)(s.charAt(0) == SINGLE_QUOTE);  | 
2491  | 0  | }  | 
2492  |  |  | 
2493  |  | // This function assumes the current itemIndex points to the quote literal.  | 
2494  |  | // Please call isQuoteLiteral prior to this function.  | 
2495  |  | void  | 
2496  | 0  | FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) { | 
2497  | 0  |     int32_t i = *itemIndex;  | 
2498  |  | 
  | 
2499  | 0  |     quote.remove();  | 
2500  | 0  |     if (items[i].charAt(0)==SINGLE_QUOTE) { | 
2501  | 0  |         quote += items[i];  | 
2502  | 0  |         ++i;  | 
2503  | 0  |     }  | 
2504  | 0  |     while ( i < itemNumber ) { | 
2505  | 0  |         if ( items[i].charAt(0)==SINGLE_QUOTE ) { | 
2506  | 0  |             if ( (i+1<itemNumber) && (items[i+1].charAt(0)==SINGLE_QUOTE)) { | 
2507  |  |                 // two single quotes e.g. 'o''clock'  | 
2508  | 0  |                 quote += items[i++];  | 
2509  | 0  |                 quote += items[i++];  | 
2510  | 0  |                 continue;  | 
2511  | 0  |             }  | 
2512  | 0  |             else { | 
2513  | 0  |                 quote += items[i];  | 
2514  | 0  |                 break;  | 
2515  | 0  |             }  | 
2516  | 0  |         }  | 
2517  | 0  |         else { | 
2518  | 0  |             quote += items[i];  | 
2519  | 0  |         }  | 
2520  | 0  |         ++i;  | 
2521  | 0  |     }  | 
2522  | 0  |     *itemIndex=i;  | 
2523  | 0  | }  | 
2524  |  |  | 
2525  |  | UBool  | 
2526  | 0  | FormatParser::isPatternSeparator(const UnicodeString& field) const { | 
2527  | 0  |     for (int32_t i=0; i<field.length(); ++i ) { | 
2528  | 0  |         UChar c= field.charAt(i);  | 
2529  | 0  |         if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) ||  | 
2530  | 0  |              (c==QUOTATION_MARK) || (c==COMMA) || (c==HYPHEN) ||(items[i].charAt(0)==DOT) ) { | 
2531  | 0  |             continue;  | 
2532  | 0  |         }  | 
2533  | 0  |         else { | 
2534  | 0  |             return FALSE;  | 
2535  | 0  |         }  | 
2536  | 0  |     }  | 
2537  | 0  |     return TRUE;  | 
2538  | 0  | }  | 
2539  |  |  | 
2540  | 0  | DistanceInfo::~DistanceInfo() {} | 
2541  |  |  | 
2542  |  | void  | 
2543  | 0  | DistanceInfo::setTo(const DistanceInfo& other) { | 
2544  | 0  |     missingFieldMask = other.missingFieldMask;  | 
2545  | 0  |     extraFieldMask= other.extraFieldMask;  | 
2546  | 0  | }  | 
2547  |  |  | 
2548  |  | PatternMapIterator::PatternMapIterator(UErrorCode& status) :  | 
2549  | 0  |     bootIndex(0), nodePtr(nullptr), matcher(nullptr), patternMap(nullptr)  | 
2550  | 0  | { | 
2551  | 0  |     if (U_FAILURE(status)) { return; } | 
2552  | 0  |     matcher.adoptInsteadAndCheckErrorCode(new DateTimeMatcher(), status);  | 
2553  | 0  | }  | 
2554  |  |  | 
2555  | 0  | PatternMapIterator::~PatternMapIterator() { | 
2556  | 0  | }  | 
2557  |  |  | 
2558  |  | void  | 
2559  | 0  | PatternMapIterator::set(PatternMap& newPatternMap) { | 
2560  | 0  |     this->patternMap=&newPatternMap;  | 
2561  | 0  | }  | 
2562  |  |  | 
2563  |  | PtnSkeleton*  | 
2564  | 0  | PatternMapIterator::getSkeleton() const { | 
2565  | 0  |     if ( nodePtr == nullptr ) { | 
2566  | 0  |         return nullptr;  | 
2567  | 0  |     }  | 
2568  | 0  |     else { | 
2569  | 0  |         return nodePtr->skeleton.getAlias();  | 
2570  | 0  |     }  | 
2571  | 0  | }  | 
2572  |  |  | 
2573  |  | UBool  | 
2574  | 0  | PatternMapIterator::hasNext() const { | 
2575  | 0  |     int32_t headIndex = bootIndex;  | 
2576  | 0  |     PtnElem *curPtr = nodePtr;  | 
2577  |  | 
  | 
2578  | 0  |     if (patternMap==nullptr) { | 
2579  | 0  |         return FALSE;  | 
2580  | 0  |     }  | 
2581  | 0  |     while ( headIndex < MAX_PATTERN_ENTRIES ) { | 
2582  | 0  |         if ( curPtr != nullptr ) { | 
2583  | 0  |             if ( curPtr->next != nullptr ) { | 
2584  | 0  |                 return TRUE;  | 
2585  | 0  |             }  | 
2586  | 0  |             else { | 
2587  | 0  |                 headIndex++;  | 
2588  | 0  |                 curPtr=nullptr;  | 
2589  | 0  |                 continue;  | 
2590  | 0  |             }  | 
2591  | 0  |         }  | 
2592  | 0  |         else { | 
2593  | 0  |             if ( patternMap->boot[headIndex] != nullptr ) { | 
2594  | 0  |                 return TRUE;  | 
2595  | 0  |             }  | 
2596  | 0  |             else { | 
2597  | 0  |                 headIndex++;  | 
2598  | 0  |                 continue;  | 
2599  | 0  |             }  | 
2600  | 0  |         }  | 
2601  | 0  |     }  | 
2602  | 0  |     return FALSE;  | 
2603  | 0  | }  | 
2604  |  |  | 
2605  |  | DateTimeMatcher&  | 
2606  | 0  | PatternMapIterator::next() { | 
2607  | 0  |     while ( bootIndex < MAX_PATTERN_ENTRIES ) { | 
2608  | 0  |         if ( nodePtr != nullptr ) { | 
2609  | 0  |             if ( nodePtr->next != nullptr ) { | 
2610  | 0  |                 nodePtr = nodePtr->next.getAlias();  | 
2611  | 0  |                 break;  | 
2612  | 0  |             }  | 
2613  | 0  |             else { | 
2614  | 0  |                 bootIndex++;  | 
2615  | 0  |                 nodePtr=nullptr;  | 
2616  | 0  |                 continue;  | 
2617  | 0  |             }  | 
2618  | 0  |         }  | 
2619  | 0  |         else { | 
2620  | 0  |             if ( patternMap->boot[bootIndex] != nullptr ) { | 
2621  | 0  |                 nodePtr = patternMap->boot[bootIndex];  | 
2622  | 0  |                 break;  | 
2623  | 0  |             }  | 
2624  | 0  |             else { | 
2625  | 0  |                 bootIndex++;  | 
2626  | 0  |                 continue;  | 
2627  | 0  |             }  | 
2628  | 0  |         }  | 
2629  | 0  |     }  | 
2630  | 0  |     if (nodePtr!=nullptr) { | 
2631  | 0  |         matcher->copyFrom(*nodePtr->skeleton);  | 
2632  | 0  |     }  | 
2633  | 0  |     else { | 
2634  | 0  |         matcher->copyFrom();  | 
2635  | 0  |     }  | 
2636  | 0  |     return *matcher;  | 
2637  | 0  | }  | 
2638  |  |  | 
2639  |  |  | 
2640  | 0  | SkeletonFields::SkeletonFields() { | 
2641  |  |     // Set initial values to zero  | 
2642  | 0  |     clear();  | 
2643  | 0  | }  | 
2644  |  |  | 
2645  | 0  | void SkeletonFields::clear() { | 
2646  | 0  |     uprv_memset(chars, 0, sizeof(chars));  | 
2647  | 0  |     uprv_memset(lengths, 0, sizeof(lengths));  | 
2648  | 0  | }  | 
2649  |  |  | 
2650  | 0  | void SkeletonFields::copyFrom(const SkeletonFields& other) { | 
2651  | 0  |     uprv_memcpy(chars, other.chars, sizeof(chars));  | 
2652  | 0  |     uprv_memcpy(lengths, other.lengths, sizeof(lengths));  | 
2653  | 0  | }  | 
2654  |  |  | 
2655  | 0  | void SkeletonFields::clearField(int32_t field) { | 
2656  | 0  |     chars[field] = 0;  | 
2657  | 0  |     lengths[field] = 0;  | 
2658  | 0  | }  | 
2659  |  |  | 
2660  | 0  | UChar SkeletonFields::getFieldChar(int32_t field) const { | 
2661  | 0  |     return chars[field];  | 
2662  | 0  | }  | 
2663  |  |  | 
2664  | 0  | int32_t SkeletonFields::getFieldLength(int32_t field) const { | 
2665  | 0  |     return lengths[field];  | 
2666  | 0  | }  | 
2667  |  |  | 
2668  | 0  | void SkeletonFields::populate(int32_t field, const UnicodeString& value) { | 
2669  | 0  |     populate(field, value.charAt(0), value.length());  | 
2670  | 0  | }  | 
2671  |  |  | 
2672  | 0  | void SkeletonFields::populate(int32_t field, UChar ch, int32_t length) { | 
2673  | 0  |     chars[field] = (int8_t) ch;  | 
2674  | 0  |     lengths[field] = (int8_t) length;  | 
2675  | 0  | }  | 
2676  |  |  | 
2677  | 0  | UBool SkeletonFields::isFieldEmpty(int32_t field) const { | 
2678  | 0  |     return lengths[field] == 0;  | 
2679  | 0  | }  | 
2680  |  |  | 
2681  | 0  | UnicodeString& SkeletonFields::appendTo(UnicodeString& string) const { | 
2682  | 0  |     for (int32_t i = 0; i < UDATPG_FIELD_COUNT; ++i) { | 
2683  | 0  |         appendFieldTo(i, string);  | 
2684  | 0  |     }  | 
2685  | 0  |     return string;  | 
2686  | 0  | }  | 
2687  |  |  | 
2688  | 0  | UnicodeString& SkeletonFields::appendFieldTo(int32_t field, UnicodeString& string) const { | 
2689  | 0  |     UChar ch(chars[field]);  | 
2690  | 0  |     int32_t length = (int32_t) lengths[field];  | 
2691  |  | 
  | 
2692  | 0  |     for (int32_t i=0; i<length; i++) { | 
2693  | 0  |         string += ch;  | 
2694  | 0  |     }  | 
2695  | 0  |     return string;  | 
2696  | 0  | }  | 
2697  |  |  | 
2698  | 0  | UChar SkeletonFields::getFirstChar() const { | 
2699  | 0  |     for (int32_t i = 0; i < UDATPG_FIELD_COUNT; ++i) { | 
2700  | 0  |         if (lengths[i] != 0) { | 
2701  | 0  |             return chars[i];  | 
2702  | 0  |         }  | 
2703  | 0  |     }  | 
2704  | 0  |     return '\0';  | 
2705  | 0  | }  | 
2706  |  |  | 
2707  |  |  | 
2708  |  | PtnSkeleton::PtnSkeleton()  | 
2709  | 0  |     : addedDefaultDayPeriod(FALSE) { | 
2710  | 0  | }  | 
2711  |  |  | 
2712  | 0  | PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) { | 
2713  | 0  |     copyFrom(other);  | 
2714  | 0  | }  | 
2715  |  |  | 
2716  | 0  | void PtnSkeleton::copyFrom(const PtnSkeleton& other) { | 
2717  | 0  |     uprv_memcpy(type, other.type, sizeof(type));  | 
2718  | 0  |     original.copyFrom(other.original);  | 
2719  | 0  |     baseOriginal.copyFrom(other.baseOriginal);  | 
2720  | 0  |     addedDefaultDayPeriod = other.addedDefaultDayPeriod;  | 
2721  | 0  | }  | 
2722  |  |  | 
2723  | 0  | void PtnSkeleton::clear() { | 
2724  | 0  |     uprv_memset(type, 0, sizeof(type));  | 
2725  | 0  |     original.clear();  | 
2726  | 0  |     baseOriginal.clear();  | 
2727  | 0  | }  | 
2728  |  |  | 
2729  |  | UBool  | 
2730  | 0  | PtnSkeleton::equals(const PtnSkeleton& other) const  { | 
2731  | 0  |     return (original == other.original)  | 
2732  | 0  |         && (baseOriginal == other.baseOriginal)  | 
2733  | 0  |         && (uprv_memcmp(type, other.type, sizeof(type)) == 0);  | 
2734  | 0  | }  | 
2735  |  |  | 
2736  |  | UnicodeString  | 
2737  | 0  | PtnSkeleton::getSkeleton() const { | 
2738  | 0  |     UnicodeString result;  | 
2739  | 0  |     result = original.appendTo(result);  | 
2740  | 0  |     int32_t pos;  | 
2741  | 0  |     if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) { | 
2742  |  |         // for backward compatibility: if DateTimeMatcher.set added a single 'a' that  | 
2743  |  |         // was not in the provided skeleton, remove it here before returning skeleton.  | 
2744  | 0  |         result.remove(pos, 1);  | 
2745  | 0  |     }  | 
2746  | 0  |     return result;  | 
2747  | 0  | }  | 
2748  |  |  | 
2749  |  | UnicodeString  | 
2750  | 0  | PtnSkeleton::getBaseSkeleton() const { | 
2751  | 0  |     UnicodeString result;  | 
2752  | 0  |     result = baseOriginal.appendTo(result);  | 
2753  | 0  |     int32_t pos;  | 
2754  | 0  |     if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) { | 
2755  |  |         // for backward compatibility: if DateTimeMatcher.set added a single 'a' that  | 
2756  |  |         // was not in the provided skeleton, remove it here before returning skeleton.  | 
2757  | 0  |         result.remove(pos, 1);  | 
2758  | 0  |     }  | 
2759  | 0  |     return result;  | 
2760  | 0  | }  | 
2761  |  |  | 
2762  |  | UChar  | 
2763  | 0  | PtnSkeleton::getFirstChar() const { | 
2764  | 0  |     return baseOriginal.getFirstChar();  | 
2765  | 0  | }  | 
2766  |  |  | 
2767  | 0  | PtnSkeleton::~PtnSkeleton() { | 
2768  | 0  | }  | 
2769  |  |  | 
2770  |  | PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) :  | 
2771  | 0  |     basePattern(basePat), skeleton(nullptr), pattern(pat), next(nullptr)  | 
2772  | 0  | { | 
2773  | 0  | }  | 
2774  |  |  | 
2775  | 0  | PtnElem::~PtnElem() { | 
2776  | 0  | }  | 
2777  |  |  | 
2778  | 0  | DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status) : fSkeletons(nullptr) { | 
2779  | 0  |     PtnElem  *curElem;  | 
2780  | 0  |     PtnSkeleton *curSkeleton;  | 
2781  | 0  |     UnicodeString s;  | 
2782  | 0  |     int32_t bootIndex;  | 
2783  |  | 
  | 
2784  | 0  |     pos=0;  | 
2785  | 0  |     fSkeletons.adoptInsteadAndCheckErrorCode(new UVector(status), status);  | 
2786  | 0  |     if (U_FAILURE(status)) { | 
2787  | 0  |         return;  | 
2788  | 0  |     }  | 
2789  |  |  | 
2790  | 0  |     for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) { | 
2791  | 0  |         curElem = patternMap.boot[bootIndex];  | 
2792  | 0  |         while (curElem!=nullptr) { | 
2793  | 0  |             switch(type) { | 
2794  | 0  |                 case DT_BASESKELETON:  | 
2795  | 0  |                     s=curElem->basePattern;  | 
2796  | 0  |                     break;  | 
2797  | 0  |                 case DT_PATTERN:  | 
2798  | 0  |                     s=curElem->pattern;  | 
2799  | 0  |                     break;  | 
2800  | 0  |                 case DT_SKELETON:  | 
2801  | 0  |                     curSkeleton=curElem->skeleton.getAlias();  | 
2802  | 0  |                     s=curSkeleton->getSkeleton();  | 
2803  | 0  |                     break;  | 
2804  | 0  |             }  | 
2805  | 0  |             if ( !isCanonicalItem(s) ) { | 
2806  | 0  |                 LocalPointer<UnicodeString> newElem(new UnicodeString(s), status);  | 
2807  | 0  |                 if (U_FAILURE(status)) {  | 
2808  | 0  |                     return;  | 
2809  | 0  |                 }  | 
2810  | 0  |                 fSkeletons->addElementX(newElem.getAlias(), status);  | 
2811  | 0  |                 if (U_FAILURE(status)) { | 
2812  | 0  |                     fSkeletons.adoptInstead(nullptr);  | 
2813  | 0  |                     return;  | 
2814  | 0  |                 }  | 
2815  | 0  |                 newElem.orphan(); // fSkeletons vector now owns the UnicodeString.  | 
2816  | 0  |             }  | 
2817  | 0  |             curElem = curElem->next.getAlias();  | 
2818  | 0  |         }  | 
2819  | 0  |     }  | 
2820  | 0  |     if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=nullptr) ) { | 
2821  | 0  |         status = U_BUFFER_OVERFLOW_ERROR;  | 
2822  | 0  |     }  | 
2823  | 0  | }  | 
2824  |  |  | 
2825  |  | const UnicodeString*  | 
2826  | 0  | DTSkeletonEnumeration::snext(UErrorCode& status) { | 
2827  | 0  |     if (U_SUCCESS(status) && fSkeletons.isValid() && pos < fSkeletons->size()) { | 
2828  | 0  |         return (const UnicodeString*)fSkeletons->elementAt(pos++);  | 
2829  | 0  |     }  | 
2830  | 0  |     return nullptr;  | 
2831  | 0  | }  | 
2832  |  |  | 
2833  |  | void  | 
2834  | 0  | DTSkeletonEnumeration::reset(UErrorCode& /*status*/) { | 
2835  | 0  |     pos=0;  | 
2836  | 0  | }  | 
2837  |  |  | 
2838  |  | int32_t  | 
2839  | 0  | DTSkeletonEnumeration::count(UErrorCode& /*status*/) const { | 
2840  | 0  |    return (fSkeletons.isNull()) ? 0 : fSkeletons->size();  | 
2841  | 0  | }  | 
2842  |  |  | 
2843  |  | UBool  | 
2844  | 0  | DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) { | 
2845  | 0  |     if ( item.length() != 1 ) { | 
2846  | 0  |         return FALSE;  | 
2847  | 0  |     }  | 
2848  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { | 
2849  | 0  |         if (item.charAt(0)==Canonical_Items[i]) { | 
2850  | 0  |             return TRUE;  | 
2851  | 0  |         }  | 
2852  | 0  |     }  | 
2853  | 0  |     return FALSE;  | 
2854  | 0  | }  | 
2855  |  |  | 
2856  | 0  | DTSkeletonEnumeration::~DTSkeletonEnumeration() { | 
2857  | 0  |     UnicodeString *s;  | 
2858  | 0  |     if (fSkeletons.isValid()) { | 
2859  | 0  |         for (int32_t i = 0; i < fSkeletons->size(); ++i) { | 
2860  | 0  |             if ((s = (UnicodeString *)fSkeletons->elementAt(i)) != nullptr) { | 
2861  | 0  |                 delete s;  | 
2862  | 0  |             }  | 
2863  | 0  |         }  | 
2864  | 0  |     }  | 
2865  | 0  | }  | 
2866  |  |  | 
2867  | 0  | DTRedundantEnumeration::DTRedundantEnumeration() : pos(0), fPatterns(nullptr) { | 
2868  | 0  | }  | 
2869  |  |  | 
2870  |  | void  | 
2871  | 0  | DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) { | 
2872  | 0  |     if (U_FAILURE(status)) { return; } | 
2873  | 0  |     if (fPatterns.isNull())  { | 
2874  | 0  |         fPatterns.adoptInsteadAndCheckErrorCode(new UVector(status), status);  | 
2875  | 0  |         if (U_FAILURE(status)) { | 
2876  | 0  |             return;  | 
2877  | 0  |        }  | 
2878  | 0  |     }  | 
2879  | 0  |     LocalPointer<UnicodeString> newElem(new UnicodeString(pattern), status);  | 
2880  | 0  |     if (U_FAILURE(status)) { | 
2881  | 0  |         return;  | 
2882  | 0  |     }  | 
2883  | 0  |     fPatterns->addElementX(newElem.getAlias(), status);  | 
2884  | 0  |     if (U_FAILURE(status)) { | 
2885  | 0  |         fPatterns.adoptInstead(nullptr);  | 
2886  | 0  |         return;  | 
2887  | 0  |     }  | 
2888  | 0  |     newElem.orphan(); // fPatterns now owns the string.  | 
2889  | 0  | }  | 
2890  |  |  | 
2891  |  | const UnicodeString*  | 
2892  | 0  | DTRedundantEnumeration::snext(UErrorCode& status) { | 
2893  | 0  |     if (U_SUCCESS(status) && fPatterns.isValid() && pos < fPatterns->size()) { | 
2894  | 0  |         return (const UnicodeString*)fPatterns->elementAt(pos++);  | 
2895  | 0  |     }  | 
2896  | 0  |     return nullptr;  | 
2897  | 0  | }  | 
2898  |  |  | 
2899  |  | void  | 
2900  | 0  | DTRedundantEnumeration::reset(UErrorCode& /*status*/) { | 
2901  | 0  |     pos=0;  | 
2902  | 0  | }  | 
2903  |  |  | 
2904  |  | int32_t  | 
2905  | 0  | DTRedundantEnumeration::count(UErrorCode& /*status*/) const { | 
2906  | 0  |     return (fPatterns.isNull()) ? 0 : fPatterns->size();  | 
2907  | 0  | }  | 
2908  |  |  | 
2909  |  | UBool  | 
2910  | 0  | DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) const { | 
2911  | 0  |     if ( item.length() != 1 ) { | 
2912  | 0  |         return FALSE;  | 
2913  | 0  |     }  | 
2914  | 0  |     for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { | 
2915  | 0  |         if (item.charAt(0)==Canonical_Items[i]) { | 
2916  | 0  |             return TRUE;  | 
2917  | 0  |         }  | 
2918  | 0  |     }  | 
2919  | 0  |     return FALSE;  | 
2920  | 0  | }  | 
2921  |  |  | 
2922  | 0  | DTRedundantEnumeration::~DTRedundantEnumeration() { | 
2923  | 0  |     UnicodeString *s;  | 
2924  | 0  |     if (fPatterns.isValid()) { | 
2925  | 0  |         for (int32_t i = 0; i < fPatterns->size(); ++i) { | 
2926  | 0  |             if ((s = (UnicodeString *)fPatterns->elementAt(i)) != nullptr) { | 
2927  | 0  |                 delete s;  | 
2928  | 0  |             }  | 
2929  | 0  |         }  | 
2930  | 0  |     }      | 
2931  | 0  | }  | 
2932  |  |  | 
2933  |  | U_NAMESPACE_END  | 
2934  |  |  | 
2935  |  |  | 
2936  |  | #endif /* #if !UCONFIG_NO_FORMATTING */  | 
2937  |  |  | 
2938  |  | //eof  |