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