pkgitems.cpp (23727B)
1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ******************************************************************************* 5 * 6 * Copyright (C) 2003-2015, International Business Machines 7 * Corporation and others. All Rights Reserved. 8 * 9 ******************************************************************************* 10 * file name: pkgitems.cpp 11 * encoding: UTF-8 12 * tab size: 8 (not used) 13 * indentation:4 14 * 15 * created on: 2005sep18 16 * created by: Markus W. Scherer 17 * 18 * Companion file to package.cpp. Deals with details of ICU data item formats. 19 * Used for item dependencies. 20 * Contains adapted code from ucnv_bld.c (swapper code from 2003). 21 */ 22 23 #include "unicode/utypes.h" 24 #include "unicode/ures.h" 25 #include "unicode/putil.h" 26 #include "unicode/udata.h" 27 #include "cstring.h" 28 #include "uinvchar.h" 29 #include "ucmndata.h" 30 #include "udataswp.h" 31 #include "swapimpl.h" 32 #include "toolutil.h" 33 #include "package.h" 34 #include "pkg_imp.h" 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 40 /* item formats in common */ 41 42 #include "uresdata.h" 43 #include "ucnv_bld.h" 44 #include "ucnv_io.h" 45 46 // general definitions ----------------------------------------------------- *** 47 48 U_CDECL_BEGIN 49 50 static void U_CALLCONV 51 printError(void *context, const char *fmt, va_list args) { 52 vfprintf((FILE *)context, fmt, args); 53 } 54 55 U_CDECL_END 56 57 // a data item in native-platform form ------------------------------------- *** 58 59 U_NAMESPACE_BEGIN 60 61 class NativeItem { 62 public: 63 NativeItem() : pItem(nullptr), pInfo(nullptr), bytes(nullptr), swapped(nullptr), length(0) {} 64 NativeItem(const Item *item, UDataSwapFn *swap) : swapped(nullptr) { 65 setItem(item, swap); 66 } 67 ~NativeItem() { 68 delete [] swapped; 69 } 70 const UDataInfo *getDataInfo() const { 71 return pInfo; 72 } 73 const uint8_t *getBytes() const { 74 return bytes; 75 } 76 int32_t getLength() const { 77 return length; 78 } 79 80 void setItem(const Item *item, UDataSwapFn *swap) { 81 pItem=item; 82 int32_t infoLength, itemHeaderLength; 83 UErrorCode errorCode=U_ZERO_ERROR; 84 pInfo=::getDataInfo(pItem->data, pItem->length, infoLength, itemHeaderLength, &errorCode); 85 if(U_FAILURE(errorCode)) { 86 exit(errorCode); // should succeed because readFile() checks headers 87 } 88 length=pItem->length-itemHeaderLength; 89 90 if(pInfo->isBigEndian==U_IS_BIG_ENDIAN && pInfo->charsetFamily==U_CHARSET_FAMILY) { 91 bytes=pItem->data+itemHeaderLength; 92 } else { 93 UDataSwapper* ds = udata_openSwapper(static_cast<UBool>(pInfo->isBigEndian), pInfo->charsetFamily, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); 94 if(U_FAILURE(errorCode)) { 95 fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n", 96 pItem->name, u_errorName(errorCode)); 97 exit(errorCode); 98 } 99 100 ds->printError=printError; 101 ds->printErrorContext=stderr; 102 103 swapped=new uint8_t[pItem->length]; 104 if(swapped==nullptr) { 105 fprintf(stderr, "icupkg: unable to allocate memory for swapping \"%s\"\n", pItem->name); 106 exit(U_MEMORY_ALLOCATION_ERROR); 107 } 108 swap(ds, pItem->data, pItem->length, swapped, &errorCode); 109 pInfo=::getDataInfo(swapped, pItem->length, infoLength, itemHeaderLength, &errorCode); 110 bytes=swapped+itemHeaderLength; 111 udata_closeSwapper(ds); 112 } 113 } 114 115 private: 116 const Item *pItem; 117 const UDataInfo *pInfo; 118 const uint8_t *bytes; 119 uint8_t *swapped; 120 int32_t length; 121 }; 122 123 // check a dependency ------------------------------------------------------ *** 124 125 /* 126 * assemble the target item name from the source item name, an ID 127 * and a suffix 128 */ 129 static void 130 makeTargetName(const char *itemName, const char *id, int32_t idLength, const char *suffix, 131 char *target, int32_t capacity, 132 UErrorCode *pErrorCode) { 133 const char *itemID; 134 int32_t treeLength, suffixLength, targetLength; 135 136 // get the item basename 137 itemID=strrchr(itemName, '/'); 138 if(itemID!=nullptr) { 139 ++itemID; 140 } else { 141 itemID=itemName; 142 } 143 144 // build the target string 145 treeLength = static_cast<int32_t>(itemID - itemName); 146 if(idLength<0) { 147 idLength = static_cast<int32_t>(strlen(id)); 148 } 149 suffixLength = static_cast<int32_t>(strlen(suffix)); 150 targetLength=treeLength+idLength+suffixLength; 151 if(targetLength>=capacity) { 152 fprintf(stderr, "icupkg/makeTargetName(%s) target item name length %ld too long\n", 153 itemName, static_cast<long>(targetLength)); 154 *pErrorCode=U_BUFFER_OVERFLOW_ERROR; 155 return; 156 } 157 158 memcpy(target, itemName, treeLength); 159 memcpy(target+treeLength, id, idLength); 160 memcpy(target+treeLength+idLength, suffix, suffixLength+1); // +1 includes the terminating NUL 161 } 162 163 static void 164 checkIDSuffix(const char *itemName, const char *id, int32_t idLength, const char *suffix, 165 CheckDependency check, void *context, 166 UErrorCode *pErrorCode) { 167 char target[200]; 168 makeTargetName(itemName, id, idLength, suffix, target, static_cast<int32_t>(sizeof(target)), pErrorCode); 169 if(U_SUCCESS(*pErrorCode)) { 170 check(context, itemName, target); 171 } 172 } 173 174 /* assemble the target item name from the item's parent item name */ 175 static void 176 checkParent(const char *itemName, CheckDependency check, void *context, 177 UErrorCode *pErrorCode) { 178 const char *itemID, *parent, *parentLimit, *suffix; 179 int32_t parentLength; 180 181 // get the item basename 182 itemID=strrchr(itemName, '/'); 183 if(itemID!=nullptr) { 184 ++itemID; 185 } else { 186 itemID=itemName; 187 } 188 189 // get the item suffix 190 suffix=strrchr(itemID, '.'); 191 if(suffix==nullptr) { 192 // empty suffix, point to the end of the string 193 suffix=strrchr(itemID, 0); 194 } 195 196 // get the position of the last '_' 197 for(parentLimit=suffix; parentLimit>itemID && *--parentLimit!='_';) {} 198 199 if(parentLimit!=itemID) { 200 // get the parent item name by truncating the last part of this item's name */ 201 parent=itemID; 202 parentLength = static_cast<int32_t>(parentLimit - itemID); 203 } else { 204 // no '_' in the item name: the parent is the root bundle 205 parent="root"; 206 parentLength=4; 207 if((suffix-itemID)==parentLength && 0==memcmp(itemID, parent, parentLength)) { 208 // the item itself is "root", which does not depend on a parent 209 return; 210 } 211 } 212 checkIDSuffix(itemName, parent, parentLength, suffix, check, context, pErrorCode); 213 } 214 215 // get dependencies from resource bundles ---------------------------------- *** 216 217 static const char16_t SLASH=0x2f; 218 219 /* 220 * Check for the alias from the string or alias resource res. 221 */ 222 static void 223 checkAlias(const char *itemName, 224 Resource res, const char16_t *alias, int32_t length, UBool useResSuffix, 225 CheckDependency check, void *context, UErrorCode *pErrorCode) { 226 int32_t i; 227 228 if(!uprv_isInvariantUString(alias, length)) { 229 fprintf(stderr, "icupkg/ures_enumDependencies(%s res=%08x) alias string contains non-invariant characters\n", 230 itemName, res); 231 *pErrorCode=U_INVALID_CHAR_FOUND; 232 return; 233 } 234 235 // extract the locale ID from alias strings like 236 // locale_ID/key1/key2/key3 237 // locale_ID 238 239 // search for the first slash 240 for(i=0; i<length && alias[i]!=SLASH; ++i) {} 241 242 if(res_getPublicType(res)==URES_ALIAS) { 243 // ignore aliases with an initial slash: 244 // /ICUDATA/... and /pkgname/... go to a different package 245 // /LOCALE/... are for dynamic sideways fallbacks and don't go to a fixed bundle 246 if(i==0) { 247 return; // initial slash ('/') 248 } 249 250 // ignore the intra-bundle path starting from the first slash ('/') 251 length=i; 252 } else /* URES_STRING */ { 253 // the whole string should only consist of a locale ID 254 if(i!=length) { 255 fprintf(stderr, "icupkg/ures_enumDependencies(%s res=%08x) %%ALIAS contains a '/'\n", 256 itemName, res); 257 *pErrorCode=U_UNSUPPORTED_ERROR; 258 return; 259 } 260 } 261 262 // convert the Unicode string to char * 263 char localeID[48]; 264 if (length >= static_cast<int32_t>(sizeof(localeID))) { 265 fprintf(stderr, "icupkg/ures_enumDependencies(%s res=%08x) alias locale ID length %ld too long\n", 266 itemName, res, static_cast<long>(length)); 267 *pErrorCode=U_BUFFER_OVERFLOW_ERROR; 268 return; 269 } 270 u_UCharsToChars(alias, localeID, length); 271 localeID[length]=0; 272 273 checkIDSuffix(itemName, localeID, -1, (useResSuffix ? ".res" : ""), check, context, pErrorCode); 274 } 275 276 /* 277 * Enumerate one resource item and its children and extract dependencies from 278 * aliases. 279 */ 280 static UBool 281 ures_enumDependencies(const char *itemName, 282 const ResourceData *pResData, 283 Resource res, const char *inKey, const char *parentKey, int32_t depth, 284 CheckDependency check, void *context, 285 Package *pkg, 286 UErrorCode *pErrorCode) { 287 UBool doCheckParent = true; // always remains true if depth>1 288 switch(res_getPublicType(res)) { 289 case URES_STRING: 290 if(depth==1 && inKey!=nullptr && 291 (0==strcmp(inKey, "%%ALIAS") || 0==strcmp(inKey, "%%Parent"))) { 292 // Top-level %%ALIAS string: 293 // The alias resource bundle will be used instead of this one. 294 // Top-level %%Parent string: 295 // We use this bundle as well as the explicit parent bundle. 296 // Either way, the truncation parent is ignored. 297 doCheckParent = false; 298 // No tracing: build tool 299 int32_t length; 300 const char16_t *alias=res_getStringNoTrace(pResData, res, &length); 301 checkAlias(itemName, res, alias, length, /*useResSuffix=*/ true, 302 check, context, pErrorCode); 303 // If there is a %%ALIAS, then there should be nothing else in this resource bundle. 304 } else if(depth==2 && parentKey!=nullptr && 0==strcmp(parentKey, "%%DEPENDENCY")) { 305 // Second-level %%DEPENDENCY string: 306 // Explicit declaration of a dependency of this item on that one. 307 // No tracing: build tool 308 int32_t length; 309 const char16_t *alias=res_getStringNoTrace(pResData, res, &length); 310 checkAlias(itemName, res, alias, length, /*useResSuffix=*/ false, 311 check, context, pErrorCode); 312 } 313 // we ignore all other strings 314 break; 315 case URES_ALIAS: 316 { 317 int32_t length; 318 const char16_t *alias=res_getAlias(pResData, res, &length); 319 checkAlias(itemName, res, alias, length, true, check, context, pErrorCode); 320 } 321 break; 322 case URES_TABLE: 323 { 324 /* recurse */ 325 int32_t count=res_countArrayItems(pResData, res); 326 for(int32_t i=0; i<count; ++i) { 327 const char *itemKey; 328 Resource item=res_getTableItemByIndex(pResData, res, i, &itemKey); 329 // This doCheckParent return value is needed to 330 // propagate the possible false value from depth=1 to depth=0. 331 doCheckParent &= ures_enumDependencies( 332 itemName, pResData, 333 item, itemKey, 334 inKey, depth+1, 335 check, context, 336 pkg, 337 pErrorCode); 338 if(U_FAILURE(*pErrorCode)) { 339 fprintf(stderr, "icupkg/ures_enumDependencies(%s table res=%08x)[%d].recurse(%s: %08x) failed\n", 340 itemName, res, i, itemKey, item); 341 break; 342 } 343 } 344 } 345 break; 346 case URES_ARRAY: 347 { 348 /* recurse */ 349 int32_t count=res_countArrayItems(pResData, res); 350 for(int32_t i=0; i<count; ++i) { 351 Resource item=res_getArrayItem(pResData, res, i); 352 ures_enumDependencies( 353 itemName, pResData, 354 item, nullptr, 355 inKey, depth+1, 356 check, context, 357 pkg, 358 pErrorCode); 359 if(U_FAILURE(*pErrorCode)) { 360 fprintf(stderr, "icupkg/ures_enumDependencies(%s array res=%08x)[%d].recurse(%08x) failed\n", 361 itemName, res, i, item); 362 break; 363 } 364 } 365 } 366 break; 367 default: 368 break; 369 } 370 return doCheckParent; 371 } 372 373 static void 374 ures_enumDependencies(const char *itemName, const UDataInfo *pInfo, 375 const uint8_t *inBytes, int32_t length, 376 CheckDependency check, void *context, 377 Package *pkg, 378 UErrorCode *pErrorCode) { 379 ResourceData resData; 380 381 res_read(&resData, pInfo, inBytes, length, pErrorCode); 382 if(U_FAILURE(*pErrorCode)) { 383 fprintf(stderr, "icupkg: .res format version %02x.%02x not supported, or bundle malformed\n", 384 pInfo->formatVersion[0], pInfo->formatVersion[1]); 385 exit(U_UNSUPPORTED_ERROR); 386 } 387 388 icu::NativeItem nativePool; 389 390 if(resData.usesPoolBundle) { 391 char poolName[200]; 392 makeTargetName(itemName, "pool", 4, ".res", poolName, static_cast<int32_t>(sizeof(poolName)), pErrorCode); 393 if(U_FAILURE(*pErrorCode)) { 394 return; 395 } 396 check(context, itemName, poolName); 397 int32_t index=pkg->findItem(poolName); 398 if(index<0) { 399 // We cannot work with a bundle if its pool resource is missing. 400 // check() already printed a complaint. 401 return; 402 } 403 // TODO: Cache the native version in the Item itself. 404 nativePool.setItem(pkg->getItem(index), ures_swap); 405 const UDataInfo *poolInfo=nativePool.getDataInfo(); 406 if(poolInfo->formatVersion[0]<=1) { 407 fprintf(stderr, "icupkg: %s is not a pool bundle\n", poolName); 408 return; 409 } 410 const int32_t* poolRoot = reinterpret_cast<const int32_t*>(nativePool.getBytes()); 411 const int32_t *poolIndexes=poolRoot+1; 412 int32_t poolIndexLength=poolIndexes[URES_INDEX_LENGTH]&0xff; 413 if(!(poolIndexLength>URES_INDEX_POOL_CHECKSUM && 414 (poolIndexes[URES_INDEX_ATTRIBUTES]&URES_ATT_IS_POOL_BUNDLE)) 415 ) { 416 fprintf(stderr, "icupkg: %s is not a pool bundle\n", poolName); 417 return; 418 } 419 if(resData.pRoot[1+URES_INDEX_POOL_CHECKSUM]==poolIndexes[URES_INDEX_POOL_CHECKSUM]) { 420 resData.poolBundleKeys = reinterpret_cast<const char*>(poolIndexes + poolIndexLength); 421 resData.poolBundleStrings = reinterpret_cast<const uint16_t*>(poolRoot + poolIndexes[URES_INDEX_KEYS_TOP]); 422 } else { 423 fprintf(stderr, "icupkg: %s has mismatched checksum for %s\n", poolName, itemName); 424 return; 425 } 426 } 427 428 UBool doCheckParent = ures_enumDependencies( 429 itemName, &resData, 430 resData.rootRes, nullptr, nullptr, 0, 431 check, context, 432 pkg, 433 pErrorCode); 434 if(!doCheckParent) { 435 return; 436 } 437 438 /* 439 * if the bundle attributes are present and the nofallback flag is not set, 440 * then add the parent bundle as a dependency 441 */ 442 if(pInfo->formatVersion[0]>1 || (pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1)) { 443 if(!resData.noFallback) { 444 /* this bundle participates in locale fallback */ 445 checkParent(itemName, check, context, pErrorCode); 446 } 447 } 448 } 449 450 // get dependencies from conversion tables --------------------------------- *** 451 452 #if !UCONFIG_NO_CONVERSION 453 /* code adapted from ucnv_swap() */ 454 static void 455 ucnv_enumDependencies(const UDataSwapper *ds, 456 const char *itemName, const UDataInfo *pInfo, 457 const uint8_t *inBytes, int32_t length, 458 CheckDependency check, void *context, 459 UErrorCode *pErrorCode) { 460 uint32_t staticDataSize; 461 462 const UConverterStaticData *inStaticData; 463 464 const _MBCSHeader *inMBCSHeader; 465 uint8_t outputType; 466 467 /* check format version */ 468 if(!( 469 pInfo->formatVersion[0]==6 && 470 pInfo->formatVersion[1]>=2 471 )) { 472 fprintf(stderr, "icupkg/ucnv_enumDependencies(): .cnv format version %02x.%02x not supported\n", 473 pInfo->formatVersion[0], pInfo->formatVersion[1]); 474 exit(U_UNSUPPORTED_ERROR); 475 } 476 477 /* read the initial UConverterStaticData structure after the UDataInfo header */ 478 inStaticData = reinterpret_cast<const UConverterStaticData*>(inBytes); 479 480 if (length < static_cast<int32_t>(sizeof(UConverterStaticData)) || 481 static_cast<uint32_t>(length) < (staticDataSize = ds->readUInt32(inStaticData->structSize)) 482 ) { 483 udata_printError(ds, "icupkg/ucnv_enumDependencies(): too few bytes (%d after header) for an ICU .cnv conversion table\n", 484 length); 485 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 486 return; 487 } 488 489 inBytes+=staticDataSize; 490 length -= static_cast<int32_t>(staticDataSize); 491 492 /* check for supported conversionType values */ 493 if(inStaticData->conversionType==UCNV_MBCS) { 494 /* MBCS data */ 495 uint32_t mbcsHeaderLength, mbcsHeaderFlags, mbcsHeaderOptions; 496 int32_t extOffset; 497 498 inMBCSHeader = reinterpret_cast<const _MBCSHeader*>(inBytes); 499 500 if (length < static_cast<int32_t>(sizeof(_MBCSHeader))) { 501 udata_printError(ds, "icupkg/ucnv_enumDependencies(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n", 502 length); 503 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 504 return; 505 } 506 if(inMBCSHeader->version[0]==4 && inMBCSHeader->version[1]>=1) { 507 mbcsHeaderLength=MBCS_HEADER_V4_LENGTH; 508 } else if(inMBCSHeader->version[0]==5 && inMBCSHeader->version[1]>=3 && 509 ((mbcsHeaderOptions=ds->readUInt32(inMBCSHeader->options))& 510 MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK)==0 511 ) { 512 mbcsHeaderLength=mbcsHeaderOptions&MBCS_OPT_LENGTH_MASK; 513 } else { 514 udata_printError(ds, "icupkg/ucnv_enumDependencies(): unsupported _MBCSHeader.version %d.%d\n", 515 inMBCSHeader->version[0], inMBCSHeader->version[1]); 516 *pErrorCode=U_UNSUPPORTED_ERROR; 517 return; 518 } 519 520 mbcsHeaderFlags=ds->readUInt32(inMBCSHeader->flags); 521 extOffset = static_cast<int32_t>(mbcsHeaderFlags >> 8); 522 outputType = static_cast<uint8_t>(mbcsHeaderFlags); 523 524 if(outputType==MBCS_OUTPUT_EXT_ONLY) { 525 /* 526 * extension-only file, 527 * contains a base name instead of normal base table data 528 */ 529 char baseName[32]; 530 int32_t baseNameLength; 531 532 /* there is extension data after the base data, see ucnv_ext.h */ 533 if(length<(extOffset+UCNV_EXT_INDEXES_MIN_LENGTH*4)) { 534 udata_printError(ds, "icupkg/ucnv_enumDependencies(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table with extension data\n", 535 length); 536 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 537 return; 538 } 539 540 /* swap the base name, between the header and the extension data */ 541 const char* inBaseName = reinterpret_cast<const char*>(inBytes) + mbcsHeaderLength * 4; 542 baseNameLength = static_cast<int32_t>(strlen(inBaseName)); 543 if (baseNameLength >= static_cast<int32_t>(sizeof(baseName))) { 544 udata_printError(ds, "icupkg/ucnv_enumDependencies(%s): base name length %ld too long\n", 545 itemName, baseNameLength); 546 *pErrorCode=U_UNSUPPORTED_ERROR; 547 return; 548 } 549 ds->swapInvChars(ds, inBaseName, baseNameLength+1, baseName, pErrorCode); 550 551 checkIDSuffix(itemName, baseName, -1, ".cnv", check, context, pErrorCode); 552 } 553 } 554 } 555 556 // ICU data formats -------------------------------------------------------- *** 557 558 static const struct { 559 uint8_t dataFormat[4]; 560 } dataFormats[]={ 561 { { 0x52, 0x65, 0x73, 0x42 } }, /* dataFormat="ResB" */ 562 { { 0x63, 0x6e, 0x76, 0x74 } }, /* dataFormat="cnvt" */ 563 { { 0x43, 0x76, 0x41, 0x6c } } /* dataFormat="CvAl" */ 564 }; 565 566 enum { 567 FMT_RES, 568 FMT_CNV, 569 FMT_ALIAS, 570 FMT_COUNT 571 }; 572 573 static int32_t 574 getDataFormat(const uint8_t dataFormat[4]) { 575 int32_t i; 576 577 for(i=0; i<FMT_COUNT; ++i) { 578 if(0==memcmp(dataFormats[i].dataFormat, dataFormat, 4)) { 579 return i; 580 } 581 } 582 return -1; 583 } 584 585 // enumerate dependencies of a package item -------------------------------- *** 586 587 void 588 Package::enumDependencies(Item *pItem, void *context, CheckDependency check) { 589 int32_t infoLength, itemHeaderLength; 590 UErrorCode errorCode=U_ZERO_ERROR; 591 const UDataInfo *pInfo=getDataInfo(pItem->data, pItem->length, infoLength, itemHeaderLength, &errorCode); 592 if(U_FAILURE(errorCode)) { 593 return; // should not occur because readFile() checks headers 594 } 595 596 // find the data format and call the corresponding function, if any 597 int32_t format=getDataFormat(pInfo->dataFormat); 598 if(format>=0) { 599 switch(format) { 600 case FMT_RES: 601 { 602 /* 603 * Swap the resource bundle (if necessary) so that we can use 604 * the normal runtime uresdata.c code to read it. 605 * We do not want to duplicate that code, especially not together with on-the-fly swapping. 606 */ 607 NativeItem nrb(pItem, ures_swap); 608 ures_enumDependencies(pItem->name, nrb.getDataInfo(), nrb.getBytes(), nrb.getLength(), check, context, this, &errorCode); 609 break; 610 } 611 case FMT_CNV: 612 { 613 // TODO: share/cache swappers 614 UDataSwapper *ds=udata_openSwapper( 615 static_cast<UBool>(pInfo->isBigEndian), pInfo->charsetFamily, 616 U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, 617 &errorCode); 618 if(U_FAILURE(errorCode)) { 619 fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n", 620 pItem->name, u_errorName(errorCode)); 621 exit(errorCode); 622 } 623 624 ds->printError=printError; 625 ds->printErrorContext=stderr; 626 627 const uint8_t *inBytes=pItem->data+itemHeaderLength; 628 int32_t length=pItem->length-itemHeaderLength; 629 630 ucnv_enumDependencies(ds, pItem->name, pInfo, inBytes, length, check, context, &errorCode); 631 udata_closeSwapper(ds); 632 break; 633 } 634 default: 635 break; 636 } 637 638 if(U_FAILURE(errorCode)) { 639 exit(errorCode); 640 } 641 } 642 } 643 #endif /* UCONFIG_NO_CONVERSION */ 644 645 U_NAMESPACE_END