From dce5b17a3a03281214aff501d61363f89568c8d7 Mon Sep 17 00:00:00 2001 From: Vladimir Weinstein Date: Mon, 24 Jun 2002 20:58:17 +0000 Subject: [PATCH] ICU-1948 Support for direct resource access and resource level sharing (aliases) X-SVN-Rev: 8934 --- icu4c/source/common/unicode/ures.h | 72 +++++- icu4c/source/common/uresbund.c | 348 +++++++++++++++++++++++------ icu4c/source/common/uresdata.c | 93 +++++++- icu4c/source/common/uresdata.h | 10 +- icu4c/source/common/uresimp.h | 20 +- 5 files changed, 457 insertions(+), 86 deletions(-) diff --git a/icu4c/source/common/unicode/ures.h b/icu4c/source/common/unicode/ures.h index 6d6bc02424a..2ad0c93a44b 100644 --- a/icu4c/source/common/unicode/ures.h +++ b/icu4c/source/common/unicode/ures.h @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (C) 1997-2001, International Business Machines +* Copyright (C) 1997-2002, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * @@ -16,6 +16,7 @@ * 06/14/99 stephen Removed functions taking a filename suffix. * 07/20/99 stephen Language-independent ypedef to void* * 11/09/99 weiv Added ures_getLocale() +* 06/24/02 weiv Added support for resource sharing ****************************************************************************** */ @@ -182,15 +183,15 @@ typedef enum { RES_NONE=-1, RES_STRING=0, RES_BINARY=1, - RES_TABLE=2, - - RES_INT=7, - RES_ARRAY=8, + RES_INT=2, /* this resource is an alias - contains a string * that is the name of resource containing data */ - RES_ALIAS=13, - RES_INT_VECTOR=14, + RES_ALIAS=3, + RES_INT_VECTOR=4, + + RES_TABLE=7, + RES_ARRAY=8, RES_RESERVED=15 } UResType; @@ -492,7 +493,8 @@ U_CAPI UBool U_EXPORT2 ures_hasNext(UResourceBundle *resourceBundle); * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it * @stable */ -U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resourceBundle, UResourceBundle *fillIn, UErrorCode *status); +U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resourceBundle, + UResourceBundle *fillIn, UErrorCode *status); /** * Returns the next string in a given resource or NULL if there are no more resources @@ -505,7 +507,9 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resource * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file. * @stable */ -U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resourceBundle, int32_t* len, const char ** key, UErrorCode *status); +U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resourceBundle, + int32_t* len, const char ** key, + UErrorCode *status); /** * Returns the resource in a given resource at the specified index. Features a fill-in parameter. @@ -518,7 +522,9 @@ U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resourceBundle * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it * @stable */ -U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resourceBundle, int32_t indexR, UResourceBundle *fillIn, UErrorCode *status); +U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resourceBundle, + int32_t indexR, + UResourceBundle *fillIn, UErrorCode *status); /** * Returns the string in a given resource at the specified index. @@ -530,7 +536,47 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resourc * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file. * @stable */ -U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status); +U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, + int32_t indexS, int32_t* len, + UErrorCode *status); + +/** + * Returns a resource that can be located using the pathToResource argument. One needs optional package, locale + * and path inside the locale, for example: "/myData/en/zoneStrings/3". Keys and indexes are supported. Keys + * need to reference data in named structures, while indexes can reference both named and anonymous resources. + * Features a fill-in parameter. + * + * @param pathToResource a path that will lead to the requested resource + * @param fillIn if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. + * Alternatively, you can supply a struct to be filled by this function. + * @param status fills in the outgoing error code. + * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it + * @draft ICU 2.2 + */ +U_CAPI UResourceBundle* U_EXPORT2 +ures_findResource(const char* pathToResource, + UResourceBundle *fillIn, UErrorCode *status); + +/** + * Returns a sub resource that can be located using the pathToResource argument. One needs a path inside + * the supplied resource, for example, if you have "en_US" resource bundle opened, you might ask for + * "zoneStrings/3". Keys and indexes are supported. Keys + * need to reference data in named structures, while indexes can reference both + * named and anonymous resources. + * Features a fill-in parameter. + * + * @param resourceBundle a resource + * @param pathToResource a path that will lead to the requested resource + * @param fillIn if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. + * Alternatively, you can supply a struct to be filled by this function. + * @param status fills in the outgoing error code. + * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it + * @draft ICU 2.2 + */ +U_CAPI UResourceBundle* U_EXPORT2 +ures_findSubResource(const UResourceBundle *resB, + const char* pathToResource, + UResourceBundle *fillIn, UErrorCode *status); /** * Returns a resource in a given resource that has a given key. This procedure works only with table @@ -544,7 +590,9 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it * @stable */ -U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resourceBundle, const char* key, UResourceBundle *fillIn, UErrorCode *status); +U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resourceBundle, + const char* key, + UResourceBundle *fillIn, UErrorCode *status); /** * Returns a string in a given resource that has a given key. This procedure works only with table diff --git a/icu4c/source/common/uresbund.c b/icu4c/source/common/uresbund.c index 17c1d071ee5..f88e816cd8d 100644 --- a/icu4c/source/common/uresbund.c +++ b/icu4c/source/common/uresbund.c @@ -1,6 +1,6 @@ /* ****************************************************************************** -* Copyright (C) 1997-2001, International Business Machines Corporation and * +* Copyright (C) 1997-2002, International Business Machines Corporation and * * others. All Rights Reserved. * ****************************************************************************** * @@ -15,6 +15,7 @@ * 11/09/99 weiv Added ures_getLocale() * March 2000 weiv Total overhaul - using data in DLLs * 06/20/2000 helena OS/400 port changes; mostly typecast. +* 06/24/02 weiv Added support for resource sharing ****************************************************************************** */ @@ -498,78 +499,124 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr static void entryClose(UResourceDataEntry *resB); /* INTERNAL: */ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r, - const char *key, UResourceDataEntry *realData, - UResourceBundle *resB, UErrorCode *status) { + const char *key, int32_t index, UResourceDataEntry *realData, + const UResourceBundle *parent, int32_t noAlias, + UResourceBundle *resB, UErrorCode *status) +{ if(status == NULL || U_FAILURE(*status)) { return resB; } if(RES_GET_TYPE(r) == RES_ALIAS) { /* This is an alias, need to exchange with real data */ - 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 */ - int32_t i = 0; - char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = NULL; - int32_t pathLen = 0, localeLen = 0, keyPathLen = 0; - chAlias = (char *)uprv_malloc((len+1)*sizeof(char)); - u_UCharsToChars(alias, chAlias, len); - chAlias[len] = 0; + 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 */ + int32_t i = 0; + char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = NULL; + int32_t pathLen = 0, localeLen = 0, keyPathLen = 0; + chAlias = (char *)uprv_malloc((len+1)*sizeof(char)); + u_UCharsToChars(alias, chAlias, len); + chAlias[len] = 0; - locale = uprv_strchr(chAlias, '|'); - if(locale == NULL) { - locale = chAlias; - } else { - *locale = 0; - locale++; - path = chAlias; - } - if(path != NULL && uprv_strlen(path) == 0) { - path = realData->fPath; - } - - keyPath = uprv_strchr(locale, '/'); - if(keyPath == NULL) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - } else { - *keyPath = 0; - keyPath++; - } - - { - char *kp = NULL; - /* got almost everything, let's try to open */ - UResourceBundle *main = ures_open(path, locale, status); - UResourceBundle *res = main; - UResourceBundle *res2 = resB; - while((kp=uprv_strchr(keyPath, '/')) && U_SUCCESS(*status)) { - *kp = 0; - res2 = ures_getByKey(res, keyPath, res2, status); - /*ures_close(res);*/ - res = res2; - keyPath = kp+1; + if(*chAlias == RES_PATH_SEPARATOR) { + /* there is a path included */ + locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR); + *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; } - res2 = ures_getByKey(res, keyPath, res2, status); - ures_close(main); - /*res = res2;*/ + 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 *main = ures_openDirect(path, locale, status); + UResourceBundle *result = NULL; - /* here we have the wanted resource */ - /* - rdata = &(res->fResData); - r = res->fRes; - realData = res->fData; - */ - uprv_free(chAlias); - return res2; + 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. + */ + const char* aKey = parent->fResPath; + if(aKey) { + r = res_findResource(&(main->fResData), main->fRes, &aKey); + } else { + r = main->fRes; + } + if(key) { + /* we need to make keyPath from parents fResPath and + * current key, if there is a key associated + */ + aKey = key; + r = res_findResource(&(main->fResData), r, &aKey); + } 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) == RES_TABLE) { + r = res_getTableItemByIndex(&(main->fResData), r, index, &aKey); + } else { /* array */ + r = res_getArrayItem(&(main->fResData), r, index); + } + } + if(r != RES_BOGUS) { + result = init_resb_result(&(main->fResData), r, key, -1, main->fData, parent, 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. + */ + result = main; + while(*keyPath) { + r = res_findResource(&(result->fResData), result->fRes, &keyPath); + 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; + } + } + uprv_free(chAlias); + ures_close(main); + return result; + } + } else { + /* bad alias, should be an error */ + *status = U_ILLEGAL_ARGUMENT_ERROR; + return resB; } } else { - /* bad alias, should be an error */ - *status = U_ILLEGAL_ARGUMENT_ERROR; + *status = U_TOO_MANY_ALIASES_ERROR; return resB; } } if(resB == NULL) { resB = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle)); ures_setIsStackObject(resB, FALSE); + resB->fResPath = NULL; } else { if(resB->fData != NULL) { entryClose(resB->fData); @@ -587,8 +634,23 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r, resB->fIsTopLevel = FALSE; resB->fIndex = -1; resB->fKey = key; + ures_freeResPath(resB); + if(parent->fResPath) { + ures_appendResPath(resB, parent->fResPath); + } + if(key != NULL) { + ures_appendResPath(resB, key); + ures_appendResPath(resB, RES_PATH_SEPARATOR_S); + } else { + char buf[256]; + T_CString_integerToString(buf, index, 10); + ures_appendResPath(resB, buf); + ures_appendResPath(resB, RES_PATH_SEPARATOR_S); + } + 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; @@ -616,6 +678,10 @@ UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *origin } } uprv_memcpy(r, original, sizeof(UResourceBundle)); + r->fResPath = NULL; + if(original->fResPath) { + ures_appendResPath(r, original->fResPath); + } ures_setIsStackObject(r, isStackObject); if(r->fData != NULL) { entryIncrease(r->fData); @@ -844,13 +910,13 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resB, UR if(r == RES_BOGUS && resB->fHasFallback) { /* TODO: do the fallback */ } - return init_resb_result(&(resB->fResData), r, key, resB->fData, fillIn, status); + return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status); case RES_ARRAY: 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->fData, fillIn, status); + return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status); case RES_INT_VECTOR: default: /*return NULL;*/ @@ -886,13 +952,13 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resB, i if(r == RES_BOGUS && resB->fHasFallback) { /* TODO: do the fallback */ } - return init_resb_result(&(resB->fResData), r, key, resB->fData, fillIn, status); + return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status); case RES_ARRAY: 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, resB->fData, fillIn, status); + return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status); case RES_INT_VECTOR: default: /*return NULL;*/ @@ -945,6 +1011,80 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, return NULL; } +U_CAPI const char *ures_getResPath(UResourceBundle *resB) { + return resB->fResPath; +} + +U_CAPI UResourceBundle* U_EXPORT2 +ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status) +{ + UResourceBundle *first = NULL; + UResourceBundle *result = fillIn; + char *packageName = NULL; + char *pathToResource = NULL; + char *locale = NULL, *localeEnd = NULL; + if(status == NULL || U_FAILURE(*status)) { + return result; + } + pathToResource = (char *)uprv_malloc((uprv_strlen(path)+1)*sizeof(char)); + uprv_strcpy(pathToResource, path); + locale = pathToResource; + if(*pathToResource == RES_PATH_SEPARATOR) { /* there is a path specification */ + pathToResource++; + packageName = pathToResource; + pathToResource = uprv_strchr(pathToResource, RES_PATH_SEPARATOR); + if(pathToResource == NULL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } else { + *pathToResource = 0; + locale = pathToResource+1; + } + } + + localeEnd = strchr(locale, RES_PATH_SEPARATOR); + if(localeEnd != NULL) { + *localeEnd = 0; + } + + first = ures_open(packageName, locale, status); + + if(U_SUCCESS(*status)) { + if(localeEnd) { + result = ures_findSubResource(first, localeEnd+1, fillIn, status); + } else { + result = ures_copyResb(fillIn, first, status); + } + ures_close(first); + } + uprv_free(pathToResource); + return result; +} + +U_CAPI UResourceBundle* U_EXPORT2 +ures_findSubResource(const UResourceBundle *resB, const char* path, UResourceBundle *fillIn, UErrorCode *status) +{ + Resource res = RES_BOGUS; + UResourceBundle *result = fillIn; + const char *pathToResource = path; + + if(status == NULL || U_FAILURE(*status)) { + return result; + } + + /* here we do looping and circular alias checking */ + + res = res_findResource(&(resB->fResData), resB->fRes, &pathToResource); + + if(res != RES_BOGUS) { + result = init_resb_result(&(resB->fResData), res, path, -1, resB->fData, resB, 0, fillIn, status); + } else { + *status = U_MISSING_RESOURCE_ERROR; + } + + return result; +} + + U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) { Resource res = RES_BOGUS; UResourceDataEntry *realData = NULL; @@ -966,7 +1106,8 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con if(resB->fHasFallback == TRUE) { const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status); if(U_SUCCESS(*status)) { - return init_resb_result(rd, res, key, realData, fillIn, status); + /* check if resB->fResPath gives the right name here */ + return init_resb_result(rd, res, key, -1, realData, resB, 0, fillIn, status); } else { *status = U_MISSING_RESOURCE_ERROR; } @@ -974,7 +1115,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con *status = U_MISSING_RESOURCE_ERROR; } } else { - return init_resb_result(&(resB->fResData), res, key, resB->fData, fillIn, status); + return init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status); } } #if 0 @@ -984,7 +1125,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con /* here should go a first attempt to locate the key using index table */ const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status); if(U_SUCCESS(*status)) { - return init_resb_result(rd, res, key, realData, fillIn, status); + return init_resb_result(rd, res, key, realData, resB, fillIn, status); } else { *status = U_MISSING_RESOURCE_ERROR; } @@ -1122,7 +1263,48 @@ static void entryClose(UResourceDataEntry *resB) { entryCloseInt(resB); 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); +} +*/ +U_CFUNC void ures_appendResPath(UResourceBundle *resB, const char* toAdd) { + if(resB->fResPath == NULL) { + resB->fResPath = resB->fResBuf; + *(resB->fResPath) = 0; + resB->fResPathLen = 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)); + uprv_strcpy(resB->fResPath, resB->fResBuf); + } else { + resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char)); + } + } + uprv_strcat(resB->fResPath, toAdd); +} +U_CFUNC void ures_freeResPath(UResourceBundle *resB) { + if(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) { @@ -1176,6 +1358,18 @@ ures_openFillIn(UResourceBundle *r, const char* path, r->fResData.rootRes = firstData->fData.rootRes; r->fRes = r->fResData.rootRes; r->fSize = res_countArrayItems(&(r->fResData), r->fRes); + /*r->fParent = RES_BOGUS;*/ + /*r->fResPath = NULL;*/ + ures_freeResPath(r); + /* + if(r->fData->fPath != NULL) { + ures_setResPath(r, r->fData->fPath); + ures_appendResPath(r, RES_PATH_PACKAGE_S); + ures_appendResPath(r, r->fData->fName); + } else { + ures_setResPath(r, r->fData->fName); + } + */ } } U_CAPI UResourceBundle* U_EXPORT2 @@ -1234,7 +1428,19 @@ ures_open(const char* path, r->fResData.pRoot = hasData->fData.pRoot; r->fResData.rootRes = hasData->fData.rootRes; r->fRes = r->fResData.rootRes; + /*r->fParent = RES_BOGUS;*/ r->fSize = res_countArrayItems(&(r->fResData), r->fRes); + r->fResPath = NULL; + /* + if(r->fData->fPath != NULL) { + ures_setResPath(r, r->fData->fPath); + ures_appendResPath(r, RES_PATH_PACKAGE_S); + ures_appendResPath(r, r->fData->fName); + } else { + ures_setResPath(r, r->fData->fName); + } + */ + return r; } @@ -1325,7 +1531,18 @@ ures_openDirect(const char* path, const char* localeID, UErrorCode* status) { r->fResData.pRoot = r->fData->fData.pRoot; r->fResData.rootRes = r->fData->fData.rootRes; r->fRes = r->fResData.rootRes; + /*r->fParent = RES_BOGUS;*/ r->fSize = res_countArrayItems(&(r->fResData), r->fRes); + r->fResPath = NULL; + /* + if(r->fData->fPath != NULL) { + ures_setResPath(r, r->fData->fPath); + ures_appendResPath(r, RES_PATH_PACKAGE_S); + ures_appendResPath(r, r->fData->fName); + } else { + ures_setResPath(r, r->fData->fName); + } + */ return r; } @@ -1390,6 +1607,7 @@ ures_close(UResourceBundle* resB) if(resB->fVersion != NULL) { uprv_free(resB->fVersion); } + ures_freeResPath(resB); if(ures_isStackObject(resB) == FALSE) { uprv_free(resB); diff --git a/icu4c/source/common/uresdata.c b/icu4c/source/common/uresdata.c index a02fdf9b1d9..a8b67c15b7f 100644 --- a/icu4c/source/common/uresdata.c +++ b/icu4c/source/common/uresdata.c @@ -1,7 +1,7 @@ /* ******************************************************************************* * * -* Copyright (C) 1999-2001, International Business Machines Corporation * +* Copyright (C) 1999-2002, International Business Machines Corporation * * and others. All Rights Reserved. * * * ******************************************************************************* @@ -16,6 +16,7 @@ * * Date Name Description * 06/20/2000 helena OS/400 port changes; mostly typecast. +* 06/24/02 weiv Added support for resource sharing */ #include "unicode/utypes.h" @@ -113,6 +114,37 @@ _res_findTableItem(const Resource *pRoot, const Resource res, const char *key) { } } +static Resource +_res_findTableItemN(const Resource *pRoot, const Resource res, const char *key, int32_t keyLen) { + uint16_t *p=(uint16_t *)RES_GET_POINTER(pRoot, res); + uint16_t i, start, limit; + + limit=*p++; /* number of entries */ + + if(limit == 0) { /* this table is empty */ + return RES_BOGUS; + } + + /* do a binary search for the key */ + start=0; + while(startpRoot, array, indexR); } +U_CFUNC Resource +res_findResource(const ResourceData *pResData, Resource r, const char** path) { + /* we pass in a path. CollationElements/Sequence or zoneStrings/3/2 etc. + * iterates over a path and stops when a scalar resource is found. This + * CAN be an alias. Path gets set to the part that has not yet been processed. + */ + + const char *pathP = *path, *nextSepP = *path; + char *closeIndex = NULL; + Resource t1 = r; + Resource t2; + int32_t indexR = 0, keyLen = 0; + UResType type = RES_GET_TYPE(t1); + + while(*pathP && nextSepP && t1 != RES_BOGUS && type >= RES_TABLE) { + /* Iteration stops if: the path has been consumed, we found a non-existing + * resource (t1 == RES_BOGUS) or we found a scalar resource (including alias) + */ + nextSepP = uprv_strchr(pathP, RES_PATH_SEPARATOR); + /* if there are more separators, terminate string + * and set path to the remaining part of the string + */ + if(nextSepP != NULL) { + keyLen = nextSepP-pathP; + *path = nextSepP+1; + } else { + keyLen = uprv_strlen(pathP); + *path += keyLen; + } + + /* try the key based access */ + t2 = _res_findTableItemN(pResData->pRoot, t1, pathP, keyLen); + if(t2 == RES_BOGUS) { + /* if we fail to get the resource by key, maybe we got an index */ + indexR = uprv_strtol(pathP, &closeIndex, 10); + if(closeIndex != pathP) { + if(type == RES_TABLE) { + /* if we indeed have an index, try to get the item by index */ + t2 = _res_getTableItem(pResData->pRoot, t1, (uint16_t)indexR); + } else { /* if(type == RES_ARRAY) { */ + t2 = _res_getArrayItem(pResData->pRoot, t1, indexR); + } + } + } + t1 = t2; + type = RES_GET_TYPE(t1); + /* position pathP to next resource key/index */ + pathP += keyLen+1; + } + + return t1; +} + U_CFUNC Resource -res_getTableItemByKey(const ResourceData *pResData, const Resource table, int32_t* indexR, const char* * key) { +res_getTableItemByKey(const ResourceData *pResData, Resource table, int32_t* indexR, const char* * key) { uint16_t tempIndex; if(key != NULL) { tempIndex = _res_findTableIndex(pResData->pRoot, table, *key); @@ -302,7 +387,7 @@ res_getTableItemByKey(const ResourceData *pResData, const Resource table, int32_ } U_CFUNC Resource -res_getTableItemByIndex(const ResourceData *pResData, const Resource table, int32_t indexR, const char * * key) { +res_getTableItemByIndex(const ResourceData *pResData, Resource table, int32_t indexR, const char * * key) { if(indexR>-1) { if(key != NULL) { *key = _res_getTableKey(pResData->pRoot, table, (uint16_t)indexR); diff --git a/icu4c/source/common/uresdata.h b/icu4c/source/common/uresdata.h index 70358c3fed0..d442247d35c 100644 --- a/icu4c/source/common/uresdata.h +++ b/icu4c/source/common/uresdata.h @@ -1,7 +1,7 @@ /* ****************************************************************************** * * -* Copyright (C) 1999-2001, International Business Machines * +* Copyright (C) 1999-2002, International Business Machines * * Corporation and others. All Rights Reserved. * * * ****************************************************************************** @@ -12,6 +12,7 @@ * * created on: 1999dec08 * created by: Markus W. Scherer +* 06/24/02 weiv Added support for resource sharing */ #ifndef __RESDATA_H__ @@ -109,8 +110,9 @@ res_countArrayItems(const ResourceData *pResData, const Resource res); U_CFUNC int32_t res_getTableSize(const ResourceData *pResData, Resource table); -U_CFUNC Resource res_getArrayItem(const ResourceData *pResData, const Resource array, const int32_t indexS); -U_CFUNC Resource res_getTableItemByIndex(const ResourceData *pResData, const Resource table, int32_t indexS, const char ** key); -U_CFUNC Resource res_getTableItemByKey(const ResourceData *pResData, const Resource table, int32_t *indexS, const char* * key); +U_CFUNC Resource res_getArrayItem(const ResourceData *pResData, Resource array, const int32_t indexS); +U_CFUNC Resource res_getTableItemByIndex(const ResourceData *pResData, Resource table, int32_t indexS, const char ** key); +U_CFUNC Resource res_getTableItemByKey(const ResourceData *pResData, Resource table, int32_t *indexS, const char* * key); +U_CFUNC Resource res_findResource(const ResourceData *pResData, Resource r, const char** path); #endif diff --git a/icu4c/source/common/uresimp.h b/icu4c/source/common/uresimp.h index 1c128eeaf2a..c942f2a84d6 100644 --- a/icu4c/source/common/uresimp.h +++ b/icu4c/source/common/uresimp.h @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (C) 2000-2001, International Business Machines +* Copyright (C) 2000-2002, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** */ @@ -26,6 +26,8 @@ #define MAGIC1 19700503 #define MAGIC2 19641227 +#define URES_MAX_ALIAS_LEVEL 256 + /* enum UResEntryType { ENTRY_OK = 0, @@ -51,8 +53,15 @@ struct UResourceDataEntry { int32_t fHashKey; /* for faster access in the hashtable */ }; +#define RES_BUFSIZE 256 +#define RES_PATH_SEPARATOR '/' +#define RES_PATH_SEPARATOR_S "/" + struct UResourceBundle { const char *fKey; /*tag*/ + char *fResPath; /* full path to the resource: "zh_TW/CollationElements/Sequence" */ + char fResBuf[RES_BUFSIZE]; + int32_t fResPathLen; char *fVersion; UBool fHasFallback; UBool fIsTopLevel; @@ -64,6 +73,12 @@ struct UResourceBundle { int32_t fSize; ResourceData fResData; Resource fRes; + + /* parent of this resource - + * lives in the same data entry + */ + /* This cannot be done right now - need support in genrb */ + /*Resource fParent; */ }; U_CFUNC void ures_initStackObject(UResourceBundle* resB); @@ -73,6 +88,9 @@ U_CFUNC UBool ures_isStackObject( UResourceBundle* resB); /* Some getters used by the copy constructor */ U_CFUNC const char* ures_getName(const UResourceBundle* resB); U_CFUNC const char* ures_getPath(const UResourceBundle* resB); +U_CFUNC void ures_appendResPath(UResourceBundle *resB, const char* toAdd); +/*U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd);*/ +U_CFUNC void ures_freeResPath(UResourceBundle *resB); /* Candidates for export */ U_CFUNC UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *original, UErrorCode *status);