]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/dtptngen.cpp
ICU-57149.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / dtptngen.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 2007-2016, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 *
7 * File DTPTNGEN.CPP
8 *
9 *******************************************************************************
10 */
11
12 #include "unicode/utypes.h"
13 #if !UCONFIG_NO_FORMATTING
14
15 #include "unicode/datefmt.h"
16 #include "unicode/decimfmt.h"
17 #include "unicode/dtfmtsym.h"
18 #include "unicode/dtptngen.h"
19 #include "unicode/simpleformatter.h"
20 #include "unicode/smpdtfmt.h"
21 #include "unicode/udat.h"
22 #include "unicode/udatpg.h"
23 #include "unicode/uniset.h"
24 #include "unicode/uloc.h"
25 #include "unicode/ures.h"
26 #include "unicode/ustring.h"
27 #include "unicode/rep.h"
28 #include "cpputils.h"
29 #include "mutex.h"
30 #include "umutex.h"
31 #include "cmemory.h"
32 #include "cstring.h"
33 #include "locbased.h"
34 #include "gregoimp.h"
35 #include "hash.h"
36 #include "uhash.h"
37 #include "uresimp.h"
38 #include "dtptngen_impl.h"
39 #include "ucln_in.h"
40 #include "charstr.h"
41
42 #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
43 /**
44 * If we are on EBCDIC, use an iterator which will
45 * traverse the bundles in ASCII order.
46 */
47 #define U_USE_ASCII_BUNDLE_ITERATOR
48 #define U_SORT_ASCII_BUNDLE_ITERATOR
49 #endif
50
51 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
52
53 #include "unicode/ustring.h"
54 #include "uarrsort.h"
55
56 struct UResAEntry {
57 UChar *key;
58 UResourceBundle *item;
59 };
60
61 struct UResourceBundleAIterator {
62 UResourceBundle *bund;
63 UResAEntry *entries;
64 int32_t num;
65 int32_t cursor;
66 };
67
68 /* Must be C linkage to pass function pointer to the sort function */
69
70 U_CDECL_BEGIN
71
72 static int32_t U_CALLCONV
73 ures_a_codepointSort(const void *context, const void *left, const void *right) {
74 //CompareContext *cmp=(CompareContext *)context;
75 return u_strcmp(((const UResAEntry *)left)->key,
76 ((const UResAEntry *)right)->key);
77 }
78
79 U_CDECL_END
80
81 static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund, UErrorCode *status) {
82 if(U_FAILURE(*status)) {
83 return;
84 }
85 aiter->bund = bund;
86 aiter->num = ures_getSize(aiter->bund);
87 aiter->cursor = 0;
88 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
89 aiter->entries = NULL;
90 #else
91 aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num);
92 for(int i=0;i<aiter->num;i++) {
93 aiter->entries[i].item = ures_getByIndex(aiter->bund, i, NULL, status);
94 const char *akey = ures_getKey(aiter->entries[i].item);
95 int32_t len = uprv_strlen(akey)+1;
96 aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar));
97 u_charsToUChars(akey, aiter->entries[i].key, len);
98 }
99 uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, NULL, TRUE, status);
100 #endif
101 }
102
103 static void ures_a_close(UResourceBundleAIterator *aiter) {
104 #if defined(U_SORT_ASCII_BUNDLE_ITERATOR)
105 for(int i=0;i<aiter->num;i++) {
106 uprv_free(aiter->entries[i].key);
107 ures_close(aiter->entries[i].item);
108 }
109 #endif
110 }
111
112 static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_t *len, const char **key, UErrorCode *err) {
113 #if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
114 return ures_getNextString(aiter->bund, len, key, err);
115 #else
116 if(U_FAILURE(*err)) return NULL;
117 UResourceBundle *item = aiter->entries[aiter->cursor].item;
118 const UChar* ret = ures_getString(item, len, err);
119 *key = ures_getKey(item);
120 aiter->cursor++;
121 return ret;
122 #endif
123 }
124
125
126 #endif
127
128
129 U_NAMESPACE_BEGIN
130
131 // *****************************************************************************
132 // class DateTimePatternGenerator
133 // *****************************************************************************
134 static const UChar Canonical_Items[] = {
135 // GyQMwWEdDFHmsSv
136 CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_E, LOW_D, CAP_D, CAP_F,
137 CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0
138 };
139
140 static const dtTypeElem dtTypes[] = {
141 // patternChar, field, type, minLen, weight
142 {CAP_G, UDATPG_ERA_FIELD, DT_SHORT, 1, 3,},
143 {CAP_G, UDATPG_ERA_FIELD, DT_LONG, 4, 0},
144 {LOW_Y, UDATPG_YEAR_FIELD, DT_NUMERIC, 1, 20},
145 {CAP_Y, UDATPG_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 20},
146 {LOW_U, UDATPG_YEAR_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 20},
147 {LOW_R, UDATPG_YEAR_FIELD, DT_NUMERIC + 3*DT_DELTA, 1, 20},
148 {CAP_U, UDATPG_YEAR_FIELD, DT_SHORT, 1, 3},
149 {CAP_U, UDATPG_YEAR_FIELD, DT_LONG, 4, 0},
150 {CAP_U, UDATPG_YEAR_FIELD, DT_NARROW, 5, 0},
151 {CAP_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC, 1, 2},
152 {CAP_Q, UDATPG_QUARTER_FIELD, DT_SHORT, 3, 0},
153 {CAP_Q, UDATPG_QUARTER_FIELD, DT_LONG, 4, 0},
154 {LOW_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
155 {LOW_Q, UDATPG_QUARTER_FIELD, DT_SHORT + DT_DELTA, 3, 0},
156 {LOW_Q, UDATPG_QUARTER_FIELD, DT_LONG + DT_DELTA, 4, 0},
157 {CAP_M, UDATPG_MONTH_FIELD, DT_NUMERIC, 1, 2},
158 {CAP_M, UDATPG_MONTH_FIELD, DT_SHORT, 3, 0},
159 {CAP_M, UDATPG_MONTH_FIELD, DT_LONG, 4, 0},
160 {CAP_M, UDATPG_MONTH_FIELD, DT_NARROW, 5, 0},
161 {CAP_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
162 {CAP_L, UDATPG_MONTH_FIELD, DT_SHORT - DT_DELTA, 3, 0},
163 {CAP_L, UDATPG_MONTH_FIELD, DT_LONG - DT_DELTA, 4, 0},
164 {CAP_L, UDATPG_MONTH_FIELD, DT_NARROW - DT_DELTA, 5, 0},
165 {LOW_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 1},
166 {LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2},
167 {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 0},
168 {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORT, 1, 3},
169 {CAP_E, UDATPG_WEEKDAY_FIELD, DT_LONG, 4, 0},
170 {CAP_E, UDATPG_WEEKDAY_FIELD, DT_NARROW, 5, 0},
171 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 2},
172 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORT - 2*DT_DELTA, 3, 0},
173 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
174 {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NARROW - 2*DT_DELTA, 5, 0},
175 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // LOW_E is currently not used in CLDR data, should not be canonical
176 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORT - DT_DELTA, 3, 0},
177 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_LONG - DT_DELTA, 4, 0},
178 {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NARROW - DT_DELTA, 5, 0},
179 {LOW_D, UDATPG_DAY_FIELD, DT_NUMERIC, 1, 2},
180 {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 3},
181 {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 0},
182 {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + 3*DT_DELTA, 1, 20}, // really internal use, so we don't care
183 {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 0},
184 {CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour
185 {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2}, // 24 hour
186 {LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour
187 {CAP_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // 12 hour
188 {LOW_M, UDATPG_MINUTE_FIELD, DT_NUMERIC, 1, 2},
189 {LOW_S, UDATPG_SECOND_FIELD, DT_NUMERIC, 1, 2},
190 {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000},
191 {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 1000},
192 {LOW_V, UDATPG_ZONE_FIELD, DT_SHORT - 2*DT_DELTA, 1, 0},
193 {LOW_V, UDATPG_ZONE_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
194 {LOW_Z, UDATPG_ZONE_FIELD, DT_SHORT, 1, 3},
195 {LOW_Z, UDATPG_ZONE_FIELD, DT_LONG, 4, 0},
196 {CAP_Z, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 3},
197 {CAP_Z, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
198 {CAP_Z, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 5, 0},
199 {CAP_O, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0},
200 {CAP_O, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
201 {CAP_V, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0},
202 {CAP_V, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 2, 0},
203 {CAP_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0},
204 {CAP_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0},
205 {CAP_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
206 {LOW_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0},
207 {LOW_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0},
208 {LOW_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
209 {LOW_J, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12/24 hour
210 {CAP_J, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12/24 hour no AM/PM
211 {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
212 };
213
214 static const char* const CLDR_FIELD_APPEND[] = {
215 "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
216 "Hour", "Minute", "Second", "*", "Timezone"
217 };
218
219 static const char* const CLDR_FIELD_NAME[] = {
220 "era", "year", "quarter", "month", "week", "*", "weekday", "*", "*", "day", "dayperiod",
221 "hour", "minute", "second", "*", "zone"
222 };
223
224 static const char* const Resource_Fields[] = {
225 "day", "dayperiod", "era", "hour", "minute", "month", "second", "week",
226 "weekday", "year", "zone", "quarter" };
227
228 // For appendItems
229 static const UChar UDATPG_ItemFormat[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
230 0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524
231
232 //static const UChar repeatedPatterns[6]={CAP_G, CAP_E, LOW_Z, LOW_V, CAP_Q, 0}; // "GEzvQ"
233
234 static const char DT_DateTimePatternsTag[]="DateTimePatterns";
235 static const char DT_DateTimeCalendarTag[]="calendar";
236 static const char DT_DateTimeGregorianTag[]="gregorian";
237 static const char DT_DateTimeAppendItemsTag[]="appendItems";
238 static const char DT_DateTimeFieldsTag[]="fields";
239 static const char DT_DateTimeAvailableFormatsTag[]="availableFormats";
240 //static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);
241
242 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator)
243 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration)
244 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration)
245
246 DateTimePatternGenerator* U_EXPORT2
247 DateTimePatternGenerator::createInstance(UErrorCode& status) {
248 return createInstance(Locale::getDefault(), status);
249 }
250
251 DateTimePatternGenerator* U_EXPORT2
252 DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) {
253 if (U_FAILURE(status)) {
254 return NULL;
255 }
256 LocalPointer<DateTimePatternGenerator> result(
257 new DateTimePatternGenerator(locale, status), status);
258 return U_SUCCESS(status) ? result.orphan() : NULL;
259 }
260
261 DateTimePatternGenerator* U_EXPORT2
262 DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) {
263 DateTimePatternGenerator *result = new DateTimePatternGenerator(status);
264 if (result == NULL) {
265 status = U_MEMORY_ALLOCATION_ERROR;
266 }
267 if (U_FAILURE(status)) {
268 delete result;
269 result = NULL;
270 }
271 return result;
272 }
273
274 DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) :
275 skipMatcher(NULL),
276 fAvailableFormatKeyHash(NULL)
277 {
278 fp = new FormatParser();
279 dtMatcher = new DateTimeMatcher();
280 distanceInfo = new DistanceInfo();
281 patternMap = new PatternMap();
282 if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
283 status = U_MEMORY_ALLOCATION_ERROR;
284 }
285 }
286
287 DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) :
288 skipMatcher(NULL),
289 fAvailableFormatKeyHash(NULL)
290 {
291 fp = new FormatParser();
292 dtMatcher = new DateTimeMatcher();
293 distanceInfo = new DistanceInfo();
294 patternMap = new PatternMap();
295 if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
296 status = U_MEMORY_ALLOCATION_ERROR;
297 }
298 else {
299 initData(locale, status);
300 }
301 }
302
303 DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) :
304 UObject(),
305 skipMatcher(NULL),
306 fAvailableFormatKeyHash(NULL)
307 {
308 fp = new FormatParser();
309 dtMatcher = new DateTimeMatcher();
310 distanceInfo = new DistanceInfo();
311 patternMap = new PatternMap();
312 *this=other;
313 }
314
315 DateTimePatternGenerator&
316 DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
317 // reflexive case
318 if (&other == this) {
319 return *this;
320 }
321 pLocale = other.pLocale;
322 fDefaultHourFormatChar = other.fDefaultHourFormatChar;
323 *fp = *(other.fp);
324 dtMatcher->copyFrom(other.dtMatcher->skeleton);
325 *distanceInfo = *(other.distanceInfo);
326 dateTimeFormat = other.dateTimeFormat;
327 decimal = other.decimal;
328 // NUL-terminate for the C API.
329 dateTimeFormat.getTerminatedBuffer();
330 decimal.getTerminatedBuffer();
331 delete skipMatcher;
332 if ( other.skipMatcher == NULL ) {
333 skipMatcher = NULL;
334 }
335 else {
336 skipMatcher = new DateTimeMatcher(*other.skipMatcher);
337 }
338 for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) {
339 appendItemFormats[i] = other.appendItemFormats[i];
340 appendItemNames[i] = other.appendItemNames[i];
341 // NUL-terminate for the C API.
342 appendItemFormats[i].getTerminatedBuffer();
343 appendItemNames[i].getTerminatedBuffer();
344 }
345 UErrorCode status = U_ZERO_ERROR;
346 patternMap->copyFrom(*other.patternMap, status);
347 copyHashtable(other.fAvailableFormatKeyHash, status);
348 return *this;
349 }
350
351
352 UBool
353 DateTimePatternGenerator::operator==(const DateTimePatternGenerator& other) const {
354 if (this == &other) {
355 return TRUE;
356 }
357 if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) &&
358 (dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) {
359 for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) {
360 if ((appendItemFormats[i] != other.appendItemFormats[i]) ||
361 (appendItemNames[i] != other.appendItemNames[i]) ) {
362 return FALSE;
363 }
364 }
365 return TRUE;
366 }
367 else {
368 return FALSE;
369 }
370 }
371
372 UBool
373 DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) const {
374 return !operator==(other);
375 }
376
377 DateTimePatternGenerator::~DateTimePatternGenerator() {
378 if (fAvailableFormatKeyHash!=NULL) {
379 delete fAvailableFormatKeyHash;
380 }
381
382 if (fp != NULL) delete fp;
383 if (dtMatcher != NULL) delete dtMatcher;
384 if (distanceInfo != NULL) delete distanceInfo;
385 if (patternMap != NULL) delete patternMap;
386 if (skipMatcher != NULL) delete skipMatcher;
387 }
388
389 namespace {
390
391 UInitOnce initOnce = U_INITONCE_INITIALIZER;
392 UHashtable *localeToAllowedHourFormatsMap = NULL;
393
394 // Value deleter for hashmap.
395 void deleteAllowedHourFormats(void *ptr) {
396 uprv_free(ptr);
397 }
398
399 // Close hashmap at cleanup.
400 UBool allowedHourFormatsCleanup() {
401 uhash_close(localeToAllowedHourFormatsMap);
402 return TRUE;
403 }
404
405 enum AllowedHourFormat{
406 ALLOWED_HOUR_FORMAT_UNKNOWN = -1,
407 ALLOWED_HOUR_FORMAT_h,
408 ALLOWED_HOUR_FORMAT_H,
409 ALLOWED_HOUR_FORMAT_hb,
410 ALLOWED_HOUR_FORMAT_Hb,
411 ALLOWED_HOUR_FORMAT_hB,
412 ALLOWED_HOUR_FORMAT_HB
413 };
414
415 } // namespace
416
417 void
418 DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
419 //const char *baseLangName = locale.getBaseName(); // unused
420
421 skipMatcher = NULL;
422 fAvailableFormatKeyHash=NULL;
423 addCanonicalItems();
424 addICUPatterns(locale, status);
425 if (U_FAILURE(status)) {
426 return;
427 }
428 addCLDRData(locale, status);
429 setDateTimeFromCalendar(locale, status);
430 setDecimalSymbols(locale, status);
431 umtx_initOnce(initOnce, loadAllowedHourFormatsData, status);
432 getAllowedHourFormats(locale, status);
433 } // DateTimePatternGenerator::initData
434
435 namespace {
436
437 struct AllowedHourFormatsSink : public ResourceTableSink {
438 // Initialize sub-sinks.
439 AllowedHourFormatsSink() : localeSink(*this), allowedListSink(*this) {}
440 virtual ~AllowedHourFormatsSink();
441
442 // Entry point.
443 virtual ResourceTableSink *getOrCreateTableSink(const char *key, int32_t, UErrorCode &status) {
444 if (U_FAILURE(status)) { return NULL; }
445
446 locale = key;
447 return &localeSink;
448 }
449
450 struct LocaleSink : public ResourceTableSink {
451 AllowedHourFormatsSink &outer;
452 LocaleSink(AllowedHourFormatsSink &outer) : outer(outer) {}
453 virtual ~LocaleSink();
454
455 virtual void put(const char *key, const ResourceValue &value, UErrorCode &status) {
456 if (U_FAILURE(status)) { return; }
457
458 if (uprv_strcmp(key, "allowed") == 0) {
459 outer.allowedFormats = static_cast<int32_t *>(uprv_malloc(2 * sizeof(int32_t)));
460 outer.allowedFormatsLength = 1;
461 if (outer.allowedFormats == NULL) {
462 status = U_MEMORY_ALLOCATION_ERROR;
463 return;
464 }
465 outer.allowedFormats[0] = outer.getHourFormatFromUnicodeString(
466 value.getUnicodeString(status));
467 }
468 }
469
470 virtual ResourceArraySink *getOrCreateArraySink(const char *key, int32_t size, UErrorCode &status) {
471 if (U_FAILURE(status)) { return NULL; }
472
473 if (uprv_strcmp(key, "allowed") == 0) {
474 outer.allowedFormats = static_cast<int32_t *>(uprv_malloc((size + 1) * sizeof(int32_t)));
475 outer.allowedFormatsLength = size;
476 if (outer.allowedFormats == NULL) {
477 status = U_MEMORY_ALLOCATION_ERROR;
478 return NULL;
479 } else {
480 return &outer.allowedListSink;
481 }
482 }
483 return NULL;
484 }
485
486 virtual void leave(UErrorCode &status) {
487 if (U_FAILURE(status) || outer.allowedFormats == NULL) { return; }
488
489 outer.allowedFormats[outer.allowedFormatsLength] = ALLOWED_HOUR_FORMAT_UNKNOWN;
490 uhash_put(localeToAllowedHourFormatsMap, const_cast<char *>(outer.locale), outer.allowedFormats, &status);
491 outer.allowedFormats = NULL;
492 }
493 } localeSink;
494
495 struct AllowedListSink : public ResourceArraySink {
496 AllowedHourFormatsSink &outer;
497 AllowedListSink(AllowedHourFormatsSink &outer) : outer(outer) {}
498 virtual ~AllowedListSink();
499
500 virtual void put(int32_t index, const ResourceValue &value, UErrorCode &status) {
501 if (U_FAILURE(status)) { return; }
502
503 outer.allowedFormats[index] = outer.getHourFormatFromUnicodeString(
504 value.getUnicodeString(status));
505 }
506 } allowedListSink;
507
508 const char *locale;
509 int32_t *allowedFormats;
510 int32_t allowedFormatsLength;
511
512 AllowedHourFormat getHourFormatFromUnicodeString(UnicodeString s) {
513 if (s.length() == 1) {
514 if (s[0] == LOW_H) { return ALLOWED_HOUR_FORMAT_h; }
515 if (s[0] == CAP_H) { return ALLOWED_HOUR_FORMAT_H; }
516 } else if (s.length() == 2) {
517 if (s[0] == LOW_H && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_hb; }
518 if (s[0] == CAP_H && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_Hb; }
519 if (s[0] == LOW_H && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_hB; }
520 if (s[0] == CAP_H && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_HB; }
521 }
522
523 return ALLOWED_HOUR_FORMAT_UNKNOWN;
524 }
525 };
526
527 } // namespace
528
529 AllowedHourFormatsSink::~AllowedHourFormatsSink() {}
530 AllowedHourFormatsSink::LocaleSink::~LocaleSink() {}
531 AllowedHourFormatsSink::AllowedListSink::~AllowedListSink() {}
532
533 void DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
534 if (U_FAILURE(status)) { return; }
535 localeToAllowedHourFormatsMap = uhash_open(
536 uhash_hashChars, uhash_compareChars, NULL, &status);
537 uhash_setValueDeleter(localeToAllowedHourFormatsMap, deleteAllowedHourFormats);
538 LocalUResourceBundlePointer rb(ures_openDirect(NULL, "supplementalData", &status));
539
540 AllowedHourFormatsSink sink;
541 // TODO: Currently in the enumeration each table allocates a new array.
542 // Try to reduce the number of memory allocations. Consider storing a
543 // UVector32 with the concatenation of all of the sub-arrays, put the start index
544 // into the hashmap, store 6 single-value sub-arrays right at the beginning of the
545 // vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime
546 // object. Remember to clean up the vector, too.
547 ures_getAllTableItemsWithFallback(rb.getAlias(), "timeData", sink, status);
548
549 ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
550 }
551
552 void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErrorCode &status) {
553 if (U_FAILURE(status)) { return; }
554
555 const char *localeID = locale.getName();
556 char maxLocaleID[ULOC_FULLNAME_CAPACITY];
557 int32_t length = uloc_addLikelySubtags(localeID, maxLocaleID, ULOC_FULLNAME_CAPACITY, &status);
558 if (U_FAILURE(status)) {
559 return;
560 } else if (length == ULOC_FULLNAME_CAPACITY) { // no room for NUL
561 status = U_BUFFER_OVERFLOW_ERROR;
562 return;
563 }
564 Locale maxLocale = Locale(maxLocaleID);
565
566 const char *country = maxLocale.getCountry();
567 if (*country == '\0') { country = "001"; }
568 const char *language = maxLocale.getLanguage();
569
570 CharString langCountry;
571 langCountry.append(language, uprv_strlen(language), status);
572 langCountry.append('_', status);
573 langCountry.append(country, uprv_strlen(country), status);
574
575 int32_t *allowedFormats;
576 allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, langCountry.data());
577 if (allowedFormats == NULL) {
578 allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, const_cast<char *>(country));
579 }
580
581 if (allowedFormats != NULL) { // Lookup is successful
582 for (int32_t i = 0; i < UPRV_LENGTHOF(fAllowedHourFormats); ++i) {
583 fAllowedHourFormats[i] = allowedFormats[i];
584 if (allowedFormats[i] == ALLOWED_HOUR_FORMAT_UNKNOWN) {
585 break;
586 }
587 }
588 } else { // Lookup failed, twice
589 fAllowedHourFormats[0] = ALLOWED_HOUR_FORMAT_H;
590 fAllowedHourFormats[1] = ALLOWED_HOUR_FORMAT_UNKNOWN;
591 }
592 }
593
594 UnicodeString
595 DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode&
596 /*status*/) {
597 FormatParser fp;
598 DateTimeMatcher matcher;
599 PtnSkeleton localSkeleton;
600 matcher.set(pattern, &fp, localSkeleton);
601 return localSkeleton.getSkeleton();
602 }
603
604 UnicodeString
605 DateTimePatternGenerator::staticGetSkeleton(
606 const UnicodeString& pattern, UErrorCode& /*status*/) {
607 FormatParser fp;
608 DateTimeMatcher matcher;
609 PtnSkeleton localSkeleton;
610 matcher.set(pattern, &fp, localSkeleton);
611 return localSkeleton.getSkeleton();
612 }
613
614 UnicodeString
615 DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) {
616 FormatParser fp;
617 DateTimeMatcher matcher;
618 PtnSkeleton localSkeleton;
619 matcher.set(pattern, &fp, localSkeleton);
620 return localSkeleton.getBaseSkeleton();
621 }
622
623 UnicodeString
624 DateTimePatternGenerator::staticGetBaseSkeleton(
625 const UnicodeString& pattern, UErrorCode& /*status*/) {
626 FormatParser fp;
627 DateTimeMatcher matcher;
628 PtnSkeleton localSkeleton;
629 matcher.set(pattern, &fp, localSkeleton);
630 return localSkeleton.getBaseSkeleton();
631 }
632
633 void
634 DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& status) {
635 UnicodeString dfPattern;
636 UnicodeString conflictingString;
637 DateFormat* df;
638
639 if (U_FAILURE(status)) {
640 return;
641 }
642
643 // Load with ICU patterns
644 for (int32_t i=DateFormat::kFull; i<=DateFormat::kShort; i++) {
645 DateFormat::EStyle style = (DateFormat::EStyle)i;
646 df = DateFormat::createDateInstance(style, locale);
647 SimpleDateFormat* sdf;
648 if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
649 addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status);
650 }
651 // TODO Maybe we should return an error when the date format isn't simple.
652 delete df;
653 if (U_FAILURE(status)) {
654 return;
655 }
656
657 df = DateFormat::createTimeInstance(style, locale);
658 if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
659 addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status);
660 // HACK for hh:ss
661 if ( i==DateFormat::kMedium ) {
662 hackPattern = dfPattern;
663 }
664 }
665 // TODO Maybe we should return an error when the date format isn't simple.
666 delete df;
667 if (U_FAILURE(status)) {
668 return;
669 }
670 }
671 }
672
673 void
674 DateTimePatternGenerator::hackTimes(const UnicodeString& hackPattern, UErrorCode& status) {
675 UnicodeString conflictingString;
676
677 fp->set(hackPattern);
678 UnicodeString mmss;
679 UBool gotMm=FALSE;
680 for (int32_t i=0; i<fp->itemNumber; ++i) {
681 UnicodeString field = fp->items[i];
682 if ( fp->isQuoteLiteral(field) ) {
683 if ( gotMm ) {
684 UnicodeString quoteLiteral;
685 fp->getQuoteLiteral(quoteLiteral, &i);
686 mmss += quoteLiteral;
687 }
688 }
689 else {
690 if (fp->isPatternSeparator(field) && gotMm) {
691 mmss+=field;
692 }
693 else {
694 UChar ch=field.charAt(0);
695 if (ch==LOW_M) {
696 gotMm=TRUE;
697 mmss+=field;
698 }
699 else {
700 if (ch==LOW_S) {
701 if (!gotMm) {
702 break;
703 }
704 mmss+= field;
705 addPattern(mmss, FALSE, conflictingString, status);
706 break;
707 }
708 else {
709 if (gotMm || ch==LOW_Z || ch==CAP_Z || ch==LOW_V || ch==CAP_V) {
710 break;
711 }
712 }
713 }
714 }
715 }
716 }
717 }
718
719 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
720
721 static const UChar hourFormatChars[] = { CAP_H, LOW_H, CAP_K, LOW_K, 0 }; // HhKk, the hour format characters
722
723 void
724 DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& err) {
725 UResourceBundle *rb, *calTypeBundle, *calBundle;
726 UResourceBundle *patBundle, *fieldBundle, *fBundle;
727 UnicodeString rbPattern, value, field;
728 UnicodeString conflictingPattern;
729 const char *key=NULL;
730 int32_t i;
731
732 UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, UPRV_LENGTHOF(UDATPG_ItemFormat)-1); // Read-only alias.
733
734 err = U_ZERO_ERROR;
735
736 fDefaultHourFormatChar = 0;
737 for (i=0; i<UDATPG_FIELD_COUNT; ++i ) {
738 appendItemNames[i]=CAP_F;
739 if (i<10) {
740 appendItemNames[i]+=(UChar)(i+0x30);
741 }
742 else {
743 appendItemNames[i]+=(UChar)0x31;
744 appendItemNames[i]+=(UChar)(i-10 + 0x30);
745 }
746 // NUL-terminate for the C API.
747 appendItemNames[i].getTerminatedBuffer();
748 }
749
750 rb = ures_open(NULL, locale.getName(), &err);
751 if (rb == NULL || U_FAILURE(err)) {
752 return;
753 }
754 const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err);
755 const char * calendarTypeToUse = DT_DateTimeGregorianTag; // initial default
756 char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
757 if ( U_SUCCESS(err) ) {
758 char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
759 // obtain a locale that always has the calendar key value that should be used
760 (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
761 "calendar", "calendar", locale.getName(), NULL, FALSE, &err);
762 localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
763 // now get the calendar key value from that locale
764 int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &err);
765 if (U_SUCCESS(err) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
766 calendarTypeToUse = calendarType;
767 }
768 err = U_ZERO_ERROR;
769 }
770 calBundle = ures_getByKeyWithFallback(rb, DT_DateTimeCalendarTag, NULL, &err);
771 calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &err);
772
773 key=NULL;
774 int32_t dtCount=0;
775 patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimePatternsTag, NULL, &err);
776 while (U_SUCCESS(err)) {
777 rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
778 dtCount++;
779 if (rbPattern.length()==0 ) {
780 break; // no more pattern
781 }
782 else {
783 if (dtCount==9) {
784 setDateTimeFormat(rbPattern);
785 } else if (dtCount==4) { // short time format
786 // set fDefaultHourFormatChar to the hour format character from this pattern
787 int32_t tfIdx, tfLen = rbPattern.length();
788 UBool ignoreChars = FALSE;
789 for (tfIdx = 0; tfIdx < tfLen; tfIdx++) {
790 UChar tfChar = rbPattern.charAt(tfIdx);
791 if ( tfChar == SINGLE_QUOTE ) {
792 ignoreChars = !ignoreChars; // toggle (handle quoted literals & '' for single quote)
793 } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != NULL ) {
794 fDefaultHourFormatChar = tfChar;
795 break;
796 }
797 }
798 }
799 }
800 }
801 ures_close(patBundle);
802
803 err = U_ZERO_ERROR;
804 patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimeAppendItemsTag, NULL, &err);
805 key=NULL;
806 UnicodeString itemKey;
807 while (U_SUCCESS(err)) {
808 rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
809 if (rbPattern.length()==0 ) {
810 break; // no more pattern
811 }
812 else {
813 setAppendItemFormat(getAppendFormatNumber(key), rbPattern);
814 }
815 }
816 ures_close(patBundle);
817
818 key=NULL;
819 err = U_ZERO_ERROR;
820 fBundle = ures_getByKeyWithFallback(rb, DT_DateTimeFieldsTag, NULL, &err);
821 for (i=0; i<MAX_RESOURCE_FIELD; ++i) {
822 err = U_ZERO_ERROR;
823 patBundle = ures_getByKeyWithFallback(fBundle, Resource_Fields[i], NULL, &err);
824 fieldBundle = ures_getByKeyWithFallback(patBundle, "dn", NULL, &err);
825 rbPattern = ures_getNextUnicodeString(fieldBundle, &key, &err);
826 ures_close(fieldBundle);
827 ures_close(patBundle);
828 if (rbPattern.length()==0 ) {
829 continue;
830 }
831 else {
832 setAppendItemName(getAppendNameNumber(Resource_Fields[i]), rbPattern);
833 }
834 }
835 ures_close(fBundle);
836
837 // add available formats
838 UBool firstTimeThrough = TRUE;
839 err = U_ZERO_ERROR;
840 initHashtable(err);
841 UBool override = TRUE;
842 while (TRUE) {
843 // At the start of the loop:
844 // - rb is the open resource bundle for the current locale being processed,
845 // whose actual name is in curLocaleName.
846 // - if U_SUCCESS(err), then calBundle and calTypeBundle are open;
847 // process contents of calTypeBundle, then close calBundle and calTypeBundle.
848 if (U_SUCCESS(err)) {
849 // process contents of calTypeBundle
850 patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
851 if (U_SUCCESS(err)) {
852 int32_t numberKeys = ures_getSize(patBundle);
853 int32_t len;
854 const UChar *retPattern;
855 key=NULL;
856 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
857 UResourceBundleAIterator aiter;
858 ures_a_open(&aiter, patBundle, &err);
859 #endif
860 for(i=0; i<numberKeys; ++i) {
861 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
862 retPattern=ures_a_getNextString(&aiter, &len, &key, &err);
863 #else
864 retPattern=ures_getNextString(patBundle, &len, &key, &err);
865 #endif
866 UnicodeString format=UnicodeString(retPattern);
867 UnicodeString retKey=UnicodeString(key, -1, US_INV);
868 if ( firstTimeThrough || !isAvailableFormatSet(retKey) ) {
869 setAvailableFormat(retKey, err);
870 // Add pattern with its associated skeleton. Override any duplicate derived from std patterns,
871 // but not a previous availableFormats entry:
872 addPatternWithSkeleton(format, &retKey, override, conflictingPattern, err);
873 }
874 }
875 #if defined(U_USE_ASCII_BUNDLE_ITERATOR)
876 ures_a_close(&aiter);
877 #endif
878 ures_close(patBundle);
879 }
880 firstTimeThrough = FALSE;
881 // close calBundle and calTypeBundle
882 ures_close(calTypeBundle);
883 ures_close(calBundle);
884 }
885 if (uprv_strcmp(curLocaleName,"root")==0 || uprv_strlen(curLocaleName)==0) {
886 // we just finished handling root, nothing more to check
887 ures_close(rb);
888 break;
889 }
890 // Find the name of the appropriate parent locale (from %%Parent if present, else
891 // uloc_getParent on the actual locale name)
892 // (It would be nice to have a ures function that did this...)
893 err = U_ZERO_ERROR;
894 char parentLocale[ULOC_FULLNAME_CAPACITY];
895 int32_t locNameLen;
896 const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &err);
897 if (U_SUCCESS(err) && err != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) {
898 u_UCharsToChars(parentUName, parentLocale, locNameLen + 1);
899 } else {
900 err = U_ZERO_ERROR;
901 uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &err);
902 if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
903 // just fallback to root, since we are not already there
904 parentLocale[0] = 0;
905 err = U_ZERO_ERROR;
906 }
907 }
908 // Close current locale bundle
909 ures_close(rb);
910 // And open its parent, which becomes the new current locale being processed
911 rb = ures_open(NULL, parentLocale, &err);
912 if ( U_FAILURE(err) ) {
913 err = U_ZERO_ERROR;
914 break;
915 }
916 // Get the name of the parent / new current locale
917 curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err);
918 if ( U_FAILURE(err) ) {
919 curLocaleName = parentLocale;
920 err = U_ZERO_ERROR;
921 }
922 if (uprv_strcmp(curLocaleName,"root")==0 || uprv_strlen(curLocaleName)==0) {
923 override = FALSE;
924 }
925 // Open calBundle and calTypeBundle
926 calBundle = ures_getByKeyWithFallback(rb, DT_DateTimeCalendarTag, NULL, &err);
927 if (U_SUCCESS(err)) {
928 calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &err);
929 if ( U_FAILURE(err) ) {
930 ures_close(calBundle);
931 }
932 }
933 // Go to the top of the loop to process contents of calTypeBundle
934 }
935
936 if (hackPattern.length()>0) {
937 hackTimes(hackPattern, err);
938 }
939 }
940
941 void
942 DateTimePatternGenerator::initHashtable(UErrorCode& err) {
943 if (fAvailableFormatKeyHash!=NULL) {
944 return;
945 }
946 if ((fAvailableFormatKeyHash = new Hashtable(FALSE, err))==NULL) {
947 err=U_MEMORY_ALLOCATION_ERROR;
948 return;
949 }
950 }
951
952
953 void
954 DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value) {
955 appendItemFormats[field] = value;
956 // NUL-terminate for the C API.
957 appendItemFormats[field].getTerminatedBuffer();
958 }
959
960 const UnicodeString&
961 DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const {
962 return appendItemFormats[field];
963 }
964
965 void
966 DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) {
967 appendItemNames[field] = value;
968 // NUL-terminate for the C API.
969 appendItemNames[field].getTerminatedBuffer();
970 }
971
972 const UnicodeString&
973 DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field) const {
974 return appendItemNames[field];
975 }
976
977 void
978 DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) {
979 value = SINGLE_QUOTE;
980 value += appendItemNames[field];
981 value += SINGLE_QUOTE;
982 }
983
984 UnicodeString
985 DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErrorCode& status) {
986 return getBestPattern(patternForm, UDATPG_MATCH_NO_OPTIONS, status);
987 }
988
989 UnicodeString
990 DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, UErrorCode& status) {
991 const UnicodeString *bestPattern=NULL;
992 UnicodeString dtFormat;
993 UnicodeString resultPattern;
994 int32_t flags = kDTPGNoFlags;
995
996 int32_t dateMask=(1<<UDATPG_DAYPERIOD_FIELD) - 1;
997 int32_t timeMask=(1<<UDATPG_FIELD_COUNT) - 1 - dateMask;
998
999 // Replace hour metacharacters 'j', 'C' and 'J', set flags as necessary
1000 UnicodeString patternFormCopy = UnicodeString(patternForm);
1001 UChar hourFormatSkeletonCharForLowJ = fDefaultHourFormatChar;
1002 switch (options & UADATPG_FORCE_HOUR_CYCLE_MASK) {
1003 case UADATPG_FORCE_12_HOUR_CYCLE: hourFormatSkeletonCharForLowJ = LOW_H; break;
1004 case UADATPG_FORCE_24_HOUR_CYCLE: hourFormatSkeletonCharForLowJ = CAP_H; break;
1005 default: break;
1006 }
1007 int32_t patPos, patLen = patternFormCopy.length();
1008 UBool inQuoted = FALSE;
1009 for (patPos = 0; patPos < patLen; patPos++) {
1010 UChar patChr = patternFormCopy.charAt(patPos);
1011 if (patChr == SINGLE_QUOTE) {
1012 inQuoted = !inQuoted;
1013 } else if (!inQuoted) {
1014 if (patChr == LOW_J) {
1015 patternFormCopy.setCharAt(patPos, hourFormatSkeletonCharForLowJ);
1016 } else if (patChr == CAP_C) {
1017 AllowedHourFormat preferred;
1018 if (fAllowedHourFormats[0] != ALLOWED_HOUR_FORMAT_UNKNOWN) {
1019 preferred = (AllowedHourFormat)fAllowedHourFormats[0];
1020 } else {
1021 status = U_INVALID_FORMAT_ERROR;
1022 return UnicodeString();
1023 }
1024
1025 if (preferred == ALLOWED_HOUR_FORMAT_H || preferred == ALLOWED_HOUR_FORMAT_HB || preferred == ALLOWED_HOUR_FORMAT_Hb) {
1026 patternFormCopy.setCharAt(patPos, CAP_H);
1027 } else {
1028 patternFormCopy.setCharAt(patPos, LOW_H);
1029 }
1030
1031 if (preferred == ALLOWED_HOUR_FORMAT_HB || preferred == ALLOWED_HOUR_FORMAT_hB) {
1032 flags |= kDTPGSkeletonUsesCapB;
1033 } else if (preferred == ALLOWED_HOUR_FORMAT_Hb || preferred == ALLOWED_HOUR_FORMAT_hb) {
1034 flags |= kDTPGSkeletonUsesLowB;
1035 }
1036 } else if (patChr == CAP_J) {
1037 // Get pattern for skeleton with H, then in adjustFieldTypes
1038 // replace hour pattern characters as necessary.
1039 patternFormCopy.setCharAt(patPos, CAP_H);
1040 flags |= kDTPGSkeletonUsesCapJ;
1041 }
1042 }
1043 }
1044
1045 resultPattern.remove();
1046 dtMatcher->set(patternFormCopy, fp);
1047 const PtnSkeleton* specifiedSkeleton=NULL;
1048 bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, &specifiedSkeleton);
1049 if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) {
1050 resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, flags, options);
1051
1052 return resultPattern;
1053 }
1054 int32_t neededFields = dtMatcher->getFieldMask();
1055 UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, options);
1056 UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, options);
1057 if (datePattern.length()==0) {
1058 if (timePattern.length()==0) {
1059 resultPattern.remove();
1060 }
1061 else {
1062 return timePattern;
1063 }
1064 }
1065 if (timePattern.length()==0) {
1066 return datePattern;
1067 }
1068 resultPattern.remove();
1069 status = U_ZERO_ERROR;
1070 dtFormat=getDateTimeFormat();
1071 SimpleFormatter(dtFormat, 2, 2, status).format(timePattern, datePattern, resultPattern, status);
1072 return resultPattern;
1073 }
1074
1075 UnicodeString
1076 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
1077 const UnicodeString& skeleton,
1078 UErrorCode& status) {
1079 return replaceFieldTypes(pattern, skeleton, UDATPG_MATCH_NO_OPTIONS, status);
1080 }
1081
1082 UnicodeString
1083 DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
1084 const UnicodeString& skeleton,
1085 UDateTimePatternMatchOptions options,
1086 UErrorCode& /*status*/) {
1087 dtMatcher->set(skeleton, fp);
1088 UnicodeString result = adjustFieldTypes(pattern, NULL, kDTPGNoFlags, options);
1089 return result;
1090 }
1091
1092 void
1093 DateTimePatternGenerator::setDecimal(const UnicodeString& newDecimal) {
1094 this->decimal = newDecimal;
1095 // NUL-terminate for the C API.
1096 this->decimal.getTerminatedBuffer();
1097 }
1098
1099 const UnicodeString&
1100 DateTimePatternGenerator::getDecimal() const {
1101 return decimal;
1102 }
1103
1104 void
1105 DateTimePatternGenerator::addCanonicalItems() {
1106 UnicodeString conflictingPattern;
1107 UErrorCode status = U_ZERO_ERROR;
1108
1109 for (int32_t i=0; i<UDATPG_FIELD_COUNT; i++) {
1110 addPattern(UnicodeString(Canonical_Items[i]), FALSE, conflictingPattern, status);
1111 }
1112 }
1113
1114 void
1115 DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) {
1116 dateTimeFormat = dtFormat;
1117 // NUL-terminate for the C API.
1118 dateTimeFormat.getTerminatedBuffer();
1119 }
1120
1121 const UnicodeString&
1122 DateTimePatternGenerator::getDateTimeFormat() const {
1123 return dateTimeFormat;
1124 }
1125
1126 void
1127 DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) {
1128 const UChar *resStr;
1129 int32_t resStrLen = 0;
1130
1131 Calendar* fCalendar = Calendar::createInstance(locale, status);
1132 CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
1133 UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, status);
1134 if (U_FAILURE(status)) return;
1135
1136 if (ures_getSize(dateTimePatterns) <= DateFormat::kDateTime)
1137 {
1138 status = U_INVALID_FORMAT_ERROR;
1139 return;
1140 }
1141 resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)DateFormat::kDateTime, &resStrLen, &status);
1142 setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen));
1143
1144 delete fCalendar;
1145 }
1146
1147 void
1148 DateTimePatternGenerator::setDecimalSymbols(const Locale& locale, UErrorCode& status) {
1149 DecimalFormatSymbols dfs = DecimalFormatSymbols(locale, status);
1150 if(U_SUCCESS(status)) {
1151 decimal = dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
1152 // NUL-terminate for the C API.
1153 decimal.getTerminatedBuffer();
1154 }
1155 }
1156
1157 UDateTimePatternConflict
1158 DateTimePatternGenerator::addPattern(
1159 const UnicodeString& pattern,
1160 UBool override,
1161 UnicodeString &conflictingPattern,
1162 UErrorCode& status)
1163 {
1164 return addPatternWithSkeleton(pattern, NULL, override, conflictingPattern, status);
1165 }
1166
1167 // For DateTimePatternGenerator::addPatternWithSkeleton -
1168 // If skeletonToUse is specified, then an availableFormats entry is being added. In this case:
1169 // 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern.
1170 // 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified
1171 // (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override
1172 // parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual
1173 // specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was
1174 // derived (i.e. entries derived from the standard date/time patters for the specified locale).
1175 // 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a
1176 // specified skeleton (which sets a new field in the PtnElem in the PatternMap).
1177 UDateTimePatternConflict
1178 DateTimePatternGenerator::addPatternWithSkeleton(
1179 const UnicodeString& pattern,
1180 const UnicodeString* skeletonToUse,
1181 UBool override,
1182 UnicodeString& conflictingPattern,
1183 UErrorCode& status)
1184 {
1185
1186 UnicodeString basePattern;
1187 PtnSkeleton skeleton;
1188 UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
1189
1190 DateTimeMatcher matcher;
1191 if ( skeletonToUse == NULL ) {
1192 matcher.set(pattern, fp, skeleton);
1193 matcher.getBasePattern(basePattern);
1194 } else {
1195 matcher.set(*skeletonToUse, fp, skeleton); // no longer trims skeleton fields to max len 3, per #7930
1196 matcher.getBasePattern(basePattern); // or perhaps instead: basePattern = *skeletonToUse;
1197 }
1198 // We only care about base conflicts - and replacing the pattern associated with a base - if:
1199 // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous
1200 // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or
1201 // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen
1202 // if we are getting here from a subsequent call to addPattern).
1203 // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking
1204 // availableFormats items from root, which should not override any previous entry with the same base.
1205 UBool entryHadSpecifiedSkeleton;
1206 const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton);
1207 if (duplicatePattern != NULL && (!entryHadSpecifiedSkeleton || (skeletonToUse != NULL && !override))) {
1208 conflictingStatus = UDATPG_BASE_CONFLICT;
1209 conflictingPattern = *duplicatePattern;
1210 if (!override) {
1211 return conflictingStatus;
1212 }
1213 }
1214 // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats
1215 // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with
1216 // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for
1217 // the previously-specified conflicting item.
1218 const PtnSkeleton* entrySpecifiedSkeleton = NULL;
1219 duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton);
1220 if (duplicatePattern != NULL ) {
1221 conflictingStatus = UDATPG_CONFLICT;
1222 conflictingPattern = *duplicatePattern;
1223 if (!override || (skeletonToUse != NULL && entrySpecifiedSkeleton != NULL)) {
1224 return conflictingStatus;
1225 }
1226 }
1227 patternMap->add(basePattern, skeleton, pattern, skeletonToUse != NULL, status);
1228 if(U_FAILURE(status)) {
1229 return conflictingStatus;
1230 }
1231
1232 return UDATPG_NO_CONFLICT;
1233 }
1234
1235
1236 UDateTimePatternField
1237 DateTimePatternGenerator::getAppendFormatNumber(const char* field) const {
1238 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1239 if (uprv_strcmp(CLDR_FIELD_APPEND[i], field)==0) {
1240 return (UDateTimePatternField)i;
1241 }
1242 }
1243 return UDATPG_FIELD_COUNT;
1244 }
1245
1246 UDateTimePatternField
1247 DateTimePatternGenerator::getAppendNameNumber(const char* field) const {
1248 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1249 if (uprv_strcmp(CLDR_FIELD_NAME[i],field)==0) {
1250 return (UDateTimePatternField)i;
1251 }
1252 }
1253 return UDATPG_FIELD_COUNT;
1254 }
1255
1256 const UnicodeString*
1257 DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source,
1258 int32_t includeMask,
1259 DistanceInfo* missingFields,
1260 const PtnSkeleton** specifiedSkeletonPtr) {
1261 int32_t bestDistance = 0x7fffffff;
1262 DistanceInfo tempInfo;
1263 const UnicodeString *bestPattern=NULL;
1264 const PtnSkeleton* specifiedSkeleton=NULL;
1265
1266 PatternMapIterator it;
1267 for (it.set(*patternMap); it.hasNext(); ) {
1268 DateTimeMatcher trial = it.next();
1269 if (trial.equals(skipMatcher)) {
1270 continue;
1271 }
1272 int32_t distance=source.getDistance(trial, includeMask, tempInfo);
1273 if (distance<bestDistance) {
1274 bestDistance=distance;
1275 bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr(), &specifiedSkeleton);
1276 missingFields->setTo(tempInfo);
1277 if (distance==0) {
1278 break;
1279 }
1280 }
1281 }
1282
1283 // If the best raw match had a specified skeleton and that skeleton was requested by the caller,
1284 // then return it too. This generally happens when the caller needs to pass that skeleton
1285 // through to adjustFieldTypes so the latter can do a better job.
1286 if (bestPattern && specifiedSkeletonPtr) {
1287 *specifiedSkeletonPtr = specifiedSkeleton;
1288 }
1289 return bestPattern;
1290 }
1291
1292 UnicodeString
1293 DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
1294 const PtnSkeleton* specifiedSkeleton,
1295 int32_t flags,
1296 UDateTimePatternMatchOptions options) {
1297 UnicodeString newPattern;
1298 fp->set(pattern);
1299 for (int32_t i=0; i < fp->itemNumber; i++) {
1300 UnicodeString field = fp->items[i];
1301 if ( fp->isQuoteLiteral(field) ) {
1302
1303 UnicodeString quoteLiteral;
1304 fp->getQuoteLiteral(quoteLiteral, &i);
1305 newPattern += quoteLiteral;
1306 }
1307 else {
1308 if (fp->isPatternSeparator(field)) {
1309 newPattern+=field;
1310 continue;
1311 }
1312 int32_t canonicalIndex = fp->getCanonicalIndex(field);
1313 if (canonicalIndex < 0) {
1314 newPattern+=field;
1315 continue; // don't adjust
1316 }
1317 const dtTypeElem *row = &dtTypes[canonicalIndex];
1318 int32_t typeValue = row->field;
1319
1320 // Handle special day periods.
1321 if (typeValue == UDATPG_DAYPERIOD_FIELD && flags != 0) {
1322 UChar c = NONE; // '0'
1323 if (flags & kDTPGSkeletonUsesCapB) { c = CAP_B; }
1324 if (flags & kDTPGSkeletonUsesLowB) { c = LOW_B; }
1325
1326 if (c != NONE) {
1327 for (int32_t i = 0; i < field.length(); ++i)
1328 field.setCharAt(i, c);
1329 }
1330 }
1331
1332 if ((flags & kDTPGFixFractionalSeconds) != 0 && typeValue == UDATPG_SECOND_FIELD) {
1333 UnicodeString newField=dtMatcher->skeleton.original[UDATPG_FRACTIONAL_SECOND_FIELD];
1334 field = field + decimal + newField;
1335 } else if (dtMatcher->skeleton.type[typeValue]!=0) {
1336 // Here:
1337 // - "reqField" is the field from the originally requested skeleton, with length
1338 // "reqFieldLen".
1339 // - "field" is the field from the found pattern.
1340 //
1341 // The adjusted field should consist of characters from the originally requested
1342 // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD or
1343 // UDATPG_WEEKDAY_FIELD or UDATPG_YEAR_FIELD, in which case it should consist
1344 // of characters from the found pattern.
1345 //
1346 // The length of the adjusted field (adjFieldLen) should match that in the originally
1347 // requested skeleton, except that in the following cases the length of the adjusted field
1348 // should match that in the found pattern (i.e. the length of this pattern field should
1349 // not be adjusted):
1350 // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is
1351 // not set (ticket #7180). Note, we may want to implement a similar change for other
1352 // numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for
1353 // field length, but options bits can be used to override this.
1354 // 2. There is a specified skeleton for the found pattern and one of the following is true:
1355 // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen.
1356 // b) The pattern field is numeric and the skeleton field is not, or vice versa.
1357
1358 UnicodeString reqField = dtMatcher->skeleton.original[typeValue];
1359 int32_t reqFieldLen = reqField.length();
1360 if (reqField.charAt(0) == CAP_E && reqFieldLen < 3)
1361 reqFieldLen = 3; // 1-3 for E are equivalent to 3 for c,e
1362 int32_t adjFieldLen = reqFieldLen;
1363 if ( (typeValue==UDATPG_HOUR_FIELD && (options & UDATPG_MATCH_HOUR_FIELD_LENGTH)==0) ||
1364 (typeValue==UDATPG_MINUTE_FIELD && (options & UDATPG_MATCH_MINUTE_FIELD_LENGTH)==0) ||
1365 (typeValue==UDATPG_SECOND_FIELD && (options & UDATPG_MATCH_SECOND_FIELD_LENGTH)==0) ) {
1366 adjFieldLen = field.length();
1367 } else if (specifiedSkeleton) {
1368 UnicodeString skelField = specifiedSkeleton->original[typeValue];
1369 int32_t skelFieldLen = skelField.length();
1370 UBool patFieldIsNumeric = (row->type > 0);
1371 UBool skelFieldIsNumeric = (specifiedSkeleton->type[typeValue] > 0);
1372 if (skelFieldLen == reqFieldLen || (patFieldIsNumeric && !skelFieldIsNumeric) || (skelFieldIsNumeric && !patFieldIsNumeric)) {
1373 // don't adjust the field length in the found pattern
1374 adjFieldLen = field.length();
1375 }
1376 }
1377 UChar c = (typeValue!= UDATPG_HOUR_FIELD && typeValue!= UDATPG_MONTH_FIELD &&
1378 typeValue!= UDATPG_WEEKDAY_FIELD && (typeValue!= UDATPG_YEAR_FIELD || reqField.charAt(0)==CAP_Y))?
1379 reqField.charAt(0): field.charAt(0);
1380 if (typeValue == UDATPG_HOUR_FIELD && (flags & kDTPGSkeletonUsesCapJ) != 0) {
1381 c = fDefaultHourFormatChar;
1382 switch (options & UADATPG_FORCE_HOUR_CYCLE_MASK) {
1383 case UADATPG_FORCE_12_HOUR_CYCLE:
1384 if (c == CAP_H || c == LOW_K) {
1385 // Have 24-hour cycle, change to 12-hour cycle.
1386 // Should have better way to pick 'h' or 'K'.
1387 c = LOW_H;
1388 };
1389 break;
1390 case UADATPG_FORCE_24_HOUR_CYCLE:
1391 if (c == LOW_H || c == CAP_K) {
1392 // Have 12-hour cycle, change to 24-hour cycle.
1393 // Should have better way to pick 'H' or 'k'.
1394 c = CAP_H;
1395 };
1396 break;
1397 default:
1398 break;
1399 }
1400 }
1401 field.remove();
1402 for (int32_t i=adjFieldLen; i>0; --i) {
1403 field+=c;
1404 }
1405 }
1406 newPattern+=field;
1407 }
1408 }
1409 return newPattern;
1410 }
1411
1412 UnicodeString
1413 DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options) {
1414 UnicodeString resultPattern, tempPattern;
1415 UErrorCode err=U_ZERO_ERROR;
1416 int32_t lastMissingFieldMask=0;
1417 if (missingFields!=0) {
1418 resultPattern=UnicodeString();
1419 const PtnSkeleton* specifiedSkeleton=NULL;
1420 tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo, &specifiedSkeleton);
1421 resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
1422 if ( distanceInfo->missingFieldMask==0 ) {
1423 return resultPattern;
1424 }
1425 while (distanceInfo->missingFieldMask!=0) { // precondition: EVERY single field must work!
1426 if ( lastMissingFieldMask == distanceInfo->missingFieldMask ) {
1427 break; // cannot find the proper missing field
1428 }
1429 if (((distanceInfo->missingFieldMask & UDATPG_SECOND_AND_FRACTIONAL_MASK)==UDATPG_FRACTIONAL_MASK) &&
1430 ((missingFields & UDATPG_SECOND_AND_FRACTIONAL_MASK) == UDATPG_SECOND_AND_FRACTIONAL_MASK)) {
1431 resultPattern = adjustFieldTypes(resultPattern, specifiedSkeleton, flags | kDTPGFixFractionalSeconds, options);
1432 distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK;
1433 continue;
1434 }
1435 int32_t startingMask = distanceInfo->missingFieldMask;
1436 tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, &specifiedSkeleton);
1437 tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
1438 int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;
1439 int32_t topField=getTopBitNumber(foundMask);
1440 UnicodeString appendName;
1441 getAppendName((UDateTimePatternField)topField, appendName);
1442 const UnicodeString *values[3] = {
1443 &resultPattern,
1444 &tempPattern,
1445 &appendName
1446 };
1447 SimpleFormatter(appendItemFormats[topField], 2, 3, err).
1448 formatAndReplace(values, 3, resultPattern, NULL, 0, err);
1449 lastMissingFieldMask = distanceInfo->missingFieldMask;
1450 }
1451 }
1452 return resultPattern;
1453 }
1454
1455 int32_t
1456 DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) {
1457 if ( foundMask==0 ) {
1458 return 0;
1459 }
1460 int32_t i=0;
1461 while (foundMask!=0) {
1462 foundMask >>=1;
1463 ++i;
1464 }
1465 if (i-1 >UDATPG_ZONE_FIELD) {
1466 return UDATPG_ZONE_FIELD;
1467 }
1468 else
1469 return i-1;
1470 }
1471
1472 void
1473 DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err)
1474 {
1475 fAvailableFormatKeyHash->puti(key, 1, err);
1476 }
1477
1478 UBool
1479 DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const {
1480 return (UBool)(fAvailableFormatKeyHash->geti(key) == 1);
1481 }
1482
1483 void
1484 DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) {
1485
1486 if (other == NULL) {
1487 return;
1488 }
1489 if (fAvailableFormatKeyHash != NULL) {
1490 delete fAvailableFormatKeyHash;
1491 fAvailableFormatKeyHash = NULL;
1492 }
1493 initHashtable(status);
1494 if(U_FAILURE(status)){
1495 return;
1496 }
1497 int32_t pos = UHASH_FIRST;
1498 const UHashElement* elem = NULL;
1499 // walk through the hash table and create a deep clone
1500 while((elem = other->nextElement(pos))!= NULL){
1501 const UHashTok otherKeyTok = elem->key;
1502 UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
1503 fAvailableFormatKeyHash->puti(*otherKey, 1, status);
1504 if(U_FAILURE(status)){
1505 return;
1506 }
1507 }
1508 }
1509
1510 StringEnumeration*
1511 DateTimePatternGenerator::getSkeletons(UErrorCode& status) const {
1512 StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status);
1513 return skeletonEnumerator;
1514 }
1515
1516 const UnicodeString&
1517 DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) const {
1518 PtnElem *curElem;
1519
1520 if (skeleton.length() ==0) {
1521 return emptyString;
1522 }
1523 curElem = patternMap->getHeader(skeleton.charAt(0));
1524 while ( curElem != NULL ) {
1525 if ( curElem->skeleton->getSkeleton()==skeleton ) {
1526 return curElem->pattern;
1527 }
1528 curElem=curElem->next;
1529 }
1530 return emptyString;
1531 }
1532
1533 StringEnumeration*
1534 DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const {
1535 StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status);
1536 return baseSkeletonEnumerator;
1537 }
1538
1539 StringEnumeration*
1540 DateTimePatternGenerator::getRedundants(UErrorCode& status) {
1541 StringEnumeration* output = new DTRedundantEnumeration();
1542 const UnicodeString *pattern;
1543 PatternMapIterator it;
1544 for (it.set(*patternMap); it.hasNext(); ) {
1545 DateTimeMatcher current = it.next();
1546 pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton()));
1547 if ( isCanonicalItem(*pattern) ) {
1548 continue;
1549 }
1550 if ( skipMatcher == NULL ) {
1551 skipMatcher = new DateTimeMatcher(current);
1552 }
1553 else {
1554 *skipMatcher = current;
1555 }
1556 UnicodeString trial = getBestPattern(current.getPattern(), status);
1557 if (trial == *pattern) {
1558 ((DTRedundantEnumeration *)output)->add(*pattern, status);
1559 }
1560 if (current.equals(skipMatcher)) {
1561 continue;
1562 }
1563 }
1564 return output;
1565 }
1566
1567 UBool
1568 DateTimePatternGenerator::isCanonicalItem(const UnicodeString& item) const {
1569 if ( item.length() != 1 ) {
1570 return FALSE;
1571 }
1572 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1573 if (item.charAt(0)==Canonical_Items[i]) {
1574 return TRUE;
1575 }
1576 }
1577 return FALSE;
1578 }
1579
1580
1581 DateTimePatternGenerator*
1582 DateTimePatternGenerator::clone() const {
1583 return new DateTimePatternGenerator(*this);
1584 }
1585
1586 PatternMap::PatternMap() {
1587 for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
1588 boot[i]=NULL;
1589 }
1590 isDupAllowed = TRUE;
1591 }
1592
1593 void
1594 PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) {
1595 this->isDupAllowed = other.isDupAllowed;
1596 for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
1597 PtnElem *curElem, *otherElem, *prevElem=NULL;
1598 otherElem = other.boot[bootIndex];
1599 while (otherElem!=NULL) {
1600 if ((curElem = new PtnElem(otherElem->basePattern, otherElem->pattern))==NULL) {
1601 // out of memory
1602 status = U_MEMORY_ALLOCATION_ERROR;
1603 return;
1604 }
1605 if ( this->boot[bootIndex]== NULL ) {
1606 this->boot[bootIndex] = curElem;
1607 }
1608 if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) {
1609 // out of memory
1610 status = U_MEMORY_ALLOCATION_ERROR;
1611 return;
1612 }
1613 curElem->skeletonWasSpecified = otherElem->skeletonWasSpecified;
1614 if (prevElem!=NULL) {
1615 prevElem->next=curElem;
1616 }
1617 curElem->next=NULL;
1618 prevElem = curElem;
1619 otherElem = otherElem->next;
1620 }
1621
1622 }
1623 }
1624
1625 PtnElem*
1626 PatternMap::getHeader(UChar baseChar) {
1627 PtnElem* curElem;
1628
1629 if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) {
1630 curElem = boot[baseChar-CAP_A];
1631 }
1632 else {
1633 if ( (baseChar >=LOW_A) && (baseChar <= LOW_Z) ) {
1634 curElem = boot[26+baseChar-LOW_A];
1635 }
1636 else {
1637 return NULL;
1638 }
1639 }
1640 return curElem;
1641 }
1642
1643 PatternMap::~PatternMap() {
1644 for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
1645 if (boot[i]!=NULL ) {
1646 delete boot[i];
1647 boot[i]=NULL;
1648 }
1649 }
1650 } // PatternMap destructor
1651
1652 void
1653 PatternMap::add(const UnicodeString& basePattern,
1654 const PtnSkeleton& skeleton,
1655 const UnicodeString& value,// mapped pattern value
1656 UBool skeletonWasSpecified,
1657 UErrorCode &status) {
1658 UChar baseChar = basePattern.charAt(0);
1659 PtnElem *curElem, *baseElem;
1660 status = U_ZERO_ERROR;
1661
1662 // the baseChar must be A-Z or a-z
1663 if ((baseChar >= CAP_A) && (baseChar <= CAP_Z)) {
1664 baseElem = boot[baseChar-CAP_A];
1665 }
1666 else {
1667 if ((baseChar >=LOW_A) && (baseChar <= LOW_Z)) {
1668 baseElem = boot[26+baseChar-LOW_A];
1669 }
1670 else {
1671 status = U_ILLEGAL_CHARACTER;
1672 return;
1673 }
1674 }
1675
1676 if (baseElem == NULL) {
1677 if ((curElem = new PtnElem(basePattern, value)) == NULL ) {
1678 // out of memory
1679 status = U_MEMORY_ALLOCATION_ERROR;
1680 return;
1681 }
1682 if (baseChar >= LOW_A) {
1683 boot[26 + (baseChar-LOW_A)] = curElem;
1684 }
1685 else {
1686 boot[baseChar-CAP_A] = curElem;
1687 }
1688 curElem->skeleton = new PtnSkeleton(skeleton);
1689 curElem->skeletonWasSpecified = skeletonWasSpecified;
1690 }
1691 if ( baseElem != NULL ) {
1692 curElem = getDuplicateElem(basePattern, skeleton, baseElem);
1693
1694 if (curElem == NULL) {
1695 // add new element to the list.
1696 curElem = baseElem;
1697 while( curElem -> next != NULL )
1698 {
1699 curElem = curElem->next;
1700 }
1701 if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) {
1702 // out of memory
1703 status = U_MEMORY_ALLOCATION_ERROR;
1704 return;
1705 }
1706 curElem=curElem->next;
1707 curElem->skeleton = new PtnSkeleton(skeleton);
1708 curElem->skeletonWasSpecified = skeletonWasSpecified;
1709 }
1710 else {
1711 // Pattern exists in the list already.
1712 if ( !isDupAllowed ) {
1713 return;
1714 }
1715 // Overwrite the value.
1716 curElem->pattern = value;
1717 // It was a bug that we were not doing the following previously,
1718 // though that bug hid other problems by making things partly work.
1719 curElem->skeletonWasSpecified = skeletonWasSpecified;
1720 }
1721 }
1722 } // PatternMap::add
1723
1724 // Find the pattern from the given basePattern string.
1725 const UnicodeString *
1726 PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified) { // key to search for
1727 PtnElem *curElem;
1728
1729 if ((curElem=getHeader(basePattern.charAt(0)))==NULL) {
1730 return NULL; // no match
1731 }
1732
1733 do {
1734 if ( basePattern.compare(curElem->basePattern)==0 ) {
1735 skeletonWasSpecified = curElem->skeletonWasSpecified;
1736 return &(curElem->pattern);
1737 }
1738 curElem=curElem->next;
1739 }while (curElem != NULL);
1740
1741 return NULL;
1742 } // PatternMap::getFromBasePattern
1743
1744
1745 // Find the pattern from the given skeleton.
1746 // At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL),
1747 // the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw)
1748 // and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the
1749 // optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
1750 // for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
1751 const UnicodeString *
1752 PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) { // key to search for
1753 PtnElem *curElem;
1754
1755 if (specifiedSkeletonPtr) {
1756 *specifiedSkeletonPtr = NULL;
1757 }
1758
1759 // find boot entry
1760 UChar baseChar='\0';
1761 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1762 if (skeleton.baseOriginal[i].length() !=0 ) {
1763 baseChar = skeleton.baseOriginal[i].charAt(0);
1764 break;
1765 }
1766 }
1767
1768 if ((curElem=getHeader(baseChar))==NULL) {
1769 return NULL; // no match
1770 }
1771
1772 do {
1773 int32_t i=0;
1774 if (specifiedSkeletonPtr != NULL) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
1775 for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
1776 if (curElem->skeleton->original[i].compare(skeleton.original[i]) != 0 )
1777 {
1778 break;
1779 }
1780 }
1781 } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
1782 for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
1783 if (curElem->skeleton->baseOriginal[i].compare(skeleton.baseOriginal[i]) != 0 )
1784 {
1785 break;
1786 }
1787 }
1788 }
1789 if (i == UDATPG_FIELD_COUNT) {
1790 if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) {
1791 *specifiedSkeletonPtr = curElem->skeleton;
1792 }
1793 return &(curElem->pattern);
1794 }
1795 curElem=curElem->next;
1796 }while (curElem != NULL);
1797
1798 return NULL;
1799 }
1800
1801 UBool
1802 PatternMap::equals(const PatternMap& other) {
1803 if ( this==&other ) {
1804 return TRUE;
1805 }
1806 for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
1807 if ( boot[bootIndex]==other.boot[bootIndex] ) {
1808 continue;
1809 }
1810 if ( (boot[bootIndex]==NULL)||(other.boot[bootIndex]==NULL) ) {
1811 return FALSE;
1812 }
1813 PtnElem *otherElem = other.boot[bootIndex];
1814 PtnElem *myElem = boot[bootIndex];
1815 while ((otherElem!=NULL) || (myElem!=NULL)) {
1816 if ( myElem == otherElem ) {
1817 break;
1818 }
1819 if ((otherElem==NULL) || (myElem==NULL)) {
1820 return FALSE;
1821 }
1822 if ( (myElem->basePattern != otherElem->basePattern) ||
1823 (myElem->pattern != otherElem->pattern) ) {
1824 return FALSE;
1825 }
1826 if ((myElem->skeleton!=otherElem->skeleton)&&
1827 !myElem->skeleton->equals(*(otherElem->skeleton))) {
1828 return FALSE;
1829 }
1830 myElem = myElem->next;
1831 otherElem=otherElem->next;
1832 }
1833 }
1834 return TRUE;
1835 }
1836
1837 // find any key existing in the mapping table already.
1838 // return TRUE if there is an existing key, otherwise return FALSE.
1839 PtnElem*
1840 PatternMap::getDuplicateElem(
1841 const UnicodeString &basePattern,
1842 const PtnSkeleton &skeleton,
1843 PtnElem *baseElem) {
1844 PtnElem *curElem;
1845
1846 if ( baseElem == (PtnElem *)NULL ) {
1847 return (PtnElem*)NULL;
1848 }
1849 else {
1850 curElem = baseElem;
1851 }
1852 do {
1853 if ( basePattern.compare(curElem->basePattern)==0 ) {
1854 UBool isEqual=TRUE;
1855 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1856 if (curElem->skeleton->type[i] != skeleton.type[i] ) {
1857 isEqual=FALSE;
1858 break;
1859 }
1860 }
1861 if (isEqual) {
1862 return curElem;
1863 }
1864 }
1865 curElem = curElem->next;
1866 } while( curElem != (PtnElem *)NULL );
1867
1868 // end of the list
1869 return (PtnElem*)NULL;
1870
1871 } // PatternMap::getDuplicateElem
1872
1873 DateTimeMatcher::DateTimeMatcher(void) {
1874 }
1875
1876 DateTimeMatcher::~DateTimeMatcher() {}
1877
1878 DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) {
1879 copyFrom(other.skeleton);
1880 }
1881
1882
1883 void
1884 DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) {
1885 PtnSkeleton localSkeleton;
1886 return set(pattern, fp, localSkeleton);
1887 }
1888
1889 void
1890 DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeletonResult) {
1891 int32_t i;
1892 for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
1893 skeletonResult.type[i]=NONE;
1894 }
1895 fp->set(pattern);
1896 for (i=0; i < fp->itemNumber; i++) {
1897 UnicodeString field = fp->items[i];
1898 if ( field.charAt(0) == LOW_A ) {
1899 continue; // skip 'a'
1900 }
1901
1902 if ( fp->isQuoteLiteral(field) ) {
1903 UnicodeString quoteLiteral;
1904 fp->getQuoteLiteral(quoteLiteral, &i);
1905 continue;
1906 }
1907 int32_t canonicalIndex = fp->getCanonicalIndex(field);
1908 if (canonicalIndex < 0 ) {
1909 continue;
1910 }
1911 const dtTypeElem *row = &dtTypes[canonicalIndex];
1912 int32_t typeValue = row->field;
1913 skeletonResult.original[typeValue]=field;
1914 UChar repeatChar = row->patternChar;
1915 int32_t repeatCount = row->minLen; // #7930 removes cap at 3
1916 while (repeatCount-- > 0) {
1917 skeletonResult.baseOriginal[typeValue] += repeatChar;
1918 }
1919 int16_t subTypeValue = row->type;
1920 if ( row->type > 0) {
1921 subTypeValue += field.length();
1922 }
1923 skeletonResult.type[typeValue] = subTypeValue;
1924 }
1925 copyFrom(skeletonResult);
1926 }
1927
1928 void
1929 DateTimeMatcher::getBasePattern(UnicodeString &result ) {
1930 result.remove(); // Reset the result first.
1931 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1932 if (skeleton.baseOriginal[i].length()!=0) {
1933 result += skeleton.baseOriginal[i];
1934 }
1935 }
1936 }
1937
1938 UnicodeString
1939 DateTimeMatcher::getPattern() {
1940 UnicodeString result;
1941
1942 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1943 if (skeleton.original[i].length()!=0) {
1944 result += skeleton.original[i];
1945 }
1946 }
1947 return result;
1948 }
1949
1950 int32_t
1951 DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) {
1952 int32_t result=0;
1953 distanceInfo.clear();
1954 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
1955 int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i];
1956 int32_t otherType = other.skeleton.type[i];
1957 if (myType==otherType) {
1958 continue;
1959 }
1960 if (myType==0) {// and other is not
1961 result += EXTRA_FIELD;
1962 distanceInfo.addExtra(i);
1963 }
1964 else {
1965 if (otherType==0) {
1966 result += MISSING_FIELD;
1967 distanceInfo.addMissing(i);
1968 }
1969 else {
1970 result += abs(myType - otherType);
1971 }
1972 }
1973
1974 }
1975 return result;
1976 }
1977
1978 void
1979 DateTimeMatcher::copyFrom(const PtnSkeleton& newSkeleton) {
1980 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1981 this->skeleton.type[i]=newSkeleton.type[i];
1982 this->skeleton.original[i]=newSkeleton.original[i];
1983 this->skeleton.baseOriginal[i]=newSkeleton.baseOriginal[i];
1984 }
1985 }
1986
1987 void
1988 DateTimeMatcher::copyFrom() {
1989 // same as clear
1990 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
1991 this->skeleton.type[i]=0;
1992 this->skeleton.original[i].remove();
1993 this->skeleton.baseOriginal[i].remove();
1994 }
1995 }
1996
1997 UBool
1998 DateTimeMatcher::equals(const DateTimeMatcher* other) const {
1999 if (other==NULL) {
2000 return FALSE;
2001 }
2002 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
2003 if (this->skeleton.original[i]!=other->skeleton.original[i] ) {
2004 return FALSE;
2005 }
2006 }
2007 return TRUE;
2008 }
2009
2010 int32_t
2011 DateTimeMatcher::getFieldMask() {
2012 int32_t result=0;
2013
2014 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
2015 if (skeleton.type[i]!=0) {
2016 result |= (1<<i);
2017 }
2018 }
2019 return result;
2020 }
2021
2022 PtnSkeleton*
2023 DateTimeMatcher::getSkeletonPtr() {
2024 return &skeleton;
2025 }
2026
2027 FormatParser::FormatParser () {
2028 status = START;
2029 itemNumber=0;
2030 }
2031
2032
2033 FormatParser::~FormatParser () {
2034 }
2035
2036
2037 // Find the next token with the starting position and length
2038 // Note: the startPos may
2039 FormatParser::TokenStatus
2040 FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) {
2041 int32_t curLoc = startPos;
2042 if ( curLoc >= pattern.length()) {
2043 return DONE;
2044 }
2045 // check the current char is between A-Z or a-z
2046 do {
2047 UChar c=pattern.charAt(curLoc);
2048 if ( (c>=CAP_A && c<=CAP_Z) || (c>=LOW_A && c<=LOW_Z) ) {
2049 curLoc++;
2050 }
2051 else {
2052 startPos = curLoc;
2053 *len=1;
2054 return ADD_TOKEN;
2055 }
2056
2057 if ( pattern.charAt(curLoc)!= pattern.charAt(startPos) ) {
2058 break; // not the same token
2059 }
2060 } while(curLoc <= pattern.length());
2061 *len = curLoc-startPos;
2062 return ADD_TOKEN;
2063 }
2064
2065 void
2066 FormatParser::set(const UnicodeString& pattern) {
2067 int32_t startPos=0;
2068 TokenStatus result=START;
2069 int32_t len=0;
2070 itemNumber =0;
2071
2072 do {
2073 result = setTokens( pattern, startPos, &len );
2074 if ( result == ADD_TOKEN )
2075 {
2076 items[itemNumber++] = UnicodeString(pattern, startPos, len );
2077 startPos += len;
2078 }
2079 else {
2080 break;
2081 }
2082 } while (result==ADD_TOKEN && itemNumber < MAX_DT_TOKEN);
2083 }
2084
2085 int32_t
2086 FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) {
2087 int32_t len = s.length();
2088 if (len == 0) {
2089 return -1;
2090 }
2091 UChar ch = s.charAt(0);
2092
2093 // Verify that all are the same character.
2094 for (int32_t l = 1; l < len; l++) {
2095 if (ch != s.charAt(l)) {
2096 return -1;
2097 }
2098 }
2099 int32_t i = 0;
2100 int32_t bestRow = -1;
2101 while (dtTypes[i].patternChar != '\0') {
2102 if ( dtTypes[i].patternChar != ch ) {
2103 ++i;
2104 continue;
2105 }
2106 bestRow = i;
2107 if (dtTypes[i].patternChar != dtTypes[i+1].patternChar) {
2108 return i;
2109 }
2110 if (dtTypes[i+1].minLen <= len) {
2111 ++i;
2112 continue;
2113 }
2114 return i;
2115 }
2116 return strict ? -1 : bestRow;
2117 }
2118
2119 UBool
2120 FormatParser::isQuoteLiteral(const UnicodeString& s) {
2121 return (UBool)(s.charAt(0)==SINGLE_QUOTE);
2122 }
2123
2124 // This function aussumes the current itemIndex points to the quote literal.
2125 // Please call isQuoteLiteral prior to this function.
2126 void
2127 FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
2128 int32_t i=*itemIndex;
2129
2130 quote.remove();
2131 if (items[i].charAt(0)==SINGLE_QUOTE) {
2132 quote += items[i];
2133 ++i;
2134 }
2135 while ( i < itemNumber ) {
2136 if ( items[i].charAt(0)==SINGLE_QUOTE ) {
2137 if ( (i+1<itemNumber) && (items[i+1].charAt(0)==SINGLE_QUOTE)) {
2138 // two single quotes e.g. 'o''clock'
2139 quote += items[i++];
2140 quote += items[i++];
2141 continue;
2142 }
2143 else {
2144 quote += items[i];
2145 break;
2146 }
2147 }
2148 else {
2149 quote += items[i];
2150 }
2151 ++i;
2152 }
2153 *itemIndex=i;
2154 }
2155
2156 UBool
2157 FormatParser::isPatternSeparator(UnicodeString& field) {
2158 for (int32_t i=0; i<field.length(); ++i ) {
2159 UChar c= field.charAt(i);
2160 if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) ||
2161 (c==QUOTATION_MARK) || (c==COMMA) || (c==HYPHEN) ||(items[i].charAt(0)==DOT) ) {
2162 continue;
2163 }
2164 else {
2165 return FALSE;
2166 }
2167 }
2168 return TRUE;
2169 }
2170
2171 DistanceInfo::~DistanceInfo() {}
2172
2173 void
2174 DistanceInfo::setTo(DistanceInfo &other) {
2175 missingFieldMask = other.missingFieldMask;
2176 extraFieldMask= other.extraFieldMask;
2177 }
2178
2179 PatternMapIterator::PatternMapIterator() {
2180 bootIndex = 0;
2181 nodePtr = NULL;
2182 patternMap=NULL;
2183 matcher= new DateTimeMatcher();
2184 }
2185
2186
2187 PatternMapIterator::~PatternMapIterator() {
2188 delete matcher;
2189 }
2190
2191 void
2192 PatternMapIterator::set(PatternMap& newPatternMap) {
2193 this->patternMap=&newPatternMap;
2194 }
2195
2196 PtnSkeleton*
2197 PatternMapIterator::getSkeleton() {
2198 if ( nodePtr == NULL ) {
2199 return NULL;
2200 }
2201 else {
2202 return nodePtr->skeleton;
2203 }
2204 }
2205
2206 UBool
2207 PatternMapIterator::hasNext() {
2208 int32_t headIndex=bootIndex;
2209 PtnElem *curPtr=nodePtr;
2210
2211 if (patternMap==NULL) {
2212 return FALSE;
2213 }
2214 while ( headIndex < MAX_PATTERN_ENTRIES ) {
2215 if ( curPtr != NULL ) {
2216 if ( curPtr->next != NULL ) {
2217 return TRUE;
2218 }
2219 else {
2220 headIndex++;
2221 curPtr=NULL;
2222 continue;
2223 }
2224 }
2225 else {
2226 if ( patternMap->boot[headIndex] != NULL ) {
2227 return TRUE;
2228 }
2229 else {
2230 headIndex++;
2231 continue;
2232 }
2233 }
2234
2235 }
2236 return FALSE;
2237 }
2238
2239 DateTimeMatcher&
2240 PatternMapIterator::next() {
2241 while ( bootIndex < MAX_PATTERN_ENTRIES ) {
2242 if ( nodePtr != NULL ) {
2243 if ( nodePtr->next != NULL ) {
2244 nodePtr = nodePtr->next;
2245 break;
2246 }
2247 else {
2248 bootIndex++;
2249 nodePtr=NULL;
2250 continue;
2251 }
2252 }
2253 else {
2254 if ( patternMap->boot[bootIndex] != NULL ) {
2255 nodePtr = patternMap->boot[bootIndex];
2256 break;
2257 }
2258 else {
2259 bootIndex++;
2260 continue;
2261 }
2262 }
2263 }
2264 if (nodePtr!=NULL) {
2265 matcher->copyFrom(*nodePtr->skeleton);
2266 }
2267 else {
2268 matcher->copyFrom();
2269 }
2270 return *matcher;
2271 }
2272
2273 PtnSkeleton::PtnSkeleton() {
2274 }
2275
2276
2277 PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) {
2278 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
2279 this->type[i]=other.type[i];
2280 this->original[i]=other.original[i];
2281 this->baseOriginal[i]=other.baseOriginal[i];
2282 }
2283 }
2284
2285 UBool
2286 PtnSkeleton::equals(const PtnSkeleton& other) {
2287 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
2288 if ( (type[i]!= other.type[i]) ||
2289 (original[i]!=other.original[i]) ||
2290 (baseOriginal[i]!=other.baseOriginal[i]) ) {
2291 return FALSE;
2292 }
2293 }
2294 return TRUE;
2295 }
2296
2297 UnicodeString
2298 PtnSkeleton::getSkeleton() {
2299 UnicodeString result;
2300
2301 for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
2302 if (original[i].length()!=0) {
2303 result += original[i];
2304 }
2305 }
2306 return result;
2307 }
2308
2309 UnicodeString
2310 PtnSkeleton::getBaseSkeleton() {
2311 UnicodeString result;
2312
2313 for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
2314 if (baseOriginal[i].length()!=0) {
2315 result += baseOriginal[i];
2316 }
2317 }
2318 return result;
2319 }
2320
2321 PtnSkeleton::~PtnSkeleton() {
2322 }
2323
2324 PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) :
2325 basePattern(basePat),
2326 skeleton(NULL),
2327 pattern(pat),
2328 next(NULL)
2329 {
2330 }
2331
2332 PtnElem::~PtnElem() {
2333
2334 if (next!=NULL) {
2335 delete next;
2336 }
2337 delete skeleton;
2338 }
2339
2340 DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) {
2341 PtnElem *curElem;
2342 PtnSkeleton *curSkeleton;
2343 UnicodeString s;
2344 int32_t bootIndex;
2345
2346 pos=0;
2347 fSkeletons = new UVector(status);
2348 if (U_FAILURE(status)) {
2349 delete fSkeletons;
2350 return;
2351 }
2352 for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
2353 curElem = patternMap.boot[bootIndex];
2354 while (curElem!=NULL) {
2355 switch(type) {
2356 case DT_BASESKELETON:
2357 s=curElem->basePattern;
2358 break;
2359 case DT_PATTERN:
2360 s=curElem->pattern;
2361 break;
2362 case DT_SKELETON:
2363 curSkeleton=curElem->skeleton;
2364 s=curSkeleton->getSkeleton();
2365 break;
2366 }
2367 if ( !isCanonicalItem(s) ) {
2368 fSkeletons->addElement(new UnicodeString(s), status);
2369 if (U_FAILURE(status)) {
2370 delete fSkeletons;
2371 fSkeletons = NULL;
2372 return;
2373 }
2374 }
2375 curElem = curElem->next;
2376 }
2377 }
2378 if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) {
2379 status = U_BUFFER_OVERFLOW_ERROR;
2380 }
2381 }
2382
2383 const UnicodeString*
2384 DTSkeletonEnumeration::snext(UErrorCode& status) {
2385 if (U_SUCCESS(status) && pos < fSkeletons->size()) {
2386 return (const UnicodeString*)fSkeletons->elementAt(pos++);
2387 }
2388 return NULL;
2389 }
2390
2391 void
2392 DTSkeletonEnumeration::reset(UErrorCode& /*status*/) {
2393 pos=0;
2394 }
2395
2396 int32_t
2397 DTSkeletonEnumeration::count(UErrorCode& /*status*/) const {
2398 return (fSkeletons==NULL) ? 0 : fSkeletons->size();
2399 }
2400
2401 UBool
2402 DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) {
2403 if ( item.length() != 1 ) {
2404 return FALSE;
2405 }
2406 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
2407 if (item.charAt(0)==Canonical_Items[i]) {
2408 return TRUE;
2409 }
2410 }
2411 return FALSE;
2412 }
2413
2414 DTSkeletonEnumeration::~DTSkeletonEnumeration() {
2415 UnicodeString *s;
2416 for (int32_t i=0; i<fSkeletons->size(); ++i) {
2417 if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) {
2418 delete s;
2419 }
2420 }
2421 delete fSkeletons;
2422 }
2423
2424 DTRedundantEnumeration::DTRedundantEnumeration() {
2425 pos=0;
2426 fPatterns = NULL;
2427 }
2428
2429 void
2430 DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) {
2431 if (U_FAILURE(status)) return;
2432 if (fPatterns == NULL) {
2433 fPatterns = new UVector(status);
2434 if (U_FAILURE(status)) {
2435 delete fPatterns;
2436 fPatterns = NULL;
2437 return;
2438 }
2439 }
2440 fPatterns->addElement(new UnicodeString(pattern), status);
2441 if (U_FAILURE(status)) {
2442 delete fPatterns;
2443 fPatterns = NULL;
2444 return;
2445 }
2446 }
2447
2448 const UnicodeString*
2449 DTRedundantEnumeration::snext(UErrorCode& status) {
2450 if (U_SUCCESS(status) && pos < fPatterns->size()) {
2451 return (const UnicodeString*)fPatterns->elementAt(pos++);
2452 }
2453 return NULL;
2454 }
2455
2456 void
2457 DTRedundantEnumeration::reset(UErrorCode& /*status*/) {
2458 pos=0;
2459 }
2460
2461 int32_t
2462 DTRedundantEnumeration::count(UErrorCode& /*status*/) const {
2463 return (fPatterns==NULL) ? 0 : fPatterns->size();
2464 }
2465
2466 UBool
2467 DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) {
2468 if ( item.length() != 1 ) {
2469 return FALSE;
2470 }
2471 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
2472 if (item.charAt(0)==Canonical_Items[i]) {
2473 return TRUE;
2474 }
2475 }
2476 return FALSE;
2477 }
2478
2479 DTRedundantEnumeration::~DTRedundantEnumeration() {
2480 UnicodeString *s;
2481 for (int32_t i=0; i<fPatterns->size(); ++i) {
2482 if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) {
2483 delete s;
2484 }
2485 }
2486 delete fPatterns;
2487 }
2488
2489 U_NAMESPACE_END
2490
2491
2492 #endif /* #if !UCONFIG_NO_FORMATTING */
2493
2494 //eof