LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - dtptngen.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1251 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 168 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13