OLD | NEW |
1 /* | 1 /* |
2 ****************************************************************************** | 2 ****************************************************************************** |
3 * Copyright (C) 1997-2014, International Business Machines Corporation and | 3 * Copyright (C) 1997-2015, International Business Machines Corporation and |
4 * others. All Rights Reserved. | 4 * others. All Rights Reserved. |
5 ****************************************************************************** | 5 ****************************************************************************** |
6 * | 6 * |
7 * File URESBUND.C | 7 * File uresbund.cpp |
8 * | 8 * |
9 * Modification History: | 9 * Modification History: |
10 * | 10 * |
11 * Date Name Description | 11 * Date Name Description |
12 * 04/01/97 aliu Creation. | 12 * 04/01/97 aliu Creation. |
13 * 06/14/99 stephen Removed functions taking a filename suffix. | 13 * 06/14/99 stephen Removed functions taking a filename suffix. |
14 * 07/20/99 stephen Changed for UResourceBundle typedef'd to void* | 14 * 07/20/99 stephen Changed for UResourceBundle typedef'd to void* |
15 * 11/09/99 weiv Added ures_getLocale() | 15 * 11/09/99 weiv Added ures_getLocale() |
16 * March 2000 weiv Total overhaul - using data in DLLs | 16 * March 2000 weiv Total overhaul - using data in DLLs |
17 * 06/20/2000 helena OS/400 port changes; mostly typecast. | 17 * 06/20/2000 helena OS/400 port changes; mostly typecast. |
(...skipping 29 matching lines...) Expand all Loading... |
47 static icu::UInitOnce gCacheInitOnce; | 47 static icu::UInitOnce gCacheInitOnce; |
48 | 48 |
49 static UMutex resbMutex = U_MUTEX_INITIALIZER; | 49 static UMutex resbMutex = U_MUTEX_INITIALIZER; |
50 | 50 |
51 /* INTERNAL: hashes an entry */ | 51 /* INTERNAL: hashes an entry */ |
52 static int32_t U_CALLCONV hashEntry(const UHashTok parm) { | 52 static int32_t U_CALLCONV hashEntry(const UHashTok parm) { |
53 UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer; | 53 UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer; |
54 UHashTok namekey, pathkey; | 54 UHashTok namekey, pathkey; |
55 namekey.pointer = b->fName; | 55 namekey.pointer = b->fName; |
56 pathkey.pointer = b->fPath; | 56 pathkey.pointer = b->fPath; |
57 return uhash_hashChars(namekey)+37*uhash_hashChars(pathkey); | 57 return uhash_hashChars(namekey)+37u*uhash_hashChars(pathkey); |
58 } | 58 } |
59 | 59 |
60 /* INTERNAL: compares two entries */ | 60 /* INTERNAL: compares two entries */ |
61 static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) { | 61 static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) { |
62 UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer; | 62 UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer; |
63 UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer; | 63 UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer; |
64 UHashTok name1, name2, path1, path2; | 64 UHashTok name1, name2, path1, path2; |
65 name1.pointer = b1->fName; | 65 name1.pointer = b1->fName; |
66 name2.pointer = b2->fName; | 66 name2.pointer = b2->fName; |
67 path1.pointer = b1->fPath; | 67 path1.pointer = b1->fPath; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 */ | 180 */ |
181 umtx_lock(&resbMutex); | 181 umtx_lock(&resbMutex); |
182 if (cache == NULL) { | 182 if (cache == NULL) { |
183 umtx_unlock(&resbMutex); | 183 umtx_unlock(&resbMutex); |
184 return 0; | 184 return 0; |
185 } | 185 } |
186 | 186 |
187 do { | 187 do { |
188 deletedMore = FALSE; | 188 deletedMore = FALSE; |
189 /*creates an enumeration to iterate through every element in the table *
/ | 189 /*creates an enumeration to iterate through every element in the table *
/ |
190 pos = -1; | 190 pos = UHASH_FIRST; |
191 while ((e = uhash_nextElement(cache, &pos)) != NULL) | 191 while ((e = uhash_nextElement(cache, &pos)) != NULL) |
192 { | 192 { |
193 resB = (UResourceDataEntry *) e->value.pointer; | 193 resB = (UResourceDataEntry *) e->value.pointer; |
194 /* Deletes only if reference counter == 0 | 194 /* Deletes only if reference counter == 0 |
195 * Don't worry about the children of this node. | 195 * Don't worry about the children of this node. |
196 * Those will eventually get deleted too, if not already. | 196 * Those will eventually get deleted too, if not already. |
197 * Don't worry about the parents of this node. | 197 * Don't worry about the parents of this node. |
198 * Those will eventually get deleted too, if not already. | 198 * Those will eventually get deleted too, if not already. |
199 */ | 199 */ |
200 /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's
not zero, that means that */ | 200 /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's
not zero, that means that */ |
(...skipping 14 matching lines...) Expand all Loading... |
215 umtx_unlock(&resbMutex); | 215 umtx_unlock(&resbMutex); |
216 | 216 |
217 return rbDeletedNum; | 217 return rbDeletedNum; |
218 } | 218 } |
219 | 219 |
220 #ifdef URES_DEBUG | 220 #ifdef URES_DEBUG |
221 #include <stdio.h> | 221 #include <stdio.h> |
222 | 222 |
223 U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) { | 223 U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) { |
224 UBool cacheNotEmpty = FALSE; | 224 UBool cacheNotEmpty = FALSE; |
225 int32_t pos = -1; | 225 int32_t pos = UHASH_FIRST; |
226 const UHashElement *e; | 226 const UHashElement *e; |
227 UResourceDataEntry *resB; | 227 UResourceDataEntry *resB; |
228 | 228 |
229 umtx_lock(&resbMutex); | 229 umtx_lock(&resbMutex); |
230 if (cache == NULL) { | 230 if (cache == NULL) { |
231 umtx_unlock(&resbMutex); | 231 umtx_unlock(&resbMutex); |
232 fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__); | 232 fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__); |
233 return FALSE; | 233 return FALSE; |
234 } | 234 } |
235 | 235 |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 *status = U_USING_FALLBACK_WARNING; | 370 *status = U_USING_FALLBACK_WARNING; |
371 r->fBogus = U_USING_FALLBACK_WARNING; | 371 r->fBogus = U_USING_FALLBACK_WARNING; |
372 } else { /* if we have a regular entry */ | 372 } else { /* if we have a regular entry */ |
373 Resource aliasres; | 373 Resource aliasres; |
374 if (r->fData.usesPoolBundle) { | 374 if (r->fData.usesPoolBundle) { |
375 r->fPool = getPoolEntry(r->fPath, status); | 375 r->fPool = getPoolEntry(r->fPath, status); |
376 if (U_SUCCESS(*status)) { | 376 if (U_SUCCESS(*status)) { |
377 const int32_t *poolIndexes = r->fPool->fData.pRoot + 1; | 377 const int32_t *poolIndexes = r->fPool->fData.pRoot + 1; |
378 if(r->fData.pRoot[1 + URES_INDEX_POOL_CHECKSUM] == poolIndex
es[URES_INDEX_POOL_CHECKSUM]) { | 378 if(r->fData.pRoot[1 + URES_INDEX_POOL_CHECKSUM] == poolIndex
es[URES_INDEX_POOL_CHECKSUM]) { |
379 r->fData.poolBundleKeys = (const char *)(poolIndexes + (
poolIndexes[URES_INDEX_LENGTH] & 0xff)); | 379 r->fData.poolBundleKeys = (const char *)(poolIndexes + (
poolIndexes[URES_INDEX_LENGTH] & 0xff)); |
| 380 r->fData.poolBundleStrings = r->fPool->fData.p16BitUnits
; |
380 } else { | 381 } else { |
381 r->fBogus = *status = U_INVALID_FORMAT_ERROR; | 382 r->fBogus = *status = U_INVALID_FORMAT_ERROR; |
382 } | 383 } |
383 } else { | 384 } else { |
384 r->fBogus = *status; | 385 r->fBogus = *status; |
385 } | 386 } |
386 } | 387 } |
387 if (U_SUCCESS(*status)) { | 388 if (U_SUCCESS(*status)) { |
388 /* handle the alias by trying to get out the %%Alias tag.*/ | 389 /* handle the alias by trying to get out the %%Alias tag.*/ |
389 /* We'll try to get alias string from the bundle */ | 390 /* We'll try to get alias string from the bundle */ |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 if( U_SUCCESS(*status) && | 440 if( U_SUCCESS(*status) && |
440 (poolBundle == NULL || poolBundle->fBogus != U_ZERO_ERROR || !poolBundle
->fData.isPoolBundle) | 441 (poolBundle == NULL || poolBundle->fBogus != U_ZERO_ERROR || !poolBundle
->fData.isPoolBundle) |
441 ) { | 442 ) { |
442 *status = U_INVALID_FORMAT_ERROR; | 443 *status = U_INVALID_FORMAT_ERROR; |
443 } | 444 } |
444 return poolBundle; | 445 return poolBundle; |
445 } | 446 } |
446 | 447 |
447 /* INTERNAL: */ | 448 /* INTERNAL: */ |
448 /* CAUTION: resbMutex must be locked when calling this function! */ | 449 /* CAUTION: resbMutex must be locked when calling this function! */ |
449 static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool
*isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) { | 450 static UResourceDataEntry * |
| 451 findFirstExisting(const char* path, char* name, |
| 452 UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode
* status) { |
450 UResourceDataEntry *r = NULL; | 453 UResourceDataEntry *r = NULL; |
451 UBool hasRealData = FALSE; | 454 UBool hasRealData = FALSE; |
452 const char *defaultLoc = uloc_getDefault(); | 455 const char *defaultLoc = uloc_getDefault(); |
453 *hasChopped = TRUE; /* we're starting with a fresh name */ | 456 *hasChopped = TRUE; /* we're starting with a fresh name */ |
454 | 457 |
455 while(*hasChopped && !hasRealData) { | 458 while(*hasChopped && !hasRealData) { |
456 r = init_entry(name, path, status); | 459 r = init_entry(name, path, status); |
457 /* Null pointer test */ | 460 /* Null pointer test */ |
458 if (U_FAILURE(*status)) { | 461 if (U_FAILURE(*status)) { |
459 return NULL; | 462 return NULL; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 static UBool ures_isStackObject(const UResourceBundle* resB) { | 498 static UBool ures_isStackObject(const UResourceBundle* resB) { |
496 return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE); | 499 return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE); |
497 } | 500 } |
498 | 501 |
499 | 502 |
500 U_CFUNC void ures_initStackObject(UResourceBundle* resB) { | 503 U_CFUNC void ures_initStackObject(UResourceBundle* resB) { |
501 uprv_memset(resB, 0, sizeof(UResourceBundle)); | 504 uprv_memset(resB, 0, sizeof(UResourceBundle)); |
502 ures_setIsStackObject(resB, TRUE); | 505 ures_setIsStackObject(resB, TRUE); |
503 } | 506 } |
504 | 507 |
505 static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
rorCode* status) { | 508 static UBool // returns U_SUCCESS(*status) |
| 509 loadParentsExceptRoot(UResourceDataEntry *&t1, |
| 510 char name[], int32_t nameCapacity, |
| 511 UBool usingUSRData, char usrDataPath[], UErrorCode *status
) { |
| 512 if (U_FAILURE(*status)) { return FALSE; } |
| 513 UBool hasChopped = TRUE; |
| 514 while (hasChopped && t1->fParent == NULL && !t1->fData.noFallback && |
| 515 res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) { |
| 516 Resource parentRes = res_getResource(&t1->fData, "%%Parent"); |
| 517 if (parentRes != RES_BOGUS) { // An explicit parent was found. |
| 518 int32_t parentLocaleLen = 0; |
| 519 const UChar *parentLocaleName = res_getString(&(t1->fData), parentRe
s, &parentLocaleLen); |
| 520 if(parentLocaleName != NULL && 0 < parentLocaleLen && parentLocaleLe
n < nameCapacity) { |
| 521 u_UCharsToChars(parentLocaleName, name, parentLocaleLen + 1); |
| 522 if (uprv_strcmp(name, kRootLocaleName) == 0) { |
| 523 return TRUE; |
| 524 } |
| 525 } |
| 526 } |
| 527 // Insert regular parents. |
| 528 UErrorCode parentStatus = U_ZERO_ERROR; |
| 529 UResourceDataEntry *t2 = init_entry(name, t1->fPath, &parentStatus); |
| 530 if (U_FAILURE(parentStatus)) { |
| 531 *status = parentStatus; |
| 532 return FALSE; |
| 533 } |
| 534 UResourceDataEntry *u2 = NULL; |
| 535 UErrorCode usrStatus = U_ZERO_ERROR; |
| 536 if (usingUSRData) { // This code inserts user override data into the in
heritance chain. |
| 537 u2 = init_entry(name, usrDataPath, &usrStatus); |
| 538 } |
| 539 |
| 540 if (usingUSRData && U_SUCCESS(usrStatus) && u2->fBogus == U_ZERO_ERROR)
{ |
| 541 t1->fParent = u2; |
| 542 u2->fParent = t2; |
| 543 } else { |
| 544 t1->fParent = t2; |
| 545 if (usingUSRData) { |
| 546 // The USR override data wasn't found, set it to be deleted. |
| 547 u2->fCountExisting = 0; |
| 548 } |
| 549 } |
| 550 t1 = t2; |
| 551 hasChopped = chopLocale(name); |
| 552 } |
| 553 return TRUE; |
| 554 } |
| 555 |
| 556 static UBool // returns U_SUCCESS(*status) |
| 557 insertRootBundle(UResourceDataEntry *&t1, UErrorCode *status) { |
| 558 if (U_FAILURE(*status)) { return FALSE; } |
| 559 UErrorCode parentStatus = U_ZERO_ERROR; |
| 560 UResourceDataEntry *t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatu
s); |
| 561 if (U_FAILURE(parentStatus)) { |
| 562 *status = parentStatus; |
| 563 return FALSE; |
| 564 } |
| 565 t1->fParent = t2; |
| 566 t1 = t2; |
| 567 return TRUE; |
| 568 } |
| 569 |
| 570 enum UResOpenType { |
| 571 /** |
| 572 * Open a resource bundle for the locale; |
| 573 * if there is not even a base language bundle, then fall back to the defaul
t locale; |
| 574 * if there is no bundle for that either, then load the root bundle. |
| 575 * |
| 576 * This is the default bundle loading behavior. |
| 577 */ |
| 578 URES_OPEN_LOCALE_DEFAULT_ROOT, |
| 579 // TODO: ICU ticket #11271 "consistent default locale across locale trees" |
| 580 // Add an option to look at the main locale tree for whether to |
| 581 // fall back to root directly (if the locale has main data) or |
| 582 // fall back to the default locale first (if the locale does not even have m
ain data). |
| 583 /** |
| 584 * Open a resource bundle for the locale; |
| 585 * if there is not even a base language bundle, then load the root bundle; |
| 586 * never fall back to the default locale. |
| 587 * |
| 588 * This is used for algorithms that have good pan-Unicode default behavior, |
| 589 * such as case mappings, collation, and segmentation (BreakIterator). |
| 590 */ |
| 591 URES_OPEN_LOCALE_ROOT, |
| 592 /** |
| 593 * Open a resource bundle for the exact bundle name as requested; |
| 594 * no fallbacks, do not load parent bundles. |
| 595 * |
| 596 * This is used for supplemental (non-locale) data. |
| 597 */ |
| 598 URES_OPEN_DIRECT |
| 599 }; |
| 600 typedef enum UResOpenType UResOpenType; |
| 601 |
| 602 static UResourceDataEntry *entryOpen(const char* path, const char* localeID, |
| 603 UResOpenType openType, UErrorCode* status)
{ |
| 604 U_ASSERT(openType != URES_OPEN_DIRECT); |
506 UErrorCode intStatus = U_ZERO_ERROR; | 605 UErrorCode intStatus = U_ZERO_ERROR; |
507 UErrorCode parentStatus = U_ZERO_ERROR; | |
508 UErrorCode usrStatus = U_ZERO_ERROR; | |
509 UResourceDataEntry *r = NULL; | 606 UResourceDataEntry *r = NULL; |
510 UResourceDataEntry *t1 = NULL; | 607 UResourceDataEntry *t1 = NULL; |
511 UResourceDataEntry *t2 = NULL; | |
512 UResourceDataEntry *u1 = NULL; | |
513 UResourceDataEntry *u2 = NULL; | |
514 UBool isDefault = FALSE; | 608 UBool isDefault = FALSE; |
515 UBool isRoot = FALSE; | 609 UBool isRoot = FALSE; |
516 UBool hasRealData = FALSE; | 610 UBool hasRealData = FALSE; |
517 UBool hasChopped = TRUE; | 611 UBool hasChopped = TRUE; |
518 UBool usingUSRData = U_USE_USRDATA && ( path == NULL || uprv_strncmp(path,U_
ICUDATA_NAME,8) == 0); | 612 UBool usingUSRData = U_USE_USRDATA && ( path == NULL || uprv_strncmp(path,U_
ICUDATA_NAME,8) == 0); |
519 | 613 |
520 char name[ULOC_FULLNAME_CAPACITY]; | 614 char name[ULOC_FULLNAME_CAPACITY]; |
521 char usrDataPath[96]; | 615 char usrDataPath[96]; |
522 | 616 |
523 initCache(status); | 617 initCache(status); |
(...skipping 19 matching lines...) Expand all Loading... |
543 | 637 |
544 umtx_lock(&resbMutex); | 638 umtx_lock(&resbMutex); |
545 { /* umtx_lock */ | 639 { /* umtx_lock */ |
546 /* We're going to skip all the locales that do not have any data */ | 640 /* We're going to skip all the locales that do not have any data */ |
547 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &int
Status); | 641 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &int
Status); |
548 | 642 |
549 if(r != NULL) { /* if there is one real locale, we can look for parents.
*/ | 643 if(r != NULL) { /* if there is one real locale, we can look for parents.
*/ |
550 t1 = r; | 644 t1 = r; |
551 hasRealData = TRUE; | 645 hasRealData = TRUE; |
552 if ( usingUSRData ) { /* This code inserts user override data into
the inheritance chain */ | 646 if ( usingUSRData ) { /* This code inserts user override data into
the inheritance chain */ |
553 u1 = init_entry(t1->fName, usrDataPath, &usrStatus); | 647 UErrorCode usrStatus = U_ZERO_ERROR; |
| 648 UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usr
Status); |
554 if ( u1 != NULL ) { | 649 if ( u1 != NULL ) { |
555 if(u1->fBogus == U_ZERO_ERROR) { | 650 if(u1->fBogus == U_ZERO_ERROR) { |
556 u1->fParent = t1; | 651 u1->fParent = t1; |
557 r = u1; | 652 r = u1; |
558 } else { | 653 } else { |
559 /* the USR override data wasn't found, set it to be deleted *
/ | 654 /* the USR override data wasn't found, set it to be deleted *
/ |
560 u1->fCountExisting = 0; | 655 u1->fCountExisting = 0; |
561 } | 656 } |
562 } | 657 } |
563 } | 658 } |
564 while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.no
Fallback) { | 659 if (hasChopped && !isRoot) { |
565 if ( res_getResource(&t1->fData,"%%Parent") != RES_BOGUS) { /* A
n explicit parent was found */ | 660 if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingU
SRData, usrDataPath, status)) { |
566 int32_t parentLocaleLen = 0; | |
567 const UChar *parentLocaleName = res_getString(&(t1->fData),
res_getResource(&t1->fData,"%%Parent") , &parentLocaleLen); | |
568 if(parentLocaleName != NULL && parentLocaleLen > 0) { | |
569 u_UCharsToChars(parentLocaleName, name, parentLocaleLen+
1); | |
570 if ( !uprv_strcmp(name,"root") ) { /* If parent is root,
we just terminate the loop */ | |
571 hasChopped = FALSE; | |
572 continue; | |
573 } | |
574 } | |
575 } | |
576 /* insert regular parents */ | |
577 t2 = init_entry(name, t1->fPath, &parentStatus); | |
578 if ( usingUSRData ) { /* This code inserts user override data i
nto the inheritance chain */ | |
579 usrStatus = U_ZERO_ERROR; | |
580 u2 = init_entry(name, usrDataPath, &usrStatus); | |
581 } | |
582 /* Check for null pointer. */ | |
583 if (t2 == NULL || ( usingUSRData && u2 == NULL)) { | |
584 *status = U_MEMORY_ALLOCATION_ERROR; | |
585 goto finishUnlock; | 661 goto finishUnlock; |
586 } | 662 } |
587 | |
588 if ( usingUSRData && u2->fBogus == U_ZERO_ERROR ) { | |
589 t1->fParent = u2; | |
590 u2->fParent = t2; | |
591 } else { | |
592 t1->fParent = t2; | |
593 if(usingUSRData) { | |
594 /* the USR override data wasn't found, set it to be dele
ted */ | |
595 u2->fCountExisting = 0; | |
596 } | |
597 } | |
598 t1 = t2; | |
599 hasChopped = chopLocale(name); | |
600 } | 663 } |
601 } | 664 } |
602 | 665 |
603 /* we could have reached this point without having any real data */ | 666 /* we could have reached this point without having any real data */ |
604 /* if that is the case, we need to chain in the default locale */ | 667 /* if that is the case, we need to chain in the default locale */ |
605 if(r==NULL && !isDefault && !isRoot /*&& t1->fParent == NULL*/) { | 668 if(r==NULL && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault &&
!isRoot) { |
606 /* insert default locale */ | 669 /* insert default locale */ |
607 uprv_strcpy(name, uloc_getDefault()); | 670 uprv_strcpy(name, uloc_getDefault()); |
608 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault,
&intStatus); | 671 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault,
&intStatus); |
609 intStatus = U_USING_DEFAULT_WARNING; | 672 intStatus = U_USING_DEFAULT_WARNING; |
610 if(r != NULL) { /* the default locale exists */ | 673 if(r != NULL) { /* the default locale exists */ |
611 t1 = r; | 674 t1 = r; |
612 hasRealData = TRUE; | 675 hasRealData = TRUE; |
613 isDefault = TRUE; | 676 isDefault = TRUE; |
614 while (hasChopped && t1->fParent == NULL) { | 677 // TODO: Why not if (usingUSRData) { ... } like in the non-defau
lt-locale code path? |
615 if ( res_getResource(&t1->fData,"%%Parent") != RES_BOGUS) {
/* An explicit parent was found */ | 678 if (hasChopped && !isRoot) { |
616 int32_t parentLocaleLen = 0; | 679 if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), us
ingUSRData, usrDataPath, status)) { |
617 const UChar *parentLocaleName = res_getString(&(t1->fDat
a), res_getResource(&t1->fData,"%%Parent") , &parentLocaleLen); | |
618 if(parentLocaleName != NULL && parentLocaleLen > 0) { | |
619 u_UCharsToChars(parentLocaleName, name, parentLocale
Len+1); | |
620 if ( !uprv_strcmp(name,"root") ) { /* If parent is r
oot, we just terminate the loop */ | |
621 hasChopped = FALSE; | |
622 continue; | |
623 } | |
624 } | |
625 } | |
626 /* insert chopped defaults */ | |
627 t2 = init_entry(name, t1->fPath, &parentStatus); | |
628 /* Check for null pointer. */ | |
629 if (t2 == NULL) { | |
630 *status = U_MEMORY_ALLOCATION_ERROR; | |
631 goto finishUnlock; | 680 goto finishUnlock; |
632 } | 681 } |
633 | |
634 if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOG
US) { | |
635 t1->fParent = t2; | |
636 t1 = t2; | |
637 } | |
638 hasChopped = chopLocale(name); | |
639 } | 682 } |
640 } | 683 } |
641 } | 684 } |
642 | 685 |
643 /* we could still have r == NULL at this point - maybe even default loca
le is not */ | 686 /* we could still have r == NULL at this point - maybe even default loca
le is not */ |
644 /* present */ | 687 /* present */ |
645 if(r == NULL) { | 688 if(r == NULL) { |
646 uprv_strcpy(name, kRootLocaleName); | 689 uprv_strcpy(name, kRootLocaleName); |
647 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault,
&intStatus); | 690 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault,
&intStatus); |
648 if(r != NULL) { | 691 if(r != NULL) { |
649 t1 = r; | 692 t1 = r; |
650 intStatus = U_USING_DEFAULT_WARNING; | 693 intStatus = U_USING_DEFAULT_WARNING; |
651 hasRealData = TRUE; | 694 hasRealData = TRUE; |
652 } else { /* we don't even have the root locale */ | 695 } else { /* we don't even have the root locale */ |
653 *status = U_MISSING_RESOURCE_ERROR; | 696 *status = U_MISSING_RESOURCE_ERROR; |
654 goto finishUnlock; | 697 goto finishUnlock; |
655 } | 698 } |
656 } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1-
>fParent == NULL && !r->fData.noFallback) { | 699 } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && |
657 /* insert root locale */ | 700 t1->fParent == NULL && !r->fData.noFallback) { |
658 t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus); | 701 if (!insertRootBundle(t1, status)) { |
659 /* Check for null pointer. */ | |
660 if (t2 == NULL) { | |
661 *status = U_MEMORY_ALLOCATION_ERROR; | |
662 goto finishUnlock; | 702 goto finishUnlock; |
663 } | 703 } |
664 if(!hasRealData) { | 704 if(!hasRealData) { |
665 r->fBogus = U_USING_DEFAULT_WARNING; | 705 r->fBogus = U_USING_DEFAULT_WARNING; |
666 } | 706 } |
667 hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) || hasRealData); | |
668 t1->fParent = t2; | |
669 t1 = t2; | |
670 } | 707 } |
671 | 708 |
| 709 // TODO: Does this ever loop? |
672 while(r != NULL && !isRoot && t1->fParent != NULL) { | 710 while(r != NULL && !isRoot && t1->fParent != NULL) { |
673 t1->fParent->fCountExisting++; | 711 t1->fParent->fCountExisting++; |
674 t1 = t1->fParent; | 712 t1 = t1->fParent; |
675 hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) || hasRealData); | |
676 } | 713 } |
677 } /* umtx_lock */ | 714 } /* umtx_lock */ |
678 finishUnlock: | 715 finishUnlock: |
679 umtx_unlock(&resbMutex); | 716 umtx_unlock(&resbMutex); |
680 | 717 |
681 if(U_SUCCESS(*status)) { | 718 if(U_SUCCESS(*status)) { |
682 if(U_SUCCESS(parentStatus)) { | 719 if(intStatus != U_ZERO_ERROR) { |
683 if(intStatus != U_ZERO_ERROR) { | 720 *status = intStatus; |
684 *status = intStatus; | |
685 } | |
686 return r; | |
687 } else { | |
688 *status = parentStatus; | |
689 return NULL; | |
690 } | 721 } |
| 722 return r; |
691 } else { | 723 } else { |
692 return NULL; | 724 return NULL; |
693 } | 725 } |
694 } | 726 } |
695 | 727 |
| 728 /** |
| 729 * Version of entryOpen() and findFirstExisting() for ures_openDirect(), |
| 730 * with no fallbacks. |
| 731 * Parent and root locale bundles are loaded if |
| 732 * the requested bundle does not have the "nofallback" flag. |
| 733 */ |
| 734 static UResourceDataEntry * |
| 735 entryOpenDirect(const char* path, const char* localeID, UErrorCode* status) { |
| 736 initCache(status); |
| 737 if(U_FAILURE(*status)) { |
| 738 return NULL; |
| 739 } |
| 740 |
| 741 umtx_lock(&resbMutex); |
| 742 // findFirstExisting() without fallbacks. |
| 743 UResourceDataEntry *r = init_entry(localeID, path, status); |
| 744 if(U_SUCCESS(*status)) { |
| 745 if(r->fBogus != U_ZERO_ERROR) { |
| 746 r->fCountExisting--; |
| 747 r = NULL; |
| 748 } |
| 749 } else { |
| 750 r = NULL; |
| 751 } |
| 752 |
| 753 // Some code depends on the ures_openDirect() bundle to have a parent bundle
chain, |
| 754 // unless it is marked with "nofallback". |
| 755 UResourceDataEntry *t1 = r; |
| 756 if(r != NULL && uprv_strcmp(localeID, kRootLocaleName) != 0 && // not root |
| 757 r->fParent == NULL && !r->fData.noFallback && |
| 758 uprv_strlen(localeID) < ULOC_FULLNAME_CAPACITY) { |
| 759 char name[ULOC_FULLNAME_CAPACITY]; |
| 760 uprv_strcpy(name, localeID); |
| 761 if(!chopLocale(name) || uprv_strcmp(name, kRootLocaleName) == 0 || |
| 762 loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), FALSE, NULL
, status)) { |
| 763 if(uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NU
LL) { |
| 764 insertRootBundle(t1, status); |
| 765 } |
| 766 } |
| 767 if(U_FAILURE(*status)) { |
| 768 r = NULL; |
| 769 } |
| 770 } |
| 771 |
| 772 if(r != NULL) { |
| 773 // TODO: Does this ever loop? |
| 774 while(t1->fParent != NULL) { |
| 775 t1->fParent->fCountExisting++; |
| 776 t1 = t1->fParent; |
| 777 } |
| 778 } |
| 779 umtx_unlock(&resbMutex); |
| 780 return r; |
| 781 } |
696 | 782 |
697 /** | 783 /** |
698 * Functions to create and destroy resource bundles. | 784 * Functions to create and destroy resource bundles. |
699 * CAUTION: resbMutex must be locked when calling this function. | 785 * CAUTION: resbMutex must be locked when calling this function. |
700 */ | 786 */ |
701 /* INTERNAL: */ | 787 /* INTERNAL: */ |
702 static void entryCloseInt(UResourceDataEntry *resB) { | 788 static void entryCloseInt(UResourceDataEntry *resB) { |
703 UResourceDataEntry *p = resB; | 789 UResourceDataEntry *p = resB; |
704 | 790 |
705 while(resB != NULL) { | 791 while(resB != NULL) { |
(...skipping 1300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2006 #ifdef URES_DEBUG | 2092 #ifdef URES_DEBUG |
2007 U_CFUNC const char* ures_getPath(const UResourceBundle* resB) { | 2093 U_CFUNC const char* ures_getPath(const UResourceBundle* resB) { |
2008 if(resB == NULL) { | 2094 if(resB == NULL) { |
2009 return NULL; | 2095 return NULL; |
2010 } | 2096 } |
2011 | 2097 |
2012 return resB->fData->fPath; | 2098 return resB->fData->fPath; |
2013 } | 2099 } |
2014 #endif | 2100 #endif |
2015 | 2101 |
2016 /* OLD API implementation */ | 2102 static UResourceBundle* |
2017 | 2103 ures_openWithType(UResourceBundle *r, const char* path, const char* localeID, |
2018 /** | 2104 UResOpenType openType, UErrorCode* status) { |
2019 * API: This function is used to open a resource bundle | 2105 if(U_FAILURE(*status)) { |
2020 * proper fallback chaining is executed while initialization. | |
2021 * The result is stored in cache for later fallback search. | |
2022 */ | |
2023 U_CAPI void U_EXPORT2 | |
2024 ures_openFillIn(UResourceBundle *r, const char* path, | |
2025 const char* localeID, UErrorCode* status) { | |
2026 if(r == NULL) { | |
2027 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
2028 } else { | |
2029 UResourceDataEntry *firstData; | |
2030 UBool isStackObject = ures_isStackObject(r); | |
2031 char canonLocaleID[ULOC_FULLNAME_CAPACITY]; | |
2032 | |
2033 uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status)
; | |
2034 if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { | |
2035 *status = U_ILLEGAL_ARGUMENT_ERROR; | |
2036 return; | |
2037 } | |
2038 | |
2039 ures_closeBundle(r, FALSE); | |
2040 uprv_memset(r, 0, sizeof(UResourceBundle)); | |
2041 ures_setIsStackObject(r, isStackObject); | |
2042 r->fHasFallback = TRUE; | |
2043 r->fIsTopLevel = TRUE; | |
2044 r->fIndex = -1; | |
2045 r->fData = entryOpen(path, canonLocaleID, status); | |
2046 if(U_FAILURE(*status)) { | |
2047 return; | |
2048 } | |
2049 /* this is a quick fix to get regular data in bundle - until constructio
n is cleaned up */ | |
2050 firstData = r->fData; | |
2051 while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) { | |
2052 firstData = firstData->fParent; | |
2053 } | |
2054 uprv_memcpy(&r->fResData, &firstData->fData, sizeof(ResourceData)); | |
2055 r->fHasFallback=(UBool)!r->fResData.noFallback; | |
2056 r->fRes = r->fResData.rootRes; | |
2057 r->fSize = res_countArrayItems(&(r->fResData), r->fRes); | |
2058 r->fTopLevelData = r->fData; | |
2059 } | |
2060 } | |
2061 | |
2062 U_CAPI UResourceBundle* U_EXPORT2 | |
2063 ures_open(const char* path, | |
2064 const char* localeID, | |
2065 UErrorCode* status) | |
2066 { | |
2067 char canonLocaleID[ULOC_FULLNAME_CAPACITY]; | |
2068 UResourceDataEntry *hasData = NULL; | |
2069 UResourceBundle *r; | |
2070 | |
2071 if(status == NULL || U_FAILURE(*status)) { | |
2072 return NULL; | 2106 return NULL; |
2073 } | 2107 } |
2074 | 2108 |
2075 /* first "canonicalize" the locale ID */ | 2109 UResourceDataEntry *entry; |
2076 uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status); | 2110 if(openType != URES_OPEN_DIRECT) { |
2077 if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { | 2111 /* first "canonicalize" the locale ID */ |
2078 *status = U_ILLEGAL_ARGUMENT_ERROR; | 2112 char canonLocaleID[ULOC_FULLNAME_CAPACITY]; |
| 2113 uloc_getBaseName(localeID, canonLocaleID, UPRV_LENGTHOF(canonLocaleID),
status); |
| 2114 if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { |
| 2115 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 2116 return NULL; |
| 2117 } |
| 2118 entry = entryOpen(path, canonLocaleID, openType, status); |
| 2119 } else { |
| 2120 entry = entryOpenDirect(path, localeID, status); |
| 2121 } |
| 2122 if(U_FAILURE(*status)) { |
| 2123 return NULL; |
| 2124 } |
| 2125 if(entry == NULL) { |
| 2126 *status = U_MISSING_RESOURCE_ERROR; |
2079 return NULL; | 2127 return NULL; |
2080 } | 2128 } |
2081 | 2129 |
2082 r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); | 2130 UBool isStackObject; |
2083 if(r == NULL) { | 2131 if(r == NULL) { |
2084 *status = U_MEMORY_ALLOCATION_ERROR; | 2132 r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); |
2085 return NULL; | 2133 if(r == NULL) { |
2086 } | 2134 entryClose(entry); |
2087 | 2135 *status = U_MEMORY_ALLOCATION_ERROR; |
2088 uprv_memset(r, 0, sizeof(UResourceBundle)); | |
2089 r->fHasFallback = TRUE; | |
2090 r->fIsTopLevel = TRUE; | |
2091 ures_setIsStackObject(r, FALSE); | |
2092 r->fIndex = -1; | |
2093 r->fData = entryOpen(path, canonLocaleID, status); | |
2094 if(U_FAILURE(*status)) { | |
2095 uprv_free(r); | |
2096 return NULL; | |
2097 } | |
2098 r->fTopLevelData = r->fData; | |
2099 | |
2100 hasData = r->fData; | |
2101 while(hasData->fBogus != U_ZERO_ERROR) { | |
2102 hasData = hasData->fParent; | |
2103 if(hasData == NULL) { | |
2104 /* This can happen only if fallback chain gets broken by an act of God
*/ | |
2105 /* TODO: this unlikely to happen, consider removing it */ | |
2106 entryClose(r->fData); | |
2107 uprv_free(r); | |
2108 *status = U_MISSING_RESOURCE_ERROR; | |
2109 return NULL; | 2136 return NULL; |
2110 } | 2137 } |
| 2138 isStackObject = FALSE; |
| 2139 } else { // fill-in |
| 2140 isStackObject = ures_isStackObject(r); |
| 2141 ures_closeBundle(r, FALSE); |
2111 } | 2142 } |
| 2143 uprv_memset(r, 0, sizeof(UResourceBundle)); |
| 2144 ures_setIsStackObject(r, isStackObject); |
2112 | 2145 |
2113 uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData)); | 2146 r->fTopLevelData = r->fData = entry; |
2114 r->fHasFallback=(UBool)!r->fResData.noFallback; | 2147 uprv_memcpy(&r->fResData, &entry->fData, sizeof(ResourceData)); |
| 2148 r->fHasFallback = openType != URES_OPEN_DIRECT && !r->fResData.noFallback; |
| 2149 r->fIsTopLevel = TRUE; |
2115 r->fRes = r->fResData.rootRes; | 2150 r->fRes = r->fResData.rootRes; |
2116 r->fSize = res_countArrayItems(&(r->fResData), r->fRes); | 2151 r->fSize = res_countArrayItems(&(r->fResData), r->fRes); |
2117 /* | 2152 r->fIndex = -1; |
2118 if(r->fData->fPath != NULL) { | |
2119 ures_setResPath(r, r->fData->fPath); | |
2120 ures_appendResPath(r, RES_PATH_PACKAGE_S); | |
2121 ures_appendResPath(r, r->fData->fName); | |
2122 } else { | |
2123 ures_setResPath(r, r->fData->fName); | |
2124 } | |
2125 */ | |
2126 | |
2127 | 2153 |
2128 return r; | 2154 return r; |
2129 } | 2155 } |
2130 | 2156 |
| 2157 U_CAPI UResourceBundle* U_EXPORT2 |
| 2158 ures_open(const char* path, const char* localeID, UErrorCode* status) { |
| 2159 return ures_openWithType(NULL, path, localeID, URES_OPEN_LOCALE_DEFAULT_ROOT
, status); |
| 2160 } |
| 2161 |
| 2162 U_CAPI UResourceBundle* U_EXPORT2 |
| 2163 ures_openNoDefault(const char* path, const char* localeID, UErrorCode* status) { |
| 2164 return ures_openWithType(NULL, path, localeID, URES_OPEN_LOCALE_ROOT, status
); |
| 2165 } |
| 2166 |
2131 /** | 2167 /** |
2132 * Opens a resource bundle without "canonicalizing" the locale name. No fallbac
k will be performed | 2168 * Opens a resource bundle without "canonicalizing" the locale name. No fallbac
k will be performed |
2133 * or sought. However, alias substitution will happen! | 2169 * or sought. However, alias substitution will happen! |
2134 */ | 2170 */ |
2135 U_CAPI UResourceBundle* U_EXPORT2 | 2171 U_CAPI UResourceBundle* U_EXPORT2 |
2136 ures_openDirect(const char* path, const char* localeID, UErrorCode* status) { | 2172 ures_openDirect(const char* path, const char* localeID, UErrorCode* status) { |
2137 UResourceBundle *r; | 2173 return ures_openWithType(NULL, path, localeID, URES_OPEN_DIRECT, status); |
2138 UErrorCode subStatus = U_ZERO_ERROR; | |
2139 | |
2140 if(status == NULL || U_FAILURE(*status)) { | |
2141 return NULL; | |
2142 } | |
2143 | |
2144 r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); | |
2145 if(r == NULL) { | |
2146 *status = U_MEMORY_ALLOCATION_ERROR; | |
2147 return NULL; | |
2148 } | |
2149 | |
2150 r->fHasFallback = FALSE; | |
2151 r->fIsTopLevel = TRUE; | |
2152 ures_setIsStackObject(r, FALSE); | |
2153 r->fIndex = -1; | |
2154 r->fData = entryOpen(path, localeID, &subStatus); | |
2155 if(U_FAILURE(subStatus)) { | |
2156 *status = subStatus; | |
2157 uprv_free(r); | |
2158 return NULL; | |
2159 } | |
2160 if(subStatus != U_ZERO_ERROR /*r->fData->fBogus != U_ZERO_ERROR*/) { | |
2161 /* we didn't find one we were looking for - so openDirect */ | |
2162 /* should fail */ | |
2163 entryClose(r->fData); | |
2164 uprv_free(r); | |
2165 *status = U_MISSING_RESOURCE_ERROR; | |
2166 return NULL; | |
2167 } | |
2168 | |
2169 r->fKey = NULL; | |
2170 r->fVersion = NULL; | |
2171 uprv_memcpy(&r->fResData, &r->fData->fData, sizeof(ResourceData)); | |
2172 /* r->fHasFallback remains FALSE here in ures_openDirect() */ | |
2173 r->fRes = r->fResData.rootRes; | |
2174 /*r->fParent = RES_BOGUS;*/ | |
2175 r->fSize = res_countArrayItems(&(r->fResData), r->fRes); | |
2176 r->fResPath = NULL; | |
2177 r->fResPathLen = 0; | |
2178 /*r->fParentRes = NULL;*/ | |
2179 r->fTopLevelData = r->fData; | |
2180 | |
2181 return r; | |
2182 } | 2174 } |
2183 | 2175 |
2184 /** | 2176 /** |
| 2177 * API: This function is used to open a resource bundle |
| 2178 * proper fallback chaining is executed while initialization. |
| 2179 * The result is stored in cache for later fallback search. |
| 2180 */ |
| 2181 U_CAPI void U_EXPORT2 |
| 2182 ures_openFillIn(UResourceBundle *r, const char* path, |
| 2183 const char* localeID, UErrorCode* status) { |
| 2184 if(U_SUCCESS(*status) && r == NULL) { |
| 2185 *status = U_ILLEGAL_ARGUMENT_ERROR; |
| 2186 return; |
| 2187 } |
| 2188 ures_openWithType(r, path, localeID, URES_OPEN_LOCALE_DEFAULT_ROOT, status); |
| 2189 } |
| 2190 |
| 2191 /** |
2185 * API: Counts members. For arrays and tables, returns number of resources. | 2192 * API: Counts members. For arrays and tables, returns number of resources. |
2186 * For strings, returns 1. | 2193 * For strings, returns 1. |
2187 */ | 2194 */ |
2188 U_CAPI int32_t U_EXPORT2 | 2195 U_CAPI int32_t U_EXPORT2 |
2189 ures_countArrayItems(const UResourceBundle* resourceBundle, | 2196 ures_countArrayItems(const UResourceBundle* resourceBundle, |
2190 const char* resourceKey, | 2197 const char* resourceKey, |
2191 UErrorCode* status) | 2198 UErrorCode* status) |
2192 { | 2199 { |
2193 UResourceBundle resData; | 2200 UResourceBundle resData; |
2194 ures_initStackObject(&resData); | 2201 ures_initStackObject(&resData); |
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2879 ures_getVersionByKey(const UResourceBundle* res, const char *key, UVersionInfo v
er, UErrorCode *status) { | 2886 ures_getVersionByKey(const UResourceBundle* res, const char *key, UVersionInfo v
er, UErrorCode *status) { |
2880 const UChar *str; | 2887 const UChar *str; |
2881 int32_t len; | 2888 int32_t len; |
2882 str = ures_getStringByKey(res, key, &len, status); | 2889 str = ures_getStringByKey(res, key, &len, status); |
2883 if(U_SUCCESS(*status)) { | 2890 if(U_SUCCESS(*status)) { |
2884 u_versionFromUString(ver, str); | 2891 u_versionFromUString(ver, str); |
2885 } | 2892 } |
2886 } | 2893 } |
2887 | 2894 |
2888 /* eof */ | 2895 /* eof */ |
OLD | NEW |