| Index: source/common/uresdata.cpp
|
| diff --git a/source/common/uresdata.c b/source/common/uresdata.cpp
|
| similarity index 79%
|
| rename from source/common/uresdata.c
|
| rename to source/common/uresdata.cpp
|
| index 53887fbfdc3174584fded6440d5bd932383584ee..fbfb56de6b52045f586f1228ac7891f015a1dcd2 100644
|
| --- a/source/common/uresdata.c
|
| +++ b/source/common/uresdata.cpp
|
| @@ -3,7 +3,7 @@
|
| * Copyright (C) 1999-2015, International Business Machines Corporation
|
| * and others. All Rights Reserved.
|
| *******************************************************************************
|
| -* file name: uresdata.c
|
| +* file name: uresdata.cpp
|
| * encoding: US-ASCII
|
| * tab size: 8 (not used)
|
| * indentation:4
|
| @@ -23,13 +23,14 @@
|
| #include "unicode/utf16.h"
|
| #include "cmemory.h"
|
| #include "cstring.h"
|
| +#include "resource.h"
|
| #include "uarrsort.h"
|
| -#include "udataswp.h"
|
| +#include "uassert.h"
|
| #include "ucol_swp.h"
|
| +#include "udataswp.h"
|
| #include "uinvchar.h"
|
| #include "uresdata.h"
|
| #include "uresimp.h"
|
| -#include "uassert.h"
|
|
|
| /*
|
| * Resource access helpers
|
| @@ -133,7 +134,7 @@ _res_findTable32Item(const ResourceData *pResData, const int32_t *keyOffsets, in
|
|
|
| static UBool U_CALLCONV
|
| isAcceptable(void *context,
|
| - const char *type, const char *name,
|
| + const char * /*type*/, const char * /*name*/,
|
| const UDataInfo *pInfo) {
|
| uprv_memcpy(context, pInfo->formatVersion, 4);
|
| return (UBool)(
|
| @@ -310,7 +311,7 @@ res_getString(const ResourceData *pResData, Resource res, int32_t *pLength) {
|
| int32_t length;
|
| if(RES_GET_TYPE(res)==URES_STRING_V2) {
|
| int32_t first;
|
| - if(offset<pResData->poolStringIndexLimit) {
|
| + if((int32_t)offset<pResData->poolStringIndexLimit) {
|
| p=(const UChar *)pResData->poolBundleStrings+offset;
|
| } else {
|
| p=(const UChar *)pResData->p16BitUnits+(offset-pResData->poolStringIndexLimit);
|
| @@ -342,6 +343,45 @@ res_getString(const ResourceData *pResData, Resource res, int32_t *pLength) {
|
| return p;
|
| }
|
|
|
| +namespace {
|
| +
|
| +/**
|
| + * CLDR string value (three empty-set symbols)=={2205, 2205, 2205}
|
| + * prevents fallback to the parent bundle.
|
| + * TODO: combine with other code that handles this marker, use EMPTY_SET constant.
|
| + * TODO: maybe move to uresbund.cpp?
|
| + */
|
| +UBool isNoInheritanceMarker(const ResourceData *pResData, Resource res) {
|
| + uint32_t offset=RES_GET_OFFSET(res);
|
| + if (offset == 0) {
|
| + // empty string
|
| + } else if (res == offset) {
|
| + const int32_t *p32=pResData->pRoot+res;
|
| + int32_t length=*p32;
|
| + const UChar *p=(const UChar *)p32;
|
| + return length == 3 && p[2] == 0x2205 && p[3] == 0x2205 && p[4] == 0x2205;
|
| + } else if (RES_GET_TYPE(res) == URES_STRING_V2) {
|
| + const UChar *p;
|
| + if((int32_t)offset<pResData->poolStringIndexLimit) {
|
| + p=(const UChar *)pResData->poolBundleStrings+offset;
|
| + } else {
|
| + p=(const UChar *)pResData->p16BitUnits+(offset-pResData->poolStringIndexLimit);
|
| + }
|
| + int32_t first=*p;
|
| + if (first == 0x2205) { // implicit length
|
| + return p[1] == 0x2205 && p[2] == 0x2205 && p[3] == 0;
|
| + } else if (first == 0xdc03) { // explicit length 3 (should not occur)
|
| + return p[1] == 0x2205 && p[2] == 0x2205 && p[3] == 0x2205;
|
| + } else {
|
| + // Assume that the string has not been stored with more length units than necessary.
|
| + return FALSE;
|
| + }
|
| + }
|
| + return FALSE;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| U_CAPI const UChar * U_EXPORT2
|
| res_getAlias(const ResourceData *pResData, Resource res, int32_t *pLength) {
|
| const UChar *p;
|
| @@ -423,6 +463,116 @@ res_countArrayItems(const ResourceData *pResData, Resource res) {
|
| }
|
| }
|
|
|
| +namespace {
|
| +
|
| +int32_t getArrayLength(const ResourceData *pResData, Resource res) {
|
| + uint32_t offset=RES_GET_OFFSET(res);
|
| + if(offset == 0) {
|
| + return 0;
|
| + }
|
| + int32_t type = RES_GET_TYPE(res);
|
| + if(type == URES_ARRAY) {
|
| + return *(pResData->pRoot+offset);
|
| + } else if(type == URES_ARRAY16) {
|
| + return pResData->p16BitUnits[offset];
|
| + } else {
|
| + return 0;
|
| + }
|
| +}
|
| +
|
| +int32_t getTableLength(const ResourceData *pResData, Resource res) {
|
| + uint32_t offset=RES_GET_OFFSET(res);
|
| + if(offset == 0) {
|
| + return 0;
|
| + }
|
| + int32_t type = RES_GET_TYPE(res);
|
| + if(type == URES_TABLE) {
|
| + return *((const uint16_t *)(pResData->pRoot+offset));
|
| + } else if(type == URES_TABLE16) {
|
| + return pResData->p16BitUnits[offset];
|
| + } else if(type == URES_TABLE32) {
|
| + return *(pResData->pRoot+offset);
|
| + } else {
|
| + return 0;
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +U_NAMESPACE_BEGIN
|
| +
|
| +ResourceDataValue::~ResourceDataValue() {}
|
| +
|
| +UResType ResourceDataValue::getType() const {
|
| + return res_getPublicType(res);
|
| +}
|
| +
|
| +const UChar *ResourceDataValue::getString(int32_t &length, UErrorCode &errorCode) const {
|
| + if(U_FAILURE(errorCode)) {
|
| + return NULL;
|
| + }
|
| + const UChar *s = res_getString(pResData, res, &length);
|
| + if(s == NULL) {
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + }
|
| + return s;
|
| +}
|
| +
|
| +const UChar *ResourceDataValue::getAliasString(int32_t &length, UErrorCode &errorCode) const {
|
| + if(U_FAILURE(errorCode)) {
|
| + return NULL;
|
| + }
|
| + const UChar *s = res_getAlias(pResData, res, &length);
|
| + if(s == NULL) {
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + }
|
| + return s;
|
| +}
|
| +
|
| +int32_t ResourceDataValue::getInt(UErrorCode &errorCode) const {
|
| + if(U_FAILURE(errorCode)) {
|
| + return 0;
|
| + }
|
| + if(RES_GET_TYPE(res) != URES_INT) {
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + }
|
| + return RES_GET_INT(res);
|
| +}
|
| +
|
| +uint32_t ResourceDataValue::getUInt(UErrorCode &errorCode) const {
|
| + if(U_FAILURE(errorCode)) {
|
| + return 0;
|
| + }
|
| + if(RES_GET_TYPE(res) != URES_INT) {
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + }
|
| + return RES_GET_UINT(res);
|
| +}
|
| +
|
| +const int32_t *ResourceDataValue::getIntVector(int32_t &length, UErrorCode &errorCode) const {
|
| + if(U_FAILURE(errorCode)) {
|
| + return NULL;
|
| + }
|
| + const int32_t *iv = res_getIntVector(pResData, res, &length);
|
| + if(iv == NULL) {
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + }
|
| + return iv;
|
| +}
|
| +
|
| +const uint8_t *ResourceDataValue::getBinary(int32_t &length, UErrorCode &errorCode) const {
|
| + if(U_FAILURE(errorCode)) {
|
| + return NULL;
|
| + }
|
| + const uint8_t *b = res_getBinary(pResData, res, &length);
|
| + if(b == NULL) {
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + }
|
| + return b;
|
| +}
|
| +
|
| +U_NAMESPACE_END
|
| +
|
| static Resource
|
| makeResourceFrom16(const ResourceData *pResData, int32_t res16) {
|
| if(res16<pResData->poolStringIndex16Limit) {
|
| @@ -541,6 +691,93 @@ res_getResource(const ResourceData *pResData, const char *key) {
|
| return res_getTableItemByKey(pResData, pResData->rootRes, &idx, &realKey);
|
| }
|
|
|
| +// TODO: Ported from Java, but enumerating at this low level may prevent us
|
| +// from doing necessary things, like resolving aliases,
|
| +// which need access to higher-level UResourceBundle code.
|
| +// Consider porting the low-level Container/Array/Table classes from Java,
|
| +// with getters for keys and values,
|
| +// and doing the enumeration in the higher-level code on top of those accessors.
|
| +U_CFUNC void
|
| +ures_getAllTableItems(const ResourceData *pResData, Resource table,
|
| + icu::ResourceDataValue &value, icu::ResourceTableSink &sink,
|
| + UErrorCode &errorCode) {
|
| + if(U_FAILURE(errorCode)) { return; }
|
| + const uint16_t *keys16 = NULL;
|
| + const int32_t *keys32 = NULL;
|
| + const uint16_t *items16 = NULL;
|
| + const Resource *items32 = NULL;
|
| + uint32_t offset = RES_GET_OFFSET(table);
|
| + int32_t length = 0;
|
| + switch(RES_GET_TYPE(table)) {
|
| + case URES_TABLE: {
|
| + if (offset != 0) { /* empty if offset==0 */
|
| + keys16 = (const uint16_t *)(pResData->pRoot+offset);
|
| + length = *keys16++;
|
| + items32 = (const Resource *)(keys16+length+(~length&1));
|
| + }
|
| + break;
|
| + }
|
| + case URES_TABLE16: {
|
| + keys16 = pResData->p16BitUnits+offset;
|
| + length = *keys16++;
|
| + items16 = keys16 + length;
|
| + break;
|
| + }
|
| + case URES_TABLE32: {
|
| + if (offset != 0) { /* empty if offset==0 */
|
| + keys32 = pResData->pRoot+offset;
|
| + length = *keys32++;
|
| + items32 = (const Resource *)keys32 + length;
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + return;
|
| + }
|
| +
|
| + for (int32_t i = 0; i < length; ++i) {
|
| + const char *key;
|
| + if (keys16 != NULL) {
|
| + key=RES_GET_KEY16(pResData, keys16[i]);
|
| + } else {
|
| + key=RES_GET_KEY32(pResData, keys32[i]);
|
| + }
|
| + Resource res;
|
| + if (items16 != NULL) {
|
| + res = makeResourceFrom16(pResData, items16[i]);
|
| + } else {
|
| + res = items32[i];
|
| + }
|
| + int32_t type = RES_GET_TYPE(res);
|
| + if (URES_IS_ARRAY(type)) {
|
| + int32_t numItems = getArrayLength(pResData, res);
|
| + icu::ResourceArraySink *subSink = sink.getOrCreateArraySink(key, numItems, errorCode);
|
| + if (subSink != NULL) {
|
| + ures_getAllArrayItems(pResData, res, value, *subSink, errorCode);
|
| + }
|
| + } else if (URES_IS_TABLE(type)) {
|
| + int32_t numItems = getTableLength(pResData, res);
|
| + icu::ResourceTableSink *subSink = sink.getOrCreateTableSink(key, numItems, errorCode);
|
| + if (subSink != NULL) {
|
| + ures_getAllTableItems(pResData, res, value, *subSink, errorCode);
|
| + }
|
| + /* TODO: settle on how to deal with aliases, port to Java
|
| + } else if (type == URES_ALIAS) {
|
| + // aliases not handled in resource enumeration
|
| + errorCode = U_UNSUPPORTED_ERROR;
|
| + return; */
|
| + } else if (isNoInheritanceMarker(pResData, res)) {
|
| + sink.putNoFallback(key, errorCode);
|
| + } else {
|
| + value.setResource(res);
|
| + sink.put(key, value, errorCode);
|
| + }
|
| + if(U_FAILURE(errorCode)) { return; }
|
| + }
|
| + sink.leave(errorCode);
|
| +}
|
| +
|
| U_CAPI Resource U_EXPORT2
|
| res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
|
| uint32_t offset=RES_GET_OFFSET(array);
|
| @@ -568,13 +805,69 @@ res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
|
| return RES_BOGUS;
|
| }
|
|
|
| +U_CFUNC void
|
| +ures_getAllArrayItems(const ResourceData *pResData, Resource array,
|
| + icu::ResourceDataValue &value, icu::ResourceArraySink &sink,
|
| + UErrorCode &errorCode) {
|
| + if(U_FAILURE(errorCode)) { return; }
|
| + const uint16_t *items16 = NULL;
|
| + const Resource *items32 = NULL;
|
| + uint32_t offset=RES_GET_OFFSET(array);
|
| + int32_t length = 0;
|
| + switch(RES_GET_TYPE(array)) {
|
| + case URES_ARRAY: {
|
| + if (offset!=0) { /* empty if offset==0 */
|
| + items32 = (const Resource *)pResData->pRoot+offset;
|
| + length = *items32++;
|
| + }
|
| + break;
|
| + }
|
| + case URES_ARRAY16: {
|
| + items16 = pResData->p16BitUnits+offset;
|
| + length = *items16++;
|
| + break;
|
| + }
|
| + default:
|
| + errorCode = U_RESOURCE_TYPE_MISMATCH;
|
| + return;
|
| + }
|
| +
|
| + for (int32_t i = 0; i < length; ++i) {
|
| + Resource res;
|
| + if (items16 != NULL) {
|
| + res = makeResourceFrom16(pResData, items16[i]);
|
| + } else {
|
| + res = items32[i];
|
| + }
|
| + int32_t type = RES_GET_TYPE(res);
|
| + if (URES_IS_ARRAY(type)) {
|
| + int32_t numItems = getArrayLength(pResData, res);
|
| + icu::ResourceArraySink *subSink = sink.getOrCreateArraySink(i, numItems, errorCode);
|
| + if (subSink != NULL) {
|
| + ures_getAllArrayItems(pResData, res, value, *subSink, errorCode);
|
| + }
|
| + } else if (URES_IS_TABLE(type)) {
|
| + int32_t numItems = getTableLength(pResData, res);
|
| + icu::ResourceTableSink *subSink = sink.getOrCreateTableSink(i, numItems, errorCode);
|
| + if (subSink != NULL) {
|
| + ures_getAllTableItems(pResData, res, value, *subSink, errorCode);
|
| + }
|
| + /* TODO: settle on how to deal with aliases, port to Java
|
| + } else if (type == URES_ALIAS) {
|
| + // aliases not handled in resource enumeration
|
| + errorCode = U_UNSUPPORTED_ERROR;
|
| + return; */
|
| + } else {
|
| + value.setResource(res);
|
| + sink.put(i, value, errorCode);
|
| + }
|
| + if(U_FAILURE(errorCode)) { return; }
|
| + }
|
| + sink.leave(errorCode);
|
| +}
|
| +
|
| U_CFUNC Resource
|
| res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key) {
|
| - /* 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.
|
| - */
|
| -
|
| char *pathP = *path, *nextSepP = *path;
|
| char *closeIndex = NULL;
|
| Resource t1 = r;
|
| @@ -601,6 +894,10 @@ res_findResource(const ResourceData *pResData, Resource r, char** path, const ch
|
| * and set path to the remaining part of the string
|
| */
|
| if(nextSepP != NULL) {
|
| + if(nextSepP == pathP) {
|
| + // Empty key string.
|
| + return RES_BOGUS;
|
| + }
|
| *nextSepP = 0; /* overwrite the separator with a NUL to terminate the key */
|
| *path = nextSepP+1;
|
| } else {
|
| @@ -615,14 +912,14 @@ res_findResource(const ResourceData *pResData, Resource r, char** path, const ch
|
| 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(*closeIndex == 0) {
|
| /* if we indeed have an index, try to get the item by index */
|
| t2 = res_getTableItemByIndex(pResData, t1, indexR, key);
|
| }
|
| }
|
| } else if(URES_IS_ARRAY(type)) {
|
| indexR = uprv_strtol(pathP, &closeIndex, 10);
|
| - if(closeIndex != pathP) {
|
| + if(*closeIndex == 0) {
|
| t2 = res_getArrayItem(pResData, t1, indexR);
|
| } else {
|
| t2 = RES_BOGUS; /* have an array, but don't have a valid index */
|
| @@ -1094,7 +1391,7 @@ ures_swap(const UDataSwapper *ds,
|
| */
|
| resFlagsLength=(length+31)>>5; /* number of bytes needed */
|
| resFlagsLength=(resFlagsLength+3)&~3; /* multiple of 4 bytes for uint32_t */
|
| - if(resFlagsLength<=sizeof(stackResFlags)) {
|
| + if(resFlagsLength<=(int32_t)sizeof(stackResFlags)) {
|
| tempTable.resFlags=stackResFlags;
|
| } else {
|
| tempTable.resFlags=(uint32_t *)uprv_malloc(resFlagsLength);
|
|
|