|
1 /* |
|
2 ******************************************************************************* |
|
3 * |
|
4 * Copyright (C) 2003-2007, International Business Machines |
|
5 * Corporation and others. All Rights Reserved. |
|
6 * |
|
7 ******************************************************************************* |
|
8 * file name: icuswap.cpp |
|
9 * encoding: US-ASCII |
|
10 * tab size: 8 (not used) |
|
11 * indentation:4 |
|
12 * |
|
13 * created on: 2003aug08 |
|
14 * created by: Markus W. Scherer |
|
15 * |
|
16 * This tool takes an ICU data file and "swaps" it, that is, changes its |
|
17 * platform properties between big-/little-endianness and ASCII/EBCDIC charset |
|
18 * families. |
|
19 * The modified data file is written to a new file. |
|
20 * Useful as an install-time tool for shipping only one flavor of ICU data |
|
21 * and preparing data files for the target platform. |
|
22 * Will not work with data DLLs (shared libraries). |
|
23 */ |
|
24 |
|
25 #include "unicode/utypes.h" |
|
26 #include "unicode/putil.h" |
|
27 #include "unicode/udata.h" |
|
28 #include "cmemory.h" |
|
29 #include "cstring.h" |
|
30 #include "uinvchar.h" |
|
31 #include "uarrsort.h" |
|
32 #include "ucmndata.h" |
|
33 #include "udataswp.h" |
|
34 #include "swapimpl.h" |
|
35 #include "toolutil.h" |
|
36 #include "uoptions.h" |
|
37 |
|
38 #include <stdio.h> |
|
39 #include <stdlib.h> |
|
40 #include <string.h> |
|
41 |
|
42 /* definitions */ |
|
43 |
|
44 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) |
|
45 #define DEFAULT_PADDING_LENGTH 15 |
|
46 |
|
47 static UOption options[]={ |
|
48 UOPTION_HELP_H, |
|
49 UOPTION_HELP_QUESTION_MARK, |
|
50 UOPTION_DEF("type", 't', UOPT_REQUIRES_ARG) |
|
51 }; |
|
52 |
|
53 enum { |
|
54 OPT_HELP_H, |
|
55 OPT_HELP_QUESTION_MARK, |
|
56 OPT_OUT_TYPE |
|
57 }; |
|
58 |
|
59 static int32_t |
|
60 fileSize(FILE *f) { |
|
61 int32_t size; |
|
62 |
|
63 fseek(f, 0, SEEK_END); |
|
64 size=(int32_t)ftell(f); |
|
65 fseek(f, 0, SEEK_SET); |
|
66 return size; |
|
67 } |
|
68 |
|
69 /** |
|
70 * Swap an ICU .dat package, including swapping of enclosed items. |
|
71 */ |
|
72 U_CFUNC int32_t U_CALLCONV |
|
73 udata_swapPackage(const char *inFilename, const char *outFilename, |
|
74 const UDataSwapper *ds, |
|
75 const void *inData, int32_t length, void *outData, |
|
76 UErrorCode *pErrorCode); |
|
77 |
|
78 U_CDECL_BEGIN |
|
79 static void U_CALLCONV |
|
80 printError(void *context, const char *fmt, va_list args) { |
|
81 vfprintf((FILE *)context, fmt, args); |
|
82 } |
|
83 U_CDECL_END |
|
84 |
|
85 static int |
|
86 printUsage(const char *pname, UBool ishelp) { |
|
87 fprintf(stderr, |
|
88 "%csage: %s [ -h, -?, --help ] -tl|-tb|-te|--type=b|... infilename outfilename\n", |
|
89 ishelp ? 'U' : 'u', pname); |
|
90 if(ishelp) { |
|
91 fprintf(stderr, |
|
92 "\nOptions: -h, -?, --help print this message and exit\n" |
|
93 " Read the input file, swap its platform properties according\n" |
|
94 " to the -t or --type option, and write the result to the output file.\n" |
|
95 " -tl change to little-endian/ASCII charset family\n" |
|
96 " -tb change to big-endian/ASCII charset family\n" |
|
97 " -te change to big-endian/EBCDIC charset family\n"); |
|
98 } |
|
99 |
|
100 return !ishelp; |
|
101 } |
|
102 |
|
103 extern int |
|
104 main(int argc, char *argv[]) { |
|
105 FILE *in, *out; |
|
106 const char *pname; |
|
107 char *data; |
|
108 int32_t length; |
|
109 UBool ishelp; |
|
110 int rc; |
|
111 |
|
112 UDataSwapper *ds; |
|
113 const UDataInfo *pInfo; |
|
114 UErrorCode errorCode; |
|
115 uint8_t outCharset; |
|
116 UBool outIsBigEndian; |
|
117 |
|
118 U_MAIN_INIT_ARGS(argc, argv); |
|
119 |
|
120 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"); |
|
121 |
|
122 /* get the program basename */ |
|
123 pname=strrchr(argv[0], U_FILE_SEP_CHAR); |
|
124 if(pname==NULL) { |
|
125 pname=strrchr(argv[0], '/'); |
|
126 } |
|
127 if(pname!=NULL) { |
|
128 ++pname; |
|
129 } else { |
|
130 pname=argv[0]; |
|
131 } |
|
132 |
|
133 argc=u_parseArgs(argc, argv, LENGTHOF(options), options); |
|
134 ishelp=options[OPT_HELP_H].doesOccur || options[OPT_HELP_QUESTION_MARK].doesOccur; |
|
135 if(ishelp || argc!=3) { |
|
136 return printUsage(pname, ishelp); |
|
137 } |
|
138 |
|
139 /* parse the output type option */ |
|
140 data=(char *)options[OPT_OUT_TYPE].value; |
|
141 if(data[0]==0 || data[1]!=0) { |
|
142 /* the type must be exactly one letter */ |
|
143 return printUsage(pname, FALSE); |
|
144 } |
|
145 switch(data[0]) { |
|
146 case 'l': |
|
147 outIsBigEndian=FALSE; |
|
148 outCharset=U_ASCII_FAMILY; |
|
149 break; |
|
150 case 'b': |
|
151 outIsBigEndian=TRUE; |
|
152 outCharset=U_ASCII_FAMILY; |
|
153 break; |
|
154 case 'e': |
|
155 outIsBigEndian=TRUE; |
|
156 outCharset=U_EBCDIC_FAMILY; |
|
157 break; |
|
158 default: |
|
159 return printUsage(pname, FALSE); |
|
160 } |
|
161 |
|
162 in=out=NULL; |
|
163 data=NULL; |
|
164 |
|
165 /* open the input file, get its length, allocate memory for it, read the file */ |
|
166 in=fopen(argv[1], "rb"); |
|
167 if(in==NULL) { |
|
168 fprintf(stderr, "%s: unable to open input file \"%s\"\n", pname, argv[1]); |
|
169 rc=2; |
|
170 goto done; |
|
171 } |
|
172 |
|
173 length=fileSize(in); |
|
174 if(length<DEFAULT_PADDING_LENGTH) { |
|
175 fprintf(stderr, "%s: empty input file \"%s\"\n", pname, argv[1]); |
|
176 rc=2; |
|
177 goto done; |
|
178 } |
|
179 |
|
180 /* |
|
181 * +15: udata_swapPackage() may need to add a few padding bytes to the |
|
182 * last item if charset swapping is done, |
|
183 * because the last item may be resorted into the middle and then needs |
|
184 * additional padding bytes |
|
185 */ |
|
186 data=(char *)malloc(length+DEFAULT_PADDING_LENGTH); |
|
187 if(data==NULL) { |
|
188 fprintf(stderr, "%s: error allocating memory for \"%s\"\n", pname, argv[1]); |
|
189 rc=2; |
|
190 goto done; |
|
191 } |
|
192 |
|
193 /* set the last 15 bytes to the usual padding byte, see udata_swapPackage() */ |
|
194 uprv_memset(data+length-DEFAULT_PADDING_LENGTH, 0xaa, DEFAULT_PADDING_LENGTH); |
|
195 |
|
196 if(length!=(int32_t)fread(data, 1, length, in)) { |
|
197 fprintf(stderr, "%s: error reading \"%s\"\n", pname, argv[1]); |
|
198 rc=3; |
|
199 goto done; |
|
200 } |
|
201 |
|
202 fclose(in); |
|
203 in=NULL; |
|
204 |
|
205 /* swap the data in-place */ |
|
206 errorCode=U_ZERO_ERROR; |
|
207 ds=udata_openSwapperForInputData(data, length, outIsBigEndian, outCharset, &errorCode); |
|
208 if(U_FAILURE(errorCode)) { |
|
209 fprintf(stderr, "%s: udata_openSwapperForInputData(\"%s\") failed - %s\n", |
|
210 pname, argv[1], u_errorName(errorCode)); |
|
211 rc=4; |
|
212 goto done; |
|
213 } |
|
214 |
|
215 ds->printError=printError; |
|
216 ds->printErrorContext=stderr; |
|
217 |
|
218 /* speculative cast, protected by the following length check */ |
|
219 pInfo=(const UDataInfo *)((const char *)data+4); |
|
220 |
|
221 if( length>=20 && |
|
222 pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */ |
|
223 pInfo->dataFormat[1]==0x6d && |
|
224 pInfo->dataFormat[2]==0x6e && |
|
225 pInfo->dataFormat[3]==0x44 |
|
226 ) { |
|
227 /* |
|
228 * swap the .dat package |
|
229 * udata_swapPackage() needs to rename ToC name entries from the old package |
|
230 * name to the new one. |
|
231 * We pass it the filenames, and udata_swapPackage() will extract the |
|
232 * package names. |
|
233 */ |
|
234 length=udata_swapPackage(argv[1], argv[2], ds, data, length, data, &errorCode); |
|
235 udata_closeSwapper(ds); |
|
236 if(U_FAILURE(errorCode)) { |
|
237 fprintf(stderr, "%s: udata_swapPackage(\"%s\") failed - %s\n", |
|
238 pname, argv[1], u_errorName(errorCode)); |
|
239 rc=4; |
|
240 goto done; |
|
241 } |
|
242 } else { |
|
243 /* swap the data, which is not a .dat package */ |
|
244 length=udata_swap(ds, data, length, data, &errorCode); |
|
245 udata_closeSwapper(ds); |
|
246 if(U_FAILURE(errorCode)) { |
|
247 fprintf(stderr, "%s: udata_swap(\"%s\") failed - %s\n", |
|
248 pname, argv[1], u_errorName(errorCode)); |
|
249 rc=4; |
|
250 goto done; |
|
251 } |
|
252 } |
|
253 |
|
254 out=fopen(argv[2], "wb"); |
|
255 if(out==NULL) { |
|
256 fprintf(stderr, "%s: unable to open output file \"%s\"\n", pname, argv[2]); |
|
257 rc=5; |
|
258 goto done; |
|
259 } |
|
260 |
|
261 if(length!=(int32_t)fwrite(data, 1, length, out)) { |
|
262 fprintf(stderr, "%s: error writing \"%s\"\n", pname, argv[2]); |
|
263 rc=6; |
|
264 goto done; |
|
265 } |
|
266 |
|
267 fclose(out); |
|
268 out=NULL; |
|
269 |
|
270 /* all done */ |
|
271 rc=0; |
|
272 |
|
273 done: |
|
274 if(in!=NULL) { |
|
275 fclose(in); |
|
276 } |
|
277 if(out!=NULL) { |
|
278 fclose(out); |
|
279 } |
|
280 if(data!=NULL) { |
|
281 free(data); |
|
282 } |
|
283 return rc; |
|
284 } |
|
285 |
|
286 /* swap .dat package files -------------------------------------------------- */ |
|
287 |
|
288 static int32_t |
|
289 extractPackageName(const UDataSwapper *ds, const char *filename, |
|
290 char pkg[], int32_t capacity, |
|
291 UErrorCode *pErrorCode) { |
|
292 const char *basename; |
|
293 int32_t len; |
|
294 |
|
295 if(U_FAILURE(*pErrorCode)) { |
|
296 return 0; |
|
297 } |
|
298 |
|
299 basename=findBasename(filename); |
|
300 len=(int32_t)uprv_strlen(basename)-4; /* -4: subtract the length of ".dat" */ |
|
301 |
|
302 if(len<=0 || 0!=uprv_strcmp(basename+len, ".dat")) { |
|
303 udata_printError(ds, "udata_swapPackage(): \"%s\" is not recognized as a package filename (must end with .dat)\n", |
|
304 basename); |
|
305 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
|
306 return 0; |
|
307 } |
|
308 |
|
309 if(len>=capacity) { |
|
310 udata_printError(ds, "udata_swapPackage(): the package name \"%s\" is too long (>=%ld)\n", |
|
311 (long)capacity); |
|
312 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
|
313 return 0; |
|
314 } |
|
315 |
|
316 uprv_memcpy(pkg, basename, len); |
|
317 pkg[len]=0; |
|
318 return len; |
|
319 } |
|
320 |
|
321 struct ToCEntry { |
|
322 uint32_t nameOffset, inOffset, outOffset, length; |
|
323 }; |
|
324 |
|
325 U_CDECL_BEGIN |
|
326 static int32_t U_CALLCONV |
|
327 compareToCEntries(const void *context, const void *left, const void *right) { |
|
328 const char *chars=(const char *)context; |
|
329 return (int32_t)uprv_strcmp(chars+((const ToCEntry *)left)->nameOffset, |
|
330 chars+((const ToCEntry *)right)->nameOffset); |
|
331 } |
|
332 U_CDECL_END |
|
333 |
|
334 U_CFUNC int32_t U_CALLCONV |
|
335 udata_swapPackage(const char *inFilename, const char *outFilename, |
|
336 const UDataSwapper *ds, |
|
337 const void *inData, int32_t length, void *outData, |
|
338 UErrorCode *pErrorCode) { |
|
339 const UDataInfo *pInfo; |
|
340 int32_t headerSize; |
|
341 |
|
342 const uint8_t *inBytes; |
|
343 uint8_t *outBytes; |
|
344 |
|
345 uint32_t itemCount, offset, i; |
|
346 int32_t itemLength; |
|
347 |
|
348 const UDataOffsetTOCEntry *inEntries; |
|
349 UDataOffsetTOCEntry *outEntries; |
|
350 |
|
351 ToCEntry *table; |
|
352 |
|
353 char inPkgName[32], outPkgName[32]; |
|
354 int32_t inPkgNameLength, outPkgNameLength; |
|
355 |
|
356 /* udata_swapDataHeader checks the arguments */ |
|
357 headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode); |
|
358 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
|
359 return 0; |
|
360 } |
|
361 |
|
362 /* check data format and format version */ |
|
363 pInfo=(const UDataInfo *)((const char *)inData+4); |
|
364 if(!( |
|
365 pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */ |
|
366 pInfo->dataFormat[1]==0x6d && |
|
367 pInfo->dataFormat[2]==0x6e && |
|
368 pInfo->dataFormat[3]==0x44 && |
|
369 pInfo->formatVersion[0]==1 |
|
370 )) { |
|
371 udata_printError(ds, "udata_swapPackage(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as an ICU .dat package\n", |
|
372 pInfo->dataFormat[0], pInfo->dataFormat[1], |
|
373 pInfo->dataFormat[2], pInfo->dataFormat[3], |
|
374 pInfo->formatVersion[0]); |
|
375 *pErrorCode=U_UNSUPPORTED_ERROR; |
|
376 return 0; |
|
377 } |
|
378 |
|
379 /* |
|
380 * We need to change the ToC name entries so that they have the correct |
|
381 * package name prefix. |
|
382 * Extract the package names from the in/out filenames. |
|
383 */ |
|
384 inPkgNameLength=extractPackageName( |
|
385 ds, inFilename, |
|
386 inPkgName, (int32_t)sizeof(inPkgName), |
|
387 pErrorCode); |
|
388 outPkgNameLength=extractPackageName( |
|
389 ds, outFilename, |
|
390 outPkgName, (int32_t)sizeof(outPkgName), |
|
391 pErrorCode); |
|
392 if(U_FAILURE(*pErrorCode)) { |
|
393 return 0; |
|
394 } |
|
395 |
|
396 /* |
|
397 * It is possible to work with inPkgNameLength!=outPkgNameLength, |
|
398 * but then the length of the data file would change more significantly, |
|
399 * which we are not currently prepared for. |
|
400 */ |
|
401 if(inPkgNameLength!=outPkgNameLength) { |
|
402 udata_printError(ds, "udata_swapPackage(): the package names \"%s\" and \"%s\" must have the same length\n", |
|
403 inPkgName, outPkgName); |
|
404 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
|
405 return 0; |
|
406 } |
|
407 |
|
408 inBytes=(const uint8_t *)inData+headerSize; |
|
409 inEntries=(const UDataOffsetTOCEntry *)(inBytes+4); |
|
410 |
|
411 if(length<0) { |
|
412 /* preflighting */ |
|
413 itemCount=ds->readUInt32(*(const uint32_t *)inBytes); |
|
414 if(itemCount==0) { |
|
415 /* no items: count only the item count and return */ |
|
416 return headerSize+4; |
|
417 } |
|
418 |
|
419 /* read the last item's offset and preflight it */ |
|
420 offset=ds->readUInt32(inEntries[itemCount-1].dataOffset); |
|
421 itemLength=udata_swap(ds, inBytes+offset, -1, NULL, pErrorCode); |
|
422 |
|
423 if(U_SUCCESS(*pErrorCode)) { |
|
424 return headerSize+offset+(uint32_t)itemLength; |
|
425 } else { |
|
426 return 0; |
|
427 } |
|
428 } else { |
|
429 /* check that the itemCount fits, then the ToC table, then at least the header of the last item */ |
|
430 length-=headerSize; |
|
431 if(length<4) { |
|
432 /* itemCount does not fit */ |
|
433 offset=0xffffffff; |
|
434 itemCount=0; /* make compilers happy */ |
|
435 } else { |
|
436 itemCount=ds->readUInt32(*(const uint32_t *)inBytes); |
|
437 if(itemCount==0) { |
|
438 offset=4; |
|
439 } else if((uint32_t)length<(4+8*itemCount)) { |
|
440 /* ToC table does not fit */ |
|
441 offset=0xffffffff; |
|
442 } else { |
|
443 /* offset of the last item plus at least 20 bytes for its header */ |
|
444 offset=20+ds->readUInt32(inEntries[itemCount-1].dataOffset); |
|
445 } |
|
446 } |
|
447 if((uint32_t)length<offset) { |
|
448 udata_printError(ds, "udata_swapPackage(): too few bytes (%d after header) for a .dat package\n", |
|
449 length); |
|
450 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; |
|
451 return 0; |
|
452 } |
|
453 |
|
454 outBytes=(uint8_t *)outData+headerSize; |
|
455 |
|
456 /* swap the item count */ |
|
457 ds->swapArray32(ds, inBytes, 4, outBytes, pErrorCode); |
|
458 |
|
459 if(itemCount==0) { |
|
460 /* no items: just return now */ |
|
461 return headerSize+4; |
|
462 } |
|
463 |
|
464 /* swap the item name strings */ |
|
465 offset=4+8*itemCount; |
|
466 itemLength=(int32_t)(ds->readUInt32(inEntries[0].dataOffset)-offset); |
|
467 udata_swapInvStringBlock(ds, inBytes+offset, itemLength, outBytes+offset, pErrorCode); |
|
468 if(U_FAILURE(*pErrorCode)) { |
|
469 udata_printError(ds, "udata_swapPackage() failed to swap the data item name strings\n"); |
|
470 return 0; |
|
471 } |
|
472 /* keep offset and itemLength in case we allocate and copy the strings below */ |
|
473 |
|
474 /* swap the package names into the output charset */ |
|
475 if(ds->outCharset!=U_CHARSET_FAMILY) { |
|
476 UDataSwapper *ds2; |
|
477 ds2=udata_openSwapper(TRUE, U_CHARSET_FAMILY, TRUE, ds->outCharset, pErrorCode); |
|
478 ds2->swapInvChars(ds2, inPkgName, inPkgNameLength, inPkgName, pErrorCode); |
|
479 ds2->swapInvChars(ds2, outPkgName, outPkgNameLength, outPkgName, pErrorCode); |
|
480 udata_closeSwapper(ds2); |
|
481 if(U_FAILURE(*pErrorCode)) { |
|
482 udata_printError(ds, "udata_swapPackage() failed to swap the input/output package names\n"); |
|
483 } |
|
484 } |
|
485 |
|
486 /* change the prefix of each ToC entry name from the old to the new package name */ |
|
487 { |
|
488 char *entryName; |
|
489 |
|
490 for(i=0; i<itemCount; ++i) { |
|
491 entryName=(char *)inBytes+ds->readUInt32(inEntries[i].nameOffset); |
|
492 |
|
493 if(0==uprv_memcmp(entryName, inPkgName, inPkgNameLength)) { |
|
494 uprv_memcpy(entryName, outPkgName, inPkgNameLength); |
|
495 } else { |
|
496 udata_printError(ds, "udata_swapPackage() failed: ToC item %ld does not have the input package name as a prefix\n", |
|
497 (long)i); |
|
498 *pErrorCode=U_INVALID_FORMAT_ERROR; |
|
499 return 0; |
|
500 } |
|
501 } |
|
502 } |
|
503 |
|
504 /* |
|
505 * Allocate the ToC table and, if necessary, a temporary buffer for |
|
506 * pseudo-in-place swapping. |
|
507 * |
|
508 * We cannot swap in-place because: |
|
509 * |
|
510 * 1. If the swapping of an item fails mid-way, then in-place swapping |
|
511 * has destroyed its data. |
|
512 * Out-of-place swapping allows us to then copy its original data. |
|
513 * |
|
514 * 2. If swapping changes the charset family, then we must resort |
|
515 * not only the ToC table but also the data items themselves. |
|
516 * This requires a permutation and is best done with separate in/out |
|
517 * buffers. |
|
518 * |
|
519 * We swapped the strings above to avoid the malloc below if string swapping fails. |
|
520 */ |
|
521 if(inData==outData) { |
|
522 /* +15: prepare for extra padding of a newly-last item */ |
|
523 table=(ToCEntry *)uprv_malloc(itemCount*sizeof(ToCEntry)+length+DEFAULT_PADDING_LENGTH); |
|
524 if(table!=NULL) { |
|
525 outBytes=(uint8_t *)(table+itemCount); |
|
526 |
|
527 /* copy the item count and the swapped strings */ |
|
528 uprv_memcpy(outBytes, inBytes, 4); |
|
529 uprv_memcpy(outBytes+offset, inBytes+offset, itemLength); |
|
530 } |
|
531 } else { |
|
532 table=(ToCEntry *)uprv_malloc(itemCount*sizeof(ToCEntry)); |
|
533 } |
|
534 if(table==NULL) { |
|
535 udata_printError(ds, "udata_swapPackage(): out of memory allocating %d bytes\n", |
|
536 inData==outData ? |
|
537 itemCount*sizeof(ToCEntry)+length+DEFAULT_PADDING_LENGTH : |
|
538 itemCount*sizeof(ToCEntry)); |
|
539 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; |
|
540 return 0; |
|
541 } |
|
542 outEntries=(UDataOffsetTOCEntry *)(outBytes+4); |
|
543 |
|
544 /* read the ToC table */ |
|
545 for(i=0; i<itemCount; ++i) { |
|
546 table[i].nameOffset=ds->readUInt32(inEntries[i].nameOffset); |
|
547 table[i].inOffset=ds->readUInt32(inEntries[i].dataOffset); |
|
548 if(i>0) { |
|
549 table[i-1].length=table[i].inOffset-table[i-1].inOffset; |
|
550 } |
|
551 } |
|
552 table[itemCount-1].length=(uint32_t)length-table[itemCount-1].inOffset; |
|
553 |
|
554 if(ds->inCharset==ds->outCharset) { |
|
555 /* no charset swapping, no resorting: keep item offsets the same */ |
|
556 for(i=0; i<itemCount; ++i) { |
|
557 table[i].outOffset=table[i].inOffset; |
|
558 } |
|
559 } else { |
|
560 /* charset swapping: resort items by their swapped names */ |
|
561 |
|
562 /* |
|
563 * Before the actual sorting, we need to make sure that each item |
|
564 * has a length that is a multiple of 16 bytes so that all items |
|
565 * are 16-aligned. |
|
566 * Only the old last item may be missing up to 15 padding bytes. |
|
567 * Add padding bytes for it. |
|
568 * Since the icuswap main() function has already allocated enough |
|
569 * input buffer space and set the last 15 bytes there to 0xaa, |
|
570 * we only need to increase the total data length and the length |
|
571 * of the last item here. |
|
572 */ |
|
573 if((length&0xf)!=0) { |
|
574 int32_t delta=16-(length&0xf); |
|
575 length+=delta; |
|
576 table[itemCount-1].length+=(uint32_t)delta; |
|
577 } |
|
578 |
|
579 /* Save the offset before we sort the TOC. */ |
|
580 offset=table[0].inOffset; |
|
581 /* sort the TOC entries */ |
|
582 uprv_sortArray(table, (int32_t)itemCount, (int32_t)sizeof(ToCEntry), |
|
583 compareToCEntries, outBytes, FALSE, pErrorCode); |
|
584 |
|
585 /* |
|
586 * Note: Before sorting, the inOffset values were in order. |
|
587 * Now the outOffset values are in order. |
|
588 */ |
|
589 |
|
590 /* assign outOffset values */ |
|
591 for(i=0; i<itemCount; ++i) { |
|
592 table[i].outOffset=offset; |
|
593 offset+=table[i].length; |
|
594 } |
|
595 } |
|
596 |
|
597 /* write the output ToC table */ |
|
598 for(i=0; i<itemCount; ++i) { |
|
599 ds->writeUInt32(&outEntries[i].nameOffset, table[i].nameOffset); |
|
600 ds->writeUInt32(&outEntries[i].dataOffset, table[i].outOffset); |
|
601 } |
|
602 |
|
603 /* swap each data item */ |
|
604 for(i=0; i<itemCount; ++i) { |
|
605 /* first copy the item bytes to make sure that unreachable bytes are copied */ |
|
606 uprv_memcpy(outBytes+table[i].outOffset, inBytes+table[i].inOffset, table[i].length); |
|
607 |
|
608 /* swap the item */ |
|
609 udata_swap(ds, inBytes+table[i].inOffset, (int32_t)table[i].length, |
|
610 outBytes+table[i].outOffset, pErrorCode); |
|
611 |
|
612 if(U_FAILURE(*pErrorCode)) { |
|
613 if(ds->outCharset==U_CHARSET_FAMILY) { |
|
614 udata_printError(ds, "warning: udata_swapPackage() failed to swap item \"%s\"\n" |
|
615 " at inOffset 0x%x length 0x%x - %s\n" |
|
616 " the data item will be copied, not swapped\n\n", |
|
617 (char *)outBytes+table[i].nameOffset, |
|
618 table[i].inOffset, table[i].length, u_errorName(*pErrorCode)); |
|
619 } else { |
|
620 udata_printError(ds, "warning: udata_swapPackage() failed to swap an item\n" |
|
621 " at inOffset 0x%x length 0x%x - %s\n" |
|
622 " the data item will be copied, not swapped\n\n", |
|
623 table[i].inOffset, table[i].length, u_errorName(*pErrorCode)); |
|
624 } |
|
625 /* reset the error code, copy the data item, and continue */ |
|
626 *pErrorCode=U_ZERO_ERROR; |
|
627 uprv_memcpy(outBytes+table[i].outOffset, inBytes+table[i].inOffset, table[i].length); |
|
628 } |
|
629 } |
|
630 |
|
631 if(inData==outData) { |
|
632 /* copy the data from the temporary buffer to the in-place buffer */ |
|
633 uprv_memcpy((uint8_t *)outData+headerSize, outBytes, length); |
|
634 } |
|
635 uprv_free(table); |
|
636 |
|
637 return headerSize+length; |
|
638 } |
|
639 } |
|
640 |
|
641 /* |
|
642 * Hey, Emacs, please set the following: |
|
643 * |
|
644 * Local Variables: |
|
645 * indent-tabs-mode: nil |
|
646 * End: |
|
647 * |
|
648 */ |