1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/tools/toolutil/package.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1313 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* 1.7 +* Copyright (C) 1999-2013, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +******************************************************************************* 1.11 +* file name: package.cpp 1.12 +* encoding: US-ASCII 1.13 +* tab size: 8 (not used) 1.14 +* indentation:4 1.15 +* 1.16 +* created on: 2005aug25 1.17 +* created by: Markus W. Scherer 1.18 +* 1.19 +* Read, modify, and write ICU .dat data package files. 1.20 +* This is an integral part of the icupkg tool, moved to the toolutil library 1.21 +* because parts of tool implementations tend to be later shared by 1.22 +* other tools. 1.23 +* Subsumes functionality and implementation code from 1.24 +* gencmn, decmn, and icuswap tools. 1.25 +*/ 1.26 + 1.27 +#include "unicode/utypes.h" 1.28 +#include "unicode/putil.h" 1.29 +#include "unicode/udata.h" 1.30 +#include "cstring.h" 1.31 +#include "uarrsort.h" 1.32 +#include "ucmndata.h" 1.33 +#include "udataswp.h" 1.34 +#include "swapimpl.h" 1.35 +#include "toolutil.h" 1.36 +#include "package.h" 1.37 +#include "cmemory.h" 1.38 + 1.39 +#include <stdio.h> 1.40 +#include <stdlib.h> 1.41 +#include <string.h> 1.42 + 1.43 + 1.44 +static const int32_t kItemsChunk = 256; /* How much to increase the filesarray by each time */ 1.45 + 1.46 +// general definitions ----------------------------------------------------- *** 1.47 + 1.48 +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 1.49 + 1.50 +/* UDataInfo cf. udata.h */ 1.51 +static const UDataInfo dataInfo={ 1.52 + (uint16_t)sizeof(UDataInfo), 1.53 + 0, 1.54 + 1.55 + U_IS_BIG_ENDIAN, 1.56 + U_CHARSET_FAMILY, 1.57 + (uint8_t)sizeof(UChar), 1.58 + 0, 1.59 + 1.60 + {0x43, 0x6d, 0x6e, 0x44}, /* dataFormat="CmnD" */ 1.61 + {1, 0, 0, 0}, /* formatVersion */ 1.62 + {3, 0, 0, 0} /* dataVersion */ 1.63 +}; 1.64 + 1.65 +U_CDECL_BEGIN 1.66 +static void U_CALLCONV 1.67 +printPackageError(void *context, const char *fmt, va_list args) { 1.68 + vfprintf((FILE *)context, fmt, args); 1.69 +} 1.70 +U_CDECL_END 1.71 + 1.72 +static uint16_t 1.73 +readSwapUInt16(uint16_t x) { 1.74 + return (uint16_t)((x<<8)|(x>>8)); 1.75 +} 1.76 + 1.77 +// platform types ---------------------------------------------------------- *** 1.78 + 1.79 +static const char *types="lb?e"; 1.80 + 1.81 +enum { TYPE_L, TYPE_B, TYPE_LE, TYPE_E, TYPE_COUNT }; 1.82 + 1.83 +static inline int32_t 1.84 +makeTypeEnum(uint8_t charset, UBool isBigEndian) { 1.85 + return 2*(int32_t)charset+isBigEndian; 1.86 +} 1.87 + 1.88 +static inline int32_t 1.89 +makeTypeEnum(char type) { 1.90 + return 1.91 + type == 'l' ? TYPE_L : 1.92 + type == 'b' ? TYPE_B : 1.93 + type == 'e' ? TYPE_E : 1.94 + -1; 1.95 +} 1.96 + 1.97 +static inline char 1.98 +makeTypeLetter(uint8_t charset, UBool isBigEndian) { 1.99 + return types[makeTypeEnum(charset, isBigEndian)]; 1.100 +} 1.101 + 1.102 +static inline char 1.103 +makeTypeLetter(int32_t typeEnum) { 1.104 + return types[typeEnum]; 1.105 +} 1.106 + 1.107 +static void 1.108 +makeTypeProps(char type, uint8_t &charset, UBool &isBigEndian) { 1.109 + int32_t typeEnum=makeTypeEnum(type); 1.110 + charset=(uint8_t)(typeEnum>>1); 1.111 + isBigEndian=(UBool)(typeEnum&1); 1.112 +} 1.113 + 1.114 +U_CFUNC const UDataInfo * 1.115 +getDataInfo(const uint8_t *data, int32_t length, 1.116 + int32_t &infoLength, int32_t &headerLength, 1.117 + UErrorCode *pErrorCode) { 1.118 + const DataHeader *pHeader; 1.119 + const UDataInfo *pInfo; 1.120 + 1.121 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.122 + return NULL; 1.123 + } 1.124 + if( data==NULL || 1.125 + (length>=0 && length<(int32_t)sizeof(DataHeader)) 1.126 + ) { 1.127 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.128 + return NULL; 1.129 + } 1.130 + 1.131 + pHeader=(const DataHeader *)data; 1.132 + pInfo=&pHeader->info; 1.133 + if( (length>=0 && length<(int32_t)sizeof(DataHeader)) || 1.134 + pHeader->dataHeader.magic1!=0xda || 1.135 + pHeader->dataHeader.magic2!=0x27 || 1.136 + pInfo->sizeofUChar!=2 1.137 + ) { 1.138 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.139 + return NULL; 1.140 + } 1.141 + 1.142 + if(pInfo->isBigEndian==U_IS_BIG_ENDIAN) { 1.143 + headerLength=pHeader->dataHeader.headerSize; 1.144 + infoLength=pInfo->size; 1.145 + } else { 1.146 + headerLength=readSwapUInt16(pHeader->dataHeader.headerSize); 1.147 + infoLength=readSwapUInt16(pInfo->size); 1.148 + } 1.149 + 1.150 + if( headerLength<(int32_t)sizeof(DataHeader) || 1.151 + infoLength<(int32_t)sizeof(UDataInfo) || 1.152 + headerLength<(int32_t)(sizeof(pHeader->dataHeader)+infoLength) || 1.153 + (length>=0 && length<headerLength) 1.154 + ) { 1.155 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.156 + return NULL; 1.157 + } 1.158 + 1.159 + return pInfo; 1.160 +} 1.161 + 1.162 +static int32_t 1.163 +getTypeEnumForInputData(const uint8_t *data, int32_t length, 1.164 + UErrorCode *pErrorCode) { 1.165 + const UDataInfo *pInfo; 1.166 + int32_t infoLength, headerLength; 1.167 + 1.168 + /* getDataInfo() checks for illegal arguments */ 1.169 + pInfo=getDataInfo(data, length, infoLength, headerLength, pErrorCode); 1.170 + if(pInfo==NULL) { 1.171 + return -1; 1.172 + } 1.173 + 1.174 + return makeTypeEnum(pInfo->charsetFamily, (UBool)pInfo->isBigEndian); 1.175 +} 1.176 + 1.177 +// file handling ----------------------------------------------------------- *** 1.178 + 1.179 +static void 1.180 +extractPackageName(const char *filename, 1.181 + char pkg[], int32_t capacity) { 1.182 + const char *basename; 1.183 + int32_t len; 1.184 + 1.185 + basename=findBasename(filename); 1.186 + len=(int32_t)strlen(basename)-4; /* -4: subtract the length of ".dat" */ 1.187 + 1.188 + if(len<=0 || 0!=strcmp(basename+len, ".dat")) { 1.189 + fprintf(stderr, "icupkg: \"%s\" is not recognized as a package filename (must end with .dat)\n", 1.190 + basename); 1.191 + exit(U_ILLEGAL_ARGUMENT_ERROR); 1.192 + } 1.193 + 1.194 + if(len>=capacity) { 1.195 + fprintf(stderr, "icupkg: the package name \"%s\" is too long (>=%ld)\n", 1.196 + basename, (long)capacity); 1.197 + exit(U_ILLEGAL_ARGUMENT_ERROR); 1.198 + } 1.199 + 1.200 + memcpy(pkg, basename, len); 1.201 + pkg[len]=0; 1.202 +} 1.203 + 1.204 +static int32_t 1.205 +getFileLength(FILE *f) { 1.206 + int32_t length; 1.207 + 1.208 + fseek(f, 0, SEEK_END); 1.209 + length=(int32_t)ftell(f); 1.210 + fseek(f, 0, SEEK_SET); 1.211 + return length; 1.212 +} 1.213 + 1.214 +/* 1.215 + * Turn tree separators and alternate file separators into normal file separators. 1.216 + */ 1.217 +#if U_TREE_ENTRY_SEP_CHAR==U_FILE_SEP_CHAR && U_FILE_ALT_SEP_CHAR==U_FILE_SEP_CHAR 1.218 +#define treeToPath(s) 1.219 +#else 1.220 +static void 1.221 +treeToPath(char *s) { 1.222 + char *t; 1.223 + 1.224 + for(t=s; *t!=0; ++t) { 1.225 + if(*t==U_TREE_ENTRY_SEP_CHAR || *t==U_FILE_ALT_SEP_CHAR) { 1.226 + *t=U_FILE_SEP_CHAR; 1.227 + } 1.228 + } 1.229 +} 1.230 +#endif 1.231 + 1.232 +/* 1.233 + * Turn file separators into tree separators. 1.234 + */ 1.235 +#if U_TREE_ENTRY_SEP_CHAR==U_FILE_SEP_CHAR && U_FILE_ALT_SEP_CHAR==U_FILE_SEP_CHAR 1.236 +#define pathToTree(s) 1.237 +#else 1.238 +static void 1.239 +pathToTree(char *s) { 1.240 + char *t; 1.241 + 1.242 + for(t=s; *t!=0; ++t) { 1.243 + if(*t==U_FILE_SEP_CHAR || *t==U_FILE_ALT_SEP_CHAR) { 1.244 + *t=U_TREE_ENTRY_SEP_CHAR; 1.245 + } 1.246 + } 1.247 +} 1.248 +#endif 1.249 + 1.250 +/* 1.251 + * Prepend the path (if any) to the name and run the name through treeToName(). 1.252 + */ 1.253 +static void 1.254 +makeFullFilename(const char *path, const char *name, 1.255 + char *filename, int32_t capacity) { 1.256 + char *s; 1.257 + 1.258 + // prepend the path unless NULL or empty 1.259 + if(path!=NULL && path[0]!=0) { 1.260 + if((int32_t)(strlen(path)+1)>=capacity) { 1.261 + fprintf(stderr, "pathname too long: \"%s\"\n", path); 1.262 + exit(U_BUFFER_OVERFLOW_ERROR); 1.263 + } 1.264 + strcpy(filename, path); 1.265 + 1.266 + // make sure the path ends with a file separator 1.267 + s=strchr(filename, 0); 1.268 + if(*(s-1)!=U_FILE_SEP_CHAR && *(s-1)!=U_FILE_ALT_SEP_CHAR) { 1.269 + *s++=U_FILE_SEP_CHAR; 1.270 + } 1.271 + } else { 1.272 + s=filename; 1.273 + } 1.274 + 1.275 + // turn the name into a filename, turn tree separators into file separators 1.276 + if((int32_t)((s-filename)+strlen(name))>=capacity) { 1.277 + fprintf(stderr, "path/filename too long: \"%s%s\"\n", filename, name); 1.278 + exit(U_BUFFER_OVERFLOW_ERROR); 1.279 + } 1.280 + strcpy(s, name); 1.281 + treeToPath(s); 1.282 +} 1.283 + 1.284 +static void 1.285 +makeFullFilenameAndDirs(const char *path, const char *name, 1.286 + char *filename, int32_t capacity) { 1.287 + char *sep; 1.288 + UErrorCode errorCode; 1.289 + 1.290 + makeFullFilename(path, name, filename, capacity); 1.291 + 1.292 + // make tree directories 1.293 + errorCode=U_ZERO_ERROR; 1.294 + sep=strchr(filename, 0)-strlen(name); 1.295 + while((sep=strchr(sep, U_FILE_SEP_CHAR))!=NULL) { 1.296 + if(sep!=filename) { 1.297 + *sep=0; // truncate temporarily 1.298 + uprv_mkdir(filename, &errorCode); 1.299 + if(U_FAILURE(errorCode)) { 1.300 + fprintf(stderr, "icupkg: unable to create tree directory \"%s\"\n", filename); 1.301 + exit(U_FILE_ACCESS_ERROR); 1.302 + } 1.303 + } 1.304 + *sep++=U_FILE_SEP_CHAR; // restore file separator character 1.305 + } 1.306 +} 1.307 + 1.308 +static uint8_t * 1.309 +readFile(const char *path, const char *name, int32_t &length, char &type) { 1.310 + char filename[1024]; 1.311 + FILE *file; 1.312 + uint8_t *data; 1.313 + UErrorCode errorCode; 1.314 + int32_t fileLength, typeEnum; 1.315 + 1.316 + makeFullFilename(path, name, filename, (int32_t)sizeof(filename)); 1.317 + 1.318 + /* open the input file, get its length, allocate memory for it, read the file */ 1.319 + file=fopen(filename, "rb"); 1.320 + if(file==NULL) { 1.321 + fprintf(stderr, "icupkg: unable to open input file \"%s\"\n", filename); 1.322 + exit(U_FILE_ACCESS_ERROR); 1.323 + } 1.324 + 1.325 + /* get the file length */ 1.326 + fileLength=getFileLength(file); 1.327 + if(ferror(file) || fileLength<=0) { 1.328 + fprintf(stderr, "icupkg: empty input file \"%s\"\n", filename); 1.329 + fclose(file); 1.330 + exit(U_FILE_ACCESS_ERROR); 1.331 + } 1.332 + 1.333 + /* allocate the buffer, pad to multiple of 16 */ 1.334 + length=(fileLength+0xf)&~0xf; 1.335 + data=(uint8_t *)uprv_malloc(length); 1.336 + if(data==NULL) { 1.337 + fclose(file); 1.338 + fprintf(stderr, "icupkg: malloc error allocating %d bytes.\n", (int)length); 1.339 + exit(U_MEMORY_ALLOCATION_ERROR); 1.340 + } 1.341 + 1.342 + /* read the file */ 1.343 + if(fileLength!=(int32_t)fread(data, 1, fileLength, file)) { 1.344 + fprintf(stderr, "icupkg: error reading \"%s\"\n", filename); 1.345 + fclose(file); 1.346 + free(data); 1.347 + exit(U_FILE_ACCESS_ERROR); 1.348 + } 1.349 + 1.350 + /* pad the file to a multiple of 16 using the usual padding byte */ 1.351 + if(fileLength<length) { 1.352 + memset(data+fileLength, 0xaa, length-fileLength); 1.353 + } 1.354 + 1.355 + fclose(file); 1.356 + 1.357 + // minimum check for ICU-format data 1.358 + errorCode=U_ZERO_ERROR; 1.359 + typeEnum=getTypeEnumForInputData(data, length, &errorCode); 1.360 + if(typeEnum<0 || U_FAILURE(errorCode)) { 1.361 + fprintf(stderr, "icupkg: not an ICU data file: \"%s\"\n", filename); 1.362 + free(data); 1.363 +#if !UCONFIG_NO_LEGACY_CONVERSION 1.364 + exit(U_INVALID_FORMAT_ERROR); 1.365 +#else 1.366 + fprintf(stderr, "U_INVALID_FORMAT_ERROR occurred but UCONFIG_NO_LEGACY_CONVERSION is on so this is expected.\n"); 1.367 + exit(0); 1.368 +#endif 1.369 + } 1.370 + type=makeTypeLetter(typeEnum); 1.371 + 1.372 + return data; 1.373 +} 1.374 + 1.375 +// .dat package file representation ---------------------------------------- *** 1.376 + 1.377 +U_CDECL_BEGIN 1.378 + 1.379 +static int32_t U_CALLCONV 1.380 +compareItems(const void * /*context*/, const void *left, const void *right) { 1.381 + U_NAMESPACE_USE 1.382 + 1.383 + return (int32_t)strcmp(((Item *)left)->name, ((Item *)right)->name); 1.384 +} 1.385 + 1.386 +U_CDECL_END 1.387 + 1.388 +U_NAMESPACE_BEGIN 1.389 + 1.390 +Package::Package() 1.391 + : doAutoPrefix(FALSE), prefixEndsWithType(FALSE) { 1.392 + inPkgName[0]=0; 1.393 + pkgPrefix[0]=0; 1.394 + inData=NULL; 1.395 + inLength=0; 1.396 + inCharset=U_CHARSET_FAMILY; 1.397 + inIsBigEndian=U_IS_BIG_ENDIAN; 1.398 + 1.399 + itemCount=0; 1.400 + itemMax=0; 1.401 + items=NULL; 1.402 + 1.403 + inStringTop=outStringTop=0; 1.404 + 1.405 + matchMode=0; 1.406 + findPrefix=findSuffix=NULL; 1.407 + findPrefixLength=findSuffixLength=0; 1.408 + findNextIndex=-1; 1.409 + 1.410 + // create a header for an empty package 1.411 + DataHeader *pHeader; 1.412 + pHeader=(DataHeader *)header; 1.413 + pHeader->dataHeader.magic1=0xda; 1.414 + pHeader->dataHeader.magic2=0x27; 1.415 + memcpy(&pHeader->info, &dataInfo, sizeof(dataInfo)); 1.416 + headerLength=(int32_t)(4+sizeof(dataInfo)); 1.417 + if(headerLength&0xf) { 1.418 + /* NUL-pad the header to a multiple of 16 */ 1.419 + int32_t length=(headerLength+0xf)&~0xf; 1.420 + memset(header+headerLength, 0, length-headerLength); 1.421 + headerLength=length; 1.422 + } 1.423 + pHeader->dataHeader.headerSize=(uint16_t)headerLength; 1.424 +} 1.425 + 1.426 +Package::~Package() { 1.427 + int32_t idx; 1.428 + 1.429 + free(inData); 1.430 + 1.431 + for(idx=0; idx<itemCount; ++idx) { 1.432 + if(items[idx].isDataOwned) { 1.433 + free(items[idx].data); 1.434 + } 1.435 + } 1.436 + 1.437 + uprv_free((void*)items); 1.438 +} 1.439 + 1.440 +void 1.441 +Package::setPrefix(const char *p) { 1.442 + if(strlen(p)>=sizeof(pkgPrefix)) { 1.443 + fprintf(stderr, "icupkg: --toc_prefix %s too long\n", p); 1.444 + exit(U_ILLEGAL_ARGUMENT_ERROR); 1.445 + } 1.446 + strcpy(pkgPrefix, p); 1.447 +} 1.448 + 1.449 +void 1.450 +Package::readPackage(const char *filename) { 1.451 + UDataSwapper *ds; 1.452 + const UDataInfo *pInfo; 1.453 + UErrorCode errorCode; 1.454 + 1.455 + const uint8_t *inBytes; 1.456 + 1.457 + int32_t length, offset, i; 1.458 + int32_t itemLength, typeEnum; 1.459 + char type; 1.460 + 1.461 + const UDataOffsetTOCEntry *inEntries; 1.462 + 1.463 + extractPackageName(filename, inPkgName, (int32_t)sizeof(inPkgName)); 1.464 + 1.465 + /* read the file */ 1.466 + inData=readFile(NULL, filename, inLength, type); 1.467 + length=inLength; 1.468 + 1.469 + /* 1.470 + * swap the header - even if the swapping itself is a no-op 1.471 + * because it tells us the header length 1.472 + */ 1.473 + errorCode=U_ZERO_ERROR; 1.474 + makeTypeProps(type, inCharset, inIsBigEndian); 1.475 + ds=udata_openSwapper(inIsBigEndian, inCharset, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); 1.476 + if(U_FAILURE(errorCode)) { 1.477 + fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n", 1.478 + filename, u_errorName(errorCode)); 1.479 + exit(errorCode); 1.480 + } 1.481 + 1.482 + ds->printError=printPackageError; 1.483 + ds->printErrorContext=stderr; 1.484 + 1.485 + headerLength=sizeof(header); 1.486 + if(length<headerLength) { 1.487 + headerLength=length; 1.488 + } 1.489 + headerLength=udata_swapDataHeader(ds, inData, headerLength, header, &errorCode); 1.490 + if(U_FAILURE(errorCode)) { 1.491 + exit(errorCode); 1.492 + } 1.493 + 1.494 + /* check data format and format version */ 1.495 + pInfo=(const UDataInfo *)((const char *)inData+4); 1.496 + if(!( 1.497 + pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */ 1.498 + pInfo->dataFormat[1]==0x6d && 1.499 + pInfo->dataFormat[2]==0x6e && 1.500 + pInfo->dataFormat[3]==0x44 && 1.501 + pInfo->formatVersion[0]==1 1.502 + )) { 1.503 + fprintf(stderr, "icupkg: data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as an ICU .dat package\n", 1.504 + pInfo->dataFormat[0], pInfo->dataFormat[1], 1.505 + pInfo->dataFormat[2], pInfo->dataFormat[3], 1.506 + pInfo->formatVersion[0]); 1.507 + exit(U_UNSUPPORTED_ERROR); 1.508 + } 1.509 + inIsBigEndian=(UBool)pInfo->isBigEndian; 1.510 + inCharset=pInfo->charsetFamily; 1.511 + 1.512 + inBytes=(const uint8_t *)inData+headerLength; 1.513 + inEntries=(const UDataOffsetTOCEntry *)(inBytes+4); 1.514 + 1.515 + /* check that the itemCount fits, then the ToC table, then at least the header of the last item */ 1.516 + length-=headerLength; 1.517 + if(length<4) { 1.518 + /* itemCount does not fit */ 1.519 + offset=0x7fffffff; 1.520 + } else { 1.521 + itemCount=udata_readInt32(ds, *(const int32_t *)inBytes); 1.522 + setItemCapacity(itemCount); /* resize so there's space */ 1.523 + if(itemCount==0) { 1.524 + offset=4; 1.525 + } else if(length<(4+8*itemCount)) { 1.526 + /* ToC table does not fit */ 1.527 + offset=0x7fffffff; 1.528 + } else { 1.529 + /* offset of the last item plus at least 20 bytes for its header */ 1.530 + offset=20+(int32_t)ds->readUInt32(inEntries[itemCount-1].dataOffset); 1.531 + } 1.532 + } 1.533 + if(length<offset) { 1.534 + fprintf(stderr, "icupkg: too few bytes (%ld after header) for a .dat package\n", 1.535 + (long)length); 1.536 + exit(U_INDEX_OUTOFBOUNDS_ERROR); 1.537 + } 1.538 + /* do not modify the package length variable until the last item's length is set */ 1.539 + 1.540 + if(itemCount<=0) { 1.541 + if(doAutoPrefix) { 1.542 + fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but the input package is empty\n"); 1.543 + exit(U_INVALID_FORMAT_ERROR); 1.544 + } 1.545 + } else { 1.546 + char prefix[MAX_PKG_NAME_LENGTH+4]; 1.547 + char *s, *inItemStrings; 1.548 + 1.549 + if(itemCount>itemMax) { 1.550 + fprintf(stderr, "icupkg: too many items, maximum is %d\n", itemMax); 1.551 + exit(U_BUFFER_OVERFLOW_ERROR); 1.552 + } 1.553 + 1.554 + /* swap the item name strings */ 1.555 + int32_t stringsOffset=4+8*itemCount; 1.556 + itemLength=(int32_t)(ds->readUInt32(inEntries[0].dataOffset))-stringsOffset; 1.557 + 1.558 + // don't include padding bytes at the end of the item names 1.559 + while(itemLength>0 && inBytes[stringsOffset+itemLength-1]!=0) { 1.560 + --itemLength; 1.561 + } 1.562 + 1.563 + if((inStringTop+itemLength)>STRING_STORE_SIZE) { 1.564 + fprintf(stderr, "icupkg: total length of item name strings too long\n"); 1.565 + exit(U_BUFFER_OVERFLOW_ERROR); 1.566 + } 1.567 + 1.568 + inItemStrings=inStrings+inStringTop; 1.569 + ds->swapInvChars(ds, inBytes+stringsOffset, itemLength, inItemStrings, &errorCode); 1.570 + if(U_FAILURE(errorCode)) { 1.571 + fprintf(stderr, "icupkg failed to swap the input .dat package item name strings\n"); 1.572 + exit(U_INVALID_FORMAT_ERROR); 1.573 + } 1.574 + inStringTop+=itemLength; 1.575 + 1.576 + // reset the Item entries 1.577 + memset(items, 0, itemCount*sizeof(Item)); 1.578 + 1.579 + /* 1.580 + * Get the common prefix of the items. 1.581 + * New-style ICU .dat packages use tree separators ('/') between package names, 1.582 + * tree names, and item names, 1.583 + * while old-style ICU .dat packages (before multi-tree support) 1.584 + * use an underscore ('_') between package and item names. 1.585 + */ 1.586 + offset=(int32_t)ds->readUInt32(inEntries[0].nameOffset)-stringsOffset; 1.587 + s=inItemStrings+offset; // name of the first entry 1.588 + int32_t prefixLength; 1.589 + if(doAutoPrefix) { 1.590 + // Use the first entry's prefix. Must be a new-style package. 1.591 + const char *prefixLimit=strchr(s, U_TREE_ENTRY_SEP_CHAR); 1.592 + if(prefixLimit==NULL) { 1.593 + fprintf(stderr, 1.594 + "icupkg: --auto_toc_prefix[_with_type] but " 1.595 + "the first entry \"%s\" does not contain a '%c'\n", 1.596 + s, U_TREE_ENTRY_SEP_CHAR); 1.597 + exit(U_INVALID_FORMAT_ERROR); 1.598 + } 1.599 + prefixLength=(int32_t)(prefixLimit-s); 1.600 + if(prefixLength==0 || prefixLength>=LENGTHOF(pkgPrefix)) { 1.601 + fprintf(stderr, 1.602 + "icupkg: --auto_toc_prefix[_with_type] but " 1.603 + "the prefix of the first entry \"%s\" is empty or too long\n", 1.604 + s); 1.605 + exit(U_INVALID_FORMAT_ERROR); 1.606 + } 1.607 + if(prefixEndsWithType && s[prefixLength-1]!=type) { 1.608 + fprintf(stderr, 1.609 + "icupkg: --auto_toc_prefix_with_type but " 1.610 + "the prefix of the first entry \"%s\" does not end with '%c'\n", 1.611 + s, type); 1.612 + exit(U_INVALID_FORMAT_ERROR); 1.613 + } 1.614 + memcpy(pkgPrefix, s, prefixLength); 1.615 + memcpy(prefix, s, ++prefixLength); // include the / 1.616 + } else { 1.617 + // Use the package basename as prefix. 1.618 + int32_t inPkgNameLength=strlen(inPkgName); 1.619 + memcpy(prefix, inPkgName, inPkgNameLength); 1.620 + prefixLength=inPkgNameLength; 1.621 + 1.622 + if( (int32_t)strlen(s)>=(inPkgNameLength+2) && 1.623 + 0==memcmp(s, inPkgName, inPkgNameLength) && 1.624 + s[inPkgNameLength]=='_' 1.625 + ) { 1.626 + // old-style .dat package 1.627 + prefix[prefixLength++]='_'; 1.628 + } else { 1.629 + // new-style .dat package 1.630 + prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR; 1.631 + // if it turns out to not contain U_TREE_ENTRY_SEP_CHAR 1.632 + // then the test in the loop below will fail 1.633 + } 1.634 + } 1.635 + prefix[prefixLength]=0; 1.636 + 1.637 + /* read the ToC table */ 1.638 + for(i=0; i<itemCount; ++i) { 1.639 + // skip the package part of the item name, error if it does not match the actual package name 1.640 + // or if nothing follows the package name 1.641 + offset=(int32_t)ds->readUInt32(inEntries[i].nameOffset)-stringsOffset; 1.642 + s=inItemStrings+offset; 1.643 + if(0!=strncmp(s, prefix, prefixLength) || s[prefixLength]==0) { 1.644 + fprintf(stderr, "icupkg: input .dat item name \"%s\" does not start with \"%s\"\n", 1.645 + s, prefix); 1.646 + exit(U_INVALID_FORMAT_ERROR); 1.647 + } 1.648 + items[i].name=s+prefixLength; 1.649 + 1.650 + // set the item's data 1.651 + items[i].data=(uint8_t *)inBytes+ds->readUInt32(inEntries[i].dataOffset); 1.652 + if(i>0) { 1.653 + items[i-1].length=(int32_t)(items[i].data-items[i-1].data); 1.654 + 1.655 + // set the previous item's platform type 1.656 + typeEnum=getTypeEnumForInputData(items[i-1].data, items[i-1].length, &errorCode); 1.657 + if(typeEnum<0 || U_FAILURE(errorCode)) { 1.658 + fprintf(stderr, "icupkg: not an ICU data file: item \"%s\" in \"%s\"\n", items[i-1].name, filename); 1.659 + exit(U_INVALID_FORMAT_ERROR); 1.660 + } 1.661 + items[i-1].type=makeTypeLetter(typeEnum); 1.662 + } 1.663 + items[i].isDataOwned=FALSE; 1.664 + } 1.665 + // set the last item's length 1.666 + items[itemCount-1].length=length-ds->readUInt32(inEntries[itemCount-1].dataOffset); 1.667 + 1.668 + // set the last item's platform type 1.669 + typeEnum=getTypeEnumForInputData(items[itemCount-1].data, items[itemCount-1].length, &errorCode); 1.670 + if(typeEnum<0 || U_FAILURE(errorCode)) { 1.671 + fprintf(stderr, "icupkg: not an ICU data file: item \"%s\" in \"%s\"\n", items[i-1].name, filename); 1.672 + exit(U_INVALID_FORMAT_ERROR); 1.673 + } 1.674 + items[itemCount-1].type=makeTypeLetter(typeEnum); 1.675 + 1.676 + if(type!=U_ICUDATA_TYPE_LETTER[0]) { 1.677 + // sort the item names for the local charset 1.678 + sortItems(); 1.679 + } 1.680 + } 1.681 + 1.682 + udata_closeSwapper(ds); 1.683 +} 1.684 + 1.685 +char 1.686 +Package::getInType() { 1.687 + return makeTypeLetter(inCharset, inIsBigEndian); 1.688 +} 1.689 + 1.690 +void 1.691 +Package::writePackage(const char *filename, char outType, const char *comment) { 1.692 + char prefix[MAX_PKG_NAME_LENGTH+4]; 1.693 + UDataOffsetTOCEntry entry; 1.694 + UDataSwapper *dsLocalToOut, *ds[TYPE_COUNT]; 1.695 + FILE *file; 1.696 + Item *pItem; 1.697 + char *name; 1.698 + UErrorCode errorCode; 1.699 + int32_t i, length, prefixLength, maxItemLength, basenameOffset, offset, outInt32; 1.700 + uint8_t outCharset; 1.701 + UBool outIsBigEndian; 1.702 + 1.703 + extractPackageName(filename, prefix, MAX_PKG_NAME_LENGTH); 1.704 + 1.705 + // if there is an explicit comment, then use it, else use what's in the current header 1.706 + if(comment!=NULL) { 1.707 + /* get the header size minus the current comment */ 1.708 + DataHeader *pHeader; 1.709 + int32_t length; 1.710 + 1.711 + pHeader=(DataHeader *)header; 1.712 + headerLength=4+pHeader->info.size; 1.713 + length=(int32_t)strlen(comment); 1.714 + if((int32_t)(headerLength+length)>=(int32_t)sizeof(header)) { 1.715 + fprintf(stderr, "icupkg: comment too long\n"); 1.716 + exit(U_BUFFER_OVERFLOW_ERROR); 1.717 + } 1.718 + memcpy(header+headerLength, comment, length+1); 1.719 + headerLength+=length; 1.720 + if(headerLength&0xf) { 1.721 + /* NUL-pad the header to a multiple of 16 */ 1.722 + length=(headerLength+0xf)&~0xf; 1.723 + memset(header+headerLength, 0, length-headerLength); 1.724 + headerLength=length; 1.725 + } 1.726 + pHeader->dataHeader.headerSize=(uint16_t)headerLength; 1.727 + } 1.728 + 1.729 + makeTypeProps(outType, outCharset, outIsBigEndian); 1.730 + 1.731 + // open (TYPE_COUNT-2) swappers 1.732 + // one is a no-op for local type==outType 1.733 + // one type (TYPE_LE) is bogus 1.734 + errorCode=U_ZERO_ERROR; 1.735 + i=makeTypeEnum(outType); 1.736 + ds[TYPE_B]= i==TYPE_B ? NULL : udata_openSwapper(TRUE, U_ASCII_FAMILY, outIsBigEndian, outCharset, &errorCode); 1.737 + ds[TYPE_L]= i==TYPE_L ? NULL : udata_openSwapper(FALSE, U_ASCII_FAMILY, outIsBigEndian, outCharset, &errorCode); 1.738 + ds[TYPE_LE]=NULL; 1.739 + ds[TYPE_E]= i==TYPE_E ? NULL : udata_openSwapper(TRUE, U_EBCDIC_FAMILY, outIsBigEndian, outCharset, &errorCode); 1.740 + if(U_FAILURE(errorCode)) { 1.741 + fprintf(stderr, "icupkg: udata_openSwapper() failed - %s\n", u_errorName(errorCode)); 1.742 + exit(errorCode); 1.743 + } 1.744 + for(i=0; i<TYPE_COUNT; ++i) { 1.745 + if(ds[i]!=NULL) { 1.746 + ds[i]->printError=printPackageError; 1.747 + ds[i]->printErrorContext=stderr; 1.748 + } 1.749 + } 1.750 + 1.751 + dsLocalToOut=ds[makeTypeEnum(U_CHARSET_FAMILY, U_IS_BIG_ENDIAN)]; 1.752 + 1.753 + // create the file and write its contents 1.754 + file=fopen(filename, "wb"); 1.755 + if(file==NULL) { 1.756 + fprintf(stderr, "icupkg: unable to create file \"%s\"\n", filename); 1.757 + exit(U_FILE_ACCESS_ERROR); 1.758 + } 1.759 + 1.760 + // swap and write the header 1.761 + if(dsLocalToOut!=NULL) { 1.762 + udata_swapDataHeader(dsLocalToOut, header, headerLength, header, &errorCode); 1.763 + if(U_FAILURE(errorCode)) { 1.764 + fprintf(stderr, "icupkg: udata_swapDataHeader(local to out) failed - %s\n", u_errorName(errorCode)); 1.765 + exit(errorCode); 1.766 + } 1.767 + } 1.768 + length=(int32_t)fwrite(header, 1, headerLength, file); 1.769 + if(length!=headerLength) { 1.770 + fprintf(stderr, "icupkg: unable to write complete header to file \"%s\"\n", filename); 1.771 + exit(U_FILE_ACCESS_ERROR); 1.772 + } 1.773 + 1.774 + // prepare and swap the package name with a tree separator 1.775 + // for prepending to item names 1.776 + if(pkgPrefix[0]==0) { 1.777 + prefixLength=(int32_t)strlen(prefix); 1.778 + } else { 1.779 + prefixLength=(int32_t)strlen(pkgPrefix); 1.780 + memcpy(prefix, pkgPrefix, prefixLength); 1.781 + if(prefixEndsWithType) { 1.782 + prefix[prefixLength-1]=outType; 1.783 + } 1.784 + } 1.785 + prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR; 1.786 + prefix[prefixLength]=0; 1.787 + if(dsLocalToOut!=NULL) { 1.788 + dsLocalToOut->swapInvChars(dsLocalToOut, prefix, prefixLength, prefix, &errorCode); 1.789 + if(U_FAILURE(errorCode)) { 1.790 + fprintf(stderr, "icupkg: swapInvChars(output package name) failed - %s\n", u_errorName(errorCode)); 1.791 + exit(errorCode); 1.792 + } 1.793 + 1.794 + // swap and sort the item names (sorting needs to be done in the output charset) 1.795 + dsLocalToOut->swapInvChars(dsLocalToOut, inStrings, inStringTop, inStrings, &errorCode); 1.796 + if(U_FAILURE(errorCode)) { 1.797 + fprintf(stderr, "icupkg: swapInvChars(item names) failed - %s\n", u_errorName(errorCode)); 1.798 + exit(errorCode); 1.799 + } 1.800 + sortItems(); 1.801 + } 1.802 + 1.803 + // create the output item names in sorted order, with the package name prepended to each 1.804 + for(i=0; i<itemCount; ++i) { 1.805 + length=(int32_t)strlen(items[i].name); 1.806 + name=allocString(FALSE, length+prefixLength); 1.807 + memcpy(name, prefix, prefixLength); 1.808 + memcpy(name+prefixLength, items[i].name, length+1); 1.809 + items[i].name=name; 1.810 + } 1.811 + 1.812 + // calculate offsets for item names and items, pad to 16-align items 1.813 + // align only the first item; each item's length is a multiple of 16 1.814 + basenameOffset=4+8*itemCount; 1.815 + offset=basenameOffset+outStringTop; 1.816 + if((length=(offset&15))!=0) { 1.817 + length=16-length; 1.818 + memset(allocString(FALSE, length-1), 0xaa, length); 1.819 + offset+=length; 1.820 + } 1.821 + 1.822 + // write the table of contents 1.823 + // first the itemCount 1.824 + outInt32=itemCount; 1.825 + if(dsLocalToOut!=NULL) { 1.826 + dsLocalToOut->swapArray32(dsLocalToOut, &outInt32, 4, &outInt32, &errorCode); 1.827 + if(U_FAILURE(errorCode)) { 1.828 + fprintf(stderr, "icupkg: swapArray32(item count) failed - %s\n", u_errorName(errorCode)); 1.829 + exit(errorCode); 1.830 + } 1.831 + } 1.832 + length=(int32_t)fwrite(&outInt32, 1, 4, file); 1.833 + if(length!=4) { 1.834 + fprintf(stderr, "icupkg: unable to write complete item count to file \"%s\"\n", filename); 1.835 + exit(U_FILE_ACCESS_ERROR); 1.836 + } 1.837 + 1.838 + // then write the item entries (and collect the maxItemLength) 1.839 + maxItemLength=0; 1.840 + for(i=0; i<itemCount; ++i) { 1.841 + entry.nameOffset=(uint32_t)(basenameOffset+(items[i].name-outStrings)); 1.842 + entry.dataOffset=(uint32_t)offset; 1.843 + if(dsLocalToOut!=NULL) { 1.844 + dsLocalToOut->swapArray32(dsLocalToOut, &entry, 8, &entry, &errorCode); 1.845 + if(U_FAILURE(errorCode)) { 1.846 + fprintf(stderr, "icupkg: swapArray32(item entry %ld) failed - %s\n", (long)i, u_errorName(errorCode)); 1.847 + exit(errorCode); 1.848 + } 1.849 + } 1.850 + length=(int32_t)fwrite(&entry, 1, 8, file); 1.851 + if(length!=8) { 1.852 + fprintf(stderr, "icupkg: unable to write complete item entry %ld to file \"%s\"\n", (long)i, filename); 1.853 + exit(U_FILE_ACCESS_ERROR); 1.854 + } 1.855 + 1.856 + length=items[i].length; 1.857 + if(length>maxItemLength) { 1.858 + maxItemLength=length; 1.859 + } 1.860 + offset+=length; 1.861 + } 1.862 + 1.863 + // write the item names 1.864 + length=(int32_t)fwrite(outStrings, 1, outStringTop, file); 1.865 + if(length!=outStringTop) { 1.866 + fprintf(stderr, "icupkg: unable to write complete item names to file \"%s\"\n", filename); 1.867 + exit(U_FILE_ACCESS_ERROR); 1.868 + } 1.869 + 1.870 + // write the items 1.871 + for(pItem=items, i=0; i<itemCount; ++pItem, ++i) { 1.872 + int32_t type=makeTypeEnum(pItem->type); 1.873 + if(ds[type]!=NULL) { 1.874 + // swap each item from its platform properties to the desired ones 1.875 + udata_swap( 1.876 + ds[type], 1.877 + pItem->data, pItem->length, pItem->data, 1.878 + &errorCode); 1.879 + if(U_FAILURE(errorCode)) { 1.880 + fprintf(stderr, "icupkg: udata_swap(item %ld) failed - %s\n", (long)i, u_errorName(errorCode)); 1.881 + exit(errorCode); 1.882 + } 1.883 + } 1.884 + length=(int32_t)fwrite(pItem->data, 1, pItem->length, file); 1.885 + if(length!=pItem->length) { 1.886 + fprintf(stderr, "icupkg: unable to write complete item %ld to file \"%s\"\n", (long)i, filename); 1.887 + exit(U_FILE_ACCESS_ERROR); 1.888 + } 1.889 + } 1.890 + 1.891 + if(ferror(file)) { 1.892 + fprintf(stderr, "icupkg: unable to write complete file \"%s\"\n", filename); 1.893 + exit(U_FILE_ACCESS_ERROR); 1.894 + } 1.895 + 1.896 + fclose(file); 1.897 + for(i=0; i<TYPE_COUNT; ++i) { 1.898 + udata_closeSwapper(ds[i]); 1.899 + } 1.900 +} 1.901 + 1.902 +int32_t 1.903 +Package::findItem(const char *name, int32_t length) const { 1.904 + int32_t i, start, limit; 1.905 + int result; 1.906 + 1.907 + /* do a binary search for the string */ 1.908 + start=0; 1.909 + limit=itemCount; 1.910 + while(start<limit) { 1.911 + i=(start+limit)/2; 1.912 + if(length>=0) { 1.913 + result=strncmp(name, items[i].name, length); 1.914 + } else { 1.915 + result=strcmp(name, items[i].name); 1.916 + } 1.917 + 1.918 + if(result==0) { 1.919 + /* found */ 1.920 + if(length>=0) { 1.921 + /* 1.922 + * if we compared just prefixes, then we may need to back up 1.923 + * to the first item with this prefix 1.924 + */ 1.925 + while(i>0 && 0==strncmp(name, items[i-1].name, length)) { 1.926 + --i; 1.927 + } 1.928 + } 1.929 + return i; 1.930 + } else if(result<0) { 1.931 + limit=i; 1.932 + } else /* result>0 */ { 1.933 + start=i+1; 1.934 + } 1.935 + } 1.936 + 1.937 + return ~start; /* not found, return binary-not of the insertion point */ 1.938 +} 1.939 + 1.940 +void 1.941 +Package::findItems(const char *pattern) { 1.942 + const char *wild; 1.943 + 1.944 + if(pattern==NULL || *pattern==0) { 1.945 + findNextIndex=-1; 1.946 + return; 1.947 + } 1.948 + 1.949 + findPrefix=pattern; 1.950 + findSuffix=NULL; 1.951 + findSuffixLength=0; 1.952 + 1.953 + wild=strchr(pattern, '*'); 1.954 + if(wild==NULL) { 1.955 + // no wildcard 1.956 + findPrefixLength=(int32_t)strlen(pattern); 1.957 + } else { 1.958 + // one wildcard 1.959 + findPrefixLength=(int32_t)(wild-pattern); 1.960 + findSuffix=wild+1; 1.961 + findSuffixLength=(int32_t)strlen(findSuffix); 1.962 + if(NULL!=strchr(findSuffix, '*')) { 1.963 + // two or more wildcards 1.964 + fprintf(stderr, "icupkg: syntax error (more than one '*') in item pattern \"%s\"\n", pattern); 1.965 + exit(U_PARSE_ERROR); 1.966 + } 1.967 + } 1.968 + 1.969 + if(findPrefixLength==0) { 1.970 + findNextIndex=0; 1.971 + } else { 1.972 + findNextIndex=findItem(findPrefix, findPrefixLength); 1.973 + } 1.974 +} 1.975 + 1.976 +int32_t 1.977 +Package::findNextItem() { 1.978 + const char *name, *middle, *treeSep; 1.979 + int32_t idx, nameLength, middleLength; 1.980 + 1.981 + if(findNextIndex<0) { 1.982 + return -1; 1.983 + } 1.984 + 1.985 + while(findNextIndex<itemCount) { 1.986 + idx=findNextIndex++; 1.987 + name=items[idx].name; 1.988 + nameLength=(int32_t)strlen(name); 1.989 + if(nameLength<(findPrefixLength+findSuffixLength)) { 1.990 + // item name too short for prefix & suffix 1.991 + continue; 1.992 + } 1.993 + if(findPrefixLength>0 && 0!=memcmp(findPrefix, name, findPrefixLength)) { 1.994 + // left the range of names with this prefix 1.995 + break; 1.996 + } 1.997 + middle=name+findPrefixLength; 1.998 + middleLength=nameLength-findPrefixLength-findSuffixLength; 1.999 + if(findSuffixLength>0 && 0!=memcmp(findSuffix, name+(nameLength-findSuffixLength), findSuffixLength)) { 1.1000 + // suffix does not match 1.1001 + continue; 1.1002 + } 1.1003 + // prefix & suffix match 1.1004 + 1.1005 + if(matchMode&MATCH_NOSLASH) { 1.1006 + treeSep=strchr(middle, U_TREE_ENTRY_SEP_CHAR); 1.1007 + if(treeSep!=NULL && (treeSep-middle)<middleLength) { 1.1008 + // the middle (matching the * wildcard) contains a tree separator / 1.1009 + continue; 1.1010 + } 1.1011 + } 1.1012 + 1.1013 + // found a matching item 1.1014 + return idx; 1.1015 + } 1.1016 + 1.1017 + // no more items 1.1018 + findNextIndex=-1; 1.1019 + return -1; 1.1020 +} 1.1021 + 1.1022 +void 1.1023 +Package::setMatchMode(uint32_t mode) { 1.1024 + matchMode=mode; 1.1025 +} 1.1026 + 1.1027 +void 1.1028 +Package::addItem(const char *name) { 1.1029 + addItem(name, NULL, 0, FALSE, U_ICUDATA_TYPE_LETTER[0]); 1.1030 +} 1.1031 + 1.1032 +void 1.1033 +Package::addItem(const char *name, uint8_t *data, int32_t length, UBool isDataOwned, char type) { 1.1034 + int32_t idx; 1.1035 + 1.1036 + idx=findItem(name); 1.1037 + if(idx<0) { 1.1038 + // new item, make space at the insertion point 1.1039 + ensureItemCapacity(); 1.1040 + // move the following items down 1.1041 + idx=~idx; 1.1042 + if(idx<itemCount) { 1.1043 + memmove(items+idx+1, items+idx, (itemCount-idx)*sizeof(Item)); 1.1044 + } 1.1045 + ++itemCount; 1.1046 + 1.1047 + // reset this Item entry 1.1048 + memset(items+idx, 0, sizeof(Item)); 1.1049 + 1.1050 + // copy the item's name 1.1051 + items[idx].name=allocString(TRUE, strlen(name)); 1.1052 + strcpy(items[idx].name, name); 1.1053 + pathToTree(items[idx].name); 1.1054 + } else { 1.1055 + // same-name item found, replace it 1.1056 + if(items[idx].isDataOwned) { 1.1057 + free(items[idx].data); 1.1058 + } 1.1059 + 1.1060 + // keep the item's name since it is the same 1.1061 + } 1.1062 + 1.1063 + // set the item's data 1.1064 + items[idx].data=data; 1.1065 + items[idx].length=length; 1.1066 + items[idx].isDataOwned=isDataOwned; 1.1067 + items[idx].type=type; 1.1068 +} 1.1069 + 1.1070 +void 1.1071 +Package::addFile(const char *filesPath, const char *name) { 1.1072 + uint8_t *data; 1.1073 + int32_t length; 1.1074 + char type; 1.1075 + 1.1076 + data=readFile(filesPath, name, length, type); 1.1077 + // readFile() exits the tool if it fails 1.1078 + addItem(name, data, length, TRUE, type); 1.1079 +} 1.1080 + 1.1081 +void 1.1082 +Package::addItems(const Package &listPkg) { 1.1083 + const Item *pItem; 1.1084 + int32_t i; 1.1085 + 1.1086 + for(pItem=listPkg.items, i=0; i<listPkg.itemCount; ++pItem, ++i) { 1.1087 + addItem(pItem->name, pItem->data, pItem->length, FALSE, pItem->type); 1.1088 + } 1.1089 +} 1.1090 + 1.1091 +void 1.1092 +Package::removeItem(int32_t idx) { 1.1093 + if(idx>=0) { 1.1094 + // remove the item 1.1095 + if(items[idx].isDataOwned) { 1.1096 + free(items[idx].data); 1.1097 + } 1.1098 + 1.1099 + // move the following items up 1.1100 + if((idx+1)<itemCount) { 1.1101 + memmove(items+idx, items+idx+1, (itemCount-(idx+1))*sizeof(Item)); 1.1102 + } 1.1103 + --itemCount; 1.1104 + 1.1105 + if(idx<=findNextIndex) { 1.1106 + --findNextIndex; 1.1107 + } 1.1108 + } 1.1109 +} 1.1110 + 1.1111 +void 1.1112 +Package::removeItems(const char *pattern) { 1.1113 + int32_t idx; 1.1114 + 1.1115 + findItems(pattern); 1.1116 + while((idx=findNextItem())>=0) { 1.1117 + removeItem(idx); 1.1118 + } 1.1119 +} 1.1120 + 1.1121 +void 1.1122 +Package::removeItems(const Package &listPkg) { 1.1123 + const Item *pItem; 1.1124 + int32_t i; 1.1125 + 1.1126 + for(pItem=listPkg.items, i=0; i<listPkg.itemCount; ++pItem, ++i) { 1.1127 + removeItems(pItem->name); 1.1128 + } 1.1129 +} 1.1130 + 1.1131 +void 1.1132 +Package::extractItem(const char *filesPath, const char *outName, int32_t idx, char outType) { 1.1133 + char filename[1024]; 1.1134 + UDataSwapper *ds; 1.1135 + FILE *file; 1.1136 + Item *pItem; 1.1137 + int32_t fileLength; 1.1138 + uint8_t itemCharset, outCharset; 1.1139 + UBool itemIsBigEndian, outIsBigEndian; 1.1140 + 1.1141 + if(idx<0 || itemCount<=idx) { 1.1142 + return; 1.1143 + } 1.1144 + pItem=items+idx; 1.1145 + 1.1146 + // swap the data to the outType 1.1147 + // outType==0: don't swap 1.1148 + if(outType!=0 && pItem->type!=outType) { 1.1149 + // open the swapper 1.1150 + UErrorCode errorCode=U_ZERO_ERROR; 1.1151 + makeTypeProps(pItem->type, itemCharset, itemIsBigEndian); 1.1152 + makeTypeProps(outType, outCharset, outIsBigEndian); 1.1153 + ds=udata_openSwapper(itemIsBigEndian, itemCharset, outIsBigEndian, outCharset, &errorCode); 1.1154 + if(U_FAILURE(errorCode)) { 1.1155 + fprintf(stderr, "icupkg: udata_openSwapper(item %ld) failed - %s\n", 1.1156 + (long)idx, u_errorName(errorCode)); 1.1157 + exit(errorCode); 1.1158 + } 1.1159 + 1.1160 + ds->printError=printPackageError; 1.1161 + ds->printErrorContext=stderr; 1.1162 + 1.1163 + // swap the item from its platform properties to the desired ones 1.1164 + udata_swap(ds, pItem->data, pItem->length, pItem->data, &errorCode); 1.1165 + if(U_FAILURE(errorCode)) { 1.1166 + fprintf(stderr, "icupkg: udata_swap(item %ld) failed - %s\n", (long)idx, u_errorName(errorCode)); 1.1167 + exit(errorCode); 1.1168 + } 1.1169 + udata_closeSwapper(ds); 1.1170 + pItem->type=outType; 1.1171 + } 1.1172 + 1.1173 + // create the file and write its contents 1.1174 + makeFullFilenameAndDirs(filesPath, outName, filename, (int32_t)sizeof(filename)); 1.1175 + file=fopen(filename, "wb"); 1.1176 + if(file==NULL) { 1.1177 + fprintf(stderr, "icupkg: unable to create file \"%s\"\n", filename); 1.1178 + exit(U_FILE_ACCESS_ERROR); 1.1179 + } 1.1180 + fileLength=(int32_t)fwrite(pItem->data, 1, pItem->length, file); 1.1181 + 1.1182 + if(ferror(file) || fileLength!=pItem->length) { 1.1183 + fprintf(stderr, "icupkg: unable to write complete file \"%s\"\n", filename); 1.1184 + exit(U_FILE_ACCESS_ERROR); 1.1185 + } 1.1186 + fclose(file); 1.1187 +} 1.1188 + 1.1189 +void 1.1190 +Package::extractItem(const char *filesPath, int32_t idx, char outType) { 1.1191 + extractItem(filesPath, items[idx].name, idx, outType); 1.1192 +} 1.1193 + 1.1194 +void 1.1195 +Package::extractItems(const char *filesPath, const char *pattern, char outType) { 1.1196 + int32_t idx; 1.1197 + 1.1198 + findItems(pattern); 1.1199 + while((idx=findNextItem())>=0) { 1.1200 + extractItem(filesPath, idx, outType); 1.1201 + } 1.1202 +} 1.1203 + 1.1204 +void 1.1205 +Package::extractItems(const char *filesPath, const Package &listPkg, char outType) { 1.1206 + const Item *pItem; 1.1207 + int32_t i; 1.1208 + 1.1209 + for(pItem=listPkg.items, i=0; i<listPkg.itemCount; ++pItem, ++i) { 1.1210 + extractItems(filesPath, pItem->name, outType); 1.1211 + } 1.1212 +} 1.1213 + 1.1214 +int32_t 1.1215 +Package::getItemCount() const { 1.1216 + return itemCount; 1.1217 +} 1.1218 + 1.1219 +const Item * 1.1220 +Package::getItem(int32_t idx) const { 1.1221 + if (0 <= idx && idx < itemCount) { 1.1222 + return &items[idx]; 1.1223 + } 1.1224 + return NULL; 1.1225 +} 1.1226 + 1.1227 +void 1.1228 +Package::checkDependency(void *context, const char *itemName, const char *targetName) { 1.1229 + // check dependency: make sure the target item is in the package 1.1230 + Package *me=(Package *)context; 1.1231 + if(me->findItem(targetName)<0) { 1.1232 + me->isMissingItems=TRUE; 1.1233 + fprintf(stderr, "Item %s depends on missing item %s\n", itemName, targetName); 1.1234 + } 1.1235 +} 1.1236 + 1.1237 +UBool 1.1238 +Package::checkDependencies() { 1.1239 + isMissingItems=FALSE; 1.1240 + enumDependencies(this, checkDependency); 1.1241 + return (UBool)!isMissingItems; 1.1242 +} 1.1243 + 1.1244 +void 1.1245 +Package::enumDependencies(void *context, CheckDependency check) { 1.1246 + int32_t i; 1.1247 + 1.1248 + for(i=0; i<itemCount; ++i) { 1.1249 + enumDependencies(items+i, context, check); 1.1250 + } 1.1251 +} 1.1252 + 1.1253 +char * 1.1254 +Package::allocString(UBool in, int32_t length) { 1.1255 + char *p; 1.1256 + int32_t top; 1.1257 + 1.1258 + if(in) { 1.1259 + top=inStringTop; 1.1260 + p=inStrings+top; 1.1261 + } else { 1.1262 + top=outStringTop; 1.1263 + p=outStrings+top; 1.1264 + } 1.1265 + top+=length+1; 1.1266 + 1.1267 + if(top>STRING_STORE_SIZE) { 1.1268 + fprintf(stderr, "icupkg: string storage overflow\n"); 1.1269 + exit(U_BUFFER_OVERFLOW_ERROR); 1.1270 + } 1.1271 + if(in) { 1.1272 + inStringTop=top; 1.1273 + } else { 1.1274 + outStringTop=top; 1.1275 + } 1.1276 + return p; 1.1277 +} 1.1278 + 1.1279 +void 1.1280 +Package::sortItems() { 1.1281 + UErrorCode errorCode=U_ZERO_ERROR; 1.1282 + uprv_sortArray(items, itemCount, (int32_t)sizeof(Item), compareItems, NULL, FALSE, &errorCode); 1.1283 + if(U_FAILURE(errorCode)) { 1.1284 + fprintf(stderr, "icupkg: sorting item names failed - %s\n", u_errorName(errorCode)); 1.1285 + exit(errorCode); 1.1286 + } 1.1287 +} 1.1288 + 1.1289 +void Package::setItemCapacity(int32_t max) 1.1290 +{ 1.1291 + if(max<=itemMax) { 1.1292 + return; 1.1293 + } 1.1294 + Item *newItems = (Item*)uprv_malloc(max * sizeof(items[0])); 1.1295 + Item *oldItems = items; 1.1296 + if(newItems == NULL) { 1.1297 + fprintf(stderr, "icupkg: Out of memory trying to allocate %lu bytes for %d items\n", 1.1298 + (unsigned long)max*sizeof(items[0]), max); 1.1299 + exit(U_MEMORY_ALLOCATION_ERROR); 1.1300 + } 1.1301 + if(items && itemCount>0) { 1.1302 + uprv_memcpy(newItems, items, itemCount*sizeof(items[0])); 1.1303 + } 1.1304 + itemMax = max; 1.1305 + items = newItems; 1.1306 + uprv_free(oldItems); 1.1307 +} 1.1308 + 1.1309 +void Package::ensureItemCapacity() 1.1310 +{ 1.1311 + if((itemCount+1)>itemMax) { 1.1312 + setItemCapacity(itemCount+kItemsChunk); 1.1313 + } 1.1314 +} 1.1315 + 1.1316 +U_NAMESPACE_END