Coverage Report

Created: 2018-09-25 14:53

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