1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/uresbund.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2880 @@ 1.4 +/* 1.5 +****************************************************************************** 1.6 +* Copyright (C) 1997-2013, International Business Machines Corporation and 1.7 +* others. All Rights Reserved. 1.8 +****************************************************************************** 1.9 +* 1.10 +* File URESBUND.C 1.11 +* 1.12 +* Modification History: 1.13 +* 1.14 +* Date Name Description 1.15 +* 04/01/97 aliu Creation. 1.16 +* 06/14/99 stephen Removed functions taking a filename suffix. 1.17 +* 07/20/99 stephen Changed for UResourceBundle typedef'd to void* 1.18 +* 11/09/99 weiv Added ures_getLocale() 1.19 +* March 2000 weiv Total overhaul - using data in DLLs 1.20 +* 06/20/2000 helena OS/400 port changes; mostly typecast. 1.21 +* 06/24/02 weiv Added support for resource sharing 1.22 +****************************************************************************** 1.23 +*/ 1.24 + 1.25 +#include "unicode/ustring.h" 1.26 +#include "unicode/ucnv.h" 1.27 +#include "charstr.h" 1.28 +#include "uresimp.h" 1.29 +#include "ustr_imp.h" 1.30 +#include "cwchar.h" 1.31 +#include "ucln_cmn.h" 1.32 +#include "cmemory.h" 1.33 +#include "cstring.h" 1.34 +#include "uhash.h" 1.35 +#include "unicode/uenum.h" 1.36 +#include "uenumimp.h" 1.37 +#include "ulocimp.h" 1.38 +#include "umutex.h" 1.39 +#include "putilimp.h" 1.40 +#include "uassert.h" 1.41 + 1.42 + 1.43 +/* 1.44 +Static cache for already opened resource bundles - mostly for keeping fallback info 1.45 +TODO: This cache should probably be removed when the deprecated code is 1.46 + completely removed. 1.47 +*/ 1.48 +static UHashtable *cache = NULL; 1.49 +static icu::UInitOnce gCacheInitOnce; 1.50 + 1.51 +static UMutex resbMutex = U_MUTEX_INITIALIZER; 1.52 + 1.53 +/* INTERNAL: hashes an entry */ 1.54 +static int32_t U_CALLCONV hashEntry(const UHashTok parm) { 1.55 + UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer; 1.56 + UHashTok namekey, pathkey; 1.57 + namekey.pointer = b->fName; 1.58 + pathkey.pointer = b->fPath; 1.59 + return uhash_hashChars(namekey)+37*uhash_hashChars(pathkey); 1.60 +} 1.61 + 1.62 +/* INTERNAL: compares two entries */ 1.63 +static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) { 1.64 + UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer; 1.65 + UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer; 1.66 + UHashTok name1, name2, path1, path2; 1.67 + name1.pointer = b1->fName; 1.68 + name2.pointer = b2->fName; 1.69 + path1.pointer = b1->fPath; 1.70 + path2.pointer = b2->fPath; 1.71 + return (UBool)(uhash_compareChars(name1, name2) && 1.72 + uhash_compareChars(path1, path2)); 1.73 +} 1.74 + 1.75 + 1.76 +/** 1.77 + * Internal function, gets parts of locale name according 1.78 + * to the position of '_' character 1.79 + */ 1.80 +static UBool chopLocale(char *name) { 1.81 + char *i = uprv_strrchr(name, '_'); 1.82 + 1.83 + if(i != NULL) { 1.84 + *i = '\0'; 1.85 + return TRUE; 1.86 + } 1.87 + 1.88 + return FALSE; 1.89 +} 1.90 + 1.91 +/** 1.92 + * Internal function 1.93 + */ 1.94 +static void entryIncrease(UResourceDataEntry *entry) { 1.95 + umtx_lock(&resbMutex); 1.96 + entry->fCountExisting++; 1.97 + while(entry->fParent != NULL) { 1.98 + entry = entry->fParent; 1.99 + entry->fCountExisting++; 1.100 + } 1.101 + umtx_unlock(&resbMutex); 1.102 +} 1.103 + 1.104 +/** 1.105 + * Internal function. Tries to find a resource in given Resource 1.106 + * Bundle, as well as in its parents 1.107 + */ 1.108 +static const ResourceData *getFallbackData(const UResourceBundle* resBundle, const char* * resTag, UResourceDataEntry* *realData, Resource *res, UErrorCode *status) { 1.109 + UResourceDataEntry *resB = resBundle->fData; 1.110 + int32_t indexR = -1; 1.111 + int32_t i = 0; 1.112 + *res = RES_BOGUS; 1.113 + if(resB != NULL) { 1.114 + if(resB->fBogus == U_ZERO_ERROR) { /* if this resource is real, */ 1.115 + *res = res_getTableItemByKey(&(resB->fData), resB->fData.rootRes, &indexR, resTag); /* try to get data from there */ 1.116 + i++; 1.117 + } 1.118 + if(resBundle->fHasFallback == TRUE) { 1.119 + while(*res == RES_BOGUS && resB->fParent != NULL) { /* Otherwise, we'll look in parents */ 1.120 + resB = resB->fParent; 1.121 + if(resB->fBogus == U_ZERO_ERROR) { 1.122 + i++; 1.123 + *res = res_getTableItemByKey(&(resB->fData), resB->fData.rootRes, &indexR, resTag); 1.124 + } 1.125 + } 1.126 + } 1.127 + 1.128 + if(*res != RES_BOGUS) { /* If the resource is found in parents, we need to adjust the error */ 1.129 + if(i>1) { 1.130 + if(uprv_strcmp(resB->fName, uloc_getDefault())==0 || uprv_strcmp(resB->fName, kRootLocaleName)==0) { 1.131 + *status = U_USING_DEFAULT_WARNING; 1.132 + } else { 1.133 + *status = U_USING_FALLBACK_WARNING; 1.134 + } 1.135 + } 1.136 + *realData = resB; 1.137 + return (&(resB->fData)); 1.138 + } else { /* If resource is not found, we need to give an error */ 1.139 + *status = U_MISSING_RESOURCE_ERROR; 1.140 + return NULL; 1.141 + } 1.142 + } else { 1.143 + *status = U_MISSING_RESOURCE_ERROR; 1.144 + return NULL; 1.145 + } 1.146 +} 1.147 + 1.148 +static void 1.149 +free_entry(UResourceDataEntry *entry) { 1.150 + UResourceDataEntry *alias; 1.151 + res_unload(&(entry->fData)); 1.152 + if(entry->fName != NULL && entry->fName != entry->fNameBuffer) { 1.153 + uprv_free(entry->fName); 1.154 + } 1.155 + if(entry->fPath != NULL) { 1.156 + uprv_free(entry->fPath); 1.157 + } 1.158 + if(entry->fPool != NULL) { 1.159 + --entry->fPool->fCountExisting; 1.160 + } 1.161 + alias = entry->fAlias; 1.162 + if(alias != NULL) { 1.163 + while(alias->fAlias != NULL) { 1.164 + alias = alias->fAlias; 1.165 + } 1.166 + --alias->fCountExisting; 1.167 + } 1.168 + uprv_free(entry); 1.169 +} 1.170 + 1.171 +/* Works just like ucnv_flushCache() */ 1.172 +static int32_t ures_flushCache() 1.173 +{ 1.174 + UResourceDataEntry *resB; 1.175 + int32_t pos; 1.176 + int32_t rbDeletedNum = 0; 1.177 + const UHashElement *e; 1.178 + UBool deletedMore; 1.179 + 1.180 + /*if shared data hasn't even been lazy evaluated yet 1.181 + * return 0 1.182 + */ 1.183 + umtx_lock(&resbMutex); 1.184 + if (cache == NULL) { 1.185 + umtx_unlock(&resbMutex); 1.186 + return 0; 1.187 + } 1.188 + 1.189 + do { 1.190 + deletedMore = FALSE; 1.191 + /*creates an enumeration to iterate through every element in the table */ 1.192 + pos = -1; 1.193 + while ((e = uhash_nextElement(cache, &pos)) != NULL) 1.194 + { 1.195 + resB = (UResourceDataEntry *) e->value.pointer; 1.196 + /* Deletes only if reference counter == 0 1.197 + * Don't worry about the children of this node. 1.198 + * Those will eventually get deleted too, if not already. 1.199 + * Don't worry about the parents of this node. 1.200 + * Those will eventually get deleted too, if not already. 1.201 + */ 1.202 + /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's not zero, that means that */ 1.203 + /* some resource bundles are still open somewhere. */ 1.204 + 1.205 + if (resB->fCountExisting == 0) { 1.206 + rbDeletedNum++; 1.207 + deletedMore = TRUE; 1.208 + uhash_removeElement(cache, e); 1.209 + free_entry(resB); 1.210 + } 1.211 + } 1.212 + /* 1.213 + * Do it again to catch bundles (aliases, pool bundle) whose fCountExisting 1.214 + * got decremented by free_entry(). 1.215 + */ 1.216 + } while(deletedMore); 1.217 + umtx_unlock(&resbMutex); 1.218 + 1.219 + return rbDeletedNum; 1.220 +} 1.221 + 1.222 +#ifdef URES_DEBUG 1.223 +#include <stdio.h> 1.224 + 1.225 +U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) { 1.226 + UBool cacheNotEmpty = FALSE; 1.227 + int32_t pos = -1; 1.228 + const UHashElement *e; 1.229 + UResourceDataEntry *resB; 1.230 + 1.231 + umtx_lock(&resbMutex); 1.232 + if (cache == NULL) { 1.233 + umtx_unlock(&resbMutex); 1.234 + fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__); 1.235 + return FALSE; 1.236 + } 1.237 + 1.238 + while ((e = uhash_nextElement(cache, &pos)) != NULL) { 1.239 + cacheNotEmpty=TRUE; 1.240 + resB = (UResourceDataEntry *) e->value.pointer; 1.241 + fprintf(stderr,"%s:%d: RB Cache: Entry @0x%p, refcount %d, name %s:%s. Pool 0x%p, alias 0x%p, parent 0x%p\n", 1.242 + __FILE__, __LINE__, 1.243 + (void*)resB, resB->fCountExisting, 1.244 + resB->fName?resB->fName:"NULL", 1.245 + resB->fPath?resB->fPath:"NULL", 1.246 + (void*)resB->fPool, 1.247 + (void*)resB->fAlias, 1.248 + (void*)resB->fParent); 1.249 + } 1.250 + 1.251 + fprintf(stderr,"%s:%d: RB Cache still contains %d items.\n", __FILE__, __LINE__, uhash_count(cache)); 1.252 + 1.253 + umtx_unlock(&resbMutex); 1.254 + 1.255 + return cacheNotEmpty; 1.256 +} 1.257 + 1.258 +#endif 1.259 + 1.260 +static UBool U_CALLCONV ures_cleanup(void) 1.261 +{ 1.262 + if (cache != NULL) { 1.263 + ures_flushCache(); 1.264 + uhash_close(cache); 1.265 + cache = NULL; 1.266 + } 1.267 + gCacheInitOnce.reset(); 1.268 + return TRUE; 1.269 +} 1.270 + 1.271 +/** INTERNAL: Initializes the cache for resources */ 1.272 +static void createCache(UErrorCode &status) { 1.273 + U_ASSERT(cache == NULL); 1.274 + cache = uhash_open(hashEntry, compareEntries, NULL, &status); 1.275 + ucln_common_registerCleanup(UCLN_COMMON_URES, ures_cleanup); 1.276 +} 1.277 + 1.278 +static void initCache(UErrorCode *status) { 1.279 + umtx_initOnce(gCacheInitOnce, &createCache, *status); 1.280 +} 1.281 + 1.282 +/** INTERNAL: sets the name (locale) of the resource bundle to given name */ 1.283 + 1.284 +static void setEntryName(UResourceDataEntry *res, const char *name, UErrorCode *status) { 1.285 + int32_t len = (int32_t)uprv_strlen(name); 1.286 + if(res->fName != NULL && res->fName != res->fNameBuffer) { 1.287 + uprv_free(res->fName); 1.288 + } 1.289 + if (len < (int32_t)sizeof(res->fNameBuffer)) { 1.290 + res->fName = res->fNameBuffer; 1.291 + } 1.292 + else { 1.293 + res->fName = (char *)uprv_malloc(len+1); 1.294 + } 1.295 + if(res->fName == NULL) { 1.296 + *status = U_MEMORY_ALLOCATION_ERROR; 1.297 + } else { 1.298 + uprv_strcpy(res->fName, name); 1.299 + } 1.300 +} 1.301 + 1.302 +static UResourceDataEntry * 1.303 +getPoolEntry(const char *path, UErrorCode *status); 1.304 + 1.305 +/** 1.306 + * INTERNAL: Inits and opens an entry from a data DLL. 1.307 + * CAUTION: resbMutex must be locked when calling this function. 1.308 + */ 1.309 +static UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) { 1.310 + UResourceDataEntry *r = NULL; 1.311 + UResourceDataEntry find; 1.312 + /*int32_t hashValue;*/ 1.313 + const char *name; 1.314 + char aliasName[100] = { 0 }; 1.315 + int32_t aliasLen = 0; 1.316 + /*UBool isAlias = FALSE;*/ 1.317 + /*UHashTok hashkey; */ 1.318 + 1.319 + if(U_FAILURE(*status)) { 1.320 + return NULL; 1.321 + } 1.322 + 1.323 + /* here we try to deduce the right locale name */ 1.324 + if(localeID == NULL) { /* if localeID is NULL, we're trying to open default locale */ 1.325 + name = uloc_getDefault(); 1.326 + } else if(*localeID == 0) { /* if localeID is "" then we try to open root locale */ 1.327 + name = kRootLocaleName; 1.328 + } else { /* otherwise, we'll open what we're given */ 1.329 + name = localeID; 1.330 + } 1.331 + 1.332 + find.fName = (char *)name; 1.333 + find.fPath = (char *)path; 1.334 + 1.335 + /* calculate the hash value of the entry */ 1.336 + /*hashkey.pointer = (void *)&find;*/ 1.337 + /*hashValue = hashEntry(hashkey);*/ 1.338 + 1.339 + /* check to see if we already have this entry */ 1.340 + r = (UResourceDataEntry *)uhash_get(cache, &find); 1.341 + if(r == NULL) { 1.342 + /* if the entry is not yet in the hash table, we'll try to construct a new one */ 1.343 + r = (UResourceDataEntry *) uprv_malloc(sizeof(UResourceDataEntry)); 1.344 + if(r == NULL) { 1.345 + *status = U_MEMORY_ALLOCATION_ERROR; 1.346 + return NULL; 1.347 + } 1.348 + 1.349 + uprv_memset(r, 0, sizeof(UResourceDataEntry)); 1.350 + /*r->fHashKey = hashValue;*/ 1.351 + 1.352 + setEntryName(r, name, status); 1.353 + if (U_FAILURE(*status)) { 1.354 + uprv_free(r); 1.355 + return NULL; 1.356 + } 1.357 + 1.358 + if(path != NULL) { 1.359 + r->fPath = (char *)uprv_strdup(path); 1.360 + if(r->fPath == NULL) { 1.361 + *status = U_MEMORY_ALLOCATION_ERROR; 1.362 + uprv_free(r); 1.363 + return NULL; 1.364 + } 1.365 + } 1.366 + 1.367 + /* this is the actual loading */ 1.368 + res_load(&(r->fData), r->fPath, r->fName, status); 1.369 + 1.370 + if (U_FAILURE(*status)) { 1.371 + /* we have no such entry in dll, so it will always use fallback */ 1.372 + *status = U_USING_FALLBACK_WARNING; 1.373 + r->fBogus = U_USING_FALLBACK_WARNING; 1.374 + } else { /* if we have a regular entry */ 1.375 + Resource aliasres; 1.376 + if (r->fData.usesPoolBundle) { 1.377 + r->fPool = getPoolEntry(r->fPath, status); 1.378 + if (U_SUCCESS(*status)) { 1.379 + const int32_t *poolIndexes = r->fPool->fData.pRoot + 1; 1.380 + if(r->fData.pRoot[1 + URES_INDEX_POOL_CHECKSUM] == poolIndexes[URES_INDEX_POOL_CHECKSUM]) { 1.381 + r->fData.poolBundleKeys = (const char *)(poolIndexes + (poolIndexes[URES_INDEX_LENGTH] & 0xff)); 1.382 + } else { 1.383 + r->fBogus = *status = U_INVALID_FORMAT_ERROR; 1.384 + } 1.385 + } else { 1.386 + r->fBogus = *status; 1.387 + } 1.388 + } 1.389 + if (U_SUCCESS(*status)) { 1.390 + /* handle the alias by trying to get out the %%Alias tag.*/ 1.391 + /* We'll try to get alias string from the bundle */ 1.392 + aliasres = res_getResource(&(r->fData), "%%ALIAS"); 1.393 + if (aliasres != RES_BOGUS) { 1.394 + const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen); 1.395 + if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */ 1.396 + u_UCharsToChars(alias, aliasName, aliasLen+1); 1.397 + r->fAlias = init_entry(aliasName, path, status); 1.398 + } 1.399 + } 1.400 + } 1.401 + } 1.402 + 1.403 + { 1.404 + UResourceDataEntry *oldR = NULL; 1.405 + if((oldR = (UResourceDataEntry *)uhash_get(cache, r)) == NULL) { /* if the data is not cached */ 1.406 + /* just insert it in the cache */ 1.407 + UErrorCode cacheStatus = U_ZERO_ERROR; 1.408 + uhash_put(cache, (void *)r, r, &cacheStatus); 1.409 + if (U_FAILURE(cacheStatus)) { 1.410 + *status = cacheStatus; 1.411 + free_entry(r); 1.412 + r = NULL; 1.413 + } 1.414 + } else { 1.415 + /* somebody have already inserted it while we were working, discard newly opened data */ 1.416 + /* Also, we could get here IF we opened an alias */ 1.417 + free_entry(r); 1.418 + r = oldR; 1.419 + } 1.420 + } 1.421 + 1.422 + } 1.423 + if(r != NULL) { 1.424 + /* return the real bundle */ 1.425 + while(r->fAlias != NULL) { 1.426 + r = r->fAlias; 1.427 + } 1.428 + r->fCountExisting++; /* we increase its reference count */ 1.429 + /* if the resource has a warning */ 1.430 + /* we don't want to overwrite a status with no error */ 1.431 + if(r->fBogus != U_ZERO_ERROR && U_SUCCESS(*status)) { 1.432 + *status = r->fBogus; /* set the returning status */ 1.433 + } 1.434 + } 1.435 + return r; 1.436 +} 1.437 + 1.438 +static UResourceDataEntry * 1.439 +getPoolEntry(const char *path, UErrorCode *status) { 1.440 + UResourceDataEntry *poolBundle = init_entry(kPoolBundleName, path, status); 1.441 + if( U_SUCCESS(*status) && 1.442 + (poolBundle == NULL || poolBundle->fBogus != U_ZERO_ERROR || !poolBundle->fData.isPoolBundle) 1.443 + ) { 1.444 + *status = U_INVALID_FORMAT_ERROR; 1.445 + } 1.446 + return poolBundle; 1.447 +} 1.448 + 1.449 +/* INTERNAL: */ 1.450 +/* CAUTION: resbMutex must be locked when calling this function! */ 1.451 +static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) { 1.452 + UResourceDataEntry *r = NULL; 1.453 + UBool hasRealData = FALSE; 1.454 + const char *defaultLoc = uloc_getDefault(); 1.455 + *hasChopped = TRUE; /* we're starting with a fresh name */ 1.456 + 1.457 + while(*hasChopped && !hasRealData) { 1.458 + r = init_entry(name, path, status); 1.459 + /* Null pointer test */ 1.460 + if (U_FAILURE(*status)) { 1.461 + return NULL; 1.462 + } 1.463 + *isDefault = (UBool)(uprv_strncmp(name, defaultLoc, uprv_strlen(name)) == 0); 1.464 + hasRealData = (UBool)(r->fBogus == U_ZERO_ERROR); 1.465 + if(!hasRealData) { 1.466 + /* this entry is not real. We will discard it. */ 1.467 + /* However, the parent line for this entry is */ 1.468 + /* not to be used - as there might be parent */ 1.469 + /* lines in cache from previous openings that */ 1.470 + /* are not updated yet. */ 1.471 + r->fCountExisting--; 1.472 + /*entryCloseInt(r);*/ 1.473 + r = NULL; 1.474 + *status = U_USING_FALLBACK_WARNING; 1.475 + } else { 1.476 + uprv_strcpy(name, r->fName); /* this is needed for supporting aliases */ 1.477 + } 1.478 + 1.479 + *isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName) == 0); 1.480 + 1.481 + /*Fallback data stuff*/ 1.482 + *hasChopped = chopLocale(name); 1.483 + } 1.484 + return r; 1.485 +} 1.486 + 1.487 +static void ures_setIsStackObject( UResourceBundle* resB, UBool state) { 1.488 + if(state) { 1.489 + resB->fMagic1 = 0; 1.490 + resB->fMagic2 = 0; 1.491 + } else { 1.492 + resB->fMagic1 = MAGIC1; 1.493 + resB->fMagic2 = MAGIC2; 1.494 + } 1.495 +} 1.496 + 1.497 +static UBool ures_isStackObject(const UResourceBundle* resB) { 1.498 + return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE); 1.499 +} 1.500 + 1.501 + 1.502 +U_CFUNC void ures_initStackObject(UResourceBundle* resB) { 1.503 + uprv_memset(resB, 0, sizeof(UResourceBundle)); 1.504 + ures_setIsStackObject(resB, TRUE); 1.505 +} 1.506 + 1.507 +static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UErrorCode* status) { 1.508 + UErrorCode intStatus = U_ZERO_ERROR; 1.509 + UErrorCode parentStatus = U_ZERO_ERROR; 1.510 + UErrorCode usrStatus = U_ZERO_ERROR; 1.511 + UResourceDataEntry *r = NULL; 1.512 + UResourceDataEntry *t1 = NULL; 1.513 + UResourceDataEntry *t2 = NULL; 1.514 + UResourceDataEntry *u1 = NULL; 1.515 + UResourceDataEntry *u2 = NULL; 1.516 + UBool isDefault = FALSE; 1.517 + UBool isRoot = FALSE; 1.518 + UBool hasRealData = FALSE; 1.519 + UBool hasChopped = TRUE; 1.520 + UBool usingUSRData = U_USE_USRDATA && ( path == NULL || uprv_strncmp(path,U_ICUDATA_NAME,8) == 0); 1.521 + 1.522 + char name[ULOC_FULLNAME_CAPACITY]; 1.523 + char usrDataPath[96]; 1.524 + 1.525 + initCache(status); 1.526 + 1.527 + if(U_FAILURE(*status)) { 1.528 + return NULL; 1.529 + } 1.530 + 1.531 + uprv_strncpy(name, localeID, sizeof(name) - 1); 1.532 + name[sizeof(name) - 1] = 0; 1.533 + 1.534 + if ( usingUSRData ) { 1.535 + if ( path == NULL ) { 1.536 + uprv_strcpy(usrDataPath, U_USRDATA_NAME); 1.537 + } else { 1.538 + uprv_strncpy(usrDataPath, path, sizeof(usrDataPath) - 1); 1.539 + usrDataPath[0] = 'u'; 1.540 + usrDataPath[1] = 's'; 1.541 + usrDataPath[2] = 'r'; 1.542 + usrDataPath[sizeof(usrDataPath) - 1] = 0; 1.543 + } 1.544 + } 1.545 + 1.546 + umtx_lock(&resbMutex); 1.547 + { /* umtx_lock */ 1.548 + /* We're going to skip all the locales that do not have any data */ 1.549 + r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus); 1.550 + 1.551 + if(r != NULL) { /* if there is one real locale, we can look for parents. */ 1.552 + t1 = r; 1.553 + hasRealData = TRUE; 1.554 + if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */ 1.555 + u1 = init_entry(t1->fName, usrDataPath, &usrStatus); 1.556 + if ( u1 != NULL ) { 1.557 + if(u1->fBogus == U_ZERO_ERROR) { 1.558 + u1->fParent = t1; 1.559 + r = u1; 1.560 + } else { 1.561 + /* the USR override data wasn't found, set it to be deleted */ 1.562 + u1->fCountExisting = 0; 1.563 + } 1.564 + } 1.565 + } 1.566 + while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.noFallback) { 1.567 + if ( res_getResource(&t1->fData,"%%Parent") != RES_BOGUS) { /* An explicit parent was found */ 1.568 + int32_t parentLocaleLen = 0; 1.569 + const UChar *parentLocaleName = res_getString(&(t1->fData), res_getResource(&t1->fData,"%%Parent") , &parentLocaleLen); 1.570 + if(parentLocaleName != NULL && parentLocaleLen > 0) { 1.571 + u_UCharsToChars(parentLocaleName, name, parentLocaleLen+1); 1.572 + if ( !uprv_strcmp(name,"root") ) { /* If parent is root, we just terminate the loop */ 1.573 + hasChopped = FALSE; 1.574 + continue; 1.575 + } 1.576 + } 1.577 + } 1.578 + /* insert regular parents */ 1.579 + t2 = init_entry(name, t1->fPath, &parentStatus); 1.580 + if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */ 1.581 + usrStatus = U_ZERO_ERROR; 1.582 + u2 = init_entry(name, usrDataPath, &usrStatus); 1.583 + } 1.584 + /* Check for null pointer. */ 1.585 + if (t2 == NULL || ( usingUSRData && u2 == NULL)) { 1.586 + *status = U_MEMORY_ALLOCATION_ERROR; 1.587 + goto finishUnlock; 1.588 + } 1.589 + 1.590 + if ( usingUSRData && u2->fBogus == U_ZERO_ERROR ) { 1.591 + t1->fParent = u2; 1.592 + u2->fParent = t2; 1.593 + } else { 1.594 + t1->fParent = t2; 1.595 + if(usingUSRData) { 1.596 + /* the USR override data wasn't found, set it to be deleted */ 1.597 + u2->fCountExisting = 0; 1.598 + } 1.599 + } 1.600 + t1 = t2; 1.601 + hasChopped = chopLocale(name); 1.602 + } 1.603 + } 1.604 + 1.605 + /* we could have reached this point without having any real data */ 1.606 + /* if that is the case, we need to chain in the default locale */ 1.607 + if(r==NULL && !isDefault && !isRoot /*&& t1->fParent == NULL*/) { 1.608 + /* insert default locale */ 1.609 + uprv_strcpy(name, uloc_getDefault()); 1.610 + r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus); 1.611 + intStatus = U_USING_DEFAULT_WARNING; 1.612 + if(r != NULL) { /* the default locale exists */ 1.613 + t1 = r; 1.614 + hasRealData = TRUE; 1.615 + isDefault = TRUE; 1.616 + while (hasChopped && t1->fParent == NULL) { 1.617 + if ( res_getResource(&t1->fData,"%%Parent") != RES_BOGUS) { /* An explicit parent was found */ 1.618 + int32_t parentLocaleLen = 0; 1.619 + const UChar *parentLocaleName = res_getString(&(t1->fData), res_getResource(&t1->fData,"%%Parent") , &parentLocaleLen); 1.620 + if(parentLocaleName != NULL && parentLocaleLen > 0) { 1.621 + u_UCharsToChars(parentLocaleName, name, parentLocaleLen+1); 1.622 + if ( !uprv_strcmp(name,"root") ) { /* If parent is root, we just terminate the loop */ 1.623 + hasChopped = FALSE; 1.624 + continue; 1.625 + } 1.626 + } 1.627 + } 1.628 + /* insert chopped defaults */ 1.629 + t2 = init_entry(name, t1->fPath, &parentStatus); 1.630 + /* Check for null pointer. */ 1.631 + if (t2 == NULL) { 1.632 + *status = U_MEMORY_ALLOCATION_ERROR; 1.633 + goto finishUnlock; 1.634 + } 1.635 + 1.636 + if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) { 1.637 + t1->fParent = t2; 1.638 + t1 = t2; 1.639 + } 1.640 + hasChopped = chopLocale(name); 1.641 + } 1.642 + } 1.643 + } 1.644 + 1.645 + /* we could still have r == NULL at this point - maybe even default locale is not */ 1.646 + /* present */ 1.647 + if(r == NULL) { 1.648 + uprv_strcpy(name, kRootLocaleName); 1.649 + r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus); 1.650 + if(r != NULL) { 1.651 + t1 = r; 1.652 + intStatus = U_USING_DEFAULT_WARNING; 1.653 + hasRealData = TRUE; 1.654 + } else { /* we don't even have the root locale */ 1.655 + *status = U_MISSING_RESOURCE_ERROR; 1.656 + goto finishUnlock; 1.657 + } 1.658 + } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL && !r->fData.noFallback) { 1.659 + /* insert root locale */ 1.660 + t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus); 1.661 + /* Check for null pointer. */ 1.662 + if (t2 == NULL) { 1.663 + *status = U_MEMORY_ALLOCATION_ERROR; 1.664 + goto finishUnlock; 1.665 + } 1.666 + if(!hasRealData) { 1.667 + r->fBogus = U_USING_DEFAULT_WARNING; 1.668 + } 1.669 + hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) || hasRealData); 1.670 + t1->fParent = t2; 1.671 + t1 = t2; 1.672 + } 1.673 + 1.674 + while(r != NULL && !isRoot && t1->fParent != NULL) { 1.675 + t1->fParent->fCountExisting++; 1.676 + t1 = t1->fParent; 1.677 + hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) || hasRealData); 1.678 + } 1.679 + } /* umtx_lock */ 1.680 +finishUnlock: 1.681 + umtx_unlock(&resbMutex); 1.682 + 1.683 + if(U_SUCCESS(*status)) { 1.684 + if(U_SUCCESS(parentStatus)) { 1.685 + if(intStatus != U_ZERO_ERROR) { 1.686 + *status = intStatus; 1.687 + } 1.688 + return r; 1.689 + } else { 1.690 + *status = parentStatus; 1.691 + return NULL; 1.692 + } 1.693 + } else { 1.694 + return NULL; 1.695 + } 1.696 +} 1.697 + 1.698 + 1.699 +/** 1.700 + * Functions to create and destroy resource bundles. 1.701 + * CAUTION: resbMutex must be locked when calling this function. 1.702 + */ 1.703 +/* INTERNAL: */ 1.704 +static void entryCloseInt(UResourceDataEntry *resB) { 1.705 + UResourceDataEntry *p = resB; 1.706 + 1.707 + while(resB != NULL) { 1.708 + p = resB->fParent; 1.709 + resB->fCountExisting--; 1.710 + 1.711 + /* Entries are left in the cache. TODO: add ures_flushCache() to force a flush 1.712 + of the cache. */ 1.713 +/* 1.714 + if(resB->fCountExisting <= 0) { 1.715 + uhash_remove(cache, resB); 1.716 + if(resB->fBogus == U_ZERO_ERROR) { 1.717 + res_unload(&(resB->fData)); 1.718 + } 1.719 + if(resB->fName != NULL) { 1.720 + uprv_free(resB->fName); 1.721 + } 1.722 + if(resB->fPath != NULL) { 1.723 + uprv_free(resB->fPath); 1.724 + } 1.725 + uprv_free(resB); 1.726 + } 1.727 +*/ 1.728 + 1.729 + resB = p; 1.730 + } 1.731 +} 1.732 + 1.733 +/** 1.734 + * API: closes a resource bundle and cleans up. 1.735 + */ 1.736 + 1.737 +static void entryClose(UResourceDataEntry *resB) { 1.738 + umtx_lock(&resbMutex); 1.739 + entryCloseInt(resB); 1.740 + umtx_unlock(&resbMutex); 1.741 +} 1.742 + 1.743 +/* 1.744 +U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) { 1.745 + if(resB->fResPath == NULL) { 1.746 + resB->fResPath = resB->fResBuf; 1.747 + *(resB->fResPath) = 0; 1.748 + } 1.749 + resB->fResPathLen = uprv_strlen(toAdd); 1.750 + if(RES_BUFSIZE <= resB->fResPathLen+1) { 1.751 + if(resB->fResPath == resB->fResBuf) { 1.752 + resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char)); 1.753 + } else { 1.754 + resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char)); 1.755 + } 1.756 + } 1.757 + uprv_strcpy(resB->fResPath, toAdd); 1.758 +} 1.759 +*/ 1.760 +static void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd, UErrorCode *status) { 1.761 + int32_t resPathLenOrig = resB->fResPathLen; 1.762 + if(resB->fResPath == NULL) { 1.763 + resB->fResPath = resB->fResBuf; 1.764 + *(resB->fResPath) = 0; 1.765 + resB->fResPathLen = 0; 1.766 + } 1.767 + resB->fResPathLen += lenToAdd; 1.768 + if(RES_BUFSIZE <= resB->fResPathLen+1) { 1.769 + if(resB->fResPath == resB->fResBuf) { 1.770 + resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char)); 1.771 + /* Check that memory was allocated correctly. */ 1.772 + if (resB->fResPath == NULL) { 1.773 + *status = U_MEMORY_ALLOCATION_ERROR; 1.774 + return; 1.775 + } 1.776 + uprv_strcpy(resB->fResPath, resB->fResBuf); 1.777 + } else { 1.778 + char *temp = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char)); 1.779 + /* Check that memory was reallocated correctly. */ 1.780 + if (temp == NULL) { 1.781 + *status = U_MEMORY_ALLOCATION_ERROR; 1.782 + return; 1.783 + } 1.784 + resB->fResPath = temp; 1.785 + } 1.786 + } 1.787 + uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd); 1.788 +} 1.789 + 1.790 +static void ures_freeResPath(UResourceBundle *resB) { 1.791 + if (resB->fResPath && resB->fResPath != resB->fResBuf) { 1.792 + uprv_free(resB->fResPath); 1.793 + } 1.794 + resB->fResPath = NULL; 1.795 + resB->fResPathLen = 0; 1.796 +} 1.797 + 1.798 +static void 1.799 +ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj) 1.800 +{ 1.801 + if(resB != NULL) { 1.802 + if(resB->fData != NULL) { 1.803 + entryClose(resB->fData); 1.804 + } 1.805 + if(resB->fVersion != NULL) { 1.806 + uprv_free(resB->fVersion); 1.807 + } 1.808 + ures_freeResPath(resB); 1.809 + 1.810 + if(ures_isStackObject(resB) == FALSE && freeBundleObj) { 1.811 + uprv_free(resB); 1.812 + } 1.813 +#if 0 /*U_DEBUG*/ 1.814 + else { 1.815 + /* poison the data */ 1.816 + uprv_memset(resB, -1, sizeof(UResourceBundle)); 1.817 + } 1.818 +#endif 1.819 + } 1.820 +} 1.821 + 1.822 +U_CAPI void U_EXPORT2 1.823 +ures_close(UResourceBundle* resB) 1.824 +{ 1.825 + ures_closeBundle(resB, TRUE); 1.826 +} 1.827 + 1.828 +static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r, 1.829 + const char *key, int32_t idx, UResourceDataEntry *realData, 1.830 + const UResourceBundle *parent, int32_t noAlias, 1.831 + UResourceBundle *resB, UErrorCode *status) 1.832 +{ 1.833 + if(status == NULL || U_FAILURE(*status)) { 1.834 + return resB; 1.835 + } 1.836 + if (parent == NULL) { 1.837 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.838 + return NULL; 1.839 + } 1.840 + if(RES_GET_TYPE(r) == URES_ALIAS) { /* This is an alias, need to exchange with real data */ 1.841 + if(noAlias < URES_MAX_ALIAS_LEVEL) { 1.842 + int32_t len = 0; 1.843 + const UChar *alias = res_getAlias(rdata, r, &len); 1.844 + if(len > 0) { 1.845 + /* we have an alias, now let's cut it up */ 1.846 + char stackAlias[200]; 1.847 + char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = NULL; 1.848 + int32_t capacity; 1.849 + 1.850 + /* 1.851 + * Allocate enough space for both the char * version 1.852 + * of the alias and parent->fResPath. 1.853 + * 1.854 + * We do this so that res_findResource() can modify the path, 1.855 + * which allows us to remove redundant _res_findResource() variants 1.856 + * in uresdata.c. 1.857 + * res_findResource() now NUL-terminates each segment so that table keys 1.858 + * can always be compared with strcmp() instead of strncmp(). 1.859 + * Saves code there and simplifies testing and code coverage. 1.860 + * 1.861 + * markus 2003oct17 1.862 + */ 1.863 + ++len; /* count the terminating NUL */ 1.864 + if(parent->fResPath != NULL) { 1.865 + capacity = (int32_t)uprv_strlen(parent->fResPath) + 1; 1.866 + } else { 1.867 + capacity = 0; 1.868 + } 1.869 + if(capacity < len) { 1.870 + capacity = len; 1.871 + } 1.872 + if(capacity <= (int32_t)sizeof(stackAlias)) { 1.873 + capacity = (int32_t)sizeof(stackAlias); 1.874 + chAlias = stackAlias; 1.875 + } else { 1.876 + chAlias = (char *)uprv_malloc(capacity); 1.877 + /* test for NULL */ 1.878 + if(chAlias == NULL) { 1.879 + *status = U_MEMORY_ALLOCATION_ERROR; 1.880 + return NULL; 1.881 + } 1.882 + } 1.883 + u_UCharsToChars(alias, chAlias, len); 1.884 + 1.885 + if(*chAlias == RES_PATH_SEPARATOR) { 1.886 + /* there is a path included */ 1.887 + locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR); 1.888 + if(locale == NULL) { 1.889 + locale = uprv_strchr(chAlias, 0); /* avoid locale == NULL to make code below work */ 1.890 + } else { 1.891 + *locale = 0; 1.892 + locale++; 1.893 + } 1.894 + path = chAlias+1; 1.895 + if(uprv_strcmp(path, "LOCALE") == 0) { 1.896 + /* this is an XPath alias, starting with "/LOCALE/" */ 1.897 + /* it contains the path to a resource which should be looked up */ 1.898 + /* starting in the requested locale */ 1.899 + keyPath = locale; 1.900 + locale = parent->fTopLevelData->fName; /* this is the requested locale's name */ 1.901 + path = realData->fPath; /* we will be looking in the same package */ 1.902 + } else { 1.903 + if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */ 1.904 + path = NULL; 1.905 + } 1.906 + keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR); 1.907 + if(keyPath) { 1.908 + *keyPath = 0; 1.909 + keyPath++; 1.910 + } 1.911 + } 1.912 + } else { 1.913 + /* no path, start with a locale */ 1.914 + locale = chAlias; 1.915 + keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR); 1.916 + if(keyPath) { 1.917 + *keyPath = 0; 1.918 + keyPath++; 1.919 + } 1.920 + path = realData->fPath; 1.921 + } 1.922 + 1.923 + 1.924 + { 1.925 + /* got almost everything, let's try to open */ 1.926 + /* first, open the bundle with real data */ 1.927 + UResourceBundle *result = resB; 1.928 + const char* temp = NULL; 1.929 + UErrorCode intStatus = U_ZERO_ERROR; 1.930 + UResourceBundle *mainRes = ures_openDirect(path, locale, &intStatus); 1.931 + if(U_SUCCESS(intStatus)) { 1.932 + if(keyPath == NULL) { 1.933 + /* no key path. This means that we are going to 1.934 + * to use the corresponding resource from 1.935 + * another bundle 1.936 + */ 1.937 + /* first, we are going to get a corresponding parent 1.938 + * resource to the one we are searching. 1.939 + */ 1.940 + char *aKey = parent->fResPath; 1.941 + if(aKey) { 1.942 + uprv_strcpy(chAlias, aKey); /* allocated large enough above */ 1.943 + aKey = chAlias; 1.944 + r = res_findResource(&(mainRes->fResData), mainRes->fRes, &aKey, &temp); 1.945 + } else { 1.946 + r = mainRes->fRes; 1.947 + } 1.948 + if(key) { 1.949 + /* we need to make keyPath from parent's fResPath and 1.950 + * current key, if there is a key associated 1.951 + */ 1.952 + len = (int32_t)(uprv_strlen(key) + 1); 1.953 + if(len > capacity) { 1.954 + capacity = len; 1.955 + if(chAlias == stackAlias) { 1.956 + chAlias = (char *)uprv_malloc(capacity); 1.957 + } else { 1.958 + chAlias = (char *)uprv_realloc(chAlias, capacity); 1.959 + } 1.960 + if(chAlias == NULL) { 1.961 + ures_close(mainRes); 1.962 + *status = U_MEMORY_ALLOCATION_ERROR; 1.963 + return NULL; 1.964 + } 1.965 + } 1.966 + uprv_memcpy(chAlias, key, len); 1.967 + aKey = chAlias; 1.968 + r = res_findResource(&(mainRes->fResData), r, &aKey, &temp); 1.969 + } else if(idx != -1) { 1.970 + /* if there is no key, but there is an index, try to get by the index */ 1.971 + /* here we have either a table or an array, so get the element */ 1.972 + int32_t type = RES_GET_TYPE(r); 1.973 + if(URES_IS_TABLE(type)) { 1.974 + r = res_getTableItemByIndex(&(mainRes->fResData), r, idx, (const char **)&aKey); 1.975 + } else { /* array */ 1.976 + r = res_getArrayItem(&(mainRes->fResData), r, idx); 1.977 + } 1.978 + } 1.979 + if(r != RES_BOGUS) { 1.980 + result = init_resb_result(&(mainRes->fResData), r, temp, -1, mainRes->fData, mainRes, noAlias+1, resB, status); 1.981 + } else { 1.982 + *status = U_MISSING_RESOURCE_ERROR; 1.983 + result = resB; 1.984 + } 1.985 + } else { 1.986 + /* this one is a bit trickier. 1.987 + * we start finding keys, but after we resolve one alias, the path might continue. 1.988 + * Consider: 1.989 + * aliastest:alias { "testtypes/anotheralias/Sequence" } 1.990 + * anotheralias:alias { "/ICUDATA/sh/CollationElements" } 1.991 + * aliastest resource should finally have the sequence, not collation elements. 1.992 + */ 1.993 + UResourceDataEntry *dataEntry = mainRes->fData; 1.994 + char stackPath[URES_MAX_BUFFER_SIZE]; 1.995 + char *pathBuf = stackPath, *myPath = pathBuf; 1.996 + if(uprv_strlen(keyPath) > URES_MAX_BUFFER_SIZE) { 1.997 + pathBuf = (char *)uprv_malloc((uprv_strlen(keyPath)+1)*sizeof(char)); 1.998 + if(pathBuf == NULL) { 1.999 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1000 + return NULL; 1.1001 + } 1.1002 + } 1.1003 + uprv_strcpy(pathBuf, keyPath); 1.1004 + result = mainRes; 1.1005 + /* now we have fallback following here */ 1.1006 + do { 1.1007 + r = dataEntry->fData.rootRes; 1.1008 + /* this loop handles 'found' resources over several levels */ 1.1009 + while(*myPath && U_SUCCESS(*status)) { 1.1010 + r = res_findResource(&(dataEntry->fData), r, &myPath, &temp); 1.1011 + if(r != RES_BOGUS) { /* found a resource, but it might be an indirection */ 1.1012 + resB = init_resb_result(&(dataEntry->fData), r, temp, -1, dataEntry, result, noAlias+1, resB, status); 1.1013 + result = resB; 1.1014 + if(result) { 1.1015 + r = result->fRes; /* switch to a new resource, possibly a new tree */ 1.1016 + dataEntry = result->fData; 1.1017 + } 1.1018 + } else { /* no resource found, we don't really want to look anymore on this level */ 1.1019 + break; 1.1020 + } 1.1021 + } 1.1022 + dataEntry = dataEntry->fParent; 1.1023 + uprv_strcpy(pathBuf, keyPath); 1.1024 + myPath = pathBuf; 1.1025 + } while(r == RES_BOGUS && dataEntry != NULL); 1.1026 + if(r == RES_BOGUS) { 1.1027 + *status = U_MISSING_RESOURCE_ERROR; 1.1028 + result = resB; 1.1029 + } 1.1030 + if(pathBuf != stackPath) { 1.1031 + uprv_free(pathBuf); 1.1032 + } 1.1033 + } 1.1034 + } else { /* we failed to open the resource we're aliasing to */ 1.1035 + *status = intStatus; 1.1036 + } 1.1037 + if(chAlias != stackAlias) { 1.1038 + uprv_free(chAlias); 1.1039 + } 1.1040 + if(mainRes != result) { 1.1041 + ures_close(mainRes); 1.1042 + } 1.1043 + return result; 1.1044 + } 1.1045 + } else { 1.1046 + /* bad alias, should be an error */ 1.1047 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1048 + return resB; 1.1049 + } 1.1050 + } else { 1.1051 + *status = U_TOO_MANY_ALIASES_ERROR; 1.1052 + return resB; 1.1053 + } 1.1054 + } 1.1055 + if(resB == NULL) { 1.1056 + resB = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); 1.1057 + /* test for NULL */ 1.1058 + if (resB == NULL) { 1.1059 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1060 + return NULL; 1.1061 + } 1.1062 + ures_setIsStackObject(resB, FALSE); 1.1063 + resB->fResPath = NULL; 1.1064 + resB->fResPathLen = 0; 1.1065 + } else { 1.1066 + if(resB->fData != NULL) { 1.1067 + entryClose(resB->fData); 1.1068 + } 1.1069 + if(resB->fVersion != NULL) { 1.1070 + uprv_free(resB->fVersion); 1.1071 + } 1.1072 + /* 1.1073 + weiv: if stack object was passed in, it doesn't really need to be reinited, 1.1074 + since the purpose of initing is to remove stack junk. However, at this point 1.1075 + we would not do anything to an allocated object, so stack object should be 1.1076 + treated the same 1.1077 + */ 1.1078 + /* 1.1079 + if(ures_isStackObject(resB) != FALSE) { 1.1080 + ures_initStackObject(resB); 1.1081 + } 1.1082 + */ 1.1083 + if(parent != resB) { 1.1084 + ures_freeResPath(resB); 1.1085 + } 1.1086 + } 1.1087 + resB->fData = realData; 1.1088 + entryIncrease(resB->fData); 1.1089 + resB->fHasFallback = FALSE; 1.1090 + resB->fIsTopLevel = FALSE; 1.1091 + resB->fIndex = -1; 1.1092 + resB->fKey = key; 1.1093 + /*resB->fParentRes = parent;*/ 1.1094 + resB->fTopLevelData = parent->fTopLevelData; 1.1095 + if(parent->fResPath && parent != resB) { 1.1096 + ures_appendResPath(resB, parent->fResPath, parent->fResPathLen, status); 1.1097 + } 1.1098 + if(key != NULL) { 1.1099 + ures_appendResPath(resB, key, (int32_t)uprv_strlen(key), status); 1.1100 + if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) { 1.1101 + ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status); 1.1102 + } 1.1103 + } else if(idx >= 0) { 1.1104 + char buf[256]; 1.1105 + int32_t len = T_CString_integerToString(buf, idx, 10); 1.1106 + ures_appendResPath(resB, buf, len, status); 1.1107 + if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) { 1.1108 + ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status); 1.1109 + } 1.1110 + } 1.1111 + /* Make sure that Purify doesn't complain about uninitialized memory copies. */ 1.1112 + { 1.1113 + int32_t usedLen = ((resB->fResBuf == resB->fResPath) ? resB->fResPathLen : 0); 1.1114 + uprv_memset(resB->fResBuf + usedLen, 0, sizeof(resB->fResBuf) - usedLen); 1.1115 + } 1.1116 + 1.1117 + resB->fVersion = NULL; 1.1118 + resB->fRes = r; 1.1119 + /*resB->fParent = parent->fRes;*/ 1.1120 + uprv_memmove(&resB->fResData, rdata, sizeof(ResourceData)); 1.1121 + resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes); 1.1122 + return resB; 1.1123 +} 1.1124 + 1.1125 +UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *original, UErrorCode *status) { 1.1126 + UBool isStackObject; 1.1127 + if(U_FAILURE(*status) || r == original) { 1.1128 + return r; 1.1129 + } 1.1130 + if(original != NULL) { 1.1131 + if(r == NULL) { 1.1132 + isStackObject = FALSE; 1.1133 + r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); 1.1134 + /* test for NULL */ 1.1135 + if (r == NULL) { 1.1136 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1137 + return NULL; 1.1138 + } 1.1139 + } else { 1.1140 + isStackObject = ures_isStackObject(r); 1.1141 + ures_closeBundle(r, FALSE); 1.1142 + } 1.1143 + uprv_memcpy(r, original, sizeof(UResourceBundle)); 1.1144 + r->fResPath = NULL; 1.1145 + r->fResPathLen = 0; 1.1146 + if(original->fResPath) { 1.1147 + ures_appendResPath(r, original->fResPath, original->fResPathLen, status); 1.1148 + } 1.1149 + ures_setIsStackObject(r, isStackObject); 1.1150 + if(r->fData != NULL) { 1.1151 + entryIncrease(r->fData); 1.1152 + } 1.1153 + } 1.1154 + return r; 1.1155 +} 1.1156 + 1.1157 +/** 1.1158 + * Functions to retrieve data from resource bundles. 1.1159 + */ 1.1160 + 1.1161 +U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_t* len, UErrorCode* status) { 1.1162 + const UChar *s; 1.1163 + if (status==NULL || U_FAILURE(*status)) { 1.1164 + return NULL; 1.1165 + } 1.1166 + if(resB == NULL) { 1.1167 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1168 + return NULL; 1.1169 + } 1.1170 + s = res_getString(&(resB->fResData), resB->fRes, len); 1.1171 + if (s == NULL) { 1.1172 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1173 + } 1.1174 + return s; 1.1175 +} 1.1176 + 1.1177 +static const char * 1.1178 +ures_toUTF8String(const UChar *s16, int32_t length16, 1.1179 + char *dest, int32_t *pLength, 1.1180 + UBool forceCopy, 1.1181 + UErrorCode *status) { 1.1182 + int32_t capacity; 1.1183 + 1.1184 + if (U_FAILURE(*status)) { 1.1185 + return NULL; 1.1186 + } 1.1187 + if (pLength != NULL) { 1.1188 + capacity = *pLength; 1.1189 + } else { 1.1190 + capacity = 0; 1.1191 + } 1.1192 + if (capacity < 0 || (capacity > 0 && dest == NULL)) { 1.1193 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1194 + return NULL; 1.1195 + } 1.1196 + 1.1197 + if (length16 == 0) { 1.1198 + /* empty string, return as read-only pointer */ 1.1199 + if (pLength != NULL) { 1.1200 + *pLength = 0; 1.1201 + } 1.1202 + if (forceCopy) { 1.1203 + u_terminateChars(dest, capacity, 0, status); 1.1204 + return dest; 1.1205 + } else { 1.1206 + return ""; 1.1207 + } 1.1208 + } else { 1.1209 + /* We need to transform the string to the destination buffer. */ 1.1210 + if (capacity < length16) { 1.1211 + /* No chance for the string to fit. Pure preflighting. */ 1.1212 + return u_strToUTF8(NULL, 0, pLength, s16, length16, status); 1.1213 + } 1.1214 + if (!forceCopy && (length16 <= 0x2aaaaaaa)) { 1.1215 + /* 1.1216 + * We know the string will fit into dest because each UChar turns 1.1217 + * into at most three UTF-8 bytes. Fill the latter part of dest 1.1218 + * so that callers do not expect to use dest as a string pointer, 1.1219 + * hopefully leading to more robust code for when resource bundles 1.1220 + * may store UTF-8 natively. 1.1221 + * (In which case dest would not be used at all.) 1.1222 + * 1.1223 + * We do not do this if forceCopy=TRUE because then the caller 1.1224 + * expects the string to start exactly at dest. 1.1225 + * 1.1226 + * The test above for <= 0x2aaaaaaa prevents overflows. 1.1227 + * The +1 is for the NUL terminator. 1.1228 + */ 1.1229 + int32_t maxLength = 3 * length16 + 1; 1.1230 + if (capacity > maxLength) { 1.1231 + dest += capacity - maxLength; 1.1232 + capacity = maxLength; 1.1233 + } 1.1234 + } 1.1235 + return u_strToUTF8(dest, capacity, pLength, s16, length16, status); 1.1236 + } 1.1237 +} 1.1238 + 1.1239 +U_CAPI const char * U_EXPORT2 1.1240 +ures_getUTF8String(const UResourceBundle *resB, 1.1241 + char *dest, int32_t *pLength, 1.1242 + UBool forceCopy, 1.1243 + UErrorCode *status) { 1.1244 + int32_t length16; 1.1245 + const UChar *s16 = ures_getString(resB, &length16, status); 1.1246 + return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status); 1.1247 +} 1.1248 + 1.1249 +U_CAPI const uint8_t* U_EXPORT2 ures_getBinary(const UResourceBundle* resB, int32_t* len, 1.1250 + UErrorCode* status) { 1.1251 + const uint8_t *p; 1.1252 + if (status==NULL || U_FAILURE(*status)) { 1.1253 + return NULL; 1.1254 + } 1.1255 + if(resB == NULL) { 1.1256 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1257 + return NULL; 1.1258 + } 1.1259 + p = res_getBinary(&(resB->fResData), resB->fRes, len); 1.1260 + if (p == NULL) { 1.1261 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1262 + } 1.1263 + return p; 1.1264 +} 1.1265 + 1.1266 +U_CAPI const int32_t* U_EXPORT2 ures_getIntVector(const UResourceBundle* resB, int32_t* len, 1.1267 + UErrorCode* status) { 1.1268 + const int32_t *p; 1.1269 + if (status==NULL || U_FAILURE(*status)) { 1.1270 + return NULL; 1.1271 + } 1.1272 + if(resB == NULL) { 1.1273 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1274 + return NULL; 1.1275 + } 1.1276 + p = res_getIntVector(&(resB->fResData), resB->fRes, len); 1.1277 + if (p == NULL) { 1.1278 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1279 + } 1.1280 + return p; 1.1281 +} 1.1282 + 1.1283 +/* this function returns a signed integer */ 1.1284 +/* it performs sign extension */ 1.1285 +U_CAPI int32_t U_EXPORT2 ures_getInt(const UResourceBundle* resB, UErrorCode *status) { 1.1286 + if (status==NULL || U_FAILURE(*status)) { 1.1287 + return 0xffffffff; 1.1288 + } 1.1289 + if(resB == NULL) { 1.1290 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1291 + return 0xffffffff; 1.1292 + } 1.1293 + if(RES_GET_TYPE(resB->fRes) != URES_INT) { 1.1294 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1295 + return 0xffffffff; 1.1296 + } 1.1297 + return RES_GET_INT(resB->fRes); 1.1298 +} 1.1299 + 1.1300 +U_CAPI uint32_t U_EXPORT2 ures_getUInt(const UResourceBundle* resB, UErrorCode *status) { 1.1301 + if (status==NULL || U_FAILURE(*status)) { 1.1302 + return 0xffffffff; 1.1303 + } 1.1304 + if(resB == NULL) { 1.1305 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1306 + return 0xffffffff; 1.1307 + } 1.1308 + if(RES_GET_TYPE(resB->fRes) != URES_INT) { 1.1309 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1310 + return 0xffffffff; 1.1311 + } 1.1312 + return RES_GET_UINT(resB->fRes); 1.1313 +} 1.1314 + 1.1315 +U_CAPI UResType U_EXPORT2 ures_getType(const UResourceBundle *resB) { 1.1316 + if(resB == NULL) { 1.1317 + return URES_NONE; 1.1318 + } 1.1319 + return res_getPublicType(resB->fRes); 1.1320 +} 1.1321 + 1.1322 +U_CAPI const char * U_EXPORT2 ures_getKey(const UResourceBundle *resB) { 1.1323 + if(resB == NULL) { 1.1324 + return NULL; 1.1325 + } 1.1326 + 1.1327 + return(resB->fKey); 1.1328 +} 1.1329 + 1.1330 +U_CAPI int32_t U_EXPORT2 ures_getSize(const UResourceBundle *resB) { 1.1331 + if(resB == NULL) { 1.1332 + return 0; 1.1333 + } 1.1334 + 1.1335 + return resB->fSize; 1.1336 +} 1.1337 + 1.1338 +static const UChar* ures_getStringWithAlias(const UResourceBundle *resB, Resource r, int32_t sIndex, int32_t *len, UErrorCode *status) { 1.1339 + if(RES_GET_TYPE(r) == URES_ALIAS) { 1.1340 + const UChar* result = 0; 1.1341 + UResourceBundle *tempRes = ures_getByIndex(resB, sIndex, NULL, status); 1.1342 + result = ures_getString(tempRes, len, status); 1.1343 + ures_close(tempRes); 1.1344 + return result; 1.1345 + } else { 1.1346 + return res_getString(&(resB->fResData), r, len); 1.1347 + } 1.1348 +} 1.1349 + 1.1350 +U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resB){ 1.1351 + if(resB == NULL) { 1.1352 + return; 1.1353 + } 1.1354 + resB->fIndex = -1; 1.1355 +} 1.1356 + 1.1357 +U_CAPI UBool U_EXPORT2 ures_hasNext(const UResourceBundle *resB) { 1.1358 + if(resB == NULL) { 1.1359 + return FALSE; 1.1360 + } 1.1361 + return (UBool)(resB->fIndex < resB->fSize-1); 1.1362 +} 1.1363 + 1.1364 +U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resB, int32_t* len, const char ** key, UErrorCode *status) { 1.1365 + Resource r = RES_BOGUS; 1.1366 + 1.1367 + if (status==NULL || U_FAILURE(*status)) { 1.1368 + return NULL; 1.1369 + } 1.1370 + if(resB == NULL) { 1.1371 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1372 + return NULL; 1.1373 + } 1.1374 + 1.1375 + if(resB->fIndex == resB->fSize-1) { 1.1376 + *status = U_INDEX_OUTOFBOUNDS_ERROR; 1.1377 + } else { 1.1378 + resB->fIndex++; 1.1379 + switch(RES_GET_TYPE(resB->fRes)) { 1.1380 + case URES_STRING: 1.1381 + case URES_STRING_V2: 1.1382 + return res_getString(&(resB->fResData), resB->fRes, len); 1.1383 + case URES_TABLE: 1.1384 + case URES_TABLE16: 1.1385 + case URES_TABLE32: 1.1386 + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, key); 1.1387 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1388 + /* TODO: do the fallback */ 1.1389 + } 1.1390 + return ures_getStringWithAlias(resB, r, resB->fIndex, len, status); 1.1391 + case URES_ARRAY: 1.1392 + case URES_ARRAY16: 1.1393 + r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex); 1.1394 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1395 + /* TODO: do the fallback */ 1.1396 + } 1.1397 + return ures_getStringWithAlias(resB, r, resB->fIndex, len, status); 1.1398 + case URES_ALIAS: 1.1399 + return ures_getStringWithAlias(resB, resB->fRes, resB->fIndex, len, status); 1.1400 + case URES_INT: 1.1401 + case URES_BINARY: 1.1402 + case URES_INT_VECTOR: 1.1403 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1404 + default: /*fall through*/ 1.1405 + return NULL; 1.1406 + } 1.1407 + } 1.1408 + 1.1409 + return NULL; 1.1410 +} 1.1411 + 1.1412 +U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resB, UResourceBundle *fillIn, UErrorCode *status) { 1.1413 + const char *key = NULL; 1.1414 + Resource r = RES_BOGUS; 1.1415 + 1.1416 + if (status==NULL || U_FAILURE(*status)) { 1.1417 + /*return NULL;*/ 1.1418 + return fillIn; 1.1419 + } 1.1420 + if(resB == NULL) { 1.1421 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1422 + /*return NULL;*/ 1.1423 + return fillIn; 1.1424 + } 1.1425 + 1.1426 + if(resB->fIndex == resB->fSize-1) { 1.1427 + *status = U_INDEX_OUTOFBOUNDS_ERROR; 1.1428 + /*return NULL;*/ 1.1429 + } else { 1.1430 + resB->fIndex++; 1.1431 + switch(RES_GET_TYPE(resB->fRes)) { 1.1432 + case URES_INT: 1.1433 + case URES_BINARY: 1.1434 + case URES_STRING: 1.1435 + case URES_STRING_V2: 1.1436 + case URES_INT_VECTOR: 1.1437 + return ures_copyResb(fillIn, resB, status); 1.1438 + case URES_TABLE: 1.1439 + case URES_TABLE16: 1.1440 + case URES_TABLE32: 1.1441 + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, &key); 1.1442 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1443 + /* TODO: do the fallback */ 1.1444 + } 1.1445 + return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status); 1.1446 + case URES_ARRAY: 1.1447 + case URES_ARRAY16: 1.1448 + r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex); 1.1449 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1450 + /* TODO: do the fallback */ 1.1451 + } 1.1452 + return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status); 1.1453 + default: 1.1454 + /*return NULL;*/ 1.1455 + return fillIn; 1.1456 + } 1.1457 + } 1.1458 + /*return NULL;*/ 1.1459 + return fillIn; 1.1460 +} 1.1461 + 1.1462 +U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resB, int32_t indexR, UResourceBundle *fillIn, UErrorCode *status) { 1.1463 + const char* key = NULL; 1.1464 + Resource r = RES_BOGUS; 1.1465 + 1.1466 + if (status==NULL || U_FAILURE(*status)) { 1.1467 + /*return NULL;*/ 1.1468 + return fillIn; 1.1469 + } 1.1470 + if(resB == NULL) { 1.1471 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1472 + /*return NULL;*/ 1.1473 + return fillIn; 1.1474 + } 1.1475 + 1.1476 + if(indexR >= 0 && resB->fSize > indexR) { 1.1477 + switch(RES_GET_TYPE(resB->fRes)) { 1.1478 + case URES_INT: 1.1479 + case URES_BINARY: 1.1480 + case URES_STRING: 1.1481 + case URES_STRING_V2: 1.1482 + case URES_INT_VECTOR: 1.1483 + return ures_copyResb(fillIn, resB, status); 1.1484 + case URES_TABLE: 1.1485 + case URES_TABLE16: 1.1486 + case URES_TABLE32: 1.1487 + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexR, &key); 1.1488 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1489 + /* TODO: do the fallback */ 1.1490 + } 1.1491 + return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status); 1.1492 + case URES_ARRAY: 1.1493 + case URES_ARRAY16: 1.1494 + r = res_getArrayItem(&(resB->fResData), resB->fRes, indexR); 1.1495 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1496 + /* TODO: do the fallback */ 1.1497 + } 1.1498 + return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status); 1.1499 + default: 1.1500 + /*return NULL;*/ 1.1501 + return fillIn; 1.1502 + } 1.1503 + } else { 1.1504 + *status = U_MISSING_RESOURCE_ERROR; 1.1505 + } 1.1506 + /*return NULL;*/ 1.1507 + return fillIn; 1.1508 +} 1.1509 + 1.1510 +U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status) { 1.1511 + const char* key = NULL; 1.1512 + Resource r = RES_BOGUS; 1.1513 + 1.1514 + if (status==NULL || U_FAILURE(*status)) { 1.1515 + return NULL; 1.1516 + } 1.1517 + if(resB == NULL) { 1.1518 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1519 + return NULL; 1.1520 + } 1.1521 + 1.1522 + if(indexS >= 0 && resB->fSize > indexS) { 1.1523 + switch(RES_GET_TYPE(resB->fRes)) { 1.1524 + case URES_STRING: 1.1525 + case URES_STRING_V2: 1.1526 + return res_getString(&(resB->fResData), resB->fRes, len); 1.1527 + case URES_TABLE: 1.1528 + case URES_TABLE16: 1.1529 + case URES_TABLE32: 1.1530 + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexS, &key); 1.1531 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1532 + /* TODO: do the fallback */ 1.1533 + } 1.1534 + return ures_getStringWithAlias(resB, r, indexS, len, status); 1.1535 + case URES_ARRAY: 1.1536 + case URES_ARRAY16: 1.1537 + r = res_getArrayItem(&(resB->fResData), resB->fRes, indexS); 1.1538 + if(r == RES_BOGUS && resB->fHasFallback) { 1.1539 + /* TODO: do the fallback */ 1.1540 + } 1.1541 + return ures_getStringWithAlias(resB, r, indexS, len, status); 1.1542 + case URES_ALIAS: 1.1543 + return ures_getStringWithAlias(resB, resB->fRes, indexS, len, status); 1.1544 + case URES_INT: 1.1545 + case URES_BINARY: 1.1546 + case URES_INT_VECTOR: 1.1547 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1548 + break; 1.1549 + default: 1.1550 + /* must not occur */ 1.1551 + *status = U_INTERNAL_PROGRAM_ERROR; 1.1552 + break; 1.1553 + } 1.1554 + } else { 1.1555 + *status = U_MISSING_RESOURCE_ERROR; 1.1556 + } 1.1557 + return NULL; 1.1558 +} 1.1559 + 1.1560 +U_CAPI const char * U_EXPORT2 1.1561 +ures_getUTF8StringByIndex(const UResourceBundle *resB, 1.1562 + int32_t idx, 1.1563 + char *dest, int32_t *pLength, 1.1564 + UBool forceCopy, 1.1565 + UErrorCode *status) { 1.1566 + int32_t length16; 1.1567 + const UChar *s16 = ures_getStringByIndex(resB, idx, &length16, status); 1.1568 + return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status); 1.1569 +} 1.1570 + 1.1571 +/*U_CAPI const char *ures_getResPath(UResourceBundle *resB) { 1.1572 + return resB->fResPath; 1.1573 +}*/ 1.1574 + 1.1575 +U_CAPI UResourceBundle* U_EXPORT2 1.1576 +ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status) 1.1577 +{ 1.1578 + UResourceBundle *first = NULL; 1.1579 + UResourceBundle *result = fillIn; 1.1580 + char *packageName = NULL; 1.1581 + char *pathToResource = NULL, *save = NULL; 1.1582 + char *locale = NULL, *localeEnd = NULL; 1.1583 + int32_t length; 1.1584 + 1.1585 + if(status == NULL || U_FAILURE(*status)) { 1.1586 + return result; 1.1587 + } 1.1588 + 1.1589 + length = (int32_t)(uprv_strlen(path)+1); 1.1590 + save = pathToResource = (char *)uprv_malloc(length*sizeof(char)); 1.1591 + /* test for NULL */ 1.1592 + if(pathToResource == NULL) { 1.1593 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1594 + return result; 1.1595 + } 1.1596 + uprv_memcpy(pathToResource, path, length); 1.1597 + 1.1598 + locale = pathToResource; 1.1599 + if(*pathToResource == RES_PATH_SEPARATOR) { /* there is a path specification */ 1.1600 + pathToResource++; 1.1601 + packageName = pathToResource; 1.1602 + pathToResource = uprv_strchr(pathToResource, RES_PATH_SEPARATOR); 1.1603 + if(pathToResource == NULL) { 1.1604 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1605 + } else { 1.1606 + *pathToResource = 0; 1.1607 + locale = pathToResource+1; 1.1608 + } 1.1609 + } 1.1610 + 1.1611 + localeEnd = uprv_strchr(locale, RES_PATH_SEPARATOR); 1.1612 + if(localeEnd != NULL) { 1.1613 + *localeEnd = 0; 1.1614 + } 1.1615 + 1.1616 + first = ures_open(packageName, locale, status); 1.1617 + 1.1618 + if(U_SUCCESS(*status)) { 1.1619 + if(localeEnd) { 1.1620 + result = ures_findSubResource(first, localeEnd+1, fillIn, status); 1.1621 + } else { 1.1622 + result = ures_copyResb(fillIn, first, status); 1.1623 + } 1.1624 + ures_close(first); 1.1625 + } 1.1626 + uprv_free(save); 1.1627 + return result; 1.1628 +} 1.1629 + 1.1630 +U_CAPI UResourceBundle* U_EXPORT2 1.1631 +ures_findSubResource(const UResourceBundle *resB, char* path, UResourceBundle *fillIn, UErrorCode *status) 1.1632 +{ 1.1633 + Resource res = RES_BOGUS; 1.1634 + UResourceBundle *result = fillIn; 1.1635 + const char *key; 1.1636 + 1.1637 + if(status == NULL || U_FAILURE(*status)) { 1.1638 + return result; 1.1639 + } 1.1640 + 1.1641 + /* here we do looping and circular alias checking */ 1.1642 + /* this loop is here because aliasing is resolved on this level, not on res level */ 1.1643 + /* so, when we encounter an alias, it is not an aggregate resource, so we return */ 1.1644 + do { 1.1645 + res = res_findResource(&(resB->fResData), resB->fRes, &path, &key); 1.1646 + if(res != RES_BOGUS) { 1.1647 + result = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status); 1.1648 + resB = result; 1.1649 + } else { 1.1650 + *status = U_MISSING_RESOURCE_ERROR; 1.1651 + break; 1.1652 + } 1.1653 + } while(*path); /* there is more stuff in the path */ 1.1654 + 1.1655 + return result; 1.1656 +} 1.1657 +U_INTERNAL const UChar* U_EXPORT2 1.1658 +ures_getStringByKeyWithFallback(const UResourceBundle *resB, 1.1659 + const char* inKey, 1.1660 + int32_t* len, 1.1661 + UErrorCode *status) { 1.1662 + 1.1663 + UResourceBundle stack; 1.1664 + const UChar* retVal = NULL; 1.1665 + ures_initStackObject(&stack); 1.1666 + ures_getByKeyWithFallback(resB, inKey, &stack, status); 1.1667 + int32_t length; 1.1668 + retVal = ures_getString(&stack, &length, status); 1.1669 + ures_close(&stack); 1.1670 + if (U_FAILURE(*status)) { 1.1671 + return NULL; 1.1672 + } 1.1673 + if (length == 3 && retVal[0] == EMPTY_SET && retVal[1] == EMPTY_SET && retVal[2] == EMPTY_SET ) { 1.1674 + retVal = NULL; 1.1675 + length = 0; 1.1676 + *status = U_MISSING_RESOURCE_ERROR; 1.1677 + } 1.1678 + if (len != NULL) { 1.1679 + *len = length; 1.1680 + } 1.1681 + return retVal; 1.1682 +} 1.1683 + 1.1684 +/* 1.1685 + Like res_getTableItemByKey but accepts full paths like "NumberElements/latn/patternsShort". 1.1686 +*/ 1.1687 +static Resource getTableItemByKeyPath(const ResourceData *pResData, Resource table, const char *key) { 1.1688 + Resource resource = table; /* The current resource */ 1.1689 + icu::CharString path; 1.1690 + UErrorCode errorCode = U_ZERO_ERROR; 1.1691 + path.append(key, errorCode); 1.1692 + if (U_FAILURE(errorCode)) { return RES_BOGUS; } 1.1693 + char *pathPart = path.data(); /* Path from current resource to desired resource */ 1.1694 + UResType type = (UResType)RES_GET_TYPE(resource); /* the current resource type */ 1.1695 + while (*pathPart && resource != RES_BOGUS && URES_IS_CONTAINER(type)) { 1.1696 + char *nextPathPart = uprv_strchr(pathPart, RES_PATH_SEPARATOR); 1.1697 + if (nextPathPart != NULL) { 1.1698 + *nextPathPart = 0; /* Terminating null for this part of path. */ 1.1699 + nextPathPart++; 1.1700 + } else { 1.1701 + nextPathPart = uprv_strchr(pathPart, 0); 1.1702 + } 1.1703 + int32_t t; 1.1704 + const char *pathP = pathPart; 1.1705 + resource = res_getTableItemByKey(pResData, resource, &t, &pathP); 1.1706 + type = (UResType)RES_GET_TYPE(resource); 1.1707 + pathPart = nextPathPart; 1.1708 + } 1.1709 + if (*pathPart) { 1.1710 + return RES_BOGUS; 1.1711 + } 1.1712 + return resource; 1.1713 +} 1.1714 + 1.1715 +U_CAPI UResourceBundle* U_EXPORT2 1.1716 +ures_getByKeyWithFallback(const UResourceBundle *resB, 1.1717 + const char* inKey, 1.1718 + UResourceBundle *fillIn, 1.1719 + UErrorCode *status) { 1.1720 + Resource res = RES_BOGUS, rootRes = RES_BOGUS; 1.1721 + /*UResourceDataEntry *realData = NULL;*/ 1.1722 + UResourceBundle *helper = NULL; 1.1723 + 1.1724 + if (status==NULL || U_FAILURE(*status)) { 1.1725 + return fillIn; 1.1726 + } 1.1727 + if(resB == NULL) { 1.1728 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1729 + return fillIn; 1.1730 + } 1.1731 + 1.1732 + int32_t type = RES_GET_TYPE(resB->fRes); 1.1733 + if(URES_IS_TABLE(type)) { 1.1734 + res = getTableItemByKeyPath(&(resB->fResData), resB->fRes, inKey); 1.1735 + const char* key = inKey; 1.1736 + if(res == RES_BOGUS) { 1.1737 + UResourceDataEntry *dataEntry = resB->fData; 1.1738 + char path[256]; 1.1739 + char* myPath = path; 1.1740 + const char* resPath = resB->fResPath; 1.1741 + int32_t len = resB->fResPathLen; 1.1742 + while(res == RES_BOGUS && dataEntry->fParent != NULL) { /* Otherwise, we'll look in parents */ 1.1743 + dataEntry = dataEntry->fParent; 1.1744 + rootRes = dataEntry->fData.rootRes; 1.1745 + 1.1746 + if(dataEntry->fBogus == U_ZERO_ERROR) { 1.1747 + if (len > 0) { 1.1748 + uprv_memcpy(path, resPath, len); 1.1749 + } 1.1750 + uprv_strcpy(path+len, inKey); 1.1751 + myPath = path; 1.1752 + key = inKey; 1.1753 + do { 1.1754 + res = res_findResource(&(dataEntry->fData), rootRes, &myPath, &key); 1.1755 + if (RES_GET_TYPE(res) == URES_ALIAS && *myPath) { 1.1756 + /* We hit an alias, but we didn't finish following the path. */ 1.1757 + helper = init_resb_result(&(dataEntry->fData), res, NULL, -1, dataEntry, resB, 0, helper, status); 1.1758 + /*helper = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, helper, status);*/ 1.1759 + if(helper) { 1.1760 + dataEntry = helper->fData; 1.1761 + rootRes = helper->fRes; 1.1762 + resPath = helper->fResPath; 1.1763 + len = helper->fResPathLen; 1.1764 + 1.1765 + } else { 1.1766 + break; 1.1767 + } 1.1768 + } 1.1769 + } while(*myPath); /* Continue until the whole path is consumed */ 1.1770 + } 1.1771 + } 1.1772 + /*const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);*/ 1.1773 + if(res != RES_BOGUS) { 1.1774 + /* check if resB->fResPath gives the right name here */ 1.1775 + if(uprv_strcmp(dataEntry->fName, uloc_getDefault())==0 || uprv_strcmp(dataEntry->fName, kRootLocaleName)==0) { 1.1776 + *status = U_USING_DEFAULT_WARNING; 1.1777 + } else { 1.1778 + *status = U_USING_FALLBACK_WARNING; 1.1779 + } 1.1780 + 1.1781 + fillIn = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, fillIn, status); 1.1782 + } else { 1.1783 + *status = U_MISSING_RESOURCE_ERROR; 1.1784 + } 1.1785 + } else { 1.1786 + fillIn = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status); 1.1787 + } 1.1788 + } 1.1789 + else { 1.1790 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1791 + } 1.1792 + ures_close(helper); 1.1793 + return fillIn; 1.1794 +} 1.1795 + 1.1796 + 1.1797 +U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) { 1.1798 + Resource res = RES_BOGUS; 1.1799 + UResourceDataEntry *realData = NULL; 1.1800 + const char *key = inKey; 1.1801 + 1.1802 + if (status==NULL || U_FAILURE(*status)) { 1.1803 + return fillIn; 1.1804 + } 1.1805 + if(resB == NULL) { 1.1806 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1807 + return fillIn; 1.1808 + } 1.1809 + 1.1810 + int32_t type = RES_GET_TYPE(resB->fRes); 1.1811 + if(URES_IS_TABLE(type)) { 1.1812 + int32_t t; 1.1813 + res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key); 1.1814 + if(res == RES_BOGUS) { 1.1815 + key = inKey; 1.1816 + if(resB->fHasFallback == TRUE) { 1.1817 + const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status); 1.1818 + if(U_SUCCESS(*status)) { 1.1819 + /* check if resB->fResPath gives the right name here */ 1.1820 + return init_resb_result(rd, res, key, -1, realData, resB, 0, fillIn, status); 1.1821 + } else { 1.1822 + *status = U_MISSING_RESOURCE_ERROR; 1.1823 + } 1.1824 + } else { 1.1825 + *status = U_MISSING_RESOURCE_ERROR; 1.1826 + } 1.1827 + } else { 1.1828 + return init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status); 1.1829 + } 1.1830 + } 1.1831 +#if 0 1.1832 + /* this is a kind of TODO item. If we have an array with an index table, we could do this. */ 1.1833 + /* not currently */ 1.1834 + else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE) { 1.1835 + /* here should go a first attempt to locate the key using index table */ 1.1836 + const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status); 1.1837 + if(U_SUCCESS(*status)) { 1.1838 + return init_resb_result(rd, res, key, realData, resB, fillIn, status); 1.1839 + } else { 1.1840 + *status = U_MISSING_RESOURCE_ERROR; 1.1841 + } 1.1842 + } 1.1843 +#endif 1.1844 + else { 1.1845 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1846 + } 1.1847 + return fillIn; 1.1848 +} 1.1849 + 1.1850 +U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, const char* inKey, int32_t* len, UErrorCode *status) { 1.1851 + Resource res = RES_BOGUS; 1.1852 + UResourceDataEntry *realData = NULL; 1.1853 + const char* key = inKey; 1.1854 + 1.1855 + if (status==NULL || U_FAILURE(*status)) { 1.1856 + return NULL; 1.1857 + } 1.1858 + if(resB == NULL) { 1.1859 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1860 + return NULL; 1.1861 + } 1.1862 + 1.1863 + int32_t type = RES_GET_TYPE(resB->fRes); 1.1864 + if(URES_IS_TABLE(type)) { 1.1865 + int32_t t=0; 1.1866 + 1.1867 + res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key); 1.1868 + 1.1869 + if(res == RES_BOGUS) { 1.1870 + key = inKey; 1.1871 + if(resB->fHasFallback == TRUE) { 1.1872 + const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status); 1.1873 + if(U_SUCCESS(*status)) { 1.1874 + switch (RES_GET_TYPE(res)) { 1.1875 + case URES_STRING: 1.1876 + case URES_STRING_V2: 1.1877 + return res_getString(rd, res, len); 1.1878 + case URES_ALIAS: 1.1879 + { 1.1880 + const UChar* result = 0; 1.1881 + UResourceBundle *tempRes = ures_getByKey(resB, inKey, NULL, status); 1.1882 + result = ures_getString(tempRes, len, status); 1.1883 + ures_close(tempRes); 1.1884 + return result; 1.1885 + } 1.1886 + default: 1.1887 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1888 + } 1.1889 + } else { 1.1890 + *status = U_MISSING_RESOURCE_ERROR; 1.1891 + } 1.1892 + } else { 1.1893 + *status = U_MISSING_RESOURCE_ERROR; 1.1894 + } 1.1895 + } else { 1.1896 + switch (RES_GET_TYPE(res)) { 1.1897 + case URES_STRING: 1.1898 + case URES_STRING_V2: 1.1899 + return res_getString(&(resB->fResData), res, len); 1.1900 + case URES_ALIAS: 1.1901 + { 1.1902 + const UChar* result = 0; 1.1903 + UResourceBundle *tempRes = ures_getByKey(resB, inKey, NULL, status); 1.1904 + result = ures_getString(tempRes, len, status); 1.1905 + ures_close(tempRes); 1.1906 + return result; 1.1907 + } 1.1908 + default: 1.1909 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1910 + } 1.1911 + } 1.1912 + } 1.1913 +#if 0 1.1914 + /* this is a kind of TODO item. If we have an array with an index table, we could do this. */ 1.1915 + /* not currently */ 1.1916 + else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE) { 1.1917 + /* here should go a first attempt to locate the key using index table */ 1.1918 + const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status); 1.1919 + if(U_SUCCESS(*status)) { 1.1920 + return res_getString(rd, res, len); 1.1921 + } else { 1.1922 + *status = U_MISSING_RESOURCE_ERROR; 1.1923 + } 1.1924 + } 1.1925 +#endif 1.1926 + else { 1.1927 + *status = U_RESOURCE_TYPE_MISMATCH; 1.1928 + } 1.1929 + return NULL; 1.1930 +} 1.1931 + 1.1932 +U_CAPI const char * U_EXPORT2 1.1933 +ures_getUTF8StringByKey(const UResourceBundle *resB, 1.1934 + const char *key, 1.1935 + char *dest, int32_t *pLength, 1.1936 + UBool forceCopy, 1.1937 + UErrorCode *status) { 1.1938 + int32_t length16; 1.1939 + const UChar *s16 = ures_getStringByKey(resB, key, &length16, status); 1.1940 + return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status); 1.1941 +} 1.1942 + 1.1943 +/* TODO: clean from here down */ 1.1944 + 1.1945 +/** 1.1946 + * INTERNAL: Get the name of the first real locale (not placeholder) 1.1947 + * that has resource bundle data. 1.1948 + */ 1.1949 +U_INTERNAL const char* U_EXPORT2 1.1950 +ures_getLocaleInternal(const UResourceBundle* resourceBundle, UErrorCode* status) 1.1951 +{ 1.1952 + if (status==NULL || U_FAILURE(*status)) { 1.1953 + return NULL; 1.1954 + } 1.1955 + if (!resourceBundle) { 1.1956 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1957 + return NULL; 1.1958 + } else { 1.1959 + return resourceBundle->fData->fName; 1.1960 + } 1.1961 +} 1.1962 + 1.1963 +U_CAPI const char* U_EXPORT2 1.1964 +ures_getLocale(const UResourceBundle* resourceBundle, 1.1965 + UErrorCode* status) 1.1966 +{ 1.1967 + return ures_getLocaleInternal(resourceBundle, status); 1.1968 +} 1.1969 + 1.1970 + 1.1971 +U_CAPI const char* U_EXPORT2 1.1972 +ures_getLocaleByType(const UResourceBundle* resourceBundle, 1.1973 + ULocDataLocaleType type, 1.1974 + UErrorCode* status) { 1.1975 + if (status==NULL || U_FAILURE(*status)) { 1.1976 + return NULL; 1.1977 + } 1.1978 + if (!resourceBundle) { 1.1979 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1980 + return NULL; 1.1981 + } else { 1.1982 + switch(type) { 1.1983 + case ULOC_ACTUAL_LOCALE: 1.1984 + return resourceBundle->fData->fName; 1.1985 + case ULOC_VALID_LOCALE: 1.1986 + return resourceBundle->fTopLevelData->fName; 1.1987 + case ULOC_REQUESTED_LOCALE: 1.1988 + return NULL; 1.1989 + default: 1.1990 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1991 + return NULL; 1.1992 + } 1.1993 + } 1.1994 +} 1.1995 + 1.1996 +U_CFUNC const char* ures_getName(const UResourceBundle* resB) { 1.1997 + if(resB == NULL) { 1.1998 + return NULL; 1.1999 + } 1.2000 + 1.2001 + return resB->fData->fName; 1.2002 +} 1.2003 + 1.2004 +#ifdef URES_DEBUG 1.2005 +U_CFUNC const char* ures_getPath(const UResourceBundle* resB) { 1.2006 + if(resB == NULL) { 1.2007 + return NULL; 1.2008 + } 1.2009 + 1.2010 + return resB->fData->fPath; 1.2011 +} 1.2012 +#endif 1.2013 + 1.2014 +/* OLD API implementation */ 1.2015 + 1.2016 +/** 1.2017 + * API: This function is used to open a resource bundle 1.2018 + * proper fallback chaining is executed while initialization. 1.2019 + * The result is stored in cache for later fallback search. 1.2020 + */ 1.2021 +U_CAPI void U_EXPORT2 1.2022 +ures_openFillIn(UResourceBundle *r, const char* path, 1.2023 + const char* localeID, UErrorCode* status) { 1.2024 + if(r == NULL) { 1.2025 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.2026 + } else { 1.2027 + UResourceDataEntry *firstData; 1.2028 + UBool isStackObject = ures_isStackObject(r); 1.2029 + char canonLocaleID[ULOC_FULLNAME_CAPACITY]; 1.2030 + 1.2031 + uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status); 1.2032 + if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { 1.2033 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.2034 + return; 1.2035 + } 1.2036 + 1.2037 + ures_closeBundle(r, FALSE); 1.2038 + uprv_memset(r, 0, sizeof(UResourceBundle)); 1.2039 + ures_setIsStackObject(r, isStackObject); 1.2040 + r->fHasFallback = TRUE; 1.2041 + r->fIsTopLevel = TRUE; 1.2042 + r->fIndex = -1; 1.2043 + r->fData = entryOpen(path, canonLocaleID, status); 1.2044 + if(U_FAILURE(*status)) { 1.2045 + return; 1.2046 + } 1.2047 + /* this is a quick fix to get regular data in bundle - until construction is cleaned up */ 1.2048 + firstData = r->fData; 1.2049 + while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) { 1.2050 + firstData = firstData->fParent; 1.2051 + } 1.2052 + uprv_memcpy(&r->fResData, &firstData->fData, sizeof(ResourceData)); 1.2053 + r->fHasFallback=(UBool)!r->fResData.noFallback; 1.2054 + r->fRes = r->fResData.rootRes; 1.2055 + r->fSize = res_countArrayItems(&(r->fResData), r->fRes); 1.2056 + r->fTopLevelData = r->fData; 1.2057 + } 1.2058 +} 1.2059 + 1.2060 +U_CAPI UResourceBundle* U_EXPORT2 1.2061 +ures_open(const char* path, 1.2062 + const char* localeID, 1.2063 + UErrorCode* status) 1.2064 +{ 1.2065 + char canonLocaleID[ULOC_FULLNAME_CAPACITY]; 1.2066 + UResourceDataEntry *hasData = NULL; 1.2067 + UResourceBundle *r; 1.2068 + 1.2069 + if(status == NULL || U_FAILURE(*status)) { 1.2070 + return NULL; 1.2071 + } 1.2072 + 1.2073 + /* first "canonicalize" the locale ID */ 1.2074 + uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status); 1.2075 + if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { 1.2076 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.2077 + return NULL; 1.2078 + } 1.2079 + 1.2080 + r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); 1.2081 + if(r == NULL) { 1.2082 + *status = U_MEMORY_ALLOCATION_ERROR; 1.2083 + return NULL; 1.2084 + } 1.2085 + 1.2086 + uprv_memset(r, 0, sizeof(UResourceBundle)); 1.2087 + r->fHasFallback = TRUE; 1.2088 + r->fIsTopLevel = TRUE; 1.2089 + ures_setIsStackObject(r, FALSE); 1.2090 + r->fIndex = -1; 1.2091 + r->fData = entryOpen(path, canonLocaleID, status); 1.2092 + if(U_FAILURE(*status)) { 1.2093 + uprv_free(r); 1.2094 + return NULL; 1.2095 + } 1.2096 + r->fTopLevelData = r->fData; 1.2097 + 1.2098 + hasData = r->fData; 1.2099 + while(hasData->fBogus != U_ZERO_ERROR) { 1.2100 + hasData = hasData->fParent; 1.2101 + if(hasData == NULL) { 1.2102 + /* This can happen only if fallback chain gets broken by an act of God */ 1.2103 + /* TODO: this unlikely to happen, consider removing it */ 1.2104 + entryClose(r->fData); 1.2105 + uprv_free(r); 1.2106 + *status = U_MISSING_RESOURCE_ERROR; 1.2107 + return NULL; 1.2108 + } 1.2109 + } 1.2110 + 1.2111 + uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData)); 1.2112 + r->fHasFallback=(UBool)!r->fResData.noFallback; 1.2113 + r->fRes = r->fResData.rootRes; 1.2114 + r->fSize = res_countArrayItems(&(r->fResData), r->fRes); 1.2115 + /* 1.2116 + if(r->fData->fPath != NULL) { 1.2117 + ures_setResPath(r, r->fData->fPath); 1.2118 + ures_appendResPath(r, RES_PATH_PACKAGE_S); 1.2119 + ures_appendResPath(r, r->fData->fName); 1.2120 + } else { 1.2121 + ures_setResPath(r, r->fData->fName); 1.2122 + } 1.2123 + */ 1.2124 + 1.2125 + 1.2126 + return r; 1.2127 +} 1.2128 + 1.2129 +/** 1.2130 + * Opens a resource bundle without "canonicalizing" the locale name. No fallback will be performed 1.2131 + * or sought. However, alias substitution will happen! 1.2132 + */ 1.2133 +U_CAPI UResourceBundle* U_EXPORT2 1.2134 +ures_openDirect(const char* path, const char* localeID, UErrorCode* status) { 1.2135 + UResourceBundle *r; 1.2136 + UErrorCode subStatus = U_ZERO_ERROR; 1.2137 + 1.2138 + if(status == NULL || U_FAILURE(*status)) { 1.2139 + return NULL; 1.2140 + } 1.2141 + 1.2142 + r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); 1.2143 + if(r == NULL) { 1.2144 + *status = U_MEMORY_ALLOCATION_ERROR; 1.2145 + return NULL; 1.2146 + } 1.2147 + 1.2148 + r->fHasFallback = FALSE; 1.2149 + r->fIsTopLevel = TRUE; 1.2150 + ures_setIsStackObject(r, FALSE); 1.2151 + r->fIndex = -1; 1.2152 + r->fData = entryOpen(path, localeID, &subStatus); 1.2153 + if(U_FAILURE(subStatus)) { 1.2154 + *status = subStatus; 1.2155 + uprv_free(r); 1.2156 + return NULL; 1.2157 + } 1.2158 + if(subStatus != U_ZERO_ERROR /*r->fData->fBogus != U_ZERO_ERROR*/) { 1.2159 + /* we didn't find one we were looking for - so openDirect */ 1.2160 + /* should fail */ 1.2161 + entryClose(r->fData); 1.2162 + uprv_free(r); 1.2163 + *status = U_MISSING_RESOURCE_ERROR; 1.2164 + return NULL; 1.2165 + } 1.2166 + 1.2167 + r->fKey = NULL; 1.2168 + r->fVersion = NULL; 1.2169 + uprv_memcpy(&r->fResData, &r->fData->fData, sizeof(ResourceData)); 1.2170 + /* r->fHasFallback remains FALSE here in ures_openDirect() */ 1.2171 + r->fRes = r->fResData.rootRes; 1.2172 + /*r->fParent = RES_BOGUS;*/ 1.2173 + r->fSize = res_countArrayItems(&(r->fResData), r->fRes); 1.2174 + r->fResPath = NULL; 1.2175 + r->fResPathLen = 0; 1.2176 + /*r->fParentRes = NULL;*/ 1.2177 + r->fTopLevelData = r->fData; 1.2178 + 1.2179 + return r; 1.2180 +} 1.2181 + 1.2182 +/** 1.2183 + * API: Counts members. For arrays and tables, returns number of resources. 1.2184 + * For strings, returns 1. 1.2185 + */ 1.2186 +U_CAPI int32_t U_EXPORT2 1.2187 +ures_countArrayItems(const UResourceBundle* resourceBundle, 1.2188 + const char* resourceKey, 1.2189 + UErrorCode* status) 1.2190 +{ 1.2191 + UResourceBundle resData; 1.2192 + ures_initStackObject(&resData); 1.2193 + if (status==NULL || U_FAILURE(*status)) { 1.2194 + return 0; 1.2195 + } 1.2196 + if(resourceBundle == NULL) { 1.2197 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.2198 + return 0; 1.2199 + } 1.2200 + ures_getByKey(resourceBundle, resourceKey, &resData, status); 1.2201 + 1.2202 + if(resData.fResData.data != NULL) { 1.2203 + int32_t result = res_countArrayItems(&resData.fResData, resData.fRes); 1.2204 + ures_close(&resData); 1.2205 + return result; 1.2206 + } else { 1.2207 + *status = U_MISSING_RESOURCE_ERROR; 1.2208 + ures_close(&resData); 1.2209 + return 0; 1.2210 + } 1.2211 +} 1.2212 + 1.2213 +/** 1.2214 + * Internal function. 1.2215 + * Return the version number associated with this ResourceBundle as a string. 1.2216 + * 1.2217 + * @param resourceBundle The resource bundle for which the version is checked. 1.2218 + * @return A version number string as specified in the resource bundle or its parent. 1.2219 + * The caller does not own this string. 1.2220 + * @see ures_getVersion 1.2221 + * @internal 1.2222 + */ 1.2223 +U_INTERNAL const char* U_EXPORT2 1.2224 +ures_getVersionNumberInternal(const UResourceBundle *resourceBundle) 1.2225 +{ 1.2226 + if (!resourceBundle) return NULL; 1.2227 + 1.2228 + if(resourceBundle->fVersion == NULL) { 1.2229 + 1.2230 + /* If the version ID has not been built yet, then do so. Retrieve */ 1.2231 + /* the minor version from the file. */ 1.2232 + UErrorCode status = U_ZERO_ERROR; 1.2233 + int32_t minor_len = 0; 1.2234 + int32_t len; 1.2235 + 1.2236 + const UChar* minor_version = ures_getStringByKey(resourceBundle, kVersionTag, &minor_len, &status); 1.2237 + 1.2238 + /* Determine the length of of the final version string. This is */ 1.2239 + /* the length of the major part + the length of the separator */ 1.2240 + /* (==1) + the length of the minor part (+ 1 for the zero byte at */ 1.2241 + /* the end). */ 1.2242 + 1.2243 + len = (minor_len > 0) ? minor_len : 1; 1.2244 + 1.2245 + /* Allocate the string, and build it up. */ 1.2246 + /* + 1 for zero byte */ 1.2247 + 1.2248 + 1.2249 + ((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_malloc(1 + len); 1.2250 + /* Check for null pointer. */ 1.2251 + if (((UResourceBundle *)resourceBundle)->fVersion == NULL) { 1.2252 + return NULL; 1.2253 + } 1.2254 + 1.2255 + if(minor_len > 0) { 1.2256 + u_UCharsToChars(minor_version, resourceBundle->fVersion , minor_len); 1.2257 + resourceBundle->fVersion[len] = '\0'; 1.2258 + } 1.2259 + else { 1.2260 + uprv_strcpy(resourceBundle->fVersion, kDefaultMinorVersion); 1.2261 + } 1.2262 + } 1.2263 + 1.2264 + return resourceBundle->fVersion; 1.2265 +} 1.2266 + 1.2267 +U_CAPI const char* U_EXPORT2 1.2268 +ures_getVersionNumber(const UResourceBundle* resourceBundle) 1.2269 +{ 1.2270 + return ures_getVersionNumberInternal(resourceBundle); 1.2271 +} 1.2272 + 1.2273 +U_CAPI void U_EXPORT2 ures_getVersion(const UResourceBundle* resB, UVersionInfo versionInfo) { 1.2274 + if (!resB) return; 1.2275 + 1.2276 + u_versionFromString(versionInfo, ures_getVersionNumberInternal(resB)); 1.2277 +} 1.2278 + 1.2279 +/** Tree support functions *******************************/ 1.2280 +#define INDEX_LOCALE_NAME "res_index" 1.2281 +#define INDEX_TAG "InstalledLocales" 1.2282 +#define DEFAULT_TAG "default" 1.2283 + 1.2284 +#if defined(URES_TREE_DEBUG) 1.2285 +#include <stdio.h> 1.2286 +#endif 1.2287 + 1.2288 +typedef struct ULocalesContext { 1.2289 + UResourceBundle installed; 1.2290 + UResourceBundle curr; 1.2291 +} ULocalesContext; 1.2292 + 1.2293 +static void U_CALLCONV 1.2294 +ures_loc_closeLocales(UEnumeration *enumerator) { 1.2295 + ULocalesContext *ctx = (ULocalesContext *)enumerator->context; 1.2296 + ures_close(&ctx->curr); 1.2297 + ures_close(&ctx->installed); 1.2298 + uprv_free(ctx); 1.2299 + uprv_free(enumerator); 1.2300 +} 1.2301 + 1.2302 +static int32_t U_CALLCONV 1.2303 +ures_loc_countLocales(UEnumeration *en, UErrorCode * /*status*/) { 1.2304 + ULocalesContext *ctx = (ULocalesContext *)en->context; 1.2305 + return ures_getSize(&ctx->installed); 1.2306 +} 1.2307 + 1.2308 +static const char* U_CALLCONV 1.2309 +ures_loc_nextLocale(UEnumeration* en, 1.2310 + int32_t* resultLength, 1.2311 + UErrorCode* status) { 1.2312 + ULocalesContext *ctx = (ULocalesContext *)en->context; 1.2313 + UResourceBundle *res = &(ctx->installed); 1.2314 + UResourceBundle *k = NULL; 1.2315 + const char *result = NULL; 1.2316 + int32_t len = 0; 1.2317 + if(ures_hasNext(res) && (k = ures_getNextResource(res, &ctx->curr, status))) { 1.2318 + result = ures_getKey(k); 1.2319 + len = (int32_t)uprv_strlen(result); 1.2320 + } 1.2321 + if (resultLength) { 1.2322 + *resultLength = len; 1.2323 + } 1.2324 + return result; 1.2325 +} 1.2326 + 1.2327 +static void U_CALLCONV 1.2328 +ures_loc_resetLocales(UEnumeration* en, 1.2329 + UErrorCode* /*status*/) { 1.2330 + UResourceBundle *res = &((ULocalesContext *)en->context)->installed; 1.2331 + ures_resetIterator(res); 1.2332 +} 1.2333 + 1.2334 + 1.2335 +static const UEnumeration gLocalesEnum = { 1.2336 + NULL, 1.2337 + NULL, 1.2338 + ures_loc_closeLocales, 1.2339 + ures_loc_countLocales, 1.2340 + uenum_unextDefault, 1.2341 + ures_loc_nextLocale, 1.2342 + ures_loc_resetLocales 1.2343 +}; 1.2344 + 1.2345 + 1.2346 +U_CAPI UEnumeration* U_EXPORT2 1.2347 +ures_openAvailableLocales(const char *path, UErrorCode *status) 1.2348 +{ 1.2349 + UResourceBundle *idx = NULL; 1.2350 + UEnumeration *en = NULL; 1.2351 + ULocalesContext *myContext = NULL; 1.2352 + 1.2353 + if(U_FAILURE(*status)) { 1.2354 + return NULL; 1.2355 + } 1.2356 + myContext = static_cast<ULocalesContext *>(uprv_malloc(sizeof(ULocalesContext))); 1.2357 + en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration)); 1.2358 + if(!en || !myContext) { 1.2359 + *status = U_MEMORY_ALLOCATION_ERROR; 1.2360 + uprv_free(en); 1.2361 + uprv_free(myContext); 1.2362 + return NULL; 1.2363 + } 1.2364 + uprv_memcpy(en, &gLocalesEnum, sizeof(UEnumeration)); 1.2365 + 1.2366 + ures_initStackObject(&myContext->installed); 1.2367 + ures_initStackObject(&myContext->curr); 1.2368 + idx = ures_openDirect(path, INDEX_LOCALE_NAME, status); 1.2369 + ures_getByKey(idx, INDEX_TAG, &myContext->installed, status); 1.2370 + if(U_SUCCESS(*status)) { 1.2371 +#if defined(URES_TREE_DEBUG) 1.2372 + fprintf(stderr, "Got %s::%s::[%s] : %s\n", 1.2373 + path, INDEX_LOCALE_NAME, INDEX_TAG, ures_getKey(&myContext->installed)); 1.2374 +#endif 1.2375 + en->context = myContext; 1.2376 + } else { 1.2377 +#if defined(URES_TREE_DEBUG) 1.2378 + fprintf(stderr, "%s open failed - %s\n", path, u_errorName(*status)); 1.2379 +#endif 1.2380 + ures_close(&myContext->installed); 1.2381 + uprv_free(myContext); 1.2382 + uprv_free(en); 1.2383 + en = NULL; 1.2384 + } 1.2385 + 1.2386 + ures_close(idx); 1.2387 + 1.2388 + return en; 1.2389 +} 1.2390 + 1.2391 +static UBool isLocaleInList(UEnumeration *locEnum, const char *locToSearch, UErrorCode *status) { 1.2392 + const char *loc; 1.2393 + while ((loc = uenum_next(locEnum, NULL, status)) != NULL) { 1.2394 + if (uprv_strcmp(loc, locToSearch) == 0) { 1.2395 + return TRUE; 1.2396 + } 1.2397 + } 1.2398 + return FALSE; 1.2399 +} 1.2400 + 1.2401 +U_CAPI int32_t U_EXPORT2 1.2402 +ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, 1.2403 + const char *path, const char *resName, const char *keyword, const char *locid, 1.2404 + UBool *isAvailable, UBool omitDefault, UErrorCode *status) 1.2405 +{ 1.2406 + char kwVal[1024] = ""; /* value of keyword 'keyword' */ 1.2407 + char defVal[1024] = ""; /* default value for given locale */ 1.2408 + char defLoc[1024] = ""; /* default value for given locale */ 1.2409 + char base[1024] = ""; /* base locale */ 1.2410 + char found[1024]; 1.2411 + char parent[1024]; 1.2412 + char full[1024] = ""; 1.2413 + UResourceBundle bund1, bund2; 1.2414 + UResourceBundle *res = NULL; 1.2415 + UErrorCode subStatus = U_ZERO_ERROR; 1.2416 + int32_t length = 0; 1.2417 + if(U_FAILURE(*status)) return 0; 1.2418 + uloc_getKeywordValue(locid, keyword, kwVal, 1024-1,&subStatus); 1.2419 + if(!uprv_strcmp(kwVal, DEFAULT_TAG)) { 1.2420 + kwVal[0]=0; 1.2421 + } 1.2422 + uloc_getBaseName(locid, base, 1024-1,&subStatus); 1.2423 +#if defined(URES_TREE_DEBUG) 1.2424 + fprintf(stderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n", 1.2425 + locid, keyword, kwVal, base, u_errorName(subStatus)); 1.2426 +#endif 1.2427 + ures_initStackObject(&bund1); 1.2428 + ures_initStackObject(&bund2); 1.2429 + 1.2430 + 1.2431 + uprv_strcpy(parent, base); 1.2432 + uprv_strcpy(found, base); 1.2433 + 1.2434 + if(isAvailable) { 1.2435 + UEnumeration *locEnum = ures_openAvailableLocales(path, &subStatus); 1.2436 + *isAvailable = TRUE; 1.2437 + if (U_SUCCESS(subStatus)) { 1.2438 + *isAvailable = isLocaleInList(locEnum, parent, &subStatus); 1.2439 + } 1.2440 + uenum_close(locEnum); 1.2441 + } 1.2442 + 1.2443 + if(U_FAILURE(subStatus)) { 1.2444 + *status = subStatus; 1.2445 + return 0; 1.2446 + } 1.2447 + 1.2448 + do { 1.2449 + subStatus = U_ZERO_ERROR; 1.2450 + res = ures_open(path, parent, &subStatus); 1.2451 + if(((subStatus == U_USING_FALLBACK_WARNING) || 1.2452 + (subStatus == U_USING_DEFAULT_WARNING)) && isAvailable) 1.2453 + { 1.2454 + *isAvailable = FALSE; 1.2455 + } 1.2456 + isAvailable = NULL; /* only want to set this the first time around */ 1.2457 + 1.2458 +#if defined(URES_TREE_DEBUG) 1.2459 + fprintf(stderr, "%s;%s -> %s [%s]\n", path?path:"ICUDATA", parent, u_errorName(subStatus), ures_getLocale(res, &subStatus)); 1.2460 +#endif 1.2461 + if(U_FAILURE(subStatus)) { 1.2462 + *status = subStatus; 1.2463 + } else if(subStatus == U_ZERO_ERROR) { 1.2464 + ures_getByKey(res,resName,&bund1, &subStatus); 1.2465 + if(subStatus == U_ZERO_ERROR) { 1.2466 + const UChar *defUstr; 1.2467 + int32_t defLen; 1.2468 + /* look for default item */ 1.2469 +#if defined(URES_TREE_DEBUG) 1.2470 + fprintf(stderr, "%s;%s : loaded default -> %s\n", 1.2471 + path?path:"ICUDATA", parent, u_errorName(subStatus)); 1.2472 +#endif 1.2473 + defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus); 1.2474 + if(U_SUCCESS(subStatus) && defLen) { 1.2475 + u_UCharsToChars(defUstr, defVal, u_strlen(defUstr)); 1.2476 +#if defined(URES_TREE_DEBUG) 1.2477 + fprintf(stderr, "%s;%s -> default %s=%s, %s\n", 1.2478 + path?path:"ICUDATA", parent, keyword, defVal, u_errorName(subStatus)); 1.2479 +#endif 1.2480 + uprv_strcpy(defLoc, parent); 1.2481 + if(kwVal[0]==0) { 1.2482 + uprv_strcpy(kwVal, defVal); 1.2483 +#if defined(URES_TREE_DEBUG) 1.2484 + fprintf(stderr, "%s;%s -> kwVal = %s\n", 1.2485 + path?path:"ICUDATA", parent, keyword, kwVal); 1.2486 +#endif 1.2487 + } 1.2488 + } 1.2489 + } 1.2490 + } 1.2491 + 1.2492 + subStatus = U_ZERO_ERROR; 1.2493 + 1.2494 + if (res != NULL) { 1.2495 + uprv_strcpy(found, ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus)); 1.2496 + } 1.2497 + 1.2498 + uloc_getParent(found,parent,sizeof(parent),&subStatus); 1.2499 + ures_close(res); 1.2500 + } while(!defVal[0] && *found && uprv_strcmp(found, "root") != 0 && U_SUCCESS(*status)); 1.2501 + 1.2502 + /* Now, see if we can find the kwVal collator.. start the search over.. */ 1.2503 + uprv_strcpy(parent, base); 1.2504 + uprv_strcpy(found, base); 1.2505 + 1.2506 + do { 1.2507 + subStatus = U_ZERO_ERROR; 1.2508 + res = ures_open(path, parent, &subStatus); 1.2509 + if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) { 1.2510 + *isAvailable = FALSE; 1.2511 + } 1.2512 + isAvailable = NULL; /* only want to set this the first time around */ 1.2513 + 1.2514 +#if defined(URES_TREE_DEBUG) 1.2515 + fprintf(stderr, "%s;%s -> %s (looking for %s)\n", 1.2516 + path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal); 1.2517 +#endif 1.2518 + if(U_FAILURE(subStatus)) { 1.2519 + *status = subStatus; 1.2520 + } else if(subStatus == U_ZERO_ERROR) { 1.2521 + ures_getByKey(res,resName,&bund1, &subStatus); 1.2522 +#if defined(URES_TREE_DEBUG) 1.2523 +/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, resName, u_errorName(subStatus)); 1.2524 +#endif 1.2525 + if(subStatus == U_ZERO_ERROR) { 1.2526 + ures_getByKey(&bund1, kwVal, &bund2, &subStatus); 1.2527 +#if defined(URES_TREE_DEBUG) 1.2528 +/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, kwVal, u_errorName(subStatus)); 1.2529 +#endif 1.2530 + if(subStatus == U_ZERO_ERROR) { 1.2531 +#if defined(URES_TREE_DEBUG) 1.2532 + fprintf(stderr, "%s;%s -> full0 %s=%s, %s\n", 1.2533 + path?path:"ICUDATA", parent, keyword, kwVal, u_errorName(subStatus)); 1.2534 +#endif 1.2535 + uprv_strcpy(full, parent); 1.2536 + if(*full == 0) { 1.2537 + uprv_strcpy(full, "root"); 1.2538 + } 1.2539 + /* now, recalculate default kw if need be */ 1.2540 + if(uprv_strlen(defLoc) > uprv_strlen(full)) { 1.2541 + const UChar *defUstr; 1.2542 + int32_t defLen; 1.2543 + /* look for default item */ 1.2544 +#if defined(URES_TREE_DEBUG) 1.2545 + fprintf(stderr, "%s;%s -> recalculating Default0\n", 1.2546 + path?path:"ICUDATA", full); 1.2547 +#endif 1.2548 + defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus); 1.2549 + if(U_SUCCESS(subStatus) && defLen) { 1.2550 + u_UCharsToChars(defUstr, defVal, u_strlen(defUstr)); 1.2551 +#if defined(URES_TREE_DEBUG) 1.2552 + fprintf(stderr, "%s;%s -> default0 %s=%s, %s\n", 1.2553 + path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus)); 1.2554 +#endif 1.2555 + uprv_strcpy(defLoc, full); 1.2556 + } 1.2557 + } /* end of recalculate default KW */ 1.2558 +#if defined(URES_TREE_DEBUG) 1.2559 + else { 1.2560 + fprintf(stderr, "No trim0, %s <= %s\n", defLoc, full); 1.2561 + } 1.2562 +#endif 1.2563 + } else { 1.2564 +#if defined(URES_TREE_DEBUG) 1.2565 + fprintf(stderr, "err=%s in %s looking for %s\n", 1.2566 + u_errorName(subStatus), parent, kwVal); 1.2567 +#endif 1.2568 + } 1.2569 + } 1.2570 + } 1.2571 + 1.2572 + subStatus = U_ZERO_ERROR; 1.2573 + 1.2574 + uprv_strcpy(found, parent); 1.2575 + uloc_getParent(found,parent,1023,&subStatus); 1.2576 + ures_close(res); 1.2577 + } while(!full[0] && *found && U_SUCCESS(*status)); 1.2578 + 1.2579 + if((full[0]==0) && uprv_strcmp(kwVal, defVal)) { 1.2580 +#if defined(URES_TREE_DEBUG) 1.2581 + fprintf(stderr, "Failed to locate kw %s - try default %s\n", kwVal, defVal); 1.2582 +#endif 1.2583 + uprv_strcpy(kwVal, defVal); 1.2584 + uprv_strcpy(parent, base); 1.2585 + uprv_strcpy(found, base); 1.2586 + 1.2587 + do { /* search for 'default' named item */ 1.2588 + subStatus = U_ZERO_ERROR; 1.2589 + res = ures_open(path, parent, &subStatus); 1.2590 + if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) { 1.2591 + *isAvailable = FALSE; 1.2592 + } 1.2593 + isAvailable = NULL; /* only want to set this the first time around */ 1.2594 + 1.2595 +#if defined(URES_TREE_DEBUG) 1.2596 + fprintf(stderr, "%s;%s -> %s (looking for default %s)\n", 1.2597 + path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal); 1.2598 +#endif 1.2599 + if(U_FAILURE(subStatus)) { 1.2600 + *status = subStatus; 1.2601 + } else if(subStatus == U_ZERO_ERROR) { 1.2602 + ures_getByKey(res,resName,&bund1, &subStatus); 1.2603 + if(subStatus == U_ZERO_ERROR) { 1.2604 + ures_getByKey(&bund1, kwVal, &bund2, &subStatus); 1.2605 + if(subStatus == U_ZERO_ERROR) { 1.2606 +#if defined(URES_TREE_DEBUG) 1.2607 + fprintf(stderr, "%s;%s -> full1 %s=%s, %s\n", path?path:"ICUDATA", 1.2608 + parent, keyword, kwVal, u_errorName(subStatus)); 1.2609 +#endif 1.2610 + uprv_strcpy(full, parent); 1.2611 + if(*full == 0) { 1.2612 + uprv_strcpy(full, "root"); 1.2613 + } 1.2614 + 1.2615 + /* now, recalculate default kw if need be */ 1.2616 + if(uprv_strlen(defLoc) > uprv_strlen(full)) { 1.2617 + const UChar *defUstr; 1.2618 + int32_t defLen; 1.2619 + /* look for default item */ 1.2620 +#if defined(URES_TREE_DEBUG) 1.2621 + fprintf(stderr, "%s;%s -> recalculating Default1\n", 1.2622 + path?path:"ICUDATA", full); 1.2623 +#endif 1.2624 + defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus); 1.2625 + if(U_SUCCESS(subStatus) && defLen) { 1.2626 + u_UCharsToChars(defUstr, defVal, u_strlen(defUstr)); 1.2627 +#if defined(URES_TREE_DEBUG) 1.2628 + fprintf(stderr, "%s;%s -> default %s=%s, %s\n", 1.2629 + path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus)); 1.2630 +#endif 1.2631 + uprv_strcpy(defLoc, full); 1.2632 + } 1.2633 + } /* end of recalculate default KW */ 1.2634 +#if defined(URES_TREE_DEBUG) 1.2635 + else { 1.2636 + fprintf(stderr, "No trim1, %s <= %s\n", defLoc, full); 1.2637 + } 1.2638 +#endif 1.2639 + } 1.2640 + } 1.2641 + } 1.2642 + subStatus = U_ZERO_ERROR; 1.2643 + 1.2644 + uprv_strcpy(found, parent); 1.2645 + uloc_getParent(found,parent,1023,&subStatus); 1.2646 + ures_close(res); 1.2647 + } while(!full[0] && *found && U_SUCCESS(*status)); 1.2648 + } 1.2649 + 1.2650 + if(U_SUCCESS(*status)) { 1.2651 + if(!full[0]) { 1.2652 +#if defined(URES_TREE_DEBUG) 1.2653 + fprintf(stderr, "Still could not load keyword %s=%s\n", keyword, kwVal); 1.2654 +#endif 1.2655 + *status = U_MISSING_RESOURCE_ERROR; 1.2656 + } else if(omitDefault) { 1.2657 +#if defined(URES_TREE_DEBUG) 1.2658 + fprintf(stderr,"Trim? full=%s, defLoc=%s, found=%s\n", full, defLoc, found); 1.2659 +#endif 1.2660 + if(uprv_strlen(defLoc) <= uprv_strlen(full)) { 1.2661 + /* found the keyword in a *child* of where the default tag was present. */ 1.2662 + if(!uprv_strcmp(kwVal, defVal)) { /* if the requested kw is default, */ 1.2663 + /* and the default is in or in an ancestor of the current locale */ 1.2664 +#if defined(URES_TREE_DEBUG) 1.2665 + fprintf(stderr, "Removing unneeded var %s=%s\n", keyword, kwVal); 1.2666 +#endif 1.2667 + kwVal[0]=0; 1.2668 + } 1.2669 + } 1.2670 + } 1.2671 + uprv_strcpy(found, full); 1.2672 + if(kwVal[0]) { 1.2673 + uprv_strcat(found, "@"); 1.2674 + uprv_strcat(found, keyword); 1.2675 + uprv_strcat(found, "="); 1.2676 + uprv_strcat(found, kwVal); 1.2677 + } else if(!omitDefault) { 1.2678 + uprv_strcat(found, "@"); 1.2679 + uprv_strcat(found, keyword); 1.2680 + uprv_strcat(found, "="); 1.2681 + uprv_strcat(found, defVal); 1.2682 + } 1.2683 + } 1.2684 + /* we found the default locale - no need to repeat it.*/ 1.2685 + 1.2686 + ures_close(&bund1); 1.2687 + ures_close(&bund2); 1.2688 + 1.2689 + length = (int32_t)uprv_strlen(found); 1.2690 + 1.2691 + if(U_SUCCESS(*status)) { 1.2692 + int32_t copyLength = uprv_min(length, resultCapacity); 1.2693 + if(copyLength>0) { 1.2694 + uprv_strncpy(result, found, copyLength); 1.2695 + } 1.2696 + if(length == 0) { 1.2697 + *status = U_MISSING_RESOURCE_ERROR; 1.2698 + } 1.2699 + } else { 1.2700 + length = 0; 1.2701 + result[0]=0; 1.2702 + } 1.2703 + return u_terminateChars(result, resultCapacity, length, status); 1.2704 +} 1.2705 + 1.2706 +U_CAPI UEnumeration* U_EXPORT2 1.2707 +ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status) 1.2708 +{ 1.2709 +#define VALUES_BUF_SIZE 2048 1.2710 +#define VALUES_LIST_SIZE 512 1.2711 + 1.2712 + char valuesBuf[VALUES_BUF_SIZE]; 1.2713 + int32_t valuesIndex = 0; 1.2714 + const char *valuesList[VALUES_LIST_SIZE]; 1.2715 + int32_t valuesCount = 0; 1.2716 + 1.2717 + const char *locale; 1.2718 + int32_t locLen; 1.2719 + 1.2720 + UEnumeration *locs = NULL; 1.2721 + 1.2722 + UResourceBundle item; 1.2723 + UResourceBundle subItem; 1.2724 + 1.2725 + ures_initStackObject(&item); 1.2726 + ures_initStackObject(&subItem); 1.2727 + locs = ures_openAvailableLocales(path, status); 1.2728 + 1.2729 + if(U_FAILURE(*status)) { 1.2730 + ures_close(&item); 1.2731 + ures_close(&subItem); 1.2732 + return NULL; 1.2733 + } 1.2734 + 1.2735 + valuesBuf[0]=0; 1.2736 + valuesBuf[1]=0; 1.2737 + 1.2738 + while((locale = uenum_next(locs, &locLen, status))) { 1.2739 + UResourceBundle *bund = NULL; 1.2740 + UResourceBundle *subPtr = NULL; 1.2741 + UErrorCode subStatus = U_ZERO_ERROR; /* don't fail if a bundle is unopenable */ 1.2742 + bund = ures_openDirect(path, locale, &subStatus); 1.2743 + 1.2744 +#if defined(URES_TREE_DEBUG) 1.2745 + if(!bund || U_FAILURE(subStatus)) { 1.2746 + fprintf(stderr, "%s-%s values: Can't open %s locale - skipping. (%s)\n", 1.2747 + path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus)); 1.2748 + } 1.2749 +#endif 1.2750 + 1.2751 + ures_getByKey(bund, keyword, &item, &subStatus); 1.2752 + 1.2753 + if(!bund || U_FAILURE(subStatus)) { 1.2754 +#if defined(URES_TREE_DEBUG) 1.2755 + fprintf(stderr, "%s-%s values: Can't find in %s - skipping. (%s)\n", 1.2756 + path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus)); 1.2757 +#endif 1.2758 + ures_close(bund); 1.2759 + bund = NULL; 1.2760 + continue; 1.2761 + } 1.2762 + 1.2763 + while((subPtr = ures_getNextResource(&item,&subItem,&subStatus)) 1.2764 + && U_SUCCESS(subStatus)) { 1.2765 + const char *k; 1.2766 + int32_t i; 1.2767 + k = ures_getKey(subPtr); 1.2768 + 1.2769 +#if defined(URES_TREE_DEBUG) 1.2770 + /* fprintf(stderr, "%s | %s | %s | %s\n", path?path:"<ICUDATA>", keyword, locale, k); */ 1.2771 +#endif 1.2772 + for(i=0;k&&i<valuesCount;i++) { 1.2773 + if(!uprv_strcmp(valuesList[i],k)) { 1.2774 + k = NULL; /* found duplicate */ 1.2775 + } 1.2776 + } 1.2777 + if(k && *k) { 1.2778 + int32_t kLen = (int32_t)uprv_strlen(k); 1.2779 + if(!uprv_strcmp(k,DEFAULT_TAG)) { 1.2780 + continue; /* don't need 'default'. */ 1.2781 + } 1.2782 + if((valuesCount >= (VALUES_LIST_SIZE-1)) || /* no more space in list .. */ 1.2783 + ((valuesIndex+kLen+1+1) >= VALUES_BUF_SIZE)) { /* no more space in buffer (string + 2 nulls) */ 1.2784 + *status = U_ILLEGAL_ARGUMENT_ERROR; /* out of space.. */ 1.2785 + } else { 1.2786 + uprv_strcpy(valuesBuf+valuesIndex, k); 1.2787 + valuesList[valuesCount++] = valuesBuf+valuesIndex; 1.2788 + valuesIndex += kLen; 1.2789 +#if defined(URES_TREE_DEBUG) 1.2790 + fprintf(stderr, "%s | %s | %s | [%s] (UNIQUE)\n", 1.2791 + path?path:"<ICUDATA>", keyword, locale, k); 1.2792 +#endif 1.2793 + valuesBuf[valuesIndex++] = 0; /* terminate */ 1.2794 + } 1.2795 + } 1.2796 + } 1.2797 + ures_close(bund); 1.2798 + } 1.2799 + valuesBuf[valuesIndex++] = 0; /* terminate */ 1.2800 + 1.2801 + ures_close(&item); 1.2802 + ures_close(&subItem); 1.2803 + uenum_close(locs); 1.2804 +#if defined(URES_TREE_DEBUG) 1.2805 + fprintf(stderr, "%s: size %d, #%d\n", u_errorName(*status), 1.2806 + valuesIndex, valuesCount); 1.2807 +#endif 1.2808 + return uloc_openKeywordList(valuesBuf, valuesIndex, status); 1.2809 +} 1.2810 +#if 0 1.2811 +/* This code isn't needed, and given the documentation warnings the implementation is suspect */ 1.2812 +U_INTERNAL UBool U_EXPORT2 1.2813 +ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){ 1.2814 + if(res1==NULL || res2==NULL){ 1.2815 + return res1==res2; /* pointer comparision */ 1.2816 + } 1.2817 + if(res1->fKey==NULL|| res2->fKey==NULL){ 1.2818 + return (res1->fKey==res2->fKey); 1.2819 + }else{ 1.2820 + if(uprv_strcmp(res1->fKey, res2->fKey)!=0){ 1.2821 + return FALSE; 1.2822 + } 1.2823 + } 1.2824 + if(uprv_strcmp(res1->fData->fName, res2->fData->fName)!=0){ 1.2825 + return FALSE; 1.2826 + } 1.2827 + if(res1->fData->fPath == NULL|| res2->fData->fPath==NULL){ 1.2828 + return (res1->fData->fPath == res2->fData->fPath); 1.2829 + }else{ 1.2830 + if(uprv_strcmp(res1->fData->fPath, res2->fData->fPath)!=0){ 1.2831 + return FALSE; 1.2832 + } 1.2833 + } 1.2834 + if(uprv_strcmp(res1->fData->fParent->fName, res2->fData->fParent->fName)!=0){ 1.2835 + return FALSE; 1.2836 + } 1.2837 + if(uprv_strcmp(res1->fData->fParent->fPath, res2->fData->fParent->fPath)!=0){ 1.2838 + return FALSE; 1.2839 + } 1.2840 + if(uprv_strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen)!=0){ 1.2841 + return FALSE; 1.2842 + } 1.2843 + if(res1->fRes != res2->fRes){ 1.2844 + return FALSE; 1.2845 + } 1.2846 + return TRUE; 1.2847 +} 1.2848 +U_INTERNAL UResourceBundle* U_EXPORT2 1.2849 +ures_clone(const UResourceBundle* res, UErrorCode* status){ 1.2850 + UResourceBundle* bundle = NULL; 1.2851 + UResourceBundle* ret = NULL; 1.2852 + if(U_FAILURE(*status) || res == NULL){ 1.2853 + return NULL; 1.2854 + } 1.2855 + bundle = ures_open(res->fData->fPath, res->fData->fName, status); 1.2856 + if(res->fResPath!=NULL){ 1.2857 + ret = ures_findSubResource(bundle, res->fResPath, NULL, status); 1.2858 + ures_close(bundle); 1.2859 + }else{ 1.2860 + ret = bundle; 1.2861 + } 1.2862 + return ret; 1.2863 +} 1.2864 +U_INTERNAL const UResourceBundle* U_EXPORT2 1.2865 +ures_getParentBundle(const UResourceBundle* res){ 1.2866 + if(res==NULL){ 1.2867 + return NULL; 1.2868 + } 1.2869 + return res->fParentRes; 1.2870 +} 1.2871 +#endif 1.2872 + 1.2873 +U_INTERNAL void U_EXPORT2 1.2874 +ures_getVersionByKey(const UResourceBundle* res, const char *key, UVersionInfo ver, UErrorCode *status) { 1.2875 + const UChar *str; 1.2876 + int32_t len; 1.2877 + str = ures_getStringByKey(res, key, &len, status); 1.2878 + if(U_SUCCESS(*status)) { 1.2879 + u_versionFromUString(ver, str); 1.2880 + } 1.2881 +} 1.2882 + 1.2883 +/* eof */