ICU-4739 add "no fallback" flag to resource bundles

X-SVN-Rev: 18835
This commit is contained in:
Markus Scherer 2005-11-28 23:59:33 +00:00
parent 53574ad971
commit 7076ab9ce6
6 changed files with 84 additions and 37 deletions

View File

@ -320,12 +320,10 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
r->fHashKey = hashValue; r->fHashKey = hashValue;
r->fParent = NULL; r->fParent = NULL;
r->fData.data = NULL; uprv_memset(&r->fData, 0, sizeof(ResourceData));
r->fData.pRoot = NULL;
r->fData.rootRes = 0;
r->fBogus = U_ZERO_ERROR; r->fBogus = U_ZERO_ERROR;
/* this is the acutal loading - returns bool true/false */ /* this is the actual loading - returns bool true/false */
result = res_load(&(r->fData), r->fPath, r->fName, status); result = res_load(&(r->fData), r->fPath, r->fName, status);
if (result == FALSE || U_FAILURE(*status)) { if (result == FALSE || U_FAILURE(*status)) {
@ -461,7 +459,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
if(r != NULL) { /* if there is one real locale, we can look for parents. */ if(r != NULL) { /* if there is one real locale, we can look for parents. */
t1 = r; t1 = r;
hasRealData = TRUE; hasRealData = TRUE;
while (hasChopped && !isRoot && t1->fParent == NULL) { while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.noFallback) {
/* insert regular parents */ /* insert regular parents */
t2 = init_entry(name, r->fPath, &parentStatus); t2 = init_entry(name, r->fPath, &parentStatus);
t1->fParent = t2; t1->fParent = t2;
@ -503,7 +501,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
} else { /* we don't even have the root locale */ } else { /* we don't even have the root locale */
*status = U_MISSING_RESOURCE_ERROR; *status = U_MISSING_RESOURCE_ERROR;
} }
} else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL) { } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL && !r->fData.noFallback) {
/* insert root locale */ /* insert root locale */
t2 = init_entry(kRootLocaleName, r->fPath, &parentStatus); t2 = init_entry(kRootLocaleName, r->fPath, &parentStatus);
if(!hasRealData) { if(!hasRealData) {
@ -869,9 +867,7 @@ static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r,
resB->fVersion = NULL; resB->fVersion = NULL;
resB->fRes = r; resB->fRes = r;
/*resB->fParent = parent->fRes;*/ /*resB->fParent = parent->fRes;*/
resB->fResData.data = rdata->data; uprv_memcpy(&resB->fResData, rdata, sizeof(ResourceData));
resB->fResData.pRoot = rdata->pRoot;
resB->fResData.rootRes = rdata->rootRes;
resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes); resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes);
return resB; return resB;
} }
@ -1727,9 +1723,8 @@ ures_openFillIn(UResourceBundle *r, const char* path,
while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) { while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) {
firstData = firstData->fParent; firstData = firstData->fParent;
} }
r->fResData.data = firstData->fData.data; uprv_memcpy(&r->fResData, &firstData->fData, sizeof(ResourceData));
r->fResData.pRoot = firstData->fData.pRoot; r->fHasFallback=(UBool)!r->fResData.noFallback;
r->fResData.rootRes = firstData->fData.rootRes;
r->fRes = r->fResData.rootRes; r->fRes = r->fResData.rootRes;
r->fSize = res_countArrayItems(&(r->fResData), r->fRes); r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
/*r->fParent = RES_BOGUS;*/ /*r->fParent = RES_BOGUS;*/
@ -1795,9 +1790,8 @@ ures_open(const char* path,
} }
} }
r->fResData.data = hasData->fData.data; uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData));
r->fResData.pRoot = hasData->fData.pRoot; r->fHasFallback=(UBool)!r->fResData.noFallback;
r->fResData.rootRes = hasData->fData.rootRes;
r->fRes = r->fResData.rootRes; r->fRes = r->fResData.rootRes;
/*r->fParent = RES_BOGUS;*/ /*r->fParent = RES_BOGUS;*/
r->fSize = res_countArrayItems(&(r->fResData), r->fRes); r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
@ -1857,9 +1851,8 @@ ures_openDirect(const char* path, const char* localeID, UErrorCode* status) {
r->fKey = NULL; r->fKey = NULL;
r->fVersion = NULL; r->fVersion = NULL;
r->fResData.data = r->fData->fData.data; uprv_memcpy(&r->fResData, &r->fData->fData, sizeof(ResourceData));
r->fResData.pRoot = r->fData->fData.pRoot; /* r->fHasFallback remains FALSE here in ures_openDirect() */
r->fResData.rootRes = r->fData->fData.rootRes;
r->fRes = r->fResData.rootRes; r->fRes = r->fResData.rootRes;
/*r->fParent = RES_BOGUS;*/ /*r->fParent = RES_BOGUS;*/
r->fSize = res_countArrayItems(&(r->fResData), r->fRes); r->fSize = res_countArrayItems(&(r->fResData), r->fRes);

View File

@ -200,6 +200,7 @@ static UBool U_CALLCONV
isAcceptable(void *context, isAcceptable(void *context,
const char *type, const char *name, const char *type, const char *name,
const UDataInfo *pInfo) { const UDataInfo *pInfo) {
uprv_memcpy(context, pInfo->formatVersion, 4);
return (UBool)( return (UBool)(
pInfo->size>=20 && pInfo->size>=20 &&
pInfo->isBigEndian==U_IS_BIG_ENDIAN && pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
@ -217,10 +218,11 @@ isAcceptable(void *context,
U_CFUNC UBool U_CFUNC UBool
res_load(ResourceData *pResData, res_load(ResourceData *pResData,
const char *path, const char *name, UErrorCode *errorCode) { const char *path, const char *name, UErrorCode *errorCode) {
UVersionInfo formatVersion;
UResType rootType; UResType rootType;
/* load the ResourceBundle file */ /* load the ResourceBundle file */
pResData->data=udata_openChoice(path, "res", name, isAcceptable, NULL, errorCode); pResData->data=udata_openChoice(path, "res", name, isAcceptable, formatVersion, errorCode);
if(U_FAILURE(*errorCode)) { if(U_FAILURE(*errorCode)) {
return FALSE; return FALSE;
} }
@ -228,6 +230,7 @@ res_load(ResourceData *pResData,
/* get its memory and root resource */ /* get its memory and root resource */
pResData->pRoot=(Resource *)udata_getMemory(pResData->data); pResData->pRoot=(Resource *)udata_getMemory(pResData->data);
pResData->rootRes=*pResData->pRoot; pResData->rootRes=*pResData->pRoot;
pResData->noFallback=FALSE;
/* currently, we accept only resources that have a Table as their roots */ /* currently, we accept only resources that have a Table as their roots */
rootType=RES_GET_TYPE(pResData->rootRes); rootType=RES_GET_TYPE(pResData->rootRes);
@ -238,6 +241,14 @@ res_load(ResourceData *pResData,
return FALSE; return FALSE;
} }
if(formatVersion[0]>1 || (formatVersion[0]==1 && formatVersion[1]>=1)) {
/* bundles with formatVersion 1.1 and later contain an indexes[] array */
const int32_t *indexes=(const int32_t *)pResData->pRoot+1;
if(indexes[URES_INDEX_LENGTH]>URES_INDEX_ATTRIBUTES) {
pResData->noFallback=(UBool)(indexes[URES_INDEX_ATTRIBUTES]&URES_ATT_NO_FALLBACK);
}
}
return TRUE; return TRUE;
} }

View File

@ -1,7 +1,7 @@
/* /*
****************************************************************************** ******************************************************************************
* * * *
* Copyright (C) 1999-2003, International Business Machines * * Copyright (C) 1999-2005, International Business Machines *
* Corporation and others. All Rights Reserved. * * Corporation and others. All Rights Reserved. *
* * * *
****************************************************************************** ******************************************************************************
@ -48,6 +48,7 @@ enum {
URES_INDEX_BUNDLE_TOP, /* [3] contains the top of the bundle, */ URES_INDEX_BUNDLE_TOP, /* [3] contains the top of the bundle, */
/* in case it were ever different from [2] */ /* in case it were ever different from [2] */
URES_INDEX_MAX_TABLE_LENGTH,/* [4] max. length of any table */ URES_INDEX_MAX_TABLE_LENGTH,/* [4] max. length of any table */
URES_INDEX_ATTRIBUTES, /* [5] attributes bit set, see URES_ATT_* (new in formatVersion 1.2) */
URES_INDEX_TOP URES_INDEX_TOP
}; };
@ -57,7 +58,20 @@ enum {
}; };
/* /*
* File format for .res resource bundle files (formatVersion=1.1) * Nofallback attribute, attribute bit 0 in indexes[URES_INDEX_ATTRIBUTES].
* New in formatVersion 1.2 (ICU 3.6).
*
* If set, then this resource bundle is a standalone bundle.
* If not set, then the bundle participates in locale fallback, eventually
* all the way to the root bundle.
* If indexes[] is missing or too short, then the attribute cannot be determined
* reliably. Dependency checking should ignore such bundles, and loading should
* use fallbacks.
*/
#define URES_ATT_NO_FALLBACK 1
/*
* File format for .res resource bundle files (formatVersion=1.2)
* *
* An ICU4C resource bundle file (.res) is a binary, memory-mappable file * An ICU4C resource bundle file (.res) is a binary, memory-mappable file
* with nested, hierarchical data structures. * with nested, hierarchical data structures.
@ -67,7 +81,7 @@ enum {
* currently, the root item must be a table or table32 resource item * currently, the root item must be a table or table32 resource item
* int32_t indexes[indexes[0]]; -- array of indexes for friendly * int32_t indexes[indexes[0]]; -- array of indexes for friendly
* reading and swapping; see URES_INDEX_* above * reading and swapping; see URES_INDEX_* above
* new in formatVersion 1.1 * new in formatVersion 1.1 (ICU 2.8)
* char keys[]; -- characters for key strings * char keys[]; -- characters for key strings
* (formatVersion 1.0: up to 65k of characters; 1.1: <2G) * (formatVersion 1.0: up to 65k of characters; 1.1: <2G)
* (minus the space for root and indexes[]), * (minus the space for root and indexes[]),
@ -156,6 +170,7 @@ typedef struct {
UDataMemory *data; UDataMemory *data;
Resource *pRoot; Resource *pRoot;
Resource rootRes; Resource rootRes;
UBool noFallback; /* see URES_ATT_NO_FALLBACK */
} ResourceData; } ResourceData;
/* /*

View File

@ -1474,6 +1474,7 @@ U_STRING_DECL(k_type_string, "string", 6);
U_STRING_DECL(k_type_binary, "binary", 6); U_STRING_DECL(k_type_binary, "binary", 6);
U_STRING_DECL(k_type_bin, "bin", 3); U_STRING_DECL(k_type_bin, "bin", 3);
U_STRING_DECL(k_type_table, "table", 5); U_STRING_DECL(k_type_table, "table", 5);
U_STRING_DECL(k_type_table_no_fallback, "table(nofallback)", 17);
U_STRING_DECL(k_type_int, "int", 3); U_STRING_DECL(k_type_int, "int", 3);
U_STRING_DECL(k_type_integer, "integer", 7); U_STRING_DECL(k_type_integer, "integer", 7);
U_STRING_DECL(k_type_array, "array", 5); U_STRING_DECL(k_type_array, "array", 5);
@ -1494,6 +1495,7 @@ typedef enum EResourceType
RT_STRING, RT_STRING,
RT_BINARY, RT_BINARY,
RT_TABLE, RT_TABLE,
RT_TABLE_NO_FALLBACK,
RT_INTEGER, RT_INTEGER,
RT_ARRAY, RT_ARRAY,
RT_ALIAS, RT_ALIAS,
@ -1515,6 +1517,7 @@ static struct {
{"string", k_type_string, parseString}, {"string", k_type_string, parseString},
{"binary", k_type_binary, parseBinary}, {"binary", k_type_binary, parseBinary},
{"table", k_type_table, parseTable}, {"table", k_type_table, parseTable},
{"table(nofallback)", k_type_table_no_fallback, NULL}, /* parseFunction will never be called */
{"integer", k_type_integer, parseInteger}, {"integer", k_type_integer, parseInteger},
{"array", k_type_array, parseArray}, {"array", k_type_array, parseArray},
{"alias", k_type_alias, parseAlias}, {"alias", k_type_alias, parseAlias},
@ -1535,6 +1538,7 @@ void initParser(UBool makeBinaryCollation)
U_STRING_INIT(k_type_binary, "binary", 6); U_STRING_INIT(k_type_binary, "binary", 6);
U_STRING_INIT(k_type_bin, "bin", 3); U_STRING_INIT(k_type_bin, "bin", 3);
U_STRING_INIT(k_type_table, "table", 5); U_STRING_INIT(k_type_table, "table", 5);
U_STRING_INIT(k_type_table_no_fallback, "table(nofallback)", 17);
U_STRING_INIT(k_type_int, "int", 3); U_STRING_INIT(k_type_int, "int", 3);
U_STRING_INIT(k_type_integer, "integer", 7); U_STRING_INIT(k_type_integer, "integer", 7);
U_STRING_INIT(k_type_array, "array", 5); U_STRING_INIT(k_type_array, "array", 5);
@ -1554,6 +1558,10 @@ void initParser(UBool makeBinaryCollation)
gMakeBinaryCollation = makeBinaryCollation; gMakeBinaryCollation = makeBinaryCollation;
} }
static U_INLINE isTable(enum EResourceType type) {
return (UBool)(type==RT_TABLE || type==RT_TABLE_NO_FALLBACK);
}
static enum EResourceType static enum EResourceType
parseResourceType(UErrorCode *status) parseResourceType(UErrorCode *status)
{ {
@ -1595,6 +1603,7 @@ parseResourceType(UErrorCode *status)
return result; return result;
} }
/* parse a non-top-level resource */
static struct SResource * static struct SResource *
parseResource(char *tag, const struct UString *comment, UErrorCode *status) parseResource(char *tag, const struct UString *comment, UErrorCode *status)
{ {
@ -1706,6 +1715,10 @@ parseResource(char *tag, const struct UString *comment, UErrorCode *status)
} }
/* printf("Type guessed as %s\n", resourceNames[resType]); */ /* printf("Type guessed as %s\n", resourceNames[resType]); */
} else if(resType == RT_TABLE_NO_FALLBACK) {
*status = U_INVALID_FORMAT_ERROR;
error(startline, "error: %s resource type not valid except on top bundle level", gResourceTypes[resType].nameChars);
return NULL;
} }
/* We should now know what we need to parse next, so call the appropriate parser /* We should now know what we need to parse next, so call the appropriate parser
@ -1722,6 +1735,7 @@ parseResource(char *tag, const struct UString *comment, UErrorCode *status)
return NULL; return NULL;
} }
/* parse the top-level resource */
struct SRBRoot * struct SRBRoot *
parse(UCHARBUF *buf, const char *currentInputDir, UErrorCode *status) parse(UCHARBUF *buf, const char *currentInputDir, UErrorCode *status)
{ {
@ -1753,21 +1767,11 @@ parse(UCHARBUF *buf, const char *currentInputDir, UErrorCode *status)
/* expect(TOK_OPEN_BRACE, NULL, &line, status); */ /* expect(TOK_OPEN_BRACE, NULL, &line, status); */
/* The following code is to make Empty bundle work no matter with :table specifer or not */ /* The following code is to make Empty bundle work no matter with :table specifer or not */
token = getToken(NULL, NULL, &line, status); token = getToken(NULL, NULL, &line, status);
if(token==TOK_COLON) {
if(token==TOK_COLON)
{
*status=U_ZERO_ERROR; *status=U_ZERO_ERROR;
}
else
{
*status=U_PARSE_ERROR;
}
if(U_SUCCESS(*status)){
bundleType=parseResourceType(status); bundleType=parseResourceType(status);
if(bundleType==RT_TABLE) if(isTable(bundleType))
{ {
expect(TOK_OPEN_BRACE, NULL, NULL, &line, status); expect(TOK_OPEN_BRACE, NULL, NULL, &line, status);
} }
@ -1779,12 +1783,16 @@ parse(UCHARBUF *buf, const char *currentInputDir, UErrorCode *status)
} }
else else
{ {
/* not a colon */
if(token==TOK_OPEN_BRACE) if(token==TOK_OPEN_BRACE)
{ {
*status=U_ZERO_ERROR; *status=U_ZERO_ERROR;
bundleType=RT_TABLE;
} }
else else
{ {
/* neither colon nor open brace */
*status=U_PARSE_ERROR;
error(line, "parse error, did not find open-brace '{' or colon ':', stopped with %s", u_errorName(*status)); error(line, "parse error, did not find open-brace '{' or colon ':', stopped with %s", u_errorName(*status));
} }
} }
@ -1796,6 +1804,15 @@ parse(UCHARBUF *buf, const char *currentInputDir, UErrorCode *status)
return NULL; return NULL;
} }
if(bundleType==RT_TABLE_NO_FALLBACK) {
/*
* Parse a top-level table with the table(nofallback) declaration.
* This is the same as a regular table, but also sets the
* URES_ATT_NO_FALLBACK flag in indexes[URES_INDEX_ATTRIBUTES] .
*/
bundle->noFallback=TRUE;
}
/* top-level tables need not handle special table names like "collations" */
realParseTable(bundle->fRoot, NULL, line, status); realParseTable(bundle->fRoot, NULL, line, status);
if (U_FAILURE(*status)) if (U_FAILURE(*status))

