Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: icu46/source/common/uresbund.c

Issue 5516007: Check in the pristine copy of ICU 4.6... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/third_party/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « icu46/source/common/ures_cnv.c ('k') | icu46/source/common/uresdata.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 /*
2 ******************************************************************************
3 * Copyright (C) 1997-2010, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 ******************************************************************************
6 *
7 * File URESBUND.C
8 *
9 * Modification History:
10 *
11 * Date Name Description
12 * 04/01/97 aliu Creation.
13 * 06/14/99 stephen Removed functions taking a filename suffix.
14 * 07/20/99 stephen Changed for UResourceBundle typedef'd to void*
15 * 11/09/99 weiv Added ures_getLocale()
16 * March 2000 weiv Total overhaul - using data in DLLs
17 * 06/20/2000 helena OS/400 port changes; mostly typecast.
18 * 06/24/02 weiv Added support for resource sharing
19 ******************************************************************************
20 */
21
22 #include "unicode/ustring.h"
23 #include "unicode/ucnv.h"
24 #include "uresimp.h"
25 #include "ustr_imp.h"
26 #include "cwchar.h"
27 #include "ucln_cmn.h"
28 #include "cmemory.h"
29 #include "cstring.h"
30 #include "uhash.h"
31 #include "unicode/uenum.h"
32 #include "uenumimp.h"
33 #include "ulocimp.h"
34 #include "umutex.h"
35 #include "putilimp.h"
36
37
38 /*
39 Static cache for already opened resource bundles - mostly for keeping fallback i nfo
40 TODO: This cache should probably be removed when the deprecated code is
41 completely removed.
42 */
43 static UHashtable *cache = NULL;
44
45 static UMTX resbMutex = NULL;
46
47 /* INTERNAL: hashes an entry */
48 static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
49 UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer;
50 UHashTok namekey, pathkey;
51 namekey.pointer = b->fName;
52 pathkey.pointer = b->fPath;
53 return uhash_hashChars(namekey)+37*uhash_hashChars(pathkey);
54 }
55
56 /* INTERNAL: compares two entries */
57 static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
58 UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer;
59 UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer;
60 UHashTok name1, name2, path1, path2;
61 name1.pointer = b1->fName;
62 name2.pointer = b2->fName;
63 path1.pointer = b1->fPath;
64 path2.pointer = b2->fPath;
65 return (UBool)(uhash_compareChars(name1, name2) &&
66 uhash_compareChars(path1, path2));
67 }
68
69
70 /**
71 * Internal function, gets parts of locale name according
72 * to the position of '_' character
73 */
74 static UBool chopLocale(char *name) {
75 char *i = uprv_strrchr(name, '_');
76
77 if(i != NULL) {
78 *i = '\0';
79 return TRUE;
80 }
81
82 return FALSE;
83 }
84
85 /**
86 * Internal function
87 */
88 static void entryIncrease(UResourceDataEntry *entry) {
89 umtx_lock(&resbMutex);
90 entry->fCountExisting++;
91 while(entry->fParent != NULL) {
92 entry = entry->fParent;
93 entry->fCountExisting++;
94 }
95 umtx_unlock(&resbMutex);
96 }
97
98 /**
99 * Internal function. Tries to find a resource in given Resource
100 * Bundle, as well as in its parents
101 */
102 static const ResourceData *getFallbackData(const UResourceBundle* resBundle, con st char* * resTag, UResourceDataEntry* *realData, Resource *res, UErrorCode *sta tus) {
103 UResourceDataEntry *resB = resBundle->fData;
104 int32_t indexR = -1;
105 int32_t i = 0;
106 *res = RES_BOGUS;
107 if(resB != NULL) {
108 if(resB->fBogus == U_ZERO_ERROR) { /* if this resource is real, */
109 *res = res_getTableItemByKey(&(resB->fData), resB->fData.rootRes, &i ndexR, resTag); /* try to get data from there */
110 i++;
111 }
112 if(resBundle->fHasFallback == TRUE) {
113 while(*res == RES_BOGUS && resB->fParent != NULL) { /* Otherwise, we 'll look in parents */
114 resB = resB->fParent;
115 if(resB->fBogus == U_ZERO_ERROR) {
116 i++;
117 *res = res_getTableItemByKey(&(resB->fData), resB->fData.roo tRes, &indexR, resTag);
118 }
119 }
120 }
121
122 if(*res != RES_BOGUS) { /* If the resource is found in parents, we need to adjust the error */
123 if(i>1) {
124 if(uprv_strcmp(resB->fName, uloc_getDefault())==0 || uprv_strcmp (resB->fName, kRootLocaleName)==0) {
125 *status = U_USING_DEFAULT_WARNING;
126 } else {
127 *status = U_USING_FALLBACK_WARNING;
128 }
129 }
130 *realData = resB;
131 return (&(resB->fData));
132 } else { /* If resource is not found, we need to give an error */
133 *status = U_MISSING_RESOURCE_ERROR;
134 return NULL;
135 }
136 } else {
137 *status = U_MISSING_RESOURCE_ERROR;
138 return NULL;
139 }
140 }
141
142 static void
143 free_entry(UResourceDataEntry *entry) {
144 UResourceDataEntry *alias;
145 res_unload(&(entry->fData));
146 if(entry->fName != NULL && entry->fName != entry->fNameBuffer) {
147 uprv_free(entry->fName);
148 }
149 if(entry->fPath != NULL) {
150 uprv_free(entry->fPath);
151 }
152 if(entry->fPool != NULL) {
153 --entry->fPool->fCountExisting;
154 }
155 alias = entry->fAlias;
156 if(alias != NULL) {
157 while(alias->fAlias != NULL) {
158 alias = alias->fAlias;
159 }
160 --alias->fCountExisting;
161 }
162 uprv_free(entry);
163 }
164
165 /* Works just like ucnv_flushCache() */
166 static int32_t ures_flushCache()
167 {
168 UResourceDataEntry *resB;
169 int32_t pos;
170 int32_t rbDeletedNum = 0;
171 const UHashElement *e;
172 UBool deletedMore;
173
174 /*if shared data hasn't even been lazy evaluated yet
175 * return 0
176 */
177 umtx_lock(&resbMutex);
178 if (cache == NULL) {
179 umtx_unlock(&resbMutex);
180 return 0;
181 }
182
183 do {
184 deletedMore = FALSE;
185 /*creates an enumeration to iterate through every element in the table * /
186 pos = -1;
187 while ((e = uhash_nextElement(cache, &pos)) != NULL)
188 {
189 resB = (UResourceDataEntry *) e->value.pointer;
190 /* Deletes only if reference counter == 0
191 * Don't worry about the children of this node.
192 * Those will eventually get deleted too, if not already.
193 * Don't worry about the parents of this node.
194 * Those will eventually get deleted too, if not already.
195 */
196 /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's not zero, that means that */
197 /* some resource bundles are still open somewhere. */
198
199 if (resB->fCountExisting == 0) {
200 rbDeletedNum++;
201 deletedMore = TRUE;
202 uhash_removeElement(cache, e);
203 free_entry(resB);
204 }
205 }
206 /*
207 * Do it again to catch bundles (aliases, pool bundle) whose fCountExist ing
208 * got decremented by free_entry().
209 */
210 } while(deletedMore);
211 umtx_unlock(&resbMutex);
212
213 return rbDeletedNum;
214 }
215
216 #ifdef URES_DEBUG
217 #include <stdio.h>
218
219 U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) {
220 UBool cacheNotEmpty = FALSE;
221 int32_t pos = -1;
222 const UHashElement *e;
223 UResourceDataEntry *resB;
224
225 umtx_lock(&resbMutex);
226 if (cache == NULL) {
227 umtx_unlock(&resbMutex);
228 fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__);
229 return FALSE;
230 }
231
232 while ((e = uhash_nextElement(cache, &pos)) != NULL) {
233 cacheNotEmpty=TRUE;
234 resB = (UResourceDataEntry *) e->value.pointer;
235 fprintf(stderr,"%s:%d: RB Cache: Entry @0x%p, refcount %d, name %s:%s. Po ol 0x%p, alias 0x%p, parent 0x%p\n",
236 __FILE__, __LINE__,
237 (void*)resB, resB->fCountExisting,
238 resB->fName?resB->fName:"NULL",
239 resB->fPath?resB->fPath:"NULL",
240 (void*)resB->fPool,
241 (void*)resB->fAlias,
242 (void*)resB->fParent);
243 }
244
245 fprintf(stderr,"%s:%d: RB Cache still contains %d items.\n", __FILE__, __LIN E__, uhash_count(cache));
246
247 umtx_unlock(&resbMutex);
248
249 return cacheNotEmpty;
250 }
251
252 #endif
253
254 static UBool U_CALLCONV ures_cleanup(void)
255 {
256 if (cache != NULL) {
257 ures_flushCache();
258 if (cache != NULL && uhash_count(cache) == 0) {
259 uhash_close(cache);
260 cache = NULL;
261 }
262 }
263 if (cache == NULL && resbMutex != NULL) {
264 umtx_destroy(&resbMutex);
265 }
266 return (cache == NULL);
267 }
268
269 /** INTERNAL: Initializes the cache for resources */
270 static void initCache(UErrorCode *status) {
271 UBool makeCache = FALSE;
272 UMTX_CHECK(&resbMutex, (cache == NULL), makeCache);
273 if(makeCache) {
274 UHashtable *newCache = uhash_open(hashEntry, compareEntries, NULL, statu s);
275 if (U_FAILURE(*status)) {
276 return;
277 }
278 umtx_lock(&resbMutex);
279 if(cache == NULL) {
280 cache = newCache;
281 newCache = NULL;
282 ucln_common_registerCleanup(UCLN_COMMON_URES, ures_cleanup);
283 }
284 umtx_unlock(&resbMutex);
285 if(newCache != NULL) {
286 uhash_close(newCache);
287 }
288 }
289 }
290
291 /** INTERNAL: sets the name (locale) of the resource bundle to given name */
292
293 static void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status ) {
294 int32_t len = (int32_t)uprv_strlen(name);
295 if(res->fName != NULL && res->fName != res->fNameBuffer) {
296 uprv_free(res->fName);
297 }
298 if (len < (int32_t)sizeof(res->fNameBuffer)) {
299 res->fName = res->fNameBuffer;
300 }
301 else {
302 res->fName = (char *)uprv_malloc(len+1);
303 }
304 if(res->fName == NULL) {
305 *status = U_MEMORY_ALLOCATION_ERROR;
306 } else {
307 uprv_strcpy(res->fName, name);
308 }
309 }
310
311 static UResourceDataEntry *
312 getPoolEntry(const char *path, UErrorCode *status);
313
314 /**
315 * INTERNAL: Inits and opens an entry from a data DLL.
316 * CAUTION: resbMutex must be locked when calling this function.
317 */
318 static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE rrorCode *status) {
319 UResourceDataEntry *r = NULL;
320 UResourceDataEntry find;
321 /*int32_t hashValue;*/
322 char name[96];
323 char aliasName[100] = { 0 };
324 int32_t aliasLen = 0;
325 /*UBool isAlias = FALSE;*/
326 UHashTok hashkey;
327
328 if(U_FAILURE(*status)) {
329 return NULL;
330 }
331
332 /* here we try to deduce the right locale name */
333 if(localeID == NULL) { /* if localeID is NULL, we're trying to open default locale */
334 uprv_strcpy(name, uloc_getDefault());
335 } else if(*localeID == 0) { /* if localeID is "" then we try to open root lo cale */
336 uprv_strcpy(name, kRootLocaleName);
337 } else { /* otherwise, we'll open what we're given */
338 uprv_strcpy(name, localeID);
339 }
340
341 find.fName = name;
342 find.fPath = (char *)path;
343
344 /* calculate the hash value of the entry */
345 hashkey.pointer = (void *)&find;
346 /*hashValue = hashEntry(hashkey);*/
347
348 /* check to see if we already have this entry */
349 r = (UResourceDataEntry *)uhash_get(cache, &find);
350 if(r == NULL) {
351 /* if the entry is not yet in the hash table, we'll try to construct a n ew one */
352 r = (UResourceDataEntry *) uprv_malloc(sizeof(UResourceDataEntry));
353 if(r == NULL) {
354 *status = U_MEMORY_ALLOCATION_ERROR;
355 return NULL;
356 }
357
358 uprv_memset(r, 0, sizeof(UResourceDataEntry));
359 /*r->fHashKey = hashValue;*/
360
361 setEntryName(r, name, status);
362 if (U_FAILURE(*status)) {
363 uprv_free(r);
364 return NULL;
365 }
366
367 if(path != NULL) {
368 r->fPath = (char *)uprv_strdup(path);
369 if(r->fPath == NULL) {
370 *status = U_MEMORY_ALLOCATION_ERROR;
371 uprv_free(r);
372 return NULL;
373 }
374 }
375
376 /* this is the actual loading */
377 res_load(&(r->fData), r->fPath, r->fName, status);
378
379 if (U_FAILURE(*status)) {
380 /* we have no such entry in dll, so it will always use fallback */
381 *status = U_USING_FALLBACK_WARNING;
382 r->fBogus = U_USING_FALLBACK_WARNING;
383 } else { /* if we have a regular entry */
384 Resource aliasres;
385 if (r->fData.usesPoolBundle) {
386 r->fPool = getPoolEntry(r->fPath, status);
387 if (U_SUCCESS(*status)) {
388 const int32_t *poolIndexes = r->fPool->fData.pRoot + 1;
389 if(r->fData.pRoot[1 + URES_INDEX_POOL_CHECKSUM] == poolIndex es[URES_INDEX_POOL_CHECKSUM]) {
390 r->fData.poolBundleKeys = (const char *)(poolIndexes + ( poolIndexes[URES_INDEX_LENGTH] & 0xff));
391 } else {
392 r->fBogus = *status = U_INVALID_FORMAT_ERROR;
393 }
394 } else {
395 r->fBogus = *status;
396 }
397 }
398 if (U_SUCCESS(*status)) {
399 /* handle the alias by trying to get out the %%Alias tag.*/
400 /* We'll try to get alias string from the bundle */
401 aliasres = res_getResource(&(r->fData), "%%ALIAS");
402 if (aliasres != RES_BOGUS) {
403 const UChar *alias = res_getString(&(r->fData), aliasres, &a liasLen);
404 if(alias != NULL && aliasLen > 0) { /* if there is actual al ias - unload and load new data */
405 u_UCharsToChars(alias, aliasName, aliasLen+1);
406 r->fAlias = init_entry(aliasName, path, status);
407 }
408 }
409 }
410 }
411
412 {
413 UResourceDataEntry *oldR = NULL;
414 if((oldR = (UResourceDataEntry *)uhash_get(cache, r)) == NULL) { /* if the data is not cached */
415 /* just insert it in the cache */
416 UErrorCode cacheStatus = U_ZERO_ERROR;
417 uhash_put(cache, (void *)r, r, &cacheStatus);
418 if (U_FAILURE(cacheStatus)) {
419 *status = cacheStatus;
420 free_entry(r);
421 r = NULL;
422 }
423 } else {
424 /* somebody have already inserted it while we were working, disc ard newly opened data */
425 /* Also, we could get here IF we opened an alias */
426 free_entry(r);
427 r = oldR;
428 }
429 }
430
431 }
432 if(r != NULL) {
433 /* return the real bundle */
434 while(r->fAlias != NULL) {
435 r = r->fAlias;
436 }
437 r->fCountExisting++; /* we increase its reference count */
438 /* if the resource has a warning */
439 /* we don't want to overwrite a status with no error */
440 if(r->fBogus != U_ZERO_ERROR && U_SUCCESS(*status)) {
441 *status = r->fBogus; /* set the returning status */
442 }
443 }
444 return r;
445 }
446
447 static UResourceDataEntry *
448 getPoolEntry(const char *path, UErrorCode *status) {
449 UResourceDataEntry *poolBundle = init_entry(kPoolBundleName, path, status);
450 if( U_SUCCESS(*status) &&
451 (poolBundle == NULL || poolBundle->fBogus != U_ZERO_ERROR || !poolBundle ->fData.isPoolBundle)
452 ) {
453 *status = U_INVALID_FORMAT_ERROR;
454 }
455 return poolBundle;
456 }
457
458 /* INTERNAL: */
459 /* CAUTION: resbMutex must be locked when calling this function! */
460 static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
461 UResourceDataEntry *r = NULL;
462 UBool hasRealData = FALSE;
463 const char *defaultLoc = uloc_getDefault();
464 *hasChopped = TRUE; /* we're starting with a fresh name */
465
466 while(*hasChopped && !hasRealData) {
467 r = init_entry(name, path, status);
468 /* Null pointer test */
469 if (U_FAILURE(*status)) {
470 return NULL;
471 }
472 *isDefault = (UBool)(uprv_strncmp(name, defaultLoc, uprv_strlen(name)) = = 0);
473 hasRealData = (UBool)(r->fBogus == U_ZERO_ERROR);
474 if(!hasRealData) {
475 /* this entry is not real. We will discard it. */
476 /* However, the parent line for this entry is */
477 /* not to be used - as there might be parent */
478 /* lines in cache from previous openings that */
479 /* are not updated yet. */
480 r->fCountExisting--;
481 /*entryCloseInt(r);*/
482 r = NULL;
483 *status = U_USING_FALLBACK_WARNING;
484 } else {
485 uprv_strcpy(name, r->fName); /* this is needed for supporting aliase s */
486 }
487
488 *isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName) == 0);
489
490 /*Fallback data stuff*/
491 *hasChopped = chopLocale(name);
492 }
493 return r;
494 }
495
496 static void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
497 if(state) {
498 resB->fMagic1 = 0;
499 resB->fMagic2 = 0;
500 } else {
501 resB->fMagic1 = MAGIC1;
502 resB->fMagic2 = MAGIC2;
503 }
504 }
505
506 static UBool ures_isStackObject(const UResourceBundle* resB) {
507 return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE);
508 }
509
510
511 U_CFUNC void ures_initStackObject(UResourceBundle* resB) {
512 uprv_memset(resB, 0, sizeof(UResourceBundle));
513 ures_setIsStackObject(resB, TRUE);
514 }
515
516 static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr rorCode* status) {
517 UErrorCode intStatus = U_ZERO_ERROR;
518 UErrorCode parentStatus = U_ZERO_ERROR;
519 UErrorCode usrStatus = U_ZERO_ERROR;
520 UResourceDataEntry *r = NULL;
521 UResourceDataEntry *t1 = NULL;
522 UResourceDataEntry *t2 = NULL;
523 UResourceDataEntry *u1 = NULL;
524 UResourceDataEntry *u2 = NULL;
525 UBool isDefault = FALSE;
526 UBool isRoot = FALSE;
527 UBool hasRealData = FALSE;
528 UBool hasChopped = TRUE;
529 UBool usingUSRData = U_USE_USRDATA && ( path == NULL || uprv_strncmp(path,U_ ICUDATA_NAME,8) == 0);
530
531 char name[96];
532 char usrDataPath[96];
533
534 initCache(status);
535
536 if(U_FAILURE(*status)) {
537 return NULL;
538 }
539
540 uprv_strcpy(name, localeID);
541
542 if ( usingUSRData ) {
543 if ( path == NULL ) {
544 uprv_strcpy(usrDataPath,U_USRDATA_NAME);
545 } else {
546 uprv_strcpy(usrDataPath,path);
547 usrDataPath[0] = 'u';
548 usrDataPath[1] = 's';
549 usrDataPath[2] = 'r';
550 }
551 }
552
553 umtx_lock(&resbMutex);
554 { /* umtx_lock */
555 /* We're going to skip all the locales that do not have any data */
556 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &int Status);
557
558 if(r != NULL) { /* if there is one real locale, we can look for parents. */
559 t1 = r;
560 hasRealData = TRUE;
561 if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */
562 u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
563 if ( u1 != NULL ) {
564 if(u1->fBogus == U_ZERO_ERROR) {
565 u1->fParent = t1;
566 r = u1;
567 } else {
568 /* the USR override data wasn't found, set it to be deleted * /
569 u1->fCountExisting = 0;
570 }
571 }
572 }
573 while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.no Fallback) {
574 /* insert regular parents */
575 t2 = init_entry(name, t1->fPath, &parentStatus);
576 if ( usingUSRData ) { /* This code inserts user override data i nto the inheritance chain */
577 usrStatus = U_ZERO_ERROR;
578 u2 = init_entry(name, usrDataPath, &usrStatus);
579 }
580 /* Check for null pointer. */
581 if (t2 == NULL || ( usingUSRData && u2 == NULL)) {
582 *status = U_MEMORY_ALLOCATION_ERROR;
583 goto finishUnlock;
584 }
585
586 if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
587 if ( usingUSRData && u2->fBogus == U_ZERO_ERROR ) {
588 t1->fParent = u2;
589 u2->fParent = t2;
590 } else {
591 t1->fParent = t2;
592 if(usingUSRData) {
593 /* the USR override data wasn't found, set it to be deleted */
594 u2->fCountExisting = 0;
595 }
596 }
597 t1 = t2;
598 } else {
599 if (usingUSRData) {
600 /* the USR override data wasn't found, set it to be dele ted */
601 u2->fCountExisting = 0;
602 }
603 /* t2->fCountExisting have to be decremented since the call to init_entry increments
604 * it and if we hit this code, that means it is not set as t he parent.
605 */
606 t2->fCountExisting--;
607 }
608 hasChopped = chopLocale(name);
609 }
610 }
611
612 /* we could have reached this point without having any real data */
613 /* if that is the case, we need to chain in the default locale */
614 if(r==NULL && !isDefault && !isRoot /*&& t1->fParent == NULL*/) {
615 /* insert default locale */
616 uprv_strcpy(name, uloc_getDefault());
617 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
618 intStatus = U_USING_DEFAULT_WARNING;
619 if(r != NULL) { /* the default locale exists */
620 t1 = r;
621 hasRealData = TRUE;
622 isDefault = TRUE;
623 while (hasChopped && t1->fParent == NULL) {
624 /* insert chopped defaults */
625 t2 = init_entry(name, t1->fPath, &parentStatus);
626 /* Check for null pointer. */
627 if (t2 == NULL) {
628 *status = U_MEMORY_ALLOCATION_ERROR;
629 goto finishUnlock;
630 }
631
632 if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOG US) {
633 t1->fParent = t2;
634 t1 = t2;
635 }
636 hasChopped = chopLocale(name);
637 }
638 }
639 }
640
641 /* we could still have r == NULL at this point - maybe even default loca le is not */
642 /* present */
643 if(r == NULL) {
644 uprv_strcpy(name, kRootLocaleName);
645 r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
646 if(r != NULL) {
647 t1 = r;
648 intStatus = U_USING_DEFAULT_WARNING;
649 hasRealData = TRUE;
650 } else { /* we don't even have the root locale */
651 *status = U_MISSING_RESOURCE_ERROR;
652 goto finishUnlock;
653 }
654 } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1- >fParent == NULL && !r->fData.noFallback) {
655 /* insert root locale */
656 t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus);
657 /* Check for null pointer. */
658 if (t2 == NULL) {
659 *status = U_MEMORY_ALLOCATION_ERROR;
660 goto finishUnlock;
661 }
662 if(!hasRealData) {
663 r->fBogus = U_USING_DEFAULT_WARNING;
664 }
665 hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) || hasRealData);
666 t1->fParent = t2;
667 t1 = t2;
668 }
669
670 while(r != NULL && !isRoot && t1->fParent != NULL) {
671 t1->fParent->fCountExisting++;
672 t1 = t1->fParent;
673 hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) || hasRealData);
674 }
675 } /* umtx_lock */
676 finishUnlock:
677 umtx_unlock(&resbMutex);
678
679 if(U_SUCCESS(*status)) {
680 if(U_SUCCESS(parentStatus)) {
681 if(intStatus != U_ZERO_ERROR) {
682 *status = intStatus;
683 }
684 return r;
685 } else {
686 *status = parentStatus;
687 return NULL;
688 }
689 } else {
690 return NULL;
691 }
692 }
693
694
695 /**
696 * Functions to create and destroy resource bundles.
697 * CAUTION: resbMutex must be locked when calling this function.
698 */
699 /* INTERNAL: */
700 static void entryCloseInt(UResourceDataEntry *resB) {
701 UResourceDataEntry *p = resB;
702
703 while(resB != NULL) {
704 p = resB->fParent;
705 resB->fCountExisting--;
706
707 /* Entries are left in the cache. TODO: add ures_flushCache() to force a flush
708 of the cache. */
709 /*
710 if(resB->fCountExisting <= 0) {
711 uhash_remove(cache, resB);
712 if(resB->fBogus == U_ZERO_ERROR) {
713 res_unload(&(resB->fData));
714 }
715 if(resB->fName != NULL) {
716 uprv_free(resB->fName);
717 }
718 if(resB->fPath != NULL) {
719 uprv_free(resB->fPath);
720 }
721 uprv_free(resB);
722 }
723 */
724
725 resB = p;
726 }
727 }
728
729 /**
730 * API: closes a resource bundle and cleans up.
731 */
732
733 static void entryClose(UResourceDataEntry *resB) {
734 umtx_lock(&resbMutex);
735 entryCloseInt(resB);
736 umtx_unlock(&resbMutex);
737 }
738
739 /*
740 U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
741 if(resB->fResPath == NULL) {
742 resB->fResPath = resB->fResBuf;
743 *(resB->fResPath) = 0;
744 }
745 resB->fResPathLen = uprv_strlen(toAdd);
746 if(RES_BUFSIZE <= resB->fResPathLen+1) {
747 if(resB->fResPath == resB->fResBuf) {
748 resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
749 } else {
750 resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1 )*sizeof(char));
751 }
752 }
753 uprv_strcpy(resB->fResPath, toAdd);
754 }
755 */
756 static void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd, UErrorCode *status) {
757 int32_t resPathLenOrig = resB->fResPathLen;
758 if(resB->fResPath == NULL) {
759 resB->fResPath = resB->fResBuf;
760 *(resB->fResPath) = 0;
761 resB->fResPathLen = 0;
762 }
763 resB->fResPathLen += lenToAdd;
764 if(RES_BUFSIZE <= resB->fResPathLen+1) {
765 if(resB->fResPath == resB->fResBuf) {
766 resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(ch ar));
767 /* Check that memory was allocated correctly. */
768 if (resB->fResPath == NULL) {
769 *status = U_MEMORY_ALLOCATION_ERROR;
770 return;
771 }
772 uprv_strcpy(resB->fResPath, resB->fResBuf);
773 } else {
774 char *temp = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen +1)*sizeof(char));
775 /* Check that memory was reallocated correctly. */
776 if (temp == NULL) {
777 *status = U_MEMORY_ALLOCATION_ERROR;
778 return;
779 }
780 resB->fResPath = temp;
781 }
782 }
783 uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd);
784 }
785
786 static void ures_freeResPath(UResourceBundle *resB) {
787 if (resB->fResPath && resB->fResPath != resB->fResBuf) {
788 uprv_free(resB->fResPath);
789 }
790 resB->fResPath = NULL;
791 resB->fResPathLen = 0;
792 }
793
794 static void
795 ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj)
796 {
797 if(resB != NULL) {
798 if(resB->fData != NULL) {
799 entryClose(resB->fData);
800 }
801 if(resB->fVersion != NULL) {
802 uprv_free(resB->fVersion);
803 }
804 ures_freeResPath(resB);
805
806 if(ures_isStackObject(resB) == FALSE && freeBundleObj) {
807 uprv_free(resB);
808 }
809 #if 0 /*U_DEBUG*/
810 else {
811 /* poison the data */
812 uprv_memset(resB, -1, sizeof(UResourceBundle));
813 }
814 #endif
815 }
816 }
817
818 U_CAPI void U_EXPORT2
819 ures_close(UResourceBundle* resB)
820 {
821 ures_closeBundle(resB, TRUE);
822 }
823
824 static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
825 const char *key, int32_t idx, UResource DataEntry *realData,
826 const UResourceBundle *parent, int32_t noAlias,
827 UResourceBundle *resB, UErrorCode *stat us)
828 {
829 if(status == NULL || U_FAILURE(*status)) {
830 return resB;
831 }
832 if (parent == NULL) {
833 *status = U_ILLEGAL_ARGUMENT_ERROR;
834 return NULL;
835 }
836 if(RES_GET_TYPE(r) == URES_ALIAS) { /* This is an alias, need to exchange wi th real data */
837 if(noAlias < URES_MAX_ALIAS_LEVEL) {
838 int32_t len = 0;
839 const UChar *alias = res_getAlias(rdata, r, &len);
840 if(len > 0) {
841 /* we have an alias, now let's cut it up */
842 char stackAlias[200];
843 char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = N ULL;
844 int32_t capacity;
845
846 /*
847 * Allocate enough space for both the char * version
848 * of the alias and parent->fResPath.
849 *
850 * We do this so that res_findResource() can modify the path,
851 * which allows us to remove redundant _res_findResource() varian ts
852 * in uresdata.c.
853 * res_findResource() now NUL-terminates each segment so that tab le keys
854 * can always be compared with strcmp() instead of strncmp().
855 * Saves code there and simplifies testing and code coverage.
856 *
857 * markus 2003oct17
858 */
859 ++len; /* count the terminating NUL */
860 if(parent->fResPath != NULL) {
861 capacity = (int32_t)uprv_strlen(parent->fResPath) + 1;
862 } else {
863 capacity = 0;
864 }
865 if(capacity < len) {
866 capacity = len;
867 }
868 if(capacity <= sizeof(stackAlias)) {
869 capacity = sizeof(stackAlias);
870 chAlias = stackAlias;
871 } else {
872 chAlias = (char *)uprv_malloc(capacity);
873 /* test for NULL */
874 if(chAlias == NULL) {
875 *status = U_MEMORY_ALLOCATION_ERROR;
876 return NULL;
877 }
878 }
879 u_UCharsToChars(alias, chAlias, len);
880
881 if(*chAlias == RES_PATH_SEPARATOR) {
882 /* there is a path included */
883 locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR);
884 if(locale == NULL) {
885 locale = uprv_strchr(chAlias, 0); /* avoid locale == NUL L to make code below work */
886 } else {
887 *locale = 0;
888 locale++;
889 }
890 path = chAlias+1;
891 if(uprv_strcmp(path, "LOCALE") == 0) {
892 /* this is an XPath alias, starting with "/LOCALE/" */
893 /* it contains the path to a resource which should be lo oked up */
894 /* starting in the requested locale */
895 keyPath = locale;
896 locale = parent->fTopLevelData->fName; /* this is the re quested locale's name */
897 path = realData->fPath; /* we will be looking in the sam e package */
898 } else {
899 if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */
900 path = NULL;
901 }
902 keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
903 if(keyPath) {
904 *keyPath = 0;
905 keyPath++;
906 }
907 }
908 } else {
909 /* no path, start with a locale */
910 locale = chAlias;
911 keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
912 if(keyPath) {
913 *keyPath = 0;
914 keyPath++;
915 }
916 path = realData->fPath;
917 }
918
919
920 {
921 /* got almost everything, let's try to open */
922 /* first, open the bundle with real data */
923 UResourceBundle *result = resB;
924 const char* temp = NULL;
925 UErrorCode intStatus = U_ZERO_ERROR;
926 UResourceBundle *mainRes = ures_openDirect(path, locale, &in tStatus);
927 if(U_SUCCESS(intStatus)) {
928 if(keyPath == NULL) {
929 /* no key path. This means that we are going to
930 * to use the corresponding resource from
931 * another bundle
932 */
933 /* first, we are going to get a corresponding parent
934 * resource to the one we are searching.
935 */
936 char *aKey = parent->fResPath;
937 if(aKey) {
938 uprv_strcpy(chAlias, aKey); /* allocated large e nough above */
939 aKey = chAlias;
940 r = res_findResource(&(mainRes->fResData), mainR es->fRes, &aKey, &temp);
941 } else {
942 r = mainRes->fRes;
943 }
944 if(key) {
945 /* we need to make keyPath from parent's fResPat h and
946 * current key, if there is a key associated
947 */
948 len = (int32_t)(uprv_strlen(key) + 1);
949 if(len > capacity) {
950 capacity = len;
951 if(chAlias == stackAlias) {
952 chAlias = (char *)uprv_malloc(capacity);
953 } else {
954 chAlias = (char *)uprv_realloc(chAlias, capacity);
955 }
956 if(chAlias == NULL) {
957 ures_close(mainRes);
958 *status = U_MEMORY_ALLOCATION_ERROR;
959 return NULL;
960 }
961 }
962 uprv_memcpy(chAlias, key, len);
963 aKey = chAlias;
964 r = res_findResource(&(mainRes->fResData), r, &a Key, &temp);
965 } else if(idx != -1) {
966 /* if there is no key, but there is an index, tr y to get by the index */
967 /* here we have either a table or an array, so g et the element */
968 UResType type = RES_GET_TYPE(r);
969 if(URES_IS_TABLE(type)) {
970 r = res_getTableItemByIndex(&(mainRes->fResD ata), r, idx, (const char **)&aKey);
971 } else { /* array */
972 r = res_getArrayItem(&(mainRes->fResData), r , idx);
973 }
974 }
975 if(r != RES_BOGUS) {
976 result = init_resb_result(&(mainRes->fResData), r, temp, -1, mainRes->fData, mainRes, noAlias+1, resB, status);
977 } else {
978 *status = U_MISSING_RESOURCE_ERROR;
979 result = resB;
980 }
981 } else {
982 /* this one is a bit trickier.
983 * we start finding keys, but after we resolve one al ias, the path might continue.
984 * Consider:
985 * aliastest:alias { "testtypes/anotheralias/Sequ ence" }
986 * anotheralias:alias { "/ICUDATA/sh/CollationEle ments" }
987 * aliastest resource should finally have the sequenc e, not collation elements.
988 */
989 UResourceDataEntry *dataEntry = mainRes->fData;
990 char stackPath[URES_MAX_BUFFER_SIZE];
991 char *pathBuf = stackPath, *myPath = pathBuf;
992 if(uprv_strlen(keyPath) > URES_MAX_BUFFER_SIZE) {
993 pathBuf = (char *)uprv_malloc((uprv_strlen(keyPa th)+1)*sizeof(char));
994 if(pathBuf == NULL) {
995 *status = U_MEMORY_ALLOCATION_ERROR;
996 return NULL;
997 }
998 }
999 uprv_strcpy(pathBuf, keyPath);
1000 result = mainRes;
1001 /* now we have fallback following here */
1002 do {
1003 r = dataEntry->fData.rootRes;
1004 /* this loop handles 'found' resources over seve ral levels */
1005 while(*myPath && U_SUCCESS(*status)) {
1006 r = res_findResource(&(dataEntry->fData), r, &myPath, &temp);
1007 if(r != RES_BOGUS) { /* found a resource, bu t it might be an indirection */
1008 resB = init_resb_result(&(dataEntry->fDa ta), r, temp, -1, dataEntry, result, noAlias+1, resB, status);
1009 result = resB;
1010 if(result) {
1011 r = result->fRes; /* switch to a new resource, possibly a new tree */
1012 dataEntry = result->fData;
1013 }
1014 } else { /* no resource found, we don't real ly want to look anymore on this level */
1015 break;
1016 }
1017 }
1018 dataEntry = dataEntry->fParent;
1019 uprv_strcpy(pathBuf, keyPath);
1020 myPath = pathBuf;
1021 } while(r == RES_BOGUS && dataEntry != NULL);
1022 if(r == RES_BOGUS) {
1023 *status = U_MISSING_RESOURCE_ERROR;
1024 result = resB;
1025 }
1026 if(pathBuf != stackPath) {
1027 uprv_free(pathBuf);
1028 }
1029 }
1030 } else { /* we failed to open the resource we're aliasing to */
1031 *status = intStatus;
1032 }
1033 if(chAlias != stackAlias) {
1034 uprv_free(chAlias);
1035 }
1036 if(mainRes != result) {
1037 ures_close(mainRes);
1038 }
1039 return result;
1040 }
1041 } else {
1042 /* bad alias, should be an error */
1043 *status = U_ILLEGAL_ARGUMENT_ERROR;
1044 return resB;
1045 }
1046 } else {
1047 *status = U_TOO_MANY_ALIASES_ERROR;
1048 return resB;
1049 }
1050 }
1051 if(resB == NULL) {
1052 resB = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
1053 /* test for NULL */
1054 if (resB == NULL) {
1055 *status = U_MEMORY_ALLOCATION_ERROR;
1056 return NULL;
1057 }
1058 ures_setIsStackObject(resB, FALSE);
1059 resB->fResPath = NULL;
1060 resB->fResPathLen = 0;
1061 } else {
1062 if(resB->fData != NULL) {
1063 entryClose(resB->fData);
1064 }
1065 if(resB->fVersion != NULL) {
1066 uprv_free(resB->fVersion);
1067 }
1068 /*
1069 weiv: if stack object was passed in, it doesn't really need to be reinit ed,
1070 since the purpose of initing is to remove stack junk. However, at this p oint
1071 we would not do anything to an allocated object, so stack object should be
1072 treated the same
1073 */
1074 /*
1075 if(ures_isStackObject(resB) != FALSE) {
1076 ures_initStackObject(resB);
1077 }
1078 */
1079 if(parent != resB) {
1080 ures_freeResPath(resB);
1081 }
1082 }
1083 resB->fData = realData;
1084 entryIncrease(resB->fData);
1085 resB->fHasFallback = FALSE;
1086 resB->fIsTopLevel = FALSE;
1087 resB->fIndex = -1;
1088 resB->fKey = key;
1089 /*resB->fParentRes = parent;*/
1090 resB->fTopLevelData = parent->fTopLevelData;
1091 if(parent->fResPath && parent != resB) {
1092 ures_appendResPath(resB, parent->fResPath, parent->fResPathLen, status);
1093 }
1094 if(key != NULL) {
1095 ures_appendResPath(resB, key, (int32_t)uprv_strlen(key), status);
1096 if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
1097 ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status);
1098 }
1099 } else if(idx >= 0) {
1100 char buf[256];
1101 int32_t len = T_CString_integerToString(buf, idx, 10);
1102 ures_appendResPath(resB, buf, len, status);
1103 if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
1104 ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status);
1105 }
1106 }
1107 /* Make sure that Purify doesn't complain about uninitialized memory copies. */
1108 {
1109 int32_t usedLen = ((resB->fResBuf == resB->fResPath) ? resB->fResPathLen : 0);
1110 uprv_memset(resB->fResBuf + usedLen, 0, sizeof(resB->fResBuf) - usedLen) ;
1111 }
1112
1113 resB->fVersion = NULL;
1114 resB->fRes = r;
1115 /*resB->fParent = parent->fRes;*/
1116 uprv_memmove(&resB->fResData, rdata, sizeof(ResourceData));
1117 resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes);
1118 return resB;
1119 }
1120
1121 UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *origin al, UErrorCode *status) {
1122 UBool isStackObject;
1123 if(U_FAILURE(*status) || r == original) {
1124 return r;
1125 }
1126 if(original != NULL) {
1127 if(r == NULL) {
1128 isStackObject = FALSE;
1129 r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
1130 /* test for NULL */
1131 if (r == NULL) {
1132 *status = U_MEMORY_ALLOCATION_ERROR;
1133 return NULL;
1134 }
1135 } else {
1136 isStackObject = ures_isStackObject(r);
1137 ures_closeBundle(r, FALSE);
1138 }
1139 uprv_memcpy(r, original, sizeof(UResourceBundle));
1140 r->fResPath = NULL;
1141 r->fResPathLen = 0;
1142 if(original->fResPath) {
1143 ures_appendResPath(r, original->fResPath, original->fResPathLen, sta tus);
1144 }
1145 ures_setIsStackObject(r, isStackObject);
1146 if(r->fData != NULL) {
1147 entryIncrease(r->fData);
1148 }
1149 }
1150 return r;
1151 }
1152
1153 /**
1154 * Functions to retrieve data from resource bundles.
1155 */
1156
1157 U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_ t* len, UErrorCode* status) {
1158 const UChar *s;
1159 if (status==NULL || U_FAILURE(*status)) {
1160 return NULL;
1161 }
1162 if(resB == NULL) {
1163 *status = U_ILLEGAL_ARGUMENT_ERROR;
1164 return NULL;
1165 }
1166 s = res_getString(&(resB->fResData), resB->fRes, len);
1167 if (s == NULL) {
1168 *status = U_RESOURCE_TYPE_MISMATCH;
1169 }
1170 return s;
1171 }
1172
1173 static const char *
1174 ures_toUTF8String(const UChar *s16, int32_t length16,
1175 char *dest, int32_t *pLength,
1176 UBool forceCopy,
1177 UErrorCode *status) {
1178 int32_t capacity;
1179
1180 if (U_FAILURE(*status)) {
1181 return NULL;
1182 }
1183 if (pLength != NULL) {
1184 capacity = *pLength;
1185 } else {
1186 capacity = 0;
1187 }
1188 if (capacity < 0 || (capacity > 0 && dest == NULL)) {
1189 *status = U_ILLEGAL_ARGUMENT_ERROR;
1190 return NULL;
1191 }
1192
1193 if (length16 == 0) {
1194 /* empty string, return as read-only pointer */
1195 if (pLength != NULL) {
1196 *pLength = 0;
1197 }
1198 if (forceCopy) {
1199 u_terminateChars(dest, capacity, 0, status);
1200 return dest;
1201 } else {
1202 return "";
1203 }
1204 } else {
1205 /* We need to transform the string to the destination buffer. */
1206 if (capacity < length16) {
1207 /* No chance for the string to fit. Pure preflighting. */
1208 return u_strToUTF8(NULL, 0, pLength, s16, length16, status);
1209 }
1210 if (!forceCopy && (length16 <= 0x2aaaaaaa)) {
1211 /*
1212 * We know the string will fit into dest because each UChar turns
1213 * into at most three UTF-8 bytes. Fill the latter part of dest
1214 * so that callers do not expect to use dest as a string pointer,
1215 * hopefully leading to more robust code for when resource bundles
1216 * may store UTF-8 natively.
1217 * (In which case dest would not be used at all.)
1218 *
1219 * We do not do this if forceCopy=TRUE because then the caller
1220 * expects the string to start exactly at dest.
1221 *
1222 * The test above for <= 0x2aaaaaaa prevents overflows.
1223 * The +1 is for the NUL terminator.
1224 */
1225 int32_t maxLength = 3 * length16 + 1;
1226 if (capacity > maxLength) {
1227 dest += capacity - maxLength;
1228 capacity = maxLength;
1229 }
1230 }
1231 return u_strToUTF8(dest, capacity, pLength, s16, length16, status);
1232 }
1233 }
1234
1235 U_CAPI const char * U_EXPORT2
1236 ures_getUTF8String(const UResourceBundle *resB,
1237 char *dest, int32_t *pLength,
1238 UBool forceCopy,
1239 UErrorCode *status) {
1240 int32_t length16;
1241 const UChar *s16 = ures_getString(resB, &length16, status);
1242 return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
1243 }
1244
1245 U_CAPI const uint8_t* U_EXPORT2 ures_getBinary(const UResourceBundle* resB, int3 2_t* len,
1246 UErrorCode* status) {
1247 const uint8_t *p;
1248 if (status==NULL || U_FAILURE(*status)) {
1249 return NULL;
1250 }
1251 if(resB == NULL) {
1252 *status = U_ILLEGAL_ARGUMENT_ERROR;
1253 return NULL;
1254 }
1255 p = res_getBinary(&(resB->fResData), resB->fRes, len);
1256 if (p == NULL) {
1257 *status = U_RESOURCE_TYPE_MISMATCH;
1258 }
1259 return p;
1260 }
1261
1262 U_CAPI const int32_t* U_EXPORT2 ures_getIntVector(const UResourceBundle* resB, i nt32_t* len,
1263 UErrorCode* sta tus) {
1264 const int32_t *p;
1265 if (status==NULL || U_FAILURE(*status)) {
1266 return NULL;
1267 }
1268 if(resB == NULL) {
1269 *status = U_ILLEGAL_ARGUMENT_ERROR;
1270 return NULL;
1271 }
1272 p = res_getIntVector(&(resB->fResData), resB->fRes, len);
1273 if (p == NULL) {
1274 *status = U_RESOURCE_TYPE_MISMATCH;
1275 }
1276 return p;
1277 }
1278
1279 /* this function returns a signed integer */
1280 /* it performs sign extension */
1281 U_CAPI int32_t U_EXPORT2 ures_getInt(const UResourceBundle* resB, UErrorCode *st atus) {
1282 if (status==NULL || U_FAILURE(*status)) {
1283 return 0xffffffff;
1284 }
1285 if(resB == NULL) {
1286 *status = U_ILLEGAL_ARGUMENT_ERROR;
1287 return 0xffffffff;
1288 }
1289 if(RES_GET_TYPE(resB->fRes) != URES_INT) {
1290 *status = U_RESOURCE_TYPE_MISMATCH;
1291 return 0xffffffff;
1292 }
1293 return RES_GET_INT(resB->fRes);
1294 }
1295
1296 U_CAPI uint32_t U_EXPORT2 ures_getUInt(const UResourceBundle* resB, UErrorCode * status) {
1297 if (status==NULL || U_FAILURE(*status)) {
1298 return 0xffffffff;
1299 }
1300 if(resB == NULL) {
1301 *status = U_ILLEGAL_ARGUMENT_ERROR;
1302 return 0xffffffff;
1303 }
1304 if(RES_GET_TYPE(resB->fRes) != URES_INT) {
1305 *status = U_RESOURCE_TYPE_MISMATCH;
1306 return 0xffffffff;
1307 }
1308 return RES_GET_UINT(resB->fRes);
1309 }
1310
1311 U_CAPI UResType U_EXPORT2 ures_getType(const UResourceBundle *resB) {
1312 if(resB == NULL) {
1313 return URES_NONE;
1314 }
1315 return res_getPublicType(resB->fRes);
1316 }
1317
1318 U_CAPI const char * U_EXPORT2 ures_getKey(const UResourceBundle *resB) {
1319 if(resB == NULL) {
1320 return NULL;
1321 }
1322
1323 return(resB->fKey);
1324 }
1325
1326 U_CAPI int32_t U_EXPORT2 ures_getSize(const UResourceBundle *resB) {
1327 if(resB == NULL) {
1328 return 0;
1329 }
1330
1331 return resB->fSize;
1332 }
1333
1334 static const UChar* ures_getStringWithAlias(const UResourceBundle *resB, Resourc e r, int32_t sIndex, int32_t *len, UErrorCode *status) {
1335 if(RES_GET_TYPE(r) == URES_ALIAS) {
1336 const UChar* result = 0;
1337 UResourceBundle *tempRes = ures_getByIndex(resB, sIndex, NULL, status);
1338 result = ures_getString(tempRes, len, status);
1339 ures_close(tempRes);
1340 return result;
1341 } else {
1342 return res_getString(&(resB->fResData), r, len);
1343 }
1344 }
1345
1346 U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resB){
1347 if(resB == NULL) {
1348 return;
1349 }
1350 resB->fIndex = -1;
1351 }
1352
1353 U_CAPI UBool U_EXPORT2 ures_hasNext(const UResourceBundle *resB) {
1354 if(resB == NULL) {
1355 return FALSE;
1356 }
1357 return (UBool)(resB->fIndex < resB->fSize-1);
1358 }
1359
1360 U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resB, int32_t* len, const char ** key, UErrorCode *status) {
1361 Resource r = RES_BOGUS;
1362
1363 if (status==NULL || U_FAILURE(*status)) {
1364 return NULL;
1365 }
1366 if(resB == NULL) {
1367 *status = U_ILLEGAL_ARGUMENT_ERROR;
1368 return NULL;
1369 }
1370
1371 if(resB->fIndex == resB->fSize-1) {
1372 *status = U_INDEX_OUTOFBOUNDS_ERROR;
1373 } else {
1374 resB->fIndex++;
1375 switch(RES_GET_TYPE(resB->fRes)) {
1376 case URES_STRING:
1377 case URES_STRING_V2:
1378 return res_getString(&(resB->fResData), resB->fRes, len);
1379 case URES_TABLE:
1380 case URES_TABLE16:
1381 case URES_TABLE32:
1382 r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, k ey);
1383 if(r == RES_BOGUS && resB->fHasFallback) {
1384 /* TODO: do the fallback */
1385 }
1386 return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
1387 case URES_ARRAY:
1388 case URES_ARRAY16:
1389 r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
1390 if(r == RES_BOGUS && resB->fHasFallback) {
1391 /* TODO: do the fallback */
1392 }
1393 return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
1394 case URES_ALIAS:
1395 return ures_getStringWithAlias(resB, resB->fRes, resB->fIndex, len, status );
1396 case URES_INT:
1397 case URES_BINARY:
1398 case URES_INT_VECTOR:
1399 *status = U_RESOURCE_TYPE_MISMATCH;
1400 default:
1401 return NULL;
1402 }
1403 }
1404
1405 return NULL;
1406 }
1407
1408 U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resB, UR esourceBundle *fillIn, UErrorCode *status) {
1409 const char *key = NULL;
1410 Resource r = RES_BOGUS;
1411
1412 if (status==NULL || U_FAILURE(*status)) {
1413 /*return NULL;*/
1414 return fillIn;
1415 }
1416 if(resB == NULL) {
1417 *status = U_ILLEGAL_ARGUMENT_ERROR;
1418 /*return NULL;*/
1419 return fillIn;
1420 }
1421
1422 if(resB->fIndex == resB->fSize-1) {
1423 *status = U_INDEX_OUTOFBOUNDS_ERROR;
1424 /*return NULL;*/
1425 } else {
1426 resB->fIndex++;
1427 switch(RES_GET_TYPE(resB->fRes)) {
1428 case URES_INT:
1429 case URES_BINARY:
1430 case URES_STRING:
1431 case URES_STRING_V2:
1432 case URES_INT_VECTOR:
1433 return ures_copyResb(fillIn, resB, status);
1434 case URES_TABLE:
1435 case URES_TABLE16:
1436 case URES_TABLE32:
1437 r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIn dex, &key);
1438 if(r == RES_BOGUS && resB->fHasFallback) {
1439 /* TODO: do the fallback */
1440 }
1441 return init_resb_result(&(resB->fResData), r, key, resB->fIndex, res B->fData, resB, 0, fillIn, status);
1442 case URES_ARRAY:
1443 case URES_ARRAY16:
1444 r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
1445 if(r == RES_BOGUS && resB->fHasFallback) {
1446 /* TODO: do the fallback */
1447 }
1448 return init_resb_result(&(resB->fResData), r, key, resB->fIndex, res B->fData, resB, 0, fillIn, status);
1449 default:
1450 /*return NULL;*/
1451 return fillIn;
1452 }
1453 }
1454 /*return NULL;*/
1455 return fillIn;
1456 }
1457
1458 U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resB, i nt32_t indexR, UResourceBundle *fillIn, UErrorCode *status) {
1459 const char* key = NULL;
1460 Resource r = RES_BOGUS;
1461
1462 if (status==NULL || U_FAILURE(*status)) {
1463 /*return NULL;*/
1464 return fillIn;
1465 }
1466 if(resB == NULL) {
1467 *status = U_ILLEGAL_ARGUMENT_ERROR;
1468 /*return NULL;*/
1469 return fillIn;
1470 }
1471
1472 if(indexR >= 0 && resB->fSize > indexR) {
1473 switch(RES_GET_TYPE(resB->fRes)) {
1474 case URES_INT:
1475 case URES_BINARY:
1476 case URES_STRING:
1477 case URES_STRING_V2:
1478 case URES_INT_VECTOR:
1479 return ures_copyResb(fillIn, resB, status);
1480 case URES_TABLE:
1481 case URES_TABLE16:
1482 case URES_TABLE32:
1483 r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexR, & key);
1484 if(r == RES_BOGUS && resB->fHasFallback) {
1485 /* TODO: do the fallback */
1486 }
1487 return init_resb_result(&(resB->fResData), r, key, indexR, resB->fDa ta, resB, 0, fillIn, status);
1488 case URES_ARRAY:
1489 case URES_ARRAY16:
1490 r = res_getArrayItem(&(resB->fResData), resB->fRes, indexR);
1491 if(r == RES_BOGUS && resB->fHasFallback) {
1492 /* TODO: do the fallback */
1493 }
1494 return init_resb_result(&(resB->fResData), r, key, indexR, resB->fDa ta, resB, 0, fillIn, status);
1495 default:
1496 /*return NULL;*/
1497 return fillIn;
1498 }
1499 } else {
1500 *status = U_MISSING_RESOURCE_ERROR;
1501 }
1502 /*return NULL;*/
1503 return fillIn;
1504 }
1505
1506 U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status) {
1507 const char* key = NULL;
1508 Resource r = RES_BOGUS;
1509
1510 if (status==NULL || U_FAILURE(*status)) {
1511 return NULL;
1512 }
1513 if(resB == NULL) {
1514 *status = U_ILLEGAL_ARGUMENT_ERROR;
1515 return NULL;
1516 }
1517
1518 if(indexS >= 0 && resB->fSize > indexS) {
1519 switch(RES_GET_TYPE(resB->fRes)) {
1520 case URES_STRING:
1521 case URES_STRING_V2:
1522 return res_getString(&(resB->fResData), resB->fRes, len);
1523 case URES_TABLE:
1524 case URES_TABLE16:
1525 case URES_TABLE32:
1526 r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexS, & key);
1527 if(r == RES_BOGUS && resB->fHasFallback) {
1528 /* TODO: do the fallback */
1529 }
1530 return ures_getStringWithAlias(resB, r, indexS, len, status);
1531 case URES_ARRAY:
1532 case URES_ARRAY16:
1533 r = res_getArrayItem(&(resB->fResData), resB->fRes, indexS);
1534 if(r == RES_BOGUS && resB->fHasFallback) {
1535 /* TODO: do the fallback */
1536 }
1537 return ures_getStringWithAlias(resB, r, indexS, len, status);
1538 case URES_ALIAS:
1539 return ures_getStringWithAlias(resB, resB->fRes, indexS, len, status );
1540 case URES_INT:
1541 case URES_BINARY:
1542 case URES_INT_VECTOR:
1543 *status = U_RESOURCE_TYPE_MISMATCH;
1544 break;
1545 default:
1546 /* must not occur */
1547 *status = U_INTERNAL_PROGRAM_ERROR;
1548 break;
1549 }
1550 } else {
1551 *status = U_MISSING_RESOURCE_ERROR;
1552 }
1553 return NULL;
1554 }
1555
1556 U_CAPI const char * U_EXPORT2
1557 ures_getUTF8StringByIndex(const UResourceBundle *resB,
1558 int32_t idx,
1559 char *dest, int32_t *pLength,
1560 UBool forceCopy,
1561 UErrorCode *status) {
1562 int32_t length16;
1563 const UChar *s16 = ures_getStringByIndex(resB, idx, &length16, status);
1564 return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
1565 }
1566
1567 /*U_CAPI const char *ures_getResPath(UResourceBundle *resB) {
1568 return resB->fResPath;
1569 }*/
1570
1571 U_CAPI UResourceBundle* U_EXPORT2
1572 ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status)
1573 {
1574 UResourceBundle *first = NULL;
1575 UResourceBundle *result = fillIn;
1576 char *packageName = NULL;
1577 char *pathToResource = NULL, *save = NULL;
1578 char *locale = NULL, *localeEnd = NULL;
1579 int32_t length;
1580
1581 if(status == NULL || U_FAILURE(*status)) {
1582 return result;
1583 }
1584
1585 length = (int32_t)(uprv_strlen(path)+1);
1586 save = pathToResource = (char *)uprv_malloc(length*sizeof(char));
1587 /* test for NULL */
1588 if(pathToResource == NULL) {
1589 *status = U_MEMORY_ALLOCATION_ERROR;
1590 return result;
1591 }
1592 uprv_memcpy(pathToResource, path, length);
1593
1594 locale = pathToResource;
1595 if(*pathToResource == RES_PATH_SEPARATOR) { /* there is a path specification * /
1596 pathToResource++;
1597 packageName = pathToResource;
1598 pathToResource = uprv_strchr(pathToResource, RES_PATH_SEPARATOR);
1599 if(pathToResource == NULL) {
1600 *status = U_ILLEGAL_ARGUMENT_ERROR;
1601 } else {
1602 *pathToResource = 0;
1603 locale = pathToResource+1;
1604 }
1605 }
1606
1607 localeEnd = uprv_strchr(locale, RES_PATH_SEPARATOR);
1608 if(localeEnd != NULL) {
1609 *localeEnd = 0;
1610 }
1611
1612 first = ures_open(packageName, locale, status);
1613
1614 if(U_SUCCESS(*status)) {
1615 if(localeEnd) {
1616 result = ures_findSubResource(first, localeEnd+1, fillIn, status);
1617 } else {
1618 result = ures_copyResb(fillIn, first, status);
1619 }
1620 ures_close(first);
1621 }
1622 uprv_free(save);
1623 return result;
1624 }
1625
1626 U_CAPI UResourceBundle* U_EXPORT2
1627 ures_findSubResource(const UResourceBundle *resB, char* path, UResourceBundle *f illIn, UErrorCode *status)
1628 {
1629 Resource res = RES_BOGUS;
1630 UResourceBundle *result = fillIn;
1631 const char *key;
1632
1633 if(status == NULL || U_FAILURE(*status)) {
1634 return result;
1635 }
1636
1637 /* here we do looping and circular alias checking */
1638 /* this loop is here because aliasing is resolved on this level, not on res le vel */
1639 /* so, when we encounter an alias, it is not an aggregate resource, so we retu rn */
1640 do {
1641 res = res_findResource(&(resB->fResData), resB->fRes, &path, &key);
1642 if(res != RES_BOGUS) {
1643 result = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
1644 resB = result;
1645 } else {
1646 *status = U_MISSING_RESOURCE_ERROR;
1647 break;
1648 }
1649 } while(*path); /* there is more stuff in the path */
1650
1651 return result;
1652 }
1653 U_INTERNAL const UChar* U_EXPORT2
1654 ures_getStringByKeyWithFallback(const UResourceBundle *resB,
1655 const char* inKey,
1656 int32_t* len,
1657 UErrorCode *status) {
1658
1659 UResourceBundle stack;
1660 const UChar* retVal = NULL;
1661 ures_initStackObject(&stack);
1662 ures_getByKeyWithFallback(resB, inKey, &stack, status);
1663 retVal = ures_getString(&stack, len, status);
1664 ures_close(&stack);
1665 return retVal;
1666 }
1667
1668 U_CAPI UResourceBundle* U_EXPORT2
1669 ures_getByKeyWithFallback(const UResourceBundle *resB,
1670 const char* inKey,
1671 UResourceBundle *fillIn,
1672 UErrorCode *status) {
1673 Resource res = RES_BOGUS, rootRes = RES_BOGUS;
1674 /*UResourceDataEntry *realData = NULL;*/
1675 const char *key = inKey;
1676 UResourceBundle *helper = NULL;
1677 UResType type;
1678
1679 if (status==NULL || U_FAILURE(*status)) {
1680 return fillIn;
1681 }
1682 if(resB == NULL) {
1683 *status = U_ILLEGAL_ARGUMENT_ERROR;
1684 return fillIn;
1685 }
1686
1687 type = RES_GET_TYPE(resB->fRes);
1688 if(URES_IS_TABLE(type)) {
1689 int32_t t;
1690 res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
1691 if(res == RES_BOGUS) {
1692 UResourceDataEntry *dataEntry = resB->fData;
1693 char path[256];
1694 char* myPath = path;
1695 const char* resPath = resB->fResPath;
1696 int32_t len = resB->fResPathLen;
1697
1698 while(res == RES_BOGUS && dataEntry->fParent != NULL) { /* Otherwise , we'll look in parents */
1699 dataEntry = dataEntry->fParent;
1700 rootRes = dataEntry->fData.rootRes;
1701
1702 if(dataEntry->fBogus == U_ZERO_ERROR) {
1703 uprv_strncpy(path, resPath, len);
1704 uprv_strcpy(path+len, inKey);
1705 myPath = path;
1706 key = inKey;
1707 do {
1708 res = res_findResource(&(dataEntry->fData), rootRes, &my Path, &key);
1709 if (RES_GET_TYPE(res) == URES_ALIAS && *myPath) {
1710 /* We hit an alias, but we didn't finish following t he path. */
1711 helper = init_resb_result(&(dataEntry->fData), res, NULL, -1, dataEntry, resB, 0, helper, status);
1712 /*helper = init_resb_result(&(dataEntry->fData), res , inKey, -1, dataEntry, resB, 0, helper, status);*/
1713 if(helper) {
1714 dataEntry = helper->fData;
1715 rootRes = helper->fRes;
1716 resPath = helper->fResPath;
1717 len = helper->fResPathLen;
1718
1719 } else {
1720 break;
1721 }
1722 }
1723 } while(*myPath); /* Continue until the whole path is consum ed */
1724 }
1725 }
1726 /*const ResourceData *rd = getFallbackData(resB, &key, &realData, &r es, status);*/
1727 if(res != RES_BOGUS) {
1728 /* check if resB->fResPath gives the right name here */
1729 if(uprv_strcmp(dataEntry->fName, uloc_getDefault())==0 || uprv_s trcmp(dataEntry->fName, kRootLocaleName)==0) {
1730 *status = U_USING_DEFAULT_WARNING;
1731 } else {
1732 *status = U_USING_FALLBACK_WARNING;
1733 }
1734
1735 fillIn = init_resb_result(&(dataEntry->fData), res, inKey, -1, d ataEntry, resB, 0, fillIn, status);
1736 } else {
1737 *status = U_MISSING_RESOURCE_ERROR;
1738 }
1739 } else {
1740 fillIn = init_resb_result(&(resB->fResData), res, key, -1, resB->fDa ta, resB, 0, fillIn, status);
1741 }
1742 }
1743 else {
1744 *status = U_RESOURCE_TYPE_MISMATCH;
1745 }
1746 ures_close(helper);
1747 return fillIn;
1748 }
1749
1750
1751 U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con st char* inKey, UResourceBundle *fillIn, UErrorCode *status) {
1752 Resource res = RES_BOGUS;
1753 UResourceDataEntry *realData = NULL;
1754 const char *key = inKey;
1755 UResType type;
1756
1757 if (status==NULL || U_FAILURE(*status)) {
1758 return fillIn;
1759 }
1760 if(resB == NULL) {
1761 *status = U_ILLEGAL_ARGUMENT_ERROR;
1762 return fillIn;
1763 }
1764
1765 type = RES_GET_TYPE(resB->fRes);
1766 if(URES_IS_TABLE(type)) {
1767 int32_t t;
1768 res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
1769 if(res == RES_BOGUS) {
1770 key = inKey;
1771 if(resB->fHasFallback == TRUE) {
1772 const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
1773 if(U_SUCCESS(*status)) {
1774 /* check if resB->fResPath gives the right name here */
1775 return init_resb_result(rd, res, key, -1, realData, resB, 0, fillIn, status);
1776 } else {
1777 *status = U_MISSING_RESOURCE_ERROR;
1778 }
1779 } else {
1780 *status = U_MISSING_RESOURCE_ERROR;
1781 }
1782 } else {
1783 return init_resb_result(&(resB->fResData), res, key, -1, resB->fData , resB, 0, fillIn, status);
1784 }
1785 }
1786 #if 0
1787 /* this is a kind of TODO item. If we have an array with an index table, we could do this. */
1788 /* not currently */
1789 else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE ) {
1790 /* here should go a first attempt to locate the key using index table */
1791 const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, st atus);
1792 if(U_SUCCESS(*status)) {
1793 return init_resb_result(rd, res, key, realData, resB, fillIn, status );
1794 } else {
1795 *status = U_MISSING_RESOURCE_ERROR;
1796 }
1797 }
1798 #endif
1799 else {
1800 *status = U_RESOURCE_TYPE_MISMATCH;
1801 }
1802 return fillIn;
1803 }
1804
1805 U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c onst char* inKey, int32_t* len, UErrorCode *status) {
1806 Resource res = RES_BOGUS;
1807 UResourceDataEntry *realData = NULL;
1808 const char* key = inKey;
1809 UResType type;
1810
1811 if (status==NULL || U_FAILURE(*status)) {
1812 return NULL;
1813 }
1814 if(resB == NULL) {
1815 *status = U_ILLEGAL_ARGUMENT_ERROR;
1816 return NULL;
1817 }
1818
1819 type = RES_GET_TYPE(resB->fRes);
1820 if(URES_IS_TABLE(type)) {
1821 int32_t t=0;
1822
1823 res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
1824
1825 if(res == RES_BOGUS) {
1826 key = inKey;
1827 if(resB->fHasFallback == TRUE) {
1828 const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
1829 if(U_SUCCESS(*status)) {
1830 switch (RES_GET_TYPE(res)) {
1831 case URES_STRING:
1832 case URES_STRING_V2:
1833 return res_getString(rd, res, len);
1834 case URES_ALIAS:
1835 {
1836 const UChar* result = 0;
1837 UResourceBundle *tempRes = ures_getByKey(resB, inKey, NU LL, status);
1838 result = ures_getString(tempRes, len, status);
1839 ures_close(tempRes);
1840 return result;
1841 }
1842 default:
1843 *status = U_RESOURCE_TYPE_MISMATCH;
1844 }
1845 } else {
1846 *status = U_MISSING_RESOURCE_ERROR;
1847 }
1848 } else {
1849 *status = U_MISSING_RESOURCE_ERROR;
1850 }
1851 } else {
1852 switch (RES_GET_TYPE(res)) {
1853 case URES_STRING:
1854 case URES_STRING_V2:
1855 return res_getString(&(resB->fResData), res, len);
1856 case URES_ALIAS:
1857 {
1858 const UChar* result = 0;
1859 UResourceBundle *tempRes = ures_getByKey(resB, inKey, NULL, stat us);
1860 result = ures_getString(tempRes, len, status);
1861 ures_close(tempRes);
1862 return result;
1863 }
1864 default:
1865 *status = U_RESOURCE_TYPE_MISMATCH;
1866 }
1867 }
1868 }
1869 #if 0
1870 /* this is a kind of TODO item. If we have an array with an index table, we could do this. */
1871 /* not currently */
1872 else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE ) {
1873 /* here should go a first attempt to locate the key using index table */
1874 const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, st atus);
1875 if(U_SUCCESS(*status)) {
1876 return res_getString(rd, res, len);
1877 } else {
1878 *status = U_MISSING_RESOURCE_ERROR;
1879 }
1880 }
1881 #endif
1882 else {
1883 *status = U_RESOURCE_TYPE_MISMATCH;
1884 }
1885 return NULL;
1886 }
1887
1888 U_CAPI const char * U_EXPORT2
1889 ures_getUTF8StringByKey(const UResourceBundle *resB,
1890 const char *key,
1891 char *dest, int32_t *pLength,
1892 UBool forceCopy,
1893 UErrorCode *status) {
1894 int32_t length16;
1895 const UChar *s16 = ures_getStringByKey(resB, key, &length16, status);
1896 return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
1897 }
1898
1899 /* TODO: clean from here down */
1900
1901 /**
1902 * INTERNAL: Get the name of the first real locale (not placeholder)
1903 * that has resource bundle data.
1904 */
1905 U_INTERNAL const char* U_EXPORT2
1906 ures_getLocaleInternal(const UResourceBundle* resourceBundle, UErrorCode* status )
1907 {
1908 if (status==NULL || U_FAILURE(*status)) {
1909 return NULL;
1910 }
1911 if (!resourceBundle) {
1912 *status = U_ILLEGAL_ARGUMENT_ERROR;
1913 return NULL;
1914 } else {
1915 return resourceBundle->fData->fName;
1916 }
1917 }
1918
1919 U_CAPI const char* U_EXPORT2
1920 ures_getLocale(const UResourceBundle* resourceBundle,
1921 UErrorCode* status)
1922 {
1923 return ures_getLocaleInternal(resourceBundle, status);
1924 }
1925
1926
1927 U_CAPI const char* U_EXPORT2
1928 ures_getLocaleByType(const UResourceBundle* resourceBundle,
1929 ULocDataLocaleType type,
1930 UErrorCode* status) {
1931 if (status==NULL || U_FAILURE(*status)) {
1932 return NULL;
1933 }
1934 if (!resourceBundle) {
1935 *status = U_ILLEGAL_ARGUMENT_ERROR;
1936 return NULL;
1937 } else {
1938 switch(type) {
1939 case ULOC_ACTUAL_LOCALE:
1940 return resourceBundle->fData->fName;
1941 case ULOC_VALID_LOCALE:
1942 return resourceBundle->fTopLevelData->fName;
1943 case ULOC_REQUESTED_LOCALE:
1944 return NULL;
1945 default:
1946 *status = U_ILLEGAL_ARGUMENT_ERROR;
1947 return NULL;
1948 }
1949 }
1950 }
1951
1952 U_CFUNC const char* ures_getName(const UResourceBundle* resB) {
1953 if(resB == NULL) {
1954 return NULL;
1955 }
1956
1957 return resB->fData->fName;
1958 }
1959
1960 #ifdef URES_DEBUG
1961 U_CFUNC const char* ures_getPath(const UResourceBundle* resB) {
1962 if(resB == NULL) {
1963 return NULL;
1964 }
1965
1966 return resB->fData->fPath;
1967 }
1968 #endif
1969
1970 /* OLD API implementation */
1971
1972 /**
1973 * API: This function is used to open a resource bundle
1974 * proper fallback chaining is executed while initialization.
1975 * The result is stored in cache for later fallback search.
1976 */
1977 U_CAPI void U_EXPORT2
1978 ures_openFillIn(UResourceBundle *r, const char* path,
1979 const char* localeID, UErrorCode* status) {
1980 if(r == NULL) {
1981 *status = U_ILLEGAL_ARGUMENT_ERROR;
1982 } else {
1983 UResourceDataEntry *firstData;
1984 UBool isStackObject = ures_isStackObject(r);
1985
1986 ures_closeBundle(r, FALSE);
1987 uprv_memset(r, 0, sizeof(UResourceBundle));
1988 ures_setIsStackObject(r, isStackObject);
1989 r->fHasFallback = TRUE;
1990 r->fIsTopLevel = TRUE;
1991 r->fIndex = -1;
1992 r->fData = entryOpen(path, localeID, status);
1993 if(U_FAILURE(*status)) {
1994 return;
1995 }
1996 /* this is a quick fix to get regular data in bundle - until constructio n is cleaned up */
1997 firstData = r->fData;
1998 while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) {
1999 firstData = firstData->fParent;
2000 }
2001 uprv_memcpy(&r->fResData, &firstData->fData, sizeof(ResourceData));
2002 r->fHasFallback=(UBool)!r->fResData.noFallback;
2003 r->fRes = r->fResData.rootRes;
2004 r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
2005 r->fTopLevelData = r->fData;
2006 }
2007 }
2008
2009 U_CAPI UResourceBundle* U_EXPORT2
2010 ures_open(const char* path,
2011 const char* localeID,
2012 UErrorCode* status)
2013 {
2014 char canonLocaleID[100];
2015 UResourceDataEntry *hasData = NULL;
2016 UResourceBundle *r;
2017
2018 if(status == NULL || U_FAILURE(*status)) {
2019 return NULL;
2020 }
2021
2022 /* first "canonicalize" the locale ID */
2023 uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
2024 if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
2025 *status = U_ILLEGAL_ARGUMENT_ERROR;
2026 return NULL;
2027 }
2028
2029 r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
2030 if(r == NULL) {
2031 *status = U_MEMORY_ALLOCATION_ERROR;
2032 return NULL;
2033 }
2034
2035 uprv_memset(r, 0, sizeof(UResourceBundle));
2036 r->fHasFallback = TRUE;
2037 r->fIsTopLevel = TRUE;
2038 ures_setIsStackObject(r, FALSE);
2039 r->fIndex = -1;
2040 r->fData = entryOpen(path, canonLocaleID, status);
2041 if(U_FAILURE(*status)) {
2042 uprv_free(r);
2043 return NULL;
2044 }
2045 r->fTopLevelData = r->fData;
2046
2047 hasData = r->fData;
2048 while(hasData->fBogus != U_ZERO_ERROR) {
2049 hasData = hasData->fParent;
2050 if(hasData == NULL) {
2051 /* This can happen only if fallback chain gets broken by an act of God */
2052 /* TODO: this unlikely to happen, consider removing it */
2053 entryClose(r->fData);
2054 uprv_free(r);
2055 *status = U_MISSING_RESOURCE_ERROR;
2056 return NULL;
2057 }
2058 }
2059
2060 uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData));
2061 r->fHasFallback=(UBool)!r->fResData.noFallback;
2062 r->fRes = r->fResData.rootRes;
2063 r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
2064 /*
2065 if(r->fData->fPath != NULL) {
2066 ures_setResPath(r, r->fData->fPath);
2067 ures_appendResPath(r, RES_PATH_PACKAGE_S);
2068 ures_appendResPath(r, r->fData->fName);
2069 } else {
2070 ures_setResPath(r, r->fData->fName);
2071 }
2072 */
2073
2074
2075 return r;
2076 }
2077
2078 /**
2079 * Opens a resource bundle without "canonicalizing" the locale name. No fallbac k will be performed
2080 * or sought. However, alias substitution will happen!
2081 */
2082 U_CAPI UResourceBundle* U_EXPORT2
2083 ures_openDirect(const char* path, const char* localeID, UErrorCode* status) {
2084 UResourceBundle *r;
2085 UErrorCode subStatus = U_ZERO_ERROR;
2086
2087 if(status == NULL || U_FAILURE(*status)) {
2088 return NULL;
2089 }
2090
2091 r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
2092 if(r == NULL) {
2093 *status = U_MEMORY_ALLOCATION_ERROR;
2094 return NULL;
2095 }
2096
2097 r->fHasFallback = FALSE;
2098 r->fIsTopLevel = TRUE;
2099 ures_setIsStackObject(r, FALSE);
2100 r->fIndex = -1;
2101 r->fData = entryOpen(path, localeID, &subStatus);
2102 if(U_FAILURE(subStatus)) {
2103 *status = subStatus;
2104 uprv_free(r);
2105 return NULL;
2106 }
2107 if(subStatus != U_ZERO_ERROR /*r->fData->fBogus != U_ZERO_ERROR*/) {
2108 /* we didn't find one we were looking for - so openDirect */
2109 /* should fail */
2110 entryClose(r->fData);
2111 uprv_free(r);
2112 *status = U_MISSING_RESOURCE_ERROR;
2113 return NULL;
2114 }
2115
2116 r->fKey = NULL;
2117 r->fVersion = NULL;
2118 uprv_memcpy(&r->fResData, &r->fData->fData, sizeof(ResourceData));
2119 /* r->fHasFallback remains FALSE here in ures_openDirect() */
2120 r->fRes = r->fResData.rootRes;
2121 /*r->fParent = RES_BOGUS;*/
2122 r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
2123 r->fResPath = NULL;
2124 r->fResPathLen = 0;
2125 /*r->fParentRes = NULL;*/
2126 r->fTopLevelData = r->fData;
2127
2128 return r;
2129 }
2130
2131 /**
2132 * API: Counts members. For arrays and tables, returns number of resources.
2133 * For strings, returns 1.
2134 */
2135 U_CAPI int32_t U_EXPORT2
2136 ures_countArrayItems(const UResourceBundle* resourceBundle,
2137 const char* resourceKey,
2138 UErrorCode* status)
2139 {
2140 UResourceBundle resData;
2141 ures_initStackObject(&resData);
2142 if (status==NULL || U_FAILURE(*status)) {
2143 return 0;
2144 }
2145 if(resourceBundle == NULL) {
2146 *status = U_ILLEGAL_ARGUMENT_ERROR;
2147 return 0;
2148 }
2149 ures_getByKey(resourceBundle, resourceKey, &resData, status);
2150
2151 if(resData.fResData.data != NULL) {
2152 int32_t result = res_countArrayItems(&resData.fResData, resData.fRes);
2153 ures_close(&resData);
2154 return result;
2155 } else {
2156 *status = U_MISSING_RESOURCE_ERROR;
2157 ures_close(&resData);
2158 return 0;
2159 }
2160 }
2161
2162 /**
2163 * Internal function.
2164 * Return the version number associated with this ResourceBundle as a string.
2165 *
2166 * @param resourceBundle The resource bundle for which the version is checked.
2167 * @return A version number string as specified in the resource bundle or its p arent.
2168 * The caller does not own this string.
2169 * @see ures_getVersion
2170 * @internal
2171 */
2172 U_INTERNAL const char* U_EXPORT2
2173 ures_getVersionNumberInternal(const UResourceBundle *resourceBundle)
2174 {
2175 if (!resourceBundle) return NULL;
2176
2177 if(resourceBundle->fVersion == NULL) {
2178
2179 /* If the version ID has not been built yet, then do so. Retrieve */
2180 /* the minor version from the file. */
2181 UErrorCode status = U_ZERO_ERROR;
2182 int32_t minor_len = 0;
2183 int32_t len;
2184
2185 const UChar* minor_version = ures_getStringByKey(resourceBundle, kVersio nTag, &minor_len, &status);
2186
2187 /* Determine the length of of the final version string. This is */
2188 /* the length of the major part + the length of the separator */
2189 /* (==1) + the length of the minor part (+ 1 for the zero byte at */
2190 /* the end). */
2191
2192 len = (minor_len > 0) ? minor_len : 1;
2193
2194 /* Allocate the string, and build it up. */
2195 /* + 1 for zero byte */
2196
2197
2198 ((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_malloc(1 + len);
2199 /* Check for null pointer. */
2200 if (((UResourceBundle *)resourceBundle)->fVersion == NULL) {
2201 return NULL;
2202 }
2203
2204 if(minor_len > 0) {
2205 u_UCharsToChars(minor_version, resourceBundle->fVersion , minor_len) ;
2206 resourceBundle->fVersion[len] = '\0';
2207 }
2208 else {
2209 uprv_strcpy(resourceBundle->fVersion, kDefaultMinorVersion);
2210 }
2211 }
2212
2213 return resourceBundle->fVersion;
2214 }
2215
2216 U_CAPI const char* U_EXPORT2
2217 ures_getVersionNumber(const UResourceBundle* resourceBundle)
2218 {
2219 return ures_getVersionNumberInternal(resourceBundle);
2220 }
2221
2222 U_CAPI void U_EXPORT2 ures_getVersion(const UResourceBundle* resB, UVersionInfo versionInfo) {
2223 if (!resB) return;
2224
2225 u_versionFromString(versionInfo, ures_getVersionNumberInternal(resB));
2226 }
2227
2228 /** Tree support functions *******************************/
2229 #define INDEX_LOCALE_NAME "res_index"
2230 #define INDEX_TAG "InstalledLocales"
2231 #define DEFAULT_TAG "default"
2232
2233 #if defined(URES_TREE_DEBUG)
2234 #include <stdio.h>
2235 #endif
2236
2237 typedef struct ULocalesContext {
2238 UResourceBundle installed;
2239 UResourceBundle curr;
2240 } ULocalesContext;
2241
2242 static void U_CALLCONV
2243 ures_loc_closeLocales(UEnumeration *enumerator) {
2244 ULocalesContext *ctx = (ULocalesContext *)enumerator->context;
2245 ures_close(&ctx->curr);
2246 ures_close(&ctx->installed);
2247 uprv_free(ctx);
2248 uprv_free(enumerator);
2249 }
2250
2251 static int32_t U_CALLCONV
2252 ures_loc_countLocales(UEnumeration *en, UErrorCode *status) {
2253 ULocalesContext *ctx = (ULocalesContext *)en->context;
2254 return ures_getSize(&ctx->installed);
2255 }
2256
2257 static const char* U_CALLCONV
2258 ures_loc_nextLocale(UEnumeration* en,
2259 int32_t* resultLength,
2260 UErrorCode* status) {
2261 ULocalesContext *ctx = (ULocalesContext *)en->context;
2262 UResourceBundle *res = &(ctx->installed);
2263 UResourceBundle *k = NULL;
2264 const char *result = NULL;
2265 int32_t len = 0;
2266 if(ures_hasNext(res) && (k = ures_getNextResource(res, &ctx->curr, status))) {
2267 result = ures_getKey(k);
2268 len = (int32_t)uprv_strlen(result);
2269 }
2270 if (resultLength) {
2271 *resultLength = len;
2272 }
2273 return result;
2274 }
2275
2276 static void U_CALLCONV
2277 ures_loc_resetLocales(UEnumeration* en,
2278 UErrorCode* status) {
2279 UResourceBundle *res = &((ULocalesContext *)en->context)->installed;
2280 ures_resetIterator(res);
2281 }
2282
2283
2284 static const UEnumeration gLocalesEnum = {
2285 NULL,
2286 NULL,
2287 ures_loc_closeLocales,
2288 ures_loc_countLocales,
2289 uenum_unextDefault,
2290 ures_loc_nextLocale,
2291 ures_loc_resetLocales
2292 };
2293
2294
2295 U_CAPI UEnumeration* U_EXPORT2
2296 ures_openAvailableLocales(const char *path, UErrorCode *status)
2297 {
2298 UResourceBundle *idx = NULL;
2299 UEnumeration *en = NULL;
2300 ULocalesContext *myContext = NULL;
2301
2302 if(U_FAILURE(*status)) {
2303 return NULL;
2304 }
2305 myContext = uprv_malloc(sizeof(ULocalesContext));
2306 en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
2307 if(!en || !myContext) {
2308 *status = U_MEMORY_ALLOCATION_ERROR;
2309 uprv_free(en);
2310 uprv_free(myContext);
2311 return NULL;
2312 }
2313 uprv_memcpy(en, &gLocalesEnum, sizeof(UEnumeration));
2314
2315 ures_initStackObject(&myContext->installed);
2316 ures_initStackObject(&myContext->curr);
2317 idx = ures_openDirect(path, INDEX_LOCALE_NAME, status);
2318 ures_getByKey(idx, INDEX_TAG, &myContext->installed, status);
2319 if(U_SUCCESS(*status)) {
2320 #if defined(URES_TREE_DEBUG)
2321 fprintf(stderr, "Got %s::%s::[%s] : %s\n",
2322 path, INDEX_LOCALE_NAME, INDEX_TAG, ures_getKey(&myContext->installe d));
2323 #endif
2324 en->context = myContext;
2325 } else {
2326 #if defined(URES_TREE_DEBUG)
2327 fprintf(stderr, "%s open failed - %s\n", path, u_errorName(*status));
2328 #endif
2329 ures_close(&myContext->installed);
2330 uprv_free(myContext);
2331 uprv_free(en);
2332 en = NULL;
2333 }
2334
2335 ures_close(idx);
2336
2337 return en;
2338 }
2339
2340 static UBool isLocaleInList(UEnumeration *locEnum, const char *locToSearch, UErr orCode *status) {
2341 const char *loc;
2342 while ((loc = uenum_next(locEnum, NULL, status)) != NULL) {
2343 if (uprv_strcmp(loc, locToSearch) == 0) {
2344 return TRUE;
2345 }
2346 }
2347 return FALSE;
2348 }
2349
2350 U_CAPI int32_t U_EXPORT2
2351 ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
2352 const char *path, const char *resName, const char * keyword, const char *locid,
2353 UBool *isAvailable, UBool omitDefault, UErrorCode * status)
2354 {
2355 char kwVal[1024] = ""; /* value of keyword 'keyword' */
2356 char defVal[1024] = ""; /* default value for given locale */
2357 char defLoc[1024] = ""; /* default value for given locale */
2358 char base[1024] = ""; /* base locale */
2359 char found[1024];
2360 char parent[1024];
2361 char full[1024] = "";
2362 UResourceBundle bund1, bund2;
2363 UResourceBundle *res = NULL;
2364 UErrorCode subStatus = U_ZERO_ERROR;
2365 int32_t length = 0;
2366 if(U_FAILURE(*status)) return 0;
2367 uloc_getKeywordValue(locid, keyword, kwVal, 1024-1,&subStatus);
2368 if(!uprv_strcmp(kwVal, DEFAULT_TAG)) {
2369 kwVal[0]=0;
2370 }
2371 uloc_getBaseName(locid, base, 1024-1,&subStatus);
2372 #if defined(URES_TREE_DEBUG)
2373 fprintf(stderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n",
2374 locid, keyword, kwVal, base, u_errorName(subStatus));
2375 #endif
2376 ures_initStackObject(&bund1);
2377 ures_initStackObject(&bund2);
2378
2379
2380 uprv_strcpy(parent, base);
2381 uprv_strcpy(found, base);
2382
2383 if(isAvailable) {
2384 UEnumeration *locEnum = ures_openAvailableLocales(path, &subStatus);
2385 *isAvailable = TRUE;
2386 if (U_SUCCESS(subStatus)) {
2387 *isAvailable = isLocaleInList(locEnum, parent, &subStatus);
2388 }
2389 uenum_close(locEnum);
2390 }
2391
2392 if(U_FAILURE(subStatus)) {
2393 *status = subStatus;
2394 return 0;
2395 }
2396
2397 do {
2398 subStatus = U_ZERO_ERROR;
2399 res = ures_open(path, parent, &subStatus);
2400 if(((subStatus == U_USING_FALLBACK_WARNING) ||
2401 (subStatus == U_USING_DEFAULT_WARNING)) && isAvailable)
2402 {
2403 *isAvailable = FALSE;
2404 }
2405 isAvailable = NULL; /* only want to set this the first time around */
2406
2407 #if defined(URES_TREE_DEBUG)
2408 fprintf(stderr, "%s;%s -> %s [%s]\n", path?path:"ICUDATA", parent, u_err orName(subStatus), ures_getLocale(res, &subStatus));
2409 #endif
2410 if(U_FAILURE(subStatus)) {
2411 *status = subStatus;
2412 } else if(subStatus == U_ZERO_ERROR) {
2413 ures_getByKey(res,resName,&bund1, &subStatus);
2414 if(subStatus == U_ZERO_ERROR) {
2415 const UChar *defUstr;
2416 int32_t defLen;
2417 /* look for default item */
2418 #if defined(URES_TREE_DEBUG)
2419 fprintf(stderr, "%s;%s : loaded default -> %s\n",
2420 path?path:"ICUDATA", parent, u_errorName(subStatus));
2421 #endif
2422 defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &sub Status);
2423 if(U_SUCCESS(subStatus) && defLen) {
2424 u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
2425 #if defined(URES_TREE_DEBUG)
2426 fprintf(stderr, "%s;%s -> default %s=%s, %s\n",
2427 path?path:"ICUDATA", parent, keyword, defVal, u_errorNam e(subStatus));
2428 #endif
2429 uprv_strcpy(defLoc, parent);
2430 if(kwVal[0]==0) {
2431 uprv_strcpy(kwVal, defVal);
2432 #if defined(URES_TREE_DEBUG)
2433 fprintf(stderr, "%s;%s -> kwVal = %s\n",
2434 path?path:"ICUDATA", parent, keyword, kwVal);
2435 #endif
2436 }
2437 }
2438 }
2439 }
2440
2441 subStatus = U_ZERO_ERROR;
2442
2443 if (res != NULL) {
2444 uprv_strcpy(found, ures_getLocaleByType(res, ULOC_VALID_LOCALE, &sub Status));
2445 }
2446
2447 uloc_getParent(found,parent,sizeof(parent),&subStatus);
2448 ures_close(res);
2449 } while(!defVal[0] && *found && uprv_strcmp(found, "root") != 0 && U_SUCCESS (*status));
2450
2451 /* Now, see if we can find the kwVal collator.. start the search over.. */
2452 uprv_strcpy(parent, base);
2453 uprv_strcpy(found, base);
2454
2455 do {
2456 subStatus = U_ZERO_ERROR;
2457 res = ures_open(path, parent, &subStatus);
2458 if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
2459 *isAvailable = FALSE;
2460 }
2461 isAvailable = NULL; /* only want to set this the first time around */
2462
2463 #if defined(URES_TREE_DEBUG)
2464 fprintf(stderr, "%s;%s -> %s (looking for %s)\n",
2465 path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal);
2466 #endif
2467 if(U_FAILURE(subStatus)) {
2468 *status = subStatus;
2469 } else if(subStatus == U_ZERO_ERROR) {
2470 ures_getByKey(res,resName,&bund1, &subStatus);
2471 #if defined(URES_TREE_DEBUG)
2472 /**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, resName, u_errorName(subStatus));
2473 #endif
2474 if(subStatus == U_ZERO_ERROR) {
2475 ures_getByKey(&bund1, kwVal, &bund2, &subStatus);
2476 #if defined(URES_TREE_DEBUG)
2477 /**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, kwVal, u_errorName(subStatus));
2478 #endif
2479 if(subStatus == U_ZERO_ERROR) {
2480 #if defined(URES_TREE_DEBUG)
2481 fprintf(stderr, "%s;%s -> full0 %s=%s, %s\n",
2482 path?path:"ICUDATA", parent, keyword, kwVal, u_errorName (subStatus));
2483 #endif
2484 uprv_strcpy(full, parent);
2485 if(*full == 0) {
2486 uprv_strcpy(full, "root");
2487 }
2488 /* now, recalculate default kw if need be */
2489 if(uprv_strlen(defLoc) > uprv_strlen(full)) {
2490 const UChar *defUstr;
2491 int32_t defLen;
2492 /* look for default item */
2493 #if defined(URES_TREE_DEBUG)
2494 fprintf(stderr, "%s;%s -> recalculating Default0\n",
2495 path?path:"ICUDATA", full);
2496 #endif
2497 defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &de fLen, &subStatus);
2498 if(U_SUCCESS(subStatus) && defLen) {
2499 u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
2500 #if defined(URES_TREE_DEBUG)
2501 fprintf(stderr, "%s;%s -> default0 %s=%s, %s\n",
2502 path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus));
2503 #endif
2504 uprv_strcpy(defLoc, full);
2505 }
2506 } /* end of recalculate default KW */
2507 #if defined(URES_TREE_DEBUG)
2508 else {
2509 fprintf(stderr, "No trim0, %s <= %s\n", defLoc, full) ;
2510 }
2511 #endif
2512 } else {
2513 #if defined(URES_TREE_DEBUG)
2514 fprintf(stderr, "err=%s in %s looking for %s\n",
2515 u_errorName(subStatus), parent, kwVal);
2516 #endif
2517 }
2518 }
2519 }
2520
2521 subStatus = U_ZERO_ERROR;
2522
2523 uprv_strcpy(found, parent);
2524 uloc_getParent(found,parent,1023,&subStatus);
2525 ures_close(res);
2526 } while(!full[0] && *found && U_SUCCESS(*status));
2527
2528 if((full[0]==0) && uprv_strcmp(kwVal, defVal)) {
2529 #if defined(URES_TREE_DEBUG)
2530 fprintf(stderr, "Failed to locate kw %s - try default %s\n", kwVal, defV al);
2531 #endif
2532 uprv_strcpy(kwVal, defVal);
2533 uprv_strcpy(parent, base);
2534 uprv_strcpy(found, base);
2535
2536 do { /* search for 'default' named item */
2537 subStatus = U_ZERO_ERROR;
2538 res = ures_open(path, parent, &subStatus);
2539 if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
2540 *isAvailable = FALSE;
2541 }
2542 isAvailable = NULL; /* only want to set this the first time around * /
2543
2544 #if defined(URES_TREE_DEBUG)
2545 fprintf(stderr, "%s;%s -> %s (looking for default %s)\n",
2546 path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal);
2547 #endif
2548 if(U_FAILURE(subStatus)) {
2549 *status = subStatus;
2550 } else if(subStatus == U_ZERO_ERROR) {
2551 ures_getByKey(res,resName,&bund1, &subStatus);
2552 if(subStatus == U_ZERO_ERROR) {
2553 ures_getByKey(&bund1, kwVal, &bund2, &subStatus);
2554 if(subStatus == U_ZERO_ERROR) {
2555 #if defined(URES_TREE_DEBUG)
2556 fprintf(stderr, "%s;%s -> full1 %s=%s, %s\n", path?path :"ICUDATA",
2557 parent, keyword, kwVal, u_errorName(subStatus));
2558 #endif
2559 uprv_strcpy(full, parent);
2560 if(*full == 0) {
2561 uprv_strcpy(full, "root");
2562 }
2563
2564 /* now, recalculate default kw if need be */
2565 if(uprv_strlen(defLoc) > uprv_strlen(full)) {
2566 const UChar *defUstr;
2567 int32_t defLen;
2568 /* look for default item */
2569 #if defined(URES_TREE_DEBUG)
2570 fprintf(stderr, "%s;%s -> recalculating Default1\n",
2571 path?path:"ICUDATA", full);
2572 #endif
2573 defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &de fLen, &subStatus);
2574 if(U_SUCCESS(subStatus) && defLen) {
2575 u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
2576 #if defined(URES_TREE_DEBUG)
2577 fprintf(stderr, "%s;%s -> default %s=%s, %s\n",
2578 path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus));
2579 #endif
2580 uprv_strcpy(defLoc, full);
2581 }
2582 } /* end of recalculate default KW */
2583 #if defined(URES_TREE_DEBUG)
2584 else {
2585 fprintf(stderr, "No trim1, %s <= %s\n", defLoc, full) ;
2586 }
2587 #endif
2588 }
2589 }
2590 }
2591 subStatus = U_ZERO_ERROR;
2592
2593 uprv_strcpy(found, parent);
2594 uloc_getParent(found,parent,1023,&subStatus);
2595 ures_close(res);
2596 } while(!full[0] && *found && U_SUCCESS(*status));
2597 }
2598
2599 if(U_SUCCESS(*status)) {
2600 if(!full[0]) {
2601 #if defined(URES_TREE_DEBUG)
2602 fprintf(stderr, "Still could not load keyword %s=%s\n", keyword, kwVal );
2603 #endif
2604 *status = U_MISSING_RESOURCE_ERROR;
2605 } else if(omitDefault) {
2606 #if defined(URES_TREE_DEBUG)
2607 fprintf(stderr,"Trim? full=%s, defLoc=%s, found=%s\n", full, defLoc, f ound);
2608 #endif
2609 if(uprv_strlen(defLoc) <= uprv_strlen(full)) {
2610 /* found the keyword in a *child* of where the default tag was prese nt. */
2611 if(!uprv_strcmp(kwVal, defVal)) { /* if the requested kw is default, */
2612 /* and the default is in or in an ancestor of the current locale * /
2613 #if defined(URES_TREE_DEBUG)
2614 fprintf(stderr, "Removing unneeded var %s=%s\n", keyword, kwVal);
2615 #endif
2616 kwVal[0]=0;
2617 }
2618 }
2619 }
2620 uprv_strcpy(found, full);
2621 if(kwVal[0]) {
2622 uprv_strcat(found, "@");
2623 uprv_strcat(found, keyword);
2624 uprv_strcat(found, "=");
2625 uprv_strcat(found, kwVal);
2626 } else if(!omitDefault) {
2627 uprv_strcat(found, "@");
2628 uprv_strcat(found, keyword);
2629 uprv_strcat(found, "=");
2630 uprv_strcat(found, defVal);
2631 }
2632 }
2633 /* we found the default locale - no need to repeat it.*/
2634
2635 ures_close(&bund1);
2636 ures_close(&bund2);
2637
2638 length = (int32_t)uprv_strlen(found);
2639
2640 if(U_SUCCESS(*status)) {
2641 int32_t copyLength = uprv_min(length, resultCapacity);
2642 if(copyLength>0) {
2643 uprv_strncpy(result, found, copyLength);
2644 }
2645 if(length == 0) {
2646 *status = U_MISSING_RESOURCE_ERROR;
2647 }
2648 } else {
2649 length = 0;
2650 result[0]=0;
2651 }
2652 return u_terminateChars(result, resultCapacity, length, status);
2653 }
2654
2655 U_CAPI UEnumeration* U_EXPORT2
2656 ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status)
2657 {
2658 #define VALUES_BUF_SIZE 2048
2659 #define VALUES_LIST_SIZE 512
2660
2661 char valuesBuf[VALUES_BUF_SIZE];
2662 int32_t valuesIndex = 0;
2663 const char *valuesList[VALUES_LIST_SIZE];
2664 int32_t valuesCount = 0;
2665
2666 const char *locale;
2667 int32_t locLen;
2668
2669 UEnumeration *locs = NULL;
2670
2671 UResourceBundle item;
2672 UResourceBundle subItem;
2673
2674 ures_initStackObject(&item);
2675 ures_initStackObject(&subItem);
2676 locs = ures_openAvailableLocales(path, status);
2677
2678 if(U_FAILURE(*status)) {
2679 ures_close(&item);
2680 ures_close(&subItem);
2681 return NULL;
2682 }
2683
2684 valuesBuf[0]=0;
2685 valuesBuf[1]=0;
2686
2687 while((locale = uenum_next(locs, &locLen, status))) {
2688 UResourceBundle *bund = NULL;
2689 UResourceBundle *subPtr = NULL;
2690 UErrorCode subStatus = U_ZERO_ERROR; /* don't fail if a bundle is unopen able */
2691 bund = ures_openDirect(path, locale, &subStatus);
2692
2693 #if defined(URES_TREE_DEBUG)
2694 if(!bund || U_FAILURE(subStatus)) {
2695 fprintf(stderr, "%s-%s values: Can't open %s locale - skipping. (%s) \n",
2696 path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus));
2697 }
2698 #endif
2699
2700 ures_getByKey(bund, keyword, &item, &subStatus);
2701
2702 if(!bund || U_FAILURE(subStatus)) {
2703 #if defined(URES_TREE_DEBUG)
2704 fprintf(stderr, "%s-%s values: Can't find in %s - skipping. (%s)\n",
2705 path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus));
2706 #endif
2707 ures_close(bund);
2708 bund = NULL;
2709 continue;
2710 }
2711
2712 while((subPtr = ures_getNextResource(&item,&subItem,&subStatus))
2713 && U_SUCCESS(subStatus)) {
2714 const char *k;
2715 int32_t i;
2716 k = ures_getKey(subPtr);
2717
2718 #if defined(URES_TREE_DEBUG)
2719 /* fprintf(stderr, "%s | %s | %s | %s\n", path?path:"<ICUDATA>", key word, locale, k); */
2720 #endif
2721 for(i=0;k&&i<valuesCount;i++) {
2722 if(!uprv_strcmp(valuesList[i],k)) {
2723 k = NULL; /* found duplicate */
2724 }
2725 }
2726 if(k && *k) {
2727 int32_t kLen = (int32_t)uprv_strlen(k);
2728 if(!uprv_strcmp(k,DEFAULT_TAG)) {
2729 continue; /* don't need 'default'. */
2730 }
2731 if((valuesCount >= (VALUES_LIST_SIZE-1)) || /* no more spa ce in list .. */
2732 ((valuesIndex+kLen+1+1) >= VALUES_BUF_SIZE)) { /* no more sp ace in buffer (string + 2 nulls) */
2733 *status = U_ILLEGAL_ARGUMENT_ERROR; /* out of space.. */
2734 } else {
2735 uprv_strcpy(valuesBuf+valuesIndex, k);
2736 valuesList[valuesCount++] = valuesBuf+valuesIndex;
2737 valuesIndex += kLen;
2738 #if defined(URES_TREE_DEBUG)
2739 fprintf(stderr, "%s | %s | %s | [%s] (UNIQUE)\n",
2740 path?path:"<ICUDATA>", keyword, locale, k);
2741 #endif
2742 valuesBuf[valuesIndex++] = 0; /* terminate */
2743 }
2744 }
2745 }
2746 ures_close(bund);
2747 }
2748 valuesBuf[valuesIndex++] = 0; /* terminate */
2749
2750 ures_close(&item);
2751 ures_close(&subItem);
2752 uenum_close(locs);
2753 #if defined(URES_TREE_DEBUG)
2754 fprintf(stderr, "%s: size %d, #%d\n", u_errorName(*status),
2755 valuesIndex, valuesCount);
2756 #endif
2757 return uloc_openKeywordList(valuesBuf, valuesIndex, status);
2758 }
2759 #if 0
2760 /* This code isn't needed, and given the documentation warnings the implementati on is suspect */
2761 U_INTERNAL UBool U_EXPORT2
2762 ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
2763 if(res1==NULL || res2==NULL){
2764 return res1==res2; /* pointer comparision */
2765 }
2766 if(res1->fKey==NULL|| res2->fKey==NULL){
2767 return (res1->fKey==res2->fKey);
2768 }else{
2769 if(uprv_strcmp(res1->fKey, res2->fKey)!=0){
2770 return FALSE;
2771 }
2772 }
2773 if(uprv_strcmp(res1->fData->fName, res2->fData->fName)!=0){
2774 return FALSE;
2775 }
2776 if(res1->fData->fPath == NULL|| res2->fData->fPath==NULL){
2777 return (res1->fData->fPath == res2->fData->fPath);
2778 }else{
2779 if(uprv_strcmp(res1->fData->fPath, res2->fData->fPath)!=0){
2780 return FALSE;
2781 }
2782 }
2783 if(uprv_strcmp(res1->fData->fParent->fName, res2->fData->fParent->fName)!=0) {
2784 return FALSE;
2785 }
2786 if(uprv_strcmp(res1->fData->fParent->fPath, res2->fData->fParent->fPath)!=0) {
2787 return FALSE;
2788 }
2789 if(uprv_strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen)!=0){
2790 return FALSE;
2791 }
2792 if(res1->fRes != res2->fRes){
2793 return FALSE;
2794 }
2795 return TRUE;
2796 }
2797 U_INTERNAL UResourceBundle* U_EXPORT2
2798 ures_clone(const UResourceBundle* res, UErrorCode* status){
2799 UResourceBundle* bundle = NULL;
2800 UResourceBundle* ret = NULL;
2801 if(U_FAILURE(*status) || res == NULL){
2802 return NULL;
2803 }
2804 bundle = ures_open(res->fData->fPath, res->fData->fName, status);
2805 if(res->fResPath!=NULL){
2806 ret = ures_findSubResource(bundle, res->fResPath, NULL, status);
2807 ures_close(bundle);
2808 }else{
2809 ret = bundle;
2810 }
2811 return ret;
2812 }
2813 U_INTERNAL const UResourceBundle* U_EXPORT2
2814 ures_getParentBundle(const UResourceBundle* res){
2815 if(res==NULL){
2816 return NULL;
2817 }
2818 return res->fParentRes;
2819 }
2820 #endif
2821
2822 U_INTERNAL void U_EXPORT2
2823 ures_getVersionByKey(const UResourceBundle* res, const char *key, UVersionInfo v er, UErrorCode *status) {
2824 const UChar *str;
2825 int32_t len;
2826 str = ures_getStringByKey(res, key, &len, status);
2827 if(U_SUCCESS(*status)) {
2828 u_versionFromUString(ver, str);
2829 }
2830 }
2831
2832 /* eof */
OLDNEW
« no previous file with comments | « icu46/source/common/ures_cnv.c ('k') | icu46/source/common/uresdata.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698