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); }
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; } }
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); }