void setItem(const Item *item, UDataSwapFn *swap) { pItem=item; int32_t infoLength, itemHeaderLength; UErrorCode errorCode=U_ZERO_ERROR; pInfo=::getDataInfo(pItem->data, pItem->length, infoLength, itemHeaderLength, &errorCode); if(U_FAILURE(errorCode)) { exit(errorCode); // should succeed because readFile() checks headers } length=pItem->length-itemHeaderLength; if(pInfo->isBigEndian==U_IS_BIG_ENDIAN && pInfo->charsetFamily==U_CHARSET_FAMILY) { bytes=pItem->data+itemHeaderLength; } else { UDataSwapper *ds=udata_openSwapper((UBool)pInfo->isBigEndian, pInfo->charsetFamily, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n", pItem->name, u_errorName(errorCode)); exit(errorCode); } ds->printError=printError; ds->printErrorContext=stderr; swapped=new uint8_t[pItem->length]; if(swapped==NULL) { fprintf(stderr, "icupkg: unable to allocate memory for swapping \"%s\"\n", pItem->name); exit(U_MEMORY_ALLOCATION_ERROR); } swap(ds, pItem->data, pItem->length, swapped, &errorCode); pInfo=::getDataInfo(swapped, pItem->length, infoLength, itemHeaderLength, &errorCode); bytes=swapped+itemHeaderLength; udata_closeSwapper(ds); } }
void Package::extractItem(const char *filesPath, const char *outName, int32_t index, char outType) { char filename[1024]; UDataSwapper *ds; FILE *file; Item *pItem; int32_t fileLength; uint8_t itemCharset, outCharset; UBool itemIsBigEndian, outIsBigEndian; if(index<0 || itemCount<=index) { return; } pItem=items+index; // swap the data to the outType // outType==0: don't swap if(outType!=0 && pItem->type!=outType) { // open the swapper UErrorCode errorCode=U_ZERO_ERROR; makeTypeProps(pItem->type, itemCharset, itemIsBigEndian); makeTypeProps(outType, outCharset, outIsBigEndian); ds=udata_openSwapper(itemIsBigEndian, itemCharset, outIsBigEndian, outCharset, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: udata_openSwapper(item %ld) failed - %s\n", (long)index, u_errorName(errorCode)); exit(errorCode); } ds->printError=printPackageError; ds->printErrorContext=stderr; // swap the item from its platform properties to the desired ones udata_swap(ds, pItem->data, pItem->length, pItem->data, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: udata_swap(item %ld) failed - %s\n", (long)index, u_errorName(errorCode)); exit(errorCode); } udata_closeSwapper(ds); } // create the file and write its contents makeFullFilenameAndDirs(filesPath, outName, filename, (int32_t)sizeof(filename)); file=fopen(filename, "wb"); if(file==NULL) { fprintf(stderr, "icupkg: unable to create file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR); } fileLength=(int32_t)fwrite(pItem->data, 1, pItem->length, file); if(ferror(file) || fileLength!=pItem->length) { fprintf(stderr, "icupkg: unable to write complete file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR); } fclose(file); }
/* unserialize a selector */ U_CAPI UConverterSelector* U_EXPORT2 ucnvsel_openFromSerialized(const void* buffer, int32_t length, UErrorCode* status) { // check if already failed if (U_FAILURE(*status)) { return NULL; } // ensure args make sense! const uint8_t *p = (const uint8_t *)buffer; if (length <= 0 || (length > 0 && (p == NULL || (U_POINTER_MASK_LSB(p, 3) != 0))) ) { *status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // header if (length < 32) { // not even enough space for a minimal header *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } const DataHeader *pHeader = (const DataHeader *)p; if (!( pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 && pHeader->info.dataFormat[0] == 0x43 && pHeader->info.dataFormat[1] == 0x53 && pHeader->info.dataFormat[2] == 0x65 && pHeader->info.dataFormat[3] == 0x6c )) { /* header not valid or dataFormat not recognized */ *status = U_INVALID_FORMAT_ERROR; return NULL; } if (pHeader->info.formatVersion[0] != 1) { *status = U_UNSUPPORTED_ERROR; return NULL; } uint8_t* swapped = NULL; if (pHeader->info.isBigEndian != U_IS_BIG_ENDIAN || pHeader->info.charsetFamily != U_CHARSET_FAMILY ) { // swap the data UDataSwapper *ds = udata_openSwapperForInputData(p, length, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, status); int32_t totalSize = ucnvsel_swap(ds, p, -1, NULL, status); if (U_FAILURE(*status)) { udata_closeSwapper(ds); return NULL; } if (length < totalSize) { udata_closeSwapper(ds); *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } swapped = (uint8_t*)uprv_malloc(totalSize); if (swapped == NULL) { udata_closeSwapper(ds); *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } ucnvsel_swap(ds, p, length, swapped, status); udata_closeSwapper(ds); if (U_FAILURE(*status)) { uprv_free(swapped); return NULL; } p = swapped; pHeader = (const DataHeader *)p; } if (length < (pHeader->dataHeader.headerSize + 16 * 4)) { // not even enough space for the header and the indexes uprv_free(swapped); *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } p += pHeader->dataHeader.headerSize; length -= pHeader->dataHeader.headerSize; // indexes const int32_t *indexes = (const int32_t *)p; if (length < indexes[UCNVSEL_INDEX_SIZE]) { uprv_free(swapped); *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } p += UCNVSEL_INDEX_COUNT * 4; // create and populate the selector object UConverterSelector* sel = (UConverterSelector*)uprv_malloc(sizeof(UConverterSelector)); char **encodings = (char **)uprv_malloc( indexes[UCNVSEL_INDEX_NAMES_COUNT] * sizeof(char *)); if (sel == NULL || encodings == NULL) { uprv_free(swapped); uprv_free(sel); uprv_free(encodings); *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } uprv_memset(sel, 0, sizeof(UConverterSelector)); sel->pvCount = indexes[UCNVSEL_INDEX_PV_COUNT]; sel->encodings = encodings; sel->encodingsCount = indexes[UCNVSEL_INDEX_NAMES_COUNT]; sel->encodingStrLength = indexes[UCNVSEL_INDEX_NAMES_LENGTH]; sel->swapped = swapped; // trie sel->trie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS, p, indexes[UCNVSEL_INDEX_TRIE_SIZE], NULL, status); p += indexes[UCNVSEL_INDEX_TRIE_SIZE]; if (U_FAILURE(*status)) { ucnvsel_close(sel); return NULL; } // bit vectors sel->pv = (uint32_t *)p; p += sel->pvCount * 4; // encoding names char* s = (char*)p; for (int32_t i = 0; i < sel->encodingsCount; ++i) { sel->encodings[i] = s; s += uprv_strlen(s) + 1; } p += sel->encodingStrLength; return sel; }
int main(int argc, char* argv[]) { UErrorCode status = U_ZERO_ERROR; const char *arg = NULL; const char *outputDir = NULL; /* NULL = no output directory, use current */ const char *inputDir = NULL; const char *encoding = ""; int i; U_MAIN_INIT_ARGS(argc, argv); argc = u_parseArgs(argc, argv, (int32_t)(sizeof(options)/sizeof(options[0])), options); /* error handling, printing usage message */ if(argc<0) { fprintf(stderr, "%s: error in command line argument \"%s\"\n", argv[0], argv[-argc]); } else if(argc<2) { argc = -1; } if(options[WRITE_POOL_BUNDLE].doesOccur && options[USE_POOL_BUNDLE].doesOccur) { fprintf(stderr, "%s: cannot combine --writePoolBundle and --usePoolBundle\n", argv[0]); argc = -1; } if(options[FORMAT_VERSION].doesOccur) { const char *s = options[FORMAT_VERSION].value; if(uprv_strlen(s) != 1 || (s[0] != '1' && s[0] != '2')) { fprintf(stderr, "%s: unsupported --formatVersion %s\n", argv[0], s); argc = -1; } else if(s[0] == '1' && (options[WRITE_POOL_BUNDLE].doesOccur || options[USE_POOL_BUNDLE].doesOccur) ) { fprintf(stderr, "%s: cannot combine --formatVersion 1 with --writePoolBundle or --usePoolBundle\n", argv[0]); argc = -1; } else { setFormatVersion(s[0] - '0'); } } if(options[VERSION].doesOccur) { fprintf(stderr, "%s version %s (ICU version %s).\n" "%s\n", argv[0], GENRB_VERSION, U_ICU_VERSION, U_COPYRIGHT_STRING); return U_ZERO_ERROR; } if(argc<0 || options[HELP1].doesOccur || options[HELP2].doesOccur) { /* * Broken into chunks because the C89 standard says the minimum * required supported string length is 509 bytes. */ fprintf(stderr, "Usage: %s [OPTIONS] [FILES]\n" "\tReads the list of resource bundle source files and creates\n" "\tbinary version of reosurce bundles (.res files)\n", argv[0]); fprintf(stderr, "Options:\n" "\t-h or -? or --help this usage text\n" "\t-q or --quiet do not display warnings\n" "\t-v or --verbose print extra information when processing files\n" "\t-V or --version prints out version number and exits\n" "\t-c or --copyright include copyright notice\n"); fprintf(stderr, "\t-e or --encoding encoding of source files\n" "\t-d of --destdir destination directory, followed by the path, defaults to %s\n" "\t-s or --sourcedir source directory for files followed by path, defaults to %s\n" "\t-i or --icudatadir directory for locating any needed intermediate data files,\n" "\t followed by path, defaults to %s\n", u_getDataDirectory(), u_getDataDirectory(), u_getDataDirectory()); fprintf(stderr, "\t-j or --write-java write a Java ListResourceBundle for ICU4J, followed by optional encoding\n" "\t defaults to ASCII and \\uXXXX format.\n"); /* This option is deprecated and should not be used ever. "\t-p or --package-name For ICU4J: package name for writing the ListResourceBundle for ICU4J,\n" "\t defaults to com.ibm.icu.impl.data\n"); */ fprintf(stderr, "\t-b or --bundle-name bundle name for writing the ListResourceBundle for ICU4J,\n" "\t defaults to LocaleElements\n" "\t-x or --write-xliff write an XLIFF file for the resource bundle. Followed by\n" "\t an optional output file name.\n" "\t-k or --strict use pedantic parsing of syntax\n" /*added by Jing*/ "\t-l or --language for XLIFF: language code compliant with BCP 47.\n"); fprintf(stderr, "\t-C or --noBinaryCollation do not generate binary collation image;\n" "\t makes .res file smaller but collator instantiation much slower;\n" "\t maintains ability to get tailoring rules\n" "\t-R or --omitCollationRules do not include collation (tailoring) rules;\n" "\t makes .res file smaller and maintains collator instantiation speed\n" "\t but tailoring rules will not be available (they are rarely used)\n"); fprintf(stderr, "\t --formatVersion write a .res file compatible with the requested formatVersion (single digit);\n" "\t for example, --formatVersion 1\n"); fprintf(stderr, "\t --writePoolBundle write a pool.res file with all of the keys of all input bundles\n" "\t --usePoolBundle [path-to-pool.res] point to keys from the pool.res keys pool bundle if they are available there;\n" "\t makes .res files smaller but dependent on the pool bundle\n" "\t (--writePoolBundle and --usePoolBundle cannot be combined)\n"); return argc < 0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR; } if(options[VERBOSE].doesOccur) { setVerbose(TRUE); } if(options[QUIET].doesOccur) { setShowWarning(FALSE); } if(options[STRICT].doesOccur) { setStrict(TRUE); } if(options[COPYRIGHT].doesOccur){ setIncludeCopyright(TRUE); } if(options[SOURCEDIR].doesOccur) { inputDir = options[SOURCEDIR].value; } if(options[DESTDIR].doesOccur) { outputDir = options[DESTDIR].value; } /* This option is deprecated and should never be used. if(options[PACKAGE_NAME].doesOccur) { gPackageName = options[PACKAGE_NAME].value; if(!strcmp(gPackageName, "ICUDATA")) { gPackageName = U_ICUDATA_NAME; } if(gPackageName[0] == 0) { gPackageName = NULL; } }*/ if(options[ENCODING].doesOccur) { encoding = options[ENCODING].value; } if(options[ICUDATADIR].doesOccur) { u_setDataDirectory(options[ICUDATADIR].value); } /* Initialize ICU */ u_init(&status); if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) { /* Note: u_init() will try to open ICU property data. * failures here are expected when building ICU from scratch. * ignore them. */ fprintf(stderr, "%s: can not initialize ICU. status = %s\n", argv[0], u_errorName(status)); exit(1); } status = U_ZERO_ERROR; if(options[WRITE_JAVA].doesOccur) { write_java = TRUE; outputEnc = options[WRITE_JAVA].value; } if(options[BUNDLE_NAME].doesOccur) { bundleName = options[BUNDLE_NAME].value; } if(options[WRITE_XLIFF].doesOccur) { write_xliff = TRUE; if(options[WRITE_XLIFF].value != NULL){ xliffOutputFileName = options[WRITE_XLIFF].value; } } initParser(options[NO_BINARY_COLLATION].doesOccur, options[NO_COLLATION_RULES].doesOccur); /*added by Jing*/ if(options[LANGUAGE].doesOccur) { language = options[LANGUAGE].value; } if(options[WRITE_POOL_BUNDLE].doesOccur) { newPoolBundle = bundle_open(NULL, TRUE, &status); if(U_FAILURE(status)) { fprintf(stderr, "unable to create an empty bundle for the pool keys: %s\n", u_errorName(status)); return status; } else { const char *poolResName = "pool.res"; char *nameWithoutSuffix = uprv_malloc(uprv_strlen(poolResName) + 1); if (nameWithoutSuffix == NULL) { fprintf(stderr, "out of memory error\n"); return U_MEMORY_ALLOCATION_ERROR; } uprv_strcpy(nameWithoutSuffix, poolResName); *uprv_strrchr(nameWithoutSuffix, '.') = 0; newPoolBundle->fLocale = nameWithoutSuffix; } } if(options[USE_POOL_BUNDLE].doesOccur) { const char *poolResName = "pool.res"; FileStream *poolFile; int32_t poolFileSize; int32_t indexLength; /* * TODO: Consolidate inputDir/filename handling from main() and processFile() * into a common function, and use it here as well. * Try to create toolutil functions for dealing with dir/filenames and * loading ICU data files without udata_open(). * Share code with icupkg? * Also, make_res_filename() seems to be unused. Review and remove. */ if (options[USE_POOL_BUNDLE].value!=NULL) { uprv_strcpy(theCurrentFileName, options[USE_POOL_BUNDLE].value); uprv_strcat(theCurrentFileName, U_FILE_SEP_STRING); } else if (inputDir) { uprv_strcpy(theCurrentFileName, inputDir); uprv_strcat(theCurrentFileName, U_FILE_SEP_STRING); } else { *theCurrentFileName = 0; } uprv_strcat(theCurrentFileName, poolResName); poolFile = T_FileStream_open(theCurrentFileName, "rb"); if (poolFile == NULL) { fprintf(stderr, "unable to open pool bundle file %s\n", theCurrentFileName); return 1; } poolFileSize = T_FileStream_size(poolFile); if (poolFileSize < 32) { fprintf(stderr, "the pool bundle file %s is too small\n", theCurrentFileName); return 1; } poolBundle.fBytes = (uint8_t *)uprv_malloc((poolFileSize + 15) & ~15); if (poolFileSize > 0 && poolBundle.fBytes == NULL) { fprintf(stderr, "unable to allocate memory for the pool bundle file %s\n", theCurrentFileName); return U_MEMORY_ALLOCATION_ERROR; } else { UDataSwapper *ds; const DataHeader *header; int32_t bytesRead = T_FileStream_read(poolFile, poolBundle.fBytes, poolFileSize); int32_t keysBottom; if (bytesRead != poolFileSize) { fprintf(stderr, "unable to read the pool bundle file %s\n", theCurrentFileName); return 1; } /* * Swap the pool bundle so that a single checked-in file can be used. * The swapper functions also test that the data looks like * a well-formed .res file. */ ds = udata_openSwapperForInputData(poolBundle.fBytes, bytesRead, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &status); if (U_FAILURE(status)) { fprintf(stderr, "udata_openSwapperForInputData(pool bundle %s) failed: %s\n", theCurrentFileName, u_errorName(status)); return status; } ures_swap(ds, poolBundle.fBytes, bytesRead, poolBundle.fBytes, &status); udata_closeSwapper(ds); if (U_FAILURE(status)) { fprintf(stderr, "ures_swap(pool bundle %s) failed: %s\n", theCurrentFileName, u_errorName(status)); return status; } header = (const DataHeader *)poolBundle.fBytes; if (header->info.formatVersion[0]!=2) { fprintf(stderr, "invalid format of pool bundle file %s\n", theCurrentFileName); return U_INVALID_FORMAT_ERROR; } poolBundle.fKeys = (const char *)header + header->dataHeader.headerSize; poolBundle.fIndexes = (const int32_t *)poolBundle.fKeys + 1; indexLength = poolBundle.fIndexes[URES_INDEX_LENGTH] & 0xff; if (indexLength <= URES_INDEX_POOL_CHECKSUM) { fprintf(stderr, "insufficient indexes[] in pool bundle file %s\n", theCurrentFileName); return U_INVALID_FORMAT_ERROR; } keysBottom = (1 + indexLength) * 4; poolBundle.fKeys += keysBottom; poolBundle.fKeysLength = (poolBundle.fIndexes[URES_INDEX_KEYS_TOP] * 4) - keysBottom; poolBundle.fChecksum = poolBundle.fIndexes[URES_INDEX_POOL_CHECKSUM]; } for (i = 0; i < poolBundle.fKeysLength; ++i) { if (poolBundle.fKeys[i] == 0) { ++poolBundle.fKeysCount; } } T_FileStream_close(poolFile); setUsePoolBundle(TRUE); } if(options[INCLUDE_UNIHAN_COLL].doesOccur) { gIncludeUnihanColl = TRUE; } if((argc-1)!=1) { printf("genrb number of files: %d\n", argc - 1); } /* generate the binary files */ for(i = 1; i < argc; ++i) { status = U_ZERO_ERROR; arg = getLongPathname(argv[i]); if (inputDir) { uprv_strcpy(theCurrentFileName, inputDir); uprv_strcat(theCurrentFileName, U_FILE_SEP_STRING); } else { *theCurrentFileName = 0; } uprv_strcat(theCurrentFileName, arg); if (isVerbose()) { printf("Processing file \"%s\"\n", theCurrentFileName); } processFile(arg, encoding, inputDir, outputDir, gPackageName, &status); } uprv_free(poolBundle.fBytes); if(options[WRITE_POOL_BUNDLE].doesOccur) { char outputFileName[256]; bundle_write(newPoolBundle, outputDir, NULL, outputFileName, sizeof(outputFileName), &status); bundle_close(newPoolBundle, &status); if(U_FAILURE(status)) { fprintf(stderr, "unable to write the pool bundle: %s\n", u_errorName(status)); } } /* Dont return warnings as a failure */ if (U_SUCCESS(status)) { return 0; } return status; }
int main(int argc, char* argv[]) { UErrorCode status = U_ZERO_ERROR; const char *arg = NULL; const char *outputDir = NULL; /* NULL = no output directory, use current */ const char *inputDir = NULL; const char *encoding = ""; int i; UBool illegalArg = FALSE; U_MAIN_INIT_ARGS(argc, argv); options[JAVA_PACKAGE].value = "com.ibm.icu.impl.data"; options[BUNDLE_NAME].value = "LocaleElements"; argc = u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options); /* error handling, printing usage message */ if(argc<0) { fprintf(stderr, "%s: error in command line argument \"%s\"\n", argv[0], argv[-argc]); illegalArg = TRUE; } else if(argc<2) { illegalArg = TRUE; } if(options[WRITE_POOL_BUNDLE].doesOccur && options[USE_POOL_BUNDLE].doesOccur) { fprintf(stderr, "%s: cannot combine --writePoolBundle and --usePoolBundle\n", argv[0]); illegalArg = TRUE; } if(options[FORMAT_VERSION].doesOccur) { const char *s = options[FORMAT_VERSION].value; if(uprv_strlen(s) != 1 || (s[0] < '1' && '3' < s[0])) { fprintf(stderr, "%s: unsupported --formatVersion %s\n", argv[0], s); illegalArg = TRUE; } else if(s[0] == '1' && (options[WRITE_POOL_BUNDLE].doesOccur || options[USE_POOL_BUNDLE].doesOccur) ) { fprintf(stderr, "%s: cannot combine --formatVersion 1 with --writePoolBundle or --usePoolBundle\n", argv[0]); illegalArg = TRUE; } else { setFormatVersion(s[0] - '0'); } } if((options[JAVA_PACKAGE].doesOccur || options[BUNDLE_NAME].doesOccur) && !options[WRITE_JAVA].doesOccur) { fprintf(stderr, "%s error: command line argument --java-package or --bundle-name " "without --write-java\n", argv[0]); illegalArg = TRUE; } if(options[VERSION].doesOccur) { fprintf(stderr, "%s version %s (ICU version %s).\n" "%s\n", argv[0], GENRB_VERSION, U_ICU_VERSION, U_COPYRIGHT_STRING); if(!illegalArg) { return U_ZERO_ERROR; } } if(illegalArg || options[HELP1].doesOccur || options[HELP2].doesOccur) { /* * Broken into chunks because the C89 standard says the minimum * required supported string length is 509 bytes. */ fprintf(stderr, "Usage: %s [OPTIONS] [FILES]\n" "\tReads the list of resource bundle source files and creates\n" "\tbinary version of resource bundles (.res files)\n", argv[0]); fprintf(stderr, "Options:\n" "\t-h or -? or --help this usage text\n" "\t-q or --quiet do not display warnings\n" "\t-v or --verbose print extra information when processing files\n" "\t-V or --version prints out version number and exits\n" "\t-c or --copyright include copyright notice\n"); fprintf(stderr, "\t-e or --encoding encoding of source files\n" "\t-d of --destdir destination directory, followed by the path, defaults to %s\n" "\t-s or --sourcedir source directory for files followed by path, defaults to %s\n" "\t-i or --icudatadir directory for locating any needed intermediate data files,\n" "\t followed by path, defaults to %s\n", u_getDataDirectory(), u_getDataDirectory(), u_getDataDirectory()); fprintf(stderr, "\t-j or --write-java write a Java ListResourceBundle for ICU4J, followed by optional encoding\n" "\t defaults to ASCII and \\uXXXX format.\n" "\t --java-package For --write-java: package name for writing the ListResourceBundle,\n" "\t defaults to com.ibm.icu.impl.data\n"); fprintf(stderr, "\t-b or --bundle-name For --write-java: root resource bundle name for writing the ListResourceBundle,\n" "\t defaults to LocaleElements\n" "\t-x or --write-xliff write an XLIFF file for the resource bundle. Followed by\n" "\t an optional output file name.\n" "\t-k or --strict use pedantic parsing of syntax\n" /*added by Jing*/ "\t-l or --language for XLIFF: language code compliant with BCP 47.\n"); fprintf(stderr, "\t-C or --noBinaryCollation do not generate binary collation image;\n" "\t makes .res file smaller but collator instantiation much slower;\n" "\t maintains ability to get tailoring rules\n" "\t-R or --omitCollationRules do not include collation (tailoring) rules;\n" "\t makes .res file smaller and maintains collator instantiation speed\n" "\t but tailoring rules will not be available (they are rarely used)\n"); fprintf(stderr, "\t --formatVersion write a .res file compatible with the requested formatVersion (single digit);\n" "\t for example, --formatVersion 1\n"); fprintf(stderr, "\t --writePoolBundle write a pool.res file with all of the keys of all input bundles\n" "\t --usePoolBundle [path-to-pool.res] point to keys from the pool.res keys pool bundle if they are available there;\n" "\t makes .res files smaller but dependent on the pool bundle\n" "\t (--writePoolBundle and --usePoolBundle cannot be combined)\n"); return illegalArg ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR; } if(options[VERBOSE].doesOccur) { setVerbose(TRUE); } if(options[QUIET].doesOccur) { setShowWarning(FALSE); } if(options[STRICT].doesOccur) { setStrict(TRUE); } if(options[COPYRIGHT].doesOccur){ setIncludeCopyright(TRUE); } if(options[SOURCEDIR].doesOccur) { inputDir = options[SOURCEDIR].value; } if(options[DESTDIR].doesOccur) { outputDir = options[DESTDIR].value; } if(options[ENCODING].doesOccur) { encoding = options[ENCODING].value; } if(options[ICUDATADIR].doesOccur) { u_setDataDirectory(options[ICUDATADIR].value); } /* Initialize ICU */ u_init(&status); if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) { /* Note: u_init() will try to open ICU property data. * failures here are expected when building ICU from scratch. * ignore them. */ fprintf(stderr, "%s: can not initialize ICU. status = %s\n", argv[0], u_errorName(status)); exit(1); } status = U_ZERO_ERROR; if(options[WRITE_JAVA].doesOccur) { write_java = TRUE; outputEnc = options[WRITE_JAVA].value; } if(options[WRITE_XLIFF].doesOccur) { write_xliff = TRUE; if(options[WRITE_XLIFF].value != NULL){ xliffOutputFileName = options[WRITE_XLIFF].value; } } initParser(); /*added by Jing*/ if(options[LANGUAGE].doesOccur) { language = options[LANGUAGE].value; } LocalPointer<SRBRoot> newPoolBundle; if(options[WRITE_POOL_BUNDLE].doesOccur) { newPoolBundle.adoptInsteadAndCheckErrorCode(new SRBRoot(NULL, TRUE, status), status); if(U_FAILURE(status)) { fprintf(stderr, "unable to create an empty bundle for the pool keys: %s\n", u_errorName(status)); return status; } else { const char *poolResName = "pool.res"; char *nameWithoutSuffix = static_cast<char *>(uprv_malloc(uprv_strlen(poolResName) + 1)); if (nameWithoutSuffix == NULL) { fprintf(stderr, "out of memory error\n"); return U_MEMORY_ALLOCATION_ERROR; } uprv_strcpy(nameWithoutSuffix, poolResName); *uprv_strrchr(nameWithoutSuffix, '.') = 0; newPoolBundle->fLocale = nameWithoutSuffix; } } if(options[USE_POOL_BUNDLE].doesOccur) { const char *poolResName = "pool.res"; FileStream *poolFile; int32_t poolFileSize; int32_t indexLength; /* * TODO: Consolidate inputDir/filename handling from main() and processFile() * into a common function, and use it here as well. * Try to create toolutil functions for dealing with dir/filenames and * loading ICU data files without udata_open(). * Share code with icupkg? * Also, make_res_filename() seems to be unused. Review and remove. */ CharString poolFileName; if (options[USE_POOL_BUNDLE].value!=NULL) { poolFileName.append(options[USE_POOL_BUNDLE].value, status); } else if (inputDir) { poolFileName.append(inputDir, status); } poolFileName.appendPathPart(poolResName, status); if (U_FAILURE(status)) { return status; } poolFile = T_FileStream_open(poolFileName.data(), "rb"); if (poolFile == NULL) { fprintf(stderr, "unable to open pool bundle file %s\n", poolFileName.data()); return 1; } poolFileSize = T_FileStream_size(poolFile); if (poolFileSize < 32) { fprintf(stderr, "the pool bundle file %s is too small\n", poolFileName.data()); return 1; } poolBundle.fBytes = new uint8_t[(poolFileSize + 15) & ~15]; if (poolFileSize > 0 && poolBundle.fBytes == NULL) { fprintf(stderr, "unable to allocate memory for the pool bundle file %s\n", poolFileName.data()); return U_MEMORY_ALLOCATION_ERROR; } UDataSwapper *ds; const DataHeader *header; int32_t bytesRead = T_FileStream_read(poolFile, poolBundle.fBytes, poolFileSize); if (bytesRead != poolFileSize) { fprintf(stderr, "unable to read the pool bundle file %s\n", poolFileName.data()); return 1; } /* * Swap the pool bundle so that a single checked-in file can be used. * The swapper functions also test that the data looks like * a well-formed .res file. */ ds = udata_openSwapperForInputData(poolBundle.fBytes, bytesRead, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &status); if (U_FAILURE(status)) { fprintf(stderr, "udata_openSwapperForInputData(pool bundle %s) failed: %s\n", poolFileName.data(), u_errorName(status)); return status; } ures_swap(ds, poolBundle.fBytes, bytesRead, poolBundle.fBytes, &status); udata_closeSwapper(ds); if (U_FAILURE(status)) { fprintf(stderr, "ures_swap(pool bundle %s) failed: %s\n", poolFileName.data(), u_errorName(status)); return status; } header = (const DataHeader *)poolBundle.fBytes; if (header->info.formatVersion[0] < 2) { fprintf(stderr, "invalid format of pool bundle file %s\n", poolFileName.data()); return U_INVALID_FORMAT_ERROR; } const int32_t *pRoot = (const int32_t *)( (const char *)header + header->dataHeader.headerSize); poolBundle.fIndexes = pRoot + 1; indexLength = poolBundle.fIndexes[URES_INDEX_LENGTH] & 0xff; if (indexLength <= URES_INDEX_POOL_CHECKSUM) { fprintf(stderr, "insufficient indexes[] in pool bundle file %s\n", poolFileName.data()); return U_INVALID_FORMAT_ERROR; } int32_t keysBottom = 1 + indexLength; int32_t keysTop = poolBundle.fIndexes[URES_INDEX_KEYS_TOP]; poolBundle.fKeys = (const char *)(pRoot + keysBottom); poolBundle.fKeysLength = (keysTop - keysBottom) * 4; poolBundle.fChecksum = poolBundle.fIndexes[URES_INDEX_POOL_CHECKSUM]; for (i = 0; i < poolBundle.fKeysLength; ++i) { if (poolBundle.fKeys[i] == 0) { ++poolBundle.fKeysCount; } } // 16BitUnits[] begins with strings-v2. // The strings-v2 may optionally be terminated by what looks like // an explicit string length that exceeds the number of remaining 16-bit units. int32_t stringUnitsLength = (poolBundle.fIndexes[URES_INDEX_16BIT_TOP] - keysTop) * 2; if (stringUnitsLength >= 2 && getFormatVersion() >= 3) { poolBundle.fStrings = new PseudoListResource(NULL, status); if (poolBundle.fStrings == NULL) { fprintf(stderr, "unable to allocate memory for the pool bundle strings %s\n", poolFileName.data()); return U_MEMORY_ALLOCATION_ERROR; } // The PseudoListResource constructor call did not allocate further memory. assert(U_SUCCESS(status)); const UChar *p = (const UChar *)(pRoot + keysTop); int32_t remaining = stringUnitsLength; do { int32_t first = *p; int8_t numCharsForLength; int32_t length; if (!U16_IS_TRAIL(first)) { // NUL-terminated numCharsForLength = 0; for (length = 0; length < remaining && p[length] != 0; ++length) {} } else if (first < 0xdfef) { numCharsForLength = 1; length = first & 0x3ff; } else if (first < 0xdfff && remaining >= 2) { numCharsForLength = 2; length = ((first - 0xdfef) << 16) | p[1]; } else if (first == 0xdfff && remaining >= 3) { numCharsForLength = 3; length = ((int32_t)p[1] << 16) | p[2]; } else { break; // overrun } // Check for overrun before changing remaining, // so that it is always accurate after the loop body. if ((numCharsForLength + length) >= remaining || p[numCharsForLength + length] != 0) { break; // overrun or explicitly terminated } int32_t poolStringIndex = stringUnitsLength - remaining; // Maximum pool string index when suffix-sharing the last character. int32_t maxStringIndex = poolStringIndex + numCharsForLength + length - 1; if (maxStringIndex >= RES_MAX_OFFSET) { // pool string index overrun break; } p += numCharsForLength; remaining -= numCharsForLength; if (length != 0) { StringResource *sr = new StringResource(poolStringIndex, numCharsForLength, p, length, status); if (sr == NULL) { fprintf(stderr, "unable to allocate memory for a pool bundle string %s\n", poolFileName.data()); return U_MEMORY_ALLOCATION_ERROR; } poolBundle.fStrings->add(sr); poolBundle.fStringIndexLimit = maxStringIndex + 1; // The StringResource constructor did not allocate further memory. assert(U_SUCCESS(status)); } p += length + 1; remaining -= length + 1; } while (remaining > 0); if (poolBundle.fStrings->fCount == 0) { delete poolBundle.fStrings; poolBundle.fStrings = NULL; } } T_FileStream_close(poolFile); setUsePoolBundle(TRUE); if (isVerbose() && poolBundle.fStrings != NULL) { printf("number of shared strings: %d\n", (int)poolBundle.fStrings->fCount); int32_t length = poolBundle.fStringIndexLimit + 1; // incl. last NUL printf("16-bit units for strings: %6d = %6d bytes\n", (int)length, (int)length * 2); } } if(!options[FORMAT_VERSION].doesOccur && getFormatVersion() == 3 && poolBundle.fStrings == NULL && !options[WRITE_POOL_BUNDLE].doesOccur) { // If we just default to formatVersion 3 // but there are no pool bundle strings to share // and we do not write a pool bundle, // then write formatVersion 2 which is just as good. setFormatVersion(2); } if(options[INCLUDE_UNIHAN_COLL].doesOccur) { puts("genrb option --includeUnihanColl ignored: \n" "CLDR 26/ICU 54 unihan data is small, except\n" "the ucadata-unihan.icu version of the collation root data\n" "is about 300kB larger than the ucadata-implicithan.icu version."); } if((argc-1)!=1) { printf("genrb number of files: %d\n", argc - 1); } /* generate the binary files */ for(i = 1; i < argc; ++i) { status = U_ZERO_ERROR; arg = getLongPathname(argv[i]); CharString theCurrentFileName; if (inputDir) { theCurrentFileName.append(inputDir, status); } theCurrentFileName.appendPathPart(arg, status); if (U_FAILURE(status)) { break; } gCurrentFileName = theCurrentFileName.data(); if (isVerbose()) { printf("Processing file \"%s\"\n", theCurrentFileName.data()); } processFile(arg, encoding, inputDir, outputDir, NULL, newPoolBundle.getAlias(), options[NO_BINARY_COLLATION].doesOccur, status); } poolBundle.close(); if(U_SUCCESS(status) && options[WRITE_POOL_BUNDLE].doesOccur) { char outputFileName[256]; newPoolBundle->write(outputDir, NULL, outputFileName, sizeof(outputFileName), status); if(U_FAILURE(status)) { fprintf(stderr, "unable to write the pool bundle: %s\n", u_errorName(status)); } } u_cleanup(); /* Dont return warnings as a failure */ if (U_SUCCESS(status)) { return 0; } return status; }
U_CDECL_END U_CFUNC int32_t U_CALLCONV udata_swapPackage(const UDataSwapper *ds, const void *inData, int32_t length, void *outData, UErrorCode *pErrorCode) { const UDataInfo *pInfo; int32_t headerSize; const uint8_t *inBytes; uint8_t *outBytes; uint32_t itemCount, offset, i; int32_t itemLength; const UDataOffsetTOCEntry *inEntries; UDataOffsetTOCEntry *outEntries; ToCEntry *table; char inPkgName[32], outPkgName[32]; int32_t inPkgNameLength, outPkgNameLength; /* udata_swapDataHeader checks the arguments */ headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode); if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { return 0; } /* check data format and format version */ pInfo=(const UDataInfo *)((const char *)inData+4); if(!( pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */ pInfo->dataFormat[1]==0x6d && pInfo->dataFormat[2]==0x6e && pInfo->dataFormat[3]==0x44 && pInfo->formatVersion[0]==1 )) { udata_printError(ds, "udata_swapPackage(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as an ICU .dat package\n", pInfo->dataFormat[0], pInfo->dataFormat[1], pInfo->dataFormat[2], pInfo->dataFormat[3], pInfo->formatVersion[0]); *pErrorCode=U_UNSUPPORTED_ERROR; return 0; } /* * We need to change the ToC name entries so that they have the correct * package name prefix. * Extract the package names from the in/out filenames. */ inPkgNameLength=extractPackageName( ds, inFilename, inPkgName, (int32_t)sizeof(inPkgName), pErrorCode); outPkgNameLength=extractPackageName( ds, outFilename, outPkgName, (int32_t)sizeof(outPkgName), pErrorCode); if(U_FAILURE(*pErrorCode)) { return 0; } /* * It is possible to work with inPkgNameLength!=outPkgNameLength, * but then the length of the data file would change more significantly, * which we are not currently prepared for. */ if(inPkgNameLength!=outPkgNameLength) { udata_printError(ds, "udata_swapPackage(): the package names \"%s\" and \"%s\" must have the same length\n", inPkgName, outPkgName); *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return 0; } inBytes=(const uint8_t *)inData+headerSize; inEntries=(const UDataOffsetTOCEntry *)(inBytes+4); if(length<0) { /* preflighting */ itemCount=ds->readUInt32(*(const uint32_t *)inBytes); if(itemCount==0) { /* no items: count only the item count and return */ return headerSize+4; } /* read the last item's offset and preflight it */ offset=ds->readUInt32(inEntries[itemCount-1].dataOffset); itemLength=udata_swap(ds, inBytes+offset, -1, NULL, pErrorCode); if(U_SUCCESS(*pErrorCode)) { return headerSize+offset+(uint32_t)itemLength; } else { return 0; } } else { /* check that the itemCount fits, then the ToC table, then at least the header of the last item */ length-=headerSize; if(length<4) { /* itemCount does not fit */ offset=0xffffffff; itemCount=0; /* make compilers happy */ } else { itemCount=ds->readUInt32(*(const uint32_t *)inBytes); if(itemCount==0) { offset=4; } else if((uint32_t)length<(4+8*itemCount)) { /* ToC table does not fit */ offset=0xffffffff; } else { /* offset of the last item plus at least 20 bytes for its header */ offset=20+ds->readUInt32(inEntries[itemCount-1].dataOffset); } } if((uint32_t)length<offset) { udata_printError(ds, "udata_swapPackage(): too few bytes (%d after header) for unames.icu\n", length); *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; return 0; } outBytes=(uint8_t *)outData+headerSize; /* swap the item count */ ds->swapArray32(ds, inBytes, 4, outBytes, pErrorCode); if(itemCount==0) { /* no items: just return now */ return headerSize+4; } /* swap the item name strings */ offset=4+8*itemCount; itemLength=(int32_t)(ds->readUInt32(inEntries[0].dataOffset)-offset); udata_swapInvStringBlock(ds, inBytes+offset, itemLength, outBytes+offset, pErrorCode); if(U_FAILURE(*pErrorCode)) { udata_printError(ds, "udata_swapPackage() failed to swap the data item name strings\n"); return 0; } /* keep offset and itemLength in case we allocate and copy the strings below */ /* swap the package names into the output charset */ if(ds->outCharset!=U_CHARSET_FAMILY) { UDataSwapper *ds2; ds2=udata_openSwapper(TRUE, U_CHARSET_FAMILY, TRUE, ds->outCharset, pErrorCode); ds2->swapInvChars(ds2, inPkgName, inPkgNameLength, inPkgName, pErrorCode); ds2->swapInvChars(ds2, outPkgName, outPkgNameLength, outPkgName, pErrorCode); udata_closeSwapper(ds2); if(U_FAILURE(*pErrorCode)) { udata_printError(ds, "udata_swapPackage() failed to swap the input/output package names\n"); } } /* change the prefix of each ToC entry name from the old to the new package name */ { char *entryName; for(i=0; i<itemCount; ++i) { entryName=(char *)inBytes+ds->readUInt32(inEntries[i].nameOffset); if(0==uprv_memcmp(entryName, inPkgName, inPkgNameLength)) { uprv_memcpy(entryName, outPkgName, inPkgNameLength); } else { udata_printError(ds, "udata_swapPackage() failed: ToC item %ld does not have the input package name as a prefix\n", (long)i); *pErrorCode=U_INVALID_FORMAT_ERROR; return 0; } } } /* * Allocate the ToC table and, if necessary, a temporary buffer for * pseudo-in-place swapping. * * We cannot swap in-place because: * * 1. If the swapping of an item fails mid-way, then in-place swapping * has destroyed its data. * Out-of-place swapping allows us to then copy its original data. * * 2. If swapping changes the charset family, then we must resort * not only the ToC table but also the data items themselves. * This requires a permutation and is best done with separate in/out * buffers. * * We swapped the strings above to avoid the malloc below if string swapping fails. */ if(inData==outData) { /* +15: prepare for extra padding of a newly-last item */ table=(ToCEntry *)uprv_malloc(itemCount*sizeof(ToCEntry)+length+15); if(table!=NULL) { outBytes=(uint8_t *)(table+itemCount); /* copy the item count and the swapped strings */ uprv_memcpy(outBytes, inBytes, 4); uprv_memcpy(outBytes+offset, inBytes+offset, itemLength); } } else { table=(ToCEntry *)uprv_malloc(itemCount*sizeof(ToCEntry)); } if(table==NULL) { udata_printError(ds, "udata_swapPackage(): out of memory allocating %d bytes\n", inData==outData ? itemCount*sizeof(ToCEntry)+length+15 : itemCount*sizeof(ToCEntry)); *pErrorCode=U_MEMORY_ALLOCATION_ERROR; return 0; } outEntries=(UDataOffsetTOCEntry *)(outBytes+4); /* read the ToC table */ for(i=0; i<itemCount; ++i) { table[i].nameOffset=ds->readUInt32(inEntries[i].nameOffset); table[i].inOffset=ds->readUInt32(inEntries[i].dataOffset); if(i>0) { table[i-1].length=table[i].inOffset-table[i-1].inOffset; } } table[itemCount-1].length=(uint32_t)length-table[itemCount-1].inOffset; if(ds->inCharset==ds->outCharset) { /* no charset swapping, no resorting: keep item offsets the same */ for(i=0; i<itemCount; ++i) { table[i].outOffset=table[i].inOffset; } } else { /* charset swapping: resort items by their swapped names */ /* * Before the actual sorting, we need to make sure that each item * has a length that is a multiple of 16 bytes so that all items * are 16-aligned. * Only the old last item may be missing up to 15 padding bytes. * Add padding bytes for it. * Since the icuswap main() function has already allocated enough * input buffer space and set the last 15 bytes there to 0xaa, * we only need to increase the total data length and the length * of the last item here. */ if((length&0xf)!=0) { int32_t delta=16-(length&0xf); length+=delta; table[itemCount-1].length+=(uint32_t)delta; } uprv_sortArray(table, (int32_t)itemCount, (int32_t)sizeof(ToCEntry), compareToCEntries, outBytes, FALSE, pErrorCode); /* * Note: Before sorting, the inOffset values were in order. * Now the outOffset values are in order. */ /* assign outOffset values */ offset=table[0].inOffset; for(i=0; i<itemCount; ++i) { table[i].outOffset=offset; offset+=table[i].length; } } /* write the output ToC table */ for(i=0; i<itemCount; ++i) { ds->writeUInt32(&outEntries[i].nameOffset, table[i].nameOffset); ds->writeUInt32(&outEntries[i].dataOffset, table[i].outOffset); } /* swap each data item */ for(i=0; i<itemCount; ++i) { /* first copy the item bytes to make sure that unreachable bytes are copied */ uprv_memcpy(outBytes+table[i].outOffset, inBytes+table[i].inOffset, table[i].length); /* swap the item */ udata_swap(ds, inBytes+table[i].inOffset, (int32_t)table[i].length, outBytes+table[i].outOffset, pErrorCode); if(U_FAILURE(*pErrorCode)) { if(ds->outCharset==U_CHARSET_FAMILY) { udata_printError(ds, "warning: udata_swapPackage() failed to swap item \"%s\"\n" " at inOffset 0x%x length 0x%x - %s\n" " the data item will be copied, not swapped\n\n", (char *)outBytes+table[i].nameOffset, table[i].inOffset, table[i].length, u_errorName(*pErrorCode)); } else { udata_printError(ds, "warning: udata_swapPackage() failed to swap an item\n" " at inOffset 0x%x length 0x%x - %s\n" " the data item will be copied, not swapped\n\n", table[i].inOffset, table[i].length, u_errorName(*pErrorCode)); } /* reset the error code, copy the data item, and continue */ *pErrorCode=U_ZERO_ERROR; uprv_memcpy(outBytes+table[i].outOffset, inBytes+table[i].inOffset, table[i].length); } } if(inData==outData) { /* copy the data from the temporary buffer to the in-place buffer */ uprv_memcpy((uint8_t *)outData+headerSize, outBytes, length); } uprv_free(table); return headerSize+length; } }
extern int main(int argc, char *argv[]) { FILE *in, *out; const char *pname; char *data; int32_t length; UBool ishelp; int rc; UDataSwapper *ds; UErrorCode errorCode; uint8_t outCharset; UBool outIsBigEndian; U_MAIN_INIT_ARGS(argc, argv); /* get the program basename */ pname=strrchr(argv[0], U_FILE_SEP_CHAR); if(pname==NULL) { pname=strrchr(argv[0], '/'); } if(pname!=NULL) { ++pname; } else { pname=argv[0]; } argc=u_parseArgs(argc, argv, LENGTHOF(options), options); ishelp=options[OPT_HELP_H].doesOccur || options[OPT_HELP_QUESTION_MARK].doesOccur; if(ishelp || argc!=3) { return printUsage(pname, ishelp); } /* parse the output type option */ data=(char *)options[OPT_OUT_TYPE].value; if(data[0]==0 || data[1]!=0) { /* the type must be exactly one letter */ return printUsage(pname, FALSE); } switch(data[0]) { case 'l': outIsBigEndian=FALSE; outCharset=U_ASCII_FAMILY; break; case 'b': outIsBigEndian=TRUE; outCharset=U_ASCII_FAMILY; break; case 'e': outIsBigEndian=TRUE; outCharset=U_EBCDIC_FAMILY; break; default: return printUsage(pname, FALSE); } in=out=NULL; data=NULL; /* udata_swapPackage() needs the filenames */ inFilename=argv[1]; outFilename=argv[2]; /* open the input file, get its length, allocate memory for it, read the file */ in=fopen(argv[1], "rb"); if(in==NULL) { fprintf(stderr, "%s: unable to open input file \"%s\"\n", pname, argv[1]); rc=2; goto done; } length=fileSize(in); if(length<=0) { fprintf(stderr, "%s: empty input file \"%s\"\n", pname, argv[1]); rc=2; goto done; } /* * +15: udata_swapPackage() may need to add a few padding bytes to the * last item if charset swapping is done, * because the last item may be resorted into the middle and then needs * additional padding bytes */ data=(char *)malloc(length+15); if(data==NULL) { fprintf(stderr, "%s: error allocating memory for \"%s\"\n", pname, argv[1]); rc=2; goto done; } /* set the last 15 bytes to the usual padding byte, see udata_swapPackage() */ uprv_memset(data+length-15, 0xaa, 15); if(length!=(int32_t)fread(data, 1, length, in)) { fprintf(stderr, "%s: error reading \"%s\"\n", pname, argv[1]); rc=3; goto done; } fclose(in); in=NULL; /* swap the data in-place */ errorCode=U_ZERO_ERROR; ds=udata_openSwapperForInputData(data, length, outIsBigEndian, outCharset, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "%s: udata_openSwapperForInputData(\"%s\") failed - %s\n", pname, argv[1], u_errorName(errorCode)); rc=4; goto done; } ds->printError=printError; ds->printErrorContext=stderr; length=udata_swap(ds, data, length, data, &errorCode); udata_closeSwapper(ds); if(U_FAILURE(errorCode)) { fprintf(stderr, "%s: udata_swap(\"%s\") failed - %s\n", pname, argv[1], u_errorName(errorCode)); rc=4; goto done; } out=fopen(argv[2], "wb"); if(out==NULL) { fprintf(stderr, "%s: unable to open output file \"%s\"\n", pname, argv[2]); rc=5; goto done; } if(length!=(int32_t)fwrite(data, 1, length, out)) { fprintf(stderr, "%s: error writing \"%s\"\n", pname, argv[2]); rc=6; goto done; } fclose(out); out=NULL; /* all done */ rc=0; done: if(in!=NULL) { fclose(in); } if(out!=NULL) { fclose(out); } if(data!=NULL) { free(data); } return rc; }
extern int main(int argc, char *argv[]) { FILE *in, *out; const char *pname; char *data; int32_t length; UBool ishelp; int rc; UDataSwapper *ds; const UDataInfo *pInfo; UErrorCode errorCode; uint8_t outCharset; UBool outIsBigEndian; U_MAIN_INIT_ARGS(argc, argv); fprintf(stderr, "Warning: icuswap is an obsolete tool and it will be removed in the next ICU release.\nPlease use the icupkg tool instead.\n"); /* get the program basename */ pname=strrchr(argv[0], U_FILE_SEP_CHAR); if(pname==NULL) { pname=strrchr(argv[0], '/'); } if(pname!=NULL) { ++pname; } else { pname=argv[0]; } argc=u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options); ishelp=options[OPT_HELP_H].doesOccur || options[OPT_HELP_QUESTION_MARK].doesOccur; if(ishelp || argc!=3) { return printUsage(pname, ishelp); } /* parse the output type option */ data=(char *)options[OPT_OUT_TYPE].value; if(data[0]==0 || data[1]!=0) { /* the type must be exactly one letter */ return printUsage(pname, FALSE); } switch(data[0]) { case 'l': outIsBigEndian=FALSE; outCharset=U_ASCII_FAMILY; break; case 'b': outIsBigEndian=TRUE; outCharset=U_ASCII_FAMILY; break; case 'e': outIsBigEndian=TRUE; outCharset=U_EBCDIC_FAMILY; break; default: return printUsage(pname, FALSE); } in=out=NULL; data=NULL; /* open the input file, get its length, allocate memory for it, read the file */ in=fopen(argv[1], "rb"); if(in==NULL) { fprintf(stderr, "%s: unable to open input file \"%s\"\n", pname, argv[1]); rc=2; goto done; } length=fileSize(in); if(length<DEFAULT_PADDING_LENGTH) { fprintf(stderr, "%s: empty input file \"%s\"\n", pname, argv[1]); rc=2; goto done; } /* * +15: udata_swapPackage() may need to add a few padding bytes to the * last item if charset swapping is done, * because the last item may be resorted into the middle and then needs * additional padding bytes */ data=(char *)malloc(length+DEFAULT_PADDING_LENGTH); if(data==NULL) { fprintf(stderr, "%s: error allocating memory for \"%s\"\n", pname, argv[1]); rc=2; goto done; } /* set the last 15 bytes to the usual padding byte, see udata_swapPackage() */ uprv_memset(data+length-DEFAULT_PADDING_LENGTH, 0xaa, DEFAULT_PADDING_LENGTH); if(length!=(int32_t)fread(data, 1, length, in)) { fprintf(stderr, "%s: error reading \"%s\"\n", pname, argv[1]); rc=3; goto done; } fclose(in); in=NULL; /* swap the data in-place */ errorCode=U_ZERO_ERROR; ds=udata_openSwapperForInputData(data, length, outIsBigEndian, outCharset, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "%s: udata_openSwapperForInputData(\"%s\") failed - %s\n", pname, argv[1], u_errorName(errorCode)); rc=4; goto done; } ds->printError=printError; ds->printErrorContext=stderr; /* speculative cast, protected by the following length check */ pInfo=(const UDataInfo *)((const char *)data+4); if( length>=20 && pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */ pInfo->dataFormat[1]==0x6d && pInfo->dataFormat[2]==0x6e && pInfo->dataFormat[3]==0x44 ) { /* * swap the .dat package * udata_swapPackage() needs to rename ToC name entries from the old package * name to the new one. * We pass it the filenames, and udata_swapPackage() will extract the * package names. */ length=udata_swapPackage(argv[1], argv[2], ds, data, length, data, &errorCode); udata_closeSwapper(ds); if(U_FAILURE(errorCode)) { fprintf(stderr, "%s: udata_swapPackage(\"%s\") failed - %s\n", pname, argv[1], u_errorName(errorCode)); rc=4; goto done; } } else { /* swap the data, which is not a .dat package */ length=udata_swap(ds, data, length, data, &errorCode); udata_closeSwapper(ds); if(U_FAILURE(errorCode)) { fprintf(stderr, "%s: udata_swap(\"%s\") failed - %s\n", pname, argv[1], u_errorName(errorCode)); rc=4; goto done; } } out=fopen(argv[2], "wb"); if(out==NULL) { fprintf(stderr, "%s: unable to open output file \"%s\"\n", pname, argv[2]); rc=5; goto done; } if(length!=(int32_t)fwrite(data, 1, length, out)) { fprintf(stderr, "%s: error writing \"%s\"\n", pname, argv[2]); rc=6; goto done; } fclose(out); out=NULL; /* all done */ rc=0; done: if(in!=NULL) { fclose(in); } if(out!=NULL) { fclose(out); } if(data!=NULL) { free(data); } return rc; }
static void TestSwapCase(UDataMemory *pData, const char *name, UDataSwapFn *swapFn, uint8_t *buffer, uint8_t *buffer2) { UDataSwapper *ds; const void *inData, *inHeader; int32_t length, dataLength, length2, headerLength; UErrorCode errorCode; UBool inEndian, oppositeEndian; uint8_t inCharset, oppositeCharset; inData=udata_getMemory(pData); /* * get the data length if possible, to verify that swapping and preflighting * handles the entire data */ dataLength=udata_getLength(pData); /* * get the header and its length * all of the swap implementation functions require the header to be included */ inHeader=udata_getRawMemory(pData); headerLength=(int32_t)((const char *)inData-(const char *)inHeader); /* first swap to opposite endianness but same charset family */ errorCode=U_ZERO_ERROR; ds=udata_openSwapperForInputData(inHeader, headerLength, !U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); if(U_FAILURE(errorCode)) { log_err("udata_openSwapperForInputData(%s->!isBig+same charset) failed - %s\n", name, u_errorName(errorCode)); return; } inEndian=ds->inIsBigEndian; inCharset=ds->inCharset; oppositeEndian=!inEndian; oppositeCharset= inCharset==U_ASCII_FAMILY ? U_EBCDIC_FAMILY : U_ASCII_FAMILY; /* make this test work with data files that are built for a different platform */ if(inEndian!=U_IS_BIG_ENDIAN || inCharset!=U_CHARSET_FAMILY) { udata_closeSwapper(ds); ds=udata_openSwapper(inEndian, inCharset, oppositeEndian, inCharset, &errorCode); if(U_FAILURE(errorCode)) { log_err("udata_openSwapper(%s->!isBig+same charset) failed - %s\n", name, u_errorName(errorCode)); return; } } ds->printError=printError; /* preflight the length */ length=swapFn(ds, inHeader, -1, NULL, &errorCode); if(U_FAILURE(errorCode)) { log_err("swapFn(preflight %s->!isBig+same charset) failed - %s\n", name, u_errorName(errorCode)); udata_closeSwapper(ds); return; } /* compare the preflighted length against the data length */ if(dataLength>=0 && (length+15)<(headerLength+dataLength)) { log_err("swapFn(preflight %s->!isBig+same charset) length too small: %d < data length %d\n", name, length, (headerLength+dataLength)); udata_closeSwapper(ds); return; } /* swap, not in-place */ length2=swapFn(ds, inHeader, length, buffer, &errorCode); udata_closeSwapper(ds); if(U_FAILURE(errorCode)) { log_err("swapFn(%s->!isBig+same charset) failed - %s\n", name, u_errorName(errorCode)); return; } /* compare the swap length against the preflighted length */ if(length2!=length) { log_err("swapFn(%s->!isBig+same charset) length differs from preflighting: %d != preflighted %d\n", name, length2, length); return; } /* next swap to opposite charset family */ ds=udata_openSwapper(oppositeEndian, inCharset, oppositeEndian, oppositeCharset, &errorCode); if(U_FAILURE(errorCode)) { log_err("udata_openSwapper(%s->!isBig+other charset) failed - %s\n", name, u_errorName(errorCode)); return; } ds->printError=printError; /* swap in-place */ length2=swapFn(ds, buffer, length, buffer, &errorCode); udata_closeSwapper(ds); if(U_FAILURE(errorCode)) { log_err("swapFn(%s->!isBig+other charset) failed - %s\n", name, u_errorName(errorCode)); return; } /* compare the swap length against the original length */ if(length2!=length) { log_err("swapFn(%s->!isBig+other charset) length differs from original: %d != original %d\n", name, length2, length); return; } /* finally swap to original platform values */ ds=udata_openSwapper(oppositeEndian, oppositeCharset, inEndian, inCharset, &errorCode); if(U_FAILURE(errorCode)) { log_err("udata_openSwapper(%s->back to original) failed - %s\n", name, u_errorName(errorCode)); return; } ds->printError=printError; /* swap, not in-place */ length2=swapFn(ds, buffer, length, buffer2, &errorCode); udata_closeSwapper(ds); if(U_FAILURE(errorCode)) { log_err("swapFn(%s->back to original) failed - %s\n", name, u_errorName(errorCode)); return; } /* compare the swap length against the original length */ if(length2!=length) { log_err("swapFn(%s->back to original) length differs from original: %d != original %d\n", name, length2, length); return; } /* compare the final contents with the original */ if(0!=uprv_memcmp(inHeader, buffer2, length)) { const uint8_t *original; uint8_t diff[8]; int32_t i, j; log_err("swapFn(%s->back to original) contents differs from original\n", name); /* find the first difference */ original=(const uint8_t *)inHeader; for(i=0; i<length && original[i]==buffer2[i]; ++i) {} /* find the next byte that is the same */ for(j=i+1; j<length && original[j]!=buffer2[j]; ++j) {} log_info(" difference at index %d=0x%x, until index %d=0x%x\n", i, i, j, j); /* round down to the last 4-boundary for better result output */ i&=~3; log_info("showing bytes from index %d=0x%x (length %d=0x%x):\n", i, i, length, length); /* print 8 bytes but limit to the buffer contents */ length2=i+sizeof(diff); if(length2>length) { length2=length; } /* print the original bytes */ uprv_memset(diff, 0, sizeof(diff)); for(j=i; j<length2; ++j) { diff[j-i]=original[j]; } log_info(" original: %02x %02x %02x %02x %02x %02x %02x %02x\n", diff[0], diff[1], diff[2], diff[3], diff[4], diff[5], diff[6], diff[7]); /* print the swapped bytes */ uprv_memset(diff, 0, sizeof(diff)); for(j=i; j<length2; ++j) { diff[j-i]=buffer2[j]; } log_info(" swapped: %02x %02x %02x %02x %02x %02x %02x %02x\n", diff[0], diff[1], diff[2], diff[3], diff[4], diff[5], diff[6], diff[7]); } }
void Package::writePackage(const char *filename, char outType, const char *comment) { char prefix[MAX_PKG_NAME_LENGTH+4]; UDataOffsetTOCEntry entry; UDataSwapper *dsLocalToOut, *ds[TYPE_COUNT]; FILE *file; Item *pItem; char *name; UErrorCode errorCode; int32_t i, length, prefixLength, maxItemLength, basenameOffset, offset, outInt32; uint8_t outCharset; UBool outIsBigEndian; extractPackageName(filename, prefix, MAX_PKG_NAME_LENGTH); // if there is an explicit comment, then use it, else use what's in the current header if(comment!=NULL) { /* get the header size minus the current comment */ DataHeader *pHeader; int32_t length; pHeader=(DataHeader *)header; headerLength=4+pHeader->info.size; length=(int32_t)strlen(comment); if((int32_t)(headerLength+length)>=(int32_t)sizeof(header)) { fprintf(stderr, "icupkg: comment too long\n"); exit(U_BUFFER_OVERFLOW_ERROR); } memcpy(header+headerLength, comment, length+1); headerLength+=length; if(headerLength&0xf) { /* NUL-pad the header to a multiple of 16 */ length=(headerLength+0xf)&~0xf; memset(header+headerLength, 0, length-headerLength); headerLength=length; } pHeader->dataHeader.headerSize=(uint16_t)headerLength; } makeTypeProps(outType, outCharset, outIsBigEndian); // open (TYPE_COUNT-2) swappers // one is a no-op for local type==outType // one type (TYPE_LE) is bogus errorCode=U_ZERO_ERROR; i=makeTypeEnum(outType); ds[TYPE_B]= i==TYPE_B ? NULL : udata_openSwapper(TRUE, U_ASCII_FAMILY, outIsBigEndian, outCharset, &errorCode); ds[TYPE_L]= i==TYPE_L ? NULL : udata_openSwapper(FALSE, U_ASCII_FAMILY, outIsBigEndian, outCharset, &errorCode); ds[TYPE_LE]=NULL; ds[TYPE_E]= i==TYPE_E ? NULL : udata_openSwapper(TRUE, U_EBCDIC_FAMILY, outIsBigEndian, outCharset, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: udata_openSwapper() failed - %s\n", u_errorName(errorCode)); exit(errorCode); } for(i=0; i<TYPE_COUNT; ++i) { if(ds[i]!=NULL) { ds[i]->printError=printPackageError; ds[i]->printErrorContext=stderr; } } dsLocalToOut=ds[makeTypeEnum(U_CHARSET_FAMILY, U_IS_BIG_ENDIAN)]; // create the file and write its contents file=fopen(filename, "wb"); if(file==NULL) { fprintf(stderr, "icupkg: unable to create file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR); } // swap and write the header if(dsLocalToOut!=NULL) { udata_swapDataHeader(dsLocalToOut, header, headerLength, header, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: udata_swapDataHeader(local to out) failed - %s\n", u_errorName(errorCode)); exit(errorCode); } } length=(int32_t)fwrite(header, 1, headerLength, file); if(length!=headerLength) { fprintf(stderr, "icupkg: unable to write complete header to file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR); } // prepare and swap the package name with a tree separator // for prepending to item names strcat(prefix, U_TREE_ENTRY_SEP_STRING); prefixLength=(int32_t)strlen(prefix); if(dsLocalToOut!=NULL) { dsLocalToOut->swapInvChars(dsLocalToOut, prefix, prefixLength, prefix, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: swapInvChars(output package name) failed - %s\n", u_errorName(errorCode)); exit(errorCode); } // swap and sort the item names (sorting needs to be done in the output charset) dsLocalToOut->swapInvChars(dsLocalToOut, inStrings, inStringTop, inStrings, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: swapInvChars(item names) failed - %s\n", u_errorName(errorCode)); exit(errorCode); } sortItems(); } // create the output item names in sorted order, with the package name prepended to each for(i=0; i<itemCount; ++i) { length=(int32_t)strlen(items[i].name); name=allocString(FALSE, length+prefixLength); memcpy(name, prefix, prefixLength); memcpy(name+prefixLength, items[i].name, length+1); items[i].name=name; } // calculate offsets for item names and items, pad to 16-align items // align only the first item; each item's length is a multiple of 16 basenameOffset=4+8*itemCount; offset=basenameOffset+outStringTop; if((length=(offset&15))!=0) { length=16-length; memset(allocString(FALSE, length-1), 0xaa, length); offset+=length; } // write the table of contents // first the itemCount outInt32=itemCount; if(dsLocalToOut!=NULL) { dsLocalToOut->swapArray32(dsLocalToOut, &outInt32, 4, &outInt32, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: swapArray32(item count) failed - %s\n", u_errorName(errorCode)); exit(errorCode); } } length=(int32_t)fwrite(&outInt32, 1, 4, file); if(length!=4) { fprintf(stderr, "icupkg: unable to write complete item count to file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR); } // then write the item entries (and collect the maxItemLength) maxItemLength=0; for(i=0; i<itemCount; ++i) { entry.nameOffset=(uint32_t)(basenameOffset+(items[i].name-outStrings)); entry.dataOffset=(uint32_t)offset; if(dsLocalToOut!=NULL) { dsLocalToOut->swapArray32(dsLocalToOut, &entry, 8, &entry, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: swapArray32(item entry %ld) failed - %s\n", (long)i, u_errorName(errorCode)); exit(errorCode); } } length=(int32_t)fwrite(&entry, 1, 8, file); if(length!=8) { fprintf(stderr, "icupkg: unable to write complete item entry %ld to file \"%s\"\n", (long)i, filename); exit(U_FILE_ACCESS_ERROR); } length=items[i].length; if(length>maxItemLength) { maxItemLength=length; } offset+=length; } // write the item names length=(int32_t)fwrite(outStrings, 1, outStringTop, file); if(length!=outStringTop) { fprintf(stderr, "icupkg: unable to write complete item names to file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR); } // write the items for(pItem=items, i=0; i<itemCount; ++pItem, ++i) { int32_t type=makeTypeEnum(pItem->type); if(ds[type]!=NULL) { // swap each item from its platform properties to the desired ones udata_swap( ds[type], pItem->data, pItem->length, pItem->data, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: udata_swap(item %ld) failed - %s\n", (long)i, u_errorName(errorCode)); exit(errorCode); } } length=(int32_t)fwrite(pItem->data, 1, pItem->length, file); if(length!=pItem->length) { fprintf(stderr, "icupkg: unable to write complete item %ld to file \"%s\"\n", (long)i, filename); exit(U_FILE_ACCESS_ERROR); } } if(ferror(file)) { fprintf(stderr, "icupkg: unable to write complete file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR); } fclose(file); for(i=0; i<TYPE_COUNT; ++i) { udata_closeSwapper(ds[i]); } }
void Package::readPackage(const char *filename) { UDataSwapper *ds; const UDataInfo *pInfo; UErrorCode errorCode; const uint8_t *inBytes; int32_t length, offset, i; int32_t itemLength, typeEnum; char type; const UDataOffsetTOCEntry *inEntries; extractPackageName(filename, inPkgName, (int32_t)sizeof(inPkgName)); /* read the file */ inData=readFile(NULL, filename, inLength, type); length=inLength; /* * swap the header - even if the swapping itself is a no-op * because it tells us the header length */ errorCode=U_ZERO_ERROR; makeTypeProps(type, inCharset, inIsBigEndian); ds=udata_openSwapper(inIsBigEndian, inCharset, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n", filename, u_errorName(errorCode)); exit(errorCode); } ds->printError=printPackageError; ds->printErrorContext=stderr; headerLength=sizeof(header); if(length<headerLength) { headerLength=length; } headerLength=udata_swapDataHeader(ds, inData, headerLength, header, &errorCode); if(U_FAILURE(errorCode)) { exit(errorCode); } /* check data format and format version */ pInfo=(const UDataInfo *)((const char *)inData+4); if(!( pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */ pInfo->dataFormat[1]==0x6d && pInfo->dataFormat[2]==0x6e && pInfo->dataFormat[3]==0x44 && pInfo->formatVersion[0]==1 )) { fprintf(stderr, "icupkg: data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as an ICU .dat package\n", pInfo->dataFormat[0], pInfo->dataFormat[1], pInfo->dataFormat[2], pInfo->dataFormat[3], pInfo->formatVersion[0]); exit(U_UNSUPPORTED_ERROR); } inIsBigEndian=(UBool)pInfo->isBigEndian; inCharset=pInfo->charsetFamily; inBytes=(const uint8_t *)inData+headerLength; inEntries=(const UDataOffsetTOCEntry *)(inBytes+4); /* check that the itemCount fits, then the ToC table, then at least the header of the last item */ length-=headerLength; if(length<4) { /* itemCount does not fit */ offset=0x7fffffff; } else { itemCount=udata_readInt32(ds, *(const int32_t *)inBytes); if(itemCount==0) { offset=4; } else if(length<(4+8*itemCount)) { /* ToC table does not fit */ offset=0x7fffffff; } else { /* offset of the last item plus at least 20 bytes for its header */ offset=20+(int32_t)ds->readUInt32(inEntries[itemCount-1].dataOffset); } } if(length<offset) { fprintf(stderr, "icupkg: too few bytes (%ld after header) for a .dat package\n", (long)length); exit(U_INDEX_OUTOFBOUNDS_ERROR); } /* do not modify the package length variable until the last item's length is set */ if(itemCount>0) { char prefix[MAX_PKG_NAME_LENGTH+4]; char *s, *inItemStrings; int32_t inPkgNameLength, prefixLength, stringsOffset; if(itemCount>MAX_FILE_COUNT) { fprintf(stderr, "icupkg: too many items, maximum is %d\n", MAX_FILE_COUNT); exit(U_BUFFER_OVERFLOW_ERROR); } /* swap the item name strings */ stringsOffset=4+8*itemCount; itemLength=(int32_t)(ds->readUInt32(inEntries[0].dataOffset))-stringsOffset; // don't include padding bytes at the end of the item names while(itemLength>0 && inBytes[stringsOffset+itemLength-1]!=0) { --itemLength; } if((inStringTop+itemLength)>STRING_STORE_SIZE) { fprintf(stderr, "icupkg: total length of item name strings too long\n"); exit(U_BUFFER_OVERFLOW_ERROR); } inItemStrings=inStrings+inStringTop; ds->swapInvChars(ds, inBytes+stringsOffset, itemLength, inItemStrings, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "icupkg failed to swap the input .dat package item name strings\n"); exit(U_INVALID_FORMAT_ERROR); } inStringTop+=itemLength; // reset the Item entries memset(items, 0, itemCount*sizeof(Item)); inPkgNameLength=strlen(inPkgName); memcpy(prefix, inPkgName, inPkgNameLength); prefixLength=inPkgNameLength; /* * Get the common prefix of the items. * New-style ICU .dat packages use tree separators ('/') between package names, * tree names, and item names, * while old-style ICU .dat packages (before multi-tree support) * use an underscore ('_') between package and item names. */ offset=(int32_t)ds->readUInt32(inEntries[0].nameOffset)-stringsOffset; s=inItemStrings+offset; if( (int32_t)strlen(s)>=(inPkgNameLength+2) && 0==memcmp(s, inPkgName, inPkgNameLength) && s[inPkgNameLength]=='_' ) { // old-style .dat package prefix[prefixLength++]='_'; } else { // new-style .dat package prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR; // if it turns out to not contain U_TREE_ENTRY_SEP_CHAR // then the test in the loop below will fail } prefix[prefixLength]=0; /* read the ToC table */ for(i=0; i<itemCount; ++i) { // skip the package part of the item name, error if it does not match the actual package name // or if nothing follows the package name offset=(int32_t)ds->readUInt32(inEntries[i].nameOffset)-stringsOffset; s=inItemStrings+offset; if(0!=strncmp(s, prefix, prefixLength) || s[prefixLength]==0) { fprintf(stderr, "icupkg: input .dat item name \"%s\" does not start with \"%s\"\n", s, prefix); exit(U_UNSUPPORTED_ERROR); } items[i].name=s+prefixLength; // set the item's data items[i].data=(uint8_t *)inBytes+ds->readUInt32(inEntries[i].dataOffset); if(i>0) { items[i-1].length=(int32_t)(items[i].data-items[i-1].data); // set the previous item's platform type typeEnum=getTypeEnumForInputData(items[i-1].data, items[i-1].length, &errorCode); if(typeEnum<0 || U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: not an ICU data file: item \"%s\" in \"%s\"\n", items[i-1].name, filename); exit(U_INVALID_FORMAT_ERROR); } items[i-1].type=makeTypeLetter(typeEnum); } items[i].isDataOwned=FALSE; } // set the last item's length items[itemCount-1].length=length-ds->readUInt32(inEntries[itemCount-1].dataOffset); // set the last item's platform type typeEnum=getTypeEnumForInputData(items[itemCount-1].data, items[itemCount-1].length, &errorCode); if(typeEnum<0 || U_FAILURE(errorCode)) { fprintf(stderr, "icupkg: not an ICU data file: item \"%s\" in \"%s\"\n", items[i-1].name, filename); exit(U_INVALID_FORMAT_ERROR); } items[itemCount-1].type=makeTypeLetter(typeEnum); if(type!=U_ICUDATA_TYPE_LETTER[0]) { // sort the item names for the local charset sortItems(); } } udata_closeSwapper(ds); }