]>
Commit | Line | Data |
---|---|---|
374ca955 A |
1 | /* |
2 | ******************************************************************************* | |
3 | * | |
46f4442e | 4 | * Copyright (C) 2003-2007, International Business Machines |
374ca955 A |
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" | |
73c04bcf | 34 | #include "swapimpl.h" |
374ca955 A |
35 | #include "toolutil.h" |
36 | #include "uoptions.h" | |
37 | ||
374ca955 A |
38 | #include <stdio.h> |
39 | #include <stdlib.h> | |
40 | #include <string.h> | |
41 | ||
374ca955 A |
42 | /* definitions */ |
43 | ||
44 | #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) | |
46f4442e | 45 | #define DEFAULT_PADDING_LENGTH 15 |
374ca955 A |
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 | ||
374ca955 A |
69 | /** |
70 | * Swap an ICU .dat package, including swapping of enclosed items. | |
71 | */ | |
72 | U_CFUNC int32_t U_CALLCONV | |
73c04bcf A |
73 | udata_swapPackage(const char *inFilename, const char *outFilename, |
74 | const UDataSwapper *ds, | |
374ca955 A |
75 | const void *inData, int32_t length, void *outData, |
76 | UErrorCode *pErrorCode); | |
77 | ||
374ca955 A |
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; | |
73c04bcf | 113 | const UDataInfo *pInfo; |
374ca955 A |
114 | UErrorCode errorCode; |
115 | uint8_t outCharset; | |
116 | UBool outIsBigEndian; | |
117 | ||
118 | U_MAIN_INIT_ARGS(argc, argv); | |
119 | ||
73c04bcf A |
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 | ||
374ca955 A |
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 | ||
374ca955 A |
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); | |
46f4442e | 174 | if(length<DEFAULT_PADDING_LENGTH) { |
374ca955 A |
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 | */ | |
46f4442e | 186 | data=(char *)malloc(length+DEFAULT_PADDING_LENGTH); |
374ca955 A |
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() */ | |
46f4442e | 194 | uprv_memset(data+length-DEFAULT_PADDING_LENGTH, 0xaa, DEFAULT_PADDING_LENGTH); |
374ca955 A |
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 | ||
73c04bcf A |
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 | } | |
374ca955 A |
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 | ||
374ca955 A |
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 | |
73c04bcf A |
335 | udata_swapPackage(const char *inFilename, const char *outFilename, |
336 | const UDataSwapper *ds, | |
374ca955 A |
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) { | |
73c04bcf | 448 | udata_printError(ds, "udata_swapPackage(): too few bytes (%d after header) for a .dat package\n", |
374ca955 A |
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 */ | |
46f4442e | 523 | table=(ToCEntry *)uprv_malloc(itemCount*sizeof(ToCEntry)+length+DEFAULT_PADDING_LENGTH); |
374ca955 A |
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 ? | |
46f4442e | 537 | itemCount*sizeof(ToCEntry)+length+DEFAULT_PADDING_LENGTH : |
374ca955 A |
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 | ||
73c04bcf A |
579 | /* Save the offset before we sort the TOC. */ |
580 | offset=table[0].inOffset; | |
581 | /* sort the TOC entries */ | |
374ca955 A |
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 */ | |
374ca955 A |
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 | */ |