1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/dtptngen.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2219 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 2007-2013, International Business Machines Corporation and 1.7 +* others. All Rights Reserved. 1.8 +******************************************************************************* 1.9 +* 1.10 +* File DTPTNGEN.CPP 1.11 +* 1.12 +******************************************************************************* 1.13 +*/ 1.14 + 1.15 +#include "unicode/utypes.h" 1.16 +#if !UCONFIG_NO_FORMATTING 1.17 + 1.18 +#include "unicode/datefmt.h" 1.19 +#include "unicode/decimfmt.h" 1.20 +#include "unicode/dtfmtsym.h" 1.21 +#include "unicode/dtptngen.h" 1.22 +#include "unicode/msgfmt.h" 1.23 +#include "unicode/smpdtfmt.h" 1.24 +#include "unicode/udat.h" 1.25 +#include "unicode/udatpg.h" 1.26 +#include "unicode/uniset.h" 1.27 +#include "unicode/uloc.h" 1.28 +#include "unicode/ures.h" 1.29 +#include "unicode/ustring.h" 1.30 +#include "unicode/rep.h" 1.31 +#include "cpputils.h" 1.32 +#include "ucln_in.h" 1.33 +#include "mutex.h" 1.34 +#include "cmemory.h" 1.35 +#include "cstring.h" 1.36 +#include "locbased.h" 1.37 +#include "gregoimp.h" 1.38 +#include "hash.h" 1.39 +#include "uresimp.h" 1.40 +#include "dtptngen_impl.h" 1.41 + 1.42 +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 1.43 + 1.44 +#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY 1.45 +/** 1.46 + * If we are on EBCDIC, use an iterator which will 1.47 + * traverse the bundles in ASCII order. 1.48 + */ 1.49 +#define U_USE_ASCII_BUNDLE_ITERATOR 1.50 +#define U_SORT_ASCII_BUNDLE_ITERATOR 1.51 +#endif 1.52 + 1.53 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR) 1.54 + 1.55 +#include "unicode/ustring.h" 1.56 +#include "uarrsort.h" 1.57 + 1.58 +struct UResAEntry { 1.59 + UChar *key; 1.60 + UResourceBundle *item; 1.61 +}; 1.62 + 1.63 +struct UResourceBundleAIterator { 1.64 + UResourceBundle *bund; 1.65 + UResAEntry *entries; 1.66 + int32_t num; 1.67 + int32_t cursor; 1.68 +}; 1.69 + 1.70 +/* Must be C linkage to pass function pointer to the sort function */ 1.71 + 1.72 +U_CDECL_BEGIN 1.73 + 1.74 +static int32_t U_CALLCONV 1.75 +ures_a_codepointSort(const void *context, const void *left, const void *right) { 1.76 + //CompareContext *cmp=(CompareContext *)context; 1.77 + return u_strcmp(((const UResAEntry *)left)->key, 1.78 + ((const UResAEntry *)right)->key); 1.79 +} 1.80 + 1.81 +U_CDECL_END 1.82 + 1.83 +static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund, UErrorCode *status) { 1.84 + if(U_FAILURE(*status)) { 1.85 + return; 1.86 + } 1.87 + aiter->bund = bund; 1.88 + aiter->num = ures_getSize(aiter->bund); 1.89 + aiter->cursor = 0; 1.90 +#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR) 1.91 + aiter->entries = NULL; 1.92 +#else 1.93 + aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num); 1.94 + for(int i=0;i<aiter->num;i++) { 1.95 + aiter->entries[i].item = ures_getByIndex(aiter->bund, i, NULL, status); 1.96 + const char *akey = ures_getKey(aiter->entries[i].item); 1.97 + int32_t len = uprv_strlen(akey)+1; 1.98 + aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar)); 1.99 + u_charsToUChars(akey, aiter->entries[i].key, len); 1.100 + } 1.101 + uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, NULL, TRUE, status); 1.102 +#endif 1.103 +} 1.104 + 1.105 +static void ures_a_close(UResourceBundleAIterator *aiter) { 1.106 +#if defined(U_SORT_ASCII_BUNDLE_ITERATOR) 1.107 + for(int i=0;i<aiter->num;i++) { 1.108 + uprv_free(aiter->entries[i].key); 1.109 + ures_close(aiter->entries[i].item); 1.110 + } 1.111 +#endif 1.112 +} 1.113 + 1.114 +static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_t *len, const char **key, UErrorCode *err) { 1.115 +#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR) 1.116 + return ures_getNextString(aiter->bund, len, key, err); 1.117 +#else 1.118 + if(U_FAILURE(*err)) return NULL; 1.119 + UResourceBundle *item = aiter->entries[aiter->cursor].item; 1.120 + const UChar* ret = ures_getString(item, len, err); 1.121 + *key = ures_getKey(item); 1.122 + aiter->cursor++; 1.123 + return ret; 1.124 +#endif 1.125 +} 1.126 + 1.127 + 1.128 +#endif 1.129 + 1.130 + 1.131 +U_NAMESPACE_BEGIN 1.132 + 1.133 + 1.134 +// ***************************************************************************** 1.135 +// class DateTimePatternGenerator 1.136 +// ***************************************************************************** 1.137 +static const UChar Canonical_Items[] = { 1.138 + // GyQMwWEdDFHmsSv 1.139 + CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_E, LOW_D, CAP_D, CAP_F, 1.140 + CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0 1.141 +}; 1.142 + 1.143 +static const dtTypeElem dtTypes[] = { 1.144 + // patternChar, field, type, minLen, weight 1.145 + {CAP_G, UDATPG_ERA_FIELD, DT_SHORT, 1, 3,}, 1.146 + {CAP_G, UDATPG_ERA_FIELD, DT_LONG, 4, 0}, 1.147 + {LOW_Y, UDATPG_YEAR_FIELD, DT_NUMERIC, 1, 20}, 1.148 + {CAP_Y, UDATPG_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 20}, 1.149 + {LOW_U, UDATPG_YEAR_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 20}, 1.150 + {CAP_U, UDATPG_YEAR_FIELD, DT_SHORT, 1, 3}, 1.151 + {CAP_U, UDATPG_YEAR_FIELD, DT_LONG, 4, 0}, 1.152 + {CAP_U, UDATPG_YEAR_FIELD, DT_NARROW, 5, 0}, 1.153 + {CAP_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC, 1, 2}, 1.154 + {CAP_Q, UDATPG_QUARTER_FIELD, DT_SHORT, 3, 0}, 1.155 + {CAP_Q, UDATPG_QUARTER_FIELD, DT_LONG, 4, 0}, 1.156 + {LOW_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, 1.157 + {LOW_Q, UDATPG_QUARTER_FIELD, DT_SHORT + DT_DELTA, 3, 0}, 1.158 + {LOW_Q, UDATPG_QUARTER_FIELD, DT_LONG + DT_DELTA, 4, 0}, 1.159 + {CAP_M, UDATPG_MONTH_FIELD, DT_NUMERIC, 1, 2}, 1.160 + {CAP_M, UDATPG_MONTH_FIELD, DT_SHORT, 3, 0}, 1.161 + {CAP_M, UDATPG_MONTH_FIELD, DT_LONG, 4, 0}, 1.162 + {CAP_M, UDATPG_MONTH_FIELD, DT_NARROW, 5, 0}, 1.163 + {CAP_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, 1.164 + {CAP_L, UDATPG_MONTH_FIELD, DT_SHORT - DT_DELTA, 3, 0}, 1.165 + {CAP_L, UDATPG_MONTH_FIELD, DT_LONG - DT_DELTA, 4, 0}, 1.166 + {CAP_L, UDATPG_MONTH_FIELD, DT_NARROW - DT_DELTA, 5, 0}, 1.167 + {LOW_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 1}, 1.168 + {LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2}, 1.169 + {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 0}, 1.170 + {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORT, 1, 3}, 1.171 + {CAP_E, UDATPG_WEEKDAY_FIELD, DT_LONG, 4, 0}, 1.172 + {CAP_E, UDATPG_WEEKDAY_FIELD, DT_NARROW, 5, 0}, 1.173 + {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 2}, 1.174 + {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORT - 2*DT_DELTA, 3, 0}, 1.175 + {LOW_C, UDATPG_WEEKDAY_FIELD, DT_LONG - 2*DT_DELTA, 4, 0}, 1.176 + {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NARROW - 2*DT_DELTA, 5, 0}, 1.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 1.178 + {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORT - DT_DELTA, 3, 0}, 1.179 + {LOW_E, UDATPG_WEEKDAY_FIELD, DT_LONG - DT_DELTA, 4, 0}, 1.180 + {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NARROW - DT_DELTA, 5, 0}, 1.181 + {LOW_D, UDATPG_DAY_FIELD, DT_NUMERIC, 1, 2}, 1.182 + {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 3}, 1.183 + {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 0}, 1.184 + {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + 3*DT_DELTA, 1, 20}, // really internal use, so we don't care 1.185 + {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 0}, 1.186 + {CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour 1.187 + {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2}, // 24 hour 1.188 + {LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour 1.189 + {CAP_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // 12 hour 1.190 + {LOW_M, UDATPG_MINUTE_FIELD, DT_NUMERIC, 1, 2}, 1.191 + {LOW_S, UDATPG_SECOND_FIELD, DT_NUMERIC, 1, 2}, 1.192 + {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000}, 1.193 + {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 1000}, 1.194 + {LOW_V, UDATPG_ZONE_FIELD, DT_SHORT - 2*DT_DELTA, 1, 0}, 1.195 + {LOW_V, UDATPG_ZONE_FIELD, DT_LONG - 2*DT_DELTA, 4, 0}, 1.196 + {LOW_Z, UDATPG_ZONE_FIELD, DT_SHORT, 1, 3}, 1.197 + {LOW_Z, UDATPG_ZONE_FIELD, DT_LONG, 4, 0}, 1.198 + {CAP_Z, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 3}, 1.199 + {CAP_Z, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, 1.200 + {CAP_Z, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 5, 0}, 1.201 + {CAP_O, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0}, 1.202 + {CAP_O, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, 1.203 + {CAP_V, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0}, 1.204 + {CAP_V, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 2, 0}, 1.205 + {CAP_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0}, 1.206 + {CAP_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0}, 1.207 + {CAP_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, 1.208 + {LOW_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0}, 1.209 + {LOW_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0}, 1.210 + {LOW_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0}, 1.211 + {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[] 1.212 + }; 1.213 + 1.214 +static const char* const CLDR_FIELD_APPEND[] = { 1.215 + "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*", 1.216 + "Hour", "Minute", "Second", "*", "Timezone" 1.217 +}; 1.218 + 1.219 +static const char* const CLDR_FIELD_NAME[] = { 1.220 + "era", "year", "quarter", "month", "week", "*", "weekday", "*", "*", "day", "dayperiod", 1.221 + "hour", "minute", "second", "*", "zone" 1.222 +}; 1.223 + 1.224 +static const char* const Resource_Fields[] = { 1.225 + "day", "dayperiod", "era", "hour", "minute", "month", "second", "week", 1.226 + "weekday", "year", "zone", "quarter" }; 1.227 + 1.228 +// For appendItems 1.229 +static const UChar UDATPG_ItemFormat[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A, 1.230 + 0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524 1.231 + 1.232 +//static const UChar repeatedPatterns[6]={CAP_G, CAP_E, LOW_Z, LOW_V, CAP_Q, 0}; // "GEzvQ" 1.233 + 1.234 +static const char DT_DateTimePatternsTag[]="DateTimePatterns"; 1.235 +static const char DT_DateTimeCalendarTag[]="calendar"; 1.236 +static const char DT_DateTimeGregorianTag[]="gregorian"; 1.237 +static const char DT_DateTimeAppendItemsTag[]="appendItems"; 1.238 +static const char DT_DateTimeFieldsTag[]="fields"; 1.239 +static const char DT_DateTimeAvailableFormatsTag[]="availableFormats"; 1.240 +//static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns); 1.241 + 1.242 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator) 1.243 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration) 1.244 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration) 1.245 + 1.246 +DateTimePatternGenerator* U_EXPORT2 1.247 +DateTimePatternGenerator::createInstance(UErrorCode& status) { 1.248 + return createInstance(Locale::getDefault(), status); 1.249 +} 1.250 + 1.251 +DateTimePatternGenerator* U_EXPORT2 1.252 +DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) { 1.253 + DateTimePatternGenerator *result = new DateTimePatternGenerator(locale, status); 1.254 + if (result == NULL) { 1.255 + status = U_MEMORY_ALLOCATION_ERROR; 1.256 + } 1.257 + if (U_FAILURE(status)) { 1.258 + delete result; 1.259 + result = NULL; 1.260 + } 1.261 + return result; 1.262 +} 1.263 + 1.264 +DateTimePatternGenerator* U_EXPORT2 1.265 +DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) { 1.266 + DateTimePatternGenerator *result = new DateTimePatternGenerator(status); 1.267 + if (result == NULL) { 1.268 + status = U_MEMORY_ALLOCATION_ERROR; 1.269 + } 1.270 + if (U_FAILURE(status)) { 1.271 + delete result; 1.272 + result = NULL; 1.273 + } 1.274 + return result; 1.275 +} 1.276 + 1.277 +DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) : 1.278 + skipMatcher(NULL), 1.279 + fAvailableFormatKeyHash(NULL) 1.280 +{ 1.281 + fp = new FormatParser(); 1.282 + dtMatcher = new DateTimeMatcher(); 1.283 + distanceInfo = new DistanceInfo(); 1.284 + patternMap = new PatternMap(); 1.285 + if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) { 1.286 + status = U_MEMORY_ALLOCATION_ERROR; 1.287 + } 1.288 +} 1.289 + 1.290 +DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) : 1.291 + skipMatcher(NULL), 1.292 + fAvailableFormatKeyHash(NULL) 1.293 +{ 1.294 + fp = new FormatParser(); 1.295 + dtMatcher = new DateTimeMatcher(); 1.296 + distanceInfo = new DistanceInfo(); 1.297 + patternMap = new PatternMap(); 1.298 + if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) { 1.299 + status = U_MEMORY_ALLOCATION_ERROR; 1.300 + } 1.301 + else { 1.302 + initData(locale, status); 1.303 + } 1.304 +} 1.305 + 1.306 +DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) : 1.307 + UObject(), 1.308 + skipMatcher(NULL), 1.309 + fAvailableFormatKeyHash(NULL) 1.310 +{ 1.311 + fp = new FormatParser(); 1.312 + dtMatcher = new DateTimeMatcher(); 1.313 + distanceInfo = new DistanceInfo(); 1.314 + patternMap = new PatternMap(); 1.315 + *this=other; 1.316 +} 1.317 + 1.318 +DateTimePatternGenerator& 1.319 +DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) { 1.320 + pLocale = other.pLocale; 1.321 + fDefaultHourFormatChar = other.fDefaultHourFormatChar; 1.322 + *fp = *(other.fp); 1.323 + dtMatcher->copyFrom(other.dtMatcher->skeleton); 1.324 + *distanceInfo = *(other.distanceInfo); 1.325 + dateTimeFormat = other.dateTimeFormat; 1.326 + decimal = other.decimal; 1.327 + // NUL-terminate for the C API. 1.328 + dateTimeFormat.getTerminatedBuffer(); 1.329 + decimal.getTerminatedBuffer(); 1.330 + delete skipMatcher; 1.331 + if ( other.skipMatcher == NULL ) { 1.332 + skipMatcher = NULL; 1.333 + } 1.334 + else { 1.335 + skipMatcher = new DateTimeMatcher(*other.skipMatcher); 1.336 + } 1.337 + for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) { 1.338 + appendItemFormats[i] = other.appendItemFormats[i]; 1.339 + appendItemNames[i] = other.appendItemNames[i]; 1.340 + // NUL-terminate for the C API. 1.341 + appendItemFormats[i].getTerminatedBuffer(); 1.342 + appendItemNames[i].getTerminatedBuffer(); 1.343 + } 1.344 + UErrorCode status = U_ZERO_ERROR; 1.345 + patternMap->copyFrom(*other.patternMap, status); 1.346 + copyHashtable(other.fAvailableFormatKeyHash, status); 1.347 + return *this; 1.348 +} 1.349 + 1.350 + 1.351 +UBool 1.352 +DateTimePatternGenerator::operator==(const DateTimePatternGenerator& other) const { 1.353 + if (this == &other) { 1.354 + return TRUE; 1.355 + } 1.356 + if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) && 1.357 + (dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) { 1.358 + for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) { 1.359 + if ((appendItemFormats[i] != other.appendItemFormats[i]) || 1.360 + (appendItemNames[i] != other.appendItemNames[i]) ) { 1.361 + return FALSE; 1.362 + } 1.363 + } 1.364 + return TRUE; 1.365 + } 1.366 + else { 1.367 + return FALSE; 1.368 + } 1.369 +} 1.370 + 1.371 +UBool 1.372 +DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) const { 1.373 + return !operator==(other); 1.374 +} 1.375 + 1.376 +DateTimePatternGenerator::~DateTimePatternGenerator() { 1.377 + if (fAvailableFormatKeyHash!=NULL) { 1.378 + delete fAvailableFormatKeyHash; 1.379 + } 1.380 + 1.381 + if (fp != NULL) delete fp; 1.382 + if (dtMatcher != NULL) delete dtMatcher; 1.383 + if (distanceInfo != NULL) delete distanceInfo; 1.384 + if (patternMap != NULL) delete patternMap; 1.385 + if (skipMatcher != NULL) delete skipMatcher; 1.386 +} 1.387 + 1.388 +void 1.389 +DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) { 1.390 + //const char *baseLangName = locale.getBaseName(); // unused 1.391 + 1.392 + skipMatcher = NULL; 1.393 + fAvailableFormatKeyHash=NULL; 1.394 + addCanonicalItems(); 1.395 + addICUPatterns(locale, status); 1.396 + if (U_FAILURE(status)) { 1.397 + return; 1.398 + } 1.399 + addCLDRData(locale, status); 1.400 + setDateTimeFromCalendar(locale, status); 1.401 + setDecimalSymbols(locale, status); 1.402 +} // DateTimePatternGenerator::initData 1.403 + 1.404 +UnicodeString 1.405 +DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode& 1.406 +/*status*/) { 1.407 + dtMatcher->set(pattern, fp); 1.408 + return dtMatcher->getSkeletonPtr()->getSkeleton(); 1.409 +} 1.410 + 1.411 +UnicodeString 1.412 +DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) { 1.413 + dtMatcher->set(pattern, fp); 1.414 + return dtMatcher->getSkeletonPtr()->getBaseSkeleton(); 1.415 +} 1.416 + 1.417 +void 1.418 +DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& status) { 1.419 + UnicodeString dfPattern; 1.420 + UnicodeString conflictingString; 1.421 + DateFormat* df; 1.422 + 1.423 + if (U_FAILURE(status)) { 1.424 + return; 1.425 + } 1.426 + 1.427 + // Load with ICU patterns 1.428 + for (int32_t i=DateFormat::kFull; i<=DateFormat::kShort; i++) { 1.429 + DateFormat::EStyle style = (DateFormat::EStyle)i; 1.430 + df = DateFormat::createDateInstance(style, locale); 1.431 + SimpleDateFormat* sdf; 1.432 + if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) { 1.433 + addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status); 1.434 + } 1.435 + // TODO Maybe we should return an error when the date format isn't simple. 1.436 + delete df; 1.437 + if (U_FAILURE(status)) { 1.438 + return; 1.439 + } 1.440 + 1.441 + df = DateFormat::createTimeInstance(style, locale); 1.442 + if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) { 1.443 + addPattern(sdf->toPattern(dfPattern), FALSE, conflictingString, status); 1.444 + // HACK for hh:ss 1.445 + if ( i==DateFormat::kMedium ) { 1.446 + hackPattern = dfPattern; 1.447 + } 1.448 + } 1.449 + // TODO Maybe we should return an error when the date format isn't simple. 1.450 + delete df; 1.451 + if (U_FAILURE(status)) { 1.452 + return; 1.453 + } 1.454 + } 1.455 +} 1.456 + 1.457 +void 1.458 +DateTimePatternGenerator::hackTimes(const UnicodeString& hackPattern, UErrorCode& status) { 1.459 + UnicodeString conflictingString; 1.460 + 1.461 + fp->set(hackPattern); 1.462 + UnicodeString mmss; 1.463 + UBool gotMm=FALSE; 1.464 + for (int32_t i=0; i<fp->itemNumber; ++i) { 1.465 + UnicodeString field = fp->items[i]; 1.466 + if ( fp->isQuoteLiteral(field) ) { 1.467 + if ( gotMm ) { 1.468 + UnicodeString quoteLiteral; 1.469 + fp->getQuoteLiteral(quoteLiteral, &i); 1.470 + mmss += quoteLiteral; 1.471 + } 1.472 + } 1.473 + else { 1.474 + if (fp->isPatternSeparator(field) && gotMm) { 1.475 + mmss+=field; 1.476 + } 1.477 + else { 1.478 + UChar ch=field.charAt(0); 1.479 + if (ch==LOW_M) { 1.480 + gotMm=TRUE; 1.481 + mmss+=field; 1.482 + } 1.483 + else { 1.484 + if (ch==LOW_S) { 1.485 + if (!gotMm) { 1.486 + break; 1.487 + } 1.488 + mmss+= field; 1.489 + addPattern(mmss, FALSE, conflictingString, status); 1.490 + break; 1.491 + } 1.492 + else { 1.493 + if (gotMm || ch==LOW_Z || ch==CAP_Z || ch==LOW_V || ch==CAP_V) { 1.494 + break; 1.495 + } 1.496 + } 1.497 + } 1.498 + } 1.499 + } 1.500 + } 1.501 +} 1.502 + 1.503 +#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) 1.504 + 1.505 +static const UChar hourFormatChars[] = { CAP_H, LOW_H, CAP_K, LOW_K, 0 }; // HhKk, the hour format characters 1.506 + 1.507 +void 1.508 +DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& err) { 1.509 + UResourceBundle *rb, *calTypeBundle, *calBundle; 1.510 + UResourceBundle *patBundle, *fieldBundle, *fBundle; 1.511 + UnicodeString rbPattern, value, field; 1.512 + UnicodeString conflictingPattern; 1.513 + const char *key=NULL; 1.514 + int32_t i; 1.515 + 1.516 + UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, LENGTHOF(UDATPG_ItemFormat)-1); // Read-only alias. 1.517 + 1.518 + err = U_ZERO_ERROR; 1.519 + 1.520 + fDefaultHourFormatChar = 0; 1.521 + for (i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1.522 + appendItemNames[i]=CAP_F; 1.523 + if (i<10) { 1.524 + appendItemNames[i]+=(UChar)(i+0x30); 1.525 + } 1.526 + else { 1.527 + appendItemNames[i]+=(UChar)0x31; 1.528 + appendItemNames[i]+=(UChar)(i-10 + 0x30); 1.529 + } 1.530 + // NUL-terminate for the C API. 1.531 + appendItemNames[i].getTerminatedBuffer(); 1.532 + } 1.533 + 1.534 + rb = ures_open(NULL, locale.getName(), &err); 1.535 + if (rb == NULL || U_FAILURE(err)) { 1.536 + return; 1.537 + } 1.538 + const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err); 1.539 + const char * calendarTypeToUse = DT_DateTimeGregorianTag; // initial default 1.540 + char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well 1.541 + if ( U_SUCCESS(err) ) { 1.542 + char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; 1.543 + // obtain a locale that always has the calendar key value that should be used 1.544 + (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL, 1.545 + "calendar", "calendar", locale.getName(), NULL, FALSE, &err); 1.546 + localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination 1.547 + // now get the calendar key value from that locale 1.548 + int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &err); 1.549 + if (U_SUCCESS(err) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { 1.550 + calendarTypeToUse = calendarType; 1.551 + } 1.552 + err = U_ZERO_ERROR; 1.553 + } 1.554 + calBundle = ures_getByKeyWithFallback(rb, DT_DateTimeCalendarTag, NULL, &err); 1.555 + calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &err); 1.556 + 1.557 + key=NULL; 1.558 + int32_t dtCount=0; 1.559 + patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimePatternsTag, NULL, &err); 1.560 + while (U_SUCCESS(err)) { 1.561 + rbPattern = ures_getNextUnicodeString(patBundle, &key, &err); 1.562 + dtCount++; 1.563 + if (rbPattern.length()==0 ) { 1.564 + break; // no more pattern 1.565 + } 1.566 + else { 1.567 + if (dtCount==9) { 1.568 + setDateTimeFormat(rbPattern); 1.569 + } else if (dtCount==4) { // short time format 1.570 + // set fDefaultHourFormatChar to the hour format character from this pattern 1.571 + int32_t tfIdx, tfLen = rbPattern.length(); 1.572 + UBool ignoreChars = FALSE; 1.573 + for (tfIdx = 0; tfIdx < tfLen; tfIdx++) { 1.574 + UChar tfChar = rbPattern.charAt(tfIdx); 1.575 + if ( tfChar == SINGLE_QUOTE ) { 1.576 + ignoreChars = !ignoreChars; // toggle (handle quoted literals & '' for single quote) 1.577 + } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != NULL ) { 1.578 + fDefaultHourFormatChar = tfChar; 1.579 + break; 1.580 + } 1.581 + } 1.582 + } 1.583 + } 1.584 + } 1.585 + ures_close(patBundle); 1.586 + 1.587 + err = U_ZERO_ERROR; 1.588 + patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimeAppendItemsTag, NULL, &err); 1.589 + key=NULL; 1.590 + UnicodeString itemKey; 1.591 + while (U_SUCCESS(err)) { 1.592 + rbPattern = ures_getNextUnicodeString(patBundle, &key, &err); 1.593 + if (rbPattern.length()==0 ) { 1.594 + break; // no more pattern 1.595 + } 1.596 + else { 1.597 + setAppendItemFormat(getAppendFormatNumber(key), rbPattern); 1.598 + } 1.599 + } 1.600 + ures_close(patBundle); 1.601 + 1.602 + key=NULL; 1.603 + err = U_ZERO_ERROR; 1.604 + fBundle = ures_getByKeyWithFallback(rb, DT_DateTimeFieldsTag, NULL, &err); 1.605 + for (i=0; i<MAX_RESOURCE_FIELD; ++i) { 1.606 + err = U_ZERO_ERROR; 1.607 + patBundle = ures_getByKeyWithFallback(fBundle, Resource_Fields[i], NULL, &err); 1.608 + fieldBundle = ures_getByKeyWithFallback(patBundle, "dn", NULL, &err); 1.609 + rbPattern = ures_getNextUnicodeString(fieldBundle, &key, &err); 1.610 + ures_close(fieldBundle); 1.611 + ures_close(patBundle); 1.612 + if (rbPattern.length()==0 ) { 1.613 + continue; 1.614 + } 1.615 + else { 1.616 + setAppendItemName(getAppendNameNumber(Resource_Fields[i]), rbPattern); 1.617 + } 1.618 + } 1.619 + ures_close(fBundle); 1.620 + 1.621 + // add available formats 1.622 + UBool firstTimeThrough = TRUE; 1.623 + err = U_ZERO_ERROR; 1.624 + initHashtable(err); 1.625 + UBool override = TRUE; 1.626 + while (TRUE) { 1.627 + // At the start of the loop: 1.628 + // - rb is the open resource bundle for the current locale being processed, 1.629 + // whose actual name is in curLocaleName. 1.630 + // - if U_SUCCESS(err), then calBundle and calTypeBundle are open; 1.631 + // process contents of calTypeBundle, then close calBundle and calTypeBundle. 1.632 + if (U_SUCCESS(err)) { 1.633 + // process contents of calTypeBundle 1.634 + patBundle = ures_getByKeyWithFallback(calTypeBundle, DT_DateTimeAvailableFormatsTag, NULL, &err); 1.635 + if (U_SUCCESS(err)) { 1.636 + int32_t numberKeys = ures_getSize(patBundle); 1.637 + int32_t len; 1.638 + const UChar *retPattern; 1.639 + key=NULL; 1.640 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR) 1.641 + UResourceBundleAIterator aiter; 1.642 + ures_a_open(&aiter, patBundle, &err); 1.643 +#endif 1.644 + for(i=0; i<numberKeys; ++i) { 1.645 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR) 1.646 + retPattern=ures_a_getNextString(&aiter, &len, &key, &err); 1.647 +#else 1.648 + retPattern=ures_getNextString(patBundle, &len, &key, &err); 1.649 +#endif 1.650 + UnicodeString format=UnicodeString(retPattern); 1.651 + UnicodeString retKey=UnicodeString(key, -1, US_INV); 1.652 + if ( firstTimeThrough || !isAvailableFormatSet(retKey) ) { 1.653 + setAvailableFormat(retKey, err); 1.654 + // Add pattern with its associated skeleton. Override any duplicate derived from std patterns, 1.655 + // but not a previous availableFormats entry: 1.656 + addPatternWithSkeleton(format, &retKey, override, conflictingPattern, err); 1.657 + } 1.658 + } 1.659 +#if defined(U_USE_ASCII_BUNDLE_ITERATOR) 1.660 + ures_a_close(&aiter); 1.661 +#endif 1.662 + ures_close(patBundle); 1.663 + } 1.664 + firstTimeThrough = FALSE; 1.665 + // close calBundle and calTypeBundle 1.666 + ures_close(calTypeBundle); 1.667 + ures_close(calBundle); 1.668 + } 1.669 + if (uprv_strcmp(curLocaleName,"root")==0 || uprv_strlen(curLocaleName)==0) { 1.670 + // we just finished handling root, nothing more to check 1.671 + ures_close(rb); 1.672 + break; 1.673 + } 1.674 + // Find the name of the appropriate parent locale (from %%Parent if present, else 1.675 + // uloc_getParent on the actual locale name) 1.676 + // (It would be nice to have a ures function that did this...) 1.677 + err = U_ZERO_ERROR; 1.678 + char parentLocale[ULOC_FULLNAME_CAPACITY]; 1.679 + int32_t locNameLen; 1.680 + const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &err); 1.681 + if (U_SUCCESS(err) && err != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) { 1.682 + u_UCharsToChars(parentUName, parentLocale, locNameLen + 1); 1.683 + } else { 1.684 + err = U_ZERO_ERROR; 1.685 + uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &err); 1.686 + if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) { 1.687 + // just fallback to root, since we are not already there 1.688 + parentLocale[0] = 0; 1.689 + err = U_ZERO_ERROR; 1.690 + } 1.691 + } 1.692 + // Close current locale bundle 1.693 + ures_close(rb); 1.694 + // And open its parent, which becomes the new current locale being processed 1.695 + rb = ures_open(NULL, parentLocale, &err); 1.696 + if ( U_FAILURE(err) ) { 1.697 + err = U_ZERO_ERROR; 1.698 + break; 1.699 + } 1.700 + // Get the name of the parent / new current locale 1.701 + curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err); 1.702 + if ( U_FAILURE(err) ) { 1.703 + curLocaleName = parentLocale; 1.704 + err = U_ZERO_ERROR; 1.705 + } 1.706 + if (uprv_strcmp(curLocaleName,"root")==0 || uprv_strlen(curLocaleName)==0) { 1.707 + override = FALSE; 1.708 + } 1.709 + // Open calBundle and calTypeBundle 1.710 + calBundle = ures_getByKeyWithFallback(rb, DT_DateTimeCalendarTag, NULL, &err); 1.711 + if (U_SUCCESS(err)) { 1.712 + calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &err); 1.713 + if ( U_FAILURE(err) ) { 1.714 + ures_close(calBundle); 1.715 + } 1.716 + } 1.717 + // Go to the top of the loop to process contents of calTypeBundle 1.718 + } 1.719 + 1.720 + if (hackPattern.length()>0) { 1.721 + hackTimes(hackPattern, err); 1.722 + } 1.723 +} 1.724 + 1.725 +void 1.726 +DateTimePatternGenerator::initHashtable(UErrorCode& err) { 1.727 + if (fAvailableFormatKeyHash!=NULL) { 1.728 + return; 1.729 + } 1.730 + if ((fAvailableFormatKeyHash = new Hashtable(FALSE, err))==NULL) { 1.731 + err=U_MEMORY_ALLOCATION_ERROR; 1.732 + return; 1.733 + } 1.734 +} 1.735 + 1.736 + 1.737 +void 1.738 +DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value) { 1.739 + appendItemFormats[field] = value; 1.740 + // NUL-terminate for the C API. 1.741 + appendItemFormats[field].getTerminatedBuffer(); 1.742 +} 1.743 + 1.744 +const UnicodeString& 1.745 +DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const { 1.746 + return appendItemFormats[field]; 1.747 +} 1.748 + 1.749 +void 1.750 +DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) { 1.751 + appendItemNames[field] = value; 1.752 + // NUL-terminate for the C API. 1.753 + appendItemNames[field].getTerminatedBuffer(); 1.754 +} 1.755 + 1.756 +const UnicodeString& 1.757 +DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field) const { 1.758 + return appendItemNames[field]; 1.759 +} 1.760 + 1.761 +void 1.762 +DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) { 1.763 + value = SINGLE_QUOTE; 1.764 + value += appendItemNames[field]; 1.765 + value += SINGLE_QUOTE; 1.766 +} 1.767 + 1.768 +UnicodeString 1.769 +DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErrorCode& status) { 1.770 + return getBestPattern(patternForm, UDATPG_MATCH_NO_OPTIONS, status); 1.771 +} 1.772 + 1.773 +UnicodeString 1.774 +DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, UErrorCode& status) { 1.775 + const UnicodeString *bestPattern=NULL; 1.776 + UnicodeString dtFormat; 1.777 + UnicodeString resultPattern; 1.778 + int32_t flags = kDTPGNoFlags; 1.779 + 1.780 + int32_t dateMask=(1<<UDATPG_DAYPERIOD_FIELD) - 1; 1.781 + int32_t timeMask=(1<<UDATPG_FIELD_COUNT) - 1 - dateMask; 1.782 + 1.783 + // Replace hour metacharacters 'j' and 'J', set flags as necessary 1.784 + UnicodeString patternFormCopy = UnicodeString(patternForm); 1.785 + int32_t patPos, patLen = patternFormCopy.length(); 1.786 + UBool inQuoted = FALSE; 1.787 + for (patPos = 0; patPos < patLen; patPos++) { 1.788 + UChar patChr = patternFormCopy.charAt(patPos); 1.789 + if (patChr == SINGLE_QUOTE) { 1.790 + inQuoted = !inQuoted; 1.791 + } else if (!inQuoted) { 1.792 + if (patChr == LOW_J) { 1.793 + patternFormCopy.setCharAt(patPos, fDefaultHourFormatChar); 1.794 + } else if (patChr == CAP_J) { 1.795 + // Get pattern for skeleton with H, then replace H or k 1.796 + // with fDefaultHourFormatChar (if different) 1.797 + patternFormCopy.setCharAt(patPos, CAP_H); 1.798 + flags |= kDTPGSkeletonUsesCapJ; 1.799 + } 1.800 + } 1.801 + } 1.802 + 1.803 + resultPattern.remove(); 1.804 + dtMatcher->set(patternFormCopy, fp); 1.805 + const PtnSkeleton* specifiedSkeleton=NULL; 1.806 + bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, &specifiedSkeleton); 1.807 + if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) { 1.808 + resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, flags, options); 1.809 + 1.810 + return resultPattern; 1.811 + } 1.812 + int32_t neededFields = dtMatcher->getFieldMask(); 1.813 + UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, options); 1.814 + UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, options); 1.815 + if (datePattern.length()==0) { 1.816 + if (timePattern.length()==0) { 1.817 + resultPattern.remove(); 1.818 + } 1.819 + else { 1.820 + return timePattern; 1.821 + } 1.822 + } 1.823 + if (timePattern.length()==0) { 1.824 + return datePattern; 1.825 + } 1.826 + resultPattern.remove(); 1.827 + status = U_ZERO_ERROR; 1.828 + dtFormat=getDateTimeFormat(); 1.829 + Formattable dateTimeObject[] = { timePattern, datePattern }; 1.830 + resultPattern = MessageFormat::format(dtFormat, dateTimeObject, 2, resultPattern, status ); 1.831 + return resultPattern; 1.832 +} 1.833 + 1.834 +UnicodeString 1.835 +DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern, 1.836 + const UnicodeString& skeleton, 1.837 + UErrorCode& status) { 1.838 + return replaceFieldTypes(pattern, skeleton, UDATPG_MATCH_NO_OPTIONS, status); 1.839 +} 1.840 + 1.841 +UnicodeString 1.842 +DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern, 1.843 + const UnicodeString& skeleton, 1.844 + UDateTimePatternMatchOptions options, 1.845 + UErrorCode& /*status*/) { 1.846 + dtMatcher->set(skeleton, fp); 1.847 + UnicodeString result = adjustFieldTypes(pattern, NULL, kDTPGNoFlags, options); 1.848 + return result; 1.849 +} 1.850 + 1.851 +void 1.852 +DateTimePatternGenerator::setDecimal(const UnicodeString& newDecimal) { 1.853 + this->decimal = newDecimal; 1.854 + // NUL-terminate for the C API. 1.855 + this->decimal.getTerminatedBuffer(); 1.856 +} 1.857 + 1.858 +const UnicodeString& 1.859 +DateTimePatternGenerator::getDecimal() const { 1.860 + return decimal; 1.861 +} 1.862 + 1.863 +void 1.864 +DateTimePatternGenerator::addCanonicalItems() { 1.865 + UnicodeString conflictingPattern; 1.866 + UErrorCode status = U_ZERO_ERROR; 1.867 + 1.868 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; i++) { 1.869 + addPattern(UnicodeString(Canonical_Items[i]), FALSE, conflictingPattern, status); 1.870 + } 1.871 +} 1.872 + 1.873 +void 1.874 +DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) { 1.875 + dateTimeFormat = dtFormat; 1.876 + // NUL-terminate for the C API. 1.877 + dateTimeFormat.getTerminatedBuffer(); 1.878 +} 1.879 + 1.880 +const UnicodeString& 1.881 +DateTimePatternGenerator::getDateTimeFormat() const { 1.882 + return dateTimeFormat; 1.883 +} 1.884 + 1.885 +void 1.886 +DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) { 1.887 + const UChar *resStr; 1.888 + int32_t resStrLen = 0; 1.889 + 1.890 + Calendar* fCalendar = Calendar::createInstance(locale, status); 1.891 + CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status); 1.892 + UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, status); 1.893 + if (U_FAILURE(status)) return; 1.894 + 1.895 + if (ures_getSize(dateTimePatterns) <= DateFormat::kDateTime) 1.896 + { 1.897 + status = U_INVALID_FORMAT_ERROR; 1.898 + return; 1.899 + } 1.900 + resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)DateFormat::kDateTime, &resStrLen, &status); 1.901 + setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen)); 1.902 + 1.903 + delete fCalendar; 1.904 +} 1.905 + 1.906 +void 1.907 +DateTimePatternGenerator::setDecimalSymbols(const Locale& locale, UErrorCode& status) { 1.908 + DecimalFormatSymbols dfs = DecimalFormatSymbols(locale, status); 1.909 + if(U_SUCCESS(status)) { 1.910 + decimal = dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); 1.911 + // NUL-terminate for the C API. 1.912 + decimal.getTerminatedBuffer(); 1.913 + } 1.914 +} 1.915 + 1.916 +UDateTimePatternConflict 1.917 +DateTimePatternGenerator::addPattern( 1.918 + const UnicodeString& pattern, 1.919 + UBool override, 1.920 + UnicodeString &conflictingPattern, 1.921 + UErrorCode& status) 1.922 +{ 1.923 + return addPatternWithSkeleton(pattern, NULL, override, conflictingPattern, status); 1.924 +} 1.925 + 1.926 +// For DateTimePatternGenerator::addPatternWithSkeleton - 1.927 +// If skeletonToUse is specified, then an availableFormats entry is being added. In this case: 1.928 +// 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern. 1.929 +// 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified 1.930 +// (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override 1.931 +// parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual 1.932 +// specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was 1.933 +// derived (i.e. entries derived from the standard date/time patters for the specified locale). 1.934 +// 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a 1.935 +// specified skeleton (which sets a new field in the PtnElem in the PatternMap). 1.936 +UDateTimePatternConflict 1.937 +DateTimePatternGenerator::addPatternWithSkeleton( 1.938 + const UnicodeString& pattern, 1.939 + const UnicodeString* skeletonToUse, 1.940 + UBool override, 1.941 + UnicodeString& conflictingPattern, 1.942 + UErrorCode& status) 1.943 +{ 1.944 + 1.945 + UnicodeString basePattern; 1.946 + PtnSkeleton skeleton; 1.947 + UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT; 1.948 + 1.949 + DateTimeMatcher matcher; 1.950 + if ( skeletonToUse == NULL ) { 1.951 + matcher.set(pattern, fp, skeleton); 1.952 + matcher.getBasePattern(basePattern); 1.953 + } else { 1.954 + matcher.set(*skeletonToUse, fp, skeleton); // no longer trims skeleton fields to max len 3, per #7930 1.955 + matcher.getBasePattern(basePattern); // or perhaps instead: basePattern = *skeletonToUse; 1.956 + } 1.957 + // We only care about base conflicts - and replacing the pattern associated with a base - if: 1.958 + // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous 1.959 + // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or 1.960 + // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen 1.961 + // if we are getting here from a subsequent call to addPattern). 1.962 + // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking 1.963 + // availableFormats items from root, which should not override any previous entry with the same base. 1.964 + UBool entryHadSpecifiedSkeleton; 1.965 + const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton); 1.966 + if (duplicatePattern != NULL && (!entryHadSpecifiedSkeleton || (skeletonToUse != NULL && !override))) { 1.967 + conflictingStatus = UDATPG_BASE_CONFLICT; 1.968 + conflictingPattern = *duplicatePattern; 1.969 + if (!override) { 1.970 + return conflictingStatus; 1.971 + } 1.972 + } 1.973 + // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats 1.974 + // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with 1.975 + // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for 1.976 + // the previously-specified conflicting item. 1.977 + const PtnSkeleton* entrySpecifiedSkeleton = NULL; 1.978 + duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton); 1.979 + if (duplicatePattern != NULL ) { 1.980 + conflictingStatus = UDATPG_CONFLICT; 1.981 + conflictingPattern = *duplicatePattern; 1.982 + if (!override || (skeletonToUse != NULL && entrySpecifiedSkeleton != NULL)) { 1.983 + return conflictingStatus; 1.984 + } 1.985 + } 1.986 + patternMap->add(basePattern, skeleton, pattern, skeletonToUse != NULL, status); 1.987 + if(U_FAILURE(status)) { 1.988 + return conflictingStatus; 1.989 + } 1.990 + 1.991 + return UDATPG_NO_CONFLICT; 1.992 +} 1.993 + 1.994 + 1.995 +UDateTimePatternField 1.996 +DateTimePatternGenerator::getAppendFormatNumber(const char* field) const { 1.997 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1.998 + if (uprv_strcmp(CLDR_FIELD_APPEND[i], field)==0) { 1.999 + return (UDateTimePatternField)i; 1.1000 + } 1.1001 + } 1.1002 + return UDATPG_FIELD_COUNT; 1.1003 +} 1.1004 + 1.1005 +UDateTimePatternField 1.1006 +DateTimePatternGenerator::getAppendNameNumber(const char* field) const { 1.1007 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1.1008 + if (uprv_strcmp(CLDR_FIELD_NAME[i],field)==0) { 1.1009 + return (UDateTimePatternField)i; 1.1010 + } 1.1011 + } 1.1012 + return UDATPG_FIELD_COUNT; 1.1013 +} 1.1014 + 1.1015 +const UnicodeString* 1.1016 +DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source, 1.1017 + int32_t includeMask, 1.1018 + DistanceInfo* missingFields, 1.1019 + const PtnSkeleton** specifiedSkeletonPtr) { 1.1020 + int32_t bestDistance = 0x7fffffff; 1.1021 + DistanceInfo tempInfo; 1.1022 + const UnicodeString *bestPattern=NULL; 1.1023 + const PtnSkeleton* specifiedSkeleton=NULL; 1.1024 + 1.1025 + PatternMapIterator it; 1.1026 + for (it.set(*patternMap); it.hasNext(); ) { 1.1027 + DateTimeMatcher trial = it.next(); 1.1028 + if (trial.equals(skipMatcher)) { 1.1029 + continue; 1.1030 + } 1.1031 + int32_t distance=source.getDistance(trial, includeMask, tempInfo); 1.1032 + if (distance<bestDistance) { 1.1033 + bestDistance=distance; 1.1034 + bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr(), &specifiedSkeleton); 1.1035 + missingFields->setTo(tempInfo); 1.1036 + if (distance==0) { 1.1037 + break; 1.1038 + } 1.1039 + } 1.1040 + } 1.1041 + 1.1042 + // If the best raw match had a specified skeleton and that skeleton was requested by the caller, 1.1043 + // then return it too. This generally happens when the caller needs to pass that skeleton 1.1044 + // through to adjustFieldTypes so the latter can do a better job. 1.1045 + if (bestPattern && specifiedSkeletonPtr) { 1.1046 + *specifiedSkeletonPtr = specifiedSkeleton; 1.1047 + } 1.1048 + return bestPattern; 1.1049 +} 1.1050 + 1.1051 +UnicodeString 1.1052 +DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern, 1.1053 + const PtnSkeleton* specifiedSkeleton, 1.1054 + int32_t flags, 1.1055 + UDateTimePatternMatchOptions options) { 1.1056 + UnicodeString newPattern; 1.1057 + fp->set(pattern); 1.1058 + for (int32_t i=0; i < fp->itemNumber; i++) { 1.1059 + UnicodeString field = fp->items[i]; 1.1060 + if ( fp->isQuoteLiteral(field) ) { 1.1061 + 1.1062 + UnicodeString quoteLiteral; 1.1063 + fp->getQuoteLiteral(quoteLiteral, &i); 1.1064 + newPattern += quoteLiteral; 1.1065 + } 1.1066 + else { 1.1067 + if (fp->isPatternSeparator(field)) { 1.1068 + newPattern+=field; 1.1069 + continue; 1.1070 + } 1.1071 + int32_t canonicalIndex = fp->getCanonicalIndex(field); 1.1072 + if (canonicalIndex < 0) { 1.1073 + newPattern+=field; 1.1074 + continue; // don't adjust 1.1075 + } 1.1076 + const dtTypeElem *row = &dtTypes[canonicalIndex]; 1.1077 + int32_t typeValue = row->field; 1.1078 + if ((flags & kDTPGFixFractionalSeconds) != 0 && typeValue == UDATPG_SECOND_FIELD) { 1.1079 + UnicodeString newField=dtMatcher->skeleton.original[UDATPG_FRACTIONAL_SECOND_FIELD]; 1.1080 + field = field + decimal + newField; 1.1081 + } else if (dtMatcher->skeleton.type[typeValue]!=0) { 1.1082 + // Here: 1.1083 + // - "reqField" is the field from the originally requested skeleton, with length 1.1084 + // "reqFieldLen". 1.1085 + // - "field" is the field from the found pattern. 1.1086 + // 1.1087 + // The adjusted field should consist of characters from the originally requested 1.1088 + // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD or 1.1089 + // UDATPG_WEEKDAY_FIELD or UDATPG_YEAR_FIELD, in which case it should consist 1.1090 + // of characters from the found pattern. 1.1091 + // 1.1092 + // The length of the adjusted field (adjFieldLen) should match that in the originally 1.1093 + // requested skeleton, except that in the following cases the length of the adjusted field 1.1094 + // should match that in the found pattern (i.e. the length of this pattern field should 1.1095 + // not be adjusted): 1.1096 + // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is 1.1097 + // not set (ticket #7180). Note, we may want to implement a similar change for other 1.1098 + // numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for 1.1099 + // field length, but options bits can be used to override this. 1.1100 + // 2. There is a specified skeleton for the found pattern and one of the following is true: 1.1101 + // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen. 1.1102 + // b) The pattern field is numeric and the skeleton field is not, or vice versa. 1.1103 + 1.1104 + UnicodeString reqField = dtMatcher->skeleton.original[typeValue]; 1.1105 + int32_t reqFieldLen = reqField.length(); 1.1106 + if (reqField.charAt(0) == CAP_E && reqFieldLen < 3) 1.1107 + reqFieldLen = 3; // 1-3 for E are equivalent to 3 for c,e 1.1108 + int32_t adjFieldLen = reqFieldLen; 1.1109 + if ( (typeValue==UDATPG_HOUR_FIELD && (options & UDATPG_MATCH_HOUR_FIELD_LENGTH)==0) || 1.1110 + (typeValue==UDATPG_MINUTE_FIELD && (options & UDATPG_MATCH_MINUTE_FIELD_LENGTH)==0) || 1.1111 + (typeValue==UDATPG_SECOND_FIELD && (options & UDATPG_MATCH_SECOND_FIELD_LENGTH)==0) ) { 1.1112 + adjFieldLen = field.length(); 1.1113 + } else if (specifiedSkeleton) { 1.1114 + UnicodeString skelField = specifiedSkeleton->original[typeValue]; 1.1115 + int32_t skelFieldLen = skelField.length(); 1.1116 + UBool patFieldIsNumeric = (row->type > 0); 1.1117 + UBool skelFieldIsNumeric = (specifiedSkeleton->type[typeValue] > 0); 1.1118 + if (skelFieldLen == reqFieldLen || (patFieldIsNumeric && !skelFieldIsNumeric) || (skelFieldIsNumeric && !patFieldIsNumeric)) { 1.1119 + // don't adjust the field length in the found pattern 1.1120 + adjFieldLen = field.length(); 1.1121 + } 1.1122 + } 1.1123 + UChar c = (typeValue!= UDATPG_HOUR_FIELD && typeValue!= UDATPG_MONTH_FIELD && 1.1124 + typeValue!= UDATPG_WEEKDAY_FIELD && (typeValue!= UDATPG_YEAR_FIELD || reqField.charAt(0)==CAP_Y))? 1.1125 + reqField.charAt(0): field.charAt(0); 1.1126 + if (typeValue == UDATPG_HOUR_FIELD && (flags & kDTPGSkeletonUsesCapJ) != 0) { 1.1127 + c = fDefaultHourFormatChar; 1.1128 + } 1.1129 + field.remove(); 1.1130 + for (int32_t i=adjFieldLen; i>0; --i) { 1.1131 + field+=c; 1.1132 + } 1.1133 + } 1.1134 + newPattern+=field; 1.1135 + } 1.1136 + } 1.1137 + return newPattern; 1.1138 +} 1.1139 + 1.1140 +UnicodeString 1.1141 +DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options) { 1.1142 + UnicodeString resultPattern, tempPattern; 1.1143 + UErrorCode err=U_ZERO_ERROR; 1.1144 + int32_t lastMissingFieldMask=0; 1.1145 + if (missingFields!=0) { 1.1146 + resultPattern=UnicodeString(); 1.1147 + const PtnSkeleton* specifiedSkeleton=NULL; 1.1148 + tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo, &specifiedSkeleton); 1.1149 + resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options); 1.1150 + if ( distanceInfo->missingFieldMask==0 ) { 1.1151 + return resultPattern; 1.1152 + } 1.1153 + while (distanceInfo->missingFieldMask!=0) { // precondition: EVERY single field must work! 1.1154 + if ( lastMissingFieldMask == distanceInfo->missingFieldMask ) { 1.1155 + break; // cannot find the proper missing field 1.1156 + } 1.1157 + if (((distanceInfo->missingFieldMask & UDATPG_SECOND_AND_FRACTIONAL_MASK)==UDATPG_FRACTIONAL_MASK) && 1.1158 + ((missingFields & UDATPG_SECOND_AND_FRACTIONAL_MASK) == UDATPG_SECOND_AND_FRACTIONAL_MASK)) { 1.1159 + resultPattern = adjustFieldTypes(resultPattern, specifiedSkeleton, flags | kDTPGFixFractionalSeconds, options); 1.1160 + distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK; 1.1161 + continue; 1.1162 + } 1.1163 + int32_t startingMask = distanceInfo->missingFieldMask; 1.1164 + tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, &specifiedSkeleton); 1.1165 + tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options); 1.1166 + int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask; 1.1167 + int32_t topField=getTopBitNumber(foundMask); 1.1168 + UnicodeString appendName; 1.1169 + getAppendName((UDateTimePatternField)topField, appendName); 1.1170 + const Formattable formatPattern[] = { 1.1171 + resultPattern, 1.1172 + tempPattern, 1.1173 + appendName 1.1174 + }; 1.1175 + UnicodeString emptyStr; 1.1176 + resultPattern = MessageFormat::format(appendItemFormats[topField], formatPattern, 3, emptyStr, err); 1.1177 + lastMissingFieldMask = distanceInfo->missingFieldMask; 1.1178 + } 1.1179 + } 1.1180 + return resultPattern; 1.1181 +} 1.1182 + 1.1183 +int32_t 1.1184 +DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) { 1.1185 + if ( foundMask==0 ) { 1.1186 + return 0; 1.1187 + } 1.1188 + int32_t i=0; 1.1189 + while (foundMask!=0) { 1.1190 + foundMask >>=1; 1.1191 + ++i; 1.1192 + } 1.1193 + if (i-1 >UDATPG_ZONE_FIELD) { 1.1194 + return UDATPG_ZONE_FIELD; 1.1195 + } 1.1196 + else 1.1197 + return i-1; 1.1198 +} 1.1199 + 1.1200 +void 1.1201 +DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err) 1.1202 +{ 1.1203 + fAvailableFormatKeyHash->puti(key, 1, err); 1.1204 +} 1.1205 + 1.1206 +UBool 1.1207 +DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const { 1.1208 + return (UBool)(fAvailableFormatKeyHash->geti(key) == 1); 1.1209 +} 1.1210 + 1.1211 +void 1.1212 +DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) { 1.1213 + 1.1214 + if (other == NULL) { 1.1215 + return; 1.1216 + } 1.1217 + if (fAvailableFormatKeyHash != NULL) { 1.1218 + delete fAvailableFormatKeyHash; 1.1219 + fAvailableFormatKeyHash = NULL; 1.1220 + } 1.1221 + initHashtable(status); 1.1222 + if(U_FAILURE(status)){ 1.1223 + return; 1.1224 + } 1.1225 + int32_t pos = -1; 1.1226 + const UHashElement* elem = NULL; 1.1227 + // walk through the hash table and create a deep clone 1.1228 + while((elem = other->nextElement(pos))!= NULL){ 1.1229 + const UHashTok otherKeyTok = elem->key; 1.1230 + UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer; 1.1231 + fAvailableFormatKeyHash->puti(*otherKey, 1, status); 1.1232 + if(U_FAILURE(status)){ 1.1233 + return; 1.1234 + } 1.1235 + } 1.1236 +} 1.1237 + 1.1238 +StringEnumeration* 1.1239 +DateTimePatternGenerator::getSkeletons(UErrorCode& status) const { 1.1240 + StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status); 1.1241 + return skeletonEnumerator; 1.1242 +} 1.1243 + 1.1244 +const UnicodeString& 1.1245 +DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) const { 1.1246 + PtnElem *curElem; 1.1247 + 1.1248 + if (skeleton.length() ==0) { 1.1249 + return emptyString; 1.1250 + } 1.1251 + curElem = patternMap->getHeader(skeleton.charAt(0)); 1.1252 + while ( curElem != NULL ) { 1.1253 + if ( curElem->skeleton->getSkeleton()==skeleton ) { 1.1254 + return curElem->pattern; 1.1255 + } 1.1256 + curElem=curElem->next; 1.1257 + } 1.1258 + return emptyString; 1.1259 +} 1.1260 + 1.1261 +StringEnumeration* 1.1262 +DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const { 1.1263 + StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status); 1.1264 + return baseSkeletonEnumerator; 1.1265 +} 1.1266 + 1.1267 +StringEnumeration* 1.1268 +DateTimePatternGenerator::getRedundants(UErrorCode& status) { 1.1269 + StringEnumeration* output = new DTRedundantEnumeration(); 1.1270 + const UnicodeString *pattern; 1.1271 + PatternMapIterator it; 1.1272 + for (it.set(*patternMap); it.hasNext(); ) { 1.1273 + DateTimeMatcher current = it.next(); 1.1274 + pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton())); 1.1275 + if ( isCanonicalItem(*pattern) ) { 1.1276 + continue; 1.1277 + } 1.1278 + if ( skipMatcher == NULL ) { 1.1279 + skipMatcher = new DateTimeMatcher(current); 1.1280 + } 1.1281 + else { 1.1282 + *skipMatcher = current; 1.1283 + } 1.1284 + UnicodeString trial = getBestPattern(current.getPattern(), status); 1.1285 + if (trial == *pattern) { 1.1286 + ((DTRedundantEnumeration *)output)->add(*pattern, status); 1.1287 + } 1.1288 + if (current.equals(skipMatcher)) { 1.1289 + continue; 1.1290 + } 1.1291 + } 1.1292 + return output; 1.1293 +} 1.1294 + 1.1295 +UBool 1.1296 +DateTimePatternGenerator::isCanonicalItem(const UnicodeString& item) const { 1.1297 + if ( item.length() != 1 ) { 1.1298 + return FALSE; 1.1299 + } 1.1300 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1301 + if (item.charAt(0)==Canonical_Items[i]) { 1.1302 + return TRUE; 1.1303 + } 1.1304 + } 1.1305 + return FALSE; 1.1306 +} 1.1307 + 1.1308 + 1.1309 +DateTimePatternGenerator* 1.1310 +DateTimePatternGenerator::clone() const { 1.1311 + return new DateTimePatternGenerator(*this); 1.1312 +} 1.1313 + 1.1314 +PatternMap::PatternMap() { 1.1315 + for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { 1.1316 + boot[i]=NULL; 1.1317 + } 1.1318 + isDupAllowed = TRUE; 1.1319 +} 1.1320 + 1.1321 +void 1.1322 +PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) { 1.1323 + this->isDupAllowed = other.isDupAllowed; 1.1324 + for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) { 1.1325 + PtnElem *curElem, *otherElem, *prevElem=NULL; 1.1326 + otherElem = other.boot[bootIndex]; 1.1327 + while (otherElem!=NULL) { 1.1328 + if ((curElem = new PtnElem(otherElem->basePattern, otherElem->pattern))==NULL) { 1.1329 + // out of memory 1.1330 + status = U_MEMORY_ALLOCATION_ERROR; 1.1331 + return; 1.1332 + } 1.1333 + if ( this->boot[bootIndex]== NULL ) { 1.1334 + this->boot[bootIndex] = curElem; 1.1335 + } 1.1336 + if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) { 1.1337 + // out of memory 1.1338 + status = U_MEMORY_ALLOCATION_ERROR; 1.1339 + return; 1.1340 + } 1.1341 + 1.1342 + if (prevElem!=NULL) { 1.1343 + prevElem->next=curElem; 1.1344 + } 1.1345 + curElem->next=NULL; 1.1346 + prevElem = curElem; 1.1347 + otherElem = otherElem->next; 1.1348 + } 1.1349 + 1.1350 + } 1.1351 +} 1.1352 + 1.1353 +PtnElem* 1.1354 +PatternMap::getHeader(UChar baseChar) { 1.1355 + PtnElem* curElem; 1.1356 + 1.1357 + if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) { 1.1358 + curElem = boot[baseChar-CAP_A]; 1.1359 + } 1.1360 + else { 1.1361 + if ( (baseChar >=LOW_A) && (baseChar <= LOW_Z) ) { 1.1362 + curElem = boot[26+baseChar-LOW_A]; 1.1363 + } 1.1364 + else { 1.1365 + return NULL; 1.1366 + } 1.1367 + } 1.1368 + return curElem; 1.1369 +} 1.1370 + 1.1371 +PatternMap::~PatternMap() { 1.1372 + for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { 1.1373 + if (boot[i]!=NULL ) { 1.1374 + delete boot[i]; 1.1375 + boot[i]=NULL; 1.1376 + } 1.1377 + } 1.1378 +} // PatternMap destructor 1.1379 + 1.1380 +void 1.1381 +PatternMap::add(const UnicodeString& basePattern, 1.1382 + const PtnSkeleton& skeleton, 1.1383 + const UnicodeString& value,// mapped pattern value 1.1384 + UBool skeletonWasSpecified, 1.1385 + UErrorCode &status) { 1.1386 + UChar baseChar = basePattern.charAt(0); 1.1387 + PtnElem *curElem, *baseElem; 1.1388 + status = U_ZERO_ERROR; 1.1389 + 1.1390 + // the baseChar must be A-Z or a-z 1.1391 + if ((baseChar >= CAP_A) && (baseChar <= CAP_Z)) { 1.1392 + baseElem = boot[baseChar-CAP_A]; 1.1393 + } 1.1394 + else { 1.1395 + if ((baseChar >=LOW_A) && (baseChar <= LOW_Z)) { 1.1396 + baseElem = boot[26+baseChar-LOW_A]; 1.1397 + } 1.1398 + else { 1.1399 + status = U_ILLEGAL_CHARACTER; 1.1400 + return; 1.1401 + } 1.1402 + } 1.1403 + 1.1404 + if (baseElem == NULL) { 1.1405 + if ((curElem = new PtnElem(basePattern, value)) == NULL ) { 1.1406 + // out of memory 1.1407 + status = U_MEMORY_ALLOCATION_ERROR; 1.1408 + return; 1.1409 + } 1.1410 + if (baseChar >= LOW_A) { 1.1411 + boot[26 + (baseChar-LOW_A)] = curElem; 1.1412 + } 1.1413 + else { 1.1414 + boot[baseChar-CAP_A] = curElem; 1.1415 + } 1.1416 + curElem->skeleton = new PtnSkeleton(skeleton); 1.1417 + curElem->skeletonWasSpecified = skeletonWasSpecified; 1.1418 + } 1.1419 + if ( baseElem != NULL ) { 1.1420 + curElem = getDuplicateElem(basePattern, skeleton, baseElem); 1.1421 + 1.1422 + if (curElem == NULL) { 1.1423 + // add new element to the list. 1.1424 + curElem = baseElem; 1.1425 + while( curElem -> next != NULL ) 1.1426 + { 1.1427 + curElem = curElem->next; 1.1428 + } 1.1429 + if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) { 1.1430 + // out of memory 1.1431 + status = U_MEMORY_ALLOCATION_ERROR; 1.1432 + return; 1.1433 + } 1.1434 + curElem=curElem->next; 1.1435 + curElem->skeleton = new PtnSkeleton(skeleton); 1.1436 + curElem->skeletonWasSpecified = skeletonWasSpecified; 1.1437 + } 1.1438 + else { 1.1439 + // Pattern exists in the list already. 1.1440 + if ( !isDupAllowed ) { 1.1441 + return; 1.1442 + } 1.1443 + // Overwrite the value. 1.1444 + curElem->pattern = value; 1.1445 + // It was a bug that we were not doing the following previously, 1.1446 + // though that bug hid other problems by making things partly work. 1.1447 + curElem->skeletonWasSpecified = skeletonWasSpecified; 1.1448 + } 1.1449 + } 1.1450 +} // PatternMap::add 1.1451 + 1.1452 +// Find the pattern from the given basePattern string. 1.1453 +const UnicodeString * 1.1454 +PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified) { // key to search for 1.1455 + PtnElem *curElem; 1.1456 + 1.1457 + if ((curElem=getHeader(basePattern.charAt(0)))==NULL) { 1.1458 + return NULL; // no match 1.1459 + } 1.1460 + 1.1461 + do { 1.1462 + if ( basePattern.compare(curElem->basePattern)==0 ) { 1.1463 + skeletonWasSpecified = curElem->skeletonWasSpecified; 1.1464 + return &(curElem->pattern); 1.1465 + } 1.1466 + curElem=curElem->next; 1.1467 + }while (curElem != NULL); 1.1468 + 1.1469 + return NULL; 1.1470 +} // PatternMap::getFromBasePattern 1.1471 + 1.1472 + 1.1473 +// Find the pattern from the given skeleton. 1.1474 +// At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL), 1.1475 +// the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw) 1.1476 +// and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the 1.1477 +// optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL), 1.1478 +// for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily. 1.1479 +const UnicodeString * 1.1480 +PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) { // key to search for 1.1481 + PtnElem *curElem; 1.1482 + 1.1483 + if (specifiedSkeletonPtr) { 1.1484 + *specifiedSkeletonPtr = NULL; 1.1485 + } 1.1486 + 1.1487 + // find boot entry 1.1488 + UChar baseChar='\0'; 1.1489 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1490 + if (skeleton.baseOriginal[i].length() !=0 ) { 1.1491 + baseChar = skeleton.baseOriginal[i].charAt(0); 1.1492 + break; 1.1493 + } 1.1494 + } 1.1495 + 1.1496 + if ((curElem=getHeader(baseChar))==NULL) { 1.1497 + return NULL; // no match 1.1498 + } 1.1499 + 1.1500 + do { 1.1501 + int32_t i=0; 1.1502 + if (specifiedSkeletonPtr != NULL) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original 1.1503 + for (i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1504 + if (curElem->skeleton->original[i].compare(skeleton.original[i]) != 0 ) 1.1505 + { 1.1506 + break; 1.1507 + } 1.1508 + } 1.1509 + } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal 1.1510 + for (i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1511 + if (curElem->skeleton->baseOriginal[i].compare(skeleton.baseOriginal[i]) != 0 ) 1.1512 + { 1.1513 + break; 1.1514 + } 1.1515 + } 1.1516 + } 1.1517 + if (i == UDATPG_FIELD_COUNT) { 1.1518 + if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) { 1.1519 + *specifiedSkeletonPtr = curElem->skeleton; 1.1520 + } 1.1521 + return &(curElem->pattern); 1.1522 + } 1.1523 + curElem=curElem->next; 1.1524 + }while (curElem != NULL); 1.1525 + 1.1526 + return NULL; 1.1527 +} 1.1528 + 1.1529 +UBool 1.1530 +PatternMap::equals(const PatternMap& other) { 1.1531 + if ( this==&other ) { 1.1532 + return TRUE; 1.1533 + } 1.1534 + for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) { 1.1535 + if ( boot[bootIndex]==other.boot[bootIndex] ) { 1.1536 + continue; 1.1537 + } 1.1538 + if ( (boot[bootIndex]==NULL)||(other.boot[bootIndex]==NULL) ) { 1.1539 + return FALSE; 1.1540 + } 1.1541 + PtnElem *otherElem = other.boot[bootIndex]; 1.1542 + PtnElem *myElem = boot[bootIndex]; 1.1543 + while ((otherElem!=NULL) || (myElem!=NULL)) { 1.1544 + if ( myElem == otherElem ) { 1.1545 + break; 1.1546 + } 1.1547 + if ((otherElem==NULL) || (myElem==NULL)) { 1.1548 + return FALSE; 1.1549 + } 1.1550 + if ( (myElem->basePattern != otherElem->basePattern) || 1.1551 + (myElem->pattern != otherElem->pattern) ) { 1.1552 + return FALSE; 1.1553 + } 1.1554 + if ((myElem->skeleton!=otherElem->skeleton)&& 1.1555 + !myElem->skeleton->equals(*(otherElem->skeleton))) { 1.1556 + return FALSE; 1.1557 + } 1.1558 + myElem = myElem->next; 1.1559 + otherElem=otherElem->next; 1.1560 + } 1.1561 + } 1.1562 + return TRUE; 1.1563 +} 1.1564 + 1.1565 +// find any key existing in the mapping table already. 1.1566 +// return TRUE if there is an existing key, otherwise return FALSE. 1.1567 +PtnElem* 1.1568 +PatternMap::getDuplicateElem( 1.1569 + const UnicodeString &basePattern, 1.1570 + const PtnSkeleton &skeleton, 1.1571 + PtnElem *baseElem) { 1.1572 + PtnElem *curElem; 1.1573 + 1.1574 + if ( baseElem == (PtnElem *)NULL ) { 1.1575 + return (PtnElem*)NULL; 1.1576 + } 1.1577 + else { 1.1578 + curElem = baseElem; 1.1579 + } 1.1580 + do { 1.1581 + if ( basePattern.compare(curElem->basePattern)==0 ) { 1.1582 + UBool isEqual=TRUE; 1.1583 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1584 + if (curElem->skeleton->type[i] != skeleton.type[i] ) { 1.1585 + isEqual=FALSE; 1.1586 + break; 1.1587 + } 1.1588 + } 1.1589 + if (isEqual) { 1.1590 + return curElem; 1.1591 + } 1.1592 + } 1.1593 + curElem = curElem->next; 1.1594 + } while( curElem != (PtnElem *)NULL ); 1.1595 + 1.1596 + // end of the list 1.1597 + return (PtnElem*)NULL; 1.1598 + 1.1599 +} // PatternMap::getDuplicateElem 1.1600 + 1.1601 +DateTimeMatcher::DateTimeMatcher(void) { 1.1602 +} 1.1603 + 1.1604 +DateTimeMatcher::~DateTimeMatcher() {} 1.1605 + 1.1606 +DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) { 1.1607 + copyFrom(other.skeleton); 1.1608 +} 1.1609 + 1.1610 + 1.1611 +void 1.1612 +DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) { 1.1613 + PtnSkeleton localSkeleton; 1.1614 + return set(pattern, fp, localSkeleton); 1.1615 +} 1.1616 + 1.1617 +void 1.1618 +DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeletonResult) { 1.1619 + int32_t i; 1.1620 + for (i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1621 + skeletonResult.type[i]=NONE; 1.1622 + } 1.1623 + fp->set(pattern); 1.1624 + for (i=0; i < fp->itemNumber; i++) { 1.1625 + UnicodeString field = fp->items[i]; 1.1626 + if ( field.charAt(0) == LOW_A ) { 1.1627 + continue; // skip 'a' 1.1628 + } 1.1629 + 1.1630 + if ( fp->isQuoteLiteral(field) ) { 1.1631 + UnicodeString quoteLiteral; 1.1632 + fp->getQuoteLiteral(quoteLiteral, &i); 1.1633 + continue; 1.1634 + } 1.1635 + int32_t canonicalIndex = fp->getCanonicalIndex(field); 1.1636 + if (canonicalIndex < 0 ) { 1.1637 + continue; 1.1638 + } 1.1639 + const dtTypeElem *row = &dtTypes[canonicalIndex]; 1.1640 + int32_t typeValue = row->field; 1.1641 + skeletonResult.original[typeValue]=field; 1.1642 + UChar repeatChar = row->patternChar; 1.1643 + int32_t repeatCount = row->minLen; // #7930 removes cap at 3 1.1644 + while (repeatCount-- > 0) { 1.1645 + skeletonResult.baseOriginal[typeValue] += repeatChar; 1.1646 + } 1.1647 + int16_t subTypeValue = row->type; 1.1648 + if ( row->type > 0) { 1.1649 + subTypeValue += field.length(); 1.1650 + } 1.1651 + skeletonResult.type[typeValue] = subTypeValue; 1.1652 + } 1.1653 + copyFrom(skeletonResult); 1.1654 +} 1.1655 + 1.1656 +void 1.1657 +DateTimeMatcher::getBasePattern(UnicodeString &result ) { 1.1658 + result.remove(); // Reset the result first. 1.1659 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1.1660 + if (skeleton.baseOriginal[i].length()!=0) { 1.1661 + result += skeleton.baseOriginal[i]; 1.1662 + } 1.1663 + } 1.1664 +} 1.1665 + 1.1666 +UnicodeString 1.1667 +DateTimeMatcher::getPattern() { 1.1668 + UnicodeString result; 1.1669 + 1.1670 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1.1671 + if (skeleton.original[i].length()!=0) { 1.1672 + result += skeleton.original[i]; 1.1673 + } 1.1674 + } 1.1675 + return result; 1.1676 +} 1.1677 + 1.1678 +int32_t 1.1679 +DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) { 1.1680 + int32_t result=0; 1.1681 + distanceInfo.clear(); 1.1682 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1.1683 + int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i]; 1.1684 + int32_t otherType = other.skeleton.type[i]; 1.1685 + if (myType==otherType) { 1.1686 + continue; 1.1687 + } 1.1688 + if (myType==0) {// and other is not 1.1689 + result += EXTRA_FIELD; 1.1690 + distanceInfo.addExtra(i); 1.1691 + } 1.1692 + else { 1.1693 + if (otherType==0) { 1.1694 + result += MISSING_FIELD; 1.1695 + distanceInfo.addMissing(i); 1.1696 + } 1.1697 + else { 1.1698 + result += abs(myType - otherType); 1.1699 + } 1.1700 + } 1.1701 + 1.1702 + } 1.1703 + return result; 1.1704 +} 1.1705 + 1.1706 +void 1.1707 +DateTimeMatcher::copyFrom(const PtnSkeleton& newSkeleton) { 1.1708 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1709 + this->skeleton.type[i]=newSkeleton.type[i]; 1.1710 + this->skeleton.original[i]=newSkeleton.original[i]; 1.1711 + this->skeleton.baseOriginal[i]=newSkeleton.baseOriginal[i]; 1.1712 + } 1.1713 +} 1.1714 + 1.1715 +void 1.1716 +DateTimeMatcher::copyFrom() { 1.1717 + // same as clear 1.1718 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1719 + this->skeleton.type[i]=0; 1.1720 + this->skeleton.original[i].remove(); 1.1721 + this->skeleton.baseOriginal[i].remove(); 1.1722 + } 1.1723 +} 1.1724 + 1.1725 +UBool 1.1726 +DateTimeMatcher::equals(const DateTimeMatcher* other) const { 1.1727 + if (other==NULL) { 1.1728 + return FALSE; 1.1729 + } 1.1730 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1731 + if (this->skeleton.original[i]!=other->skeleton.original[i] ) { 1.1732 + return FALSE; 1.1733 + } 1.1734 + } 1.1735 + return TRUE; 1.1736 +} 1.1737 + 1.1738 +int32_t 1.1739 +DateTimeMatcher::getFieldMask() { 1.1740 + int32_t result=0; 1.1741 + 1.1742 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.1743 + if (skeleton.type[i]!=0) { 1.1744 + result |= (1<<i); 1.1745 + } 1.1746 + } 1.1747 + return result; 1.1748 +} 1.1749 + 1.1750 +PtnSkeleton* 1.1751 +DateTimeMatcher::getSkeletonPtr() { 1.1752 + return &skeleton; 1.1753 +} 1.1754 + 1.1755 +FormatParser::FormatParser () { 1.1756 + status = START; 1.1757 + itemNumber=0; 1.1758 +} 1.1759 + 1.1760 + 1.1761 +FormatParser::~FormatParser () { 1.1762 +} 1.1763 + 1.1764 + 1.1765 +// Find the next token with the starting position and length 1.1766 +// Note: the startPos may 1.1767 +FormatParser::TokenStatus 1.1768 +FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) { 1.1769 + int32_t curLoc = startPos; 1.1770 + if ( curLoc >= pattern.length()) { 1.1771 + return DONE; 1.1772 + } 1.1773 + // check the current char is between A-Z or a-z 1.1774 + do { 1.1775 + UChar c=pattern.charAt(curLoc); 1.1776 + if ( (c>=CAP_A && c<=CAP_Z) || (c>=LOW_A && c<=LOW_Z) ) { 1.1777 + curLoc++; 1.1778 + } 1.1779 + else { 1.1780 + startPos = curLoc; 1.1781 + *len=1; 1.1782 + return ADD_TOKEN; 1.1783 + } 1.1784 + 1.1785 + if ( pattern.charAt(curLoc)!= pattern.charAt(startPos) ) { 1.1786 + break; // not the same token 1.1787 + } 1.1788 + } while(curLoc <= pattern.length()); 1.1789 + *len = curLoc-startPos; 1.1790 + return ADD_TOKEN; 1.1791 +} 1.1792 + 1.1793 +void 1.1794 +FormatParser::set(const UnicodeString& pattern) { 1.1795 + int32_t startPos=0; 1.1796 + TokenStatus result=START; 1.1797 + int32_t len=0; 1.1798 + itemNumber =0; 1.1799 + 1.1800 + do { 1.1801 + result = setTokens( pattern, startPos, &len ); 1.1802 + if ( result == ADD_TOKEN ) 1.1803 + { 1.1804 + items[itemNumber++] = UnicodeString(pattern, startPos, len ); 1.1805 + startPos += len; 1.1806 + } 1.1807 + else { 1.1808 + break; 1.1809 + } 1.1810 + } while (result==ADD_TOKEN && itemNumber < MAX_DT_TOKEN); 1.1811 +} 1.1812 + 1.1813 +int32_t 1.1814 +FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) { 1.1815 + int32_t len = s.length(); 1.1816 + if (len == 0) { 1.1817 + return -1; 1.1818 + } 1.1819 + UChar ch = s.charAt(0); 1.1820 + 1.1821 + // Verify that all are the same character. 1.1822 + for (int32_t l = 1; l < len; l++) { 1.1823 + if (ch != s.charAt(l)) { 1.1824 + return -1; 1.1825 + } 1.1826 + } 1.1827 + int32_t i = 0; 1.1828 + int32_t bestRow = -1; 1.1829 + while (dtTypes[i].patternChar != '\0') { 1.1830 + if ( dtTypes[i].patternChar != ch ) { 1.1831 + ++i; 1.1832 + continue; 1.1833 + } 1.1834 + bestRow = i; 1.1835 + if (dtTypes[i].patternChar != dtTypes[i+1].patternChar) { 1.1836 + return i; 1.1837 + } 1.1838 + if (dtTypes[i+1].minLen <= len) { 1.1839 + ++i; 1.1840 + continue; 1.1841 + } 1.1842 + return i; 1.1843 + } 1.1844 + return strict ? -1 : bestRow; 1.1845 +} 1.1846 + 1.1847 +UBool 1.1848 +FormatParser::isQuoteLiteral(const UnicodeString& s) const { 1.1849 + return (UBool)(s.charAt(0)==SINGLE_QUOTE); 1.1850 +} 1.1851 + 1.1852 +// This function aussumes the current itemIndex points to the quote literal. 1.1853 +// Please call isQuoteLiteral prior to this function. 1.1854 +void 1.1855 +FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) { 1.1856 + int32_t i=*itemIndex; 1.1857 + 1.1858 + quote.remove(); 1.1859 + if (items[i].charAt(0)==SINGLE_QUOTE) { 1.1860 + quote += items[i]; 1.1861 + ++i; 1.1862 + } 1.1863 + while ( i < itemNumber ) { 1.1864 + if ( items[i].charAt(0)==SINGLE_QUOTE ) { 1.1865 + if ( (i+1<itemNumber) && (items[i+1].charAt(0)==SINGLE_QUOTE)) { 1.1866 + // two single quotes e.g. 'o''clock' 1.1867 + quote += items[i++]; 1.1868 + quote += items[i++]; 1.1869 + continue; 1.1870 + } 1.1871 + else { 1.1872 + quote += items[i]; 1.1873 + break; 1.1874 + } 1.1875 + } 1.1876 + else { 1.1877 + quote += items[i]; 1.1878 + } 1.1879 + ++i; 1.1880 + } 1.1881 + *itemIndex=i; 1.1882 +} 1.1883 + 1.1884 +UBool 1.1885 +FormatParser::isPatternSeparator(UnicodeString& field) { 1.1886 + for (int32_t i=0; i<field.length(); ++i ) { 1.1887 + UChar c= field.charAt(i); 1.1888 + if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) || 1.1889 + (c==QUOTATION_MARK) || (c==COMMA) || (c==HYPHEN) ||(items[i].charAt(0)==DOT) ) { 1.1890 + continue; 1.1891 + } 1.1892 + else { 1.1893 + return FALSE; 1.1894 + } 1.1895 + } 1.1896 + return TRUE; 1.1897 +} 1.1898 + 1.1899 +DistanceInfo::~DistanceInfo() {} 1.1900 + 1.1901 +void 1.1902 +DistanceInfo::setTo(DistanceInfo &other) { 1.1903 + missingFieldMask = other.missingFieldMask; 1.1904 + extraFieldMask= other.extraFieldMask; 1.1905 +} 1.1906 + 1.1907 +PatternMapIterator::PatternMapIterator() { 1.1908 + bootIndex = 0; 1.1909 + nodePtr = NULL; 1.1910 + patternMap=NULL; 1.1911 + matcher= new DateTimeMatcher(); 1.1912 +} 1.1913 + 1.1914 + 1.1915 +PatternMapIterator::~PatternMapIterator() { 1.1916 + delete matcher; 1.1917 +} 1.1918 + 1.1919 +void 1.1920 +PatternMapIterator::set(PatternMap& newPatternMap) { 1.1921 + this->patternMap=&newPatternMap; 1.1922 +} 1.1923 + 1.1924 +PtnSkeleton* 1.1925 +PatternMapIterator::getSkeleton() { 1.1926 + if ( nodePtr == NULL ) { 1.1927 + return NULL; 1.1928 + } 1.1929 + else { 1.1930 + return nodePtr->skeleton; 1.1931 + } 1.1932 +} 1.1933 + 1.1934 +UBool 1.1935 +PatternMapIterator::hasNext() { 1.1936 + int32_t headIndex=bootIndex; 1.1937 + PtnElem *curPtr=nodePtr; 1.1938 + 1.1939 + if (patternMap==NULL) { 1.1940 + return FALSE; 1.1941 + } 1.1942 + while ( headIndex < MAX_PATTERN_ENTRIES ) { 1.1943 + if ( curPtr != NULL ) { 1.1944 + if ( curPtr->next != NULL ) { 1.1945 + return TRUE; 1.1946 + } 1.1947 + else { 1.1948 + headIndex++; 1.1949 + curPtr=NULL; 1.1950 + continue; 1.1951 + } 1.1952 + } 1.1953 + else { 1.1954 + if ( patternMap->boot[headIndex] != NULL ) { 1.1955 + return TRUE; 1.1956 + } 1.1957 + else { 1.1958 + headIndex++; 1.1959 + continue; 1.1960 + } 1.1961 + } 1.1962 + 1.1963 + } 1.1964 + return FALSE; 1.1965 +} 1.1966 + 1.1967 +DateTimeMatcher& 1.1968 +PatternMapIterator::next() { 1.1969 + while ( bootIndex < MAX_PATTERN_ENTRIES ) { 1.1970 + if ( nodePtr != NULL ) { 1.1971 + if ( nodePtr->next != NULL ) { 1.1972 + nodePtr = nodePtr->next; 1.1973 + break; 1.1974 + } 1.1975 + else { 1.1976 + bootIndex++; 1.1977 + nodePtr=NULL; 1.1978 + continue; 1.1979 + } 1.1980 + } 1.1981 + else { 1.1982 + if ( patternMap->boot[bootIndex] != NULL ) { 1.1983 + nodePtr = patternMap->boot[bootIndex]; 1.1984 + break; 1.1985 + } 1.1986 + else { 1.1987 + bootIndex++; 1.1988 + continue; 1.1989 + } 1.1990 + } 1.1991 + } 1.1992 + if (nodePtr!=NULL) { 1.1993 + matcher->copyFrom(*nodePtr->skeleton); 1.1994 + } 1.1995 + else { 1.1996 + matcher->copyFrom(); 1.1997 + } 1.1998 + return *matcher; 1.1999 +} 1.2000 + 1.2001 +PtnSkeleton::PtnSkeleton() { 1.2002 +} 1.2003 + 1.2004 + 1.2005 +PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) { 1.2006 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.2007 + this->type[i]=other.type[i]; 1.2008 + this->original[i]=other.original[i]; 1.2009 + this->baseOriginal[i]=other.baseOriginal[i]; 1.2010 + } 1.2011 +} 1.2012 + 1.2013 +UBool 1.2014 +PtnSkeleton::equals(const PtnSkeleton& other) { 1.2015 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.2016 + if ( (type[i]!= other.type[i]) || 1.2017 + (original[i]!=other.original[i]) || 1.2018 + (baseOriginal[i]!=other.baseOriginal[i]) ) { 1.2019 + return FALSE; 1.2020 + } 1.2021 + } 1.2022 + return TRUE; 1.2023 +} 1.2024 + 1.2025 +UnicodeString 1.2026 +PtnSkeleton::getSkeleton() { 1.2027 + UnicodeString result; 1.2028 + 1.2029 + for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) { 1.2030 + if (original[i].length()!=0) { 1.2031 + result += original[i]; 1.2032 + } 1.2033 + } 1.2034 + return result; 1.2035 +} 1.2036 + 1.2037 +UnicodeString 1.2038 +PtnSkeleton::getBaseSkeleton() { 1.2039 + UnicodeString result; 1.2040 + 1.2041 + for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) { 1.2042 + if (baseOriginal[i].length()!=0) { 1.2043 + result += baseOriginal[i]; 1.2044 + } 1.2045 + } 1.2046 + return result; 1.2047 +} 1.2048 + 1.2049 +PtnSkeleton::~PtnSkeleton() { 1.2050 +} 1.2051 + 1.2052 +PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) : 1.2053 +basePattern(basePat), 1.2054 +skeleton(NULL), 1.2055 +pattern(pat), 1.2056 +next(NULL) 1.2057 +{ 1.2058 +} 1.2059 + 1.2060 +PtnElem::~PtnElem() { 1.2061 + 1.2062 + if (next!=NULL) { 1.2063 + delete next; 1.2064 + } 1.2065 + delete skeleton; 1.2066 +} 1.2067 + 1.2068 +DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) { 1.2069 + PtnElem *curElem; 1.2070 + PtnSkeleton *curSkeleton; 1.2071 + UnicodeString s; 1.2072 + int32_t bootIndex; 1.2073 + 1.2074 + pos=0; 1.2075 + fSkeletons = new UVector(status); 1.2076 + if (U_FAILURE(status)) { 1.2077 + delete fSkeletons; 1.2078 + return; 1.2079 + } 1.2080 + for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) { 1.2081 + curElem = patternMap.boot[bootIndex]; 1.2082 + while (curElem!=NULL) { 1.2083 + switch(type) { 1.2084 + case DT_BASESKELETON: 1.2085 + s=curElem->basePattern; 1.2086 + break; 1.2087 + case DT_PATTERN: 1.2088 + s=curElem->pattern; 1.2089 + break; 1.2090 + case DT_SKELETON: 1.2091 + curSkeleton=curElem->skeleton; 1.2092 + s=curSkeleton->getSkeleton(); 1.2093 + break; 1.2094 + } 1.2095 + if ( !isCanonicalItem(s) ) { 1.2096 + fSkeletons->addElement(new UnicodeString(s), status); 1.2097 + if (U_FAILURE(status)) { 1.2098 + delete fSkeletons; 1.2099 + fSkeletons = NULL; 1.2100 + return; 1.2101 + } 1.2102 + } 1.2103 + curElem = curElem->next; 1.2104 + } 1.2105 + } 1.2106 + if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) { 1.2107 + status = U_BUFFER_OVERFLOW_ERROR; 1.2108 + } 1.2109 +} 1.2110 + 1.2111 +const UnicodeString* 1.2112 +DTSkeletonEnumeration::snext(UErrorCode& status) { 1.2113 + if (U_SUCCESS(status) && pos < fSkeletons->size()) { 1.2114 + return (const UnicodeString*)fSkeletons->elementAt(pos++); 1.2115 + } 1.2116 + return NULL; 1.2117 +} 1.2118 + 1.2119 +void 1.2120 +DTSkeletonEnumeration::reset(UErrorCode& /*status*/) { 1.2121 + pos=0; 1.2122 +} 1.2123 + 1.2124 +int32_t 1.2125 +DTSkeletonEnumeration::count(UErrorCode& /*status*/) const { 1.2126 + return (fSkeletons==NULL) ? 0 : fSkeletons->size(); 1.2127 +} 1.2128 + 1.2129 +UBool 1.2130 +DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) { 1.2131 + if ( item.length() != 1 ) { 1.2132 + return FALSE; 1.2133 + } 1.2134 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.2135 + if (item.charAt(0)==Canonical_Items[i]) { 1.2136 + return TRUE; 1.2137 + } 1.2138 + } 1.2139 + return FALSE; 1.2140 +} 1.2141 + 1.2142 +DTSkeletonEnumeration::~DTSkeletonEnumeration() { 1.2143 + UnicodeString *s; 1.2144 + for (int32_t i=0; i<fSkeletons->size(); ++i) { 1.2145 + if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) { 1.2146 + delete s; 1.2147 + } 1.2148 + } 1.2149 + delete fSkeletons; 1.2150 +} 1.2151 + 1.2152 +DTRedundantEnumeration::DTRedundantEnumeration() { 1.2153 + pos=0; 1.2154 + fPatterns = NULL; 1.2155 +} 1.2156 + 1.2157 +void 1.2158 +DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) { 1.2159 + if (U_FAILURE(status)) return; 1.2160 + if (fPatterns == NULL) { 1.2161 + fPatterns = new UVector(status); 1.2162 + if (U_FAILURE(status)) { 1.2163 + delete fPatterns; 1.2164 + fPatterns = NULL; 1.2165 + return; 1.2166 + } 1.2167 + } 1.2168 + fPatterns->addElement(new UnicodeString(pattern), status); 1.2169 + if (U_FAILURE(status)) { 1.2170 + delete fPatterns; 1.2171 + fPatterns = NULL; 1.2172 + return; 1.2173 + } 1.2174 +} 1.2175 + 1.2176 +const UnicodeString* 1.2177 +DTRedundantEnumeration::snext(UErrorCode& status) { 1.2178 + if (U_SUCCESS(status) && pos < fPatterns->size()) { 1.2179 + return (const UnicodeString*)fPatterns->elementAt(pos++); 1.2180 + } 1.2181 + return NULL; 1.2182 +} 1.2183 + 1.2184 +void 1.2185 +DTRedundantEnumeration::reset(UErrorCode& /*status*/) { 1.2186 + pos=0; 1.2187 +} 1.2188 + 1.2189 +int32_t 1.2190 +DTRedundantEnumeration::count(UErrorCode& /*status*/) const { 1.2191 + return (fPatterns==NULL) ? 0 : fPatterns->size(); 1.2192 +} 1.2193 + 1.2194 +UBool 1.2195 +DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) { 1.2196 + if ( item.length() != 1 ) { 1.2197 + return FALSE; 1.2198 + } 1.2199 + for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1.2200 + if (item.charAt(0)==Canonical_Items[i]) { 1.2201 + return TRUE; 1.2202 + } 1.2203 + } 1.2204 + return FALSE; 1.2205 +} 1.2206 + 1.2207 +DTRedundantEnumeration::~DTRedundantEnumeration() { 1.2208 + UnicodeString *s; 1.2209 + for (int32_t i=0; i<fPatterns->size(); ++i) { 1.2210 + if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) { 1.2211 + delete s; 1.2212 + } 1.2213 + } 1.2214 + delete fPatterns; 1.2215 +} 1.2216 + 1.2217 +U_NAMESPACE_END 1.2218 + 1.2219 + 1.2220 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.2221 + 1.2222 +//eof