Bug Summary

File:out/../deps/icu-small/source/common/uresbund.cpp
Warning:line 753, column 13
Value stored to 'hasRealData' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name uresbund.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D V8_DEPRECATION_WARNINGS -D V8_IMMINENT_DEPRECATION_WARNINGS -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D U_COMMON_IMPLEMENTATION=1 -D U_ATTRIBUTE_DEPRECATED= -D _CRT_SECURE_NO_DEPRECATE= -D U_STATIC_IMPLEMENTATION=1 -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/icu-small/source/common -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-deprecated-declarations -Wno-strict-aliasing -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/icu-small/source/common/uresbund.cpp
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5* Copyright (C) 1997-2016, International Business Machines Corporation and
6* others. All Rights Reserved.
7******************************************************************************
8*
9* File uresbund.cpp
10*
11* Modification History:
12*
13* Date Name Description
14* 04/01/97 aliu Creation.
15* 06/14/99 stephen Removed functions taking a filename suffix.
16* 07/20/99 stephen Changed for UResourceBundle typedef'd to void*
17* 11/09/99 weiv Added ures_getLocale()
18* March 2000 weiv Total overhaul - using data in DLLs
19* 06/20/2000 helena OS/400 port changes; mostly typecast.
20* 06/24/02 weiv Added support for resource sharing
21******************************************************************************
22*/
23
24#include "unicode/ures.h"
25#include "unicode/ustring.h"
26#include "unicode/ucnv.h"
27#include "charstr.h"
28#include "uresimp.h"
29#include "ustr_imp.h"
30#include "cwchar.h"
31#include "ucln_cmn.h"
32#include "cmemory.h"
33#include "cstring.h"
34#include "mutex.h"
35#include "uhash.h"
36#include "unicode/uenum.h"
37#include "uenumimp.h"
38#include "ulocimp.h"
39#include "umutex.h"
40#include "putilimp.h"
41#include "uassert.h"
42#include "uresdata.h"
43
44using namespace icu;
45
46/*
47Static cache for already opened resource bundles - mostly for keeping fallback info
48TODO: This cache should probably be removed when the deprecated code is
49 completely removed.
50*/
51static UHashtable *cache = NULL__null;
52static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER{{ 0 }, U_ZERO_ERROR};
53
54static UMutex resbMutex;
55
56/* INTERNAL: hashes an entry */
57static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
58 UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer;
59 UHashTok namekey, pathkey;
60 namekey.pointer = b->fName;
61 pathkey.pointer = b->fPath;
62 return uhash_hashCharsuhash_hashChars_71(namekey)+37u*uhash_hashCharsuhash_hashChars_71(pathkey);
63}
64
65/* INTERNAL: compares two entries */
66static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
67 UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer;
68 UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer;
69 UHashTok name1, name2, path1, path2;
70 name1.pointer = b1->fName;
71 name2.pointer = b2->fName;
72 path1.pointer = b1->fPath;
73 path2.pointer = b2->fPath;
74 return (UBool)(uhash_compareCharsuhash_compareChars_71(name1, name2) &&
75 uhash_compareCharsuhash_compareChars_71(path1, path2));
76}
77
78
79/**
80 * Internal function, gets parts of locale name according
81 * to the position of '_' character
82 */
83static UBool chopLocale(char *name) {
84 char *i = uprv_strrchr(name, '_'):: strrchr(name, '_');
85
86 if(i != NULL__null) {
87 *i = '\0';
88 return TRUE1;
89 }
90
91 return FALSE0;
92}
93
94/**
95 * Called to check whether a name without '_' needs to be checked for a parent.
96 * Some code had assumed that locale IDs with '_' could not have a non-root parent.
97 * We may want a better way of doing this.
98 */
99static UBool mayHaveParent(char *name) {
100 return (name[0] != 0 && uprv_strstr("nb nn",name):: strstr("nb nn", name) != nullptr);
101}
102
103/**
104 * Internal function
105 */
106static void entryIncrease(UResourceDataEntry *entry) {
107 Mutex lock(&resbMutex);
108 entry->fCountExisting++;
109 while(entry->fParent != NULL__null) {
110 entry = entry->fParent;
111 entry->fCountExisting++;
112 }
113}
114
115/**
116 * Internal function. Tries to find a resource in given Resource
117 * Bundle, as well as in its parents
118 */
119static UResourceDataEntry *getFallbackData(
120 const UResourceBundle *resBundle,
121 const char **resTag, Resource *res, UErrorCode *status) {
122 UResourceDataEntry *dataEntry = resBundle->fData;
123 int32_t indexR = -1;
124 int32_t i = 0;
125 *res = RES_BOGUS0xffffffff;
126 if(dataEntry == nullptr) {
127 *status = U_MISSING_RESOURCE_ERROR;
128 return nullptr;
129 }
130 if(dataEntry->fBogus == U_ZERO_ERROR) { /* if this resource is real, */
131 *res = res_getTableItemByKeyres_getTableItemByKey_71(&(dataEntry->fData), dataEntry->fData.rootRes, &indexR, resTag); /* try to get data from there */
132 i++;
133 }
134 if(resBundle->fHasFallback) {
135 // Otherwise, we'll look in parents.
136 while(*res == RES_BOGUS0xffffffff && dataEntry->fParent != nullptr) {
137 dataEntry = dataEntry->fParent;
138 if(dataEntry->fBogus == U_ZERO_ERROR) {
139 i++;
140 *res = res_getTableItemByKeyres_getTableItemByKey_71(&(dataEntry->fData), dataEntry->fData.rootRes, &indexR, resTag);
141 }
142 }
143 }
144
145 if(*res == RES_BOGUS0xffffffff) {
146 // If the resource is not found, we need to give an error.
147 *status = U_MISSING_RESOURCE_ERROR;
148 return nullptr;
149 }
150 // If the resource is found in parents, we need to adjust the error.
151 if(i>1) {
152 if(uprv_strcmp(dataEntry->fName, uloc_getDefault()):: strcmp(dataEntry->fName, uloc_getDefault_71())==0 || uprv_strcmp(dataEntry->fName, kRootLocaleName):: strcmp(dataEntry->fName, "root")==0) {
153 *status = U_USING_DEFAULT_WARNING;
154 } else {
155 *status = U_USING_FALLBACK_WARNING;
156 }
157 }
158 return dataEntry;
159}
160
161static void
162free_entry(UResourceDataEntry *entry) {
163 UResourceDataEntry *alias;
164 res_unloadres_unload_71(&(entry->fData));
165 if(entry->fName != NULL__null && entry->fName != entry->fNameBuffer) {
166 uprv_freeuprv_free_71(entry->fName);
167 }
168 if(entry->fPath != NULL__null) {
169 uprv_freeuprv_free_71(entry->fPath);
170 }
171 if(entry->fPool != NULL__null) {
172 --entry->fPool->fCountExisting;
173 }
174 alias = entry->fAlias;
175 if(alias != NULL__null) {
176 while(alias->fAlias != NULL__null) {
177 alias = alias->fAlias;
178 }
179 --alias->fCountExisting;
180 }
181 uprv_freeuprv_free_71(entry);
182}
183
184/* Works just like ucnv_flushCache() */
185static int32_t ures_flushCache()
186{
187 UResourceDataEntry *resB;
188 int32_t pos;
189 int32_t rbDeletedNum = 0;
190 const UHashElement *e;
191 UBool deletedMore;
192
193 /*if shared data hasn't even been lazy evaluated yet
194 * return 0
195 */
196 Mutex lock(&resbMutex);
197 if (cache == NULL__null) {
198 return 0;
199 }
200
201 do {
202 deletedMore = FALSE0;
203 /*creates an enumeration to iterate through every element in the table */
204 pos = UHASH_FIRST(-1);
205 while ((e = uhash_nextElementuhash_nextElement_71(cache, &pos)) != NULL__null)
206 {
207 resB = (UResourceDataEntry *) e->value.pointer;
208 /* Deletes only if reference counter == 0
209 * Don't worry about the children of this node.
210 * Those will eventually get deleted too, if not already.
211 * Don't worry about the parents of this node.
212 * Those will eventually get deleted too, if not already.
213 */
214 /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's not zero, that means that */
215 /* some resource bundles are still open somewhere. */
216
217 if (resB->fCountExisting == 0) {
218 rbDeletedNum++;
219 deletedMore = TRUE1;
220 uhash_removeElementuhash_removeElement_71(cache, e);
221 free_entry(resB);
222 }
223 }
224 /*
225 * Do it again to catch bundles (aliases, pool bundle) whose fCountExisting
226 * got decremented by free_entry().
227 */
228 } while(deletedMore);
229
230 return rbDeletedNum;
231}
232
233#ifdef URES_DEBUG
234#include <stdio.h>
235
236U_CAPIextern "C" UBool U_EXPORT2 ures_dumpCacheContents(void) {
237 UBool cacheNotEmpty = FALSE0;
238 int32_t pos = UHASH_FIRST(-1);
239 const UHashElement *e;
240 UResourceDataEntry *resB;
241
242 Mutex lock(&resbMutex);
243 if (cache == NULL__null) {
244 fprintf(stderrstderr,"%s:%d: RB Cache is NULL.\n", __FILE__"../deps/icu-small/source/common/uresbund.cpp", __LINE__244);
245 return FALSE0;
246 }
247
248 while ((e = uhash_nextElementuhash_nextElement_71(cache, &pos)) != NULL__null) {
249 cacheNotEmpty=TRUE1;
250 resB = (UResourceDataEntry *) e->value.pointer;
251 fprintf(stderrstderr,"%s:%d: RB Cache: Entry @0x%p, refcount %d, name %s:%s. Pool 0x%p, alias 0x%p, parent 0x%p\n",
252 __FILE__"../deps/icu-small/source/common/uresbund.cpp", __LINE__252,
253 (void*)resB, resB->fCountExisting,
254 resB->fName?resB->fName:"NULL",
255 resB->fPath?resB->fPath:"NULL",
256 (void*)resB->fPool,
257 (void*)resB->fAlias,
258 (void*)resB->fParent);
259 }
260
261 fprintf(stderrstderr,"%s:%d: RB Cache still contains %d items.\n", __FILE__"../deps/icu-small/source/common/uresbund.cpp", __LINE__261, uhash_countuhash_count_71(cache));
262 return cacheNotEmpty;
263}
264
265#endif
266
267static UBool U_CALLCONV ures_cleanup(void)
268{
269 if (cache != NULL__null) {
270 ures_flushCache();
271 uhash_closeuhash_close_71(cache);
272 cache = NULL__null;
273 }
274 gCacheInitOnce.reset();
275 return TRUE1;
276}
277
278/** INTERNAL: Initializes the cache for resources */
279static void U_CALLCONV createCache(UErrorCode &status) {
280 U_ASSERT(cache == NULL)(void)0;
281 cache = uhash_openuhash_open_71(hashEntry, compareEntries, NULL__null, &status);
282 ucln_common_registerCleanupucln_common_registerCleanup_71(UCLN_COMMON_URES, ures_cleanup);
283}
284
285static void initCache(UErrorCode *status) {
286 umtx_initOnce(gCacheInitOnce, &createCache, *status);
287}
288
289/** INTERNAL: sets the name (locale) of the resource bundle to given name */
290
291static void setEntryName(UResourceDataEntry *res, const char *name, UErrorCode *status) {
292 int32_t len = (int32_t)uprv_strlen(name):: strlen(name);
293 if(res->fName != NULL__null && res->fName != res->fNameBuffer) {
294 uprv_freeuprv_free_71(res->fName);
295 }
296 if (len < (int32_t)sizeof(res->fNameBuffer)) {
297 res->fName = res->fNameBuffer;
298 }
299 else {
300 res->fName = (char *)uprv_mallocuprv_malloc_71(len+1);
301 }
302 if(res->fName == NULL__null) {
303 *status = U_MEMORY_ALLOCATION_ERROR;
304 } else {
305 uprv_strcpy(res->fName, name):: strcpy(res->fName, name);
306 }
307}
308
309static UResourceDataEntry *
310getPoolEntry(const char *path, UErrorCode *status);
311
312/**
313 * INTERNAL: Inits and opens an entry from a data DLL.
314 * CAUTION: resbMutex must be locked when calling this function.
315 */
316static UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) {
317 UResourceDataEntry *r = NULL__null;
318 UResourceDataEntry find;
319 /*int32_t hashValue;*/
320 const char *name;
321 char aliasName[100] = { 0 };
322 int32_t aliasLen = 0;
323 /*UBool isAlias = FALSE;*/
324 /*UHashTok hashkey; */
325
326 if(U_FAILURE(*status)) {
327 return NULL__null;
328 }
329
330 /* here we try to deduce the right locale name */
331 if(localeID == NULL__null) { /* if localeID is NULL, we're trying to open default locale */
332 name = uloc_getDefaultuloc_getDefault_71();
333 } else if(*localeID == 0) { /* if localeID is "" then we try to open root locale */
334 name = kRootLocaleName"root";
335 } else { /* otherwise, we'll open what we're given */
336 name = localeID;
337 }
338
339 find.fName = (char *)name;
340 find.fPath = (char *)path;
341
342 /* calculate the hash value of the entry */
343 /*hashkey.pointer = (void *)&find;*/
344 /*hashValue = hashEntry(hashkey);*/
345
346 /* check to see if we already have this entry */
347 r = (UResourceDataEntry *)uhash_getuhash_get_71(cache, &find);
348 if(r == NULL__null) {
349 /* if the entry is not yet in the hash table, we'll try to construct a new one */
350 r = (UResourceDataEntry *) uprv_mallocuprv_malloc_71(sizeof(UResourceDataEntry));
351 if(r == NULL__null) {
352 *status = U_MEMORY_ALLOCATION_ERROR;
353 return NULL__null;
354 }
355
356 uprv_memset(r, 0, sizeof(UResourceDataEntry)):: memset(r, 0, sizeof(UResourceDataEntry));
357 /*r->fHashKey = hashValue;*/
358
359 setEntryName(r, name, status);
360 if (U_FAILURE(*status)) {
361 uprv_freeuprv_free_71(r);
362 return NULL__null;
363 }
364
365 if(path != NULL__null) {
366 r->fPath = (char *)uprv_strdupuprv_strdup_71(path);
367 if(r->fPath == NULL__null) {
368 *status = U_MEMORY_ALLOCATION_ERROR;
369 uprv_freeuprv_free_71(r);
370 return NULL__null;
371 }
372 }
373
374 /* this is the actual loading */
375 res_loadres_load_71(&(r->fData), r->fPath, r->fName, status);
376
377 if (U_FAILURE(*status)) {
378 /* if we failed to load due to an out-of-memory error, exit early. */
379 if (*status == U_MEMORY_ALLOCATION_ERROR) {
380 uprv_freeuprv_free_71(r);
381 return NULL__null;
382 }
383 /* we have no such entry in dll, so it will always use fallback */
384 *status = U_USING_FALLBACK_WARNING;
385 r->fBogus = U_USING_FALLBACK_WARNING;
386 } else { /* if we have a regular entry */
387 Resource aliasres;
388 if (r->fData.usesPoolBundle) {
389 r->fPool = getPoolEntry(r->fPath, status);
390 if (U_SUCCESS(*status)) {
391 const int32_t *poolIndexes = r->fPool->fData.pRoot + 1;
392 if(r->fData.pRoot[1 + URES_INDEX_POOL_CHECKSUM] == poolIndexes[URES_INDEX_POOL_CHECKSUM]) {
393 r->fData.poolBundleKeys = (const char *)(poolIndexes + (poolIndexes[URES_INDEX_LENGTH] & 0xff));
394 r->fData.poolBundleStrings = r->fPool->fData.p16BitUnits;
395 } else {
396 r->fBogus = *status = U_INVALID_FORMAT_ERROR;
397 }
398 } else {
399 r->fBogus = *status;
400 }
401 }
402 if (U_SUCCESS(*status)) {
403 /* handle the alias by trying to get out the %%Alias tag.*/
404 /* We'll try to get alias string from the bundle */
405 aliasres = res_getResourceres_getResource_71(&(r->fData), "%%ALIAS");
406 if (aliasres != RES_BOGUS0xffffffff) {
407 // No tracing: called during initial data loading
408 const UChar *alias = res_getStringNoTraceres_getStringNoTrace_71(&(r->fData), aliasres, &aliasLen);
409 if(alias != NULL__null && aliasLen > 0) { /* if there is actual alias - unload and load new data */
410 u_UCharsToCharsu_UCharsToChars_71(alias, aliasName, aliasLen+1);
411 r->fAlias = init_entry(aliasName, path, status);
412 }
413 }
414 }
415 }
416
417 {
418 UResourceDataEntry *oldR = NULL__null;
419 if((oldR = (UResourceDataEntry *)uhash_getuhash_get_71(cache, r)) == NULL__null) { /* if the data is not cached */
420 /* just insert it in the cache */
421 UErrorCode cacheStatus = U_ZERO_ERROR;
422 uhash_putuhash_put_71(cache, (void *)r, r, &cacheStatus);
423 if (U_FAILURE(cacheStatus)) {
424 *status = cacheStatus;
425 free_entry(r);
426 r = NULL__null;
427 }
428 } else {
429 /* somebody have already inserted it while we were working, discard newly opened data */
430 /* Also, we could get here IF we opened an alias */
431 free_entry(r);
432 r = oldR;
433 }
434 }
435
436 }
437 if(r != NULL__null) {
438 /* return the real bundle */
439 while(r->fAlias != NULL__null) {
440 r = r->fAlias;
441 }
442 r->fCountExisting++; /* we increase its reference count */
443 /* if the resource has a warning */
444 /* we don't want to overwrite a status with no error */
445 if(r->fBogus != U_ZERO_ERROR && U_SUCCESS(*status)) {
446 *status = r->fBogus; /* set the returning status */
447 }
448 }
449 return r;
450}
451
452static UResourceDataEntry *
453getPoolEntry(const char *path, UErrorCode *status) {
454 UResourceDataEntry *poolBundle = init_entry(kPoolBundleName"pool", path, status);
455 if( U_SUCCESS(*status) &&
456 (poolBundle == NULL__null || poolBundle->fBogus != U_ZERO_ERROR || !poolBundle->fData.isPoolBundle)
457 ) {
458 *status = U_INVALID_FORMAT_ERROR;
459 }
460 return poolBundle;
461}
462
463/* INTERNAL: */
464/* CAUTION: resbMutex must be locked when calling this function! */
465static UResourceDataEntry *
466findFirstExisting(const char* path, char* name, const char* defaultLocale,
467 UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
468 UResourceDataEntry *r = NULL__null;
469 UBool hasRealData = FALSE0;
470 *hasChopped = TRUE1; /* we're starting with a fresh name */
471
472 while(*hasChopped && !hasRealData) {
473 r = init_entry(name, path, status);
474 /* Null pointer test */
475 if (U_FAILURE(*status)) {
476 return NULL__null;
477 }
478 *isDefault = (UBool)(uprv_strncmp(name, defaultLocale, uprv_strlen(name)):: strncmp(name, defaultLocale, :: strlen(name)) == 0);
479 hasRealData = (UBool)(r->fBogus == U_ZERO_ERROR);
480 if(!hasRealData) {
481 /* this entry is not real. We will discard it. */
482 /* However, the parent line for this entry is */
483 /* not to be used - as there might be parent */
484 /* lines in cache from previous openings that */
485 /* are not updated yet. */
486 r->fCountExisting--;
487 /*entryCloseInt(r);*/
488 r = NULL__null;
489 *status = U_USING_FALLBACK_WARNING;
490 } else {
491 uprv_strcpy(name, r->fName):: strcpy(name, r->fName); /* this is needed for supporting aliases */
492 }
493
494 *isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName):: strcmp(name, "root") == 0);
495
496 /*Fallback data stuff*/
497 *hasChopped = chopLocale(name);
498 if (*hasChopped && *name == '\0') {
499 uprv_strcpy(name, "und"):: strcpy(name, "und");
500 }
501 }
502 return r;
503}
504
505static void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
506 if(state) {
507 resB->fMagic1 = 0;
508 resB->fMagic2 = 0;
509 } else {
510 resB->fMagic1 = MAGIC119700503;
511 resB->fMagic2 = MAGIC219641227;
512 }
513}
514
515static UBool ures_isStackObject(const UResourceBundle* resB) {
516 return((resB->fMagic1 == MAGIC119700503 && resB->fMagic2 == MAGIC219641227)?FALSE0:TRUE1);
517}
518
519
520U_CFUNCextern "C" void ures_initStackObjectures_initStackObject_71(UResourceBundle* resB) {
521 uprv_memset(resB, 0, sizeof(UResourceBundle)):: memset(resB, 0, sizeof(UResourceBundle));
522 ures_setIsStackObject(resB, TRUE1);
523}
524
525U_NAMESPACE_BEGINnamespace icu_71 {
526
527StackUResourceBundle::StackUResourceBundle() {
528 ures_initStackObjectures_initStackObject_71(&bundle);
529}
530
531StackUResourceBundle::~StackUResourceBundle() {
532 ures_closeures_close_71(&bundle);
533}
534
535U_NAMESPACE_END}
536
537static UBool // returns U_SUCCESS(*status)
538loadParentsExceptRoot(UResourceDataEntry *&t1,
539 char name[], int32_t nameCapacity,
540 UBool usingUSRData, char usrDataPath[], UErrorCode *status) {
541 if (U_FAILURE(*status)) { return FALSE0; }
542 UBool checkParent = TRUE1;
543 while (checkParent && t1->fParent == NULL__null && !t1->fData.noFallback &&
544 res_getResourceres_getResource_71(&t1->fData,"%%ParentIsRoot") == RES_BOGUS0xffffffff) {
545 Resource parentRes = res_getResourceres_getResource_71(&t1->fData, "%%Parent");
546 if (parentRes != RES_BOGUS0xffffffff) { // An explicit parent was found.
547 int32_t parentLocaleLen = 0;
548 // No tracing: called during initial data loading
549 const UChar *parentLocaleName = res_getStringNoTraceres_getStringNoTrace_71(&(t1->fData), parentRes, &parentLocaleLen);
550 if(parentLocaleName != NULL__null && 0 < parentLocaleLen && parentLocaleLen < nameCapacity) {
551 u_UCharsToCharsu_UCharsToChars_71(parentLocaleName, name, parentLocaleLen + 1);
552 if (uprv_strcmp(name, kRootLocaleName):: strcmp(name, "root") == 0) {
553 return TRUE1;
554 }
555 }
556 }
557 // Insert regular parents.
558 UErrorCode parentStatus = U_ZERO_ERROR;
559 UResourceDataEntry *t2 = init_entry(name, t1->fPath, &parentStatus);
560 if (U_FAILURE(parentStatus)) {
561 *status = parentStatus;
562 return FALSE0;
563 }
564 UResourceDataEntry *u2 = NULL__null;
565 UErrorCode usrStatus = U_ZERO_ERROR;
566 if (usingUSRData) { // This code inserts user override data into the inheritance chain.
567 u2 = init_entry(name, usrDataPath, &usrStatus);
568 // If we failed due to out-of-memory, report that to the caller and exit early.
569 if (usrStatus == U_MEMORY_ALLOCATION_ERROR) {
570 *status = usrStatus;
571 return FALSE0;
572 }
573 }
574
575 if (usingUSRData && U_SUCCESS(usrStatus) && u2->fBogus == U_ZERO_ERROR) {
576 t1->fParent = u2;
577 u2->fParent = t2;
578 } else {
579 t1->fParent = t2;
580 if (usingUSRData) {
581 // The USR override data wasn't found, set it to be deleted.
582 u2->fCountExisting = 0;
583 }
584 }
585 t1 = t2;
586 checkParent = chopLocale(name) || mayHaveParent(name);
587 }
588 return TRUE1;
589}
590
591static UBool // returns U_SUCCESS(*status)
592insertRootBundle(UResourceDataEntry *&t1, UErrorCode *status) {
593 if (U_FAILURE(*status)) { return FALSE0; }
594 UErrorCode parentStatus = U_ZERO_ERROR;
595 UResourceDataEntry *t2 = init_entry(kRootLocaleName"root", t1->fPath, &parentStatus);
596 if (U_FAILURE(parentStatus)) {
597 *status = parentStatus;
598 return FALSE0;
599 }
600 t1->fParent = t2;
601 t1 = t2;
602 return TRUE1;
603}
604
605enum UResOpenType {
606 /**
607 * Open a resource bundle for the locale;
608 * if there is not even a base language bundle, then fall back to the default locale;
609 * if there is no bundle for that either, then load the root bundle.
610 *
611 * This is the default bundle loading behavior.
612 */
613 URES_OPEN_LOCALE_DEFAULT_ROOT,
614 // TODO: ICU ticket #11271 "consistent default locale across locale trees"
615 // Add an option to look at the main locale tree for whether to
616 // fall back to root directly (if the locale has main data) or
617 // fall back to the default locale first (if the locale does not even have main data).
618 /**
619 * Open a resource bundle for the locale;
620 * if there is not even a base language bundle, then load the root bundle;
621 * never fall back to the default locale.
622 *
623 * This is used for algorithms that have good pan-Unicode default behavior,
624 * such as case mappings, collation, and segmentation (BreakIterator).
625 */
626 URES_OPEN_LOCALE_ROOT,
627 /**
628 * Open a resource bundle for the exact bundle name as requested;
629 * no fallbacks, do not load parent bundles.
630 *
631 * This is used for supplemental (non-locale) data.
632 */
633 URES_OPEN_DIRECT
634};
635typedef enum UResOpenType UResOpenType;
636
637static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
638 UResOpenType openType, UErrorCode* status) {
639 U_ASSERT(openType != URES_OPEN_DIRECT)(void)0;
640 UErrorCode intStatus = U_ZERO_ERROR;
641 UResourceDataEntry *r = NULL__null;
642 UResourceDataEntry *t1 = NULL__null;
643 UBool isDefault = FALSE0;
644 UBool isRoot = FALSE0;
645 UBool hasRealData = FALSE0;
646 UBool hasChopped = TRUE1;
647 UBool usingUSRData = U_USE_USRDATA0 && ( path == NULL__null || uprv_strncmp(path,U_ICUDATA_NAME,8):: strncmp(path, "icudt" "71" "l", 8) == 0);
648
649 char name[ULOC_FULLNAME_CAPACITY157];
650 char usrDataPath[96];
651
652 initCache(status);
653
654 if(U_FAILURE(*status)) {
655 return NULL__null;
656 }
657
658 uprv_strncpy(name, localeID, sizeof(name) - 1):: strncpy(name, localeID, sizeof(name) - 1);
659 name[sizeof(name) - 1] = 0;
660
661 if ( usingUSRData ) {
662 if ( path == NULL__null ) {
663 uprv_strcpy(usrDataPath, U_USRDATA_NAME):: strcpy(usrDataPath, "usrdt" "71" "l");
664 } else {
665 uprv_strncpy(usrDataPath, path, sizeof(usrDataPath) - 1):: strncpy(usrDataPath, path, sizeof(usrDataPath) - 1);
666 usrDataPath[0] = 'u';
667 usrDataPath[1] = 's';
668 usrDataPath[2] = 'r';
669 usrDataPath[sizeof(usrDataPath) - 1] = 0;
670 }
671 }
672
673 // Note: We need to query the default locale *before* locking resbMutex.
674 const char *defaultLocale = uloc_getDefaultuloc_getDefault_71();
675
676 Mutex lock(&resbMutex); // Lock resbMutex until the end of this function.
677
678 /* We're going to skip all the locales that do not have any data */
679 r = findFirstExisting(path, name, defaultLocale, &isRoot, &hasChopped, &isDefault, &intStatus);
680
681 // If we failed due to out-of-memory, report the failure and exit early.
682 if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
683 *status = intStatus;
684 goto finish;
685 }
686
687 if(r != NULL__null) { /* if there is one real locale, we can look for parents. */
688 t1 = r;
689 hasRealData = TRUE1;
690 if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */
691 UErrorCode usrStatus = U_ZERO_ERROR;
692 UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
693 // If we failed due to out-of-memory, report the failure and exit early.
694 if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
695 *status = intStatus;
696 goto finish;
697 }
698 if ( u1 != NULL__null ) {
699 if(u1->fBogus == U_ZERO_ERROR) {
700 u1->fParent = t1;
701 r = u1;
702 } else {
703 /* the USR override data wasn't found, set it to be deleted */
704 u1->fCountExisting = 0;
705 }
706 }
707 }
708 if ((hasChopped || mayHaveParent(name)) && !isRoot) {
709 if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name)(int32_t)(sizeof(name)/sizeof((name)[0])), usingUSRData, usrDataPath, status)) {
710 goto finish;
711 }
712 }
713 }
714
715 /* we could have reached this point without having any real data */
716 /* if that is the case, we need to chain in the default locale */
717 if(r==NULL__null && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault && !isRoot) {
718 /* insert default locale */
719 uprv_strcpy(name, defaultLocale):: strcpy(name, defaultLocale);
720 r = findFirstExisting(path, name, defaultLocale, &isRoot, &hasChopped, &isDefault, &intStatus);
721 // If we failed due to out-of-memory, report the failure and exit early.
722 if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
723 *status = intStatus;
724 goto finish;
725 }
726 intStatus = U_USING_DEFAULT_WARNING;
727 if(r != NULL__null) { /* the default locale exists */
728 t1 = r;
729 hasRealData = TRUE1;
730 isDefault = TRUE1;
731 // TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
732 if ((hasChopped || mayHaveParent(name)) && !isRoot) {
733 if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name)(int32_t)(sizeof(name)/sizeof((name)[0])), usingUSRData, usrDataPath, status)) {
734 goto finish;
735 }
736 }
737 }
738 }
739
740 /* we could still have r == NULL at this point - maybe even default locale is not */
741 /* present */
742 if(r == NULL__null) {
743 uprv_strcpy(name, kRootLocaleName):: strcpy(name, "root");
744 r = findFirstExisting(path, name, defaultLocale, &isRoot, &hasChopped, &isDefault, &intStatus);
745 // If we failed due to out-of-memory, report the failure and exit early.
746 if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
747 *status = intStatus;
748 goto finish;
749 }
750 if(r != NULL__null) {
751 t1 = r;
752 intStatus = U_USING_DEFAULT_WARNING;
753 hasRealData = TRUE1;
Value stored to 'hasRealData' is never read
754 } else { /* we don't even have the root locale */
755 *status = U_MISSING_RESOURCE_ERROR;
756 goto finish;
757 }
758 } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName):: strcmp(t1->fName, "root") != 0 &&
759 t1->fParent == NULL__null && !r->fData.noFallback) {
760 if (!insertRootBundle(t1, status)) {
761 goto finish;
762 }
763 if(!hasRealData) {
764 r->fBogus = U_USING_DEFAULT_WARNING;
765 }
766 }
767
768 // TODO: Does this ever loop?
769 while(r != NULL__null && !isRoot && t1->fParent != NULL__null) {
770 t1->fParent->fCountExisting++;
771 t1 = t1->fParent;
772 }
773
774finish:
775 if(U_SUCCESS(*status)) {
776 if(intStatus != U_ZERO_ERROR) {
777 *status = intStatus;
778 }
779 return r;
780 } else {
781 return NULL__null;
782 }
783}
784
785/**
786 * Version of entryOpen() and findFirstExisting() for ures_openDirect(),
787 * with no fallbacks.
788 * Parent and root locale bundles are loaded if
789 * the requested bundle does not have the "nofallback" flag.
790 */
791static UResourceDataEntry *
792entryOpenDirect(const char* path, const char* localeID, UErrorCode* status) {
793 initCache(status);
794 if(U_FAILURE(*status)) {
795 return NULL__null;
796 }
797
798 // Note: We need to query the default locale *before* locking resbMutex.
799 // If the localeID is NULL, then we want to use the default locale.
800 if (localeID == NULL__null) {
801 localeID = uloc_getDefaultuloc_getDefault_71();
802 } else if (*localeID == 0) {
803 // If the localeID is "", then we want to use the root locale.
804 localeID = kRootLocaleName"root";
805 }
806
807 Mutex lock(&resbMutex);
808
809 // findFirstExisting() without fallbacks.
810 UResourceDataEntry *r = init_entry(localeID, path, status);
811 if(U_SUCCESS(*status)) {
812 if(r->fBogus != U_ZERO_ERROR) {
813 r->fCountExisting--;
814 r = NULL__null;
815 }
816 } else {
817 r = NULL__null;
818 }
819
820 // Some code depends on the ures_openDirect() bundle to have a parent bundle chain,
821 // unless it is marked with "nofallback".
822 UResourceDataEntry *t1 = r;
823 if(r != NULL__null && uprv_strcmp(localeID, kRootLocaleName):: strcmp(localeID, "root") != 0 && // not root
824 r->fParent == NULL__null && !r->fData.noFallback &&
825 uprv_strlen(localeID):: strlen(localeID) < ULOC_FULLNAME_CAPACITY157) {
826 char name[ULOC_FULLNAME_CAPACITY157];
827 uprv_strcpy(name, localeID):: strcpy(name, localeID);
828 if(!chopLocale(name) || uprv_strcmp(name, kRootLocaleName):: strcmp(name, "root") == 0 ||
829 loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name)(int32_t)(sizeof(name)/sizeof((name)[0])), FALSE0, NULL__null, status)) {
830 if(uprv_strcmp(t1->fName, kRootLocaleName):: strcmp(t1->fName, "root") != 0 && t1->fParent == NULL__null) {
831 insertRootBundle(t1, status);
832 }
833 }
834 if(U_FAILURE(*status)) {
835 r = NULL__null;
836 }
837 }
838
839 if(r != NULL__null) {
840 // TODO: Does this ever loop?
841 while(t1->fParent != NULL__null) {
842 t1->fParent->fCountExisting++;
843 t1 = t1->fParent;
844 }
845 }
846 return r;
847}
848
849/**
850 * Functions to create and destroy resource bundles.
851 * CAUTION: resbMutex must be locked when calling this function.
852 */
853/* INTERNAL: */
854static void entryCloseInt(UResourceDataEntry *resB) {
855 UResourceDataEntry *p = resB;
856
857 while(resB != NULL__null) {
858 p = resB->fParent;
859 resB->fCountExisting--;
860
861 /* Entries are left in the cache. TODO: add ures_flushCache() to force a flush
862 of the cache. */
863/*
864 if(resB->fCountExisting <= 0) {
865 uhash_remove(cache, resB);
866 if(resB->fBogus == U_ZERO_ERROR) {
867 res_unload(&(resB->fData));
868 }
869 if(resB->fName != NULL) {
870 uprv_free(resB->fName);
871 }
872 if(resB->fPath != NULL) {
873 uprv_free(resB->fPath);
874 }
875 uprv_free(resB);
876 }
877*/
878
879 resB = p;
880 }
881}
882
883/**
884 * API: closes a resource bundle and cleans up.
885 */
886
887static void entryClose(UResourceDataEntry *resB) {
888 Mutex lock(&resbMutex);
889 entryCloseInt(resB);
890}
891
892/*
893U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
894 if(resB->fResPath == NULL) {
895 resB->fResPath = resB->fResBuf;
896 *(resB->fResPath) = 0;
897 }
898 resB->fResPathLen = uprv_strlen(toAdd);
899 if(RES_BUFSIZE <= resB->fResPathLen+1) {
900 if(resB->fResPath == resB->fResBuf) {
901 resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
902 } else {
903 resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
904 }
905 }
906 uprv_strcpy(resB->fResPath, toAdd);
907}
908*/
909static void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd, UErrorCode *status) {
910 int32_t resPathLenOrig = resB->fResPathLen;
911 if(resB->fResPath == NULL__null) {
912 resB->fResPath = resB->fResBuf;
913 *(resB->fResPath) = 0;
914 resB->fResPathLen = 0;
915 }
916 resB->fResPathLen += lenToAdd;
917 if(RES_BUFSIZE64 <= resB->fResPathLen+1) {
918 if(resB->fResPath == resB->fResBuf) {
919 resB->fResPath = (char *)uprv_mallocuprv_malloc_71((resB->fResPathLen+1)*sizeof(char));
920 /* Check that memory was allocated correctly. */
921 if (resB->fResPath == NULL__null) {
922 *status = U_MEMORY_ALLOCATION_ERROR;
923 return;
924 }
925 uprv_strcpy(resB->fResPath, resB->fResBuf):: strcpy(resB->fResPath, resB->fResBuf);
926 } else {
927 char *temp = (char *)uprv_reallocuprv_realloc_71(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
928 /* Check that memory was reallocated correctly. */
929 if (temp == NULL__null) {
930 *status = U_MEMORY_ALLOCATION_ERROR;
931 return;
932 }
933 resB->fResPath = temp;
934 }
935 }
936 uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd):: strcpy(resB->fResPath + resPathLenOrig, toAdd);
937}
938
939static void ures_freeResPath(UResourceBundle *resB) {
940 if (resB->fResPath && resB->fResPath != resB->fResBuf) {
941 uprv_freeuprv_free_71(resB->fResPath);
942 }
943 resB->fResPath = NULL__null;
944 resB->fResPathLen = 0;
945}
946
947static void
948ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj)
949{
950 if(resB != NULL__null) {
951 if(resB->fData != NULL__null) {
952 entryClose(resB->fData);
953 }
954 if(resB->fVersion != NULL__null) {
955 uprv_freeuprv_free_71(resB->fVersion);
956 }
957 ures_freeResPath(resB);
958
959 if(ures_isStackObject(resB) == FALSE0 && freeBundleObj) {
960 uprv_freeuprv_free_71(resB);
961 }
962#if 0 /*U_DEBUG*/
963 else {
964 /* poison the data */
965 uprv_memset(resB, -1, sizeof(UResourceBundle)):: memset(resB, -1, sizeof(UResourceBundle));
966 }
967#endif
968 }
969}
970
971U_CAPIextern "C" void U_EXPORT2
972ures_closeures_close_71(UResourceBundle* resB)
973{
974 ures_closeBundle(resB, TRUE1);
975}
976
977namespace {
978
979UResourceBundle *init_resb_result(
980 UResourceDataEntry *dataEntry, Resource r, const char *key, int32_t idx,
981 UResourceDataEntry *validLocaleDataEntry, const char *containerResPath,
982 int32_t recursionDepth,
983 UResourceBundle *resB, UErrorCode *status);
984
985// TODO: Try to refactor further, so that we output a dataEntry + Resource + (optionally) resPath,
986// rather than a UResourceBundle.
987// May need to entryIncrease() the resulting dataEntry.
988UResourceBundle *getAliasTargetAsResourceBundle(
989 const ResourceData &resData, Resource r, const char *key, int32_t idx,
990 UResourceDataEntry *validLocaleDataEntry, const char *containerResPath,
991 int32_t recursionDepth,
992 UResourceBundle *resB, UErrorCode *status) {
993 // TODO: When an error occurs: Should we return nullptr vs. resB?
994 if (U_FAILURE(*status)) { return resB; }
995 U_ASSERT(RES_GET_TYPE(r) == URES_ALIAS)(void)0;
996 int32_t len = 0;
997 const UChar *alias = res_getAliasres_getAlias_71(&resData, r, &len);
998 if(len <= 0) {
999 // bad alias
1000 *status = U_ILLEGAL_ARGUMENT_ERROR;
1001 return resB;
1002 }
1003
1004 // Copy the UTF-16 alias string into an invariant-character string.
1005 //
1006 // We do this so that res_findResource() can modify the path,
1007 // which allows us to remove redundant _res_findResource() variants
1008 // in uresdata.c.
1009 // res_findResource() now NUL-terminates each segment so that table keys
1010 // can always be compared with strcmp() instead of strncmp().
1011 // Saves code there and simplifies testing and code coverage.
1012 //
1013 // markus 2003oct17
1014 CharString chAlias;
1015 chAlias.appendInvariantChars(alias, len, *status);
1016 if (U_FAILURE(*status)) {
1017 return nullptr;
1018 }
1019
1020 // We have an alias, now let's cut it up.
1021 const char *path = nullptr, *locale = nullptr, *keyPath = nullptr;
1022 if(chAlias[0] == RES_PATH_SEPARATOR'/') {
1023 // There is a path included.
1024 char *chAliasData = chAlias.data();
1025 char *sep = chAliasData + 1;
1026 path = sep;
1027 sep = uprv_strchr(sep, RES_PATH_SEPARATOR):: strchr(sep, '/');
1028 if(sep != nullptr) {
1029 *sep++ = 0;
1030 }
1031 if(uprv_strcmp(path, "LOCALE"):: strcmp(path, "LOCALE") == 0) {
1032 // This is an XPath alias, starting with "/LOCALE/".
1033 // It contains the path to a resource which should be looked up
1034 // starting in the valid locale.
1035 // TODO: Can/should we forbid a /LOCALE alias without key path?
1036 // It seems weird to alias to the same path, just starting from the valid locale.
1037 // That will often yield an infinite loop.
1038 keyPath = sep;
1039 // Read from the valid locale which we already have.
1040 path = locale = nullptr;
1041 } else {
1042 if(uprv_strcmp(path, "ICUDATA"):: strcmp(path, "ICUDATA") == 0) { /* want ICU data */
1043 path = nullptr;
1044 }
1045 if (sep == nullptr) {
1046 // TODO: This ends up using the root bundle. Can/should we forbid this?
1047 locale = "";
1048 } else {
1049 locale = sep;
1050 sep = uprv_strchr(sep, RES_PATH_SEPARATOR):: strchr(sep, '/');
1051 if(sep != nullptr) {
1052 *sep++ = 0;
1053 }
1054 keyPath = sep;
1055 }
1056 }
1057 } else {
1058 // No path, start with a locale.
1059 char *sep = chAlias.data();
1060 locale = sep;
1061 sep = uprv_strchr(sep, RES_PATH_SEPARATOR):: strchr(sep, '/');
1062 if(sep != nullptr) {
1063 *sep++ = 0;
1064 }
1065 keyPath = sep;
1066 path = validLocaleDataEntry->fPath;
1067 }
1068
1069 // Got almost everything, let's try to open.
1070 // First, open the bundle with real data.
1071 LocalUResourceBundlePointer mainRes;
1072 UResourceDataEntry *dataEntry;
1073 if (locale == nullptr) {
1074 // alias = /LOCALE/keyPath
1075 // Read from the valid locale which we already have.
1076 dataEntry = validLocaleDataEntry;
1077 } else {
1078 UErrorCode intStatus = U_ZERO_ERROR;
1079 // TODO: Shouldn't we use ures_open() for locale data bundles (!noFallback)?
1080 mainRes.adoptInstead(ures_openDirectures_openDirect_71(path, locale, &intStatus));
1081 if(U_FAILURE(intStatus)) {
1082 // We failed to open the resource bundle we're aliasing to.
1083 *status = intStatus;
1084 return resB;
1085 }
1086 dataEntry = mainRes->fData;
1087 }
1088
1089 const char* temp = nullptr;
1090 if(keyPath == nullptr) {
1091 // No key path. This means that we are going to to use the corresponding resource from
1092 // another bundle.
1093 // TODO: Why the special code path?
1094 // Why not put together a key path from containerResPath + key or idx,
1095 // as a comment below suggests, and go into the regular code branch?
1096 // First, we are going to get a corresponding container
1097 // resource to the one we are searching.
1098 r = dataEntry->fData.rootRes;
1099 if(containerResPath) {
1100 chAlias.clear().append(containerResPath, *status);
1101 if (U_FAILURE(*status)) {
1102 return nullptr;
1103 }
1104 char *aKey = chAlias.data();
1105 // TODO: should res_findResource() return a new dataEntry, too?
1106 r = res_findResourceres_findResource_71(&dataEntry->fData, r, &aKey, &temp);
1107 }
1108 if(key) {
1109 // We need to make keyPath from the containerResPath and
1110 // current key, if there is a key associated.
1111 chAlias.clear().append(key, *status);
1112 if (U_FAILURE(*status)) {
1113 return nullptr;
1114 }
1115 char *aKey = chAlias.data();
1116 r = res_findResourceres_findResource_71(&dataEntry->fData, r, &aKey, &temp);
1117 } else if(idx != -1) {
1118 // If there is no key, but there is an index, try to get by the index.
1119 // Here we have either a table or an array, so get the element.
1120 int32_t type = RES_GET_TYPE(r)((int32_t)((r)>>28UL));
1121 if(URES_IS_TABLE(type)((int32_t)(type)==URES_TABLE || (int32_t)(type)==URES_TABLE16
|| (int32_t)(type)==URES_TABLE32)
) {
1122 const char *aKey;
1123 r = res_getTableItemByIndexres_getTableItemByIndex_71(&dataEntry->fData, r, idx, &aKey);
1124 } else { /* array */
1125 r = res_getArrayItemres_getArrayItem_71(&dataEntry->fData, r, idx);
1126 }
1127 }
1128 if(r != RES_BOGUS0xffffffff) {
1129 resB = init_resb_result(
1130 dataEntry, r, temp, -1, validLocaleDataEntry, nullptr, recursionDepth+1,
1131 resB, status);
1132 } else {
1133 *status = U_MISSING_RESOURCE_ERROR;
1134 }
1135 } else {
1136 // This one is a bit trickier.
1137 // We start finding keys, but after we resolve one alias, the path might continue.
1138 // Consider:
1139 // aliastest:alias { "testtypes/anotheralias/Sequence" }
1140 // anotheralias:alias { "/ICUDATA/sh/CollationElements" }
1141 // aliastest resource should finally have the sequence, not collation elements.
1142 CharString pathBuf(keyPath, *status);
1143 if (U_FAILURE(*status)) {
1144 return nullptr;
1145 }
1146 char *myPath = pathBuf.data();
1147 containerResPath = nullptr;
1148 // Now we have fallback following here.
1149 for(;;) {
1150 r = dataEntry->fData.rootRes;
1151 // TODO: Move containerResPath = nullptr to here,
1152 // consistent with restarting from the rootRes of another bundle?!
1153
1154 // This loop handles 'found' resources over several levels.
1155 while(*myPath && U_SUCCESS(*status)) {
1156 r = res_findResourceres_findResource_71(&(dataEntry->fData), r, &myPath, &temp);
1157 if(r == RES_BOGUS0xffffffff) {
1158 // No resource found, we don't really want to look anymore on this level.
1159 break;
1160 }
1161 // Found a resource, but it might be an indirection.
1162 resB = init_resb_result(
1163 dataEntry, r, temp, -1,
1164 validLocaleDataEntry, containerResPath, recursionDepth+1,
1165 resB, status);
1166 if (U_FAILURE(*status)) {
1167 break;
1168 }
1169 if (temp == nullptr || uprv_strcmp(keyPath, temp):: strcmp(keyPath, temp) != 0) {
1170 // The call to init_resb_result() above will set resB->fKeyPath to be
1171 // the same as resB->fKey,
1172 // throwing away any additional path elements if we had them --
1173 // if the key path wasn't just a single resource ID, clear out
1174 // the bundle's key path and re-set it to be equal to keyPath.
1175 ures_freeResPath(resB);
1176 ures_appendResPath(resB, keyPath, (int32_t)uprv_strlen(keyPath):: strlen(keyPath), status);
1177 if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR'/') {
1178 ures_appendResPath(resB, RES_PATH_SEPARATOR_S"/", 1, status);
1179 }
1180 if (U_FAILURE(*status)) {
1181 break;
1182 }
1183 }
1184 r = resB->fRes; /* switch to a new resource, possibly a new tree */
1185 dataEntry = resB->fData;
1186 containerResPath = resB->fResPath;
1187 }
1188 if (U_FAILURE(*status) || r != RES_BOGUS0xffffffff) {
1189 break;
1190 }
1191 // Fall back to the parent bundle, if there is one.
1192 dataEntry = dataEntry->fParent;
1193 if (dataEntry == nullptr) {
1194 *status = U_MISSING_RESOURCE_ERROR;
1195 break;
1196 }
1197 // Copy the same keyPath again.
1198 myPath = pathBuf.data();
1199 uprv_strcpy(myPath, keyPath):: strcpy(myPath, keyPath);
1200 }
1201 }
1202 if(mainRes.getAlias() == resB) {
1203 mainRes.orphan();
1204 }
1205 ResourceTracer(resB).maybeTrace("getalias");
1206 return resB;
1207}
1208
1209// Recursive function, should be called only by itself, by its simpler wrapper,
1210// or by getAliasTargetAsResourceBundle().
1211UResourceBundle *init_resb_result(
1212 UResourceDataEntry *dataEntry, Resource r, const char *key, int32_t idx,
1213 UResourceDataEntry *validLocaleDataEntry, const char *containerResPath,
1214 int32_t recursionDepth,
1215 UResourceBundle *resB, UErrorCode *status) {
1216 // TODO: When an error occurs: Should we return nullptr vs. resB?
1217 if(status == NULL__null || U_FAILURE(*status)) {
1218 return resB;
1219 }
1220 if (validLocaleDataEntry == nullptr) {
1221 *status = U_ILLEGAL_ARGUMENT_ERROR;
1222 return NULL__null;
1223 }
1224 if(RES_GET_TYPE(r)((int32_t)((r)>>28UL)) == URES_ALIAS) {
1225 // This is an alias, need to exchange with real data.
1226 if(recursionDepth >= URES_MAX_ALIAS_LEVEL256) {
1227 *status = U_TOO_MANY_ALIASES_ERROR;
1228 return resB;
1229 }
1230 return getAliasTargetAsResourceBundle(
1231 dataEntry->fData, r, key, idx,
1232 validLocaleDataEntry, containerResPath, recursionDepth, resB, status);
1233 }
1234 if(resB == NULL__null) {
1235 resB = (UResourceBundle *)uprv_mallocuprv_malloc_71(sizeof(UResourceBundle));
1236 if (resB == NULL__null) {
1237 *status = U_MEMORY_ALLOCATION_ERROR;
1238 return NULL__null;
1239 }
1240 ures_setIsStackObject(resB, FALSE0);
1241 resB->fResPath = NULL__null;
1242 resB->fResPathLen = 0;
1243 } else {
1244 if(resB->fData != NULL__null) {
1245 entryClose(resB->fData);
1246 }
1247 if(resB->fVersion != NULL__null) {
1248 uprv_freeuprv_free_71(resB->fVersion);
1249 }
1250 /*
1251 weiv: if stack object was passed in, it doesn't really need to be reinited,
1252 since the purpose of initing is to remove stack junk. However, at this point
1253 we would not do anything to an allocated object, so stack object should be
1254 treated the same
1255 */
1256 /*
1257 if(ures_isStackObject(resB) != FALSE) {
1258 ures_initStackObject(resB);
1259 }
1260 */
1261 if(containerResPath != resB->fResPath) {
1262 ures_freeResPath(resB);
1263 }
1264 }
1265 resB->fData = dataEntry;
1266 entryIncrease(resB->fData);
1267 resB->fHasFallback = FALSE0;
1268 resB->fIsTopLevel = FALSE0;
1269 resB->fIndex = -1;
1270 resB->fKey = key;
1271 resB->fValidLocaleDataEntry = validLocaleDataEntry;
1272 if(containerResPath != resB->fResPath) {
1273 ures_appendResPath(
1274 resB, containerResPath, static_cast<int32_t>(uprv_strlen(containerResPath):: strlen(containerResPath)), status);
1275 }
1276 if(key != NULL__null) {
1277 ures_appendResPath(resB, key, (int32_t)uprv_strlen(key):: strlen(key), status);
1278 if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR'/') {
1279 ures_appendResPath(resB, RES_PATH_SEPARATOR_S"/", 1, status);
1280 }
1281 } else if(idx >= 0) {
1282 char buf[256];
1283 int32_t len = T_CString_integerToStringT_CString_integerToString_71(buf, idx, 10);
1284 ures_appendResPath(resB, buf, len, status);
1285 if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR'/') {
1286 ures_appendResPath(resB, RES_PATH_SEPARATOR_S"/", 1, status);
1287 }
1288 }
1289 /* Make sure that Purify doesn't complain about uninitialized memory copies. */
1290 {
1291 int32_t usedLen = ((resB->fResBuf == resB->fResPath) ? resB->fResPathLen : 0);
1292 uprv_memset(resB->fResBuf + usedLen, 0, sizeof(resB->fResBuf) - usedLen):: memset(resB->fResBuf + usedLen, 0, sizeof(resB->fResBuf
) - usedLen)
;
1293 }
1294
1295 resB->fVersion = NULL__null;
1296 resB->fRes = r;
1297 resB->fSize = res_countArrayItemsres_countArrayItems_71(&resB->getResData(), resB->fRes);
1298 ResourceTracer(resB).trace("get");
1299 return resB;
1300}
1301
1302UResourceBundle *init_resb_result(
1303 UResourceDataEntry *dataEntry, Resource r, const char *key, int32_t idx,
1304 // validLocaleDataEntry + containerResPath
1305 const UResourceBundle *container,
1306 UResourceBundle *resB, UErrorCode *status) {
1307 return init_resb_result(
1308 dataEntry, r, key, idx,
1309 container->fValidLocaleDataEntry, container->fResPath, 0, resB, status);
1310}
1311
1312} // namespace
1313
1314UResourceBundle *ures_copyResbures_copyResb_71(UResourceBundle *r, const UResourceBundle *original, UErrorCode *status) {
1315 UBool isStackObject;
1316 if(U_FAILURE(*status) || r == original) {
1317 return r;
1318 }
1319 if(original != NULL__null) {
1320 if(r == NULL__null) {
1321 isStackObject = FALSE0;
1322 r = (UResourceBundle *)uprv_mallocuprv_malloc_71(sizeof(UResourceBundle));
1323 /* test for NULL */
1324 if (r == NULL__null) {
1325 *status = U_MEMORY_ALLOCATION_ERROR;
1326 return NULL__null;
1327 }
1328 } else {
1329 isStackObject = ures_isStackObject(r);
1330 ures_closeBundle(r, FALSE0);
1331 }
1332 uprv_memcpy(r, original, sizeof(UResourceBundle))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(r, original
, sizeof(UResourceBundle)); } while (false)
;
1333 r->fResPath = NULL__null;
1334 r->fResPathLen = 0;
1335 if(original->fResPath) {
1336 ures_appendResPath(r, original->fResPath, original->fResPathLen, status);
1337 }
1338 ures_setIsStackObject(r, isStackObject);
1339 if(r->fData != NULL__null) {
1340 entryIncrease(r->fData);
1341 }
1342 }
1343 return r;
1344}
1345
1346/**
1347 * Functions to retrieve data from resource bundles.
1348 */
1349
1350U_CAPIextern "C" const UChar* U_EXPORT2 ures_getStringures_getString_71(const UResourceBundle* resB, int32_t* len, UErrorCode* status) {
1351 const UChar *s;
1352 if (status==NULL__null || U_FAILURE(*status)) {
1353 return NULL__null;
1354 }
1355 if(resB == NULL__null) {
1356 *status = U_ILLEGAL_ARGUMENT_ERROR;
1357 return NULL__null;
1358 }
1359 s = res_getString({resB}, &resB->getResData(), resB->fRes, len);
1360 if (s == NULL__null) {
1361 *status = U_RESOURCE_TYPE_MISMATCH;
1362 }
1363 return s;
1364}
1365
1366static const char *
1367ures_toUTF8String(const UChar *s16, int32_t length16,
1368 char *dest, int32_t *pLength,
1369 UBool forceCopy,
1370 UErrorCode *status) {
1371 int32_t capacity;
1372
1373 if (U_FAILURE(*status)) {
1374 return NULL__null;
1375 }
1376 if (pLength != NULL__null) {
1377 capacity = *pLength;
1378 } else {
1379 capacity = 0;
1380 }
1381 if (capacity < 0 || (capacity > 0 && dest == NULL__null)) {
1382 *status = U_ILLEGAL_ARGUMENT_ERROR;
1383 return NULL__null;
1384 }
1385
1386 if (length16 == 0) {
1387 /* empty string, return as read-only pointer */
1388 if (pLength != NULL__null) {
1389 *pLength = 0;
1390 }
1391 if (forceCopy) {
1392 u_terminateCharsu_terminateChars_71(dest, capacity, 0, status);
1393 return dest;
1394 } else {
1395 return "";
1396 }
1397 } else {
1398 /* We need to transform the string to the destination buffer. */
1399 if (capacity < length16) {
1400 /* No chance for the string to fit. Pure preflighting. */
1401 return u_strToUTF8u_strToUTF8_71(NULL__null, 0, pLength, s16, length16, status);
1402 }
1403 if (!forceCopy && (length16 <= 0x2aaaaaaa)) {
1404 /*
1405 * We know the string will fit into dest because each UChar turns
1406 * into at most three UTF-8 bytes. Fill the latter part of dest
1407 * so that callers do not expect to use dest as a string pointer,
1408 * hopefully leading to more robust code for when resource bundles
1409 * may store UTF-8 natively.
1410 * (In which case dest would not be used at all.)
1411 *
1412 * We do not do this if forceCopy=TRUE because then the caller
1413 * expects the string to start exactly at dest.
1414 *
1415 * The test above for <= 0x2aaaaaaa prevents overflows.
1416 * The +1 is for the NUL terminator.
1417 */
1418 int32_t maxLength = 3 * length16 + 1;
1419 if (capacity > maxLength) {
1420 dest += capacity - maxLength;
1421 capacity = maxLength;
1422 }
1423 }
1424 return u_strToUTF8u_strToUTF8_71(dest, capacity, pLength, s16, length16, status);
1425 }
1426}
1427
1428U_CAPIextern "C" const char * U_EXPORT2
1429ures_getUTF8Stringures_getUTF8String_71(const UResourceBundle *resB,
1430 char *dest, int32_t *pLength,
1431 UBool forceCopy,
1432 UErrorCode *status) {
1433 int32_t length16;
1434 const UChar *s16 = ures_getStringures_getString_71(resB, &length16, status);
1435 return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
1436}
1437
1438U_CAPIextern "C" const uint8_t* U_EXPORT2 ures_getBinaryures_getBinary_71(const UResourceBundle* resB, int32_t* len,
1439 UErrorCode* status) {
1440 const uint8_t *p;
1441 if (status==NULL__null || U_FAILURE(*status)) {
1442 return NULL__null;
1443 }
1444 if(resB == NULL__null) {
1445 *status = U_ILLEGAL_ARGUMENT_ERROR;
1446 return NULL__null;
1447 }
1448 p = res_getBinary({resB}, &resB->getResData(), resB->fRes, len);
1449 if (p == NULL__null) {
1450 *status = U_RESOURCE_TYPE_MISMATCH;
1451 }
1452 return p;
1453}
1454
1455U_CAPIextern "C" const int32_t* U_EXPORT2 ures_getIntVectorures_getIntVector_71(const UResourceBundle* resB, int32_t* len,
1456 UErrorCode* status) {
1457 const int32_t *p;
1458 if (status==NULL__null || U_FAILURE(*status)) {
1459 return NULL__null;
1460 }
1461 if(resB == NULL__null) {
1462 *status = U_ILLEGAL_ARGUMENT_ERROR;
1463 return NULL__null;
1464 }
1465 p = res_getIntVector({resB}, &resB->getResData(), resB->fRes, len);
1466 if (p == NULL__null) {
1467 *status = U_RESOURCE_TYPE_MISMATCH;
1468 }
1469 return p;
1470}
1471
1472/* this function returns a signed integer */
1473/* it performs sign extension */
1474U_CAPIextern "C" int32_t U_EXPORT2 ures_getIntures_getInt_71(const UResourceBundle* resB, UErrorCode *status) {
1475 if (status==NULL__null || U_FAILURE(*status)) {
1476 return 0xffffffff;
1477 }
1478 if(resB == NULL__null) {
1479 *status = U_ILLEGAL_ARGUMENT_ERROR;
1480 return 0xffffffff;
1481 }
1482 if(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL)) != URES_INT) {
1483 *status = U_RESOURCE_TYPE_MISMATCH;
1484 return 0xffffffff;
1485 }
1486 return res_getInt({resB}, resB->fRes);
1487}
1488
1489U_CAPIextern "C" uint32_t U_EXPORT2 ures_getUIntures_getUInt_71(const UResourceBundle* resB, UErrorCode *status) {
1490 if (status==NULL__null || U_FAILURE(*status)) {
1491 return 0xffffffff;
1492 }
1493 if(resB == NULL__null) {
1494 *status = U_ILLEGAL_ARGUMENT_ERROR;
1495 return 0xffffffff;
1496 }
1497 if(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL)) != URES_INT) {
1498 *status = U_RESOURCE_TYPE_MISMATCH;
1499 return 0xffffffff;
1500 }
1501 return res_getUInt({resB}, resB->fRes);
1502}
1503
1504U_CAPIextern "C" UResType U_EXPORT2 ures_getTypeures_getType_71(const UResourceBundle *resB) {
1505 if(resB == NULL__null) {
1506 return URES_NONE;
1507 }
1508 return res_getPublicTyperes_getPublicType_71(resB->fRes);
1509}
1510
1511U_CAPIextern "C" const char * U_EXPORT2 ures_getKeyures_getKey_71(const UResourceBundle *resB) {
1512 //
1513 // TODO: Trace ures_getKey? I guess not usually.
1514 //
1515 // We usually get the key string to decide whether we want the value, or to
1516 // make a key-value pair. Tracing the value should suffice.
1517 //
1518 // However, I believe we have some data (e.g., in res_index) where the key
1519 // strings are the data. Tracing the enclosing table should suffice.
1520 //
1521 if(resB == NULL__null) {
1522 return NULL__null;
1523 }
1524 return(resB->fKey);
1525}
1526
1527U_CAPIextern "C" int32_t U_EXPORT2 ures_getSizeures_getSize_71(const UResourceBundle *resB) {
1528 if(resB == NULL__null) {
1529 return 0;
1530 }
1531
1532 return resB->fSize;
1533}
1534
1535static const UChar* ures_getStringWithAlias(const UResourceBundle *resB, Resource r, int32_t sIndex, int32_t *len, UErrorCode *status) {
1536 if(RES_GET_TYPE(r)((int32_t)((r)>>28UL)) == URES_ALIAS) {
1537 const UChar* result = 0;
1538 UResourceBundle *tempRes = ures_getByIndexures_getByIndex_71(resB, sIndex, NULL__null, status);
1539 result = ures_getStringures_getString_71(tempRes, len, status);
1540 ures_closeures_close_71(tempRes);
1541 return result;
1542 } else {
1543 return res_getString({resB, sIndex}, &resB->getResData(), r, len);
1544 }
1545}
1546
1547U_CAPIextern "C" void U_EXPORT2 ures_resetIteratorures_resetIterator_71(UResourceBundle *resB){
1548 if(resB == NULL__null) {
1549 return;
1550 }
1551 resB->fIndex = -1;
1552}
1553
1554U_CAPIextern "C" UBool U_EXPORT2 ures_hasNextures_hasNext_71(const UResourceBundle *resB) {
1555 if(resB == NULL__null) {
1556 return FALSE0;
1557 }
1558 return (UBool)(resB->fIndex < resB->fSize-1);
1559}
1560
1561U_CAPIextern "C" const UChar* U_EXPORT2 ures_getNextStringures_getNextString_71(UResourceBundle *resB, int32_t* len, const char ** key, UErrorCode *status) {
1562 Resource r = RES_BOGUS0xffffffff;
1563
1564 if (status==NULL__null || U_FAILURE(*status)) {
1565 return NULL__null;
1566 }
1567 if(resB == NULL__null) {
1568 *status = U_ILLEGAL_ARGUMENT_ERROR;
1569 return NULL__null;
1570 }
1571
1572 if(resB->fIndex == resB->fSize-1) {
1573 *status = U_INDEX_OUTOFBOUNDS_ERROR;
1574 } else {
1575 resB->fIndex++;
1576 switch(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL))) {
1577 case URES_STRING:
1578 case URES_STRING_V2:
1579 return res_getString({resB}, &resB->getResData(), resB->fRes, len);
1580 case URES_TABLE:
1581 case URES_TABLE16:
1582 case URES_TABLE32:
1583 r = res_getTableItemByIndexres_getTableItemByIndex_71(&resB->getResData(), resB->fRes, resB->fIndex, key);
1584 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1585 /* TODO: do the fallback */
1586 }
1587 return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
1588 case URES_ARRAY:
1589 case URES_ARRAY16:
1590 r = res_getArrayItemres_getArrayItem_71(&resB->getResData(), resB->fRes, resB->fIndex);
1591 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1592 /* TODO: do the fallback */
1593 }
1594 return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
1595 case URES_ALIAS:
1596 return ures_getStringWithAlias(resB, resB->fRes, resB->fIndex, len, status);
1597 case URES_INT:
1598 case URES_BINARY:
1599 case URES_INT_VECTOR:
1600 *status = U_RESOURCE_TYPE_MISMATCH;
1601 U_FALLTHROUGH[[clang::fallthrough]];
1602 default:
1603 return NULL__null;
1604 }
1605 }
1606
1607 return NULL__null;
1608}
1609
1610U_CAPIextern "C" UResourceBundle* U_EXPORT2 ures_getNextResourceures_getNextResource_71(UResourceBundle *resB, UResourceBundle *fillIn, UErrorCode *status) {
1611 const char *key = NULL__null;
1612 Resource r = RES_BOGUS0xffffffff;
1613
1614 if (status==NULL__null || U_FAILURE(*status)) {
1615 /*return NULL;*/
1616 return fillIn;
1617 }
1618 if(resB == NULL__null) {
1619 *status = U_ILLEGAL_ARGUMENT_ERROR;
1620 /*return NULL;*/
1621 return fillIn;
1622 }
1623
1624 if(resB->fIndex == resB->fSize-1) {
1625 *status = U_INDEX_OUTOFBOUNDS_ERROR;
1626 /*return NULL;*/
1627 } else {
1628 resB->fIndex++;
1629 switch(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL))) {
1630 case URES_INT:
1631 case URES_BINARY:
1632 case URES_STRING:
1633 case URES_STRING_V2:
1634 case URES_INT_VECTOR:
1635 return ures_copyResbures_copyResb_71(fillIn, resB, status);
1636 case URES_TABLE:
1637 case URES_TABLE16:
1638 case URES_TABLE32:
1639 r = res_getTableItemByIndexres_getTableItemByIndex_71(&resB->getResData(), resB->fRes, resB->fIndex, &key);
1640 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1641 /* TODO: do the fallback */
1642 }
1643 return init_resb_result(resB->fData, r, key, resB->fIndex, resB, fillIn, status);
1644 case URES_ARRAY:
1645 case URES_ARRAY16:
1646 r = res_getArrayItemres_getArrayItem_71(&resB->getResData(), resB->fRes, resB->fIndex);
1647 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1648 /* TODO: do the fallback */
1649 }
1650 return init_resb_result(resB->fData, r, key, resB->fIndex, resB, fillIn, status);
1651 default:
1652 /*return NULL;*/
1653 return fillIn;
1654 }
1655 }
1656 /*return NULL;*/
1657 return fillIn;
1658}
1659
1660U_CAPIextern "C" UResourceBundle* U_EXPORT2 ures_getByIndexures_getByIndex_71(const UResourceBundle *resB, int32_t indexR, UResourceBundle *fillIn, UErrorCode *status) {
1661 const char* key = NULL__null;
1662 Resource r = RES_BOGUS0xffffffff;
1663
1664 if (status==NULL__null || U_FAILURE(*status)) {
1665 /*return NULL;*/
1666 return fillIn;
1667 }
1668 if(resB == NULL__null) {
1669 *status = U_ILLEGAL_ARGUMENT_ERROR;
1670 /*return NULL;*/
1671 return fillIn;
1672 }
1673
1674 if(indexR >= 0 && resB->fSize > indexR) {
1675 switch(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL))) {
1676 case URES_INT:
1677 case URES_BINARY:
1678 case URES_STRING:
1679 case URES_STRING_V2:
1680 case URES_INT_VECTOR:
1681 return ures_copyResbures_copyResb_71(fillIn, resB, status);
1682 case URES_TABLE:
1683 case URES_TABLE16:
1684 case URES_TABLE32:
1685 r = res_getTableItemByIndexres_getTableItemByIndex_71(&resB->getResData(), resB->fRes, indexR, &key);
1686 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1687 /* TODO: do the fallback */
1688 }
1689 return init_resb_result(resB->fData, r, key, indexR, resB, fillIn, status);
1690 case URES_ARRAY:
1691 case URES_ARRAY16:
1692 r = res_getArrayItemres_getArrayItem_71(&resB->getResData(), resB->fRes, indexR);
1693 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1694 /* TODO: do the fallback */
1695 }
1696 return init_resb_result(resB->fData, r, key, indexR, resB, fillIn, status);
1697 default:
1698 /*return NULL;*/
1699 return fillIn;
1700 }
1701 } else {
1702 *status = U_MISSING_RESOURCE_ERROR;
1703 }
1704 /*return NULL;*/
1705 return fillIn;
1706}
1707
1708U_CAPIextern "C" const UChar* U_EXPORT2 ures_getStringByIndexures_getStringByIndex_71(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status) {
1709 const char* key = NULL__null;
1710 Resource r = RES_BOGUS0xffffffff;
1711
1712 if (status==NULL__null || U_FAILURE(*status)) {
1713 return NULL__null;
1714 }
1715 if(resB == NULL__null) {
1716 *status = U_ILLEGAL_ARGUMENT_ERROR;
1717 return NULL__null;
1718 }
1719
1720 if(indexS >= 0 && resB->fSize > indexS) {
1721 switch(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL))) {
1722 case URES_STRING:
1723 case URES_STRING_V2:
1724 return res_getString({resB}, &resB->getResData(), resB->fRes, len);
1725 case URES_TABLE:
1726 case URES_TABLE16:
1727 case URES_TABLE32:
1728 r = res_getTableItemByIndexres_getTableItemByIndex_71(&resB->getResData(), resB->fRes, indexS, &key);
1729 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1730 /* TODO: do the fallback */
1731 }
1732 return ures_getStringWithAlias(resB, r, indexS, len, status);
1733 case URES_ARRAY:
1734 case URES_ARRAY16:
1735 r = res_getArrayItemres_getArrayItem_71(&resB->getResData(), resB->fRes, indexS);
1736 if(r == RES_BOGUS0xffffffff && resB->fHasFallback) {
1737 /* TODO: do the fallback */
1738 }
1739 return ures_getStringWithAlias(resB, r, indexS, len, status);
1740 case URES_ALIAS:
1741 return ures_getStringWithAlias(resB, resB->fRes, indexS, len, status);
1742 case URES_INT:
1743 case URES_BINARY:
1744 case URES_INT_VECTOR:
1745 *status = U_RESOURCE_TYPE_MISMATCH;
1746 break;
1747 default:
1748 /* must not occur */
1749 *status = U_INTERNAL_PROGRAM_ERROR;
1750 break;
1751 }
1752 } else {
1753 *status = U_MISSING_RESOURCE_ERROR;
1754 }
1755 return NULL__null;
1756}
1757
1758U_CAPIextern "C" const char * U_EXPORT2
1759ures_getUTF8StringByIndexures_getUTF8StringByIndex_71(const UResourceBundle *resB,
1760 int32_t idx,
1761 char *dest, int32_t *pLength,
1762 UBool forceCopy,
1763 UErrorCode *status) {
1764 int32_t length16;
1765 const UChar *s16 = ures_getStringByIndexures_getStringByIndex_71(resB, idx, &length16, status);
1766 return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
1767}
1768
1769/*U_CAPI const char *ures_getResPath(UResourceBundle *resB) {
1770 return resB->fResPath;
1771}*/
1772
1773U_CAPIextern "C" UResourceBundle* U_EXPORT2
1774ures_findResourceures_findResource_71(const char* path, UResourceBundle *fillIn, UErrorCode *status)
1775{
1776 UResourceBundle *first = NULL__null;
1777 UResourceBundle *result = fillIn;
1778 char *packageName = NULL__null;
1779 char *pathToResource = NULL__null, *save = NULL__null;
1780 char *locale = NULL__null, *localeEnd = NULL__null;
1781 int32_t length;
1782
1783 if(status == NULL__null || U_FAILURE(*status)) {
1784 return result;
1785 }
1786
1787 length = (int32_t)(uprv_strlen(path):: strlen(path)+1);
1788 save = pathToResource = (char *)uprv_mallocuprv_malloc_71(length*sizeof(char));
1789 /* test for NULL */
1790 if(pathToResource == NULL__null) {
1791 *status = U_MEMORY_ALLOCATION_ERROR;
1792 return result;
1793 }
1794 uprv_memcpy(pathToResource, path, length)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(pathToResource
, path, length); } while (false)
;
1795
1796 locale = pathToResource;
1797 if(*pathToResource == RES_PATH_SEPARATOR'/') { /* there is a path specification */
1798 pathToResource++;
1799 packageName = pathToResource;
1800 pathToResource = uprv_strchr(pathToResource, RES_PATH_SEPARATOR):: strchr(pathToResource, '/');
1801 if(pathToResource == NULL__null) {
1802 *status = U_ILLEGAL_ARGUMENT_ERROR;
1803 } else {
1804 *pathToResource = 0;
1805 locale = pathToResource+1;
1806 }
1807 }
1808
1809 localeEnd = uprv_strchr(locale, RES_PATH_SEPARATOR):: strchr(locale, '/');
1810 if(localeEnd != NULL__null) {
1811 *localeEnd = 0;
1812 }
1813
1814 first = ures_openures_open_71(packageName, locale, status);
1815
1816 if(U_SUCCESS(*status)) {
1817 if(localeEnd) {
1818 result = ures_findSubResourceures_findSubResource_71(first, localeEnd+1, fillIn, status);
1819 } else {
1820 result = ures_copyResbures_copyResb_71(fillIn, first, status);
1821 }
1822 ures_closeures_close_71(first);
1823 }
1824 uprv_freeuprv_free_71(save);
1825 return result;
1826}
1827
1828U_CAPIextern "C" UResourceBundle* U_EXPORT2
1829ures_findSubResourceures_findSubResource_71(const UResourceBundle *resB, char* path, UResourceBundle *fillIn, UErrorCode *status)
1830{
1831 Resource res = RES_BOGUS0xffffffff;
1832 UResourceBundle *result = fillIn;
1833 const char *key;
1834
1835 if(status == NULL__null || U_FAILURE(*status)) {
1836 return result;
1837 }
1838
1839 /* here we do looping and circular alias checking */
1840 /* this loop is here because aliasing is resolved on this level, not on res level */
1841 /* so, when we encounter an alias, it is not an aggregate resource, so we return */
1842 do {
1843 res = res_findResourceres_findResource_71(&resB->getResData(), resB->fRes, &path, &key);
1844 if(res != RES_BOGUS0xffffffff) {
1845 result = init_resb_result(resB->fData, res, key, -1, resB, fillIn, status);
1846 resB = result;
1847 } else {
1848 *status = U_MISSING_RESOURCE_ERROR;
1849 break;
1850 }
1851 } while(*path); /* there is more stuff in the path */
1852
1853 return result;
1854}
1855U_CAPIextern "C" const UChar* U_EXPORT2
1856ures_getStringByKeyWithFallbackures_getStringByKeyWithFallback_71(const UResourceBundle *resB,
1857 const char* inKey,
1858 int32_t* len,
1859 UErrorCode *status) {
1860
1861 UResourceBundle stack;
1862 const UChar* retVal = NULL__null;
1863 ures_initStackObjectures_initStackObject_71(&stack);
1864 ures_getByKeyWithFallbackures_getByKeyWithFallback_71(resB, inKey, &stack, status);
1865 int32_t length;
1866 retVal = ures_getStringures_getString_71(&stack, &length, status);
1867 ures_closeures_close_71(&stack);
1868 if (U_FAILURE(*status)) {
1869 return NULL__null;
1870 }
1871 if (length == 3 && retVal[0] == EMPTY_SET0x2205 && retVal[1] == EMPTY_SET0x2205 && retVal[2] == EMPTY_SET0x2205 ) {
1872 retVal = NULL__null;
1873 length = 0;
1874 *status = U_MISSING_RESOURCE_ERROR;
1875 }
1876 if (len != NULL__null) {
1877 *len = length;
1878 }
1879 return retVal;
1880}
1881
1882/*
1883 Like res_getTableItemByKey but accepts full paths like "NumberElements/latn/patternsShort".
1884*/
1885static Resource getTableItemByKeyPath(const ResourceData *pResData, Resource table, const char *key) {
1886 Resource resource = table; /* The current resource */
1887 icu::CharString path;
1888 UErrorCode errorCode = U_ZERO_ERROR;
1889 path.append(key, errorCode);
1890 if (U_FAILURE(errorCode)) { return RES_BOGUS0xffffffff; }
1891 char *pathPart = path.data(); /* Path from current resource to desired resource */
1892 UResType type = (UResType)RES_GET_TYPE(resource)((int32_t)((resource)>>28UL)); /* the current resource type */
1893 while (*pathPart && resource != RES_BOGUS0xffffffff && URES_IS_CONTAINER(type)(((int32_t)(type)==URES_TABLE || (int32_t)(type)==URES_TABLE16
|| (int32_t)(type)==URES_TABLE32) || ((int32_t)(type)==URES_ARRAY
|| (int32_t)(type)==URES_ARRAY16))
) {
1894 char *nextPathPart = uprv_strchr(pathPart, RES_PATH_SEPARATOR):: strchr(pathPart, '/');
1895 if (nextPathPart != NULL__null) {
1896 *nextPathPart = 0; /* Terminating null for this part of path. */
1897 nextPathPart++;
1898 } else {
1899 nextPathPart = uprv_strchr(pathPart, 0):: strchr(pathPart, 0);
1900 }
1901 int32_t t;
1902 const char *pathP = pathPart;
1903 resource = res_getTableItemByKeyres_getTableItemByKey_71(pResData, resource, &t, &pathP);
1904 type = (UResType)RES_GET_TYPE(resource)((int32_t)((resource)>>28UL));
1905 pathPart = nextPathPart;
1906 }
1907 if (*pathPart) {
1908 return RES_BOGUS0xffffffff;
1909 }
1910 return resource;
1911}
1912
1913static void createPath(const char* origResPath,
1914 int32_t origResPathLen,
1915 const char* resPath,
1916 int32_t resPathLen,
1917 const char* inKey,
1918 CharString& path,
1919 UErrorCode* status) {
1920 // This is a utility function used by ures_getByKeyWithFallback() below. This function builds a path from
1921 // resPath and inKey, returning the result in `path`. Originally, this function just cleared `path` and
1922 // appended resPath and inKey to it, but that caused problems for horizontal inheritance.
1923 //
1924 // In normal cases, resPath is the same as origResPath, but if ures_getByKeyWithFallback() has followed an
1925 // alias, resPath may be different from origResPath. Not only may the existing path elements be different,
1926 // but resPath may also have MORE path elements than origResPath did. If it does, those additional path
1927 // elements SUPERSEDE the corresponding elements of inKey. So this code counts the number of elements in
1928 // resPath and origResPath and, for each path element in resPath that doesn't have a counterpart in origResPath,
1929 // deletes a path element from the beginning of inKey. The remainder of inKey is then appended to
1930 // resPath to form the result. (We're not using uprv_strchr() here because resPath and origResPath may
1931 // not be zero-terminated.)
1932 path.clear();
1933 const char* key = inKey;
1934 if (resPathLen > 0) {
1935 path.append(resPath, resPathLen, *status);
1936 if (U_SUCCESS(*status)) {
1937 const char* resPathLimit = resPath + resPathLen;
1938 const char* origResPathLimit = origResPath + origResPathLen;
1939 const char* resPathPtr = resPath;
1940 const char* origResPathPtr = origResPath;
1941
1942 // Remove from the beginning of resPath the number of segments that are contained in origResPath.
1943 // If origResPath has MORE segments than resPath, this will leave resPath as the empty string.
1944 while (origResPathPtr < origResPathLimit && resPathPtr < resPathLimit) {
1945 while (origResPathPtr < origResPathLimit && *origResPathPtr != RES_PATH_SEPARATOR'/') {
1946 ++origResPathPtr;
1947 }
1948 if (origResPathPtr < origResPathLimit && *origResPathPtr == RES_PATH_SEPARATOR'/') {
1949 ++origResPathPtr;
1950 }
1951 while (resPathPtr < resPathLimit && *resPathPtr != RES_PATH_SEPARATOR'/') {
1952 ++resPathPtr;
1953 }
1954 if (resPathPtr < resPathLimit && *resPathPtr == RES_PATH_SEPARATOR'/') {
1955 ++resPathPtr;
1956 }
1957 }
1958
1959 // New remove from the beginning of `key` the number of segments remaining in resPath.
1960 // If resPath has more segments than `key` does, `key` will end up empty.
1961 while (resPathPtr < resPathLimit && *key != '\0') {
1962 while (resPathPtr < resPathLimit && *resPathPtr != RES_PATH_SEPARATOR'/') {
1963 ++resPathPtr;
1964 }
1965 if (resPathPtr < resPathLimit && *resPathPtr == RES_PATH_SEPARATOR'/') {
1966 ++resPathPtr;
1967 }
1968 while (*key != '\0' && *key != RES_PATH_SEPARATOR'/') {
1969 ++key;
1970 }
1971 if (*key == RES_PATH_SEPARATOR'/') {
1972 ++key;
1973 }
1974 }
1975 }
1976 // Finally, append what's left of `key` to `path`. What you end up with here is `resPath`, plus
1977 // any pieces of `key` that aren't superseded by `resPath`.
1978 // Or, to put it another way, calculate <#-segments-in-key> - (<#-segments-in-resPath> - <#-segments-in-origResPath>),
1979 // and append that many segments from the end of `key` to `resPath` to produce the result.
1980 path.append(key, *status);
1981 } else {
1982 path.append(inKey, *status);
1983 }
1984}
1985
1986U_CAPIextern "C" UResourceBundle* U_EXPORT2
1987ures_getByKeyWithFallbackures_getByKeyWithFallback_71(const UResourceBundle *resB,
1988 const char* inKey,
1989 UResourceBundle *fillIn,
1990 UErrorCode *status) {
1991 Resource res = RES_BOGUS0xffffffff, rootRes = RES_BOGUS0xffffffff;
1992 UResourceBundle *helper = NULL__null;
1993
1994 if (status==NULL__null || U_FAILURE(*status)) {
1995 return fillIn;
1996 }
1997 if(resB == NULL__null) {
1998 *status = U_ILLEGAL_ARGUMENT_ERROR;
1999 return fillIn;
2000 }
2001
2002 int32_t type = RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL));
2003 if(URES_IS_TABLE(type)((int32_t)(type)==URES_TABLE || (int32_t)(type)==URES_TABLE16
|| (int32_t)(type)==URES_TABLE32)
) {
2004 const char* origResPath = resB->fResPath;
2005 int32_t origResPathLen = resB->fResPathLen;
2006 res = getTableItemByKeyPath(&resB->getResData(), resB->fRes, inKey);
2007 const char* key = inKey;
2008 bool didRootOnce = false;
2009 if(res == RES_BOGUS0xffffffff) {
2010 UResourceDataEntry *dataEntry = resB->fData;
2011 CharString path;
2012 char *myPath = NULL__null;
2013 const char* resPath = resB->fResPath;
2014 int32_t len = resB->fResPathLen;
2015 while(res == RES_BOGUS0xffffffff && (dataEntry->fParent != NULL__null || !didRootOnce)) { /* Otherwise, we'll look in parents */
2016 if (dataEntry->fParent != NULL__null) {
2017 dataEntry = dataEntry->fParent;
2018 } else {
2019 // We can't just stop when we get to a bundle whose fParent is NULL. That'll work most of the time,
2020 // but if the bundle that the caller passed to us was "root" (which happens in getAllItemsWithFallback(),
2021 // this function will drop right out without doing anything if "root" doesn't contain the exact key path
2022 // specified. In that case, we need one extra time through this loop to make sure we follow any
2023 // applicable aliases at the root level.
2024 didRootOnce = true;
2025 }
2026 rootRes = dataEntry->fData.rootRes;
2027
2028 if(dataEntry->fBogus == U_ZERO_ERROR) {
2029 createPath(origResPath, origResPathLen, resPath, len, inKey, path, status);
2030 if (U_FAILURE(*status)) {
2031 ures_closeures_close_71(helper);
2032 return fillIn;
2033 }
2034 myPath = path.data();
2035 key = inKey;
2036 do {
2037 res = res_findResourceres_findResource_71(&(dataEntry->fData), rootRes, &myPath, &key);
2038 if (RES_GET_TYPE(res)((int32_t)((res)>>28UL)) == URES_ALIAS && *myPath) {
2039 /* We hit an alias, but we didn't finish following the path. */
2040 helper = init_resb_result(dataEntry, res, NULL__null, -1, resB, helper, status);
2041 /*helper = init_resb_result(dataEntry, res, inKey, -1, resB, helper, status);*/
2042 if(helper) {
2043 dataEntry = helper->fData;
2044 rootRes = helper->fRes;
2045 resPath = helper->fResPath;
2046 len = helper->fResPathLen;
2047
2048 } else {
2049 break;
2050 }
2051 } else if (res == RES_BOGUS0xffffffff) {
2052 break;
2053 }
2054 } while(*myPath); /* Continue until the whole path is consumed */
2055 }
2056 }
2057 /*dataEntry = getFallbackData(resB, &key, &res, status);*/
2058 if(res != RES_BOGUS0xffffffff) {
2059 /* check if resB->fResPath gives the right name here */
2060 if(uprv_strcmp(dataEntry->fName, uloc_getDefault()):: strcmp(dataEntry->fName, uloc_getDefault_71())==0 || uprv_strcmp(dataEntry->fName, kRootLocaleName):: strcmp(dataEntry->fName, "root")==0) {
2061 *status = U_USING_DEFAULT_WARNING;
2062 } else {
2063 *status = U_USING_FALLBACK_WARNING;
2064 }
2065
2066 fillIn = init_resb_result(dataEntry, res, key, -1, resB, fillIn, status);
2067 if (resPath != nullptr) {
2068 createPath(origResPath, origResPathLen, resPath, len, inKey, path, status);
2069 } else {
2070 const char* separator = nullptr;
2071 if (fillIn->fResPath != nullptr) {
2072 separator = uprv_strchr(fillIn->fResPath, RES_PATH_SEPARATOR):: strchr(fillIn->fResPath, '/');
2073 }
2074 if (separator != nullptr && separator[1] != '\0') {
2075 createPath(origResPath, origResPathLen, fillIn->fResPath,
2076 static_cast<int32_t>(uprv_strlen(fillIn->fResPath):: strlen(fillIn->fResPath)), inKey, path, status);
2077 } else {
2078 createPath(origResPath, origResPathLen, "", 0, inKey, path, status);
2079 }
2080 }
2081 ures_freeResPath(fillIn);
2082 ures_appendResPath(fillIn, path.data(), path.length(), status);
2083 if(fillIn->fResPath[fillIn->fResPathLen-1] != RES_PATH_SEPARATOR'/') {
2084 ures_appendResPath(fillIn, RES_PATH_SEPARATOR_S"/", 1, status);
2085 }
2086 } else {
2087 *status = U_MISSING_RESOURCE_ERROR;
2088 }
2089 } else {
2090 fillIn = init_resb_result(resB->fData, res, key, -1, resB, fillIn, status);
2091 }
2092 }
2093 else {
2094 *status = U_RESOURCE_TYPE_MISMATCH;
2095 }
2096 ures_closeures_close_71(helper);
2097 return fillIn;
2098}
2099
2100namespace {
2101
2102void getAllItemsWithFallback(
2103 const UResourceBundle *bundle, ResourceDataValue &value,
2104 ResourceSink &sink, UErrorCode &errorCode) {
2105 if (U_FAILURE(errorCode)) { return; }
2106 // We recursively enumerate child-first,
2107 // only storing parent items in the absence of child items.
2108 // The sink needs to store a placeholder value for the no-fallback/no-inheritance marker
2109 // to prevent a parent item from being stored.
2110 //
2111 // It would be possible to recursively enumerate parent-first,
2112 // overriding parent items with child items.
2113 // When the sink sees the no-fallback/no-inheritance marker,
2114 // then it would remove the parent's item.
2115 // We would deserialize parent values even though they are overridden in a child bundle.
2116 value.setData(bundle->getResData());
2117 value.setValidLocaleDataEntry(bundle->fValidLocaleDataEntry);
2118 UResourceDataEntry *parentEntry = bundle->fData->fParent;
2119 UBool hasParent = parentEntry != NULL__null && U_SUCCESS(parentEntry->fBogus);
2120 value.setResource(bundle->fRes, ResourceTracer(bundle));
2121 sink.put(bundle->fKey, value, !hasParent, errorCode);
2122 if (hasParent) {
2123 // We might try to query the sink whether
2124 // any fallback from the parent bundle is still possible.
2125
2126 // Turn the parent UResourceDataEntry into a UResourceBundle,
2127 // much like in ures_openWithType().
2128 // TODO: See if we can refactor ures_getByKeyWithFallback()
2129 // and pull out an inner function that takes and returns a UResourceDataEntry
2130 // so that we need not create UResourceBundle objects.
2131 StackUResourceBundle parentBundle;
2132 UResourceBundle &parentRef = parentBundle.ref();
2133 parentRef.fData = parentEntry;
2134 parentRef.fValidLocaleDataEntry = bundle->fValidLocaleDataEntry;
2135 parentRef.fHasFallback = !parentRef.getResData().noFallback;
2136 parentRef.fIsTopLevel = TRUE1;
2137 parentRef.fRes = parentRef.getResData().rootRes;
2138 parentRef.fSize = res_countArrayItemsres_countArrayItems_71(&parentRef.getResData(), parentRef.fRes);
2139 parentRef.fIndex = -1;
2140 entryIncrease(parentEntry);
2141
2142 // Look up the container item in the parent bundle.
2143 StackUResourceBundle containerBundle;
2144 const UResourceBundle *rb;
2145 UErrorCode pathErrorCode = U_ZERO_ERROR; // Ignore if parents up to root do not have this path.
2146 if (bundle->fResPath == NULL__null || *bundle->fResPath == 0) {
2147 rb = parentBundle.getAlias();
2148 } else {
2149 rb = ures_getByKeyWithFallbackures_getByKeyWithFallback_71(parentBundle.getAlias(), bundle->fResPath,
2150 containerBundle.getAlias(), &pathErrorCode);
2151 }
2152 if (U_SUCCESS(pathErrorCode)) {
2153 getAllItemsWithFallback(rb, value, sink, errorCode);
2154 }
2155 }
2156}
2157
2158struct GetAllChildrenSink : public ResourceSink {
2159 // Destination sink
2160 ResourceSink& dest;
2161
2162 GetAllChildrenSink(ResourceSink& dest)
2163 : dest(dest) {}
2164 virtual ~GetAllChildrenSink() override;
2165 virtual void put(const char *key, ResourceValue &value, UBool isRoot,
2166 UErrorCode &errorCode) override {
2167 ResourceTable itemsTable = value.getTable(errorCode);
2168 if (U_FAILURE(errorCode)) { return; }
2169 for (int32_t i = 0; itemsTable.getKeyAndValue(i, key, value); ++i) {
2170 if (value.getType() == URES_ALIAS) {
2171 ResourceDataValue& rdv = static_cast<ResourceDataValue&>(value);
2172 StackUResourceBundle stackTempBundle;
2173 UResourceBundle* aliasRB = getAliasTargetAsResourceBundle(rdv.getData(), rdv.getResource(), nullptr, -1,
2174 rdv.getValidLocaleDataEntry(), nullptr, 0,
2175 stackTempBundle.getAlias(), &errorCode);
2176 if (U_SUCCESS(errorCode)) {
2177 ResourceDataValue aliasedValue;
2178 aliasedValue.setData(aliasRB->getResData());
2179 aliasedValue.setValidLocaleDataEntry(aliasRB->fValidLocaleDataEntry);
2180 aliasedValue.setResource(aliasRB->fRes, ResourceTracer(aliasRB));
2181 dest.put(key, aliasedValue, isRoot, errorCode);
2182 }
2183 } else {
2184 dest.put(key, value, isRoot, errorCode);
2185 }
2186 if (U_FAILURE(errorCode)) { return; }
2187 }
2188 }
2189};
2190
2191// Virtual destructors must be defined out of line.
2192GetAllChildrenSink::~GetAllChildrenSink() {}
2193
2194U_CAPIextern "C" void U_EXPORT2
2195ures_getAllChildrenWithFallbackures_getAllChildrenWithFallback_71(const UResourceBundle *bundle, const char *path,
2196 icu::ResourceSink &sink, UErrorCode &errorCode) {
2197 GetAllChildrenSink allChildrenSink(sink);
2198 ures_getAllItemsWithFallbackures_getAllItemsWithFallback_71(bundle, path, allChildrenSink, errorCode);
2199}
2200
2201} // namespace
2202
2203// Requires a ResourceDataValue fill-in, so that we need not cast from a ResourceValue.
2204// Unfortunately, the caller must know which subclass to make and pass in.
2205// Alternatively, we could make it as polymorphic as in Java by
2206// returning a ResourceValue pointer (possibly wrapped into a LocalPointer)
2207// that the caller then owns.
2208//
2209// Also requires a UResourceBundle fill-in, so that the value's ResourceTracer
2210// can point to a non-local bundle.
2211// Without tracing, the child bundle could be a function-local object.
2212U_CAPIextern "C" void U_EXPORT2
2213ures_getValueWithFallbackures_getValueWithFallback_71(const UResourceBundle *bundle, const char *path,
2214 UResourceBundle *tempFillIn,
2215 ResourceDataValue &value, UErrorCode &errorCode) {
2216 if (U_FAILURE(errorCode)) { return; }
2217 if (path == nullptr) {
2218 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
2219 return;
2220 }
2221 const UResourceBundle *rb;
2222 if (*path == 0) {
2223 // empty path
2224 rb = bundle;
2225 } else {
2226 rb = ures_getByKeyWithFallbackures_getByKeyWithFallback_71(bundle, path, tempFillIn, &errorCode);
2227 if (U_FAILURE(errorCode)) {
2228 return;
2229 }
2230 }
2231 value.setData(rb->getResData());
2232 value.setValidLocaleDataEntry(rb->fValidLocaleDataEntry);
2233 value.setResource(rb->fRes, ResourceTracer(rb));
2234}
2235
2236U_CAPIextern "C" void U_EXPORT2
2237ures_getAllItemsWithFallbackures_getAllItemsWithFallback_71(const UResourceBundle *bundle, const char *path,
2238 icu::ResourceSink &sink, UErrorCode &errorCode) {
2239 if (U_FAILURE(errorCode)) { return; }
2240 if (path == nullptr) {
2241 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
2242 return;
2243 }
2244 StackUResourceBundle stackBundle;
2245 const UResourceBundle *rb;
2246 if (*path == 0) {
2247 // empty path
2248 rb = bundle;
2249 } else {
2250 rb = ures_getByKeyWithFallbackures_getByKeyWithFallback_71(bundle, path, stackBundle.getAlias(), &errorCode);
2251 if (U_FAILURE(errorCode)) {
2252 return;
2253 }
2254 }
2255 // Get all table items with fallback.
2256 ResourceDataValue value;
2257 getAllItemsWithFallback(rb, value, sink, errorCode);
2258}
2259
2260U_CAPIextern "C" UResourceBundle* U_EXPORT2 ures_getByKeyures_getByKey_71(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) {
2261 Resource res = RES_BOGUS0xffffffff;
2262 UResourceDataEntry *dataEntry = NULL__null;
2263 const char *key = inKey;
2264
2265 if (status==NULL__null || U_FAILURE(*status)) {
2266 return fillIn;
2267 }
2268 if(resB == NULL__null) {
2269 *status = U_ILLEGAL_ARGUMENT_ERROR;
2270 return fillIn;
2271 }
2272
2273 int32_t type = RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL));
2274 if(URES_IS_TABLE(type)((int32_t)(type)==URES_TABLE || (int32_t)(type)==URES_TABLE16
|| (int32_t)(type)==URES_TABLE32)
) {
2275 int32_t t;
2276 res = res_getTableItemByKeyres_getTableItemByKey_71(&resB->getResData(), resB->fRes, &t, &key);
2277 if(res == RES_BOGUS0xffffffff) {
2278 key = inKey;
2279 if(resB->fHasFallback == TRUE1) {
2280 dataEntry = getFallbackData(resB, &key, &res, status);
2281 if(U_SUCCESS(*status)) {
2282 /* check if resB->fResPath gives the right name here */
2283 return init_resb_result(dataEntry, res, key, -1, resB, fillIn, status);
2284 } else {
2285 *status = U_MISSING_RESOURCE_ERROR;
2286 }
2287 } else {
2288 *status = U_MISSING_RESOURCE_ERROR;
2289 }
2290 } else {
2291 return init_resb_result(resB->fData, res, key, -1, resB, fillIn, status);
2292 }
2293 }
2294#if 0
2295 /* this is a kind of TODO item. If we have an array with an index table, we could do this. */
2296 /* not currently */
2297 else if(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL)) == URES_ARRAY && resB->fHasFallback == TRUE1) {
2298 /* here should go a first attempt to locate the key using index table */
2299 dataEntry = getFallbackData(resB, &key, &res, status);
2300 if(U_SUCCESS(*status)) {
2301 return init_resb_result(dataEntry, res, key, resB, fillIn, status);
2302 } else {
2303 *status = U_MISSING_RESOURCE_ERROR;
2304 }
2305 }
2306#endif
2307 else {
2308 *status = U_RESOURCE_TYPE_MISMATCH;
2309 }
2310 return fillIn;
2311}
2312
2313U_CAPIextern "C" const UChar* U_EXPORT2 ures_getStringByKeyures_getStringByKey_71(const UResourceBundle *resB, const char* inKey, int32_t* len, UErrorCode *status) {
2314 Resource res = RES_BOGUS0xffffffff;
2315 UResourceDataEntry *dataEntry = NULL__null;
2316 const char* key = inKey;
2317
2318 if (status==NULL__null || U_FAILURE(*status)) {
2319 return NULL__null;
2320 }
2321 if(resB == NULL__null) {
2322 *status = U_ILLEGAL_ARGUMENT_ERROR;
2323 return NULL__null;
2324 }
2325
2326 int32_t type = RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL));
2327 if(URES_IS_TABLE(type)((int32_t)(type)==URES_TABLE || (int32_t)(type)==URES_TABLE16
|| (int32_t)(type)==URES_TABLE32)
) {
2328 int32_t t=0;
2329
2330 res = res_getTableItemByKeyres_getTableItemByKey_71(&resB->getResData(), resB->fRes, &t, &key);
2331
2332 if(res == RES_BOGUS0xffffffff) {
2333 key = inKey;
2334 if(resB->fHasFallback == TRUE1) {
2335 dataEntry = getFallbackData(resB, &key, &res, status);
2336 if(U_SUCCESS(*status)) {
2337 switch (RES_GET_TYPE(res)((int32_t)((res)>>28UL))) {
2338 case URES_STRING:
2339 case URES_STRING_V2:
2340 return res_getString({resB, key}, &dataEntry->fData, res, len);
2341 case URES_ALIAS:
2342 {
2343 const UChar* result = 0;
2344 UResourceBundle *tempRes = ures_getByKeyures_getByKey_71(resB, inKey, NULL__null, status);
2345 result = ures_getStringures_getString_71(tempRes, len, status);
2346 ures_closeures_close_71(tempRes);
2347 return result;
2348 }
2349 default:
2350 *status = U_RESOURCE_TYPE_MISMATCH;
2351 }
2352 } else {
2353 *status = U_MISSING_RESOURCE_ERROR;
2354 }
2355 } else {
2356 *status = U_MISSING_RESOURCE_ERROR;
2357 }
2358 } else {
2359 switch (RES_GET_TYPE(res)((int32_t)((res)>>28UL))) {
2360 case URES_STRING:
2361 case URES_STRING_V2:
2362 return res_getString({resB, key}, &resB->getResData(), res, len);
2363 case URES_ALIAS:
2364 {
2365 const UChar* result = 0;
2366 UResourceBundle *tempRes = ures_getByKeyures_getByKey_71(resB, inKey, NULL__null, status);
2367 result = ures_getStringures_getString_71(tempRes, len, status);
2368 ures_closeures_close_71(tempRes);
2369 return result;
2370 }
2371 default:
2372 *status = U_RESOURCE_TYPE_MISMATCH;
2373 }
2374 }
2375 }
2376#if 0
2377 /* this is a kind of TODO item. If we have an array with an index table, we could do this. */
2378 /* not currently */
2379 else if(RES_GET_TYPE(resB->fRes)((int32_t)((resB->fRes)>>28UL)) == URES_ARRAY && resB->fHasFallback == TRUE1) {
2380 /* here should go a first attempt to locate the key using index table */
2381 dataEntry = getFallbackData(resB, &key, &res, status);
2382 if(U_SUCCESS(*status)) {
2383 // TODO: Tracing
2384 return res_getString(rd, res, len);
2385 } else {
2386 *status = U_MISSING_RESOURCE_ERROR;
2387 }
2388 }
2389#endif
2390 else {
2391 *status = U_RESOURCE_TYPE_MISMATCH;
2392 }
2393 return NULL__null;
2394}
2395
2396U_CAPIextern "C" const char * U_EXPORT2
2397ures_getUTF8StringByKeyures_getUTF8StringByKey_71(const UResourceBundle *resB,
2398 const char *key,
2399 char *dest, int32_t *pLength,
2400 UBool forceCopy,
2401 UErrorCode *status) {
2402 int32_t length16;
2403 const UChar *s16 = ures_getStringByKeyures_getStringByKey_71(resB, key, &length16, status);
2404 return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
2405}
2406
2407/* TODO: clean from here down */
2408
2409/**
2410 * INTERNAL: Get the name of the first real locale (not placeholder)
2411 * that has resource bundle data.
2412 */
2413U_CAPIextern "C" const char* U_EXPORT2
2414ures_getLocaleInternalures_getLocaleInternal_71(const UResourceBundle* resourceBundle, UErrorCode* status)
2415{
2416 if (status==NULL__null || U_FAILURE(*status)) {
2417 return NULL__null;
2418 }
2419 if (!resourceBundle) {
2420 *status = U_ILLEGAL_ARGUMENT_ERROR;
2421 return NULL__null;
2422 } else {
2423 return resourceBundle->fData->fName;
2424 }
2425}
2426
2427U_CAPIextern "C" const char* U_EXPORT2
2428ures_getLocaleures_getLocale_71(const UResourceBundle* resourceBundle,
2429 UErrorCode* status)
2430{
2431 return ures_getLocaleInternalures_getLocaleInternal_71(resourceBundle, status);
2432}
2433
2434
2435U_CAPIextern "C" const char* U_EXPORT2
2436ures_getLocaleByTypeures_getLocaleByType_71(const UResourceBundle* resourceBundle,
2437 ULocDataLocaleType type,
2438 UErrorCode* status) {
2439 if (status==NULL__null || U_FAILURE(*status)) {
2440 return NULL__null;
2441 }
2442 if (!resourceBundle) {
2443 *status = U_ILLEGAL_ARGUMENT_ERROR;
2444 return NULL__null;
2445 } else {
2446 switch(type) {
2447 case ULOC_ACTUAL_LOCALE:
2448 return resourceBundle->fData->fName;
2449 case ULOC_VALID_LOCALE:
2450 return resourceBundle->fValidLocaleDataEntry->fName;
2451 case ULOC_REQUESTED_LOCALE:
2452 default:
2453 *status = U_ILLEGAL_ARGUMENT_ERROR;
2454 return NULL__null;
2455 }
2456 }
2457}
2458
2459U_CFUNCextern "C" const char* ures_getNameures_getName_71(const UResourceBundle* resB) {
2460 if(resB == NULL__null) {
2461 return NULL__null;
2462 }
2463
2464 return resB->fData->fName;
2465}
2466
2467#ifdef URES_DEBUG
2468U_CFUNCextern "C" const char* ures_getPath(const UResourceBundle* resB) {
2469 if(resB == NULL__null) {
2470 return NULL__null;
2471 }
2472
2473 return resB->fData->fPath;
2474}
2475#endif
2476
2477static UResourceBundle*
2478ures_openWithType(UResourceBundle *r, const char* path, const char* localeID,
2479 UResOpenType openType, UErrorCode* status) {
2480 if(U_FAILURE(*status)) {
2481 return NULL__null;
2482 }
2483
2484 UResourceDataEntry *entry;
2485 if(openType != URES_OPEN_DIRECT) {
2486 /* first "canonicalize" the locale ID */
2487 char canonLocaleID[ULOC_FULLNAME_CAPACITY157];
2488 uloc_getBaseNameuloc_getBaseName_71(localeID, canonLocaleID, UPRV_LENGTHOF(canonLocaleID)(int32_t)(sizeof(canonLocaleID)/sizeof((canonLocaleID)[0])), status);
2489 if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
2490 *status = U_ILLEGAL_ARGUMENT_ERROR;
2491 return NULL__null;
2492 }
2493 entry = entryOpen(path, canonLocaleID, openType, status);
2494 } else {
2495 entry = entryOpenDirect(path, localeID, status);
2496 }
2497 if(U_FAILURE(*status)) {
2498 return NULL__null;
2499 }
2500 if(entry == NULL__null) {
2501 *status = U_MISSING_RESOURCE_ERROR;
2502 return NULL__null;
2503 }
2504
2505 UBool isStackObject;
2506 if(r == NULL__null) {
2507 r = (UResourceBundle *)uprv_mallocuprv_malloc_71(sizeof(UResourceBundle));
2508 if(r == NULL__null) {
2509 entryClose(entry);
2510 *status = U_MEMORY_ALLOCATION_ERROR;
2511 return NULL__null;
2512 }
2513 isStackObject = FALSE0;
2514 } else { // fill-in
2515 isStackObject = ures_isStackObject(r);
2516 ures_closeBundle(r, FALSE0);
2517 }
2518 uprv_memset(r, 0, sizeof(UResourceBundle)):: memset(r, 0, sizeof(UResourceBundle));
2519 ures_setIsStackObject(r, isStackObject);
2520
2521 r->fValidLocaleDataEntry = r->fData = entry;
2522 r->fHasFallback = openType != URES_OPEN_DIRECT && !r->getResData().noFallback;
2523 r->fIsTopLevel = TRUE1;
2524 r->fRes = r->getResData().rootRes;
2525 r->fSize = res_countArrayItemsres_countArrayItems_71(&r->getResData(), r->fRes);
2526 r->fIndex = -1;
2527
2528 ResourceTracer(r).traceOpen();
2529
2530 return r;
2531}
2532
2533U_CAPIextern "C" UResourceBundle* U_EXPORT2
2534ures_openures_open_71(const char* path, const char* localeID, UErrorCode* status) {
2535 return ures_openWithType(NULL__null, path, localeID, URES_OPEN_LOCALE_DEFAULT_ROOT, status);
2536}
2537
2538U_CAPIextern "C" UResourceBundle* U_EXPORT2
2539ures_openNoDefaultures_openNoDefault_71(const char* path, const char* localeID, UErrorCode* status) {
2540 return ures_openWithType(NULL__null, path, localeID, URES_OPEN_LOCALE_ROOT, status);
2541}
2542
2543/**
2544 * Opens a resource bundle without "canonicalizing" the locale name. No fallback will be performed
2545 * or sought. However, alias substitution will happen!
2546 */
2547U_CAPIextern "C" UResourceBundle* U_EXPORT2
2548ures_openDirectures_openDirect_71(const char* path, const char* localeID, UErrorCode* status) {
2549 return ures_openWithType(NULL__null, path, localeID, URES_OPEN_DIRECT, status);
2550}
2551
2552/**
2553 * Internal API: This function is used to open a resource bundle
2554 * proper fallback chaining is executed while initialization.
2555 * The result is stored in cache for later fallback search.
2556 *
2557 * Same as ures_open(), but uses the fill-in parameter and does not allocate a new bundle.
2558 */
2559U_CAPIextern "C" void U_EXPORT2
2560ures_openFillInures_openFillIn_71(UResourceBundle *r, const char* path,
2561 const char* localeID, UErrorCode* status) {
2562 if(U_SUCCESS(*status) && r == NULL__null) {
2563 *status = U_ILLEGAL_ARGUMENT_ERROR;
2564 return;
2565 }
2566 ures_openWithType(r, path, localeID, URES_OPEN_LOCALE_DEFAULT_ROOT, status);
2567}
2568
2569/**
2570 * Same as ures_openDirect(), but uses the fill-in parameter and does not allocate a new bundle.
2571 */
2572U_CAPIextern "C" void U_EXPORT2
2573ures_openDirectFillInures_openDirectFillIn_71(UResourceBundle *r, const char* path, const char* localeID, UErrorCode* status) {
2574 if(U_SUCCESS(*status) && r == NULL__null) {
2575 *status = U_ILLEGAL_ARGUMENT_ERROR;
2576 return;
2577 }
2578 ures_openWithType(r, path, localeID, URES_OPEN_DIRECT, status);
2579}
2580
2581/**
2582 * API: Counts members. For arrays and tables, returns number of resources.
2583 * For strings, returns 1.
2584 */
2585U_CAPIextern "C" int32_t U_EXPORT2
2586ures_countArrayItemsures_countArrayItems_71(const UResourceBundle* resourceBundle,
2587 const char* resourceKey,
2588 UErrorCode* status)
2589{
2590 UResourceBundle resData;
2591 ures_initStackObjectures_initStackObject_71(&resData);
2592 if (status==NULL__null || U_FAILURE(*status)) {
2593 return 0;
2594 }
2595 if(resourceBundle == NULL__null) {
2596 *status = U_ILLEGAL_ARGUMENT_ERROR;
2597 return 0;
2598 }
2599 ures_getByKeyures_getByKey_71(resourceBundle, resourceKey, &resData, status);
2600
2601 if(resData.getResData().data != NULL__null) {
2602 int32_t result = res_countArrayItemsres_countArrayItems_71(&resData.getResData(), resData.fRes);
2603 ures_closeures_close_71(&resData);
2604 return result;
2605 } else {
2606 *status = U_MISSING_RESOURCE_ERROR;
2607 ures_closeures_close_71(&resData);
2608 return 0;
2609 }
2610}
2611
2612/**
2613 * Internal function.
2614 * Return the version number associated with this ResourceBundle as a string.
2615 *
2616 * @param resourceBundle The resource bundle for which the version is checked.
2617 * @return A version number string as specified in the resource bundle or its parent.
2618 * The caller does not own this string.
2619 * @see ures_getVersion
2620 * @internal
2621 */
2622U_CAPIextern "C" const char* U_EXPORT2
2623ures_getVersionNumberInternalures_getVersionNumberInternal_71(const UResourceBundle *resourceBundle)
2624{
2625 if (!resourceBundle) return NULL__null;
2626
2627 if(resourceBundle->fVersion == NULL__null) {
2628
2629 /* If the version ID has not been built yet, then do so. Retrieve */
2630 /* the minor version from the file. */
2631 UErrorCode status = U_ZERO_ERROR;
2632 int32_t minor_len = 0;
2633 int32_t len;
2634
2635 const UChar* minor_version = ures_getStringByKeyures_getStringByKey_71(resourceBundle, kVersionTag"Version", &minor_len, &status);
2636
2637 /* Determine the length of of the final version string. This is */
2638 /* the length of the major part + the length of the separator */
2639 /* (==1) + the length of the minor part (+ 1 for the zero byte at */
2640 /* the end). */
2641
2642 len = (minor_len > 0) ? minor_len : 1;
2643
2644 /* Allocate the string, and build it up. */
2645 /* + 1 for zero byte */
2646
2647
2648 ((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_mallocuprv_malloc_71(1 + len);
2649 /* Check for null pointer. */
2650 if (((UResourceBundle *)resourceBundle)->fVersion == NULL__null) {
2651 return NULL__null;
2652 }
2653
2654 if(minor_len > 0) {
2655 u_UCharsToCharsu_UCharsToChars_71(minor_version, resourceBundle->fVersion , minor_len);
2656 resourceBundle->fVersion[len] = '\0';
2657 }
2658 else {
2659 uprv_strcpy(resourceBundle->fVersion, kDefaultMinorVersion):: strcpy(resourceBundle->fVersion, "0");
2660 }
2661 }
2662
2663 return resourceBundle->fVersion;
2664}
2665
2666U_CAPIextern "C" const char* U_EXPORT2
2667ures_getVersionNumberures_getVersionNumber_71(const UResourceBundle* resourceBundle)
2668{
2669 return ures_getVersionNumberInternalures_getVersionNumberInternal_71(resourceBundle);
2670}
2671
2672U_CAPIextern "C" void U_EXPORT2 ures_getVersionures_getVersion_71(const UResourceBundle* resB, UVersionInfo versionInfo) {
2673 if (!resB) return;
2674
2675 u_versionFromStringu_versionFromString_71(versionInfo, ures_getVersionNumberInternalures_getVersionNumberInternal_71(resB));
2676}
2677
2678/** Tree support functions *******************************/
2679#define INDEX_LOCALE_NAME"res_index" "res_index"
2680#define INDEX_TAG"InstalledLocales" "InstalledLocales"
2681#define DEFAULT_TAG"default" "default"
2682
2683#if defined(URES_TREE_DEBUG)
2684#include <stdio.h>
2685#endif
2686
2687typedef struct ULocalesContext {
2688 UResourceBundle installed;
2689 UResourceBundle curr;
2690} ULocalesContext;
2691
2692static void U_CALLCONV
2693ures_loc_closeLocales(UEnumeration *enumerator) {
2694 ULocalesContext *ctx = (ULocalesContext *)enumerator->context;
2695 ures_closeures_close_71(&ctx->curr);
2696 ures_closeures_close_71(&ctx->installed);
2697 uprv_freeuprv_free_71(ctx);
2698 uprv_freeuprv_free_71(enumerator);
2699}
2700
2701static int32_t U_CALLCONV
2702ures_loc_countLocales(UEnumeration *en, UErrorCode * /*status*/) {
2703 ULocalesContext *ctx = (ULocalesContext *)en->context;
2704 return ures_getSizeures_getSize_71(&ctx->installed);
2705}
2706
2707U_CDECL_BEGINextern "C" {
2708
2709
2710static const char * U_CALLCONV
2711ures_loc_nextLocale(UEnumeration* en,
2712 int32_t* resultLength,
2713 UErrorCode* status) {
2714 ULocalesContext *ctx = (ULocalesContext *)en->context;
2715 UResourceBundle *res = &(ctx->installed);
2716 UResourceBundle *k = NULL__null;
2717 const char *result = NULL__null;
2718 int32_t len = 0;
2719 if(ures_hasNextures_hasNext_71(res) && (k = ures_getNextResourceures_getNextResource_71(res, &ctx->curr, status)) != 0) {
2720 result = ures_getKeyures_getKey_71(k);
2721 len = (int32_t)uprv_strlen(result):: strlen(result);
2722 }
2723 if (resultLength) {
2724 *resultLength = len;
2725 }
2726 return result;
2727}
2728
2729static void U_CALLCONV
2730ures_loc_resetLocales(UEnumeration* en,
2731 UErrorCode* /*status*/) {
2732 UResourceBundle *res = &((ULocalesContext *)en->context)->installed;
2733 ures_resetIteratorures_resetIterator_71(res);
2734}
2735
2736U_CDECL_END}
2737
2738static const UEnumeration gLocalesEnum = {
2739 NULL__null,
2740 NULL__null,
2741 ures_loc_closeLocales,
2742 ures_loc_countLocales,
2743 uenum_unextDefaultuenum_unextDefault_71,
2744 ures_loc_nextLocale,
2745 ures_loc_resetLocales
2746};
2747
2748
2749U_CAPIextern "C" UEnumeration* U_EXPORT2
2750ures_openAvailableLocalesures_openAvailableLocales_71(const char *path, UErrorCode *status)
2751{
2752 UResourceBundle *idx = NULL__null;
2753 UEnumeration *en = NULL__null;
2754 ULocalesContext *myContext = NULL__null;
2755
2756 if(U_FAILURE(*status)) {
2757 return NULL__null;
2758 }
2759 myContext = static_cast<ULocalesContext *>(uprv_mallocuprv_malloc_71(sizeof(ULocalesContext)));
2760 en = (UEnumeration *)uprv_mallocuprv_malloc_71(sizeof(UEnumeration));
2761 if(!en || !myContext) {
2762 *status = U_MEMORY_ALLOCATION_ERROR;
2763 uprv_freeuprv_free_71(en);
2764 uprv_freeuprv_free_71(myContext);
2765 return NULL__null;
2766 }
2767 uprv_memcpy(en, &gLocalesEnum, sizeof(UEnumeration))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(en, &
gLocalesEnum, sizeof(UEnumeration)); } while (false)
;
2768
2769 ures_initStackObjectures_initStackObject_71(&myContext->installed);
2770 ures_initStackObjectures_initStackObject_71(&myContext->curr);
2771 idx = ures_openDirectures_openDirect_71(path, INDEX_LOCALE_NAME"res_index", status);
2772 ures_getByKeyures_getByKey_71(idx, INDEX_TAG"InstalledLocales", &myContext->installed, status);
2773 if(U_SUCCESS(*status)) {
2774#if defined(URES_TREE_DEBUG)
2775 fprintf(stderrstderr, "Got %s::%s::[%s] : %s\n",
2776 path, INDEX_LOCALE_NAME"res_index", INDEX_TAG"InstalledLocales", ures_getKeyures_getKey_71(&myContext->installed));
2777#endif
2778 en->context = myContext;
2779 } else {
2780#if defined(URES_TREE_DEBUG)
2781 fprintf(stderrstderr, "%s open failed - %s\n", path, u_errorNameu_errorName_71(*status));
2782#endif
2783 ures_closeures_close_71(&myContext->installed);
2784 uprv_freeuprv_free_71(myContext);
2785 uprv_freeuprv_free_71(en);
2786 en = NULL__null;
2787 }
2788
2789 ures_closeures_close_71(idx);
2790
2791 return en;
2792}
2793
2794static UBool isLocaleInList(UEnumeration *locEnum, const char *locToSearch, UErrorCode *status) {
2795 const char *loc;
2796 while ((loc = uenum_nextuenum_next_71(locEnum, NULL__null, status)) != NULL__null) {
2797 if (uprv_strcmp(loc, locToSearch):: strcmp(loc, locToSearch) == 0) {
2798 return TRUE1;
2799 }
2800 }
2801 return FALSE0;
2802}
2803
2804U_CAPIextern "C" int32_t U_EXPORT2
2805ures_getFunctionalEquivalentures_getFunctionalEquivalent_71(char *result, int32_t resultCapacity,
2806 const char *path, const char *resName, const char *keyword, const char *locid,
2807 UBool *isAvailable, UBool omitDefault, UErrorCode *status)
2808{
2809 char kwVal[1024] = ""; /* value of keyword 'keyword' */
2810 char defVal[1024] = ""; /* default value for given locale */
2811 char defLoc[1024] = ""; /* default value for given locale */
2812 char base[1024] = ""; /* base locale */
2813 char found[1024] = "";
2814 char parent[1024] = "";
2815 char full[1024] = "";
2816 UResourceBundle bund1, bund2;
2817 UResourceBundle *res = NULL__null;
2818 UErrorCode subStatus = U_ZERO_ERROR;
2819 int32_t length = 0;
2820 if(U_FAILURE(*status)) return 0;
2821 uloc_getKeywordValueuloc_getKeywordValue_71(locid, keyword, kwVal, 1024-1,&subStatus);
2822 if(!uprv_strcmp(kwVal, DEFAULT_TAG):: strcmp(kwVal, "default")) {
2823 kwVal[0]=0;
2824 }
2825 uloc_getBaseNameuloc_getBaseName_71(locid, base, 1024-1,&subStatus);
2826#if defined(URES_TREE_DEBUG)
2827 fprintf(stderrstderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n",
2828 locid, keyword, kwVal, base, u_errorNameu_errorName_71(subStatus));
2829#endif
2830 ures_initStackObjectures_initStackObject_71(&bund1);
2831 ures_initStackObjectures_initStackObject_71(&bund2);
2832
2833
2834 uprv_strcpy(parent, base):: strcpy(parent, base);
2835 uprv_strcpy(found, base):: strcpy(found, base);
2836
2837 if(isAvailable) {
2838 UEnumeration *locEnum = ures_openAvailableLocalesures_openAvailableLocales_71(path, &subStatus);
2839 *isAvailable = TRUE1;
2840 if (U_SUCCESS(subStatus)) {
2841 *isAvailable = isLocaleInList(locEnum, parent, &subStatus);
2842 }
2843 uenum_closeuenum_close_71(locEnum);
2844 }
2845
2846 if(U_FAILURE(subStatus)) {
2847 *status = subStatus;
2848 return 0;
2849 }
2850
2851 do {
2852 subStatus = U_ZERO_ERROR;
2853 res = ures_openures_open_71(path, parent, &subStatus);
2854 if(((subStatus == U_USING_FALLBACK_WARNING) ||
2855 (subStatus == U_USING_DEFAULT_WARNING)) && isAvailable)
2856 {
2857 *isAvailable = FALSE0;
2858 }
2859 isAvailable = NULL__null; /* only want to set this the first time around */
2860
2861#if defined(URES_TREE_DEBUG)
2862 fprintf(stderrstderr, "%s;%s -> %s [%s]\n", path?path:"ICUDATA", parent, u_errorNameu_errorName_71(subStatus), ures_getLocaleures_getLocale_71(res, &subStatus));
2863#endif
2864 if(U_FAILURE(subStatus)) {
2865 *status = subStatus;
2866 } else if(subStatus == U_ZERO_ERROR) {
2867 ures_getByKeyures_getByKey_71(res,resName,&bund1, &subStatus);
2868 if(subStatus == U_ZERO_ERROR) {
2869 const UChar *defUstr;
2870 int32_t defLen;
2871 /* look for default item */
2872#if defined(URES_TREE_DEBUG)
2873 fprintf(stderrstderr, "%s;%s : loaded default -> %s\n",
2874 path?path:"ICUDATA", parent, u_errorNameu_errorName_71(subStatus));
2875#endif
2876 defUstr = ures_getStringByKeyures_getStringByKey_71(&bund1, DEFAULT_TAG"default", &defLen, &subStatus);
2877 if(U_SUCCESS(subStatus) && defLen) {
2878 u_UCharsToCharsu_UCharsToChars_71(defUstr, defVal, u_strlenu_strlen_71(defUstr));
2879#if defined(URES_TREE_DEBUG)
2880 fprintf(stderrstderr, "%s;%s -> default %s=%s, %s\n",
2881 path?path:"ICUDATA", parent, keyword, defVal, u_errorNameu_errorName_71(subStatus));
2882#endif
2883 uprv_strcpy(defLoc, parent):: strcpy(defLoc, parent);
2884 if(kwVal[0]==0) {
2885 uprv_strcpy(kwVal, defVal):: strcpy(kwVal, defVal);
2886#if defined(URES_TREE_DEBUG)
2887 fprintf(stderrstderr, "%s;%s -> kwVal = %s\n",
2888 path?path:"ICUDATA", parent, keyword, kwVal);
2889#endif
2890 }
2891 }
2892 }
2893 }
2894
2895 subStatus = U_ZERO_ERROR;
2896
2897 if (res != NULL__null) {
2898 uprv_strcpy(found, ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus)):: strcpy(found, ures_getLocaleByType_71(res, ULOC_VALID_LOCALE
, &subStatus))
;
2899 }
2900
2901 uloc_getParentuloc_getParent_71(found,parent,sizeof(parent),&subStatus);
2902 ures_closeures_close_71(res);
2903 } while(!defVal[0] && *found && uprv_strcmp(found, "root"):: strcmp(found, "root") != 0 && U_SUCCESS(*status));
2904
2905 /* Now, see if we can find the kwVal collator.. start the search over.. */
2906 uprv_strcpy(parent, base):: strcpy(parent, base);
2907 uprv_strcpy(found, base):: strcpy(found, base);
2908
2909 do {
2910 subStatus = U_ZERO_ERROR;
2911 res = ures_openures_open_71(path, parent, &subStatus);
2912 if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
2913 *isAvailable = FALSE0;
2914 }
2915 isAvailable = NULL__null; /* only want to set this the first time around */
2916
2917#if defined(URES_TREE_DEBUG)
2918 fprintf(stderrstderr, "%s;%s -> %s (looking for %s)\n",
2919 path?path:"ICUDATA", parent, u_errorNameu_errorName_71(subStatus), kwVal);
2920#endif
2921 if(U_FAILURE(subStatus)) {
2922 *status = subStatus;
2923 } else if(subStatus == U_ZERO_ERROR) {
2924 ures_getByKeyures_getByKey_71(res,resName,&bund1, &subStatus);
2925#if defined(URES_TREE_DEBUG)
2926/**/ fprintf(stderrstderr,"@%d [%s] %s\n", __LINE__2926, resName, u_errorNameu_errorName_71(subStatus));
2927#endif
2928 if(subStatus == U_ZERO_ERROR) {
2929 ures_getByKeyures_getByKey_71(&bund1, kwVal, &bund2, &subStatus);
2930#if defined(URES_TREE_DEBUG)
2931/**/ fprintf(stderrstderr,"@%d [%s] %s\n", __LINE__2931, kwVal, u_errorNameu_errorName_71(subStatus));
2932#endif
2933 if(subStatus == U_ZERO_ERROR) {
2934#if defined(URES_TREE_DEBUG)
2935 fprintf(stderrstderr, "%s;%s -> full0 %s=%s, %s\n",
2936 path?path:"ICUDATA", parent, keyword, kwVal, u_errorNameu_errorName_71(subStatus));
2937#endif
2938 uprv_strcpy(full, parent):: strcpy(full, parent);
2939 if(*full == 0) {
2940 uprv_strcpy(full, "root"):: strcpy(full, "root");
2941 }
2942 /* now, recalculate default kw if need be */
2943 if(uprv_strlen(defLoc):: strlen(defLoc) > uprv_strlen(full):: strlen(full)) {
2944 const UChar *defUstr;
2945 int32_t defLen;
2946 /* look for default item */
2947#if defined(URES_TREE_DEBUG)
2948 fprintf(stderrstderr, "%s;%s -> recalculating Default0\n",
2949 path?path:"ICUDATA", full);
2950#endif
2951 defUstr = ures_getStringByKeyures_getStringByKey_71(&bund1, DEFAULT_TAG"default", &defLen, &subStatus);
2952 if(U_SUCCESS(subStatus) && defLen) {
2953 u_UCharsToCharsu_UCharsToChars_71(defUstr, defVal, u_strlenu_strlen_71(defUstr));
2954#if defined(URES_TREE_DEBUG)
2955 fprintf(stderrstderr, "%s;%s -> default0 %s=%s, %s\n",
2956 path?path:"ICUDATA", full, keyword, defVal, u_errorNameu_errorName_71(subStatus));
2957#endif
2958 uprv_strcpy(defLoc, full):: strcpy(defLoc, full);
2959 }
2960 } /* end of recalculate default KW */
2961#if defined(URES_TREE_DEBUG)
2962 else {
2963 fprintf(stderrstderr, "No trim0, %s <= %s\n", defLoc, full);
2964 }
2965#endif
2966 } else {
2967#if defined(URES_TREE_DEBUG)
2968 fprintf(stderrstderr, "err=%s in %s looking for %s\n",
2969 u_errorNameu_errorName_71(subStatus), parent, kwVal);
2970#endif
2971 }
2972 }
2973 }
2974
2975 subStatus = U_ZERO_ERROR;
2976
2977 uprv_strcpy(found, parent):: strcpy(found, parent);
2978 uloc_getParentuloc_getParent_71(found,parent,1023,&subStatus);
2979 ures_closeures_close_71(res);
2980 } while(!full[0] && *found && U_SUCCESS(*status));
2981
2982 if((full[0]==0) && uprv_strcmp(kwVal, defVal):: strcmp(kwVal, defVal)) {
2983#if defined(URES_TREE_DEBUG)
2984 fprintf(stderrstderr, "Failed to locate kw %s - try default %s\n", kwVal, defVal);
2985#endif
2986 uprv_strcpy(kwVal, defVal):: strcpy(kwVal, defVal);
2987 uprv_strcpy(parent, base):: strcpy(parent, base);
2988 uprv_strcpy(found, base):: strcpy(found, base);
2989
2990 do { /* search for 'default' named item */
2991 subStatus = U_ZERO_ERROR;
2992 res = ures_openures_open_71(path, parent, &subStatus);
2993 if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
2994 *isAvailable = FALSE0;
2995 }
2996 isAvailable = NULL__null; /* only want to set this the first time around */
2997
2998#if defined(URES_TREE_DEBUG)
2999 fprintf(stderrstderr, "%s;%s -> %s (looking for default %s)\n",
3000 path?path:"ICUDATA", parent, u_errorNameu_errorName_71(subStatus), kwVal);
3001#endif
3002 if(U_FAILURE(subStatus)) {
3003 *status = subStatus;
3004 } else if(subStatus == U_ZERO_ERROR) {
3005 ures_getByKeyures_getByKey_71(res,resName,&bund1, &subStatus);
3006 if(subStatus == U_ZERO_ERROR) {
3007 ures_getByKeyures_getByKey_71(&bund1, kwVal, &bund2, &subStatus);
3008 if(subStatus == U_ZERO_ERROR) {
3009#if defined(URES_TREE_DEBUG)
3010 fprintf(stderrstderr, "%s;%s -> full1 %s=%s, %s\n", path?path:"ICUDATA",
3011 parent, keyword, kwVal, u_errorNameu_errorName_71(subStatus));
3012#endif
3013 uprv_strcpy(full, parent):: strcpy(full, parent);
3014 if(*full == 0) {
3015 uprv_strcpy(full, "root"):: strcpy(full, "root");
3016 }
3017
3018 /* now, recalculate default kw if need be */
3019 if(uprv_strlen(defLoc):: strlen(defLoc) > uprv_strlen(full):: strlen(full)) {
3020 const UChar *defUstr;
3021 int32_t defLen;
3022 /* look for default item */
3023#if defined(URES_TREE_DEBUG)
3024 fprintf(stderrstderr, "%s;%s -> recalculating Default1\n",
3025 path?path:"ICUDATA", full);
3026#endif
3027 defUstr = ures_getStringByKeyures_getStringByKey_71(&bund1, DEFAULT_TAG"default", &defLen, &subStatus);
3028 if(U_SUCCESS(subStatus) && defLen) {
3029 u_UCharsToCharsu_UCharsToChars_71(defUstr, defVal, u_strlenu_strlen_71(defUstr));
3030#if defined(URES_TREE_DEBUG)
3031 fprintf(stderrstderr, "%s;%s -> default %s=%s, %s\n",
3032 path?path:"ICUDATA", full, keyword, defVal, u_errorNameu_errorName_71(subStatus));
3033#endif
3034 uprv_strcpy(defLoc, full):: strcpy(defLoc, full);
3035 }
3036 } /* end of recalculate default KW */
3037#if defined(URES_TREE_DEBUG)
3038 else {
3039 fprintf(stderrstderr, "No trim1, %s <= %s\n", defLoc, full);
3040 }
3041#endif
3042 }
3043 }
3044 }
3045 subStatus = U_ZERO_ERROR;
3046
3047 uprv_strcpy(found, parent):: strcpy(found, parent);
3048 uloc_getParentuloc_getParent_71(found,parent,1023,&subStatus);
3049 ures_closeures_close_71(res);
3050 } while(!full[0] && *found && U_SUCCESS(*status));
3051 }
3052
3053 if(U_SUCCESS(*status)) {
3054 if(!full[0]) {
3055#if defined(URES_TREE_DEBUG)
3056 fprintf(stderrstderr, "Still could not load keyword %s=%s\n", keyword, kwVal);
3057#endif
3058 *status = U_MISSING_RESOURCE_ERROR;
3059 } else if(omitDefault) {
3060#if defined(URES_TREE_DEBUG)
3061 fprintf(stderrstderr,"Trim? full=%s, defLoc=%s, found=%s\n", full, defLoc, found);
3062#endif
3063 if(uprv_strlen(defLoc):: strlen(defLoc) <= uprv_strlen(full):: strlen(full)) {
3064 /* found the keyword in a *child* of where the default tag was present. */
3065 if(!uprv_strcmp(kwVal, defVal):: strcmp(kwVal, defVal)) { /* if the requested kw is default, */
3066 /* and the default is in or in an ancestor of the current locale */
3067#if defined(URES_TREE_DEBUG)
3068 fprintf(stderrstderr, "Removing unneeded var %s=%s\n", keyword, kwVal);
3069#endif
3070 kwVal[0]=0;
3071 }
3072 }
3073 }
3074 uprv_strcpy(found, full):: strcpy(found, full);
3075 if(kwVal[0]) {
3076 uprv_strcat(found, "@"):: strcat(found, "@");
3077 uprv_strcat(found, keyword):: strcat(found, keyword);
3078 uprv_strcat(found, "="):: strcat(found, "=");
3079 uprv_strcat(found, kwVal):: strcat(found, kwVal);
3080 } else if(!omitDefault) {
3081 uprv_strcat(found, "@"):: strcat(found, "@");
3082 uprv_strcat(found, keyword):: strcat(found, keyword);
3083 uprv_strcat(found, "="):: strcat(found, "=");
3084 uprv_strcat(found, defVal):: strcat(found, defVal);
3085 }
3086 }
3087 /* we found the default locale - no need to repeat it.*/
3088
3089 ures_closeures_close_71(&bund1);
3090 ures_closeures_close_71(&bund2);
3091
3092 length = (int32_t)uprv_strlen(found):: strlen(found);
3093
3094 if(U_SUCCESS(*status)) {
3095 int32_t copyLength = uprv_minuprv_min_71(length, resultCapacity);
3096 if(copyLength>0) {
3097 uprv_strncpy(result, found, copyLength):: strncpy(result, found, copyLength);
3098 }
3099 if(length == 0) {
3100 *status = U_MISSING_RESOURCE_ERROR;
3101 }
3102 } else {
3103 length = 0;
3104 result[0]=0;
3105 }
3106 return u_terminateCharsu_terminateChars_71(result, resultCapacity, length, status);
3107}
3108
3109U_CAPIextern "C" UEnumeration* U_EXPORT2
3110ures_getKeywordValuesures_getKeywordValues_71(const char *path, const char *keyword, UErrorCode *status)
3111{
3112#define VALUES_BUF_SIZE2048 2048
3113#define VALUES_LIST_SIZE512 512
3114
3115 char valuesBuf[VALUES_BUF_SIZE2048];
3116 int32_t valuesIndex = 0;
3117 const char *valuesList[VALUES_LIST_SIZE512];
3118 int32_t valuesCount = 0;
3119
3120 const char *locale;
3121 int32_t locLen;
3122
3123 UEnumeration *locs = NULL__null;
3124
3125 UResourceBundle item;
3126 UResourceBundle subItem;
3127
3128 ures_initStackObjectures_initStackObject_71(&item);
3129 ures_initStackObjectures_initStackObject_71(&subItem);
3130 locs = ures_openAvailableLocalesures_openAvailableLocales_71(path, status);
3131
3132 if(U_FAILURE(*status)) {
3133 ures_closeures_close_71(&item);
3134 ures_closeures_close_71(&subItem);
3135 return NULL__null;
3136 }
3137
3138 valuesBuf[0]=0;
3139 valuesBuf[1]=0;
3140
3141 while((locale = uenum_nextuenum_next_71(locs, &locLen, status)) != 0) {
3142 UResourceBundle *bund = NULL__null;
3143 UResourceBundle *subPtr = NULL__null;
3144 UErrorCode subStatus = U_ZERO_ERROR; /* don't fail if a bundle is unopenable */
3145 bund = ures_openures_open_71(path, locale, &subStatus);
3146
3147#if defined(URES_TREE_DEBUG)
3148 if(!bund || U_FAILURE(subStatus)) {
3149 fprintf(stderrstderr, "%s-%s values: Can't open %s locale - skipping. (%s)\n",
3150 path?path:"<ICUDATA>", keyword, locale, u_errorNameu_errorName_71(subStatus));
3151 }
3152#endif
3153
3154 ures_getByKeyures_getByKey_71(bund, keyword, &item, &subStatus);
3155
3156 if(!bund || U_FAILURE(subStatus)) {
3157#if defined(URES_TREE_DEBUG)
3158 fprintf(stderrstderr, "%s-%s values: Can't find in %s - skipping. (%s)\n",
3159 path?path:"<ICUDATA>", keyword, locale, u_errorNameu_errorName_71(subStatus));
3160#endif
3161 ures_closeures_close_71(bund);
3162 bund = NULL__null;
3163 continue;
3164 }
3165
3166 while((subPtr = ures_getNextResourceures_getNextResource_71(&item,&subItem,&subStatus)) != 0
3167 && U_SUCCESS(subStatus)) {
3168 const char *k;
3169 int32_t i;
3170 k = ures_getKeyures_getKey_71(subPtr);
3171
3172#if defined(URES_TREE_DEBUG)
3173 /* fprintf(stderr, "%s | %s | %s | %s\n", path?path:"<ICUDATA>", keyword, locale, k); */
3174#endif
3175 if(k == NULL__null || *k == 0 ||
3176 uprv_strcmp(k, DEFAULT_TAG):: strcmp(k, "default") == 0 || uprv_strncmp(k, "private-", 8):: strncmp(k, "private-", 8) == 0) {
3177 // empty or "default" or unlisted type
3178 continue;
3179 }
3180 for(i=0; i<valuesCount; i++) {
3181 if(!uprv_strcmp(valuesList[i],k):: strcmp(valuesList[i], k)) {
3182 k = NULL__null; /* found duplicate */
3183 break;
3184 }
3185 }
3186 if(k != NULL__null) {
3187 int32_t kLen = (int32_t)uprv_strlen(k):: strlen(k);
3188 if((valuesCount >= (VALUES_LIST_SIZE512-1)) || /* no more space in list .. */
3189 ((valuesIndex+kLen+1+1) >= VALUES_BUF_SIZE2048)) { /* no more space in buffer (string + 2 nulls) */
3190 *status = U_ILLEGAL_ARGUMENT_ERROR; /* out of space.. */
3191 } else {
3192 uprv_strcpy(valuesBuf+valuesIndex, k):: strcpy(valuesBuf+valuesIndex, k);
3193 valuesList[valuesCount++] = valuesBuf+valuesIndex;
3194 valuesIndex += kLen;
3195#if defined(URES_TREE_DEBUG)
3196 fprintf(stderrstderr, "%s | %s | %s | [%s] (UNIQUE)\n",
3197 path?path:"<ICUDATA>", keyword, locale, k);
3198#endif
3199 valuesBuf[valuesIndex++] = 0; /* terminate */
3200 }
3201 }
3202 }
3203 ures_closeures_close_71(bund);
3204 }
3205 valuesBuf[valuesIndex++] = 0; /* terminate */
3206
3207 ures_closeures_close_71(&item);
3208 ures_closeures_close_71(&subItem);
3209 uenum_closeuenum_close_71(locs);
3210#if defined(URES_TREE_DEBUG)
3211 fprintf(stderrstderr, "%s: size %d, #%d\n", u_errorNameu_errorName_71(*status),
3212 valuesIndex, valuesCount);
3213#endif
3214 return uloc_openKeywordListuloc_openKeywordList_71(valuesBuf, valuesIndex, status);
3215}
3216#if 0
3217/* This code isn't needed, and given the documentation warnings the implementation is suspect */
3218U_CAPIextern "C" UBool U_EXPORT2
3219ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
3220 if(res1==NULL__null || res2==NULL__null){
3221 return res1==res2; /* pointer comparison */
3222 }
3223 if(res1->fKey==NULL__null|| res2->fKey==NULL__null){
3224 return (res1->fKey==res2->fKey);
3225 }else{
3226 if(uprv_strcmp(res1->fKey, res2->fKey):: strcmp(res1->fKey, res2->fKey)!=0){
3227 return FALSE0;
3228 }
3229 }
3230 if(uprv_strcmp(res1->fData->fName, res2->fData->fName):: strcmp(res1->fData->fName, res2->fData->fName)!=0){
3231 return FALSE0;
3232 }
3233 if(res1->fData->fPath == NULL__null|| res2->fData->fPath==NULL__null){
3234 return (res1->fData->fPath == res2->fData->fPath);
3235 }else{
3236 if(uprv_strcmp(res1->fData->fPath, res2->fData->fPath):: strcmp(res1->fData->fPath, res2->fData->fPath)!=0){
3237 return FALSE0;
3238 }
3239 }
3240 if(uprv_strcmp(res1->fData->fParent->fName, res2->fData->fParent->fName):: strcmp(res1->fData->fParent->fName, res2->fData
->fParent->fName)
!=0){
3241 return FALSE0;
3242 }
3243 if(uprv_strcmp(res1->fData->fParent->fPath, res2->fData->fParent->fPath):: strcmp(res1->fData->fParent->fPath, res2->fData
->fParent->fPath)
!=0){
3244 return FALSE0;
3245 }
3246 if(uprv_strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen):: strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen
)
!=0){
3247 return FALSE0;
3248 }
3249 if(res1->fRes != res2->fRes){
3250 return FALSE0;
3251 }
3252 return TRUE1;
3253}
3254U_CAPIextern "C" UResourceBundle* U_EXPORT2
3255ures_clone(const UResourceBundle* res, UErrorCode* status){
3256 UResourceBundle* bundle = NULL__null;
3257 UResourceBundle* ret = NULL__null;
3258 if(U_FAILURE(*status) || res == NULL__null){
3259 return NULL__null;
3260 }
3261 bundle = ures_openures_open_71(res->fData->fPath, res->fData->fName, status);
3262 if(res->fResPath!=NULL__null){
3263 ret = ures_findSubResourceures_findSubResource_71(bundle, res->fResPath, NULL__null, status);
3264 ures_closeures_close_71(bundle);
3265 }else{
3266 ret = bundle;
3267 }
3268 return ret;
3269}
3270U_CAPIextern "C" const UResourceBundle* U_EXPORT2
3271ures_getParentBundle(const UResourceBundle* res){
3272 if(res==NULL__null){
3273 return NULL__null;
3274 }
3275 return res->fParentRes;
3276}
3277#endif
3278
3279U_CAPIextern "C" void U_EXPORT2
3280ures_getVersionByKeyures_getVersionByKey_71(const UResourceBundle* res, const char *key, UVersionInfo ver, UErrorCode *status) {
3281 const UChar *str;
3282 int32_t len;
3283 str = ures_getStringByKeyures_getStringByKey_71(res, key, &len, status);
3284 if(U_SUCCESS(*status)) {
3285 u_versionFromUStringu_versionFromUString_71(ver, str);
3286 }
3287}
3288
3289/* eof */