View File

@ -1,7 +1,7 @@
/* /*
******************************************************************************* *******************************************************************************
* *
* Copyright (C) 2000-2004, International Business Machines * Copyright (C) 2000-2005, International Business Machines
* Corporation and others. All Rights Reserved. * Corporation and others. All Rights Reserved.
* *
******************************************************************************* *******************************************************************************
@ -40,7 +40,7 @@ static const UDataInfo dataInfo= {
0, 0,
{0x52, 0x65, 0x73, 0x42}, /* dataFormat="resb" */ {0x52, 0x65, 0x73, 0x42}, /* dataFormat="resb" */
{1, 1, 0, 0}, /* formatVersion */ {1, 2, 0, 0}, /* formatVersion */
{1, 4, 0, 0} /* dataVersion take a look at version inside parsed resb*/ {1, 4, 0, 0} /* dataVersion take a look at version inside parsed resb*/
}; };
@ -393,12 +393,22 @@ void bundle_write(struct SRBRoot *bundle, const char *outputDir, const char *out
* write int32_t indexes[] after root and before the strings * write int32_t indexes[] after root and before the strings
* to make it easier to parse resource bundles in icuswap or from Java etc. * to make it easier to parse resource bundles in icuswap or from Java etc.
*/ */
uprv_memset(indexes, 0, sizeof(indexes));
indexes[URES_INDEX_LENGTH]= URES_INDEX_TOP; indexes[URES_INDEX_LENGTH]= URES_INDEX_TOP;
indexes[URES_INDEX_STRINGS_TOP]= (int32_t)(usedOffset>>2); indexes[URES_INDEX_STRINGS_TOP]= (int32_t)(usedOffset>>2);
indexes[URES_INDEX_RESOURCES_TOP]= (int32_t)(top>>2); indexes[URES_INDEX_RESOURCES_TOP]= (int32_t)(top>>2);
indexes[URES_INDEX_BUNDLE_TOP]= indexes[URES_INDEX_RESOURCES_TOP]; indexes[URES_INDEX_BUNDLE_TOP]= indexes[URES_INDEX_RESOURCES_TOP];
indexes[URES_INDEX_MAX_TABLE_LENGTH]= bundle->fMaxTableLength; indexes[URES_INDEX_MAX_TABLE_LENGTH]= bundle->fMaxTableLength;
/*
* formatVersion 1.2 (ICU 3.6):
* write indexes[URES_INDEX_ATTRIBUTES] with URES_ATT_NO_FALLBACK set or not set
* the memset() above initialized all indexes[] to 0
*/
if(bundle->noFallback) {
indexes[URES_INDEX_ATTRIBUTES]=URES_ATT_NO_FALLBACK;
}
/* write the indexes[] */ /* write the indexes[] */
udata_writeBlock(mem, indexes, sizeof(indexes)); udata_writeBlock(mem, indexes, sizeof(indexes));

View File

@ -1,7 +1,7 @@
/* /*
******************************************************************************* *******************************************************************************
* *
* Copyright (C) 2000-2003, International Business Machines * Copyright (C) 2000-2005, International Business Machines
* Corporation and others. All Rights Reserved. * Corporation and others. All Rights Reserved.
* *
******************************************************************************* *******************************************************************************
@ -41,6 +41,7 @@ struct SRBRoot {
int32_t fCount; int32_t fCount;
struct SResource *fRoot; struct SResource *fRoot;
int32_t fMaxTableLength; int32_t fMaxTableLength;
UBool noFallback; /* see URES_ATT_NO_FALLBACK */
}; };
struct SRBRoot *bundle_open(const struct UString* comment, UErrorCode *status); struct SRBRoot *bundle_open(const struct UString* comment, UErrorCode *status);