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; }
static void printOutBundle(FILE *out, UConverter *converter, UResourceBundle *resource, int32_t indent, const char *pname, UErrorCode *status) { static const UChar cr[] = { '\n' }; /* int32_t noOfElements = ures_getSize(resource);*/ int32_t i = 0; const char *key = ures_getKey(resource); switch(ures_getType(resource)) { case RES_STRING : { int32_t len=0; const UChar* thestr = ures_getString(resource, &len, status); UChar *string = quotedString(thestr); /* TODO: String truncation */ if(trunc && len > truncsize) { char msg[128]; printIndent(out, converter, indent); sprintf(msg, "// WARNING: this resource, size %li is truncated to %li\n", (long)len, (long)(truncsize/2)); printCString(out, converter, msg, -1); len = truncsize/2; } printIndent(out, converter, indent); if(key != NULL) { static const UChar openStr[] = { 0x0020, 0x007B, 0x0020, 0x0022 }; /* " { \"" */ static const UChar closeStr[] = { 0x0022, 0x0020, 0x007D }; /* "\" }" */ printCString(out, converter, key, (int32_t)uprv_strlen(key)); printString(out, converter, openStr, (int32_t)(sizeof(openStr)/sizeof(*openStr))); printString(out, converter, string, len); printString(out, converter, closeStr, (int32_t)(sizeof(closeStr) / sizeof(*closeStr))); } else { static const UChar openStr[] = { 0x0022 }; /* "\"" */ static const UChar closeStr[] = { 0x0022, 0x002C }; /* "\"," */ printString(out, converter, openStr, (int32_t)(sizeof(openStr) / sizeof(*openStr))); printString(out, converter, string, (int32_t)(u_strlen(string))); printString(out, converter, closeStr, (int32_t)(sizeof(closeStr) / sizeof(*closeStr))); } if(verbose) { printCString(out, converter, "// STRING", -1); } printString(out, converter, cr, (int32_t)(sizeof(cr) / sizeof(*cr))); uprv_free(string); } break; case RES_INT : { static const UChar openStr[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0020, 0x007B, 0x0020 }; /* ":int { " */ static const UChar closeStr[] = { 0x0020, 0x007D }; /* " }" */ UChar num[20]; printIndent(out, converter, indent); if(key != NULL) { printCString(out, converter, key, -1); } printString(out, converter, openStr, (int32_t)(sizeof(openStr) / sizeof(*openStr))); uprv_itou(num, 20, ures_getInt(resource, status), 10, 0); printString(out, converter, num, u_strlen(num)); printString(out, converter, closeStr, (int32_t)(sizeof(closeStr) / sizeof(*closeStr))); if(verbose) { printCString(out, converter, "// INT", -1); } printString(out, converter, cr, (int32_t)(sizeof(cr) / sizeof(*cr))); break; } case RES_BINARY : { int32_t len = 0; const int8_t *data = (const int8_t *)ures_getBinary(resource, &len, status); if(trunc && len > truncsize) { char msg[128]; printIndent(out, converter, indent); sprintf(msg, "// WARNING: this resource, size %li is truncated to %li\n", (long)len, (long)(truncsize/2)); printCString(out, converter, msg, -1); len = truncsize; } if(U_SUCCESS(*status)) { static const UChar openStr[] = { 0x003A, 0x0062, 0x0069, 0x006E, 0x0061, 0x0072, 0x0079, 0x0020, 0x007B, 0x0020 }; /* ":binary { " */ static const UChar closeStr[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */ printIndent(out, converter, indent); if(key != NULL) { printCString(out, converter, key, -1); } printString(out, converter, openStr, (int32_t)(sizeof(openStr) / sizeof(*openStr))); for(i = 0; i<len; i++) { printHex(out, converter, *data++); } printString(out, converter, closeStr, (int32_t)(sizeof(closeStr) / sizeof(*closeStr))); if(verbose) { printCString(out, converter, " // BINARY", -1); } printString(out, converter, cr, (int32_t)(sizeof(cr) / sizeof(*cr))); } else { reportError(pname, status, "getting binary value"); } } break; case RES_INT_VECTOR : { int32_t len = 0; const int32_t *data = ures_getIntVector(resource, &len, status); if(U_SUCCESS(*status)) { static const UChar openStr[] = { 0x003A, 0x0069, 0x006E, 0x0074, 0x0076, 0x0065, 0x0063, 0x0074, 0x006F, 0x0072, 0x0020, 0x007B, 0x0020 }; /* ":intvector { " */ static const UChar closeStr[] = { 0x0020, 0x007D, 0x0020 }; /* " } " */ UChar num[20]; printIndent(out, converter, indent); if(key != NULL) { printCString(out, converter, key, -1); } printString(out, converter, openStr, (int32_t)(sizeof(openStr) / sizeof(*openStr))); for(i = 0; i < len - 1; i++) { int32_t numLen = uprv_itou(num, 20, data[i], 10, 0); num[numLen++] = 0x002C; /* ',' */ num[numLen++] = 0x0020; /* ' ' */ num[numLen] = 0; printString(out, converter, num, u_strlen(num)); } if(len > 0) { uprv_itou(num, 20, data[len - 1], 10, 0); printString(out, converter, num, u_strlen(num)); } printString(out, converter, closeStr, (int32_t)(sizeof(closeStr) / sizeof(*closeStr))); if(verbose) { printCString(out, converter, "// INTVECTOR", -1); } printString(out, converter, cr, (int32_t)(sizeof(cr) / sizeof(*cr))); } else { reportError(pname, status, "getting int vector"); } } break; case RES_TABLE : case RES_ARRAY : { static const UChar openStr[] = { 0x007B }; /* "{" */ static const UChar closeStr[] = { 0x007D, '\n' }; /* "}\n" */ UResourceBundle *t = NULL; ures_resetIterator(resource); printIndent(out, converter, indent); if(key != NULL) { printCString(out, converter, key, -1); } printString(out, converter, openStr, (int32_t)(sizeof(openStr) / sizeof(*openStr))); if(verbose) { if(ures_getType(resource) == RES_TABLE) { printCString(out, converter, "// TABLE", -1); } else { printCString(out, converter, "// ARRAY", -1); } } printString(out, converter, cr, (int32_t)(sizeof(cr) / sizeof(*cr))); if(suppressAliases == FALSE) { while(U_SUCCESS(*status) && ures_hasNext(resource)) { t = ures_getNextResource(resource, t, status); if(U_SUCCESS(*status)) { printOutBundle(out, converter, t, indent+indentsize, pname, status); } else { reportError(pname, status, "While processing table"); *status = U_ZERO_ERROR; } } } else { /* we have to use low level access to do this */ Resource r = RES_BOGUS; for(i = 0; i < ures_getSize(resource); i++) { /* need to know if it's an alias */ if(ures_getType(resource) == RES_TABLE) { r = derb_getTableItem(resource->fResData.pRoot, resource->fRes, (int16_t)i); key = derb_getTableKey(resource->fResData.pRoot, resource->fRes, (int16_t)i); } else { r = derb_getArrayItem(resource->fResData.pRoot, resource->fRes, i); } if(U_SUCCESS(*status)) { if(RES_GET_TYPE(r) == RES_ALIAS) { printOutAlias(out, converter, resource, r, key, indent+indentsize, pname, status); } else { t = ures_getByIndex(resource, i, t, status); printOutBundle(out, converter, t, indent+indentsize, pname, status); } } else { reportError(pname, status, "While processing table"); *status = U_ZERO_ERROR; } } } printIndent(out, converter, indent); printString(out, converter, closeStr, (int32_t)(sizeof(closeStr) / sizeof(*closeStr))); ures_close(t); } break; default: break; } }
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; Resource t2; int32_t indexR = 0; UResType type = (UResType)RES_GET_TYPE(t1); /* 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 != NULL) { *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); 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 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) { t2 = res_getArrayItem(pResData, t1, indexR); } else { t2 = RES_BOGUS; /* have an array, but don't have a valid index */ } *key = NULL; } 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; } return t1; }
U_CAPI UResType U_EXPORT2 res_getPublicType(Resource res) { return (UResType)gPublicTypes[RES_GET_TYPE(res)]; }
static void res_init(ResourceData *pResData, UVersionInfo formatVersion, const void *inBytes, int32_t length, UErrorCode *errorCode) { UResType rootType; /* get the root resource */ pResData->pRoot=(const int32_t *)inBytes; pResData->rootRes=(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=(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(indexLength>URES_INDEX_ATTRIBUTES) { int32_t att=indexes[URES_INDEX_ATTRIBUTES]; pResData->noFallback=(UBool)(att&URES_ATT_NO_FALLBACK); pResData->isPoolBundle=(UBool)((att&URES_ATT_IS_POOL_BUNDLE)!=0); pResData->usesPoolBundle=(UBool)((att&URES_ATT_USES_POOL_BUNDLE)!=0); } 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=(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; } }
/* * 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; } }
static void res_init(ResourceData *pResData, UVersionInfo formatVersion, const void *inBytes, int32_t length, UErrorCode *errorCode) { UResType rootType; /* get the root resource */ pResData->pRoot=(const int32_t *)inBytes; pResData->rootRes=(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=(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=(int32_t)((uint32_t)indexes[URES_INDEX_LENGTH]>>8); } if(indexLength>URES_INDEX_ATTRIBUTES) { int32_t att=indexes[URES_INDEX_ATTRIBUTES]; pResData->noFallback=(UBool)(att&URES_ATT_NO_FALLBACK); pResData->isPoolBundle=(UBool)((att&URES_ATT_IS_POOL_BUNDLE)!=0); pResData->usesPoolBundle=(UBool)((att&URES_ATT_USES_POOL_BUNDLE)!=0); pResData->poolStringIndexLimit|=(att&0xf000)<<12; // bits 15..12 -> 27..24 pResData->poolStringIndex16Limit=(int32_t)((uint32_t)att>>16); }
bool CPointBase::r_WriteVal( LPCTSTR pszKey, CGString & sVal ) const { ADDTOCALLSTACK("CPointBase::r_WriteVal"); if ( !strnicmp( pszKey, "STATICS", 7 ) ) { pszKey += 7; const CGrayMapBlock * pBlock = g_World.GetMapBlock( *(this) ); if ( !pBlock ) return false; if ( *pszKey == '\0' ) { int iStaticQty = 0; for ( size_t i = 0; i < pBlock->m_Statics.GetStaticQty(); i++ ) { const CUOStaticItemRec * pStatic = pBlock->m_Statics.GetStatic( i ); CPointMap ptTest( pStatic->m_x+pBlock->m_x, pStatic->m_y+pBlock->m_y, pStatic->m_z, this->m_map ); if ( this->GetDist( ptTest ) > 0 ) continue; iStaticQty++; } sVal.FormatVal( iStaticQty ); return true; } SKIP_SEPARATORS( pszKey ); const CUOStaticItemRec * pStatic = NULL; int iStatic = 0; int type = 0; if ( !strnicmp( pszKey, "FINDID", 6 ) ) { pszKey += 6; SKIP_SEPARATORS( pszKey ); iStatic = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iStatic ); if ( type == 0 ) type = RES_ITEMDEF; SKIP_SEPARATORS( pszKey ); } else { iStatic = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iStatic ); } if ( type == RES_ITEMDEF ) { const CItemBase * pItemDef = CItemBase::FindItemBase(static_cast<ITEMID_TYPE>(RES_GET_INDEX(iStatic))); if ( !pItemDef ) { sVal.FormatVal( 0 ); return false; } for ( size_t i = 0; i < pBlock->m_Statics.GetStaticQty(); pStatic = NULL, i++ ) { pStatic = pBlock->m_Statics.GetStatic( i ); CPointMap ptTest( pStatic->m_x+pBlock->m_x, pStatic->m_y+pBlock->m_y, pStatic->m_z, this->m_map); if ( this->GetDist( ptTest ) > 0 ) continue; if ( pStatic->GetDispID() == pItemDef->GetDispID() ) break; } } else { for ( size_t i = 0; i < pBlock->m_Statics.GetStaticQty(); pStatic = NULL, i++ ) { pStatic = pBlock->m_Statics.GetStatic( i ); CPointMap ptTest( pStatic->m_x+pBlock->m_x, pStatic->m_y+pBlock->m_y, pStatic->m_z, this->m_map); if ( this->GetDist( ptTest ) > 0 ) continue; if ( iStatic == 0 ) break; iStatic--; } } if ( !pStatic ) { sVal.FormatHex(0); return true; } SKIP_SEPARATORS( pszKey ); if ( !*pszKey ) pszKey = "ID"; ITEMID_TYPE idTile = pStatic->GetDispID(); if ( !strnicmp( pszKey, "COLOR", 5 ) ) { sVal.FormatHex( pStatic->m_wHue ); return true; } else if ( !strnicmp( pszKey, "ID", 2 ) ) { sVal.FormatHex( idTile ); return true; } else if ( !strnicmp( pszKey, "Z", 1 ) ) { sVal.FormatVal( pStatic->m_z ); return true; } // Check the script def for the item. CItemBase * pItemDef = CItemBase::FindItemBase( idTile ); if ( pItemDef == NULL ) { DEBUG_ERR(("Must have ITEMDEF section for item ID 0%x\n", idTile )); return false; } return pItemDef->r_WriteVal( pszKey, sVal, &g_Serv ); } else if ( !strnicmp( pszKey, "COMPONENTS", 10) ) { pszKey += 10; CRegionLinks rlinks; const CRegionBase* pRegion = NULL; CItem* pItem = NULL; const CGrayMulti* pMulti = NULL; const CUOMultiItemRec2* pMultiItem = NULL; size_t iMultiQty = GetRegions(REGION_TYPE_MULTI, rlinks); if ( *pszKey == '\0' ) { int iComponentQty = 0; for (size_t i = 0; i < iMultiQty; i++) { pRegion = rlinks.GetAt(i); if (pRegion == NULL) continue; pItem = pRegion->GetResourceID().ItemFind(); if (pItem == NULL) continue; const CPointMap ptMulti = pItem->GetTopPoint(); pMulti = g_Cfg.GetMultiItemDefs(pItem); if (pMulti == NULL) continue; size_t iQty = pMulti->GetItemCount(); for (size_t ii = 0; ii < iQty; ii++) { pMultiItem = pMulti->GetItem(ii); if (pMultiItem == NULL) break; if (pMultiItem->m_visible == 0) continue; CPointMap ptTest(static_cast<WORD>(ptMulti.m_x + pMultiItem->m_dx), static_cast<WORD>(ptMulti.m_y + pMultiItem->m_dy), static_cast<signed char>(ptMulti.m_z + pMultiItem->m_dz), this->m_map); if (GetDist(ptTest) > 0) continue; iComponentQty++; } } sVal.FormatVal( iComponentQty ); return true; } SKIP_SEPARATORS( pszKey ); int iComponent = 0; int type = 0; if ( strnicmp( pszKey, "FINDID", 6 ) == 0 ) { pszKey += 6; SKIP_SEPARATORS( pszKey ); iComponent = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iComponent ); if ( type == 0 ) type = RES_ITEMDEF; SKIP_SEPARATORS( pszKey ); } else { iComponent = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iComponent ); } if ( type == RES_ITEMDEF ) { const CItemBase * pItemDef = CItemBase::FindItemBase(static_cast<ITEMID_TYPE>(RES_GET_INDEX(iComponent))); if ( pItemDef == NULL ) { sVal.FormatVal( 0 ); return false; } for (size_t i = 0; i < iMultiQty; i++) { pRegion = rlinks.GetAt(i); if (pRegion == NULL) continue; pItem = pRegion->GetResourceID().ItemFind(); if (pItem == NULL) continue; const CPointMap ptMulti = pItem->GetTopPoint(); pMulti = g_Cfg.GetMultiItemDefs(pItem); if (pMulti == NULL) continue; size_t iQty = pMulti->GetItemCount(); for (size_t ii = 0; ii < iQty; pMultiItem = NULL, ii++) { pMultiItem = pMulti->GetItem(ii); if (pMultiItem == NULL) break; if (pMultiItem->m_visible == 0) continue; CPointMap ptTest(static_cast<WORD>(ptMulti.m_x + pMultiItem->m_dx), static_cast<WORD>(ptMulti.m_y + pMultiItem->m_dy), static_cast<signed char>(ptMulti.m_z + pMultiItem->m_dz), this->m_map); if (GetDist(ptTest) > 0) continue; const CItemBase* pMultiItemDef = CItemBase::FindItemBase(pMultiItem->GetDispID()); if (pMultiItemDef != NULL && pMultiItemDef->GetDispID() == pItemDef->GetDispID()) break; } if (pMultiItem != NULL) break; } } else { for (size_t i = 0; i < iMultiQty; i++) { pRegion = rlinks.GetAt(i); if (pRegion == NULL) continue; pItem = pRegion->GetResourceID().ItemFind(); if (pItem == NULL) continue; const CPointMap ptMulti = pItem->GetTopPoint(); pMulti = g_Cfg.GetMultiItemDefs(pItem); if (pMulti == NULL) continue; size_t iQty = pMulti->GetItemCount(); for (size_t ii = 0; ii < iQty; pMultiItem = NULL, ii++) { pMultiItem = pMulti->GetItem(ii); if (pMultiItem == NULL) break; if (pMultiItem->m_visible == 0) continue; CPointMap ptTest(static_cast<WORD>(ptMulti.m_x + pMultiItem->m_dx), static_cast<WORD>(ptMulti.m_y + pMultiItem->m_dy), static_cast<signed char>(ptMulti.m_z + pMultiItem->m_dz), this->m_map); if (GetDist(ptTest) > 0) continue; if (iComponent == 0) break; iComponent--; } if (pMultiItem != NULL) break; } } if ( pMultiItem == NULL ) { sVal.FormatHex(0); return true; } SKIP_SEPARATORS( pszKey ); if ( !*pszKey ) pszKey = "ID"; ITEMID_TYPE idTile = pMultiItem->GetDispID(); if ( strnicmp( pszKey, "ID", 2 ) == 0 ) { sVal.FormatHex( idTile ); return true; } else if ( strnicmp( pszKey, "MULTI", 5 ) == 0 ) { pszKey += 5; if (*pszKey != '\0') { SKIP_SEPARATORS(pszKey); return pItem->r_WriteVal( pszKey, sVal, &g_Serv ); } sVal.FormatHex( pItem->GetUID() ); return true; } else if ( strnicmp( pszKey, "Z", 1 ) == 0 ) { sVal.FormatVal( pItem->GetTopZ() + pMultiItem->m_dz ); return true; } // Check the script def for the item. CItemBase * pItemDef = CItemBase::FindItemBase( idTile ); if ( pItemDef == NULL ) { DEBUG_ERR(("Must have ITEMDEF section for item ID 0%x\n", idTile )); return false; } return pItemDef->r_WriteVal( pszKey, sVal, &g_Serv ); } int index = FindTableHeadSorted( pszKey, sm_szLoadKeys, COUNTOF(sm_szLoadKeys)-1 ); if ( index < 0 ) return false; switch ( index ) { case PT_M: case PT_MAP: sVal.FormatVal(m_map); break; case PT_X: sVal.FormatVal(m_x); break; case PT_Y: sVal.FormatVal(m_y); break; case PT_Z: sVal.FormatVal(m_z); break; case PT_ISNEARTYPE: { pszKey += 10; SKIP_SEPARATORS( pszKey ); SKIP_ARGSEP( pszKey ); int iType = g_Cfg.ResourceGetIndexType( RES_TYPEDEF, pszKey ); int iDistance = 0; bool bCheckMulti = false; SKIP_IDENTIFIERSTRING( pszKey ); SKIP_SEPARATORS( pszKey ); SKIP_ARGSEP( pszKey ); if ( *pszKey ) iDistance = Exp_GetVal(pszKey); if ( *pszKey ) bCheckMulti = Exp_GetVal(pszKey) != 0; sVal.FormatVal( g_World.IsItemTypeNear(*this, static_cast<IT_TYPE>(iType), iDistance, bCheckMulti)); break; } case PT_REGION: { // Check that the syntax is correct. if ( pszKey[6] && pszKey[6] != '.' ) return false; CRegionWorld * pRegionTemp = dynamic_cast <CRegionWorld*>(this->GetRegion(REGION_TYPE_AREA | REGION_TYPE_MULTI)); if ( !pszKey[6] ) { // We're just checking if the reference is valid. sVal.FormatVal( pRegionTemp? 1:0 ); return true; } // We're trying to retrieve a property from the region. pszKey += 7; if ( pRegionTemp ) return pRegionTemp->r_WriteVal( pszKey, sVal, &g_Serv ); return false; } case PT_ROOM: { if ( pszKey[4] && pszKey[4] != '.' ) return false; CRegionBase * pRegionTemp = this->GetRegion( REGION_TYPE_ROOM ); if ( !pszKey[4] ) { sVal.FormatVal( pRegionTemp? 1:0 ); return true; } pszKey += 5; if ( pRegionTemp ) return pRegionTemp->r_WriteVal( pszKey, sVal, &g_Serv ); return false; } case PT_SECTOR: { if ( pszKey[6] == '.' ) { pszKey += 7; CSector * pSectorTemp = this->GetSector(); if (pSectorTemp) return pSectorTemp->r_WriteVal(pszKey, sVal, &g_Serv); } return false; } default: { const CUOMapMeter * pMeter = g_World.GetMapMeter(*this); if ( pMeter ) { switch( index ) { case PT_TYPE: { CItemTypeDef * pTypeDef = g_World.GetTerrainItemTypeDef( pMeter->m_wTerrainIndex ); if ( pTypeDef != NULL ) sVal = pTypeDef->GetResourceName(); else sVal = ""; } return true; case PT_TERRAIN: { pszKey += strlen(sm_szLoadKeys[index]); if ( *pszKey == '.' ) // do we have an argument? { SKIP_SEPARATORS( pszKey ); if ( !strnicmp( pszKey, "Z", 1 )) { sVal.FormatVal( pMeter->m_z ); return( true ); } return( false ); } else { sVal.FormatHex( pMeter->m_wTerrainIndex ); } } return true; } } return false; } } return true; }