1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 2003-2015, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: ucol_swp.cpp
12 * tab size: 8 (not used)
15 * created on: 2003sep10
16 * created by: Markus W. Scherer
18 * Swap collation binaries.
21 #include "unicode/udata.h" /* UDataInfo */
26 #include "ucol_data.h"
29 /* swapping ----------------------------------------------------------------- */
31 #if !UCONFIG_NO_COLLATION
33 U_CAPI UBool U_EXPORT2
34 ucol_looksLikeCollationBinary(const UDataSwapper
*ds
,
35 const void *inData
, int32_t length
) {
36 if(ds
==NULL
|| inData
==NULL
|| length
<-1) {
40 // First check for format version 4+ which has a standard data header.
41 UErrorCode errorCode
=U_ZERO_ERROR
;
42 (void)udata_swapDataHeader(ds
, inData
, -1, NULL
, &errorCode
);
43 if(U_SUCCESS(errorCode
)) {
44 const UDataInfo
&info
=*(const UDataInfo
*)((const char *)inData
+4);
45 if(info
.dataFormat
[0]==0x55 && // dataFormat="UCol"
46 info
.dataFormat
[1]==0x43 &&
47 info
.dataFormat
[2]==0x6f &&
48 info
.dataFormat
[3]==0x6c) {
53 // Else check for format version 3.
54 const UCATableHeader
*inHeader
=(const UCATableHeader
*)inData
;
57 * The collation binary must contain at least the UCATableHeader,
58 * starting with its size field.
59 * sizeof(UCATableHeader)==42*4 in ICU 2.8
60 * check the length against the header size before reading the size field
62 UCATableHeader header
;
63 uprv_memset(&header
, 0, sizeof(header
));
65 header
.size
=udata_readInt32(ds
, inHeader
->size
);
66 } else if((length
<(42*4) || length
<(header
.size
=udata_readInt32(ds
, inHeader
->size
)))) {
70 header
.magic
=ds
->readUInt32(inHeader
->magic
);
72 header
.magic
==UCOL_HEADER_MAGIC
&&
73 inHeader
->formatVersion
[0]==3 /*&&
74 inHeader->formatVersion[1]>=0*/
79 if(inHeader
->isBigEndian
!=ds
->inIsBigEndian
|| inHeader
->charSetFamily
!=ds
->inCharset
) {
88 /* swap a header-less collation formatVersion=3 binary, inside a resource bundle or ucadata.icu */
90 swapFormatVersion3(const UDataSwapper
*ds
,
91 const void *inData
, int32_t length
, void *outData
,
92 UErrorCode
*pErrorCode
) {
93 const uint8_t *inBytes
;
96 const UCATableHeader
*inHeader
;
97 UCATableHeader
*outHeader
;
98 UCATableHeader header
;
102 /* argument checking in case we were not called from ucol_swap() */
103 if(U_FAILURE(*pErrorCode
)) {
106 if(ds
==NULL
|| inData
==NULL
|| length
<-1 || (length
>0 && outData
==NULL
)) {
107 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
111 inBytes
=(const uint8_t *)inData
;
112 outBytes
=(uint8_t *)outData
;
114 inHeader
=(const UCATableHeader
*)inData
;
115 outHeader
=(UCATableHeader
*)outData
;
118 * The collation binary must contain at least the UCATableHeader,
119 * starting with its size field.
120 * sizeof(UCATableHeader)==42*4 in ICU 2.8
121 * check the length against the header size before reading the size field
123 uprv_memset(&header
, 0, sizeof(header
));
125 header
.size
=udata_readInt32(ds
, inHeader
->size
);
126 } else if((length
<(42*4) || length
<(header
.size
=udata_readInt32(ds
, inHeader
->size
)))) {
127 udata_printError(ds
, "ucol_swap(formatVersion=3): too few bytes (%d after header) for collation data\n",
129 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
133 header
.magic
=ds
->readUInt32(inHeader
->magic
);
135 header
.magic
==UCOL_HEADER_MAGIC
&&
136 inHeader
->formatVersion
[0]==3 /*&&
137 inHeader->formatVersion[1]>=0*/
139 udata_printError(ds
, "ucol_swap(formatVersion=3): magic 0x%08x or format version %02x.%02x is not a collation binary\n",
141 inHeader
->formatVersion
[0], inHeader
->formatVersion
[1]);
142 *pErrorCode
=U_UNSUPPORTED_ERROR
;
146 if(inHeader
->isBigEndian
!=ds
->inIsBigEndian
|| inHeader
->charSetFamily
!=ds
->inCharset
) {
147 udata_printError(ds
, "ucol_swap(formatVersion=3): endianness %d or charset %d does not match the swapper\n",
148 inHeader
->isBigEndian
, inHeader
->charSetFamily
);
149 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
154 /* copy everything, takes care of data that needs no swapping */
155 if(inBytes
!=outBytes
) {
156 uprv_memcpy(outBytes
, inBytes
, header
.size
);
159 /* swap the necessary pieces in the order of their occurrence in the data */
161 /* read more of the UCATableHeader (the size field was read above) */
162 header
.options
= ds
->readUInt32(inHeader
->options
);
163 header
.UCAConsts
= ds
->readUInt32(inHeader
->UCAConsts
);
164 header
.contractionUCACombos
= ds
->readUInt32(inHeader
->contractionUCACombos
);
165 header
.mappingPosition
= ds
->readUInt32(inHeader
->mappingPosition
);
166 header
.expansion
= ds
->readUInt32(inHeader
->expansion
);
167 header
.contractionIndex
= ds
->readUInt32(inHeader
->contractionIndex
);
168 header
.contractionCEs
= ds
->readUInt32(inHeader
->contractionCEs
);
169 header
.contractionSize
= ds
->readUInt32(inHeader
->contractionSize
);
170 header
.endExpansionCE
= ds
->readUInt32(inHeader
->endExpansionCE
);
171 header
.expansionCESize
= ds
->readUInt32(inHeader
->expansionCESize
);
172 header
.endExpansionCECount
= udata_readInt32(ds
, inHeader
->endExpansionCECount
);
173 header
.contractionUCACombosSize
=udata_readInt32(ds
, inHeader
->contractionUCACombosSize
);
174 header
.scriptToLeadByte
= ds
->readUInt32(inHeader
->scriptToLeadByte
);
175 header
.leadByteToScript
= ds
->readUInt32(inHeader
->leadByteToScript
);
177 /* swap the 32-bit integers in the header */
178 ds
->swapArray32(ds
, inHeader
, (int32_t)((const char *)&inHeader
->jamoSpecial
-(const char *)inHeader
),
179 outHeader
, pErrorCode
);
180 ds
->swapArray32(ds
, &(inHeader
->scriptToLeadByte
), sizeof(header
.scriptToLeadByte
) + sizeof(header
.leadByteToScript
),
181 &(outHeader
->scriptToLeadByte
), pErrorCode
);
182 /* set the output platform properties */
183 outHeader
->isBigEndian
=ds
->outIsBigEndian
;
184 outHeader
->charSetFamily
=ds
->outCharset
;
186 /* swap the options */
187 if(header
.options
!=0) {
188 ds
->swapArray32(ds
, inBytes
+header
.options
, header
.expansion
-header
.options
,
189 outBytes
+header
.options
, pErrorCode
);
192 /* swap the expansions */
193 if(header
.mappingPosition
!=0 && header
.expansion
!=0) {
194 if(header
.contractionIndex
!=0) {
195 /* expansions bounded by contractions */
196 count
=header
.contractionIndex
-header
.expansion
;
198 /* no contractions: expansions bounded by the main trie */
199 count
=header
.mappingPosition
-header
.expansion
;
201 ds
->swapArray32(ds
, inBytes
+header
.expansion
, (int32_t)count
,
202 outBytes
+header
.expansion
, pErrorCode
);
205 /* swap the contractions */
206 if(header
.contractionSize
!=0) {
207 /* contractionIndex: UChar[] */
208 ds
->swapArray16(ds
, inBytes
+header
.contractionIndex
, header
.contractionSize
*2,
209 outBytes
+header
.contractionIndex
, pErrorCode
);
211 /* contractionCEs: CEs[] */
212 ds
->swapArray32(ds
, inBytes
+header
.contractionCEs
, header
.contractionSize
*4,
213 outBytes
+header
.contractionCEs
, pErrorCode
);
216 /* swap the main trie */
217 if(header
.mappingPosition
!=0) {
218 count
=header
.endExpansionCE
-header
.mappingPosition
;
219 utrie_swap(ds
, inBytes
+header
.mappingPosition
, (int32_t)count
,
220 outBytes
+header
.mappingPosition
, pErrorCode
);
223 /* swap the max expansion table */
224 if(header
.endExpansionCECount
!=0) {
225 ds
->swapArray32(ds
, inBytes
+header
.endExpansionCE
, header
.endExpansionCECount
*4,
226 outBytes
+header
.endExpansionCE
, pErrorCode
);
229 /* expansionCESize, unsafeCP, contrEndCP: uint8_t[], no need to swap */
231 /* swap UCA constants */
232 if(header
.UCAConsts
!=0) {
234 * if UCAConsts!=0 then contractionUCACombos because we are swapping
235 * the UCA data file, and we know that the UCA contains contractions
237 ds
->swapArray32(ds
, inBytes
+header
.UCAConsts
, header
.contractionUCACombos
-header
.UCAConsts
,
238 outBytes
+header
.UCAConsts
, pErrorCode
);
241 /* swap UCA contractions */
242 if(header
.contractionUCACombosSize
!=0) {
243 count
=header
.contractionUCACombosSize
*inHeader
->contractionUCACombosWidth
*U_SIZEOF_UCHAR
;
244 ds
->swapArray16(ds
, inBytes
+header
.contractionUCACombos
, (int32_t)count
,
245 outBytes
+header
.contractionUCACombos
, pErrorCode
);
248 /* swap the script to lead bytes */
249 if(header
.scriptToLeadByte
!=0) {
250 int indexCount
= ds
->readUInt16(*((uint16_t*)(inBytes
+header
.scriptToLeadByte
))); // each entry = 2 * uint16
251 int dataCount
= ds
->readUInt16(*((uint16_t*)(inBytes
+header
.scriptToLeadByte
+ 2))); // each entry = uint16
252 ds
->swapArray16(ds
, inBytes
+header
.scriptToLeadByte
,
253 4 + (4 * indexCount
) + (2 * dataCount
),
254 outBytes
+header
.scriptToLeadByte
, pErrorCode
);
257 /* swap the lead byte to scripts */
258 if(header
.leadByteToScript
!=0) {
259 int indexCount
= ds
->readUInt16(*((uint16_t*)(inBytes
+header
.leadByteToScript
))); // each entry = uint16
260 int dataCount
= ds
->readUInt16(*((uint16_t*)(inBytes
+header
.leadByteToScript
+ 2))); // each entry = uint16
261 ds
->swapArray16(ds
, inBytes
+header
.leadByteToScript
,
262 4 + (2 * indexCount
) + (2 * dataCount
),
263 outBytes
+header
.leadByteToScript
, pErrorCode
);
270 // swap formatVersion 4 or 5 ----------------------------------------------- ***
272 // The following are copied from CollationDataReader, trading an awkward copy of constants
273 // for an awkward relocation of the i18n collationdatareader.h file into the common library.
274 // Keep them in sync!
277 IX_INDEXES_LENGTH
, // 0
282 IX_JAMO_CE32S_START
, // 4
283 IX_REORDER_CODES_OFFSET
,
284 IX_REORDER_TABLE_OFFSET
,
287 IX_RESERVED8_OFFSET
, // 8
289 IX_RESERVED10_OFFSET
,
292 IX_ROOT_ELEMENTS_OFFSET
, // 12
294 IX_UNSAFE_BWD_OFFSET
,
295 IX_FAST_LATIN_TABLE_OFFSET
,
297 IX_SCRIPTS_OFFSET
, // 16
298 IX_COMPRESSIBLE_BYTES_OFFSET
,
299 IX_RESERVED18_OFFSET
,
304 swapFormatVersion4(const UDataSwapper
*ds
,
305 const void *inData
, int32_t length
, void *outData
,
306 UErrorCode
&errorCode
) {
307 if(U_FAILURE(errorCode
)) { return 0; }
309 const uint8_t *inBytes
=(const uint8_t *)inData
;
310 uint8_t *outBytes
=(uint8_t *)outData
;
312 const int32_t *inIndexes
=(const int32_t *)inBytes
;
313 int32_t indexes
[IX_TOTAL_SIZE
+1];
315 // Need at least IX_INDEXES_LENGTH and IX_OPTIONS.
316 if(0<=length
&& length
<8) {
317 udata_printError(ds
, "ucol_swap(formatVersion=4): too few bytes "
318 "(%d after header) for collation data\n",
320 errorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
324 int32_t indexesLength
=indexes
[0]=udata_readInt32(ds
, inIndexes
[0]);
325 if(0<=length
&& length
<(indexesLength
*4)) {
326 udata_printError(ds
, "ucol_swap(formatVersion=4): too few bytes "
327 "(%d after header) for collation data\n",
329 errorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
333 for(int32_t i
=1; i
<=IX_TOTAL_SIZE
&& i
<indexesLength
; ++i
) {
334 indexes
[i
]=udata_readInt32(ds
, inIndexes
[i
]);
336 for(int32_t i
=indexesLength
; i
<=IX_TOTAL_SIZE
; ++i
) {
339 inIndexes
=NULL
; // Make sure we do not accidentally use these instead of indexes[].
341 // Get the total length of the data.
343 if(indexesLength
>IX_TOTAL_SIZE
) {
344 size
=indexes
[IX_TOTAL_SIZE
];
345 } else if(indexesLength
>IX_REORDER_CODES_OFFSET
) {
346 size
=indexes
[indexesLength
-1];
348 size
=indexesLength
*4;
350 if(length
<0) { return size
; }
353 udata_printError(ds
, "ucol_swap(formatVersion=4): too few bytes "
354 "(%d after header) for collation data\n",
356 errorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
360 // Copy the data for inaccessible bytes and arrays of bytes.
361 if(inBytes
!=outBytes
) {
362 uprv_memcpy(outBytes
, inBytes
, size
);
365 // Swap the int32_t indexes[].
366 ds
->swapArray32(ds
, inBytes
, indexesLength
* 4, outBytes
, &errorCode
);
368 // The following is a modified version of CollationDataReader::read().
369 // Here we use indexes[] not inIndexes[] because
370 // the inIndexes[] may not be in this machine's endianness.
371 int32_t index
; // one of the indexes[] slots
372 int32_t offset
; // byte offset for the index part
373 // int32_t length; // number of bytes in the index part
375 index
= IX_REORDER_CODES_OFFSET
;
376 offset
= indexes
[index
];
377 length
= indexes
[index
+ 1] - offset
;
379 ds
->swapArray32(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
382 // Skip the IX_REORDER_TABLE_OFFSET byte array.
384 index
= IX_TRIE_OFFSET
;
385 offset
= indexes
[index
];
386 length
= indexes
[index
+ 1] - offset
;
388 utrie2_swap(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
391 index
= IX_RESERVED8_OFFSET
;
392 offset
= indexes
[index
];
393 length
= indexes
[index
+ 1] - offset
;
395 udata_printError(ds
, "ucol_swap(formatVersion=4): unknown data at IX_RESERVED8_OFFSET\n", length
);
396 errorCode
= U_UNSUPPORTED_ERROR
;
400 index
= IX_CES_OFFSET
;
401 offset
= indexes
[index
];
402 length
= indexes
[index
+ 1] - offset
;
404 ds
->swapArray64(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
407 index
= IX_RESERVED10_OFFSET
;
408 offset
= indexes
[index
];
409 length
= indexes
[index
+ 1] - offset
;
411 udata_printError(ds
, "ucol_swap(formatVersion=4): unknown data at IX_RESERVED10_OFFSET\n", length
);
412 errorCode
= U_UNSUPPORTED_ERROR
;
416 index
= IX_CE32S_OFFSET
;
417 offset
= indexes
[index
];
418 length
= indexes
[index
+ 1] - offset
;
420 ds
->swapArray32(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
423 index
= IX_ROOT_ELEMENTS_OFFSET
;
424 offset
= indexes
[index
];
425 length
= indexes
[index
+ 1] - offset
;
427 ds
->swapArray32(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
430 index
= IX_CONTEXTS_OFFSET
;
431 offset
= indexes
[index
];
432 length
= indexes
[index
+ 1] - offset
;
434 ds
->swapArray16(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
437 index
= IX_UNSAFE_BWD_OFFSET
;
438 offset
= indexes
[index
];
439 length
= indexes
[index
+ 1] - offset
;
441 ds
->swapArray16(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
444 index
= IX_FAST_LATIN_TABLE_OFFSET
;
445 offset
= indexes
[index
];
446 length
= indexes
[index
+ 1] - offset
;
448 ds
->swapArray16(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
451 index
= IX_SCRIPTS_OFFSET
;
452 offset
= indexes
[index
];
453 length
= indexes
[index
+ 1] - offset
;
455 ds
->swapArray16(ds
, inBytes
+ offset
, length
, outBytes
+ offset
, &errorCode
);
458 // Skip the IX_COMPRESSIBLE_BYTES_OFFSET byte array.
460 index
= IX_RESERVED18_OFFSET
;
461 offset
= indexes
[index
];
462 length
= indexes
[index
+ 1] - offset
;
464 udata_printError(ds
, "ucol_swap(formatVersion=4): unknown data at IX_RESERVED18_OFFSET\n", length
);
465 errorCode
= U_UNSUPPORTED_ERROR
;
474 /* swap ICU collation data like ucadata.icu */
475 U_CAPI
int32_t U_EXPORT2
476 ucol_swap(const UDataSwapper
*ds
,
477 const void *inData
, int32_t length
, void *outData
,
478 UErrorCode
*pErrorCode
) {
479 if(U_FAILURE(*pErrorCode
)) { return 0; }
481 /* udata_swapDataHeader checks the arguments */
482 int32_t headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
483 if(U_FAILURE(*pErrorCode
)) {
484 // Try to swap the old format version which did not have a standard data header.
485 *pErrorCode
=U_ZERO_ERROR
;
486 return swapFormatVersion3(ds
, inData
, length
, outData
, pErrorCode
);
489 /* check data format and format version */
490 const UDataInfo
&info
=*(const UDataInfo
*)((const char *)inData
+4);
492 info
.dataFormat
[0]==0x55 && // dataFormat="UCol"
493 info
.dataFormat
[1]==0x43 &&
494 info
.dataFormat
[2]==0x6f &&
495 info
.dataFormat
[3]==0x6c &&
496 (3<=info
.formatVersion
[0] && info
.formatVersion
[0]<=5)
498 udata_printError(ds
, "ucol_swap(): data format %02x.%02x.%02x.%02x "
499 "(format version %02x.%02x) is not recognized as collation data\n",
500 info
.dataFormat
[0], info
.dataFormat
[1],
501 info
.dataFormat
[2], info
.dataFormat
[3],
502 info
.formatVersion
[0], info
.formatVersion
[1]);
503 *pErrorCode
=U_UNSUPPORTED_ERROR
;
507 inData
=(const char *)inData
+headerSize
;
508 if(length
>=0) { length
-=headerSize
; }
509 outData
=(char *)outData
+headerSize
;
510 int32_t collationSize
;
511 if(info
.formatVersion
[0]>=4) {
512 collationSize
=swapFormatVersion4(ds
, inData
, length
, outData
, *pErrorCode
);
514 collationSize
=swapFormatVersion3(ds
, inData
, length
, outData
, pErrorCode
);
516 if(U_SUCCESS(*pErrorCode
)) {
517 return headerSize
+collationSize
;
523 /* swap inverse UCA collation data (invuca.icu) */
524 U_CAPI
int32_t U_EXPORT2
525 ucol_swapInverseUCA(const UDataSwapper
*ds
,
526 const void *inData
, int32_t length
, void *outData
,
527 UErrorCode
*pErrorCode
) {
528 const UDataInfo
*pInfo
;
531 const uint8_t *inBytes
;
534 const InverseUCATableHeader
*inHeader
;
535 InverseUCATableHeader
*outHeader
;
536 InverseUCATableHeader header
={ 0,0,0,0,0,{0,0,0,0},{0,0,0,0,0,0,0,0} };
538 /* udata_swapDataHeader checks the arguments */
539 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
540 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
544 /* check data format and format version */
545 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
547 pInfo
->dataFormat
[0]==0x49 && /* dataFormat="InvC" */
548 pInfo
->dataFormat
[1]==0x6e &&
549 pInfo
->dataFormat
[2]==0x76 &&
550 pInfo
->dataFormat
[3]==0x43 &&
551 pInfo
->formatVersion
[0]==2 &&
552 pInfo
->formatVersion
[1]>=1
554 udata_printError(ds
, "ucol_swapInverseUCA(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not an inverse UCA collation file\n",
555 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
556 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
557 pInfo
->formatVersion
[0], pInfo
->formatVersion
[1]);
558 *pErrorCode
=U_UNSUPPORTED_ERROR
;
562 inBytes
=(const uint8_t *)inData
+headerSize
;
563 outBytes
=(uint8_t *)outData
+headerSize
;
565 inHeader
=(const InverseUCATableHeader
*)inBytes
;
566 outHeader
=(InverseUCATableHeader
*)outBytes
;
569 * The inverse UCA collation binary must contain at least the InverseUCATableHeader,
570 * starting with its size field.
571 * sizeof(UCATableHeader)==8*4 in ICU 2.8
572 * check the length against the header size before reading the size field
575 header
.byteSize
=udata_readInt32(ds
, inHeader
->byteSize
);
577 ((length
-headerSize
)<(8*4) ||
578 (uint32_t)(length
-headerSize
)<(header
.byteSize
=udata_readInt32(ds
, inHeader
->byteSize
)))
580 udata_printError(ds
, "ucol_swapInverseUCA(): too few bytes (%d after header) for inverse UCA collation data\n",
582 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
587 /* copy everything, takes care of data that needs no swapping */
588 if(inBytes
!=outBytes
) {
589 uprv_memcpy(outBytes
, inBytes
, header
.byteSize
);
592 /* swap the necessary pieces in the order of their occurrence in the data */
594 /* read more of the InverseUCATableHeader (the byteSize field was read above) */
595 header
.tableSize
= ds
->readUInt32(inHeader
->tableSize
);
596 header
.contsSize
= ds
->readUInt32(inHeader
->contsSize
);
597 header
.table
= ds
->readUInt32(inHeader
->table
);
598 header
.conts
= ds
->readUInt32(inHeader
->conts
);
600 /* swap the 32-bit integers in the header */
601 ds
->swapArray32(ds
, inHeader
, 5*4, outHeader
, pErrorCode
);
603 /* swap the inverse table; tableSize counts uint32_t[3] rows */
604 ds
->swapArray32(ds
, inBytes
+header
.table
, header
.tableSize
*3*4,
605 outBytes
+header
.table
, pErrorCode
);
607 /* swap the continuation table; contsSize counts UChars */
608 ds
->swapArray16(ds
, inBytes
+header
.conts
, header
.contsSize
*U_SIZEOF_UCHAR
,
609 outBytes
+header
.conts
, pErrorCode
);
612 return headerSize
+header
.byteSize
;
615 #endif /* #if !UCONFIG_NO_COLLATION */