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 55struct UResAEntry { 56 UChar *key; 57 UResourceBundle *item; 58}; 59 60struct 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 69U_CDECL_BEGIN 70 71static int32_t U_CALLCONV 72ures_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 78U_CDECL_END 79 80static 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 102static 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 111static 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 128U_NAMESPACE_BEGIN 129 130 131// ***************************************************************************** 132// class DateTimePatternGenerator 133// ***************************************************************************** 134static 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 140static 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 212static const char* const CLDR_FIELD_APPEND[] = { 213 "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*", 214 "Hour", "Minute", "Second", "*", "Timezone" 215}; 216 217static const char* const CLDR_FIELD_NAME[] = { 218 "era", "year", "quarter", "month", "week", "*", "weekday", "*", "*", "day", "dayperiod", 219 "hour", "minute", "second", "*", "zone" 220}; 221 222static const char* const Resource_Fields[] = { 223 "day", "dayperiod", "era", "hour", "minute", "month", "second", "week", 224 "weekday", "year", "zone", "quarter" }; 225 226// For appendItems 227static 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 232static const char DT_DateTimePatternsTag[]="DateTimePatterns"; 233static const char DT_DateTimeCalendarTag[]="calendar"; 234static const char DT_DateTimeGregorianTag[]="gregorian"; 235static const char DT_DateTimeAppendItemsTag[]="appendItems"; 236static const char DT_DateTimeFieldsTag[]="fields"; 237static const char DT_DateTimeAvailableFormatsTag[]="availableFormats"; 238//static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns); 239 240UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator) 241UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration) 242UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration) 243 244DateTimePatternGenerator* U_EXPORT2 245DateTimePatternGenerator::createInstance(UErrorCode& status) { 246 return createInstance(Locale::getDefault(), status); 247} 248 249DateTimePatternGenerator* U_EXPORT2 250DateTimePatternGenerator::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 262DateTimePatternGenerator* U_EXPORT2 263DateTimePatternGenerator::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 275DateTimePatternGenerator::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 288DateTimePatternGenerator::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 304DateTimePatternGenerator::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 316DateTimePatternGenerator& 317DateTimePatternGenerator::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 349UBool 350DateTimePatternGenerator::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 369UBool 370DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) const { 371 return !operator==(other); 372} 373 374DateTimePatternGenerator::~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 386void 387DateTimePatternGenerator::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 402UnicodeString 403DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode& 404/*status*/) { 405 dtMatcher->set(pattern, fp); 406 return dtMatcher->getSkeletonPtr()->getSkeleton(); 407} 408 409UnicodeString 410DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) { 411 dtMatcher->set(pattern, fp); 412 return dtMatcher->getSkeletonPtr()->getBaseSkeleton(); 413} 414 415void 416DateTimePatternGenerator::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 455void 456DateTimePatternGenerator::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 503static const UChar hourFormatChars[] = { CAP_H, LOW_H, CAP_K, LOW_K, 0 }; // HhKk, the hour format characters 504 505void 506DateTimePatternGenerator::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 723void 724DateTimePatternGenerator::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 735void 736DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value) { 737 appendItemFormats[field] = value; 738 // NUL-terminate for the C API. 739 appendItemFormats[field].getTerminatedBuffer(); 740} 741 742const UnicodeString& 743DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const { 744 return appendItemFormats[field]; 745} 746 747void 748DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) { 749 appendItemNames[field] = value; 750 // NUL-terminate for the C API. 751 appendItemNames[field].getTerminatedBuffer(); 752} 753 754const UnicodeString& 755DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field) const { 756 return appendItemNames[field]; 757} 758 759void 760DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) { 761 value = SINGLE_QUOTE; 762 value += appendItemNames[field]; 763 value += SINGLE_QUOTE; 764} 765 766UnicodeString 767DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErrorCode& status) { 768 return getBestPattern(patternForm, UDATPG_MATCH_NO_OPTIONS, status); 769} 770 771UnicodeString 772DateTimePatternGenerator::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 UChar hourFormatSkeletonCharForLowJ = fDefaultHourFormatChar; 784 switch (options & UADATPG_FORCE_HOUR_CYCLE_MASK) { 785 case UADATPG_FORCE_12_HOUR_CYCLE: hourFormatSkeletonCharForLowJ = LOW_H; break; 786 case UADATPG_FORCE_24_HOUR_CYCLE: hourFormatSkeletonCharForLowJ = CAP_H; break; 787 default: break; 788 } 789 int32_t patPos, patLen = patternFormCopy.length(); 790 UBool inQuoted = FALSE; 791 for (patPos = 0; patPos < patLen; patPos++) { 792 UChar patChr = patternFormCopy.charAt(patPos); 793 if (patChr == SINGLE_QUOTE) { 794 inQuoted = !inQuoted; 795 } else if (!inQuoted) { 796 if (patChr == LOW_J) { 797 patternFormCopy.setCharAt(patPos, hourFormatSkeletonCharForLowJ); 798 } else if (patChr == CAP_J) { 799 // Get pattern for skeleton with H, then in adjustFieldTypes 800 // replace hour pattern characters as necessary. 801 patternFormCopy.setCharAt(patPos, CAP_H); 802 flags |= kDTPGSkeletonUsesCapJ; 803 } 804 } 805 } 806 807 resultPattern.remove(); 808 dtMatcher->set(patternFormCopy, fp); 809 const PtnSkeleton* specifiedSkeleton=NULL; 810 bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, &specifiedSkeleton); 811 if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) { 812 resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, flags, options); 813 814 return resultPattern; 815 } 816 int32_t neededFields = dtMatcher->getFieldMask(); 817 UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, options); 818 UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, options); 819 if (datePattern.length()==0) { 820 if (timePattern.length()==0) { 821 resultPattern.remove(); 822 } 823 else { 824 return timePattern; 825 } 826 } 827 if (timePattern.length()==0) { 828 return datePattern; 829 } 830 resultPattern.remove(); 831 status = U_ZERO_ERROR; 832 dtFormat=getDateTimeFormat(); 833 Formattable dateTimeObject[] = { timePattern, datePattern }; 834 resultPattern = MessageFormat::format(dtFormat, dateTimeObject, 2, resultPattern, status ); 835 return resultPattern; 836} 837 838UnicodeString 839DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern, 840 const UnicodeString& skeleton, 841 UErrorCode& status) { 842 return replaceFieldTypes(pattern, skeleton, UDATPG_MATCH_NO_OPTIONS, status); 843} 844 845UnicodeString 846DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern, 847 const UnicodeString& skeleton, 848 UDateTimePatternMatchOptions options, 849 UErrorCode& /*status*/) { 850 dtMatcher->set(skeleton, fp); 851 UnicodeString result = adjustFieldTypes(pattern, NULL, kDTPGNoFlags, options); 852 return result; 853} 854 855void 856DateTimePatternGenerator::setDecimal(const UnicodeString& newDecimal) { 857 this->decimal = newDecimal; 858 // NUL-terminate for the C API. 859 this->decimal.getTerminatedBuffer(); 860} 861 862const UnicodeString& 863DateTimePatternGenerator::getDecimal() const { 864 return decimal; 865} 866 867void 868DateTimePatternGenerator::addCanonicalItems() { 869 UnicodeString conflictingPattern; 870 UErrorCode status = U_ZERO_ERROR; 871 872 for (int32_t i=0; i<UDATPG_FIELD_COUNT; i++) { 873 addPattern(UnicodeString(Canonical_Items[i]), FALSE, conflictingPattern, status); 874 } 875} 876 877void 878DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) { 879 dateTimeFormat = dtFormat; 880 // NUL-terminate for the C API. 881 dateTimeFormat.getTerminatedBuffer(); 882} 883 884const UnicodeString& 885DateTimePatternGenerator::getDateTimeFormat() const { 886 return dateTimeFormat; 887} 888 889void 890DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) { 891 const UChar *resStr; 892 int32_t resStrLen = 0; 893 894 Calendar* fCalendar = Calendar::createInstance(locale, status); 895 CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status); 896 UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, status); 897 if (U_FAILURE(status)) return; 898 899 if (ures_getSize(dateTimePatterns) <= DateFormat::kDateTime) 900 { 901 status = U_INVALID_FORMAT_ERROR; 902 return; 903 } 904 resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)DateFormat::kDateTime, &resStrLen, &status); 905 setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen)); 906 907 delete fCalendar; 908} 909 910void 911DateTimePatternGenerator::setDecimalSymbols(const Locale& locale, UErrorCode& status) { 912 DecimalFormatSymbols dfs = DecimalFormatSymbols(locale, status); 913 if(U_SUCCESS(status)) { 914 decimal = dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); 915 // NUL-terminate for the C API. 916 decimal.getTerminatedBuffer(); 917 } 918} 919 920UDateTimePatternConflict 921DateTimePatternGenerator::addPattern( 922 const UnicodeString& pattern, 923 UBool override, 924 UnicodeString &conflictingPattern, 925 UErrorCode& status) 926{ 927 return addPatternWithSkeleton(pattern, NULL, override, conflictingPattern, status); 928} 929 930// For DateTimePatternGenerator::addPatternWithSkeleton - 931// If skeletonToUse is specified, then an availableFormats entry is being added. In this case: 932// 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern. 933// 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified 934// (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override 935// parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual 936// specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was 937// derived (i.e. entries derived from the standard date/time patters for the specified locale). 938// 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a 939// specified skeleton (which sets a new field in the PtnElem in the PatternMap). 940UDateTimePatternConflict 941DateTimePatternGenerator::addPatternWithSkeleton( 942 const UnicodeString& pattern, 943 const UnicodeString* skeletonToUse, 944 UBool override, 945 UnicodeString& conflictingPattern, 946 UErrorCode& status) 947{ 948 949 UnicodeString basePattern; 950 PtnSkeleton skeleton; 951 UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT; 952 953 DateTimeMatcher matcher; 954 if ( skeletonToUse == NULL ) { 955 matcher.set(pattern, fp, skeleton); 956 matcher.getBasePattern(basePattern); 957 } else { 958 matcher.set(*skeletonToUse, fp, skeleton); // no longer trims skeleton fields to max len 3, per #7930 959 matcher.getBasePattern(basePattern); // or perhaps instead: basePattern = *skeletonToUse; 960 } 961 // We only care about base conflicts - and replacing the pattern associated with a base - if: 962 // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous 963 // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or 964 // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen 965 // if we are getting here from a subsequent call to addPattern). 966 // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking 967 // availableFormats items from root, which should not override any previous entry with the same base. 968 UBool entryHadSpecifiedSkeleton; 969 const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton); 970 if (duplicatePattern != NULL && (!entryHadSpecifiedSkeleton || (skeletonToUse != NULL && !override))) { 971 conflictingStatus = UDATPG_BASE_CONFLICT; 972 conflictingPattern = *duplicatePattern; 973 if (!override) { 974 return conflictingStatus; 975 } 976 } 977 // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats 978 // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with 979 // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for 980 // the previously-specified conflicting item. 981 const PtnSkeleton* entrySpecifiedSkeleton = NULL; 982 duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton); 983 if (duplicatePattern != NULL ) { 984 conflictingStatus = UDATPG_CONFLICT; 985 conflictingPattern = *duplicatePattern; 986 if (!override || (skeletonToUse != NULL && entrySpecifiedSkeleton != NULL)) { 987 return conflictingStatus; 988 } 989 } 990 patternMap->add(basePattern, skeleton, pattern, skeletonToUse != NULL, status); 991 if(U_FAILURE(status)) { 992 return conflictingStatus; 993 } 994 995 return UDATPG_NO_CONFLICT; 996} 997 998 999UDateTimePatternField 1000DateTimePatternGenerator::getAppendFormatNumber(const char* field) const { 1001 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1002 if (uprv_strcmp(CLDR_FIELD_APPEND[i], field)==0) { 1003 return (UDateTimePatternField)i; 1004 } 1005 } 1006 return UDATPG_FIELD_COUNT; 1007} 1008 1009UDateTimePatternField 1010DateTimePatternGenerator::getAppendNameNumber(const char* field) const { 1011 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1012 if (uprv_strcmp(CLDR_FIELD_NAME[i],field)==0) { 1013 return (UDateTimePatternField)i; 1014 } 1015 } 1016 return UDATPG_FIELD_COUNT; 1017} 1018 1019const UnicodeString* 1020DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source, 1021 int32_t includeMask, 1022 DistanceInfo* missingFields, 1023 const PtnSkeleton** specifiedSkeletonPtr) { 1024 int32_t bestDistance = 0x7fffffff; 1025 DistanceInfo tempInfo; 1026 const UnicodeString *bestPattern=NULL; 1027 const PtnSkeleton* specifiedSkeleton=NULL; 1028 1029 PatternMapIterator it; 1030 for (it.set(*patternMap); it.hasNext(); ) { 1031 DateTimeMatcher trial = it.next(); 1032 if (trial.equals(skipMatcher)) { 1033 continue; 1034 } 1035 int32_t distance=source.getDistance(trial, includeMask, tempInfo); 1036 if (distance<bestDistance) { 1037 bestDistance=distance; 1038 bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr(), &specifiedSkeleton); 1039 missingFields->setTo(tempInfo); 1040 if (distance==0) { 1041 break; 1042 } 1043 } 1044 } 1045 1046 // If the best raw match had a specified skeleton and that skeleton was requested by the caller, 1047 // then return it too. This generally happens when the caller needs to pass that skeleton 1048 // through to adjustFieldTypes so the latter can do a better job. 1049 if (bestPattern && specifiedSkeletonPtr) { 1050 *specifiedSkeletonPtr = specifiedSkeleton; 1051 } 1052 return bestPattern; 1053} 1054 1055UnicodeString 1056DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern, 1057 const PtnSkeleton* specifiedSkeleton, 1058 int32_t flags, 1059 UDateTimePatternMatchOptions options) { 1060 UnicodeString newPattern; 1061 fp->set(pattern); 1062 for (int32_t i=0; i < fp->itemNumber; i++) { 1063 UnicodeString field = fp->items[i]; 1064 if ( fp->isQuoteLiteral(field) ) { 1065 1066 UnicodeString quoteLiteral; 1067 fp->getQuoteLiteral(quoteLiteral, &i); 1068 newPattern += quoteLiteral; 1069 } 1070 else { 1071 if (fp->isPatternSeparator(field)) { 1072 newPattern+=field; 1073 continue; 1074 } 1075 int32_t canonicalIndex = fp->getCanonicalIndex(field); 1076 if (canonicalIndex < 0) { 1077 newPattern+=field; 1078 continue; // don't adjust 1079 } 1080 const dtTypeElem *row = &dtTypes[canonicalIndex]; 1081 int32_t typeValue = row->field; 1082 if ((flags & kDTPGFixFractionalSeconds) != 0 && typeValue == UDATPG_SECOND_FIELD) { 1083 UnicodeString newField=dtMatcher->skeleton.original[UDATPG_FRACTIONAL_SECOND_FIELD]; 1084 field = field + decimal + newField; 1085 } else if (dtMatcher->skeleton.type[typeValue]!=0) { 1086 // Here: 1087 // - "reqField" is the field from the originally requested skeleton, with length 1088 // "reqFieldLen". 1089 // - "field" is the field from the found pattern. 1090 // 1091 // The adjusted field should consist of characters from the originally requested 1092 // skeleton, except in the case of UDATPG_HOUR_FIELD or UDATPG_MONTH_FIELD or 1093 // UDATPG_WEEKDAY_FIELD or UDATPG_YEAR_FIELD, in which case it should consist 1094 // of characters from the found pattern. 1095 // 1096 // The length of the adjusted field (adjFieldLen) should match that in the originally 1097 // requested skeleton, except that in the following cases the length of the adjusted field 1098 // should match that in the found pattern (i.e. the length of this pattern field should 1099 // not be adjusted): 1100 // 1. typeValue is UDATPG_HOUR_FIELD/MINUTE/SECOND and the corresponding bit in options is 1101 // not set (ticket #7180). Note, we may want to implement a similar change for other 1102 // numeric fields (MM, dd, etc.) so the default behavior is to get locale preference for 1103 // field length, but options bits can be used to override this. 1104 // 2. There is a specified skeleton for the found pattern and one of the following is true: 1105 // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen. 1106 // b) The pattern field is numeric and the skeleton field is not, or vice versa. 1107 1108 UnicodeString reqField = dtMatcher->skeleton.original[typeValue]; 1109 int32_t reqFieldLen = reqField.length(); 1110 if (reqField.charAt(0) == CAP_E && reqFieldLen < 3) 1111 reqFieldLen = 3; // 1-3 for E are equivalent to 3 for c,e 1112 int32_t adjFieldLen = reqFieldLen; 1113 if ( (typeValue==UDATPG_HOUR_FIELD && (options & UDATPG_MATCH_HOUR_FIELD_LENGTH)==0) || 1114 (typeValue==UDATPG_MINUTE_FIELD && (options & UDATPG_MATCH_MINUTE_FIELD_LENGTH)==0) || 1115 (typeValue==UDATPG_SECOND_FIELD && (options & UDATPG_MATCH_SECOND_FIELD_LENGTH)==0) ) { 1116 adjFieldLen = field.length(); 1117 } else if (specifiedSkeleton) { 1118 UnicodeString skelField = specifiedSkeleton->original[typeValue]; 1119 int32_t skelFieldLen = skelField.length(); 1120 UBool patFieldIsNumeric = (row->type > 0); 1121 UBool skelFieldIsNumeric = (specifiedSkeleton->type[typeValue] > 0); 1122 if (skelFieldLen == reqFieldLen || (patFieldIsNumeric && !skelFieldIsNumeric) || (skelFieldIsNumeric && !patFieldIsNumeric)) { 1123 // don't adjust the field length in the found pattern 1124 adjFieldLen = field.length(); 1125 } 1126 } 1127 UChar c = (typeValue!= UDATPG_HOUR_FIELD && typeValue!= UDATPG_MONTH_FIELD && 1128 typeValue!= UDATPG_WEEKDAY_FIELD && (typeValue!= UDATPG_YEAR_FIELD || reqField.charAt(0)==CAP_Y))? 1129 reqField.charAt(0): field.charAt(0); 1130 if (typeValue == UDATPG_HOUR_FIELD && (flags & kDTPGSkeletonUsesCapJ) != 0) { 1131 c = fDefaultHourFormatChar; 1132 switch (options & UADATPG_FORCE_HOUR_CYCLE_MASK) { 1133 case UADATPG_FORCE_12_HOUR_CYCLE: 1134 if (c == CAP_H || c == LOW_K) { 1135 // Have 24-hour cycle, change to 12-hour cycle. 1136 // Should have better way to pick 'h' or 'K'. 1137 c = LOW_H; 1138 }; 1139 break; 1140 case UADATPG_FORCE_24_HOUR_CYCLE: 1141 if (c == LOW_H || c == CAP_K) { 1142 // Have 12-hour cycle, change to 24-hour cycle. 1143 // Should have better way to pick 'H' or 'k'. 1144 c = CAP_H; 1145 }; 1146 break; 1147 default: 1148 break; 1149 } 1150 } 1151 field.remove(); 1152 for (int32_t i=adjFieldLen; i>0; --i) { 1153 field+=c; 1154 } 1155 } 1156 newPattern+=field; 1157 } 1158 } 1159 return newPattern; 1160} 1161 1162UnicodeString 1163DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options) { 1164 UnicodeString resultPattern, tempPattern; 1165 UErrorCode err=U_ZERO_ERROR; 1166 int32_t lastMissingFieldMask=0; 1167 if (missingFields!=0) { 1168 resultPattern=UnicodeString(); 1169 const PtnSkeleton* specifiedSkeleton=NULL; 1170 tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo, &specifiedSkeleton); 1171 resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options); 1172 if ( distanceInfo->missingFieldMask==0 ) { 1173 return resultPattern; 1174 } 1175 while (distanceInfo->missingFieldMask!=0) { // precondition: EVERY single field must work! 1176 if ( lastMissingFieldMask == distanceInfo->missingFieldMask ) { 1177 break; // cannot find the proper missing field 1178 } 1179 if (((distanceInfo->missingFieldMask & UDATPG_SECOND_AND_FRACTIONAL_MASK)==UDATPG_FRACTIONAL_MASK) && 1180 ((missingFields & UDATPG_SECOND_AND_FRACTIONAL_MASK) == UDATPG_SECOND_AND_FRACTIONAL_MASK)) { 1181 resultPattern = adjustFieldTypes(resultPattern, specifiedSkeleton, flags | kDTPGFixFractionalSeconds, options); 1182 distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK; 1183 continue; 1184 } 1185 int32_t startingMask = distanceInfo->missingFieldMask; 1186 tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, &specifiedSkeleton); 1187 tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options); 1188 int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask; 1189 int32_t topField=getTopBitNumber(foundMask); 1190 UnicodeString appendName; 1191 getAppendName((UDateTimePatternField)topField, appendName); 1192 const Formattable formatPattern[] = { 1193 resultPattern, 1194 tempPattern, 1195 appendName 1196 }; 1197 UnicodeString emptyStr; 1198 resultPattern = MessageFormat::format(appendItemFormats[topField], formatPattern, 3, emptyStr, err); 1199 lastMissingFieldMask = distanceInfo->missingFieldMask; 1200 } 1201 } 1202 return resultPattern; 1203} 1204 1205int32_t 1206DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) { 1207 if ( foundMask==0 ) { 1208 return 0; 1209 } 1210 int32_t i=0; 1211 while (foundMask!=0) { 1212 foundMask >>=1; 1213 ++i; 1214 } 1215 if (i-1 >UDATPG_ZONE_FIELD) { 1216 return UDATPG_ZONE_FIELD; 1217 } 1218 else 1219 return i-1; 1220} 1221 1222void 1223DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err) 1224{ 1225 fAvailableFormatKeyHash->puti(key, 1, err); 1226} 1227 1228UBool 1229DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const { 1230 return (UBool)(fAvailableFormatKeyHash->geti(key) == 1); 1231} 1232 1233void 1234DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) { 1235 1236 if (other == NULL) { 1237 return; 1238 } 1239 if (fAvailableFormatKeyHash != NULL) { 1240 delete fAvailableFormatKeyHash; 1241 fAvailableFormatKeyHash = NULL; 1242 } 1243 initHashtable(status); 1244 if(U_FAILURE(status)){ 1245 return; 1246 } 1247 int32_t pos = -1; 1248 const UHashElement* elem = NULL; 1249 // walk through the hash table and create a deep clone 1250 while((elem = other->nextElement(pos))!= NULL){ 1251 const UHashTok otherKeyTok = elem->key; 1252 UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer; 1253 fAvailableFormatKeyHash->puti(*otherKey, 1, status); 1254 if(U_FAILURE(status)){ 1255 return; 1256 } 1257 } 1258} 1259 1260StringEnumeration* 1261DateTimePatternGenerator::getSkeletons(UErrorCode& status) const { 1262 StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status); 1263 return skeletonEnumerator; 1264} 1265 1266const UnicodeString& 1267DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) const { 1268 PtnElem *curElem; 1269 1270 if (skeleton.length() ==0) { 1271 return emptyString; 1272 } 1273 curElem = patternMap->getHeader(skeleton.charAt(0)); 1274 while ( curElem != NULL ) { 1275 if ( curElem->skeleton->getSkeleton()==skeleton ) { 1276 return curElem->pattern; 1277 } 1278 curElem=curElem->next; 1279 } 1280 return emptyString; 1281} 1282 1283StringEnumeration* 1284DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const { 1285 StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status); 1286 return baseSkeletonEnumerator; 1287} 1288 1289StringEnumeration* 1290DateTimePatternGenerator::getRedundants(UErrorCode& status) { 1291 StringEnumeration* output = new DTRedundantEnumeration(); 1292 const UnicodeString *pattern; 1293 PatternMapIterator it; 1294 for (it.set(*patternMap); it.hasNext(); ) { 1295 DateTimeMatcher current = it.next(); 1296 pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton())); 1297 if ( isCanonicalItem(*pattern) ) { 1298 continue; 1299 } 1300 if ( skipMatcher == NULL ) { 1301 skipMatcher = new DateTimeMatcher(current); 1302 } 1303 else { 1304 *skipMatcher = current; 1305 } 1306 UnicodeString trial = getBestPattern(current.getPattern(), status); 1307 if (trial == *pattern) { 1308 ((DTRedundantEnumeration *)output)->add(*pattern, status); 1309 } 1310 if (current.equals(skipMatcher)) { 1311 continue; 1312 } 1313 } 1314 return output; 1315} 1316 1317UBool 1318DateTimePatternGenerator::isCanonicalItem(const UnicodeString& item) const { 1319 if ( item.length() != 1 ) { 1320 return FALSE; 1321 } 1322 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1323 if (item.charAt(0)==Canonical_Items[i]) { 1324 return TRUE; 1325 } 1326 } 1327 return FALSE; 1328} 1329 1330 1331DateTimePatternGenerator* 1332DateTimePatternGenerator::clone() const { 1333 return new DateTimePatternGenerator(*this); 1334} 1335 1336PatternMap::PatternMap() { 1337 for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { 1338 boot[i]=NULL; 1339 } 1340 isDupAllowed = TRUE; 1341} 1342 1343void 1344PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) { 1345 this->isDupAllowed = other.isDupAllowed; 1346 for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) { 1347 PtnElem *curElem, *otherElem, *prevElem=NULL; 1348 otherElem = other.boot[bootIndex]; 1349 while (otherElem!=NULL) { 1350 if ((curElem = new PtnElem(otherElem->basePattern, otherElem->pattern))==NULL) { 1351 // out of memory 1352 status = U_MEMORY_ALLOCATION_ERROR; 1353 return; 1354 } 1355 if ( this->boot[bootIndex]== NULL ) { 1356 this->boot[bootIndex] = curElem; 1357 } 1358 if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) { 1359 // out of memory 1360 status = U_MEMORY_ALLOCATION_ERROR; 1361 return; 1362 } 1363 1364 if (prevElem!=NULL) { 1365 prevElem->next=curElem; 1366 } 1367 curElem->next=NULL; 1368 prevElem = curElem; 1369 otherElem = otherElem->next; 1370 } 1371 1372 } 1373} 1374 1375PtnElem* 1376PatternMap::getHeader(UChar baseChar) { 1377 PtnElem* curElem; 1378 1379 if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) { 1380 curElem = boot[baseChar-CAP_A]; 1381 } 1382 else { 1383 if ( (baseChar >=LOW_A) && (baseChar <= LOW_Z) ) { 1384 curElem = boot[26+baseChar-LOW_A]; 1385 } 1386 else { 1387 return NULL; 1388 } 1389 } 1390 return curElem; 1391} 1392 1393PatternMap::~PatternMap() { 1394 for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) { 1395 if (boot[i]!=NULL ) { 1396 delete boot[i]; 1397 boot[i]=NULL; 1398 } 1399 } 1400} // PatternMap destructor 1401 1402void 1403PatternMap::add(const UnicodeString& basePattern, 1404 const PtnSkeleton& skeleton, 1405 const UnicodeString& value,// mapped pattern value 1406 UBool skeletonWasSpecified, 1407 UErrorCode &status) { 1408 UChar baseChar = basePattern.charAt(0); 1409 PtnElem *curElem, *baseElem; 1410 status = U_ZERO_ERROR; 1411 1412 // the baseChar must be A-Z or a-z 1413 if ((baseChar >= CAP_A) && (baseChar <= CAP_Z)) { 1414 baseElem = boot[baseChar-CAP_A]; 1415 } 1416 else { 1417 if ((baseChar >=LOW_A) && (baseChar <= LOW_Z)) { 1418 baseElem = boot[26+baseChar-LOW_A]; 1419 } 1420 else { 1421 status = U_ILLEGAL_CHARACTER; 1422 return; 1423 } 1424 } 1425 1426 if (baseElem == NULL) { 1427 if ((curElem = new PtnElem(basePattern, value)) == NULL ) { 1428 // out of memory 1429 status = U_MEMORY_ALLOCATION_ERROR; 1430 return; 1431 } 1432 if (baseChar >= LOW_A) { 1433 boot[26 + (baseChar-LOW_A)] = curElem; 1434 } 1435 else { 1436 boot[baseChar-CAP_A] = curElem; 1437 } 1438 curElem->skeleton = new PtnSkeleton(skeleton); 1439 curElem->skeletonWasSpecified = skeletonWasSpecified; 1440 } 1441 if ( baseElem != NULL ) { 1442 curElem = getDuplicateElem(basePattern, skeleton, baseElem); 1443 1444 if (curElem == NULL) { 1445 // add new element to the list. 1446 curElem = baseElem; 1447 while( curElem -> next != NULL ) 1448 { 1449 curElem = curElem->next; 1450 } 1451 if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) { 1452 // out of memory 1453 status = U_MEMORY_ALLOCATION_ERROR; 1454 return; 1455 } 1456 curElem=curElem->next; 1457 curElem->skeleton = new PtnSkeleton(skeleton); 1458 curElem->skeletonWasSpecified = skeletonWasSpecified; 1459 } 1460 else { 1461 // Pattern exists in the list already. 1462 if ( !isDupAllowed ) { 1463 return; 1464 } 1465 // Overwrite the value. 1466 curElem->pattern = value; 1467 // It was a bug that we were not doing the following previously, 1468 // though that bug hid other problems by making things partly work. 1469 curElem->skeletonWasSpecified = skeletonWasSpecified; 1470 } 1471 } 1472} // PatternMap::add 1473 1474// Find the pattern from the given basePattern string. 1475const UnicodeString * 1476PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified) { // key to search for 1477 PtnElem *curElem; 1478 1479 if ((curElem=getHeader(basePattern.charAt(0)))==NULL) { 1480 return NULL; // no match 1481 } 1482 1483 do { 1484 if ( basePattern.compare(curElem->basePattern)==0 ) { 1485 skeletonWasSpecified = curElem->skeletonWasSpecified; 1486 return &(curElem->pattern); 1487 } 1488 curElem=curElem->next; 1489 }while (curElem != NULL); 1490 1491 return NULL; 1492} // PatternMap::getFromBasePattern 1493 1494 1495// Find the pattern from the given skeleton. 1496// At least when this is called from getBestRaw & addPattern (in which case specifiedSkeletonPtr is non-NULL), 1497// the comparison should be based on skeleton.original (which is unique and tied to the distance measurement in bestRaw) 1498// and not skeleton.baseOriginal (which is not unique); otherwise we may pick a different skeleton than the one with the 1499// optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL), 1500// for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily. 1501const UnicodeString * 1502PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) { // key to search for 1503 PtnElem *curElem; 1504 1505 if (specifiedSkeletonPtr) { 1506 *specifiedSkeletonPtr = NULL; 1507 } 1508 1509 // find boot entry 1510 UChar baseChar='\0'; 1511 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1512 if (skeleton.baseOriginal[i].length() !=0 ) { 1513 baseChar = skeleton.baseOriginal[i].charAt(0); 1514 break; 1515 } 1516 } 1517 1518 if ((curElem=getHeader(baseChar))==NULL) { 1519 return NULL; // no match 1520 } 1521 1522 do { 1523 int32_t i=0; 1524 if (specifiedSkeletonPtr != NULL) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original 1525 for (i=0; i<UDATPG_FIELD_COUNT; ++i) { 1526 if (curElem->skeleton->original[i].compare(skeleton.original[i]) != 0 ) 1527 { 1528 break; 1529 } 1530 } 1531 } else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal 1532 for (i=0; i<UDATPG_FIELD_COUNT; ++i) { 1533 if (curElem->skeleton->baseOriginal[i].compare(skeleton.baseOriginal[i]) != 0 ) 1534 { 1535 break; 1536 } 1537 } 1538 } 1539 if (i == UDATPG_FIELD_COUNT) { 1540 if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) { 1541 *specifiedSkeletonPtr = curElem->skeleton; 1542 } 1543 return &(curElem->pattern); 1544 } 1545 curElem=curElem->next; 1546 }while (curElem != NULL); 1547 1548 return NULL; 1549} 1550 1551UBool 1552PatternMap::equals(const PatternMap& other) { 1553 if ( this==&other ) { 1554 return TRUE; 1555 } 1556 for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) { 1557 if ( boot[bootIndex]==other.boot[bootIndex] ) { 1558 continue; 1559 } 1560 if ( (boot[bootIndex]==NULL)||(other.boot[bootIndex]==NULL) ) { 1561 return FALSE; 1562 } 1563 PtnElem *otherElem = other.boot[bootIndex]; 1564 PtnElem *myElem = boot[bootIndex]; 1565 while ((otherElem!=NULL) || (myElem!=NULL)) { 1566 if ( myElem == otherElem ) { 1567 break; 1568 } 1569 if ((otherElem==NULL) || (myElem==NULL)) { 1570 return FALSE; 1571 } 1572 if ( (myElem->basePattern != otherElem->basePattern) || 1573 (myElem->pattern != otherElem->pattern) ) { 1574 return FALSE; 1575 } 1576 if ((myElem->skeleton!=otherElem->skeleton)&& 1577 !myElem->skeleton->equals(*(otherElem->skeleton))) { 1578 return FALSE; 1579 } 1580 myElem = myElem->next; 1581 otherElem=otherElem->next; 1582 } 1583 } 1584 return TRUE; 1585} 1586 1587// find any key existing in the mapping table already. 1588// return TRUE if there is an existing key, otherwise return FALSE. 1589PtnElem* 1590PatternMap::getDuplicateElem( 1591 const UnicodeString &basePattern, 1592 const PtnSkeleton &skeleton, 1593 PtnElem *baseElem) { 1594 PtnElem *curElem; 1595 1596 if ( baseElem == (PtnElem *)NULL ) { 1597 return (PtnElem*)NULL; 1598 } 1599 else { 1600 curElem = baseElem; 1601 } 1602 do { 1603 if ( basePattern.compare(curElem->basePattern)==0 ) { 1604 UBool isEqual=TRUE; 1605 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1606 if (curElem->skeleton->type[i] != skeleton.type[i] ) { 1607 isEqual=FALSE; 1608 break; 1609 } 1610 } 1611 if (isEqual) { 1612 return curElem; 1613 } 1614 } 1615 curElem = curElem->next; 1616 } while( curElem != (PtnElem *)NULL ); 1617 1618 // end of the list 1619 return (PtnElem*)NULL; 1620 1621} // PatternMap::getDuplicateElem 1622 1623DateTimeMatcher::DateTimeMatcher(void) { 1624} 1625 1626DateTimeMatcher::~DateTimeMatcher() {} 1627 1628DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) { 1629 copyFrom(other.skeleton); 1630} 1631 1632 1633void 1634DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) { 1635 PtnSkeleton localSkeleton; 1636 return set(pattern, fp, localSkeleton); 1637} 1638 1639void 1640DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeletonResult) { 1641 int32_t i; 1642 for (i=0; i<UDATPG_FIELD_COUNT; ++i) { 1643 skeletonResult.type[i]=NONE; 1644 } 1645 fp->set(pattern); 1646 for (i=0; i < fp->itemNumber; i++) { 1647 UnicodeString field = fp->items[i]; 1648 if ( field.charAt(0) == LOW_A ) { 1649 continue; // skip 'a' 1650 } 1651 1652 if ( fp->isQuoteLiteral(field) ) { 1653 UnicodeString quoteLiteral; 1654 fp->getQuoteLiteral(quoteLiteral, &i); 1655 continue; 1656 } 1657 int32_t canonicalIndex = fp->getCanonicalIndex(field); 1658 if (canonicalIndex < 0 ) { 1659 continue; 1660 } 1661 const dtTypeElem *row = &dtTypes[canonicalIndex]; 1662 int32_t typeValue = row->field; 1663 skeletonResult.original[typeValue]=field; 1664 UChar repeatChar = row->patternChar; 1665 int32_t repeatCount = row->minLen; // #7930 removes cap at 3 1666 while (repeatCount-- > 0) { 1667 skeletonResult.baseOriginal[typeValue] += repeatChar; 1668 } 1669 int16_t subTypeValue = row->type; 1670 if ( row->type > 0) { 1671 subTypeValue += field.length(); 1672 } 1673 skeletonResult.type[typeValue] = subTypeValue; 1674 } 1675 copyFrom(skeletonResult); 1676} 1677 1678void 1679DateTimeMatcher::getBasePattern(UnicodeString &result ) { 1680 result.remove(); // Reset the result first. 1681 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1682 if (skeleton.baseOriginal[i].length()!=0) { 1683 result += skeleton.baseOriginal[i]; 1684 } 1685 } 1686} 1687 1688UnicodeString 1689DateTimeMatcher::getPattern() { 1690 UnicodeString result; 1691 1692 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1693 if (skeleton.original[i].length()!=0) { 1694 result += skeleton.original[i]; 1695 } 1696 } 1697 return result; 1698} 1699 1700int32_t 1701DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) { 1702 int32_t result=0; 1703 distanceInfo.clear(); 1704 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) { 1705 int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i]; 1706 int32_t otherType = other.skeleton.type[i]; 1707 if (myType==otherType) { 1708 continue; 1709 } 1710 if (myType==0) {// and other is not 1711 result += EXTRA_FIELD; 1712 distanceInfo.addExtra(i); 1713 } 1714 else { 1715 if (otherType==0) { 1716 result += MISSING_FIELD; 1717 distanceInfo.addMissing(i); 1718 } 1719 else { 1720 result += abs(myType - otherType); 1721 } 1722 } 1723 1724 } 1725 return result; 1726} 1727 1728void 1729DateTimeMatcher::copyFrom(const PtnSkeleton& newSkeleton) { 1730 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1731 this->skeleton.type[i]=newSkeleton.type[i]; 1732 this->skeleton.original[i]=newSkeleton.original[i]; 1733 this->skeleton.baseOriginal[i]=newSkeleton.baseOriginal[i]; 1734 } 1735} 1736 1737void 1738DateTimeMatcher::copyFrom() { 1739 // same as clear 1740 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1741 this->skeleton.type[i]=0; 1742 this->skeleton.original[i].remove(); 1743 this->skeleton.baseOriginal[i].remove(); 1744 } 1745} 1746 1747UBool 1748DateTimeMatcher::equals(const DateTimeMatcher* other) const { 1749 if (other==NULL) { 1750 return FALSE; 1751 } 1752 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1753 if (this->skeleton.original[i]!=other->skeleton.original[i] ) { 1754 return FALSE; 1755 } 1756 } 1757 return TRUE; 1758} 1759 1760int32_t 1761DateTimeMatcher::getFieldMask() { 1762 int32_t result=0; 1763 1764 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 1765 if (skeleton.type[i]!=0) { 1766 result |= (1<<i); 1767 } 1768 } 1769 return result; 1770} 1771 1772PtnSkeleton* 1773DateTimeMatcher::getSkeletonPtr() { 1774 return &skeleton; 1775} 1776 1777FormatParser::FormatParser () { 1778 status = START; 1779 itemNumber=0; 1780} 1781 1782 1783FormatParser::~FormatParser () { 1784} 1785 1786 1787// Find the next token with the starting position and length 1788// Note: the startPos may 1789FormatParser::TokenStatus 1790FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) { 1791 int32_t curLoc = startPos; 1792 if ( curLoc >= pattern.length()) { 1793 return DONE; 1794 } 1795 // check the current char is between A-Z or a-z 1796 do { 1797 UChar c=pattern.charAt(curLoc); 1798 if ( (c>=CAP_A && c<=CAP_Z) || (c>=LOW_A && c<=LOW_Z) ) { 1799 curLoc++; 1800 } 1801 else { 1802 startPos = curLoc; 1803 *len=1; 1804 return ADD_TOKEN; 1805 } 1806 1807 if ( pattern.charAt(curLoc)!= pattern.charAt(startPos) ) { 1808 break; // not the same token 1809 } 1810 } while(curLoc <= pattern.length()); 1811 *len = curLoc-startPos; 1812 return ADD_TOKEN; 1813} 1814 1815void 1816FormatParser::set(const UnicodeString& pattern) { 1817 int32_t startPos=0; 1818 TokenStatus result=START; 1819 int32_t len=0; 1820 itemNumber =0; 1821 1822 do { 1823 result = setTokens( pattern, startPos, &len ); 1824 if ( result == ADD_TOKEN ) 1825 { 1826 items[itemNumber++] = UnicodeString(pattern, startPos, len ); 1827 startPos += len; 1828 } 1829 else { 1830 break; 1831 } 1832 } while (result==ADD_TOKEN && itemNumber < MAX_DT_TOKEN); 1833} 1834 1835int32_t 1836FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) { 1837 int32_t len = s.length(); 1838 if (len == 0) { 1839 return -1; 1840 } 1841 UChar ch = s.charAt(0); 1842 1843 // Verify that all are the same character. 1844 for (int32_t l = 1; l < len; l++) { 1845 if (ch != s.charAt(l)) { 1846 return -1; 1847 } 1848 } 1849 int32_t i = 0; 1850 int32_t bestRow = -1; 1851 while (dtTypes[i].patternChar != '\0') { 1852 if ( dtTypes[i].patternChar != ch ) { 1853 ++i; 1854 continue; 1855 } 1856 bestRow = i; 1857 if (dtTypes[i].patternChar != dtTypes[i+1].patternChar) { 1858 return i; 1859 } 1860 if (dtTypes[i+1].minLen <= len) { 1861 ++i; 1862 continue; 1863 } 1864 return i; 1865 } 1866 return strict ? -1 : bestRow; 1867} 1868 1869UBool 1870FormatParser::isQuoteLiteral(const UnicodeString& s) const { 1871 return (UBool)(s.charAt(0)==SINGLE_QUOTE); 1872} 1873 1874// This function aussumes the current itemIndex points to the quote literal. 1875// Please call isQuoteLiteral prior to this function. 1876void 1877FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) { 1878 int32_t i=*itemIndex; 1879 1880 quote.remove(); 1881 if (items[i].charAt(0)==SINGLE_QUOTE) { 1882 quote += items[i]; 1883 ++i; 1884 } 1885 while ( i < itemNumber ) { 1886 if ( items[i].charAt(0)==SINGLE_QUOTE ) { 1887 if ( (i+1<itemNumber) && (items[i+1].charAt(0)==SINGLE_QUOTE)) { 1888 // two single quotes e.g. 'o''clock' 1889 quote += items[i++]; 1890 quote += items[i++]; 1891 continue; 1892 } 1893 else { 1894 quote += items[i]; 1895 break; 1896 } 1897 } 1898 else { 1899 quote += items[i]; 1900 } 1901 ++i; 1902 } 1903 *itemIndex=i; 1904} 1905 1906UBool 1907FormatParser::isPatternSeparator(UnicodeString& field) { 1908 for (int32_t i=0; i<field.length(); ++i ) { 1909 UChar c= field.charAt(i); 1910 if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) || 1911 (c==QUOTATION_MARK) || (c==COMMA) || (c==HYPHEN) ||(items[i].charAt(0)==DOT) ) { 1912 continue; 1913 } 1914 else { 1915 return FALSE; 1916 } 1917 } 1918 return TRUE; 1919} 1920 1921DistanceInfo::~DistanceInfo() {} 1922 1923void 1924DistanceInfo::setTo(DistanceInfo &other) { 1925 missingFieldMask = other.missingFieldMask; 1926 extraFieldMask= other.extraFieldMask; 1927} 1928 1929PatternMapIterator::PatternMapIterator() { 1930 bootIndex = 0; 1931 nodePtr = NULL; 1932 patternMap=NULL; 1933 matcher= new DateTimeMatcher(); 1934} 1935 1936 1937PatternMapIterator::~PatternMapIterator() { 1938 delete matcher; 1939} 1940 1941void 1942PatternMapIterator::set(PatternMap& newPatternMap) { 1943 this->patternMap=&newPatternMap; 1944} 1945 1946PtnSkeleton* 1947PatternMapIterator::getSkeleton() { 1948 if ( nodePtr == NULL ) { 1949 return NULL; 1950 } 1951 else { 1952 return nodePtr->skeleton; 1953 } 1954} 1955 1956UBool 1957PatternMapIterator::hasNext() { 1958 int32_t headIndex=bootIndex; 1959 PtnElem *curPtr=nodePtr; 1960 1961 if (patternMap==NULL) { 1962 return FALSE; 1963 } 1964 while ( headIndex < MAX_PATTERN_ENTRIES ) { 1965 if ( curPtr != NULL ) { 1966 if ( curPtr->next != NULL ) { 1967 return TRUE; 1968 } 1969 else { 1970 headIndex++; 1971 curPtr=NULL; 1972 continue; 1973 } 1974 } 1975 else { 1976 if ( patternMap->boot[headIndex] != NULL ) { 1977 return TRUE; 1978 } 1979 else { 1980 headIndex++; 1981 continue; 1982 } 1983 } 1984 1985 } 1986 return FALSE; 1987} 1988 1989DateTimeMatcher& 1990PatternMapIterator::next() { 1991 while ( bootIndex < MAX_PATTERN_ENTRIES ) { 1992 if ( nodePtr != NULL ) { 1993 if ( nodePtr->next != NULL ) { 1994 nodePtr = nodePtr->next; 1995 break; 1996 } 1997 else { 1998 bootIndex++; 1999 nodePtr=NULL; 2000 continue; 2001 } 2002 } 2003 else { 2004 if ( patternMap->boot[bootIndex] != NULL ) { 2005 nodePtr = patternMap->boot[bootIndex]; 2006 break; 2007 } 2008 else { 2009 bootIndex++; 2010 continue; 2011 } 2012 } 2013 } 2014 if (nodePtr!=NULL) { 2015 matcher->copyFrom(*nodePtr->skeleton); 2016 } 2017 else { 2018 matcher->copyFrom(); 2019 } 2020 return *matcher; 2021} 2022 2023PtnSkeleton::PtnSkeleton() { 2024} 2025 2026 2027PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) { 2028 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 2029 this->type[i]=other.type[i]; 2030 this->original[i]=other.original[i]; 2031 this->baseOriginal[i]=other.baseOriginal[i]; 2032 } 2033} 2034 2035UBool 2036PtnSkeleton::equals(const PtnSkeleton& other) { 2037 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 2038 if ( (type[i]!= other.type[i]) || 2039 (original[i]!=other.original[i]) || 2040 (baseOriginal[i]!=other.baseOriginal[i]) ) { 2041 return FALSE; 2042 } 2043 } 2044 return TRUE; 2045} 2046 2047UnicodeString 2048PtnSkeleton::getSkeleton() { 2049 UnicodeString result; 2050 2051 for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) { 2052 if (original[i].length()!=0) { 2053 result += original[i]; 2054 } 2055 } 2056 return result; 2057} 2058 2059UnicodeString 2060PtnSkeleton::getBaseSkeleton() { 2061 UnicodeString result; 2062 2063 for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) { 2064 if (baseOriginal[i].length()!=0) { 2065 result += baseOriginal[i]; 2066 } 2067 } 2068 return result; 2069} 2070 2071PtnSkeleton::~PtnSkeleton() { 2072} 2073 2074PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) : 2075basePattern(basePat), 2076skeleton(NULL), 2077pattern(pat), 2078next(NULL) 2079{ 2080} 2081 2082PtnElem::~PtnElem() { 2083 2084 if (next!=NULL) { 2085 delete next; 2086 } 2087 delete skeleton; 2088} 2089 2090DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) { 2091 PtnElem *curElem; 2092 PtnSkeleton *curSkeleton; 2093 UnicodeString s; 2094 int32_t bootIndex; 2095 2096 pos=0; 2097 fSkeletons = new UVector(status); 2098 if (U_FAILURE(status)) { 2099 delete fSkeletons; 2100 return; 2101 } 2102 for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) { 2103 curElem = patternMap.boot[bootIndex]; 2104 while (curElem!=NULL) { 2105 switch(type) { 2106 case DT_BASESKELETON: 2107 s=curElem->basePattern; 2108 break; 2109 case DT_PATTERN: 2110 s=curElem->pattern; 2111 break; 2112 case DT_SKELETON: 2113 curSkeleton=curElem->skeleton; 2114 s=curSkeleton->getSkeleton(); 2115 break; 2116 } 2117 if ( !isCanonicalItem(s) ) { 2118 fSkeletons->addElement(new UnicodeString(s), status); 2119 if (U_FAILURE(status)) { 2120 delete fSkeletons; 2121 fSkeletons = NULL; 2122 return; 2123 } 2124 } 2125 curElem = curElem->next; 2126 } 2127 } 2128 if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) { 2129 status = U_BUFFER_OVERFLOW_ERROR; 2130 } 2131} 2132 2133const UnicodeString* 2134DTSkeletonEnumeration::snext(UErrorCode& status) { 2135 if (U_SUCCESS(status) && pos < fSkeletons->size()) { 2136 return (const UnicodeString*)fSkeletons->elementAt(pos++); 2137 } 2138 return NULL; 2139} 2140 2141void 2142DTSkeletonEnumeration::reset(UErrorCode& /*status*/) { 2143 pos=0; 2144} 2145 2146int32_t 2147DTSkeletonEnumeration::count(UErrorCode& /*status*/) const { 2148 return (fSkeletons==NULL) ? 0 : fSkeletons->size(); 2149} 2150 2151UBool 2152DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) { 2153 if ( item.length() != 1 ) { 2154 return FALSE; 2155 } 2156 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 2157 if (item.charAt(0)==Canonical_Items[i]) { 2158 return TRUE; 2159 } 2160 } 2161 return FALSE; 2162} 2163 2164DTSkeletonEnumeration::~DTSkeletonEnumeration() { 2165 UnicodeString *s; 2166 for (int32_t i=0; i<fSkeletons->size(); ++i) { 2167 if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) { 2168 delete s; 2169 } 2170 } 2171 delete fSkeletons; 2172} 2173 2174DTRedundantEnumeration::DTRedundantEnumeration() { 2175 pos=0; 2176 fPatterns = NULL; 2177} 2178 2179void 2180DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) { 2181 if (U_FAILURE(status)) return; 2182 if (fPatterns == NULL) { 2183 fPatterns = new UVector(status); 2184 if (U_FAILURE(status)) { 2185 delete fPatterns; 2186 fPatterns = NULL; 2187 return; 2188 } 2189 } 2190 fPatterns->addElement(new UnicodeString(pattern), status); 2191 if (U_FAILURE(status)) { 2192 delete fPatterns; 2193 fPatterns = NULL; 2194 return; 2195 } 2196} 2197 2198const UnicodeString* 2199DTRedundantEnumeration::snext(UErrorCode& status) { 2200 if (U_SUCCESS(status) && pos < fPatterns->size()) { 2201 return (const UnicodeString*)fPatterns->elementAt(pos++); 2202 } 2203 return NULL; 2204} 2205 2206void 2207DTRedundantEnumeration::reset(UErrorCode& /*status*/) { 2208 pos=0; 2209} 2210 2211int32_t 2212DTRedundantEnumeration::count(UErrorCode& /*status*/) const { 2213 return (fPatterns==NULL) ? 0 : fPatterns->size(); 2214} 2215 2216UBool 2217DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) { 2218 if ( item.length() != 1 ) { 2219 return FALSE; 2220 } 2221 for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) { 2222 if (item.charAt(0)==Canonical_Items[i]) { 2223 return TRUE; 2224 } 2225 } 2226 return FALSE; 2227} 2228 2229DTRedundantEnumeration::~DTRedundantEnumeration() { 2230 UnicodeString *s; 2231 for (int32_t i=0; i<fPatterns->size(); ++i) { 2232 if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) { 2233 delete s; 2234 } 2235 } 2236 delete fPatterns; 2237} 2238 2239U_NAMESPACE_END 2240 2241 2242#endif /* #if !UCONFIG_NO_FORMATTING */ 2243 2244//eof 2245