/*
******************************************************************************
-* Copyright (C) 1997-2004, International Business Machines Corporation and *
+* Copyright (C) 1997-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*
static UMTX resbMutex = NULL;
/* INTERNAL: hashes an entry */
-static int32_t U_EXPORT2 U_CALLCONV hashEntry(const UHashTok parm) {
+static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer;
UHashTok namekey, pathkey;
namekey.pointer = b->fName;
}
/* INTERNAL: compares two entries */
-static UBool U_EXPORT2 U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
+static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer;
UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer;
UHashTok name1, name2, path1, path2;
name2.pointer = b2->fName;
path1.pointer = b1->fPath;
path2.pointer = b2->fPath;
- return (UBool)(uhash_compareChars(name1, name2) &
+ return (UBool)(uhash_compareChars(name1, name2) &&
uhash_compareChars(path1, path2));
}
}
}
+static void
+free_entry(UResourceDataEntry *entry) {
+ UResourceDataEntry *alias;
+ res_unload(&(entry->fData));
+ if(entry->fName != NULL && entry->fName != entry->fNameBuffer) {
+ uprv_free(entry->fName);
+ }
+ if(entry->fPath != NULL) {
+ uprv_free(entry->fPath);
+ }
+ if(entry->fPool != NULL) {
+ --entry->fPool->fCountExisting;
+ }
+ alias = entry->fAlias;
+ if(alias != NULL) {
+ while(alias->fAlias != NULL) {
+ alias = alias->fAlias;
+ }
+ --alias->fCountExisting;
+ }
+ uprv_free(entry);
+}
+
/* Works just like ucnv_flushCache() */
-/* TODO: figure out why fCountExisting may not go to zero. Do not make this function public yet. */
static int32_t ures_flushCache()
{
- UResourceDataEntry *resB = NULL;
- int32_t pos = -1;
+ UResourceDataEntry *resB;
+ int32_t pos;
int32_t rbDeletedNum = 0;
const UHashElement *e;
+ UBool deletedMore;
/*if shared data hasn't even been lazy evaluated yet
* return 0
return 0;
}
- /*creates an enumeration to iterate through every element in the table */
- while ((e = uhash_nextElement(cache, &pos)) != NULL)
- {
- resB = (UResourceDataEntry *) e->value.pointer;
- /* Deletes only if reference counter == 0
- * Don't worry about the children of this node.
- * Those will eventually get deleted too, if not already.
- * Don't worry about the parents of this node.
- * Those will eventually get deleted too, if not already.
- */
- /* DONE: figure out why fCountExisting may not go to zero. Do not make this function public yet. */
- /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's not zero, that means that */
- /* some resource bundles are still open somewhere. */
-
- /*U_ASSERT(resB->fCountExisting == 0);*/
- if (resB->fCountExisting == 0) {
- rbDeletedNum++;
- uhash_removeElement(cache, e);
- if(resB->fBogus == U_ZERO_ERROR) {
- res_unload(&(resB->fData));
- }
- if(resB->fName != NULL) {
- uprv_free(resB->fName);
- }
- if(resB->fPath != NULL) {
- uprv_free(resB->fPath);
+ do {
+ deletedMore = FALSE;
+ /*creates an enumeration to iterate through every element in the table */
+ pos = -1;
+ while ((e = uhash_nextElement(cache, &pos)) != NULL)
+ {
+ resB = (UResourceDataEntry *) e->value.pointer;
+ /* Deletes only if reference counter == 0
+ * Don't worry about the children of this node.
+ * Those will eventually get deleted too, if not already.
+ * Don't worry about the parents of this node.
+ * Those will eventually get deleted too, if not already.
+ */
+ /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's not zero, that means that */
+ /* some resource bundles are still open somewhere. */
+
+ if (resB->fCountExisting == 0) {
+ rbDeletedNum++;
+ deletedMore = TRUE;
+ uhash_removeElement(cache, e);
+ free_entry(resB);
}
- uprv_free(resB);
}
- }
+ /*
+ * Do it again to catch bundles (aliases, pool bundle) whose fCountExisting
+ * got decremented by free_entry().
+ */
+ } while(deletedMore);
umtx_unlock(&resbMutex);
return rbDeletedNum;
}
+#ifdef URES_DEBUG
+#include <stdio.h>
+
+U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) {
+ UBool cacheNotEmpty = FALSE;
+ int32_t pos = -1;
+ const UHashElement *e;
+ UResourceDataEntry *resB;
+
+ umtx_lock(&resbMutex);
+ if (cache == NULL) {
+ umtx_unlock(&resbMutex);
+ fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ while ((e = uhash_nextElement(cache, &pos)) != NULL) {
+ cacheNotEmpty=TRUE;
+ resB = (UResourceDataEntry *) e->value.pointer;
+ fprintf(stderr,"%s:%d: RB Cache: Entry @0x%p, refcount %d, name %s:%s. Pool 0x%p, alias 0x%p, parent 0x%p\n",
+ __FILE__, __LINE__,
+ (void*)resB, resB->fCountExisting,
+ resB->fName?resB->fName:"NULL",
+ resB->fPath?resB->fPath:"NULL",
+ (void*)resB->fPool,
+ (void*)resB->fAlias,
+ (void*)resB->fParent);
+ }
+
+ fprintf(stderr,"%s:%d: RB Cache still contains %d items.\n", __FILE__, __LINE__, uhash_count(cache));
+
+ umtx_unlock(&resbMutex);
+
+ return cacheNotEmpty;
+}
+
+#endif
+
static UBool U_CALLCONV ures_cleanup(void)
{
if (cache != NULL) {
/** INTERNAL: Initializes the cache for resources */
static void initCache(UErrorCode *status) {
UBool makeCache = FALSE;
- umtx_lock(&resbMutex);
- makeCache = (cache == NULL);
- umtx_unlock(&resbMutex);
+ UMTX_CHECK(&resbMutex, (cache == NULL), makeCache);
if(makeCache) {
- UHashtable *newCache = uhash_open(hashEntry, compareEntries, status);
+ UHashtable *newCache = uhash_open(hashEntry, compareEntries, NULL, status);
if (U_FAILURE(*status)) {
return;
}
/** INTERNAL: sets the name (locale) of the resource bundle to given name */
static void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status) {
- if(res->fName != NULL) {
+ int32_t len = (int32_t)uprv_strlen(name);
+ if(res->fName != NULL && res->fName != res->fNameBuffer) {
uprv_free(res->fName);
}
- res->fName = (char *)uprv_malloc(sizeof(char)*uprv_strlen(name)+1);
+ if (len < (int32_t)sizeof(res->fNameBuffer)) {
+ res->fName = res->fNameBuffer;
+ }
+ else {
+ res->fName = (char *)uprv_malloc(len+1);
+ }
if(res->fName == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
} else {
}
}
+static UResourceDataEntry *
+getPoolEntry(const char *path, UErrorCode *status);
+
/**
* INTERNAL: Inits and opens an entry from a data DLL.
* CAUTION: resbMutex must be locked when calling this function.
static UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) {
UResourceDataEntry *r = NULL;
UResourceDataEntry find;
- int32_t hashValue;
+ /*int32_t hashValue;*/
char name[96];
- const char *myPath = NULL;
char aliasName[100] = { 0 };
int32_t aliasLen = 0;
- UBool isAlias = FALSE;
+ /*UBool isAlias = FALSE;*/
UHashTok hashkey;
if(U_FAILURE(*status)) {
/* here we try to deduce the right locale name */
if(localeID == NULL) { /* if localeID is NULL, we're trying to open default locale */
uprv_strcpy(name, uloc_getDefault());
- } else if(uprv_strlen(localeID) == 0) { /* if localeID is "" then we try to open root locale */
+ } else if(*localeID == 0) { /* if localeID is "" then we try to open root locale */
uprv_strcpy(name, kRootLocaleName);
} else { /* otherwise, we'll open what we're given */
uprv_strcpy(name, localeID);
}
- if(path != NULL) { /* if we actually have path, we'll use it */
- myPath = path;
- }
-
find.fName = name;
- find.fPath = (char *)myPath;
+ find.fPath = (char *)path;
/* calculate the hash value of the entry */
hashkey.pointer = (void *)&find;
- hashValue = hashEntry(hashkey);
+ /*hashValue = hashEntry(hashkey);*/
/* check to see if we already have this entry */
r = (UResourceDataEntry *)uhash_get(cache, &find);
-
- if(r != NULL) { /* if the entry is already in the hash table */
- r->fCountExisting++; /* we just increase it's reference count */
- /* if the resource has a warning */
- /* we don't want to overwrite a status with no error */
- if(r->fBogus != U_ZERO_ERROR) {
- *status = r->fBogus; /* set the returning status */
- }
- } else { /* otherwise, we'll try to construct a new entry */
- UBool result = FALSE;
-
+ if(r == NULL) {
+ /* if the entry is not yet in the hash table, we'll try to construct a new one */
r = (UResourceDataEntry *) uprv_malloc(sizeof(UResourceDataEntry));
-
if(r == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- r->fCountExisting = 1;
- r->fName = NULL;
+ uprv_memset(r, 0, sizeof(UResourceDataEntry));
+ /*r->fHashKey = hashValue;*/
+
setEntryName(r, name, status);
+ if (U_FAILURE(*status)) {
+ uprv_free(r);
+ return NULL;
+ }
- r->fPath = NULL;
- if(myPath != NULL && !U_FAILURE(*status)) {
- r->fPath = (char *)uprv_malloc(sizeof(char)*uprv_strlen(myPath)+1);
+ if(path != NULL) {
+ r->fPath = (char *)uprv_strdup(path);
if(r->fPath == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- uprv_strcpy(r->fPath, myPath);
+ uprv_free(r);
+ return NULL;
}
}
- r->fHashKey = hashValue;
- r->fParent = NULL;
- r->fData.data = NULL;
- r->fData.pRoot = NULL;
- r->fData.rootRes = 0;
- r->fBogus = U_ZERO_ERROR;
-
- /* this is the acutal loading - returns bool true/false */
- result = res_load(&(r->fData), r->fPath, r->fName, status);
+ /* this is the actual loading */
+ res_load(&(r->fData), r->fPath, r->fName, status);
- if (result == FALSE || U_FAILURE(*status)) {
+ if (U_FAILURE(*status)) {
/* we have no such entry in dll, so it will always use fallback */
*status = U_USING_FALLBACK_WARNING;
r->fBogus = U_USING_FALLBACK_WARNING;
} else { /* if we have a regular entry */
- /* We might be able to do this a wee bit more efficiently (we could check whether the aliased data) */
- /* is already in the cache), but it's good the way it is */
- /* handle the alias by trying to get out the %%Alias tag.*/
- /* We'll try to get alias string from the bundle */
- Resource aliasres = res_getResource(&(r->fData), "%%ALIAS");
- const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen);
- if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */
- u_UCharsToChars(alias, aliasName, aliasLen+1);
- isAlias = TRUE;
- res_unload(&(r->fData));
- result = res_load(&(r->fData), r->fPath, aliasName, status);
- if (result == FALSE || U_FAILURE(*status)) {
- /* we couldn't load aliased data - so we have no data */
- *status = U_USING_FALLBACK_WARNING;
- r->fBogus = U_USING_FALLBACK_WARNING;
+ Resource aliasres;
+ if (r->fData.usesPoolBundle) {
+ r->fPool = getPoolEntry(r->fPath, status);
+ if (U_SUCCESS(*status)) {
+ const int32_t *poolIndexes = r->fPool->fData.pRoot + 1;
+ if(r->fData.pRoot[1 + URES_INDEX_POOL_CHECKSUM] == poolIndexes[URES_INDEX_POOL_CHECKSUM]) {
+ r->fData.poolBundleKeys = (const char *)(poolIndexes + (poolIndexes[URES_INDEX_LENGTH] & 0xff));
+ } else {
+ r->fBogus = *status = U_INVALID_FORMAT_ERROR;
+ }
+ } else {
+ r->fBogus = *status;
+ }
+ }
+ if (U_SUCCESS(*status)) {
+ /* handle the alias by trying to get out the %%Alias tag.*/
+ /* We'll try to get alias string from the bundle */
+ aliasres = res_getResource(&(r->fData), "%%ALIAS");
+ if (aliasres != RES_BOGUS) {
+ const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen);
+ if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */
+ u_UCharsToChars(alias, aliasName, aliasLen+1);
+ r->fAlias = init_entry(aliasName, path, status);
+ }
}
- setEntryName(r, aliasName, status);
}
}
{
UResourceDataEntry *oldR = NULL;
if((oldR = (UResourceDataEntry *)uhash_get(cache, r)) == NULL) { /* if the data is not cached */
- /* just insert it in the cache */
- uhash_put(cache, (void *)r, r, status);
- } else {
- /* somebody have already inserted it while we were working, discard newly opened data */
- /* Also, we could get here IF we opened an alias */
- uprv_free(r->fName);
- if(r->fPath != NULL) {
- uprv_free(r->fPath);
+ /* just insert it in the cache */
+ UErrorCode cacheStatus = U_ZERO_ERROR;
+ uhash_put(cache, (void *)r, r, &cacheStatus);
+ if (U_FAILURE(cacheStatus)) {
+ *status = cacheStatus;
+ free_entry(r);
+ r = NULL;
}
- res_unload(&(r->fData));
- uprv_free(r);
+ } else {
+ /* somebody have already inserted it while we were working, discard newly opened data */
+ /* Also, we could get here IF we opened an alias */
+ free_entry(r);
r = oldR;
- r->fCountExisting++;
}
}
}
+ if(r != NULL) {
+ /* return the real bundle */
+ while(r->fAlias != NULL) {
+ r = r->fAlias;
+ }
+ r->fCountExisting++; /* we increase its reference count */
+ /* if the resource has a warning */
+ /* we don't want to overwrite a status with no error */
+ if(r->fBogus != U_ZERO_ERROR && U_SUCCESS(*status)) {
+ *status = r->fBogus; /* set the returning status */
+ }
+ }
return r;
}
+static UResourceDataEntry *
+getPoolEntry(const char *path, UErrorCode *status) {
+ UResourceDataEntry *poolBundle = init_entry(kPoolBundleName, path, status);
+ if( U_SUCCESS(*status) &&
+ (poolBundle == NULL || poolBundle->fBogus != U_ZERO_ERROR || !poolBundle->fData.isPoolBundle)
+ ) {
+ *status = U_INVALID_FORMAT_ERROR;
+ }
+ return poolBundle;
+}
+
/* INTERNAL: */
/* CAUTION: resbMutex must be locked when calling this function! */
static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
- UResourceDataEntry *r = NULL;
- UBool hasRealData = FALSE;
- const char *defaultLoc = uloc_getDefault();
- UErrorCode intStatus = U_ZERO_ERROR;
- *hasChopped = TRUE; /* we're starting with a fresh name */
-
- while(*hasChopped && !hasRealData) {
- r = init_entry(name, path, &intStatus);
- *isDefault = (UBool)(uprv_strncmp(name, defaultLoc, uprv_strlen(name)) == 0);
- hasRealData = (UBool)(r->fBogus == U_ZERO_ERROR);
- if(!hasRealData) {
- /* this entry is not real. We will discard it. */
- /* However, the parent line for this entry is */
- /* not to be used - as there might be parent */
- /* lines in cache from previous openings that */
- /* are not updated yet. */
- r->fCountExisting--;
- /*entryCloseInt(r);*/
- r = NULL;
- *status = U_USING_FALLBACK_WARNING;
- } else {
- uprv_strcpy(name, r->fName); /* this is needed for supporting aliases */
- }
+ UResourceDataEntry *r = NULL;
+ UBool hasRealData = FALSE;
+ const char *defaultLoc = uloc_getDefault();
+ *hasChopped = TRUE; /* we're starting with a fresh name */
- *isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName) == 0);
+ while(*hasChopped && !hasRealData) {
+ r = init_entry(name, path, status);
+ /* Null pointer test */
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ *isDefault = (UBool)(uprv_strncmp(name, defaultLoc, uprv_strlen(name)) == 0);
+ hasRealData = (UBool)(r->fBogus == U_ZERO_ERROR);
+ if(!hasRealData) {
+ /* this entry is not real. We will discard it. */
+ /* However, the parent line for this entry is */
+ /* not to be used - as there might be parent */
+ /* lines in cache from previous openings that */
+ /* are not updated yet. */
+ r->fCountExisting--;
+ /*entryCloseInt(r);*/
+ r = NULL;
+ *status = U_USING_FALLBACK_WARNING;
+ } else {
+ uprv_strcpy(name, r->fName); /* this is needed for supporting aliases */
+ }
- /*Fallback data stuff*/
- *hasChopped = chopLocale(name);
- }
- return r;
+ *isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName) == 0);
+
+ /*Fallback data stuff*/
+ *hasChopped = chopLocale(name);
+ }
+ return r;
}
static void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UErrorCode* status) {
UErrorCode intStatus = U_ZERO_ERROR;
UErrorCode parentStatus = U_ZERO_ERROR;
+ UErrorCode usrStatus = U_ZERO_ERROR;
UResourceDataEntry *r = NULL;
UResourceDataEntry *t1 = NULL;
UResourceDataEntry *t2 = NULL;
+ UResourceDataEntry *u1 = NULL;
+ UResourceDataEntry *u2 = NULL;
UBool isDefault = FALSE;
UBool isRoot = FALSE;
UBool hasRealData = FALSE;
UBool hasChopped = TRUE;
+ UBool usingUSRData = U_USE_USRDATA && ( path == NULL || uprv_strncmp(path,U_ICUDATA_NAME,8) == 0);
+
char name[96];
+ char usrDataPath[96];
+
+ initCache(status);
if(U_FAILURE(*status)) {
- return NULL;
+ return NULL;
}
- initCache(status);
-
uprv_strcpy(name, localeID);
+ if ( usingUSRData ) {
+ if ( path == NULL ) {
+ uprv_strcpy(usrDataPath,U_USRDATA_NAME);
+ } else {
+ uprv_strcpy(usrDataPath,path);
+ usrDataPath[0] = 'u';
+ usrDataPath[1] = 's';
+ usrDataPath[2] = 'r';
+ }
+ }
+
umtx_lock(&resbMutex);
{ /* umtx_lock */
- /* We're going to skip all the locales that do not have any data */
- r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
-
- if(r != NULL) { /* if there is one real locale, we can look for parents. */
- t1 = r;
- hasRealData = TRUE;
- while (hasChopped && !isRoot && t1->fParent == NULL) {
- /* insert regular parents */
- t2 = init_entry(name, r->fPath, &parentStatus);
- t1->fParent = t2;
- t1 = t2;
- hasChopped = chopLocale(name);
- }
- }
+ /* We're going to skip all the locales that do not have any data */
+ r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
- /* we could have reached this point without having any real data */
- /* if that is the case, we need to chain in the default locale */
- if(r==NULL && !isDefault && !isRoot /*&& t1->fParent == NULL*/) {
- /* insert default locale */
- uprv_strcpy(name, uloc_getDefault());
- r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
- intStatus = U_USING_DEFAULT_WARNING;
- if(r != NULL) { /* the default locale exists */
+ if(r != NULL) { /* if there is one real locale, we can look for parents. */
t1 = r;
hasRealData = TRUE;
- isDefault = TRUE;
- while (hasChopped && t1->fParent == NULL) {
- /* insert chopped defaults */
- t2 = init_entry(name, r->fPath, &parentStatus);
- t1->fParent = t2;
- t1 = t2;
+ if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */
+ u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
+ if ( u1 != NULL ) {
+ if(u1->fBogus == U_ZERO_ERROR) {
+ u1->fParent = t1;
+ r = u1;
+ } else {
+ /* the USR override data wasn't found, set it to be deleted */
+ u1->fCountExisting = 0;
+ }
+ }
+ }
+ while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.noFallback) {
+ /* insert regular parents */
+ t2 = init_entry(name, t1->fPath, &parentStatus);
+ if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */
+ usrStatus = U_ZERO_ERROR;
+ u2 = init_entry(name, usrDataPath, &usrStatus);
+ }
+ /* Check for null pointer. */
+ if (t2 == NULL || ( usingUSRData && u2 == NULL)) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto finishUnlock;
+ }
+
+ if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
+ if ( usingUSRData && u2->fBogus == U_ZERO_ERROR ) {
+ t1->fParent = u2;
+ u2->fParent = t2;
+ } else {
+ t1->fParent = t2;
+ if(usingUSRData) {
+ /* the USR override data wasn't found, set it to be deleted */
+ u2->fCountExisting = 0;
+ }
+ }
+ t1 = t2;
+ } else {
+ if (usingUSRData) {
+ /* the USR override data wasn't found, set it to be deleted */
+ u2->fCountExisting = 0;
+ }
+ /* t2->fCountExisting have to be decremented since the call to init_entry increments
+ * it and if we hit this code, that means it is not set as the parent.
+ */
+ t2->fCountExisting--;
+ }
hasChopped = chopLocale(name);
}
- }
- }
+ }
- /* we could still have r == NULL at this point - maybe even default locale is not */
- /* present */
- if(r == NULL) {
- uprv_strcpy(name, kRootLocaleName);
- r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
- if(r != NULL) {
- t1 = r;
- intStatus = U_USING_DEFAULT_WARNING;
- hasRealData = TRUE;
- } else { /* we don't even have the root locale */
- *status = U_MISSING_RESOURCE_ERROR;
+ /* we could have reached this point without having any real data */
+ /* if that is the case, we need to chain in the default locale */
+ if(r==NULL && !isDefault && !isRoot /*&& t1->fParent == NULL*/) {
+ /* insert default locale */
+ uprv_strcpy(name, uloc_getDefault());
+ r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+ intStatus = U_USING_DEFAULT_WARNING;
+ if(r != NULL) { /* the default locale exists */
+ t1 = r;
+ hasRealData = TRUE;
+ isDefault = TRUE;
+ while (hasChopped && t1->fParent == NULL) {
+ /* insert chopped defaults */
+ t2 = init_entry(name, t1->fPath, &parentStatus);
+ /* Check for null pointer. */
+ if (t2 == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto finishUnlock;
+ }
+
+ if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
+ t1->fParent = t2;
+ t1 = t2;
+ }
+ hasChopped = chopLocale(name);
+ }
+ }
}
- } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL) {
- /* insert root locale */
- t2 = init_entry(kRootLocaleName, r->fPath, &parentStatus);
- if(!hasRealData) {
- r->fBogus = U_USING_DEFAULT_WARNING;
- }
- hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) | hasRealData);
- t1->fParent = t2;
- t1 = t2;
- }
- while(r != NULL && !isRoot && t1->fParent != NULL) {
- t1->fParent->fCountExisting++;
- t1 = t1->fParent;
- hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) | hasRealData);
- }
+ /* we could still have r == NULL at this point - maybe even default locale is not */
+ /* present */
+ if(r == NULL) {
+ uprv_strcpy(name, kRootLocaleName);
+ r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+ if(r != NULL) {
+ t1 = r;
+ intStatus = U_USING_DEFAULT_WARNING;
+ hasRealData = TRUE;
+ } else { /* we don't even have the root locale */
+ *status = U_MISSING_RESOURCE_ERROR;
+ goto finishUnlock;
+ }
+ } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL && !r->fData.noFallback) {
+ /* insert root locale */
+ t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus);
+ /* Check for null pointer. */
+ if (t2 == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto finishUnlock;
+ }
+ if(!hasRealData) {
+ r->fBogus = U_USING_DEFAULT_WARNING;
+ }
+ hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) || hasRealData);
+ t1->fParent = t2;
+ t1 = t2;
+ }
+
+ while(r != NULL && !isRoot && t1->fParent != NULL) {
+ t1->fParent->fCountExisting++;
+ t1 = t1->fParent;
+ hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) || hasRealData);
+ }
} /* umtx_lock */
+finishUnlock:
umtx_unlock(&resbMutex);
if(U_SUCCESS(*status)) {
- if(U_SUCCESS(parentStatus)) {
- if(intStatus != U_ZERO_ERROR) {
- *status = intStatus;
+ if(U_SUCCESS(parentStatus)) {
+ if(intStatus != U_ZERO_ERROR) {
+ *status = intStatus;
+ }
+ return r;
+ } else {
+ *status = parentStatus;
+ return NULL;
}
- return r;
- } else {
- *status = parentStatus;
- return NULL;
- }
} else {
- return NULL;
+ return NULL;
}
}
p = resB->fParent;
resB->fCountExisting--;
- /* Entries are left in the cache. TODO: add ures_cacheFlush() to force a flush
+ /* Entries are left in the cache. TODO: add ures_flushCache() to force a flush
of the cache. */
/*
if(resB->fCountExisting <= 0) {
umtx_unlock(&resbMutex);
}
+/*
+U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
+ if(resB->fResPath == NULL) {
+ resB->fResPath = resB->fResBuf;
+ *(resB->fResPath) = 0;
+ }
+ resB->fResPathLen = uprv_strlen(toAdd);
+ if(RES_BUFSIZE <= resB->fResPathLen+1) {
+ if(resB->fResPath == resB->fResBuf) {
+ resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
+ } else {
+ resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+ }
+ }
+ uprv_strcpy(resB->fResPath, toAdd);
+}
+*/
+static void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd, UErrorCode *status) {
+ int32_t resPathLenOrig = resB->fResPathLen;
+ if(resB->fResPath == NULL) {
+ resB->fResPath = resB->fResBuf;
+ *(resB->fResPath) = 0;
+ resB->fResPathLen = 0;
+ }
+ resB->fResPathLen += lenToAdd;
+ if(RES_BUFSIZE <= resB->fResPathLen+1) {
+ if(resB->fResPath == resB->fResBuf) {
+ resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
+ /* Check that memory was allocated correctly. */
+ if (resB->fResPath == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_strcpy(resB->fResPath, resB->fResBuf);
+ } else {
+ char *temp = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+ /* Check that memory was reallocated correctly. */
+ if (temp == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ resB->fResPath = temp;
+ }
+ }
+ uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd);
+}
+
+static void ures_freeResPath(UResourceBundle *resB) {
+ if (resB->fResPath && resB->fResPath != resB->fResBuf) {
+ uprv_free(resB->fResPath);
+ }
+ resB->fResPath = NULL;
+ resB->fResPathLen = 0;
+}
+
+static void
+ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj)
+{
+ if(resB != NULL) {
+ if(resB->fData != NULL) {
+ entryClose(resB->fData);
+ }
+ if(resB->fVersion != NULL) {
+ uprv_free(resB->fVersion);
+ }
+ ures_freeResPath(resB);
+
+ if(ures_isStackObject(resB) == FALSE && freeBundleObj) {
+ uprv_free(resB);
+ }
+#if 0 /*U_DEBUG*/
+ else {
+ /* poison the data */
+ uprv_memset(resB, -1, sizeof(UResourceBundle));
+ }
+#endif
+ }
+}
+
+U_CAPI void U_EXPORT2
+ures_close(UResourceBundle* resB)
+{
+ ures_closeBundle(resB, TRUE);
+}
+
static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
- const char *key, int32_t index, UResourceDataEntry *realData,
+ const char *key, int32_t idx, UResourceDataEntry *realData,
const UResourceBundle *parent, int32_t noAlias,
UResourceBundle *resB, UErrorCode *status)
{
if(status == NULL || U_FAILURE(*status)) {
return resB;
}
+ if (parent == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
if(RES_GET_TYPE(r) == URES_ALIAS) { /* This is an alias, need to exchange with real data */
- if(noAlias < URES_MAX_ALIAS_LEVEL) {
- int32_t len = 0;
- const UChar *alias = res_getAlias(rdata, r, &len);
- if(len > 0) {
- /* we have an alias, now let's cut it up */
- char stackAlias[200];
- char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = NULL;
- int32_t capacity;
-
- /*
- * Allocate enough space for both the char * version
- * of the alias and parent->fResPath.
- *
- * We do this so that res_findResource() can modify the path,
- * which allows us to remove redundant _res_findResource() variants
- * in uresdata.c.
- * res_findResource() now NUL-terminates each segment so that table keys
- * can always be compared with strcmp() instead of strncmp().
- * Saves code there and simplifies testing and code coverage.
- *
- * markus 2003oct17
- */
- ++len; /* count the terminating NUL */
- if(parent != NULL && parent->fResPath != NULL) {
- capacity = uprv_strlen(parent->fResPath) + 1;
- } else {
- capacity = 0;
- }
- if(capacity < len) {
- capacity = len;
- }
- if(capacity <= sizeof(stackAlias)) {
- capacity = sizeof(stackAlias);
- chAlias = stackAlias;
- } else {
- chAlias = (char *)uprv_malloc(capacity);
- /* test for NULL */
- if(chAlias == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- }
- u_UCharsToChars(alias, chAlias, len);
-
- if(*chAlias == RES_PATH_SEPARATOR) {
- /* there is a path included */
- locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR);
- if(locale == NULL) {
- locale = uprv_strchr(chAlias, 0); /* avoid locale == NULL to make code below work */
- } else {
- *locale = 0;
- locale++;
- }
- path = chAlias+1;
- if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */
- path = NULL;
- }
- } else {
- /* no path, start with a locale */
- locale = chAlias;
- path = realData->fPath;
- }
- keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
- if(keyPath) {
- *keyPath = 0;
- keyPath++;
- }
- {
- /* got almost everything, let's try to open */
- /* first, open the bundle with real data */
- UResourceBundle *result = resB;
- const char* temp = NULL;
- UErrorCode intStatus = U_ZERO_ERROR;
- UResourceBundle *mainRes = ures_openDirect(path, locale, &intStatus);
- if(U_SUCCESS(intStatus)) {
- if(keyPath == NULL) {
- /* no key path. This means that we are going to
- * to use the corresponding resource from
- * another bundle
- */
- /* first, we are going to get a corresponding parent
- * resource to the one we are searching.
- */
- char *aKey = parent->fResPath;
- if(aKey) {
- uprv_strcpy(chAlias, aKey); /* allocated large enough above */
- aKey = chAlias;
- r = res_findResource(&(mainRes->fResData), mainRes->fRes, &aKey, &temp);
+ if(noAlias < URES_MAX_ALIAS_LEVEL) {
+ int32_t len = 0;
+ const UChar *alias = res_getAlias(rdata, r, &len);
+ if(len > 0) {
+ /* we have an alias, now let's cut it up */
+ char stackAlias[200];
+ char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = NULL;
+ int32_t capacity;
+
+ /*
+ * Allocate enough space for both the char * version
+ * of the alias and parent->fResPath.
+ *
+ * We do this so that res_findResource() can modify the path,
+ * which allows us to remove redundant _res_findResource() variants
+ * in uresdata.c.
+ * res_findResource() now NUL-terminates each segment so that table keys
+ * can always be compared with strcmp() instead of strncmp().
+ * Saves code there and simplifies testing and code coverage.
+ *
+ * markus 2003oct17
+ */
+ ++len; /* count the terminating NUL */
+ if(parent->fResPath != NULL) {
+ capacity = (int32_t)uprv_strlen(parent->fResPath) + 1;
} else {
- r = mainRes->fRes;
+ capacity = 0;
}
- if(key) {
- /* we need to make keyPath from parent's fResPath and
- * current key, if there is a key associated
- */
- len = uprv_strlen(key) + 1;
- if(len > capacity) {
+ if(capacity < len) {
capacity = len;
- if(chAlias == stackAlias) {
- chAlias = (char *)uprv_malloc(capacity);
- } else {
- chAlias = (char *)uprv_realloc(chAlias, capacity);
- }
+ }
+ if(capacity <= sizeof(stackAlias)) {
+ capacity = sizeof(stackAlias);
+ chAlias = stackAlias;
+ } else {
+ chAlias = (char *)uprv_malloc(capacity);
+ /* test for NULL */
if(chAlias == NULL) {
- ures_close(mainRes);
- *status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
}
- }
- uprv_memcpy(chAlias, key, len);
- aKey = chAlias;
- r = res_findResource(&(mainRes->fResData), r, &aKey, &temp);
- } else if(index != -1) {
- /* if there is no key, but there is an index, try to get by the index */
- /* here we have either a table or an array, so get the element */
- if(RES_GET_TYPE(r) == URES_TABLE || RES_GET_TYPE(r) == URES_TABLE32) {
- r = res_getTableItemByIndex(&(mainRes->fResData), r, index, (const char **)&aKey);
- } else { /* array */
- r = res_getArrayItem(&(mainRes->fResData), r, index);
- }
}
- if(r != RES_BOGUS) {
- result = init_resb_result(&(mainRes->fResData), r, key, -1, mainRes->fData, parent, noAlias+1, resB, status);
+ u_UCharsToChars(alias, chAlias, len);
+
+ if(*chAlias == RES_PATH_SEPARATOR) {
+ /* there is a path included */
+ locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR);
+ if(locale == NULL) {
+ locale = uprv_strchr(chAlias, 0); /* avoid locale == NULL to make code below work */
+ } else {
+ *locale = 0;
+ locale++;
+ }
+ path = chAlias+1;
+ if(uprv_strcmp(path, "LOCALE") == 0) {
+ /* this is an XPath alias, starting with "/LOCALE/" */
+ /* it contains the path to a resource which should be looked up */
+ /* starting in the requested locale */
+ keyPath = locale;
+ locale = parent->fTopLevelData->fName; /* this is the requested locale's name */
+ path = realData->fPath; /* we will be looking in the same package */
+ } else {
+ if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */
+ path = NULL;
+ }
+ keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
+ if(keyPath) {
+ *keyPath = 0;
+ keyPath++;
+ }
+ }
} else {
- *status = U_MISSING_RESOURCE_ERROR;
- result = resB;
+ /* no path, start with a locale */
+ locale = chAlias;
+ keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
+ if(keyPath) {
+ *keyPath = 0;
+ keyPath++;
+ }
+ path = realData->fPath;
}
- } else {
- /* this one is a bit trickier.
- * we start finding keys, but after we resolve one alias, the path might continue.
- * Consider:
- * aliastest:alias { "testtypes/anotheralias/Sequence" }
- * anotheralias:alias { "/ICUDATA/sh/CollationElements" }
- * aliastest resource should finally have the sequence, not collation elements.
- */
- result = mainRes;
- while(*keyPath && U_SUCCESS(*status)) {
- r = res_findResource(&(result->fResData), result->fRes, &keyPath, &temp);
- if(r == RES_BOGUS) {
- *status = U_MISSING_RESOURCE_ERROR;
- result = resB;
- break;
- }
- resB = init_resb_result(&(result->fResData), r, key, -1, result->fData, parent, noAlias+1, resB, status);
- result = resB;
+
+
+ {
+ /* got almost everything, let's try to open */
+ /* first, open the bundle with real data */
+ UResourceBundle *result = resB;
+ const char* temp = NULL;
+ UErrorCode intStatus = U_ZERO_ERROR;
+ UResourceBundle *mainRes = ures_openDirect(path, locale, &intStatus);
+ if(U_SUCCESS(intStatus)) {
+ if(keyPath == NULL) {
+ /* no key path. This means that we are going to
+ * to use the corresponding resource from
+ * another bundle
+ */
+ /* first, we are going to get a corresponding parent
+ * resource to the one we are searching.
+ */
+ char *aKey = parent->fResPath;
+ if(aKey) {
+ uprv_strcpy(chAlias, aKey); /* allocated large enough above */
+ aKey = chAlias;
+ r = res_findResource(&(mainRes->fResData), mainRes->fRes, &aKey, &temp);
+ } else {
+ r = mainRes->fRes;
+ }
+ if(key) {
+ /* we need to make keyPath from parent's fResPath and
+ * current key, if there is a key associated
+ */
+ len = (int32_t)(uprv_strlen(key) + 1);
+ if(len > capacity) {
+ capacity = len;
+ if(chAlias == stackAlias) {
+ chAlias = (char *)uprv_malloc(capacity);
+ } else {
+ chAlias = (char *)uprv_realloc(chAlias, capacity);
+ }
+ if(chAlias == NULL) {
+ ures_close(mainRes);
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ }
+ uprv_memcpy(chAlias, key, len);
+ aKey = chAlias;
+ r = res_findResource(&(mainRes->fResData), r, &aKey, &temp);
+ } else if(idx != -1) {
+ /* if there is no key, but there is an index, try to get by the index */
+ /* here we have either a table or an array, so get the element */
+ UResType type = RES_GET_TYPE(r);
+ if(URES_IS_TABLE(type)) {
+ r = res_getTableItemByIndex(&(mainRes->fResData), r, idx, (const char **)&aKey);
+ } else { /* array */
+ r = res_getArrayItem(&(mainRes->fResData), r, idx);
+ }
+ }
+ if(r != RES_BOGUS) {
+ result = init_resb_result(&(mainRes->fResData), r, temp, -1, mainRes->fData, mainRes, noAlias+1, resB, status);
+ } else {
+ *status = U_MISSING_RESOURCE_ERROR;
+ result = resB;
+ }
+ } else {
+ /* this one is a bit trickier.
+ * we start finding keys, but after we resolve one alias, the path might continue.
+ * Consider:
+ * aliastest:alias { "testtypes/anotheralias/Sequence" }
+ * anotheralias:alias { "/ICUDATA/sh/CollationElements" }
+ * aliastest resource should finally have the sequence, not collation elements.
+ */
+ UResourceDataEntry *dataEntry = mainRes->fData;
+ char stackPath[URES_MAX_BUFFER_SIZE];
+ char *pathBuf = stackPath, *myPath = pathBuf;
+ if(uprv_strlen(keyPath) > URES_MAX_BUFFER_SIZE) {
+ pathBuf = (char *)uprv_malloc((uprv_strlen(keyPath)+1)*sizeof(char));
+ if(pathBuf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ }
+ uprv_strcpy(pathBuf, keyPath);
+ result = mainRes;
+ /* now we have fallback following here */
+ do {
+ r = dataEntry->fData.rootRes;
+ /* this loop handles 'found' resources over several levels */
+ while(*myPath && U_SUCCESS(*status)) {
+ r = res_findResource(&(dataEntry->fData), r, &myPath, &temp);
+ if(r != RES_BOGUS) { /* found a resource, but it might be an indirection */
+ resB = init_resb_result(&(dataEntry->fData), r, temp, -1, dataEntry, result, noAlias+1, resB, status);
+ result = resB;
+ if(result) {
+ r = result->fRes; /* switch to a new resource, possibly a new tree */
+ dataEntry = result->fData;
+ }
+ } else { /* no resource found, we don't really want to look anymore on this level */
+ break;
+ }
+ }
+ dataEntry = dataEntry->fParent;
+ uprv_strcpy(pathBuf, keyPath);
+ myPath = pathBuf;
+ } while(r == RES_BOGUS && dataEntry != NULL);
+ if(r == RES_BOGUS) {
+ *status = U_MISSING_RESOURCE_ERROR;
+ result = resB;
+ }
+ if(pathBuf != stackPath) {
+ uprv_free(pathBuf);
+ }
+ }
+ } else { /* we failed to open the resource we're aliasing to */
+ *status = intStatus;
+ }
+ if(chAlias != stackAlias) {
+ uprv_free(chAlias);
+ }
+ if(mainRes != result) {
+ ures_close(mainRes);
+ }
+ return result;
}
- }
- } else { /* we failed to open the resource we're aliasing to */
- *status = intStatus;
- }
- if(chAlias != stackAlias) {
- uprv_free(chAlias);
- }
- if(mainRes != result) {
- ures_close(mainRes);
+ } else {
+ /* bad alias, should be an error */
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return resB;
}
- return result;
- }
} else {
- /* bad alias, should be an error */
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return resB;
+ *status = U_TOO_MANY_ALIASES_ERROR;
+ return resB;
}
- } else {
- *status = U_TOO_MANY_ALIASES_ERROR;
- return resB;
- }
}
if(resB == NULL) {
resB = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
if(resB->fVersion != NULL) {
uprv_free(resB->fVersion);
}
+ /*
+ weiv: if stack object was passed in, it doesn't really need to be reinited,
+ since the purpose of initing is to remove stack junk. However, at this point
+ we would not do anything to an allocated object, so stack object should be
+ treated the same
+ */
+ /*
if(ures_isStackObject(resB) != FALSE) {
- ures_initStackObject(resB);
+ ures_initStackObject(resB);
}
+ */
if(parent != resB) {
ures_freeResPath(resB);
}
resB->fHasFallback = FALSE;
resB->fIsTopLevel = FALSE;
resB->fIndex = -1;
- resB->fKey = key;
- resB->fParentRes = parent;
+ resB->fKey = key;
+ /*resB->fParentRes = parent;*/
resB->fTopLevelData = parent->fTopLevelData;
if(parent->fResPath && parent != resB) {
- ures_appendResPath(resB, parent->fResPath, parent->fResPathLen);
+ ures_appendResPath(resB, parent->fResPath, parent->fResPathLen, status);
}
if(key != NULL) {
- ures_appendResPath(resB, key, uprv_strlen(key));
- ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1);
- } else {
- char buf[256];
- int32_t len = T_CString_integerToString(buf, index, 10);
- ures_appendResPath(resB, buf, len);
- ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1);
+ ures_appendResPath(resB, key, (int32_t)uprv_strlen(key), status);
+ if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
+ ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status);
+ }
+ } else if(idx >= 0) {
+ char buf[256];
+ int32_t len = T_CString_integerToString(buf, idx, 10);
+ ures_appendResPath(resB, buf, len, status);
+ if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
+ ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status);
+ }
+ }
+ /* Make sure that Purify doesn't complain about uninitialized memory copies. */
+ {
+ int32_t usedLen = ((resB->fResBuf == resB->fResPath) ? resB->fResPathLen : 0);
+ uprv_memset(resB->fResBuf + usedLen, 0, sizeof(resB->fResBuf) - usedLen);
}
resB->fVersion = NULL;
resB->fRes = r;
/*resB->fParent = parent->fRes;*/
- resB->fResData.data = rdata->data;
- resB->fResData.pRoot = rdata->pRoot;
- resB->fResData.rootRes = rdata->rootRes;
+ uprv_memmove(&resB->fResData, rdata, sizeof(ResourceData));
resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes);
return resB;
}
}
} else {
isStackObject = ures_isStackObject(r);
- if(U_FAILURE(*status)) {
- return r;
- }
- ures_close(r);
- if(isStackObject == FALSE) {
- r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
- /* test for NULL */
- if (r == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- }
+ ures_closeBundle(r, FALSE);
}
uprv_memcpy(r, original, sizeof(UResourceBundle));
r->fResPath = NULL;
r->fResPathLen = 0;
if(original->fResPath) {
- ures_appendResPath(r, original->fResPath, original->fResPathLen);
+ ures_appendResPath(r, original->fResPath, original->fResPathLen, status);
}
ures_setIsStackObject(r, isStackObject);
if(r->fData != NULL) {
- entryIncrease(r->fData);
+ entryIncrease(r->fData);
}
- return r;
- } else {
- return r;
}
+ return r;
}
/**
*/
U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_t* len, UErrorCode* status) {
-
+ const UChar *s;
if (status==NULL || U_FAILURE(*status)) {
return NULL;
}
*status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
+ s = res_getString(&(resB->fResData), resB->fRes, len);
+ if (s == NULL) {
+ *status = U_RESOURCE_TYPE_MISMATCH;
+ }
+ return s;
+}
- switch(RES_GET_TYPE(resB->fRes)) {
- case URES_STRING:
- return res_getString(&(resB->fResData), resB->fRes, len);
- case URES_INT:
- case URES_INT_VECTOR:
- case URES_BINARY:
- case URES_ARRAY:
- case URES_TABLE:
- case URES_TABLE32:
- default:
- *status = U_RESOURCE_TYPE_MISMATCH;
+static const char *
+ures_toUTF8String(const UChar *s16, int32_t length16,
+ char *dest, int32_t *pLength,
+ UBool forceCopy,
+ UErrorCode *status) {
+ int32_t capacity;
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if (pLength != NULL) {
+ capacity = *pLength;
+ } else {
+ capacity = 0;
+ }
+ if (capacity < 0 || (capacity > 0 && dest == NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
}
- return NULL;
+ if (length16 == 0) {
+ /* empty string, return as read-only pointer */
+ if (pLength != NULL) {
+ *pLength = 0;
+ }
+ if (forceCopy) {
+ u_terminateChars(dest, capacity, 0, status);
+ return dest;
+ } else {
+ return "";
+ }
+ } else {
+ /* We need to transform the string to the destination buffer. */
+ if (capacity < length16) {
+ /* No chance for the string to fit. Pure preflighting. */
+ return u_strToUTF8(NULL, 0, pLength, s16, length16, status);
+ }
+ if (!forceCopy && (length16 <= 0x2aaaaaaa)) {
+ /*
+ * We know the string will fit into dest because each UChar turns
+ * into at most three UTF-8 bytes. Fill the latter part of dest
+ * so that callers do not expect to use dest as a string pointer,
+ * hopefully leading to more robust code for when resource bundles
+ * may store UTF-8 natively.
+ * (In which case dest would not be used at all.)
+ *
+ * We do not do this if forceCopy=TRUE because then the caller
+ * expects the string to start exactly at dest.
+ *
+ * The test above for <= 0x2aaaaaaa prevents overflows.
+ * The +1 is for the NUL terminator.
+ */
+ int32_t maxLength = 3 * length16 + 1;
+ if (capacity > maxLength) {
+ dest += capacity - maxLength;
+ capacity = maxLength;
+ }
+ }
+ return u_strToUTF8(dest, capacity, pLength, s16, length16, status);
+ }
+}
+
+U_CAPI const char * U_EXPORT2
+ures_getUTF8String(const UResourceBundle *resB,
+ char *dest, int32_t *pLength,
+ UBool forceCopy,
+ UErrorCode *status) {
+ int32_t length16;
+ const UChar *s16 = ures_getString(resB, &length16, status);
+ return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
}
U_CAPI const uint8_t* U_EXPORT2 ures_getBinary(const UResourceBundle* resB, int32_t* len,
UErrorCode* status) {
+ const uint8_t *p;
if (status==NULL || U_FAILURE(*status)) {
return NULL;
}
*status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
- switch(RES_GET_TYPE(resB->fRes)) {
- case URES_BINARY:
- return res_getBinary(&(resB->fResData), resB->fRes, len);
- case URES_INT:
- case URES_STRING:
- case URES_INT_VECTOR:
- case URES_ARRAY:
- case URES_TABLE:
- case URES_TABLE32:
- default:
+ p = res_getBinary(&(resB->fResData), resB->fRes, len);
+ if (p == NULL) {
*status = U_RESOURCE_TYPE_MISMATCH;
}
-
- return NULL;
+ return p;
}
U_CAPI const int32_t* U_EXPORT2 ures_getIntVector(const UResourceBundle* resB, int32_t* len,
UErrorCode* status) {
+ const int32_t *p;
if (status==NULL || U_FAILURE(*status)) {
return NULL;
}
*status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
- switch(RES_GET_TYPE(resB->fRes)) {
- case URES_INT_VECTOR:
- return res_getIntVector(&(resB->fResData), resB->fRes, len);
- case URES_INT:
- case URES_STRING:
- case URES_ARRAY:
- case URES_BINARY:
- case URES_TABLE:
- case URES_TABLE32:
- default:
+ p = res_getIntVector(&(resB->fResData), resB->fRes, len);
+ if (p == NULL) {
*status = U_RESOURCE_TYPE_MISMATCH;
}
-
- return NULL;
+ return p;
}
/* this function returns a signed integer */
return RES_GET_UINT(resB->fRes);
}
-
U_CAPI UResType U_EXPORT2 ures_getType(const UResourceBundle *resB) {
- UResType type;
-
if(resB == NULL) {
return URES_NONE;
}
- type = (UResType) RES_GET_TYPE(resB->fRes);
- return type == URES_TABLE32 ? URES_TABLE : type;
+ return res_getPublicType(resB->fRes);
}
U_CAPI const char * U_EXPORT2 ures_getKey(const UResourceBundle *resB) {
} else {
resB->fIndex++;
switch(RES_GET_TYPE(resB->fRes)) {
- case URES_INT:
- case URES_BINARY:
case URES_STRING:
+ case URES_STRING_V2:
return res_getString(&(resB->fResData), resB->fRes, len);
case URES_TABLE:
+ case URES_TABLE16:
case URES_TABLE32:
r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, key);
if(r == RES_BOGUS && resB->fHasFallback) {
}
return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
case URES_ARRAY:
+ case URES_ARRAY16:
r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
if(r == RES_BOGUS && resB->fHasFallback) {
/* TODO: do the fallback */
return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
case URES_ALIAS:
return ures_getStringWithAlias(resB, resB->fRes, resB->fIndex, len, status);
+ case URES_INT:
+ case URES_BINARY:
case URES_INT_VECTOR:
+ *status = U_RESOURCE_TYPE_MISMATCH;
default:
return NULL;
- break;
}
}
case URES_INT:
case URES_BINARY:
case URES_STRING:
+ case URES_STRING_V2:
+ case URES_INT_VECTOR:
return ures_copyResb(fillIn, resB, status);
case URES_TABLE:
+ case URES_TABLE16:
case URES_TABLE32:
r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, &key);
if(r == RES_BOGUS && resB->fHasFallback) {
}
return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status);
case URES_ARRAY:
+ case URES_ARRAY16:
r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
if(r == RES_BOGUS && resB->fHasFallback) {
/* TODO: do the fallback */
}
return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status);
- case URES_INT_VECTOR:
default:
/*return NULL;*/
return fillIn;
case URES_INT:
case URES_BINARY:
case URES_STRING:
+ case URES_STRING_V2:
+ case URES_INT_VECTOR:
return ures_copyResb(fillIn, resB, status);
case URES_TABLE:
+ case URES_TABLE16:
case URES_TABLE32:
r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexR, &key);
if(r == RES_BOGUS && resB->fHasFallback) {
}
return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status);
case URES_ARRAY:
+ case URES_ARRAY16:
r = res_getArrayItem(&(resB->fResData), resB->fRes, indexR);
if(r == RES_BOGUS && resB->fHasFallback) {
/* TODO: do the fallback */
}
return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status);
- case URES_INT_VECTOR:
default:
/*return NULL;*/
return fillIn;
if(indexS >= 0 && resB->fSize > indexS) {
switch(RES_GET_TYPE(resB->fRes)) {
- case URES_INT:
- case URES_BINARY:
case URES_STRING:
+ case URES_STRING_V2:
return res_getString(&(resB->fResData), resB->fRes, len);
case URES_TABLE:
+ case URES_TABLE16:
case URES_TABLE32:
r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexS, &key);
if(r == RES_BOGUS && resB->fHasFallback) {
}
return ures_getStringWithAlias(resB, r, indexS, len, status);
case URES_ARRAY:
+ case URES_ARRAY16:
r = res_getArrayItem(&(resB->fResData), resB->fRes, indexS);
if(r == RES_BOGUS && resB->fHasFallback) {
/* TODO: do the fallback */
}
return ures_getStringWithAlias(resB, r, indexS, len, status);
case URES_ALIAS:
- return ures_getStringWithAlias(resB, resB->fRes, indexS, len, status);
-
- /*case URES_INT_VECTOR:*/
- /*default:*/
- /*return;*/
+ return ures_getStringWithAlias(resB, resB->fRes, indexS, len, status);
+ case URES_INT:
+ case URES_BINARY:
+ case URES_INT_VECTOR:
+ *status = U_RESOURCE_TYPE_MISMATCH;
+ break;
+ default:
+ /* must not occur */
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ break;
}
} else {
*status = U_MISSING_RESOURCE_ERROR;
return NULL;
}
+U_CAPI const char * U_EXPORT2
+ures_getUTF8StringByIndex(const UResourceBundle *resB,
+ int32_t idx,
+ char *dest, int32_t *pLength,
+ UBool forceCopy,
+ UErrorCode *status) {
+ int32_t length16;
+ const UChar *s16 = ures_getStringByIndex(resB, idx, &length16, status);
+ return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
+
/*U_CAPI const char *ures_getResPath(UResourceBundle *resB) {
return resB->fResPath;
}*/
UResourceBundle *first = NULL;
UResourceBundle *result = fillIn;
char *packageName = NULL;
- char *pathToResource = NULL;
+ char *pathToResource = NULL, *save = NULL;
char *locale = NULL, *localeEnd = NULL;
int32_t length;
return result;
}
- length = uprv_strlen(path)+1;
- pathToResource = (char *)uprv_malloc(length*sizeof(char));
+ length = (int32_t)(uprv_strlen(path)+1);
+ save = pathToResource = (char *)uprv_malloc(length*sizeof(char));
/* test for NULL */
if(pathToResource == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
}
ures_close(first);
}
- uprv_free(pathToResource);
+ uprv_free(save);
return result;
}
*status = U_MISSING_RESOURCE_ERROR;
break;
}
- } while(uprv_strlen(path)); /* there is more stuff in the path */
+ } while(*path); /* there is more stuff in the path */
return result;
}
+U_INTERNAL const UChar* U_EXPORT2
+ures_getStringByKeyWithFallback(const UResourceBundle *resB,
+ const char* inKey,
+ int32_t* len,
+ UErrorCode *status) {
+
+ UResourceBundle stack;
+ const UChar* retVal = NULL;
+ ures_initStackObject(&stack);
+ ures_getByKeyWithFallback(resB, inKey, &stack, status);
+ retVal = ures_getString(&stack, len, status);
+ ures_close(&stack);
+ return retVal;
+}
U_CAPI UResourceBundle* U_EXPORT2
ures_getByKeyWithFallback(const UResourceBundle *resB,
const char* inKey,
UResourceBundle *fillIn,
UErrorCode *status) {
- Resource res = RES_BOGUS;
+ Resource res = RES_BOGUS, rootRes = RES_BOGUS;
/*UResourceDataEntry *realData = NULL;*/
const char *key = inKey;
UResourceBundle *helper = NULL;
+ UResType type;
if (status==NULL || U_FAILURE(*status)) {
return fillIn;
return fillIn;
}
- if(RES_GET_TYPE(resB->fRes) == URES_TABLE || RES_GET_TYPE(resB->fRes) == URES_TABLE32) {
+ type = RES_GET_TYPE(resB->fRes);
+ if(URES_IS_TABLE(type)) {
int32_t t;
res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
if(res == RES_BOGUS) {
UResourceDataEntry *dataEntry = resB->fData;
char path[256];
char* myPath = path;
+ const char* resPath = resB->fResPath;
+ int32_t len = resB->fResPathLen;
while(res == RES_BOGUS && dataEntry->fParent != NULL) { /* Otherwise, we'll look in parents */
dataEntry = dataEntry->fParent;
+ rootRes = dataEntry->fData.rootRes;
+
if(dataEntry->fBogus == U_ZERO_ERROR) {
- uprv_strncpy(path, resB->fResPath, resB->fResPathLen);
- uprv_strcpy(path+resB->fResPathLen, inKey);
+ uprv_strncpy(path, resPath, len);
+ uprv_strcpy(path+len, inKey);
myPath = path;
key = inKey;
do {
- res = res_findResource(&(dataEntry->fData), dataEntry->fData.rootRes, &myPath, &key);
+ res = res_findResource(&(dataEntry->fData), rootRes, &myPath, &key);
if (RES_GET_TYPE(res) == URES_ALIAS && *myPath) {
/* We hit an alias, but we didn't finish following the path. */
- helper = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, helper, status);
- dataEntry = helper->fData;
+ helper = init_resb_result(&(dataEntry->fData), res, NULL, -1, dataEntry, resB, 0, helper, status);
+ /*helper = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, helper, status);*/
+ if(helper) {
+ dataEntry = helper->fData;
+ rootRes = helper->fRes;
+ resPath = helper->fResPath;
+ len = helper->fResPathLen;
+
+ } else {
+ break;
+ }
}
- } while(uprv_strlen(myPath));
+ } while(*myPath); /* Continue until the whole path is consumed */
}
}
/*const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);*/
if(res != RES_BOGUS) {
/* check if resB->fResPath gives the right name here */
+ if(uprv_strcmp(dataEntry->fName, uloc_getDefault())==0 || uprv_strcmp(dataEntry->fName, kRootLocaleName)==0) {
+ *status = U_USING_DEFAULT_WARNING;
+ } else {
+ *status = U_USING_FALLBACK_WARNING;
+ }
+
fillIn = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, fillIn, status);
} else {
*status = U_MISSING_RESOURCE_ERROR;
Resource res = RES_BOGUS;
UResourceDataEntry *realData = NULL;
const char *key = inKey;
+ UResType type;
if (status==NULL || U_FAILURE(*status)) {
return fillIn;
return fillIn;
}
- if(RES_GET_TYPE(resB->fRes) == URES_TABLE || RES_GET_TYPE(resB->fRes) == URES_TABLE32) {
+ type = RES_GET_TYPE(resB->fRes);
+ if(URES_IS_TABLE(type)) {
int32_t t;
res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
if(res == RES_BOGUS) {
Resource res = RES_BOGUS;
UResourceDataEntry *realData = NULL;
const char* key = inKey;
+ UResType type;
if (status==NULL || U_FAILURE(*status)) {
return NULL;
return NULL;
}
- if(RES_GET_TYPE(resB->fRes) == URES_TABLE || RES_GET_TYPE(resB->fRes) == URES_TABLE32) {
+ type = RES_GET_TYPE(resB->fRes);
+ if(URES_IS_TABLE(type)) {
int32_t t=0;
res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
if(U_SUCCESS(*status)) {
switch (RES_GET_TYPE(res)) {
case URES_STRING:
- case URES_TABLE:
- case URES_TABLE32:
- case URES_ARRAY:
+ case URES_STRING_V2:
return res_getString(rd, res, len);
case URES_ALIAS:
{
} else {
switch (RES_GET_TYPE(res)) {
case URES_STRING:
- case URES_TABLE:
- case URES_TABLE32:
- case URES_ARRAY:
+ case URES_STRING_V2:
return res_getString(&(resB->fResData), res, len);
case URES_ALIAS:
{
return NULL;
}
+U_CAPI const char * U_EXPORT2
+ures_getUTF8StringByKey(const UResourceBundle *resB,
+ const char *key,
+ char *dest, int32_t *pLength,
+ UBool forceCopy,
+ UErrorCode *status) {
+ int32_t length16;
+ const UChar *s16 = ures_getStringByKey(resB, key, &length16, status);
+ return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
/* TODO: clean from here down */
* INTERNAL: Get the name of the first real locale (not placeholder)
* that has resource bundle data.
*/
-U_CAPI const char* U_EXPORT2
-ures_getLocale(const UResourceBundle* resourceBundle, UErrorCode* status)
+U_INTERNAL const char* U_EXPORT2
+ures_getLocaleInternal(const UResourceBundle* resourceBundle, UErrorCode* status)
{
if (status==NULL || U_FAILURE(*status)) {
return NULL;
}
}
+U_CAPI const char* U_EXPORT2
+ures_getLocale(const UResourceBundle* resourceBundle,
+ UErrorCode* status)
+{
+ return ures_getLocaleInternal(resourceBundle, status);
+}
+
+
U_CAPI const char* U_EXPORT2
ures_getLocaleByType(const UResourceBundle* resourceBundle,
ULocDataLocaleType type,
switch(type) {
case ULOC_ACTUAL_LOCALE:
return resourceBundle->fData->fName;
- break;
case ULOC_VALID_LOCALE:
return resourceBundle->fTopLevelData->fName;
- break;
case ULOC_REQUESTED_LOCALE:
return NULL;
- break;
default:
*status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
}
-
-/*
-U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
- if(resB->fResPath == NULL) {
- resB->fResPath = resB->fResBuf;
- *(resB->fResPath) = 0;
- }
- resB->fResPathLen = uprv_strlen(toAdd);
- if(RES_BUFSIZE <= resB->fResPathLen+1) {
- if(resB->fResPath == resB->fResBuf) {
- resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
- } else {
- resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
- }
- }
- uprv_strcpy(resB->fResPath, toAdd);
-}
-*/
-U_CFUNC void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd) {
- int32_t resPathLenOrig = resB->fResPathLen;
- if(resB->fResPath == NULL) {
- resB->fResPath = resB->fResBuf;
- *(resB->fResPath) = 0;
- resB->fResPathLen = 0;
- }
- resB->fResPathLen += lenToAdd;
- if(RES_BUFSIZE <= resB->fResPathLen+1) {
- if(resB->fResPath == resB->fResBuf) {
- resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
- uprv_strcpy(resB->fResPath, resB->fResBuf);
- } else {
- resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
- }
- }
- uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd);
-}
-
-U_CFUNC void ures_freeResPath(UResourceBundle *resB) {
- if (resB->fResPath && resB->fResPath != resB->fResBuf) {
- uprv_free(resB->fResPath);
- }
- resB->fResPath = NULL;
- resB->fResPathLen = 0;
-}
-
-
U_CFUNC const char* ures_getName(const UResourceBundle* resB) {
if(resB == NULL) {
return NULL;
return resB->fData->fName;
}
+#ifdef URES_DEBUG
U_CFUNC const char* ures_getPath(const UResourceBundle* resB) {
if(resB == NULL) {
return NULL;
return resB->fData->fPath;
}
+#endif
/* OLD API implementation */
ures_openFillIn(UResourceBundle *r, const char* path,
const char* localeID, UErrorCode* status) {
if(r == NULL) {
- *status = U_INTERNAL_PROGRAM_ERROR;
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
} else {
UResourceDataEntry *firstData;
+ UBool isStackObject = ures_isStackObject(r);
+
+ ures_closeBundle(r, FALSE);
+ uprv_memset(r, 0, sizeof(UResourceBundle));
+ ures_setIsStackObject(r, isStackObject);
r->fHasFallback = TRUE;
r->fIsTopLevel = TRUE;
- r->fKey = NULL;
- r->fVersion = NULL;
r->fIndex = -1;
- if(r->fData != NULL) {
- entryClose(r->fData);
- }
- if(r->fVersion != NULL) {
- uprv_free(r->fVersion);
- }
r->fData = entryOpen(path, localeID, status);
+ if(U_FAILURE(*status)) {
+ return;
+ }
/* this is a quick fix to get regular data in bundle - until construction is cleaned up */
firstData = r->fData;
while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) {
firstData = firstData->fParent;
}
- r->fResData.data = firstData->fData.data;
- r->fResData.pRoot = firstData->fData.pRoot;
- r->fResData.rootRes = firstData->fData.rootRes;
+ uprv_memcpy(&r->fResData, &firstData->fData, sizeof(ResourceData));
+ r->fHasFallback=(UBool)!r->fResData.noFallback;
r->fRes = r->fResData.rootRes;
r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
- /*r->fParent = RES_BOGUS;*/
- /*r->fResPath = NULL;*/
- r->fParentRes = NULL;
r->fTopLevelData = r->fData;
-
- ures_freeResPath(r);
}
}
char canonLocaleID[100];
UResourceDataEntry *hasData = NULL;
UResourceBundle *r;
- int32_t length;
if(status == NULL || U_FAILURE(*status)) {
return NULL;
}
/* first "canonicalize" the locale ID */
- length = uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
+ uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
return NULL;
}
+ uprv_memset(r, 0, sizeof(UResourceBundle));
r->fHasFallback = TRUE;
r->fIsTopLevel = TRUE;
ures_setIsStackObject(r, FALSE);
- r->fKey = NULL;
- r->fVersion = NULL;
r->fIndex = -1;
r->fData = entryOpen(path, canonLocaleID, status);
if(U_FAILURE(*status)) {
uprv_free(r);
return NULL;
}
- r->fParentRes = NULL;
r->fTopLevelData = r->fData;
hasData = r->fData;
}
}
- r->fResData.data = hasData->fData.data;
- r->fResData.pRoot = hasData->fData.pRoot;
- r->fResData.rootRes = hasData->fData.rootRes;
+ uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData));
+ r->fHasFallback=(UBool)!r->fResData.noFallback;
r->fRes = r->fResData.rootRes;
- /*r->fParent = RES_BOGUS;*/
r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
- r->fResPath = NULL;
- r->fResPathLen = 0;
/*
if(r->fData->fPath != NULL) {
ures_setResPath(r, r->fData->fPath);
r->fKey = NULL;
r->fVersion = NULL;
- r->fResData.data = r->fData->fData.data;
- r->fResData.pRoot = r->fData->fData.pRoot;
- r->fResData.rootRes = r->fData->fData.rootRes;
+ uprv_memcpy(&r->fResData, &r->fData->fData, sizeof(ResourceData));
+ /* r->fHasFallback remains FALSE here in ures_openDirect() */
r->fRes = r->fResData.rootRes;
/*r->fParent = RES_BOGUS;*/
r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
r->fResPath = NULL;
r->fResPathLen = 0;
- r->fParentRes = NULL;
+ /*r->fParentRes = NULL;*/
r->fTopLevelData = r->fData;
return r;
}
}
-U_CAPI void U_EXPORT2
-ures_close(UResourceBundle* resB)
-{
- if(resB != NULL) {
- if(resB->fData != NULL) {
- entryClose(resB->fData);
- }
- if(resB->fVersion != NULL) {
- uprv_free(resB->fVersion);
- }
- ures_freeResPath(resB);
-
- if(ures_isStackObject(resB) == FALSE) {
- uprv_free(resB);
- }
- else {
-#if 0 /*U_DEBUG*/
- /* poison the data */
- uprv_memset(resB, -1, sizeof(UResourceBundle));
-#endif
- }
- }
-}
-
-U_CAPI const char* U_EXPORT2
-ures_getVersionNumber(const UResourceBundle* resourceBundle)
+/**
+ * Internal function.
+ * Return the version number associated with this ResourceBundle as a string.
+ *
+ * @param resourceBundle The resource bundle for which the version is checked.
+ * @return A version number string as specified in the resource bundle or its parent.
+ * The caller does not own this string.
+ * @see ures_getVersion
+ * @internal
+ */
+U_INTERNAL const char* U_EXPORT2
+ures_getVersionNumberInternal(const UResourceBundle *resourceBundle)
{
if (!resourceBundle) return NULL;
((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_malloc(1 + len);
+ /* Check for null pointer. */
+ if (((UResourceBundle *)resourceBundle)->fVersion == NULL) {
+ return NULL;
+ }
if(minor_len > 0) {
u_UCharsToChars(minor_version, resourceBundle->fVersion , minor_len);
resourceBundle->fVersion[len] = '\0';
}
else {
- uprv_strcpy(resourceBundle->fVersion, kDefaultMinorVersion);
+ uprv_strcpy(resourceBundle->fVersion, kDefaultMinorVersion);
}
}
return resourceBundle->fVersion;
}
+U_CAPI const char* U_EXPORT2
+ures_getVersionNumber(const UResourceBundle* resourceBundle)
+{
+ return ures_getVersionNumberInternal(resourceBundle);
+}
+
U_CAPI void U_EXPORT2 ures_getVersion(const UResourceBundle* resB, UVersionInfo versionInfo) {
if (!resB) return;
- u_versionFromString(versionInfo, ures_getVersionNumber(resB));
+ u_versionFromString(versionInfo, ures_getVersionNumberInternal(resB));
}
/** Tree support functions *******************************/
int32_t len = 0;
if(ures_hasNext(res) && (k = ures_getNextResource(res, &ctx->curr, status))) {
result = ures_getKey(k);
- len = uprv_strlen(result);
+ len = (int32_t)uprv_strlen(result);
}
if (resultLength) {
*resultLength = len;
U_CAPI UEnumeration* U_EXPORT2
ures_openAvailableLocales(const char *path, UErrorCode *status)
{
- UResourceBundle *index = NULL;
+ UResourceBundle *idx = NULL;
UEnumeration *en = NULL;
ULocalesContext *myContext = NULL;
ures_initStackObject(&myContext->installed);
ures_initStackObject(&myContext->curr);
- index = ures_openDirect(path, INDEX_LOCALE_NAME, status);
- ures_getByKey(index, INDEX_TAG, &myContext->installed, status);
+ idx = ures_openDirect(path, INDEX_LOCALE_NAME, status);
+ ures_getByKey(idx, INDEX_TAG, &myContext->installed, status);
if(U_SUCCESS(*status)) {
#if defined(URES_TREE_DEBUG)
fprintf(stderr, "Got %s::%s::[%s] : %s\n",
en = NULL;
}
- ures_close(index);
+ ures_close(idx);
return en;
}
+static UBool isLocaleInList(UEnumeration *locEnum, const char *locToSearch, UErrorCode *status) {
+ const char *loc;
+ while ((loc = uenum_next(locEnum, NULL, status)) != NULL) {
+ if (uprv_strcmp(loc, locToSearch) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
U_CAPI int32_t U_EXPORT2
ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
const char *path, const char *resName, const char *keyword, const char *locid,
UErrorCode subStatus = U_ZERO_ERROR;
int32_t length = 0;
if(U_FAILURE(*status)) return 0;
- if(isAvailable) {
- *isAvailable = TRUE;
- }
uloc_getKeywordValue(locid, keyword, kwVal, 1024-1,&subStatus);
if(!uprv_strcmp(kwVal, DEFAULT_TAG)) {
kwVal[0]=0;
uprv_strcpy(parent, base);
uprv_strcpy(found, base);
-
+
+ if(isAvailable) {
+ UEnumeration *locEnum = ures_openAvailableLocales(path, &subStatus);
+ *isAvailable = TRUE;
+ if (U_SUCCESS(subStatus)) {
+ *isAvailable = isLocaleInList(locEnum, parent, &subStatus);
+ }
+ uenum_close(locEnum);
+ }
+
if(U_FAILURE(subStatus)) {
*status = subStatus;
return 0;
subStatus = U_ZERO_ERROR;
res = ures_open(path, parent, &subStatus);
if(((subStatus == U_USING_FALLBACK_WARNING) ||
- (subStatus == U_USING_DEFAULT_WARNING)) && isAvailable) {
+ (subStatus == U_USING_DEFAULT_WARNING)) && isAvailable)
+ {
*isAvailable = FALSE;
}
isAvailable = NULL; /* only want to set this the first time around */
}
subStatus = U_ZERO_ERROR;
-
- uprv_strcpy(found, parent);
- uloc_getParent(found,parent,1023,&subStatus);
+
+ if (res != NULL) {
+ uprv_strcpy(found, ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus));
+ }
+
+ uloc_getParent(found,parent,sizeof(parent),&subStatus);
ures_close(res);
- } while(!defVal[0] && *found && U_SUCCESS(*status));
+ } while(!defVal[0] && *found && uprv_strcmp(found, "root") != 0 && U_SUCCESS(*status));
/* Now, see if we can find the kwVal collator.. start the search over.. */
uprv_strcpy(parent, base);
ures_close(&bund1);
ures_close(&bund2);
- length = uprv_strlen(found);
+ length = (int32_t)uprv_strlen(found);
if(U_SUCCESS(*status)) {
int32_t copyLength = uprv_min(length, resultCapacity);
locs = ures_openAvailableLocales(path, status);
if(U_FAILURE(*status)) {
- ures_close(&item);
- ures_close(&subItem);
+ ures_close(&item);
+ ures_close(&subItem);
return NULL;
}
&& U_SUCCESS(subStatus)) {
const char *k;
int32_t i;
- k = ures_getKey(&subItem);
+ k = ures_getKey(subPtr);
#if defined(URES_TREE_DEBUG)
/* fprintf(stderr, "%s | %s | %s | %s\n", path?path:"<ICUDATA>", keyword, locale, k); */
}
}
if(k && *k) {
- int32_t kLen = uprv_strlen(k);
+ int32_t kLen = (int32_t)uprv_strlen(k);
if(!uprv_strcmp(k,DEFAULT_TAG)) {
continue; /* don't need 'default'. */
}
#endif
return uloc_openKeywordList(valuesBuf, valuesIndex, status);
}
+#if 0
+/* This code isn't needed, and given the documentation warnings the implementation is suspect */
+U_INTERNAL UBool U_EXPORT2
+ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
+ if(res1==NULL || res2==NULL){
+ return res1==res2; /* pointer comparision */
+ }
+ if(res1->fKey==NULL|| res2->fKey==NULL){
+ return (res1->fKey==res2->fKey);
+ }else{
+ if(uprv_strcmp(res1->fKey, res2->fKey)!=0){
+ return FALSE;
+ }
+ }
+ if(uprv_strcmp(res1->fData->fName, res2->fData->fName)!=0){
+ return FALSE;
+ }
+ if(res1->fData->fPath == NULL|| res2->fData->fPath==NULL){
+ return (res1->fData->fPath == res2->fData->fPath);
+ }else{
+ if(uprv_strcmp(res1->fData->fPath, res2->fData->fPath)!=0){
+ return FALSE;
+ }
+ }
+ if(uprv_strcmp(res1->fData->fParent->fName, res2->fData->fParent->fName)!=0){
+ return FALSE;
+ }
+ if(uprv_strcmp(res1->fData->fParent->fPath, res2->fData->fParent->fPath)!=0){
+ return FALSE;
+ }
+ if(uprv_strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen)!=0){
+ return FALSE;
+ }
+ if(res1->fRes != res2->fRes){
+ return FALSE;
+ }
+ return TRUE;
+}
+U_INTERNAL UResourceBundle* U_EXPORT2
+ures_clone(const UResourceBundle* res, UErrorCode* status){
+ UResourceBundle* bundle = NULL;
+ UResourceBundle* ret = NULL;
+ if(U_FAILURE(*status) || res == NULL){
+ return NULL;
+ }
+ bundle = ures_open(res->fData->fPath, res->fData->fName, status);
+ if(res->fResPath!=NULL){
+ ret = ures_findSubResource(bundle, res->fResPath, NULL, status);
+ ures_close(bundle);
+ }else{
+ ret = bundle;
+ }
+ return ret;
+}
+U_INTERNAL const UResourceBundle* U_EXPORT2
+ures_getParentBundle(const UResourceBundle* res){
+ if(res==NULL){
+ return NULL;
+ }
+ return res->fParentRes;
+}
+#endif
+
+U_INTERNAL void U_EXPORT2
+ures_getVersionByKey(const UResourceBundle* res, const char *key, UVersionInfo ver, UErrorCode *status) {
+ const UChar *str;
+ int32_t len;
+ str = ures_getStringByKey(res, key, &len, status);
+ if(U_SUCCESS(*status)) {
+ u_versionFromUString(ver, str);
+ }
+}
/* eof */