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