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