U_CAPI Resource U_EXPORT2 res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) { uint32_t offset=RES_GET_OFFSET(array); U_ASSERT(indexR>=0); /* to ensure the index is not negative */ switch(RES_GET_TYPE(array)) { case URES_ARRAY: { if (offset!=0) { /* empty if offset==0 */ const int32_t *p= pResData->pRoot+offset; if(indexR<*p) { return (Resource)p[1+indexR]; } } break; } case URES_ARRAY16: { const uint16_t *p=pResData->p16BitUnits+offset; if(indexR<*p) { return URES_MAKE_RESOURCE(URES_STRING_V2, p[1+indexR]); } break; } default: break; } return RES_BOGUS; }
U_CAPI const UChar * U_EXPORT2 res_getString(const ResourceData *pResData, Resource res, int32_t *pLength) { const UChar *p; uint32_t offset=RES_GET_OFFSET(res); int32_t length; if(RES_GET_TYPE(res)==URES_STRING_V2) { int32_t first; p=(const UChar *)(pResData->p16BitUnits+offset); first=*p; if(!U16_IS_TRAIL(first)) { length=u_strlen(p); } else if(first<0xdfef) { length=first&0x3ff; ++p; } else if(first<0xdfff) { length=((first-0xdfef)<<16)|p[1]; p+=2; } else { length=((int32_t)p[1]<<16)|p[2]; p+=3; } } else if(res==offset) /* RES_GET_TYPE(res)==URES_STRING */ { const int32_t *p32= res==0 ? &gEmptyString.length : pResData->pRoot+res; length=*p32++; p=(const UChar *)p32; } else { p=NULL; length=0; } if(pLength) { *pLength=length; } return p; }
U_CAPI Resource U_EXPORT2 res_getArrayItem(const ResourceData * pResData, Resource array, int32_t indexR) { uint32_t offset = RES_GET_OFFSET(array); switch (RES_GET_TYPE(array)) { case URES_ARRAY: { const int32_t * p = offset == 0 ? &gEmpty32 : pResData->pRoot + offset; if (indexR < *p) { return (Resource)p[1 + indexR]; } break; } case URES_ARRAY16: { const uint16_t * p = pResData->p16BitUnits + offset; if (indexR < *p) { return URES_MAKE_RESOURCE(URES_STRING_V2, p[1 + indexR]); } break; } default: break; } return RES_BOGUS; }
U_CAPI int32_t U_EXPORT2 res_countArrayItems(const ResourceData * pResData, Resource res) { uint32_t offset = RES_GET_OFFSET(res); switch (RES_GET_TYPE(res)) { case URES_STRING: case URES_STRING_V2: case URES_BINARY: case URES_ALIAS: case URES_INT: case URES_INT_VECTOR: return 1; case URES_ARRAY: case URES_TABLE32: return offset == 0 ? 0 : *(pResData->pRoot + offset); case URES_TABLE: return offset == 0 ? 0 : *((const uint16_t *)(pResData->pRoot + offset)); case URES_ARRAY16: case URES_TABLE16: return pResData->p16BitUnits[offset]; default: return 0; } }
U_CAPI Resource U_EXPORT2 res_getTableItemByIndex(const ResourceData * pResData, Resource table, int32_t indexR, const char ** key) { uint32_t offset = RES_GET_OFFSET(table); int32_t length; switch (RES_GET_TYPE(table)) { case URES_TABLE: { const uint16_t * p = offset == 0 ? &gEmpty16 : (const uint16_t *)(pResData->pRoot + offset); length = *p++; if (indexR < length) { const Resource * p32 = (const Resource *)(p + length + (~length & 1)); if (key != NULL) { *key = RES_GET_KEY16(pResData, p[indexR]); } return p32[indexR]; } break; } case URES_TABLE16: { const uint16_t * p = pResData->p16BitUnits + offset; length = *p++; if (indexR < length) { if (key != NULL) { *key = RES_GET_KEY16(pResData, p[indexR]); } return URES_MAKE_RESOURCE(URES_STRING_V2, p[length + indexR]); } break; } case URES_TABLE32: { const int32_t * p = offset == 0 ? &gEmpty32 : pResData->pRoot + offset; length = *p++; if (indexR < length) { if (key != NULL) { *key = RES_GET_KEY32(pResData, p[indexR]); } return (Resource)p[length + indexR]; } break; } default: break; } return RES_BOGUS; }
U_CAPI Resource U_EXPORT2 res_getTableItemByKey(const ResourceData * pResData, Resource table, int32_t * indexR, const char ** key) { uint32_t offset = RES_GET_OFFSET(table); int32_t length; int32_t idx; if (key == NULL || *key == NULL) { return RES_BOGUS; } switch (RES_GET_TYPE(table)) { case URES_TABLE: { const uint16_t * p = offset == 0 ? &gEmpty16 : (const uint16_t *)(pResData->pRoot + offset); length = *p++; *indexR = idx = _res_findTableItem(pResData, p, length, *key, key); if (idx >= 0) { const Resource * p32 = (const Resource *)(p + length + (~length & 1)); return p32[idx]; } break; } case URES_TABLE16: { const uint16_t * p = pResData->p16BitUnits + offset; length = *p++; *indexR = idx = _res_findTableItem(pResData, p, length, *key, key); if (idx >= 0) { return URES_MAKE_RESOURCE(URES_STRING_V2, p[length + idx]); } break; } case URES_TABLE32: { const int32_t * p = offset == 0 ? &gEmpty32 : pResData->pRoot + offset; length = *p++; *indexR = idx = _res_findTable32Item(pResData, p, length, *key, key); if (idx >= 0) { return (Resource)p[length + idx]; } break; } default: break; } return RES_BOGUS; }
U_CAPI const int32_t * U_EXPORT2 res_getIntVector(const ResourceData *pResData, Resource res, int32_t *pLength) { const int32_t *p; uint32_t offset=RES_GET_OFFSET(res); int32_t length; if(RES_GET_TYPE(res)==URES_INT_VECTOR) { p= offset==0 ? (const int32_t *)&gEmpty32 : pResData->pRoot+offset; length=*p++; } else { p=NULL; length=0; } if(pLength) { *pLength=length; } return p; }
U_CAPI const uint8_t * U_EXPORT2 res_getBinary(const ResourceData *pResData, Resource res, int32_t *pLength) { const uint8_t *p; uint32_t offset=RES_GET_OFFSET(res); int32_t length; if(RES_GET_TYPE(res)==URES_BINARY) { const int32_t *p32= offset==0 ? (const int32_t*)&gEmpty32 : pResData->pRoot+offset; length=*p32++; p=(const uint8_t *)p32; } else { p=NULL; length=0; } if(pLength) { *pLength=length; } return p; }
U_CAPI const UChar * U_EXPORT2 res_getAlias(const ResourceData *pResData, Resource res, int32_t *pLength) { const UChar *p; uint32_t offset=RES_GET_OFFSET(res); int32_t length; if(RES_GET_TYPE(res)==URES_ALIAS) { const int32_t *p32= offset==0 ? &gEmptyString.length : pResData->pRoot+offset; length=*p32++; p=(const UChar *)p32; } else { p=NULL; length=0; } if(pLength) { *pLength=length; } return p; }
/* * Enumerate one resource item and its children and extract dependencies from * aliases. * Code adapted from ures_preflightResource() and ures_swapResource(). */ static void ures_enumDependencies(const UDataSwapper *ds, const char *itemName, const Resource *inBundle, int32_t length, Resource res, const char *inKey, int32_t depth, CheckDependency check, void *context, UErrorCode *pErrorCode) { const Resource *p; int32_t offset; if(res==0 || RES_GET_TYPE(res)==URES_INT) { /* empty string or integer, nothing to do */ return; } /* all other types use an offset to point to their data */ offset=(int32_t)RES_GET_OFFSET(res); if(0<=length && length<=offset) { udata_printError(ds, "icupkg/ures_enumDependencies(%s res=%08x) resource offset exceeds bundle length %d\n", itemName, res, length); *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; return; } p=inBundle+offset; switch(RES_GET_TYPE(res)) { /* strings and aliases have physically the same value layout */ case URES_STRING: // we ignore all strings except top-level strings with a %%ALIAS key if(depth!=1) { break; } else { char key[8]; int32_t keyLength; keyLength=(int32_t)strlen(inKey); if(keyLength!=gAliasKeyLength) { break; } ds->swapInvChars(ds, inKey, gAliasKeyLength+1, key, pErrorCode); if(U_FAILURE(*pErrorCode)) { udata_printError(ds, "icupkg/ures_enumDependencies(%s res=%08x) string key contains variant characters\n", itemName, res); return; } if(0!=strcmp(key, gAliasKey)) { break; } } // for the top-level %%ALIAS string fall through to URES_ALIAS case URES_ALIAS: { char localeID[32]; const uint16_t *p16; int32_t i, stringLength; uint16_t u16, ored16; stringLength=udata_readInt32(ds, (int32_t)*p); /* top=offset+1+(string length +1)/2 rounded up */ offset+=1+((stringLength+1)+1)/2; if(offset>length) { break; // the resource does not fit into the bundle, print error below } // extract the locale ID from alias strings like // locale_ID/key1/key2/key3 // locale_ID if(U_IS_BIG_ENDIAN==ds->inIsBigEndian) { u16=0x2f; // slash in local endianness } else { u16=0x2f00; // slash in opposite endianness } p16=(const uint16_t *)(p+1); // Unicode string contents // search for the first slash for(i=0; i<stringLength && p16[i]!=u16; ++i) {} if(RES_GET_TYPE(res)==URES_ALIAS) { // ignore aliases with an initial slash: // /ICUDATA/... and /pkgname/... go to a different package // /LOCALE/... are for dynamic sideways fallbacks and don't go to a fixed bundle if(i==0) { break; // initial slash ('/') } // ignore the intra-bundle path starting from the first slash ('/') stringLength=i; } else /* URES_STRING */ { // the whole string should only consist of a locale ID if(i!=stringLength) { udata_printError(ds, "icupkg/ures_enumDependencies(%s res=%08x) %%ALIAS contains a '/'\n", itemName, res); *pErrorCode=U_UNSUPPORTED_ERROR; return; } } // convert the Unicode string to char * and // check that it has a bundle path but no package if(stringLength>=(int32_t)sizeof(localeID)) { udata_printError(ds, "icupkg/ures_enumDependencies(%s res=%08x) alias locale ID length %ld too long\n", itemName, res, stringLength); *pErrorCode=U_BUFFER_OVERFLOW_ERROR; return; } // convert the alias Unicode string to US-ASCII ored16=0; if(U_IS_BIG_ENDIAN==ds->inIsBigEndian) { for(i=0; i<stringLength; ++i) { u16=p16[i]; ored16|=u16; localeID[i]=(char)u16; } } else { for(i=0; i<stringLength; ++i) { u16=p16[i]; ored16|=u16; localeID[i]=(char)(u16>>8); } ored16=(uint16_t)((ored16<<8)|(ored16>>8)); } localeID[stringLength]=0; if(ored16>0x7f) { udata_printError(ds, "icupkg/ures_enumDependencies(%s res=%08x) alias string contains non-ASCII characters\n", itemName, res); *pErrorCode=U_INVALID_CHAR_FOUND; return; } #if (U_CHARSET_FAMILY==U_EBCDIC_FAMILY) // swap to EBCDIC // our swapper is probably not the right one, but // the function uses it only for printing errors uprv_ebcdicFromAscii(ds, localeID, stringLength, localeID, pErrorCode); if(U_FAILURE(*pErrorCode)) { return; } #endif #if U_CHARSET_FAMILY!=U_ASCII_FAMILY && U_CHARSET_FAMILY!=U_EBCDIC_FAMILY # error Unknown U_CHARSET_FAMILY value! #endif checkIDSuffix(itemName, localeID, -1, ".res", check, context, pErrorCode); } break; case URES_TABLE: case URES_TABLE32: { const uint16_t *pKey16; const int32_t *pKey32; Resource item; int32_t i, count; if(RES_GET_TYPE(res)==URES_TABLE) { /* get table item count */ pKey16=(const uint16_t *)p; count=ds->readUInt16(*pKey16++); pKey32=NULL; /* top=((1+ table item count)/2 rounded up)+(table item count) */ offset+=((1+count)+1)/2; } else { /* get table item count */ pKey32=(const int32_t *)p; count=udata_readInt32(ds, *pKey32++); pKey16=NULL; /* top=(1+ table item count)+(table item count) */ offset+=1+count; } p=inBundle+offset; /* pointer to table resources */ offset+=count; if(offset>length) { break; // the resource does not fit into the bundle, print error below } /* recurse */ for(i=0; i<count; ++i) { item=ds->readUInt32(*p++); ures_enumDependencies( ds, itemName, inBundle, length, item, ((const char *)inBundle)+ (pKey16!=NULL ? ds->readUInt16(pKey16[i]) : udata_readInt32(ds, pKey32[i])), depth+1, check, context, pErrorCode); if(U_FAILURE(*pErrorCode)) { udata_printError(ds, "icupkg/ures_enumDependencies(%s table res=%08x)[%d].recurse(%08x) failed\n", itemName, res, i, item); break; } } } break; case URES_ARRAY: { Resource item; int32_t i, count; /* top=offset+1+(array length) */ count=udata_readInt32(ds, (int32_t)*p++); offset+=1+count; if(offset>length) { break; // the resource does not fit into the bundle, print error below } /* recurse */ for(i=0; i<count; ++i) { item=ds->readUInt32(*p++); ures_enumDependencies( ds, itemName, inBundle, length, item, NULL, depth+1, check, context, pErrorCode); if(U_FAILURE(*pErrorCode)) { udata_printError(ds, "icupkg/ures_enumDependencies(%s array res=%08x)[%d].recurse(%08x) failed\n", itemName, res, i, item); break; } } } break; default: break; } if(U_FAILURE(*pErrorCode)) { /* nothing to do */ } else if(0<=length && length<offset) { udata_printError(ds, "icupkg/ures_enumDependencies(%s res=%08x) resource limit exceeds bundle length %d\n", itemName, res, length); *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; } }