2 *******************************************************************************
4 * Copyright (C) 2003-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: icuswap.cpp
10 * tab size: 8 (not used)
13 * created on: 2003aug08
14 * created by: Markus W. Scherer
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
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).
25 #include "unicode/utypes.h"
26 #include "unicode/putil.h"
27 #include "unicode/udata.h"
37 /* swapping implementations in common */
54 /* swapping implementations in i18n */
58 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
60 static UOption options
[]={
62 UOPTION_HELP_QUESTION_MARK
,
63 UOPTION_DEF("type", 't', UOPT_REQUIRES_ARG
)
68 OPT_HELP_QUESTION_MARK
,
76 fseek(f
, 0, SEEK_END
);
77 size
=(int32_t)ftell(f
);
78 fseek(f
, 0, SEEK_SET
);
83 * Identifies and then transforms the ICU data piece in-place, or determines
84 * its length. See UDataSwapFn.
85 * This function handles .dat data packages as well as single data pieces
86 * and internally dispatches to per-type swap functions.
87 * Sets a U_UNSUPPORTED_ERROR if the data format is not recognized.
90 * @see udata_openSwapper
91 * @see udata_openSwapperForInputData
95 udata_swap(const UDataSwapper
*ds
,
96 const void *inData
, int32_t length
, void *outData
,
97 UErrorCode
*pErrorCode
);
100 * Swap an ICU .dat package, including swapping of enclosed items.
102 U_CFUNC
int32_t U_CALLCONV
103 udata_swapPackage(const UDataSwapper
*ds
,
104 const void *inData
, int32_t length
, void *outData
,
105 UErrorCode
*pErrorCode
);
108 * udata_swapPackage() needs to rename ToC name entries from the old package
109 * name to the new one.
110 * We store the filenames here, and udata_swapPackage() will extract the
113 static const char *inFilename
, *outFilename
;
116 static void U_CALLCONV
117 printError(void *context
, const char *fmt
, va_list args
) {
118 vfprintf((FILE *)context
, fmt
, args
);
123 printUsage(const char *pname
, UBool ishelp
) {
125 "%csage: %s [ -h, -?, --help ] -tl|-tb|-te|--type=b|... infilename outfilename\n",
126 ishelp
? 'U' : 'u', pname
);
129 "\nOptions: -h, -?, --help print this message and exit\n"
130 " Read the input file, swap its platform properties according\n"
131 " to the -t or --type option, and write the result to the output file.\n"
132 " -tl change to little-endian/ASCII charset family\n"
133 " -tb change to big-endian/ASCII charset family\n"
134 " -te change to big-endian/EBCDIC charset family\n");
141 main(int argc
, char *argv
[]) {
150 UErrorCode errorCode
;
152 UBool outIsBigEndian
;
154 U_MAIN_INIT_ARGS(argc
, argv
);
156 /* get the program basename */
157 pname
=strrchr(argv
[0], U_FILE_SEP_CHAR
);
159 pname
=strrchr(argv
[0], '/');
167 argc
=u_parseArgs(argc
, argv
, LENGTHOF(options
), options
);
168 ishelp
=options
[OPT_HELP_H
].doesOccur
|| options
[OPT_HELP_QUESTION_MARK
].doesOccur
;
169 if(ishelp
|| argc
!=3) {
170 return printUsage(pname
, ishelp
);
173 /* parse the output type option */
174 data
=(char *)options
[OPT_OUT_TYPE
].value
;
175 if(data
[0]==0 || data
[1]!=0) {
176 /* the type must be exactly one letter */
177 return printUsage(pname
, FALSE
);
181 outIsBigEndian
=FALSE
;
182 outCharset
=U_ASCII_FAMILY
;
186 outCharset
=U_ASCII_FAMILY
;
190 outCharset
=U_EBCDIC_FAMILY
;
193 return printUsage(pname
, FALSE
);
199 /* udata_swapPackage() needs the filenames */
203 /* open the input file, get its length, allocate memory for it, read the file */
204 in
=fopen(argv
[1], "rb");
206 fprintf(stderr
, "%s: unable to open input file \"%s\"\n", pname
, argv
[1]);
213 fprintf(stderr
, "%s: empty input file \"%s\"\n", pname
, argv
[1]);
219 * +15: udata_swapPackage() may need to add a few padding bytes to the
220 * last item if charset swapping is done,
221 * because the last item may be resorted into the middle and then needs
222 * additional padding bytes
224 data
=(char *)malloc(length
+15);
226 fprintf(stderr
, "%s: error allocating memory for \"%s\"\n", pname
, argv
[1]);
231 /* set the last 15 bytes to the usual padding byte, see udata_swapPackage() */
232 uprv_memset(data
+length
-15, 0xaa, 15);
234 if(length
!=(int32_t)fread(data
, 1, length
, in
)) {
235 fprintf(stderr
, "%s: error reading \"%s\"\n", pname
, argv
[1]);
243 /* swap the data in-place */
244 errorCode
=U_ZERO_ERROR
;
245 ds
=udata_openSwapperForInputData(data
, length
, outIsBigEndian
, outCharset
, &errorCode
);
246 if(U_FAILURE(errorCode
)) {
247 fprintf(stderr
, "%s: udata_openSwapperForInputData(\"%s\") failed - %s\n",
248 pname
, argv
[1], u_errorName(errorCode
));
253 ds
->printError
=printError
;
254 ds
->printErrorContext
=stderr
;
256 length
=udata_swap(ds
, data
, length
, data
, &errorCode
);
257 udata_closeSwapper(ds
);
258 if(U_FAILURE(errorCode
)) {
259 fprintf(stderr
, "%s: udata_swap(\"%s\") failed - %s\n",
260 pname
, argv
[1], u_errorName(errorCode
));
265 out
=fopen(argv
[2], "wb");
267 fprintf(stderr
, "%s: unable to open output file \"%s\"\n", pname
, argv
[2]);
272 if(length
!=(int32_t)fwrite(data
, 1, length
, out
)) {
273 fprintf(stderr
, "%s: error writing \"%s\"\n", pname
, argv
[2]);
297 /* swap the data ------------------------------------------------------------ */
299 static const struct {
300 uint8_t dataFormat
[4];
303 { { 0x52, 0x65, 0x73, 0x42 }, ures_swap
}, /* dataFormat="ResB" */
304 #if !UCONFIG_NO_LEGACY_CONVERSION
305 { { 0x63, 0x6e, 0x76, 0x74 }, ucnv_swap
}, /* dataFormat="cnvt" */
306 { { 0x43, 0x76, 0x41, 0x6c }, ucnv_swapAliases
}, /* dataFormat="CvAl" */
308 { { 0x43, 0x6d, 0x6e, 0x44 }, udata_swapPackage
}, /* dataFormat="CmnD" */
310 { { 0x53, 0x50, 0x52, 0x50 }, usprep_swap
}, /* dataFormat="SPRP" */
312 /* insert data formats here, descending by expected frequency of occurrence */
313 { { 0x55, 0x50, 0x72, 0x6f }, uprops_swap
}, /* dataFormat="UPro" */
315 { { UCASE_FMT_0
, UCASE_FMT_1
, UCASE_FMT_2
, UCASE_FMT_3
},
316 ucase_swap
}, /* dataFormat="cAsE" */
318 #if !UCONFIG_NO_NORMALIZATION
319 { { 0x4e, 0x6f, 0x72, 0x6d }, unorm_swap
}, /* dataFormat="Norm" */
321 #if !UCONFIG_NO_COLLATION
322 { { 0x55, 0x43, 0x6f, 0x6c }, ucol_swap
}, /* dataFormat="UCol" */
323 { { 0x49, 0x6e, 0x76, 0x43 }, ucol_swapInverseUCA
},/* dataFormat="InvC" */
325 #if !UCONFIG_NO_BREAK_ITERATION
326 { { 0x42, 0x72, 0x6b, 0x20 }, ubrk_swap
}, /* dataFormat="Brk " */
328 { { 0x70, 0x6e, 0x61, 0x6d }, upname_swap
}, /* dataFormat="pnam" */
329 { { 0x75, 0x6e, 0x61, 0x6d }, uchar_swapNames
} /* dataFormat="unam" */
333 udata_swap(const UDataSwapper
*ds
,
334 const void *inData
, int32_t length
, void *outData
,
335 UErrorCode
*pErrorCode
) {
336 char dataFormatChars
[4];
337 const UDataInfo
*pInfo
;
338 int32_t headerSize
, i
, swappedLength
;
340 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
345 * Preflight the header first; checks for illegal arguments, too.
346 * Do not swap the header right away because the format-specific swapper
347 * will swap it, get the headerSize again, and also use the header
348 * information. Otherwise we would have to pass some of the information
349 * and not be able to use the UDataSwapFn signature.
351 headerSize
=udata_swapDataHeader(ds
, inData
, -1, NULL
, pErrorCode
);
354 * If we wanted udata_swap() to also handle non-loadable data like a UTrie,
355 * then we could check here for further known magic values and structures.
357 if(U_FAILURE(*pErrorCode
)) {
358 return 0; /* the data format was not recognized */
361 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
364 /* convert the data format from ASCII to Unicode to the system charset */
366 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
367 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3]
370 if(uprv_isInvariantUString(u
, 4)) {
371 u_UCharsToChars(u
, dataFormatChars
, 4);
373 dataFormatChars
[0]=dataFormatChars
[1]=dataFormatChars
[2]=dataFormatChars
[3]='?';
377 /* dispatch to the swap function for the dataFormat */
378 for(i
=0; i
<LENGTHOF(swapFns
); ++i
) {
379 if(0==memcmp(swapFns
[i
].dataFormat
, pInfo
->dataFormat
, 4)) {
380 swappedLength
=swapFns
[i
].swapFn(ds
, inData
, length
, outData
, pErrorCode
);
382 if(U_FAILURE(*pErrorCode
)) {
383 udata_printError(ds
, "udata_swap(): failure swapping data format %02x.%02x.%02x.%02x (\"%c%c%c%c\") - %s\n",
384 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
385 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
386 dataFormatChars
[0], dataFormatChars
[1],
387 dataFormatChars
[2], dataFormatChars
[3],
388 u_errorName(*pErrorCode
));
389 } else if(swappedLength
<(length
-15)) {
390 /* swapped less than expected */
391 udata_printError(ds
, "udata_swap() warning: swapped only %d out of %d bytes - data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
392 swappedLength
, length
,
393 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
394 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
395 dataFormatChars
[0], dataFormatChars
[1],
396 dataFormatChars
[2], dataFormatChars
[3],
397 u_errorName(*pErrorCode
));
400 return swappedLength
;
404 /* the dataFormat was not recognized */
405 udata_printError(ds
, "udata_swap(): unknown data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
406 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
407 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
408 dataFormatChars
[0], dataFormatChars
[1],
409 dataFormatChars
[2], dataFormatChars
[3]);
411 *pErrorCode
=U_UNSUPPORTED_ERROR
;
415 /* swap .dat package files -------------------------------------------------- */
418 extractPackageName(const UDataSwapper
*ds
, const char *filename
,
419 char pkg
[], int32_t capacity
,
420 UErrorCode
*pErrorCode
) {
421 const char *basename
;
424 if(U_FAILURE(*pErrorCode
)) {
428 basename
=findBasename(filename
);
429 len
=(int32_t)uprv_strlen(basename
)-4; /* -4: subtract the length of ".dat" */
431 if(len
<=0 || 0!=uprv_strcmp(basename
+len
, ".dat")) {
432 udata_printError(ds
, "udata_swapPackage(): \"%s\" is not recognized as a package filename (must end with .dat)\n",
434 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
439 udata_printError(ds
, "udata_swapPackage(): the package name \"%s\" is too long (>=%ld)\n",
441 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
445 uprv_memcpy(pkg
, basename
, len
);
451 uint32_t nameOffset
, inOffset
, outOffset
, length
;
455 static int32_t U_CALLCONV
456 compareToCEntries(const void *context
, const void *left
, const void *right
) {
457 const char *chars
=(const char *)context
;
458 return (int32_t)uprv_strcmp(chars
+((const ToCEntry
*)left
)->nameOffset
,
459 chars
+((const ToCEntry
*)right
)->nameOffset
);
463 U_CFUNC
int32_t U_CALLCONV
464 udata_swapPackage(const UDataSwapper
*ds
,
465 const void *inData
, int32_t length
, void *outData
,
466 UErrorCode
*pErrorCode
) {
467 const UDataInfo
*pInfo
;
470 const uint8_t *inBytes
;
473 uint32_t itemCount
, offset
, i
;
476 const UDataOffsetTOCEntry
*inEntries
;
477 UDataOffsetTOCEntry
*outEntries
;
481 char inPkgName
[32], outPkgName
[32];
482 int32_t inPkgNameLength
, outPkgNameLength
;
484 /* udata_swapDataHeader checks the arguments */
485 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
486 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
490 /* check data format and format version */
491 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
493 pInfo
->dataFormat
[0]==0x43 && /* dataFormat="CmnD" */
494 pInfo
->dataFormat
[1]==0x6d &&
495 pInfo
->dataFormat
[2]==0x6e &&
496 pInfo
->dataFormat
[3]==0x44 &&
497 pInfo
->formatVersion
[0]==1
499 udata_printError(ds
, "udata_swapPackage(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as an ICU .dat package\n",
500 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
501 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
502 pInfo
->formatVersion
[0]);
503 *pErrorCode
=U_UNSUPPORTED_ERROR
;
508 * We need to change the ToC name entries so that they have the correct
509 * package name prefix.
510 * Extract the package names from the in/out filenames.
512 inPkgNameLength
=extractPackageName(
514 inPkgName
, (int32_t)sizeof(inPkgName
),
516 outPkgNameLength
=extractPackageName(
518 outPkgName
, (int32_t)sizeof(outPkgName
),
520 if(U_FAILURE(*pErrorCode
)) {
525 * It is possible to work with inPkgNameLength!=outPkgNameLength,
526 * but then the length of the data file would change more significantly,
527 * which we are not currently prepared for.
529 if(inPkgNameLength
!=outPkgNameLength
) {
530 udata_printError(ds
, "udata_swapPackage(): the package names \"%s\" and \"%s\" must have the same length\n",
531 inPkgName
, outPkgName
);
532 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
536 inBytes
=(const uint8_t *)inData
+headerSize
;
537 inEntries
=(const UDataOffsetTOCEntry
*)(inBytes
+4);
541 itemCount
=ds
->readUInt32(*(const uint32_t *)inBytes
);
543 /* no items: count only the item count and return */
547 /* read the last item's offset and preflight it */
548 offset
=ds
->readUInt32(inEntries
[itemCount
-1].dataOffset
);
549 itemLength
=udata_swap(ds
, inBytes
+offset
, -1, NULL
, pErrorCode
);
551 if(U_SUCCESS(*pErrorCode
)) {
552 return headerSize
+offset
+(uint32_t)itemLength
;
557 /* check that the itemCount fits, then the ToC table, then at least the header of the last item */
560 /* itemCount does not fit */
562 itemCount
=0; /* make compilers happy */
564 itemCount
=ds
->readUInt32(*(const uint32_t *)inBytes
);
567 } else if((uint32_t)length
<(4+8*itemCount
)) {
568 /* ToC table does not fit */
571 /* offset of the last item plus at least 20 bytes for its header */
572 offset
=20+ds
->readUInt32(inEntries
[itemCount
-1].dataOffset
);
575 if((uint32_t)length
<offset
) {
576 udata_printError(ds
, "udata_swapPackage(): too few bytes (%d after header) for unames.icu\n",
578 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
582 outBytes
=(uint8_t *)outData
+headerSize
;
584 /* swap the item count */
585 ds
->swapArray32(ds
, inBytes
, 4, outBytes
, pErrorCode
);
588 /* no items: just return now */
592 /* swap the item name strings */
593 offset
=4+8*itemCount
;
594 itemLength
=(int32_t)(ds
->readUInt32(inEntries
[0].dataOffset
)-offset
);
595 udata_swapInvStringBlock(ds
, inBytes
+offset
, itemLength
, outBytes
+offset
, pErrorCode
);
596 if(U_FAILURE(*pErrorCode
)) {
597 udata_printError(ds
, "udata_swapPackage() failed to swap the data item name strings\n");
600 /* keep offset and itemLength in case we allocate and copy the strings below */
602 /* swap the package names into the output charset */
603 if(ds
->outCharset
!=U_CHARSET_FAMILY
) {
605 ds2
=udata_openSwapper(TRUE
, U_CHARSET_FAMILY
, TRUE
, ds
->outCharset
, pErrorCode
);
606 ds2
->swapInvChars(ds2
, inPkgName
, inPkgNameLength
, inPkgName
, pErrorCode
);
607 ds2
->swapInvChars(ds2
, outPkgName
, outPkgNameLength
, outPkgName
, pErrorCode
);
608 udata_closeSwapper(ds2
);
609 if(U_FAILURE(*pErrorCode
)) {
610 udata_printError(ds
, "udata_swapPackage() failed to swap the input/output package names\n");
614 /* change the prefix of each ToC entry name from the old to the new package name */
618 for(i
=0; i
<itemCount
; ++i
) {
619 entryName
=(char *)inBytes
+ds
->readUInt32(inEntries
[i
].nameOffset
);
621 if(0==uprv_memcmp(entryName
, inPkgName
, inPkgNameLength
)) {
622 uprv_memcpy(entryName
, outPkgName
, inPkgNameLength
);
624 udata_printError(ds
, "udata_swapPackage() failed: ToC item %ld does not have the input package name as a prefix\n",
626 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
633 * Allocate the ToC table and, if necessary, a temporary buffer for
634 * pseudo-in-place swapping.
636 * We cannot swap in-place because:
638 * 1. If the swapping of an item fails mid-way, then in-place swapping
639 * has destroyed its data.
640 * Out-of-place swapping allows us to then copy its original data.
642 * 2. If swapping changes the charset family, then we must resort
643 * not only the ToC table but also the data items themselves.
644 * This requires a permutation and is best done with separate in/out
647 * We swapped the strings above to avoid the malloc below if string swapping fails.
649 if(inData
==outData
) {
650 /* +15: prepare for extra padding of a newly-last item */
651 table
=(ToCEntry
*)uprv_malloc(itemCount
*sizeof(ToCEntry
)+length
+15);
653 outBytes
=(uint8_t *)(table
+itemCount
);
655 /* copy the item count and the swapped strings */
656 uprv_memcpy(outBytes
, inBytes
, 4);
657 uprv_memcpy(outBytes
+offset
, inBytes
+offset
, itemLength
);
660 table
=(ToCEntry
*)uprv_malloc(itemCount
*sizeof(ToCEntry
));
663 udata_printError(ds
, "udata_swapPackage(): out of memory allocating %d bytes\n",
665 itemCount
*sizeof(ToCEntry
)+length
+15 :
666 itemCount
*sizeof(ToCEntry
));
667 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
670 outEntries
=(UDataOffsetTOCEntry
*)(outBytes
+4);
672 /* read the ToC table */
673 for(i
=0; i
<itemCount
; ++i
) {
674 table
[i
].nameOffset
=ds
->readUInt32(inEntries
[i
].nameOffset
);
675 table
[i
].inOffset
=ds
->readUInt32(inEntries
[i
].dataOffset
);
677 table
[i
-1].length
=table
[i
].inOffset
-table
[i
-1].inOffset
;
680 table
[itemCount
-1].length
=(uint32_t)length
-table
[itemCount
-1].inOffset
;
682 if(ds
->inCharset
==ds
->outCharset
) {
683 /* no charset swapping, no resorting: keep item offsets the same */
684 for(i
=0; i
<itemCount
; ++i
) {
685 table
[i
].outOffset
=table
[i
].inOffset
;
688 /* charset swapping: resort items by their swapped names */
691 * Before the actual sorting, we need to make sure that each item
692 * has a length that is a multiple of 16 bytes so that all items
694 * Only the old last item may be missing up to 15 padding bytes.
695 * Add padding bytes for it.
696 * Since the icuswap main() function has already allocated enough
697 * input buffer space and set the last 15 bytes there to 0xaa,
698 * we only need to increase the total data length and the length
699 * of the last item here.
701 if((length
&0xf)!=0) {
702 int32_t delta
=16-(length
&0xf);
704 table
[itemCount
-1].length
+=(uint32_t)delta
;
707 uprv_sortArray(table
, (int32_t)itemCount
, (int32_t)sizeof(ToCEntry
),
708 compareToCEntries
, outBytes
, FALSE
, pErrorCode
);
711 * Note: Before sorting, the inOffset values were in order.
712 * Now the outOffset values are in order.
715 /* assign outOffset values */
716 offset
=table
[0].inOffset
;
717 for(i
=0; i
<itemCount
; ++i
) {
718 table
[i
].outOffset
=offset
;
719 offset
+=table
[i
].length
;
723 /* write the output ToC table */
724 for(i
=0; i
<itemCount
; ++i
) {
725 ds
->writeUInt32(&outEntries
[i
].nameOffset
, table
[i
].nameOffset
);
726 ds
->writeUInt32(&outEntries
[i
].dataOffset
, table
[i
].outOffset
);
729 /* swap each data item */
730 for(i
=0; i
<itemCount
; ++i
) {
731 /* first copy the item bytes to make sure that unreachable bytes are copied */
732 uprv_memcpy(outBytes
+table
[i
].outOffset
, inBytes
+table
[i
].inOffset
, table
[i
].length
);
735 udata_swap(ds
, inBytes
+table
[i
].inOffset
, (int32_t)table
[i
].length
,
736 outBytes
+table
[i
].outOffset
, pErrorCode
);
738 if(U_FAILURE(*pErrorCode
)) {
739 if(ds
->outCharset
==U_CHARSET_FAMILY
) {
740 udata_printError(ds
, "warning: udata_swapPackage() failed to swap item \"%s\"\n"
741 " at inOffset 0x%x length 0x%x - %s\n"
742 " the data item will be copied, not swapped\n\n",
743 (char *)outBytes
+table
[i
].nameOffset
,
744 table
[i
].inOffset
, table
[i
].length
, u_errorName(*pErrorCode
));
746 udata_printError(ds
, "warning: udata_swapPackage() failed to swap an item\n"
747 " at inOffset 0x%x length 0x%x - %s\n"
748 " the data item will be copied, not swapped\n\n",
749 table
[i
].inOffset
, table
[i
].length
, u_errorName(*pErrorCode
));
751 /* reset the error code, copy the data item, and continue */
752 *pErrorCode
=U_ZERO_ERROR
;
753 uprv_memcpy(outBytes
+table
[i
].outOffset
, inBytes
+table
[i
].inOffset
, table
[i
].length
);
757 if(inData
==outData
) {
758 /* copy the data from the temporary buffer to the in-place buffer */
759 uprv_memcpy((uint8_t *)outData
+headerSize
, outBytes
, length
);
763 return headerSize
+length
;
768 * Hey, Emacs, please set the following:
771 * indent-tabs-mode: nil