1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 2003-2014, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: udataswp.c
12 * tab size: 8 (not used)
15 * created on: 2003jun05
16 * created by: Markus W. Scherer
18 * Definitions for ICU data transformations for different platforms,
19 * changing between big- and little-endian data and/or between
20 * charset families (ASCII<->EBCDIC).
24 #include "unicode/utypes.h"
25 #include "unicode/udata.h" /* UDataInfo */
26 #include "ucmndata.h" /* DataHeader */
30 /* swapping primitives ------------------------------------------------------ */
32 static int32_t U_CALLCONV
33 uprv_swapArray16(const UDataSwapper
*ds
,
34 const void *inData
, int32_t length
, void *outData
,
35 UErrorCode
*pErrorCode
) {
41 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
44 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&1)!=0 || outData
==NULL
) {
45 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
49 /* setup and swapping */
50 p
=(const uint16_t *)inData
;
51 q
=(uint16_t *)outData
;
55 *q
++=(uint16_t)((x
<<8)|(x
>>8));
62 static int32_t U_CALLCONV
63 uprv_copyArray16(const UDataSwapper
*ds
,
64 const void *inData
, int32_t length
, void *outData
,
65 UErrorCode
*pErrorCode
) {
66 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
69 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&1)!=0 || outData
==NULL
) {
70 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
74 if(length
>0 && inData
!=outData
) {
75 uprv_memcpy(outData
, inData
, length
);
80 static int32_t U_CALLCONV
81 uprv_swapArray32(const UDataSwapper
*ds
,
82 const void *inData
, int32_t length
, void *outData
,
83 UErrorCode
*pErrorCode
) {
89 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
92 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&3)!=0 || outData
==NULL
) {
93 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
97 /* setup and swapping */
98 p
=(const uint32_t *)inData
;
99 q
=(uint32_t *)outData
;
103 *q
++=(uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
110 static int32_t U_CALLCONV
111 uprv_copyArray32(const UDataSwapper
*ds
,
112 const void *inData
, int32_t length
, void *outData
,
113 UErrorCode
*pErrorCode
) {
114 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
117 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&3)!=0 || outData
==NULL
) {
118 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
122 if(length
>0 && inData
!=outData
) {
123 uprv_memcpy(outData
, inData
, length
);
128 static int32_t U_CALLCONV
129 uprv_swapArray64(const UDataSwapper
*ds
,
130 const void *inData
, int32_t length
, void *outData
,
131 UErrorCode
*pErrorCode
) {
136 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
139 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&7)!=0 || outData
==NULL
) {
140 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
144 /* setup and swapping */
145 p
=(const uint64_t *)inData
;
146 q
=(uint64_t *)outData
;
150 x
=(x
<<56)|((x
&0xff00)<<40)|((x
&0xff0000)<<24)|((x
&0xff000000)<<8)|
151 ((x
>>8)&0xff000000)|((x
>>24)&0xff0000)|((x
>>40)&0xff00)|(x
>>56);
159 static int32_t U_CALLCONV
160 uprv_copyArray64(const UDataSwapper
*ds
,
161 const void *inData
, int32_t length
, void *outData
,
162 UErrorCode
*pErrorCode
) {
163 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
166 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&7)!=0 || outData
==NULL
) {
167 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
171 if(length
>0 && inData
!=outData
) {
172 uprv_memcpy(outData
, inData
, length
);
177 static uint16_t U_CALLCONV
178 uprv_readSwapUInt16(uint16_t x
) {
179 return (uint16_t)((x
<<8)|(x
>>8));
182 static uint16_t U_CALLCONV
183 uprv_readDirectUInt16(uint16_t x
) {
187 static uint32_t U_CALLCONV
188 uprv_readSwapUInt32(uint32_t x
) {
189 return (uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
192 static uint32_t U_CALLCONV
193 uprv_readDirectUInt32(uint32_t x
) {
197 static void U_CALLCONV
198 uprv_writeSwapUInt16(uint16_t *p
, uint16_t x
) {
199 *p
=(uint16_t)((x
<<8)|(x
>>8));
202 static void U_CALLCONV
203 uprv_writeDirectUInt16(uint16_t *p
, uint16_t x
) {
207 static void U_CALLCONV
208 uprv_writeSwapUInt32(uint32_t *p
, uint32_t x
) {
209 *p
=(uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
212 static void U_CALLCONV
213 uprv_writeDirectUInt32(uint32_t *p
, uint32_t x
) {
217 U_CAPI
int16_t U_EXPORT2
218 udata_readInt16(const UDataSwapper
*ds
, int16_t x
) {
219 return (int16_t)ds
->readUInt16((uint16_t)x
);
222 U_CAPI
int32_t U_EXPORT2
223 udata_readInt32(const UDataSwapper
*ds
, int32_t x
) {
224 return (int32_t)ds
->readUInt32((uint32_t)x
);
228 * Swap a block of invariant, NUL-terminated strings, but not padding
229 * bytes after the last string.
232 U_CAPI
int32_t U_EXPORT2
233 udata_swapInvStringBlock(const UDataSwapper
*ds
,
234 const void *inData
, int32_t length
, void *outData
,
235 UErrorCode
*pErrorCode
) {
237 int32_t stringsLength
;
239 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
242 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
>0 && outData
==NULL
)) {
243 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
247 /* reduce the strings length to not include bytes after the last NUL */
248 inChars
=(const char *)inData
;
249 stringsLength
=length
;
250 while(stringsLength
>0 && inChars
[stringsLength
-1]!=0) {
254 /* swap up to the last NUL */
255 ds
->swapInvChars(ds
, inData
, stringsLength
, outData
, pErrorCode
);
257 /* copy the bytes after the last NUL */
258 if(inData
!=outData
&& length
>stringsLength
) {
259 uprv_memcpy((char *)outData
+stringsLength
, inChars
+stringsLength
, length
-stringsLength
);
262 /* return the length including padding bytes */
263 if(U_SUCCESS(*pErrorCode
)) {
270 U_CAPI
void U_EXPORT2
271 udata_printError(const UDataSwapper
*ds
,
276 if(ds
->printError
!=NULL
) {
278 ds
->printError(ds
->printErrorContext
, fmt
, args
);
283 /* swap a data header ------------------------------------------------------- */
285 U_CAPI
int32_t U_EXPORT2
286 udata_swapDataHeader(const UDataSwapper
*ds
,
287 const void *inData
, int32_t length
, void *outData
,
288 UErrorCode
*pErrorCode
) {
289 const DataHeader
*pHeader
;
290 uint16_t headerSize
, infoSize
;
292 /* argument checking */
293 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
296 if(ds
==NULL
|| inData
==NULL
|| length
<-1 || (length
>0 && outData
==NULL
)) {
297 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
301 /* check minimum length and magic bytes */
302 pHeader
=(const DataHeader
*)inData
;
303 if( (length
>=0 && length
<(int32_t)sizeof(DataHeader
)) ||
304 pHeader
->dataHeader
.magic1
!=0xda ||
305 pHeader
->dataHeader
.magic2
!=0x27 ||
306 pHeader
->info
.sizeofUChar
!=2
308 udata_printError(ds
, "udata_swapDataHeader(): initial bytes do not look like ICU data\n");
309 *pErrorCode
=U_UNSUPPORTED_ERROR
;
313 headerSize
=ds
->readUInt16(pHeader
->dataHeader
.headerSize
);
314 infoSize
=ds
->readUInt16(pHeader
->info
.size
);
316 if( headerSize
<sizeof(DataHeader
) ||
317 infoSize
<sizeof(UDataInfo
) ||
318 headerSize
<(sizeof(pHeader
->dataHeader
)+infoSize
) ||
319 (length
>=0 && length
<headerSize
)
321 udata_printError(ds
, "udata_swapDataHeader(): header size mismatch - headerSize %d infoSize %d length %d\n",
322 headerSize
, infoSize
, length
);
323 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
328 DataHeader
*outHeader
;
332 /* Most of the fields are just bytes and need no swapping. */
333 if(inData
!=outData
) {
334 uprv_memcpy(outData
, inData
, headerSize
);
336 outHeader
=(DataHeader
*)outData
;
338 outHeader
->info
.isBigEndian
= ds
->outIsBigEndian
;
339 outHeader
->info
.charsetFamily
= ds
->outCharset
;
341 /* swap headerSize */
342 ds
->swapArray16(ds
, &pHeader
->dataHeader
.headerSize
, 2, &outHeader
->dataHeader
.headerSize
, pErrorCode
);
344 /* swap UDataInfo size and reservedWord */
345 ds
->swapArray16(ds
, &pHeader
->info
.size
, 4, &outHeader
->info
.size
, pErrorCode
);
347 /* swap copyright statement after the UDataInfo */
348 infoSize
+=sizeof(pHeader
->dataHeader
);
349 s
=(const char *)inData
+infoSize
;
350 maxLength
=headerSize
-infoSize
;
351 /* get the length of the string */
352 for(length
=0; length
<maxLength
&& s
[length
]!=0; ++length
) {}
353 /* swap the string contents */
354 ds
->swapInvChars(ds
, s
, length
, (char *)outData
+infoSize
, pErrorCode
);
360 /* API functions ------------------------------------------------------------ */
362 U_CAPI UDataSwapper
* U_EXPORT2
363 udata_openSwapper(UBool inIsBigEndian
, uint8_t inCharset
,
364 UBool outIsBigEndian
, uint8_t outCharset
,
365 UErrorCode
*pErrorCode
) {
366 UDataSwapper
*swapper
;
368 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
371 if(inCharset
>U_EBCDIC_FAMILY
|| outCharset
>U_EBCDIC_FAMILY
) {
372 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
376 /* allocate the swapper */
377 swapper
=(UDataSwapper
*)uprv_malloc(sizeof(UDataSwapper
));
379 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
382 uprv_memset(swapper
, 0, sizeof(UDataSwapper
));
384 /* set values and functions pointers according to in/out parameters */
385 swapper
->inIsBigEndian
=inIsBigEndian
;
386 swapper
->inCharset
=inCharset
;
387 swapper
->outIsBigEndian
=outIsBigEndian
;
388 swapper
->outCharset
=outCharset
;
390 swapper
->readUInt16
= inIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_readDirectUInt16
: uprv_readSwapUInt16
;
391 swapper
->readUInt32
= inIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_readDirectUInt32
: uprv_readSwapUInt32
;
393 swapper
->writeUInt16
= outIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_writeDirectUInt16
: uprv_writeSwapUInt16
;
394 swapper
->writeUInt32
= outIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_writeDirectUInt32
: uprv_writeSwapUInt32
;
396 swapper
->compareInvChars
= outCharset
==U_ASCII_FAMILY
? uprv_compareInvAscii
: uprv_compareInvEbcdic
;
398 if(inIsBigEndian
==outIsBigEndian
) {
399 swapper
->swapArray16
=uprv_copyArray16
;
400 swapper
->swapArray32
=uprv_copyArray32
;
401 swapper
->swapArray64
=uprv_copyArray64
;
403 swapper
->swapArray16
=uprv_swapArray16
;
404 swapper
->swapArray32
=uprv_swapArray32
;
405 swapper
->swapArray64
=uprv_swapArray64
;
408 if(inCharset
==U_ASCII_FAMILY
) {
409 swapper
->swapInvChars
= outCharset
==U_ASCII_FAMILY
? uprv_copyAscii
: uprv_ebcdicFromAscii
;
410 } else /* U_EBCDIC_FAMILY */ {
411 swapper
->swapInvChars
= outCharset
==U_EBCDIC_FAMILY
? uprv_copyEbcdic
: uprv_asciiFromEbcdic
;
417 U_CAPI UDataSwapper
* U_EXPORT2
418 udata_openSwapperForInputData(const void *data
, int32_t length
,
419 UBool outIsBigEndian
, uint8_t outCharset
,
420 UErrorCode
*pErrorCode
) {
421 const DataHeader
*pHeader
;
422 uint16_t headerSize
, infoSize
;
426 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
430 (length
>=0 && length
<(int32_t)sizeof(DataHeader
)) ||
431 outCharset
>U_EBCDIC_FAMILY
433 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
437 pHeader
=(const DataHeader
*)data
;
438 if( (length
>=0 && length
<(int32_t)sizeof(DataHeader
)) ||
439 pHeader
->dataHeader
.magic1
!=0xda ||
440 pHeader
->dataHeader
.magic2
!=0x27 ||
441 pHeader
->info
.sizeofUChar
!=2
443 *pErrorCode
=U_UNSUPPORTED_ERROR
;
447 inIsBigEndian
=(UBool
)pHeader
->info
.isBigEndian
;
448 inCharset
=pHeader
->info
.charsetFamily
;
450 if(inIsBigEndian
==U_IS_BIG_ENDIAN
) {
451 headerSize
=pHeader
->dataHeader
.headerSize
;
452 infoSize
=pHeader
->info
.size
;
454 headerSize
=uprv_readSwapUInt16(pHeader
->dataHeader
.headerSize
);
455 infoSize
=uprv_readSwapUInt16(pHeader
->info
.size
);
458 if( headerSize
<sizeof(DataHeader
) ||
459 infoSize
<sizeof(UDataInfo
) ||
460 headerSize
<(sizeof(pHeader
->dataHeader
)+infoSize
) ||
461 (length
>=0 && length
<headerSize
)
463 *pErrorCode
=U_UNSUPPORTED_ERROR
;
467 return udata_openSwapper(inIsBigEndian
, inCharset
, outIsBigEndian
, outCharset
, pErrorCode
);
470 U_CAPI
void U_EXPORT2
471 udata_closeSwapper(UDataSwapper
*ds
) {