tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dtptngen.cpp (114653B)


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