1 /******************************************************************************* 2 * Copyright (C) 2008-2010, International Business Machines Corporation and 3 * others. All Rights Reserved. 4 ******************************************************************************* 5 * 6 * File DTITVINF.CPP 7 * 8 ******************************************************************************* 9 */ 10 11 #include "unicode/dtitvinf.h" 12 13 14 #if !UCONFIG_NO_FORMATTING 15 16 //TODO: define it in compiler time 17 //#define DTITVINF_DEBUG 1 18 19 20 #ifdef DTITVINF_DEBUG 21 #include <iostream> 22 #endif 23 24 #include "cstring.h" 25 #include "unicode/msgfmt.h" 26 #include "unicode/uloc.h" 27 #include "unicode/ures.h" 28 #include "dtitv_impl.h" 29 #include "hash.h" 30 #include "gregoimp.h" 31 #include "uresimp.h" 32 #include "hash.h" 33 #include "gregoimp.h" 34 #include "uresimp.h" 35 36 37 U_NAMESPACE_BEGIN 38 39 40 #ifdef DTITVINF_DEBUG 41 #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; } 42 #endif 43 44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo) 45 46 static const char gCalendarTag[]="calendar"; 47 static const char gGregorianTag[]="gregorian"; 48 static const char gIntervalDateTimePatternTag[]="intervalFormats"; 49 static const char gFallbackPatternTag[]="fallback"; 50 51 // {0} 52 static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET}; 53 // {1} 54 static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET}; 55 56 // default fall-back 57 static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0}; 58 59 60 61 DateIntervalInfo::DateIntervalInfo(UErrorCode& status) 62 : fFallbackIntervalPattern(gDefaultFallbackPattern), 63 fFirstDateInPtnIsLaterDate(false), 64 fIntervalPatterns(NULL) 65 { 66 fIntervalPatterns = initHash(status); 67 } 68 69 70 71 DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status) 72 : fFallbackIntervalPattern(gDefaultFallbackPattern), 73 fFirstDateInPtnIsLaterDate(false), 74 fIntervalPatterns(NULL) 75 { 76 initializeData(locale, status); 77 } 78 79 80 81 void 82 DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton, 83 UCalendarDateFields lrgDiffCalUnit, 84 const UnicodeString& intervalPattern, 85 UErrorCode& status) { 86 87 if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) { 88 setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status); 89 setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status); 90 } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH || 91 lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) { 92 setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status); 93 } else { 94 setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status); 95 } 96 } 97 98 99 void 100 DateIntervalInfo::setFallbackIntervalPattern( 101 const UnicodeString& fallbackPattern, 102 UErrorCode& status) { 103 if ( U_FAILURE(status) ) { 104 return; 105 } 106 int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, 107 sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0); 108 int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern, 109 sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0); 110 if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) { 111 status = U_ILLEGAL_ARGUMENT_ERROR; 112 return; 113 } 114 if ( firstPatternIndex > secondPatternIndex ) { 115 fFirstDateInPtnIsLaterDate = true; 116 } 117 fFallbackIntervalPattern = fallbackPattern; 118 } 119 120 121 122 DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf) 123 : UObject(dtitvinf), 124 fIntervalPatterns(NULL) 125 { 126 *this = dtitvinf; 127 } 128 129 130 131 DateIntervalInfo& 132 DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) { 133 if ( this == &dtitvinf ) { 134 return *this; 135 } 136 137 UErrorCode status = U_ZERO_ERROR; 138 deleteHash(fIntervalPatterns); 139 fIntervalPatterns = initHash(status); 140 copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status); 141 if ( U_FAILURE(status) ) { 142 return *this; 143 } 144 145 fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern; 146 fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate; 147 return *this; 148 } 149 150 151 DateIntervalInfo* 152 DateIntervalInfo::clone() const { 153 return new DateIntervalInfo(*this); 154 } 155 156 157 DateIntervalInfo::~DateIntervalInfo() { 158 deleteHash(fIntervalPatterns); 159 fIntervalPatterns = NULL; 160 } 161 162 163 UBool 164 DateIntervalInfo::operator==(const DateIntervalInfo& other) const { 165 UBool equal = ( 166 fFallbackIntervalPattern == other.fFallbackIntervalPattern && 167 fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate ); 168 169 if ( equal == TRUE ) { 170 equal = fIntervalPatterns->equals(*(other.fIntervalPatterns)); 171 } 172 173 return equal; 174 } 175 176 177 UnicodeString& 178 DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton, 179 UCalendarDateFields field, 180 UnicodeString& result, 181 UErrorCode& status) const { 182 if ( U_FAILURE(status) ) { 183 return result; 184 } 185 186 const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton); 187 if ( patternsOfOneSkeleton != NULL ) { 188 IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status); 189 if ( U_FAILURE(status) ) { 190 return result; 191 } 192 const UnicodeString& intervalPattern = patternsOfOneSkeleton[index]; 193 if ( !intervalPattern.isEmpty() ) { 194 result = intervalPattern; 195 } 196 } 197 return result; 198 } 199 200 201 UBool 202 DateIntervalInfo::getDefaultOrder() const { 203 return fFirstDateInPtnIsLaterDate; 204 } 205 206 207 UnicodeString& 208 DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const { 209 result = fFallbackIntervalPattern; 210 return result; 211 } 212 213 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) 214 215 void 216 DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err) 217 { 218 fIntervalPatterns = initHash(err); 219 if ( U_FAILURE(err) ) { 220 return; 221 } 222 const char *locName = locale.getName(); 223 char parentLocale[ULOC_FULLNAME_CAPACITY]; 224 int32_t locNameLen; 225 uprv_strcpy(parentLocale, locName); 226 UErrorCode status = U_ZERO_ERROR; 227 Hashtable skeletonSet(FALSE, status); 228 if ( U_FAILURE(status) ) { 229 return; 230 } 231 232 // determine calendar type 233 const char * calendarTypeToUse = gGregorianTag; // initial default 234 char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well 235 char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; 236 // obtain a locale that always has the calendar key value that should be used 237 (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL, 238 "calendar", "calendar", locName, NULL, FALSE, &status); 239 localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination 240 // now get the calendar key value from that locale 241 int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status); 242 if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { 243 calendarTypeToUse = calendarType; 244 } 245 status = U_ZERO_ERROR; 246 247 do { 248 UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource; 249 rb = ures_open(NULL, parentLocale, &status); 250 calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); 251 calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status); 252 itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, 253 gIntervalDateTimePatternTag, NULL, &status); 254 255 if ( U_SUCCESS(status) ) { 256 // look for fallback first, since it establishes the default order 257 const UChar* resStr; 258 int32_t resStrLen = 0; 259 resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, 260 gFallbackPatternTag, 261 &resStrLen, &status); 262 if ( U_SUCCESS(status) ) { 263 UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen); 264 setFallbackIntervalPattern(pattern, status); 265 } 266 267 int32_t size = ures_getSize(itvDtPtnResource); 268 int32_t index; 269 for ( index = 0; index < size; ++index ) { 270 UResourceBundle* oneRes = ures_getByIndex(itvDtPtnResource, index, 271 NULL, &status); 272 if ( U_SUCCESS(status) ) { 273 const char* skeleton = ures_getKey(oneRes); 274 if ( skeleton == NULL || 275 skeletonSet.geti(UnicodeString(skeleton)) == 1 ) { 276 ures_close(oneRes); 277 continue; 278 } 279 skeletonSet.puti(UnicodeString(skeleton), 1, status); 280 if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) { 281 ures_close(oneRes); 282 continue; // fallback 283 } 284 285 UResourceBundle* intervalPatterns = ures_getByKey( 286 itvDtPtnResource, skeleton, NULL, &status); 287 288 if ( U_FAILURE(status) ) { 289 ures_close(intervalPatterns); 290 ures_close(oneRes); 291 break; 292 } 293 if ( intervalPatterns == NULL ) { 294 ures_close(intervalPatterns); 295 ures_close(oneRes); 296 continue; 297 } 298 299 const UChar* pattern; 300 const char* key; 301 int32_t ptLength; 302 int32_t ptnNum = ures_getSize(intervalPatterns); 303 int32_t ptnIndex; 304 for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) { 305 pattern = ures_getNextString(intervalPatterns, &ptLength, &key, 306 &status); 307 if ( U_FAILURE(status) ) { 308 break; 309 } 310 311 UCalendarDateFields calendarField = UCAL_FIELD_COUNT; 312 if ( !uprv_strcmp(key, "y") ) { 313 calendarField = UCAL_YEAR; 314 } else if ( !uprv_strcmp(key, "M") ) { 315 calendarField = UCAL_MONTH; 316 } else if ( !uprv_strcmp(key, "d") ) { 317 calendarField = UCAL_DATE; 318 } else if ( !uprv_strcmp(key, "a") ) { 319 calendarField = UCAL_AM_PM; 320 } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) { 321 calendarField = UCAL_HOUR; 322 } else if ( !uprv_strcmp(key, "m") ) { 323 calendarField = UCAL_MINUTE; 324 } 325 if ( calendarField != UCAL_FIELD_COUNT ) { 326 setIntervalPatternInternally(skeleton, calendarField, pattern,status); 327 } 328 } 329 ures_close(intervalPatterns); 330 } 331 ures_close(oneRes); 332 } 333 } 334 ures_close(itvDtPtnResource); 335 ures_close(calTypeBundle); 336 ures_close(calBundle); 337 ures_close(rb); 338 status = U_ZERO_ERROR; 339 locNameLen = uloc_getParent(parentLocale, parentLocale, 340 ULOC_FULLNAME_CAPACITY,&status); 341 } while ( locNameLen > 0 ); 342 } 343 344 345 346 void 347 DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton, 348 UCalendarDateFields lrgDiffCalUnit, 349 const UnicodeString& intervalPattern, 350 UErrorCode& status) { 351 IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status); 352 if ( U_FAILURE(status) ) { 353 return; 354 } 355 UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton)); 356 UBool emptyHash = false; 357 if ( patternsOfOneSkeleton == NULL ) { 358 patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX]; 359 emptyHash = true; 360 } 361 362 patternsOfOneSkeleton[index] = intervalPattern; 363 if ( emptyHash == TRUE ) { 364 fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status); 365 } 366 } 367 368 369 370 void 371 DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton, 372 int32_t* skeletonFieldWidth) { 373 const int8_t PATTERN_CHAR_BASE = 0x41; 374 int32_t i; 375 for ( i = 0; i < skeleton.length(); ++i ) { 376 // it is an ASCII char in skeleton 377 int8_t ch = (int8_t)skeleton.charAt(i); 378 ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE]; 379 } 380 } 381 382 383 384 UBool 385 DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth, 386 char patternLetter) { 387 if ( patternLetter == 'M' ) { 388 if ( (fieldWidth <= 2 && anotherFieldWidth > 2) || 389 (fieldWidth > 2 && anotherFieldWidth <= 2 )) { 390 return true; 391 } 392 } 393 return false; 394 } 395 396 397 398 const UnicodeString* 399 DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton, 400 int8_t& bestMatchDistanceInfo) const { 401 #ifdef DTITVINF_DEBUG 402 char result[1000]; 403 char result_1[1000]; 404 char mesg[2000]; 405 skeleton.extract(0, skeleton.length(), result, "UTF-8"); 406 sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result); 407 PRINTMESG(mesg) 408 #endif 409 410 411 int32_t inputSkeletonFieldWidth[] = 412 { 413 // A B C D E F G H I J K L M N O 414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 415 // P Q R S T U V W X Y Z 416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 417 // a b c d e f g h i j k l m n o 418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 419 // p q r s t u v w x y z 420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 421 }; 422 423 int32_t skeletonFieldWidth[] = 424 { 425 // A B C D E F G H I J K L M N O 426 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427 // P Q R S T U V W X Y Z 428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 429 // a b c d e f g h i j k l m n o 430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 431 // p q r s t u v w x y z 432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 433 }; 434 435 const int32_t DIFFERENT_FIELD = 0x1000; 436 const int32_t STRING_NUMERIC_DIFFERENCE = 0x100; 437 const int32_t BASE = 0x41; 438 const UChar CHAR_V = 0x0076; 439 const UChar CHAR_Z = 0x007A; 440 441 // hack for 'v' and 'z'. 442 // resource bundle only have time skeletons ending with 'v', 443 // but not for time skeletons ending with 'z'. 444 UBool replaceZWithV = false; 445 const UnicodeString* inputSkeleton = &skeleton; 446 UnicodeString copySkeleton; 447 if ( skeleton.indexOf(CHAR_Z) != -1 ) { 448 UChar zstr[2]; 449 UChar vstr[2]; 450 zstr[0]=CHAR_Z; 451 vstr[0]=CHAR_V; 452 zstr[1]=0; 453 vstr[1]=0; 454 copySkeleton = skeleton; 455 copySkeleton.findAndReplace(zstr, vstr); 456 inputSkeleton = ©Skeleton; 457 replaceZWithV = true; 458 } 459 460 parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth); 461 int32_t bestDistance = MAX_POSITIVE_INT; 462 const UnicodeString* bestSkeleton = NULL; 463 464 // 0 means exact the same skeletons; 465 // 1 means having the same field, but with different length, 466 // 2 means only z/v differs 467 // -1 means having different field. 468 bestMatchDistanceInfo = 0; 469 int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]); 470 471 int32_t pos = -1; 472 const UHashElement* elem = NULL; 473 while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) { 474 const UHashTok keyTok = elem->key; 475 UnicodeString* skeleton = (UnicodeString*)keyTok.pointer; 476 #ifdef DTITVINF_DEBUG 477 skeleton->extract(0, skeleton->length(), result, "UTF-8"); 478 sprintf(mesg, "available skeletons: skeleton: %s; \n", result); 479 PRINTMESG(mesg) 480 #endif 481 482 // clear skeleton field width 483 int8_t i; 484 for ( i = 0; i < fieldLength; ++i ) { 485 skeletonFieldWidth[i] = 0; 486 } 487 parseSkeleton(*skeleton, skeletonFieldWidth); 488 // calculate distance 489 int32_t distance = 0; 490 int8_t fieldDifference = 1; 491 for ( i = 0; i < fieldLength; ++i ) { 492 int32_t inputFieldWidth = inputSkeletonFieldWidth[i]; 493 int32_t fieldWidth = skeletonFieldWidth[i]; 494 if ( inputFieldWidth == fieldWidth ) { 495 continue; 496 } 497 if ( inputFieldWidth == 0 ) { 498 fieldDifference = -1; 499 distance += DIFFERENT_FIELD; 500 } else if ( fieldWidth == 0 ) { 501 fieldDifference = -1; 502 distance += DIFFERENT_FIELD; 503 } else if (stringNumeric(inputFieldWidth, fieldWidth, 504 (char)(i+BASE) ) ) { 505 distance += STRING_NUMERIC_DIFFERENCE; 506 } else { 507 distance += (inputFieldWidth > fieldWidth) ? 508 (inputFieldWidth - fieldWidth) : 509 (fieldWidth - inputFieldWidth); 510 } 511 } 512 if ( distance < bestDistance ) { 513 bestSkeleton = skeleton; 514 bestDistance = distance; 515 bestMatchDistanceInfo = fieldDifference; 516 } 517 if ( distance == 0 ) { 518 bestMatchDistanceInfo = 0; 519 break; 520 } 521 } 522 if ( replaceZWithV && bestMatchDistanceInfo != -1 ) { 523 bestMatchDistanceInfo = 2; 524 } 525 return bestSkeleton; 526 } 527 528 529 530 DateIntervalInfo::IntervalPatternIndex 531 DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field, 532 UErrorCode& status) { 533 if ( U_FAILURE(status) ) { 534 return kIPI_MAX_INDEX; 535 } 536 IntervalPatternIndex index = kIPI_MAX_INDEX; 537 switch ( field ) { 538 case UCAL_ERA: 539 index = kIPI_ERA; 540 break; 541 case UCAL_YEAR: 542 index = kIPI_YEAR; 543 break; 544 case UCAL_MONTH: 545 index = kIPI_MONTH; 546 break; 547 case UCAL_DATE: 548 case UCAL_DAY_OF_WEEK: 549 //case UCAL_DAY_OF_MONTH: 550 index = kIPI_DATE; 551 break; 552 case UCAL_AM_PM: 553 index = kIPI_AM_PM; 554 break; 555 case UCAL_HOUR: 556 case UCAL_HOUR_OF_DAY: 557 index = kIPI_HOUR; 558 break; 559 case UCAL_MINUTE: 560 index = kIPI_MINUTE; 561 break; 562 default: 563 status = U_ILLEGAL_ARGUMENT_ERROR; 564 } 565 return index; 566 } 567 568 569 570 void 571 DateIntervalInfo::deleteHash(Hashtable* hTable) 572 { 573 if ( hTable == NULL ) { 574 return; 575 } 576 int32_t pos = -1; 577 const UHashElement* element = NULL; 578 while ( (element = hTable->nextElement(pos)) != NULL ) { 579 const UHashTok keyTok = element->key; 580 const UHashTok valueTok = element->value; 581 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 582 delete[] value; 583 } 584 delete fIntervalPatterns; 585 } 586 587 588 U_CDECL_BEGIN 589 590 /** 591 * set hash table value comparator 592 * 593 * @param val1 one value in comparison 594 * @param val2 the other value in comparison 595 * @return TRUE if 2 values are the same, FALSE otherwise 596 */ 597 static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2); 598 599 static UBool 600 U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) { 601 const UnicodeString* pattern1 = (UnicodeString*)val1.pointer; 602 const UnicodeString* pattern2 = (UnicodeString*)val2.pointer; 603 UBool ret = TRUE; 604 int8_t i; 605 for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) { 606 ret = (pattern1[i] == pattern2[i]); 607 } 608 return ret; 609 } 610 611 U_CDECL_END 612 613 614 Hashtable* 615 DateIntervalInfo::initHash(UErrorCode& status) { 616 if ( U_FAILURE(status) ) { 617 return NULL; 618 } 619 Hashtable* hTable; 620 if ( (hTable = new Hashtable(FALSE, status)) == NULL ) { 621 status = U_MEMORY_ALLOCATION_ERROR; 622 return NULL; 623 } 624 hTable->setValueComparator(dtitvinfHashTableValueComparator); 625 return hTable; 626 } 627 628 629 void 630 DateIntervalInfo::copyHash(const Hashtable* source, 631 Hashtable* target, 632 UErrorCode& status) { 633 if ( U_FAILURE(status) ) { 634 return; 635 } 636 int32_t pos = -1; 637 const UHashElement* element = NULL; 638 if ( source ) { 639 while ( (element = source->nextElement(pos)) != NULL ) { 640 const UHashTok keyTok = element->key; 641 const UnicodeString* key = (UnicodeString*)keyTok.pointer; 642 const UHashTok valueTok = element->value; 643 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 644 UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX]; 645 int8_t i; 646 for ( i = 0; i < kIPI_MAX_INDEX; ++i ) { 647 copy[i] = value[i]; 648 } 649 target->put(UnicodeString(*key), copy, status); 650 if ( U_FAILURE(status) ) { 651 return; 652 } 653 } 654 } 655 } 656 657 658 U_NAMESPACE_END 659 660 #endif 661