/* get a const char* pointer to the key with the keyOffset byte offset from pRoot */ #define RES_GET_KEY16(pResData, keyOffset) \
((keyOffset)<(pResData)->localKeyLimit ? \
(constchar *)(pResData)->pRoot+(keyOffset) : \
(pResData)->poolBundleKeys+(keyOffset)-(pResData)->localKeyLimit)
/* get the root resource */
pResData->pRoot = static_cast<const int32_t*>(inBytes);
pResData->rootRes = static_cast<Resource>(*pResData->pRoot);
pResData->p16BitUnits=&gEmpty16;
/* formatVersion 1.1 must have a root item and at least 5 indexes */ if(length>=0 && (length/4)<((formatVersion[0]==1 && formatVersion[1]==0) ? 1 : 1+5)) {
*errorCode=U_INVALID_FORMAT_ERROR;
res_unload(pResData); return;
}
/* currently, we accept only resources that have a Table as their roots */
rootType = static_cast<UResType>(RES_GET_TYPE(pResData->rootRes)); if(!URES_IS_TABLE(rootType)) {
*errorCode=U_INVALID_FORMAT_ERROR;
res_unload(pResData); return;
}
if(formatVersion[0]==1 && formatVersion[1]==0) {
pResData->localKeyLimit=0x10000; /* greater than any 16-bit key string offset */
} else { /* bundles with formatVersion 1.1 and later contain an indexes[] array */ const int32_t *indexes=pResData->pRoot+1;
int32_t indexLength=indexes[URES_INDEX_LENGTH]&0xff; if(indexLength<=URES_INDEX_MAX_TABLE_LENGTH) {
*errorCode=U_INVALID_FORMAT_ERROR;
res_unload(pResData); return;
} if( length>=0 &&
(length<((1+indexLength)<<2) ||
length<(indexes[URES_INDEX_BUNDLE_TOP]<<2))
) {
*errorCode=U_INVALID_FORMAT_ERROR;
res_unload(pResData); return;
} if(indexes[URES_INDEX_KEYS_TOP]>(1+indexLength)) {
pResData->localKeyLimit=indexes[URES_INDEX_KEYS_TOP]<<2;
} if(formatVersion[0]>=3) { // In formatVersion 1, the indexLength took up this whole int. // In version 2, bits 31..8 were reserved and always 0. // In version 3, they contain bits 23..0 of the poolStringIndexLimit. // Bits 27..24 are in indexes[URES_INDEX_ATTRIBUTES] bits 15..12.
pResData->poolStringIndexLimit = static_cast<int32_t>(static_cast<uint32_t>(indexes[URES_INDEX_LENGTH]) >> 8);
} if(indexLength>URES_INDEX_ATTRIBUTES) {
int32_t att=indexes[URES_INDEX_ATTRIBUTES];
pResData->noFallback = static_cast<UBool>(att & URES_ATT_NO_FALLBACK);
pResData->isPoolBundle = static_cast<UBool>((att & URES_ATT_IS_POOL_BUNDLE) != 0);
pResData->usesPoolBundle = static_cast<UBool>((att & URES_ATT_USES_POOL_BUNDLE) != 0);
pResData->poolStringIndexLimit|=(att&0xf000)<<12; // bits 15..12 -> 27..24
pResData->poolStringIndex16Limit = static_cast<int32_t>(static_cast<uint32_t>(att) >> 16);
} if((pResData->isPoolBundle || pResData->usesPoolBundle) && indexLength<=URES_INDEX_POOL_CHECKSUM) {
*errorCode=U_INVALID_FORMAT_ERROR;
res_unload(pResData); return;
} if( indexLength>URES_INDEX_16BIT_TOP &&
indexes[URES_INDEX_16BIT_TOP]>indexes[URES_INDEX_KEYS_TOP]
) {
pResData->p16BitUnits = reinterpret_cast<const uint16_t*>(pResData->pRoot + indexes[URES_INDEX_KEYS_TOP]);
}
}
if(formatVersion[0]==1 || U_CHARSET_FAMILY==U_ASCII_FAMILY) { /* * formatVersion 1: compare key strings in native-charset order * formatVersion 2 and up: compare key strings in ASCII order
*/
pResData->useNativeStrcmp=true;
}
}
static Resource
makeResourceFrom16(const ResourceData *pResData, int32_t res16) { if(res16<pResData->poolStringIndex16Limit) { // Pool string, nothing to do.
} else { // Local string, adjust the 16-bit offset to a regular one, // with a larger pool string index limit.
res16=res16-pResData->poolStringIndex16Limit+pResData->poolStringIndexLimit;
} return URES_MAKE_RESOURCE(URES_STRING_V2, res16);
}
UBool icu::ResourceTable::getKeyAndValue(int32_t i, constchar *&key, icu::ResourceValue &value) const { if(0 <= i && i < length) {
icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value); if (keys16 != nullptr) {
key = RES_GET_KEY16(&rdValue.getData(), keys16[i]);
} else {
key = RES_GET_KEY32(&rdValue.getData(), keys32[i]);
}
Resource res; if (items16 != nullptr) {
res = makeResourceFrom16(&rdValue.getData(), items16[i]);
} else {
res = items32[i];
} // Note: the ResourceTracer keeps a reference to the field of this // ResourceTable. This is OK because the ResourceTable should remain // alive for the duration that fields are being read from it // (including nested fields).
rdValue.setResource(res, ResourceTracer(fTraceInfo, key)); returntrue;
} returnfalse;
}
UBool icu::ResourceTable::findValue(constchar *key, ResourceValue &value) const {
icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value); constchar *realKey = nullptr;
int32_t i; if (keys16 != nullptr) {
i = _res_findTableItem(&rdValue.getData(), keys16, length, key, &realKey);
} else {
i = _res_findTable32Item(&rdValue.getData(), keys32, length, key, &realKey);
} if (i >= 0) {
Resource res; if (items16 != nullptr) {
res = makeResourceFrom16(&rdValue.getData(), items16[i]);
} else {
res = items32[i];
} // Same note about lifetime as in getKeyAndValue().
rdValue.setResource(res, ResourceTracer(fTraceInfo, key)); returntrue;
} returnfalse;
}
UBool icu::ResourceArray::getValue(int32_t i, icu::ResourceValue &value) const { if(0 <= i && i < length) {
icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value); // Note: the ResourceTracer keeps a reference to the field of this // ResourceArray. This is OK because the ResourceArray should remain // alive for the duration that fields are being read from it // (including nested fields).
rdValue.setResource(
internalGetResource(&rdValue.getData(), i),
ResourceTracer(fTraceInfo, i)); returntrue;
} returnfalse;
}
/* if you come in with an empty path, you'll be getting back the same resource */ if(!uprv_strlen(pathP)) { return r;
}
/* one needs to have an aggregate resource in order to search in it */ if(!URES_IS_CONTAINER(type)) { return RES_BOGUS;
}
while(nextSepP && *pathP && t1 != RES_BOGUS && URES_IS_CONTAINER(type)) { /* 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 != nullptr) { 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 {
*path = uprv_strchr(pathP, 0);
}
/* if the resource is a table */ /* try the key based access */ if(URES_IS_TABLE(type)) {
*key = pathP;
t2 = res_getTableItemByKey(pResData, t1, &indexR, key);
} elseif(URES_IS_ARRAY(type)) {
indexR = uprv_strtol(pathP, &closeIndex, 10); if(indexR >= 0 && *closeIndex == 0) {
t2 = res_getArrayItem(pResData, t1, indexR);
} else {
t2 = RES_BOGUS; /* have an array, but don't have a valid index */
}
*key = nullptr;
} else { /* can't do much here, except setting t2 to bogus */
t2 = RES_BOGUS;
}
t1 = t2;
type = (UResType)RES_GET_TYPE(t1); /* position pathP to next resource key/index */
pathP = *path;
}
/* * Need to always enumerate the entire item tree, * track the lowest address of any item to use as the limit for char keys[], * track the highest address of any item to return the size of the data. * * We should have thought of storing those in the data... * It is possible to extend the data structure by putting additional values * in places that are inaccessible by ordinary enumeration of the item tree. * For example, additional integers could be stored at the beginning or * end of the key strings; this could be indicated by a minor version number, * and the data swapping would have to know about these values. * * The data structure does not forbid keys to be shared, so we must swap * all keys once instead of each key when it is referenced. * * These swapping functions assume that a resource bundle always has a length * that is a multiple of 4 bytes. * Currently, this is trivially true because genrb writes bundle tree leaves * physically first, before their branches, so that the root table with its * array of resource items (uint32_t values) is always last.
*/
/* definitions for table sorting ------------------------ */
/* * row of a temporary array * * gets platform-endian key string indexes and sorting indexes; * after sorting this array by keys, the actual key/value arrays are permutated * according to the sorting indexes
*/ typedefstruct Row {
int32_t keyIndex, sortIndex;
} Row;
switch(RES_GET_TYPE(res)) { case URES_TABLE16: case URES_STRING_V2: case URES_INT: case URES_ARRAY16: /* integer, or points to 16-bit units, nothing to do here */ return; default: break;
}
/* all other types use an offset to point to their data */
offset = static_cast<int32_t>(RES_GET_OFFSET(res)); if(offset==0) { /* special offset indicating an empty item */ return;
} if (pTempTable->resFlags[offset >> 5] & (static_cast<uint32_t>(1) << (offset & 0x1f))) { /* we already swapped this resource item */ return;
} else { /* mark it as swapped now */
pTempTable->resFlags[offset >> 5] |= static_cast<uint32_t>(1) << (offset & 0x1f);
}
p=inBundle+offset;
q=outBundle+offset;
switch(RES_GET_TYPE(res)) { case URES_ALIAS: /* physically same value layout as string, fall through */
U_FALLTHROUGH; case URES_STRING:
count = udata_readInt32(ds, static_cast<int32_t>(*p)); /* swap length */
ds->swapArray32(ds, p, 4, q, pErrorCode); /* swap each char16_t (the terminating NUL would not change) */
ds->swapArray16(ds, p+1, 2*count, q+1, pErrorCode); break; case URES_BINARY:
count = udata_readInt32(ds, static_cast<int32_t>(*p)); /* swap length */
ds->swapArray32(ds, p, 4, q, pErrorCode); /* no need to swap or copy bytes - ures_swap() copied them all */
/* swap known formats */ #if !UCONFIG_NO_COLLATION if( key!=nullptr && /* the binary is in a table */
(key!=gUnknownKey ? /* its table key string is "%%CollationBin" */
0==ds->compareInvChars(ds, key, -1,
gCollationBinKey, UPRV_LENGTHOF(gCollationBinKey)-1) : /* its table key string is unknown but it looks like a collation binary */
ucol_looksLikeCollationBinary(ds, p+1, count))
) {
ucol_swap(ds, p+1, count, q+1, pErrorCode);
} #endif break; case URES_TABLE: case URES_TABLE32:
{ const uint16_t *pKey16;
uint16_t *qKey16;
if(pTempTable->majorFormatVersion>1 || ds->inCharset==ds->outCharset) { /* no need to sort, just swap the offset/value arrays */ if(pKey16!=nullptr) {
ds->swapArray16(ds, pKey16, count*2, qKey16, pErrorCode);
ds->swapArray32(ds, p, count*4, q, pErrorCode);
} else { /* swap key offsets and items as one array */
ds->swapArray32(ds, pKey32, count*2*4, qKey32, pErrorCode);
} break;
}
/* * We need to sort tables by outCharset key strings because they * sort differently for different charset families. * ures_swap() already set pTempTable->keyChars appropriately. * First we set up a temporary table with the key indexes and * sorting indexes and sort that. * Then we permutate and copy/swap the actual values.
*/ if(pKey16!=nullptr) { for(i=0; i<count; ++i) {
pTempTable->rows[i].keyIndex=ds->readUInt16(pKey16[i]);
pTempTable->rows[i].sortIndex=i;
}
} else { for(i=0; i<count; ++i) {
pTempTable->rows[i].keyIndex=udata_readInt32(ds, pKey32[i]);
pTempTable->rows[i].sortIndex=i;
}
}
uprv_sortArray(pTempTable->rows, count, sizeof(Row),
ures_compareRows, pTempTable->keyChars, false, pErrorCode); if(U_FAILURE(*pErrorCode)) {
udata_printError(ds, "ures_swapResource(table res=%08x).uprv_sortArray(%d items) failed\n",
res, count); return;
}
/* * copy/swap/permutate items * * If we swap in-place, then the permutation must use another * temporary array (pTempTable->resort) * before the results are copied to the outBundle.
*/ /* keys */ if(pKey16!=nullptr) {
uint16_t *rKey16;
/* check data format and format version */
pInfo=(const UDataInfo *)((constchar *)inData+4); if(!(
pInfo->dataFormat[0]==0x52 && /* dataFormat="ResB" */
pInfo->dataFormat[1]==0x65 &&
pInfo->dataFormat[2]==0x73 &&
pInfo->dataFormat[3]==0x42 && /* formatVersion 1.1+ or 2.x or 3.x */
((pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1) ||
pInfo->formatVersion[0]==2 || pInfo->formatVersion[0]==3)
)) {
udata_printError(ds, "ures_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not a resource bundle\n",
pInfo->dataFormat[0], pInfo->dataFormat[1],
pInfo->dataFormat[2], pInfo->dataFormat[3],
pInfo->formatVersion[0], pInfo->formatVersion[1]);
*pErrorCode=U_UNSUPPORTED_ERROR; return 0;
}
tempTable.majorFormatVersion=pInfo->formatVersion[0];
/* a resource bundle must contain at least one resource item */ if(length<0) {
bundleLength=-1;
} else {
bundleLength=(length-headerSize)/4;
/* formatVersion 1.1 must have a root item and at least 5 indexes */ if(bundleLength<(1+5)) {
udata_printError(ds, "ures_swap(): too few bytes (%d after header) for a resource bundle\n",
length-headerSize);
*pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; return 0;
}
}
/* track which resources we have already swapped */
uint32_t stackResFlags[STACK_ROW_CAPACITY];
int32_t resFlagsLength;
/* * We need one bit per 4 resource bundle bytes so that we can track * every possible Resource for whether we have swapped it already. * Multiple Resource words can refer to the same bundle offsets * for sharing identical values. * We could optimize this by allocating only for locations above * where Resource values are stored (above keys & strings).
*/
resFlagsLength=(length+31)>>5; /* number of bytes needed */
resFlagsLength=(resFlagsLength+3)&~3; /* multiple of 4 bytes for uint32_t */ if(resFlagsLength<=(int32_t)sizeof(stackResFlags)) {
tempTable.resFlags=stackResFlags;
} else {
tempTable.resFlags=(uint32_t *)uprv_malloc(resFlagsLength); if(tempTable.resFlags==nullptr) {
udata_printError(ds, "ures_swap(): unable to allocate memory for tracking resources\n");
*pErrorCode=U_MEMORY_ALLOCATION_ERROR; return 0;
}
}
uprv_memset(tempTable.resFlags, 0, resFlagsLength);
/* copy the bundle for binary and inaccessible data */ if(inData!=outData) {
uprv_memcpy(outBundle, inBundle, 4*top);
}
/* swap the key strings, but not the padding bytes (0xaa) after the last string and its NUL */
udata_swapInvStringBlock(ds, inBundle+keysBottom, 4*(keysTop-keysBottom),
outBundle+keysBottom, pErrorCode); if(U_FAILURE(*pErrorCode)) {
udata_printError(ds, "ures_swap().udata_swapInvStringBlock(keys[%d]) failed\n", 4*(keysTop-keysBottom)); if(tempTable.resFlags!=stackResFlags) {
uprv_free(tempTable.resFlags);
} return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.