1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/tools/toolutil/pkgitems.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,632 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* 1.7 +* Copyright (C) 2003-2011, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +******************************************************************************* 1.11 +* file name: pkgitems.cpp 1.12 +* encoding: US-ASCII 1.13 +* tab size: 8 (not used) 1.14 +* indentation:4 1.15 +* 1.16 +* created on: 2005sep18 1.17 +* created by: Markus W. Scherer 1.18 +* 1.19 +* Companion file to package.cpp. Deals with details of ICU data item formats. 1.20 +* Used for item dependencies. 1.21 +* Contains adapted code from ucnv_bld.c (swapper code from 2003). 1.22 +*/ 1.23 + 1.24 +#include "unicode/utypes.h" 1.25 +#include "unicode/ures.h" 1.26 +#include "unicode/putil.h" 1.27 +#include "unicode/udata.h" 1.28 +#include "cstring.h" 1.29 +#include "uinvchar.h" 1.30 +#include "ucmndata.h" 1.31 +#include "udataswp.h" 1.32 +#include "swapimpl.h" 1.33 +#include "toolutil.h" 1.34 +#include "package.h" 1.35 +#include "pkg_imp.h" 1.36 + 1.37 +#include <stdio.h> 1.38 +#include <stdlib.h> 1.39 +#include <string.h> 1.40 + 1.41 +/* item formats in common */ 1.42 + 1.43 +#include "uresdata.h" 1.44 +#include "ucnv_bld.h" 1.45 +#include "ucnv_io.h" 1.46 + 1.47 +// general definitions ----------------------------------------------------- *** 1.48 + 1.49 +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 1.50 + 1.51 +U_CDECL_BEGIN 1.52 + 1.53 +static void U_CALLCONV 1.54 +printError(void *context, const char *fmt, va_list args) { 1.55 + vfprintf((FILE *)context, fmt, args); 1.56 +} 1.57 + 1.58 +U_CDECL_END 1.59 + 1.60 +// a data item in native-platform form ------------------------------------- *** 1.61 + 1.62 +U_NAMESPACE_BEGIN 1.63 + 1.64 +class NativeItem { 1.65 +public: 1.66 + NativeItem() : pItem(NULL), pInfo(NULL), bytes(NULL), swapped(NULL), length(0) {} 1.67 + NativeItem(const Item *item, UDataSwapFn *swap) : swapped(NULL) { 1.68 + setItem(item, swap); 1.69 + } 1.70 + ~NativeItem() { 1.71 + delete [] swapped; 1.72 + } 1.73 + const UDataInfo *getDataInfo() const { 1.74 + return pInfo; 1.75 + } 1.76 + const uint8_t *getBytes() const { 1.77 + return bytes; 1.78 + } 1.79 + int32_t getLength() const { 1.80 + return length; 1.81 + } 1.82 + 1.83 + void setItem(const Item *item, UDataSwapFn *swap) { 1.84 + pItem=item; 1.85 + int32_t infoLength, itemHeaderLength; 1.86 + UErrorCode errorCode=U_ZERO_ERROR; 1.87 + pInfo=::getDataInfo(pItem->data, pItem->length, infoLength, itemHeaderLength, &errorCode); 1.88 + if(U_FAILURE(errorCode)) { 1.89 + exit(errorCode); // should succeed because readFile() checks headers 1.90 + } 1.91 + length=pItem->length-itemHeaderLength; 1.92 + 1.93 + if(pInfo->isBigEndian==U_IS_BIG_ENDIAN && pInfo->charsetFamily==U_CHARSET_FAMILY) { 1.94 + bytes=pItem->data+itemHeaderLength; 1.95 + } else { 1.96 + UDataSwapper *ds=udata_openSwapper((UBool)pInfo->isBigEndian, pInfo->charsetFamily, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); 1.97 + if(U_FAILURE(errorCode)) { 1.98 + fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n", 1.99 + pItem->name, u_errorName(errorCode)); 1.100 + exit(errorCode); 1.101 + } 1.102 + 1.103 + ds->printError=printError; 1.104 + ds->printErrorContext=stderr; 1.105 + 1.106 + swapped=new uint8_t[pItem->length]; 1.107 + if(swapped==NULL) { 1.108 + fprintf(stderr, "icupkg: unable to allocate memory for swapping \"%s\"\n", pItem->name); 1.109 + exit(U_MEMORY_ALLOCATION_ERROR); 1.110 + } 1.111 + swap(ds, pItem->data, pItem->length, swapped, &errorCode); 1.112 + pInfo=::getDataInfo(swapped, pItem->length, infoLength, itemHeaderLength, &errorCode); 1.113 + bytes=swapped+itemHeaderLength; 1.114 + udata_closeSwapper(ds); 1.115 + } 1.116 + } 1.117 + 1.118 +private: 1.119 + const Item *pItem; 1.120 + const UDataInfo *pInfo; 1.121 + const uint8_t *bytes; 1.122 + uint8_t *swapped; 1.123 + int32_t length; 1.124 +}; 1.125 + 1.126 +// check a dependency ------------------------------------------------------ *** 1.127 + 1.128 +/* 1.129 + * assemble the target item name from the source item name, an ID 1.130 + * and a suffix 1.131 + */ 1.132 +static void 1.133 +makeTargetName(const char *itemName, const char *id, int32_t idLength, const char *suffix, 1.134 + char *target, int32_t capacity, 1.135 + UErrorCode *pErrorCode) { 1.136 + const char *itemID; 1.137 + int32_t treeLength, suffixLength, targetLength; 1.138 + 1.139 + // get the item basename 1.140 + itemID=strrchr(itemName, '/'); 1.141 + if(itemID!=NULL) { 1.142 + ++itemID; 1.143 + } else { 1.144 + itemID=itemName; 1.145 + } 1.146 + 1.147 + // build the target string 1.148 + treeLength=(int32_t)(itemID-itemName); 1.149 + if(idLength<0) { 1.150 + idLength=(int32_t)strlen(id); 1.151 + } 1.152 + suffixLength=(int32_t)strlen(suffix); 1.153 + targetLength=treeLength+idLength+suffixLength; 1.154 + if(targetLength>=capacity) { 1.155 + fprintf(stderr, "icupkg/makeTargetName(%s) target item name length %ld too long\n", 1.156 + itemName, (long)targetLength); 1.157 + *pErrorCode=U_BUFFER_OVERFLOW_ERROR; 1.158 + return; 1.159 + } 1.160 + 1.161 + memcpy(target, itemName, treeLength); 1.162 + memcpy(target+treeLength, id, idLength); 1.163 + memcpy(target+treeLength+idLength, suffix, suffixLength+1); // +1 includes the terminating NUL 1.164 +} 1.165 + 1.166 +static void 1.167 +checkIDSuffix(const char *itemName, const char *id, int32_t idLength, const char *suffix, 1.168 + CheckDependency check, void *context, 1.169 + UErrorCode *pErrorCode) { 1.170 + char target[200]; 1.171 + makeTargetName(itemName, id, idLength, suffix, target, (int32_t)sizeof(target), pErrorCode); 1.172 + if(U_SUCCESS(*pErrorCode)) { 1.173 + check(context, itemName, target); 1.174 + } 1.175 +} 1.176 + 1.177 +/* assemble the target item name from the item's parent item name */ 1.178 +static void 1.179 +checkParent(const char *itemName, CheckDependency check, void *context, 1.180 + UErrorCode *pErrorCode) { 1.181 + const char *itemID, *parent, *parentLimit, *suffix; 1.182 + int32_t parentLength; 1.183 + 1.184 + // get the item basename 1.185 + itemID=strrchr(itemName, '/'); 1.186 + if(itemID!=NULL) { 1.187 + ++itemID; 1.188 + } else { 1.189 + itemID=itemName; 1.190 + } 1.191 + 1.192 + // get the item suffix 1.193 + suffix=strrchr(itemID, '.'); 1.194 + if(suffix==NULL) { 1.195 + // empty suffix, point to the end of the string 1.196 + suffix=strrchr(itemID, 0); 1.197 + } 1.198 + 1.199 + // get the position of the last '_' 1.200 + for(parentLimit=suffix; parentLimit>itemID && *--parentLimit!='_';) {} 1.201 + 1.202 + if(parentLimit!=itemID) { 1.203 + // get the parent item name by truncating the last part of this item's name */ 1.204 + parent=itemID; 1.205 + parentLength=(int32_t)(parentLimit-itemID); 1.206 + } else { 1.207 + // no '_' in the item name: the parent is the root bundle 1.208 + parent="root"; 1.209 + parentLength=4; 1.210 + if((suffix-itemID)==parentLength && 0==memcmp(itemID, parent, parentLength)) { 1.211 + // the item itself is "root", which does not depend on a parent 1.212 + return; 1.213 + } 1.214 + } 1.215 + checkIDSuffix(itemName, parent, parentLength, suffix, check, context, pErrorCode); 1.216 +} 1.217 + 1.218 +// get dependencies from resource bundles ---------------------------------- *** 1.219 + 1.220 +static const UChar SLASH=0x2f; 1.221 + 1.222 +/* 1.223 + * Check for the alias from the string or alias resource res. 1.224 + */ 1.225 +static void 1.226 +checkAlias(const char *itemName, 1.227 + Resource res, const UChar *alias, int32_t length, UBool useResSuffix, 1.228 + CheckDependency check, void *context, UErrorCode *pErrorCode) { 1.229 + int32_t i; 1.230 + 1.231 + if(!uprv_isInvariantUString(alias, length)) { 1.232 + fprintf(stderr, "icupkg/ures_enumDependencies(%s res=%08x) alias string contains non-invariant characters\n", 1.233 + itemName, res); 1.234 + *pErrorCode=U_INVALID_CHAR_FOUND; 1.235 + return; 1.236 + } 1.237 + 1.238 + // extract the locale ID from alias strings like 1.239 + // locale_ID/key1/key2/key3 1.240 + // locale_ID 1.241 + 1.242 + // search for the first slash 1.243 + for(i=0; i<length && alias[i]!=SLASH; ++i) {} 1.244 + 1.245 + if(res_getPublicType(res)==URES_ALIAS) { 1.246 + // ignore aliases with an initial slash: 1.247 + // /ICUDATA/... and /pkgname/... go to a different package 1.248 + // /LOCALE/... are for dynamic sideways fallbacks and don't go to a fixed bundle 1.249 + if(i==0) { 1.250 + return; // initial slash ('/') 1.251 + } 1.252 + 1.253 + // ignore the intra-bundle path starting from the first slash ('/') 1.254 + length=i; 1.255 + } else /* URES_STRING */ { 1.256 + // the whole string should only consist of a locale ID 1.257 + if(i!=length) { 1.258 + fprintf(stderr, "icupkg/ures_enumDependencies(%s res=%08x) %%ALIAS contains a '/'\n", 1.259 + itemName, res); 1.260 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.261 + return; 1.262 + } 1.263 + } 1.264 + 1.265 + // convert the Unicode string to char * 1.266 + char localeID[32]; 1.267 + if(length>=(int32_t)sizeof(localeID)) { 1.268 + fprintf(stderr, "icupkg/ures_enumDependencies(%s res=%08x) alias locale ID length %ld too long\n", 1.269 + itemName, res, (long)length); 1.270 + *pErrorCode=U_BUFFER_OVERFLOW_ERROR; 1.271 + return; 1.272 + } 1.273 + u_UCharsToChars(alias, localeID, length); 1.274 + localeID[length]=0; 1.275 + 1.276 + checkIDSuffix(itemName, localeID, -1, (useResSuffix ? ".res" : ""), check, context, pErrorCode); 1.277 +} 1.278 + 1.279 +/* 1.280 + * Enumerate one resource item and its children and extract dependencies from 1.281 + * aliases. 1.282 + */ 1.283 +static void 1.284 +ures_enumDependencies(const char *itemName, 1.285 + const ResourceData *pResData, 1.286 + Resource res, const char *inKey, const char *parentKey, int32_t depth, 1.287 + CheckDependency check, void *context, 1.288 + Package *pkg, 1.289 + UErrorCode *pErrorCode) { 1.290 + switch(res_getPublicType(res)) { 1.291 + case URES_STRING: 1.292 + { 1.293 + UBool useResSuffix = TRUE; 1.294 + // Check for %%ALIAS 1.295 + if(depth==1 && inKey!=NULL) { 1.296 + if(0!=strcmp(inKey, "%%ALIAS")) { 1.297 + break; 1.298 + } 1.299 + } 1.300 + // Check for %%DEPENDENCY 1.301 + else if(depth==2 && parentKey!=NULL) { 1.302 + if(0!=strcmp(parentKey, "%%DEPENDENCY")) { 1.303 + break; 1.304 + } 1.305 + useResSuffix = FALSE; 1.306 + } else { 1.307 + // we ignore all other strings 1.308 + break; 1.309 + } 1.310 + int32_t length; 1.311 + const UChar *alias=res_getString(pResData, res, &length); 1.312 + checkAlias(itemName, res, alias, length, useResSuffix, check, context, pErrorCode); 1.313 + } 1.314 + break; 1.315 + case URES_ALIAS: 1.316 + { 1.317 + int32_t length; 1.318 + const UChar *alias=res_getAlias(pResData, res, &length); 1.319 + checkAlias(itemName, res, alias, length, TRUE, check, context, pErrorCode); 1.320 + } 1.321 + break; 1.322 + case URES_TABLE: 1.323 + { 1.324 + /* recurse */ 1.325 + int32_t count=res_countArrayItems(pResData, res); 1.326 + for(int32_t i=0; i<count; ++i) { 1.327 + const char *itemKey; 1.328 + Resource item=res_getTableItemByIndex(pResData, res, i, &itemKey); 1.329 + ures_enumDependencies( 1.330 + itemName, pResData, 1.331 + item, itemKey, 1.332 + inKey, depth+1, 1.333 + check, context, 1.334 + pkg, 1.335 + pErrorCode); 1.336 + if(U_FAILURE(*pErrorCode)) { 1.337 + fprintf(stderr, "icupkg/ures_enumDependencies(%s table res=%08x)[%d].recurse(%s: %08x) failed\n", 1.338 + itemName, res, i, itemKey, item); 1.339 + break; 1.340 + } 1.341 + } 1.342 + } 1.343 + break; 1.344 + case URES_ARRAY: 1.345 + { 1.346 + /* recurse */ 1.347 + int32_t count=res_countArrayItems(pResData, res); 1.348 + for(int32_t i=0; i<count; ++i) { 1.349 + Resource item=res_getArrayItem(pResData, res, i); 1.350 + ures_enumDependencies( 1.351 + itemName, pResData, 1.352 + item, NULL, 1.353 + inKey, depth+1, 1.354 + check, context, 1.355 + pkg, 1.356 + pErrorCode); 1.357 + if(U_FAILURE(*pErrorCode)) { 1.358 + fprintf(stderr, "icupkg/ures_enumDependencies(%s array res=%08x)[%d].recurse(%08x) failed\n", 1.359 + itemName, res, i, item); 1.360 + break; 1.361 + } 1.362 + } 1.363 + } 1.364 + break; 1.365 + default: 1.366 + break; 1.367 + } 1.368 +} 1.369 + 1.370 +static void 1.371 +ures_enumDependencies(const char *itemName, const UDataInfo *pInfo, 1.372 + const uint8_t *inBytes, int32_t length, 1.373 + CheckDependency check, void *context, 1.374 + Package *pkg, 1.375 + UErrorCode *pErrorCode) { 1.376 + ResourceData resData; 1.377 + 1.378 + res_read(&resData, pInfo, inBytes, length, pErrorCode); 1.379 + if(U_FAILURE(*pErrorCode)) { 1.380 + fprintf(stderr, "icupkg: .res format version %02x.%02x not supported, or bundle malformed\n", 1.381 + pInfo->formatVersion[0], pInfo->formatVersion[1]); 1.382 + exit(U_UNSUPPORTED_ERROR); 1.383 + } 1.384 + 1.385 + /* 1.386 + * if the bundle attributes are present and the nofallback flag is not set, 1.387 + * then add the parent bundle as a dependency 1.388 + */ 1.389 + if(pInfo->formatVersion[0]>1 || (pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1)) { 1.390 + if(!resData.noFallback) { 1.391 + /* this bundle participates in locale fallback */ 1.392 + checkParent(itemName, check, context, pErrorCode); 1.393 + } 1.394 + } 1.395 + 1.396 + icu::NativeItem nativePool; 1.397 + 1.398 + if(resData.usesPoolBundle) { 1.399 + char poolName[200]; 1.400 + makeTargetName(itemName, "pool", 4, ".res", poolName, (int32_t)sizeof(poolName), pErrorCode); 1.401 + if(U_FAILURE(*pErrorCode)) { 1.402 + return; 1.403 + } 1.404 + check(context, itemName, poolName); 1.405 + int32_t index=pkg->findItem(poolName); 1.406 + if(index<0) { 1.407 + // We cannot work with a bundle if its pool resource is missing. 1.408 + // check() already printed a complaint. 1.409 + return; 1.410 + } 1.411 + // TODO: Cache the native version in the Item itself. 1.412 + nativePool.setItem(pkg->getItem(index), ures_swap); 1.413 + const UDataInfo *poolInfo=nativePool.getDataInfo(); 1.414 + if(poolInfo->formatVersion[0]<=1) { 1.415 + fprintf(stderr, "icupkg: %s is not a pool bundle\n", poolName); 1.416 + return; 1.417 + } 1.418 + const int32_t *poolIndexes=(const int32_t *)nativePool.getBytes()+1; 1.419 + int32_t poolIndexLength=poolIndexes[URES_INDEX_LENGTH]&0xff; 1.420 + if(!(poolIndexLength>URES_INDEX_POOL_CHECKSUM && 1.421 + (poolIndexes[URES_INDEX_ATTRIBUTES]&URES_ATT_IS_POOL_BUNDLE)) 1.422 + ) { 1.423 + fprintf(stderr, "icupkg: %s is not a pool bundle\n", poolName); 1.424 + return; 1.425 + } 1.426 + if(resData.pRoot[1+URES_INDEX_POOL_CHECKSUM]==poolIndexes[URES_INDEX_POOL_CHECKSUM]) { 1.427 + resData.poolBundleKeys=(const char *)(poolIndexes+poolIndexLength); 1.428 + } else { 1.429 + fprintf(stderr, "icupkg: %s has mismatched checksum for %s\n", poolName, itemName); 1.430 + return; 1.431 + } 1.432 + } 1.433 + 1.434 + ures_enumDependencies( 1.435 + itemName, &resData, 1.436 + resData.rootRes, NULL, NULL, 0, 1.437 + check, context, 1.438 + pkg, 1.439 + pErrorCode); 1.440 +} 1.441 + 1.442 +// get dependencies from conversion tables --------------------------------- *** 1.443 + 1.444 +/* code adapted from ucnv_swap() */ 1.445 +static void 1.446 +ucnv_enumDependencies(const UDataSwapper *ds, 1.447 + const char *itemName, const UDataInfo *pInfo, 1.448 + const uint8_t *inBytes, int32_t length, 1.449 + CheckDependency check, void *context, 1.450 + UErrorCode *pErrorCode) { 1.451 + uint32_t staticDataSize; 1.452 + 1.453 + const UConverterStaticData *inStaticData; 1.454 + 1.455 + const _MBCSHeader *inMBCSHeader; 1.456 + uint8_t outputType; 1.457 + 1.458 + /* check format version */ 1.459 + if(!( 1.460 + pInfo->formatVersion[0]==6 && 1.461 + pInfo->formatVersion[1]>=2 1.462 + )) { 1.463 + fprintf(stderr, "icupkg/ucnv_enumDependencies(): .cnv format version %02x.%02x not supported\n", 1.464 + pInfo->formatVersion[0], pInfo->formatVersion[1]); 1.465 + exit(U_UNSUPPORTED_ERROR); 1.466 + } 1.467 + 1.468 + /* read the initial UConverterStaticData structure after the UDataInfo header */ 1.469 + inStaticData=(const UConverterStaticData *)inBytes; 1.470 + 1.471 + if( length<(int32_t)sizeof(UConverterStaticData) || 1.472 + (uint32_t)length<(staticDataSize=ds->readUInt32(inStaticData->structSize)) 1.473 + ) { 1.474 + udata_printError(ds, "icupkg/ucnv_enumDependencies(): too few bytes (%d after header) for an ICU .cnv conversion table\n", 1.475 + length); 1.476 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.477 + return; 1.478 + } 1.479 + 1.480 + inBytes+=staticDataSize; 1.481 + length-=(int32_t)staticDataSize; 1.482 + 1.483 + /* check for supported conversionType values */ 1.484 + if(inStaticData->conversionType==UCNV_MBCS) { 1.485 + /* MBCS data */ 1.486 + uint32_t mbcsHeaderLength, mbcsHeaderFlags, mbcsHeaderOptions; 1.487 + int32_t extOffset; 1.488 + 1.489 + inMBCSHeader=(const _MBCSHeader *)inBytes; 1.490 + 1.491 + if(length<(int32_t)sizeof(_MBCSHeader)) { 1.492 + udata_printError(ds, "icupkg/ucnv_enumDependencies(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n", 1.493 + length); 1.494 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.495 + return; 1.496 + } 1.497 + if(inMBCSHeader->version[0]==4 && inMBCSHeader->version[1]>=1) { 1.498 + mbcsHeaderLength=MBCS_HEADER_V4_LENGTH; 1.499 + } else if(inMBCSHeader->version[0]==5 && inMBCSHeader->version[1]>=3 && 1.500 + ((mbcsHeaderOptions=ds->readUInt32(inMBCSHeader->options))& 1.501 + MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK)==0 1.502 + ) { 1.503 + mbcsHeaderLength=mbcsHeaderOptions&MBCS_OPT_LENGTH_MASK; 1.504 + } else { 1.505 + udata_printError(ds, "icupkg/ucnv_enumDependencies(): unsupported _MBCSHeader.version %d.%d\n", 1.506 + inMBCSHeader->version[0], inMBCSHeader->version[1]); 1.507 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.508 + return; 1.509 + } 1.510 + 1.511 + mbcsHeaderFlags=ds->readUInt32(inMBCSHeader->flags); 1.512 + extOffset=(int32_t)(mbcsHeaderFlags>>8); 1.513 + outputType=(uint8_t)mbcsHeaderFlags; 1.514 + 1.515 + if(outputType==MBCS_OUTPUT_EXT_ONLY) { 1.516 + /* 1.517 + * extension-only file, 1.518 + * contains a base name instead of normal base table data 1.519 + */ 1.520 + char baseName[32]; 1.521 + int32_t baseNameLength; 1.522 + 1.523 + /* there is extension data after the base data, see ucnv_ext.h */ 1.524 + if(length<(extOffset+UCNV_EXT_INDEXES_MIN_LENGTH*4)) { 1.525 + udata_printError(ds, "icupkg/ucnv_enumDependencies(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table with extension data\n", 1.526 + length); 1.527 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.528 + return; 1.529 + } 1.530 + 1.531 + /* swap the base name, between the header and the extension data */ 1.532 + const char *inBaseName=(const char *)inBytes+mbcsHeaderLength*4; 1.533 + baseNameLength=(int32_t)strlen(inBaseName); 1.534 + if(baseNameLength>=(int32_t)sizeof(baseName)) { 1.535 + udata_printError(ds, "icupkg/ucnv_enumDependencies(%s): base name length %ld too long\n", 1.536 + itemName, baseNameLength); 1.537 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.538 + return; 1.539 + } 1.540 + ds->swapInvChars(ds, inBaseName, baseNameLength+1, baseName, pErrorCode); 1.541 + 1.542 + checkIDSuffix(itemName, baseName, -1, ".cnv", check, context, pErrorCode); 1.543 + } 1.544 + } 1.545 +} 1.546 + 1.547 +// ICU data formats -------------------------------------------------------- *** 1.548 + 1.549 +static const struct { 1.550 + uint8_t dataFormat[4]; 1.551 +} dataFormats[]={ 1.552 + { { 0x52, 0x65, 0x73, 0x42 } }, /* dataFormat="ResB" */ 1.553 + { { 0x63, 0x6e, 0x76, 0x74 } }, /* dataFormat="cnvt" */ 1.554 + { { 0x43, 0x76, 0x41, 0x6c } } /* dataFormat="CvAl" */ 1.555 +}; 1.556 + 1.557 +enum { 1.558 + FMT_RES, 1.559 + FMT_CNV, 1.560 + FMT_ALIAS, 1.561 + FMT_COUNT 1.562 +}; 1.563 + 1.564 +static int32_t 1.565 +getDataFormat(const uint8_t dataFormat[4]) { 1.566 + int32_t i; 1.567 + 1.568 + for(i=0; i<FMT_COUNT; ++i) { 1.569 + if(0==memcmp(dataFormats[i].dataFormat, dataFormat, 4)) { 1.570 + return i; 1.571 + } 1.572 + } 1.573 + return -1; 1.574 +} 1.575 + 1.576 +// enumerate dependencies of a package item -------------------------------- *** 1.577 + 1.578 +void 1.579 +Package::enumDependencies(Item *pItem, void *context, CheckDependency check) { 1.580 + int32_t infoLength, itemHeaderLength; 1.581 + UErrorCode errorCode=U_ZERO_ERROR; 1.582 + const UDataInfo *pInfo=getDataInfo(pItem->data, pItem->length, infoLength, itemHeaderLength, &errorCode); 1.583 + if(U_FAILURE(errorCode)) { 1.584 + return; // should not occur because readFile() checks headers 1.585 + } 1.586 + 1.587 + // find the data format and call the corresponding function, if any 1.588 + int32_t format=getDataFormat(pInfo->dataFormat); 1.589 + if(format>=0) { 1.590 + switch(format) { 1.591 + case FMT_RES: 1.592 + { 1.593 + /* 1.594 + * Swap the resource bundle (if necessary) so that we can use 1.595 + * the normal runtime uresdata.c code to read it. 1.596 + * We do not want to duplicate that code, especially not together with on-the-fly swapping. 1.597 + */ 1.598 + NativeItem nrb(pItem, ures_swap); 1.599 + ures_enumDependencies(pItem->name, nrb.getDataInfo(), nrb.getBytes(), nrb.getLength(), check, context, this, &errorCode); 1.600 + break; 1.601 + } 1.602 + case FMT_CNV: 1.603 + { 1.604 + // TODO: share/cache swappers 1.605 + UDataSwapper *ds=udata_openSwapper( 1.606 + (UBool)pInfo->isBigEndian, pInfo->charsetFamily, 1.607 + U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, 1.608 + &errorCode); 1.609 + if(U_FAILURE(errorCode)) { 1.610 + fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n", 1.611 + pItem->name, u_errorName(errorCode)); 1.612 + exit(errorCode); 1.613 + } 1.614 + 1.615 + ds->printError=printError; 1.616 + ds->printErrorContext=stderr; 1.617 + 1.618 + const uint8_t *inBytes=pItem->data+itemHeaderLength; 1.619 + int32_t length=pItem->length-itemHeaderLength; 1.620 + 1.621 + ucnv_enumDependencies(ds, pItem->name, pInfo, inBytes, length, check, context, &errorCode); 1.622 + udata_closeSwapper(ds); 1.623 + break; 1.624 + } 1.625 + default: 1.626 + break; 1.627 + } 1.628 + 1.629 + if(U_FAILURE(errorCode)) { 1.630 + exit(errorCode); 1.631 + } 1.632 + } 1.633 +} 1.634 + 1.635 +U_NAMESPACE_END