2 *******************************************************************************
4 * Copyright (C) 2003-2014, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: udataswp.c
10 * tab size: 8 (not used)
13 * created on: 2003jun05
14 * created by: Markus W. Scherer
16 * Definitions for ICU data transformations for different platforms,
17 * changing between big- and little-endian data and/or between
18 * charset families (ASCII<->EBCDIC).
22 #include "unicode/utypes.h"
23 #include "unicode/udata.h" /* UDataInfo */
24 #include "ucmndata.h" /* DataHeader */
28 /* swapping primitives ------------------------------------------------------ */
30 static int32_t U_CALLCONV
31 uprv_swapArray16(const UDataSwapper
*ds
,
32 const void *inData
, int32_t length
, void *outData
,
33 UErrorCode
*pErrorCode
) {
39 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
42 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&1)!=0 || outData
==NULL
) {
43 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
47 /* setup and swapping */
48 p
=(const uint16_t *)inData
;
49 q
=(uint16_t *)outData
;
53 *q
++=(uint16_t)((x
<<8)|(x
>>8));
60 static int32_t U_CALLCONV
61 uprv_copyArray16(const UDataSwapper
*ds
,
62 const void *inData
, int32_t length
, void *outData
,
63 UErrorCode
*pErrorCode
) {
64 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
67 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&1)!=0 || outData
==NULL
) {
68 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
72 if(length
>0 && inData
!=outData
) {
73 uprv_memcpy(outData
, inData
, length
);
78 static int32_t U_CALLCONV
79 uprv_swapArray32(const UDataSwapper
*ds
,
80 const void *inData
, int32_t length
, void *outData
,
81 UErrorCode
*pErrorCode
) {
87 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
90 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&3)!=0 || outData
==NULL
) {
91 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
95 /* setup and swapping */
96 p
=(const uint32_t *)inData
;
97 q
=(uint32_t *)outData
;
101 *q
++=(uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
108 static int32_t U_CALLCONV
109 uprv_copyArray32(const UDataSwapper
*ds
,
110 const void *inData
, int32_t length
, void *outData
,
111 UErrorCode
*pErrorCode
) {
112 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
115 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&3)!=0 || outData
==NULL
) {
116 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
120 if(length
>0 && inData
!=outData
) {
121 uprv_memcpy(outData
, inData
, length
);
126 static int32_t U_CALLCONV
127 uprv_swapArray64(const UDataSwapper
*ds
,
128 const void *inData
, int32_t length
, void *outData
,
129 UErrorCode
*pErrorCode
) {
134 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
137 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&7)!=0 || outData
==NULL
) {
138 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
142 /* setup and swapping */
143 p
=(const uint64_t *)inData
;
144 q
=(uint64_t *)outData
;
148 x
=(x
<<56)|((x
&0xff00)<<40)|((x
&0xff0000)<<24)|((x
&0xff000000)<<8)|
149 ((x
>>8)&0xff000000)|((x
>>24)&0xff0000)|((x
>>40)&0xff00)|(x
>>56);
157 static int32_t U_CALLCONV
158 uprv_copyArray64(const UDataSwapper
*ds
,
159 const void *inData
, int32_t length
, void *outData
,
160 UErrorCode
*pErrorCode
) {
161 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
164 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
&7)!=0 || outData
==NULL
) {
165 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
169 if(length
>0 && inData
!=outData
) {
170 uprv_memcpy(outData
, inData
, length
);
175 static uint16_t U_CALLCONV
176 uprv_readSwapUInt16(uint16_t x
) {
177 return (uint16_t)((x
<<8)|(x
>>8));
180 static uint16_t U_CALLCONV
181 uprv_readDirectUInt16(uint16_t x
) {
185 static uint32_t U_CALLCONV
186 uprv_readSwapUInt32(uint32_t x
) {
187 return (uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
190 static uint32_t U_CALLCONV
191 uprv_readDirectUInt32(uint32_t x
) {
195 static void U_CALLCONV
196 uprv_writeSwapUInt16(uint16_t *p
, uint16_t x
) {
197 *p
=(uint16_t)((x
<<8)|(x
>>8));
200 static void U_CALLCONV
201 uprv_writeDirectUInt16(uint16_t *p
, uint16_t x
) {
205 static void U_CALLCONV
206 uprv_writeSwapUInt32(uint32_t *p
, uint32_t x
) {
207 *p
=(uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
210 static void U_CALLCONV
211 uprv_writeDirectUInt32(uint32_t *p
, uint32_t x
) {
215 U_CAPI
int16_t U_EXPORT2
216 udata_readInt16(const UDataSwapper
*ds
, int16_t x
) {
217 return (int16_t)ds
->readUInt16((uint16_t)x
);
220 U_CAPI
int32_t U_EXPORT2
221 udata_readInt32(const UDataSwapper
*ds
, int32_t x
) {
222 return (int32_t)ds
->readUInt32((uint32_t)x
);
226 * Swap a block of invariant, NUL-terminated strings, but not padding
227 * bytes after the last string.
230 U_CAPI
int32_t U_EXPORT2
231 udata_swapInvStringBlock(const UDataSwapper
*ds
,
232 const void *inData
, int32_t length
, void *outData
,
233 UErrorCode
*pErrorCode
) {
235 int32_t stringsLength
;
237 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
240 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
>0 && outData
==NULL
)) {
241 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
245 /* reduce the strings length to not include bytes after the last NUL */
246 inChars
=(const char *)inData
;
247 stringsLength
=length
;
248 while(stringsLength
>0 && inChars
[stringsLength
-1]!=0) {
252 /* swap up to the last NUL */
253 ds
->swapInvChars(ds
, inData
, stringsLength
, outData
, pErrorCode
);
255 /* copy the bytes after the last NUL */
256 if(inData
!=outData
&& length
>stringsLength
) {
257 uprv_memcpy((char *)outData
+stringsLength
, inChars
+stringsLength
, length
-stringsLength
);
260 /* return the length including padding bytes */
261 if(U_SUCCESS(*pErrorCode
)) {
268 U_CAPI
void U_EXPORT2
269 udata_printError(const UDataSwapper
*ds
,
274 if(ds
->printError
!=NULL
) {
276 ds
->printError(ds
->printErrorContext
, fmt
, args
);
281 /* swap a data header ------------------------------------------------------- */
283 U_CAPI
int32_t U_EXPORT2
284 udata_swapDataHeader(const UDataSwapper
*ds
,
285 const void *inData
, int32_t length
, void *outData
,
286 UErrorCode
*pErrorCode
) {
287 const DataHeader
*pHeader
;
288 uint16_t headerSize
, infoSize
;
290 /* argument checking */
291 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
294 if(ds
==NULL
|| inData
==NULL
|| length
<-1 || (length
>0 && outData
==NULL
)) {
295 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
299 /* check minimum length and magic bytes */
300 pHeader
=(const DataHeader
*)inData
;
301 if( (length
>=0 && length
<sizeof(DataHeader
)) ||
302 pHeader
->dataHeader
.magic1
!=0xda ||
303 pHeader
->dataHeader
.magic2
!=0x27 ||
304 pHeader
->info
.sizeofUChar
!=2
306 udata_printError(ds
, "udata_swapDataHeader(): initial bytes do not look like ICU data\n");
307 *pErrorCode
=U_UNSUPPORTED_ERROR
;
311 headerSize
=ds
->readUInt16(pHeader
->dataHeader
.headerSize
);
312 infoSize
=ds
->readUInt16(pHeader
->info
.size
);
314 if( headerSize
<sizeof(DataHeader
) ||
315 infoSize
<sizeof(UDataInfo
) ||
316 headerSize
<(sizeof(pHeader
->dataHeader
)+infoSize
) ||
317 (length
>=0 && length
<headerSize
)
319 udata_printError(ds
, "udata_swapDataHeader(): header size mismatch - headerSize %d infoSize %d length %d\n",
320 headerSize
, infoSize
, length
);
321 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
326 DataHeader
*outHeader
;
330 /* Most of the fields are just bytes and need no swapping. */
331 if(inData
!=outData
) {
332 uprv_memcpy(outData
, inData
, headerSize
);
334 outHeader
=(DataHeader
*)outData
;
336 outHeader
->info
.isBigEndian
= ds
->outIsBigEndian
;
337 outHeader
->info
.charsetFamily
= ds
->outCharset
;
339 /* swap headerSize */
340 ds
->swapArray16(ds
, &pHeader
->dataHeader
.headerSize
, 2, &outHeader
->dataHeader
.headerSize
, pErrorCode
);
342 /* swap UDataInfo size and reservedWord */
343 ds
->swapArray16(ds
, &pHeader
->info
.size
, 4, &outHeader
->info
.size
, pErrorCode
);
345 /* swap copyright statement after the UDataInfo */
346 infoSize
+=sizeof(pHeader
->dataHeader
);
347 s
=(const char *)inData
+infoSize
;
348 maxLength
=headerSize
-infoSize
;
349 /* get the length of the string */
350 for(length
=0; length
<maxLength
&& s
[length
]!=0; ++length
) {}
351 /* swap the string contents */
352 ds
->swapInvChars(ds
, s
, length
, (char *)outData
+infoSize
, pErrorCode
);
358 /* API functions ------------------------------------------------------------ */
360 U_CAPI UDataSwapper
* U_EXPORT2
361 udata_openSwapper(UBool inIsBigEndian
, uint8_t inCharset
,
362 UBool outIsBigEndian
, uint8_t outCharset
,
363 UErrorCode
*pErrorCode
) {
364 UDataSwapper
*swapper
;
366 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
369 if(inCharset
>U_EBCDIC_FAMILY
|| outCharset
>U_EBCDIC_FAMILY
) {
370 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
374 /* allocate the swapper */
375 swapper
=uprv_malloc(sizeof(UDataSwapper
));
377 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
380 uprv_memset(swapper
, 0, sizeof(UDataSwapper
));
382 /* set values and functions pointers according to in/out parameters */
383 swapper
->inIsBigEndian
=inIsBigEndian
;
384 swapper
->inCharset
=inCharset
;
385 swapper
->outIsBigEndian
=outIsBigEndian
;
386 swapper
->outCharset
=outCharset
;
388 swapper
->readUInt16
= inIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_readDirectUInt16
: uprv_readSwapUInt16
;
389 swapper
->readUInt32
= inIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_readDirectUInt32
: uprv_readSwapUInt32
;
391 swapper
->writeUInt16
= outIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_writeDirectUInt16
: uprv_writeSwapUInt16
;
392 swapper
->writeUInt32
= outIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_writeDirectUInt32
: uprv_writeSwapUInt32
;
394 swapper
->compareInvChars
= outCharset
==U_ASCII_FAMILY
? uprv_compareInvAscii
: uprv_compareInvEbcdic
;
396 if(inIsBigEndian
==outIsBigEndian
) {
397 swapper
->swapArray16
=uprv_copyArray16
;
398 swapper
->swapArray32
=uprv_copyArray32
;
399 swapper
->swapArray64
=uprv_copyArray64
;
401 swapper
->swapArray16
=uprv_swapArray16
;
402 swapper
->swapArray32
=uprv_swapArray32
;
403 swapper
->swapArray64
=uprv_swapArray64
;
406 if(inCharset
==U_ASCII_FAMILY
) {
407 swapper
->swapInvChars
= outCharset
==U_ASCII_FAMILY
? uprv_copyAscii
: uprv_ebcdicFromAscii
;
408 } else /* U_EBCDIC_FAMILY */ {
409 swapper
->swapInvChars
= outCharset
==U_EBCDIC_FAMILY
? uprv_copyEbcdic
: uprv_asciiFromEbcdic
;
415 U_CAPI UDataSwapper
* U_EXPORT2
416 udata_openSwapperForInputData(const void *data
, int32_t length
,
417 UBool outIsBigEndian
, uint8_t outCharset
,
418 UErrorCode
*pErrorCode
) {
419 const DataHeader
*pHeader
;
420 uint16_t headerSize
, infoSize
;
424 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
428 (length
>=0 && length
<sizeof(DataHeader
)) ||
429 outCharset
>U_EBCDIC_FAMILY
431 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
435 pHeader
=(const DataHeader
*)data
;
436 if( (length
>=0 && length
<sizeof(DataHeader
)) ||
437 pHeader
->dataHeader
.magic1
!=0xda ||
438 pHeader
->dataHeader
.magic2
!=0x27 ||
439 pHeader
->info
.sizeofUChar
!=2
441 *pErrorCode
=U_UNSUPPORTED_ERROR
;
445 inIsBigEndian
=(UBool
)pHeader
->info
.isBigEndian
;
446 inCharset
=pHeader
->info
.charsetFamily
;
448 if(inIsBigEndian
==U_IS_BIG_ENDIAN
) {
449 headerSize
=pHeader
->dataHeader
.headerSize
;
450 infoSize
=pHeader
->info
.size
;
452 headerSize
=uprv_readSwapUInt16(pHeader
->dataHeader
.headerSize
);
453 infoSize
=uprv_readSwapUInt16(pHeader
->info
.size
);
456 if( headerSize
<sizeof(DataHeader
) ||
457 infoSize
<sizeof(UDataInfo
) ||
458 headerSize
<(sizeof(pHeader
->dataHeader
)+infoSize
) ||
459 (length
>=0 && length
<headerSize
)
461 *pErrorCode
=U_UNSUPPORTED_ERROR
;
465 return udata_openSwapper(inIsBigEndian
, inCharset
, outIsBigEndian
, outCharset
, pErrorCode
);
468 U_CAPI
void U_EXPORT2
469 udata_closeSwapper(UDataSwapper
*ds
) {