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