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