2 *******************************************************************************
4 * Copyright (C) 2003, 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 uint16_t U_CALLCONV
127 uprv_readSwapUInt16(uint16_t x
) {
128 return (uint16_t)((x
<<8)|(x
>>8));
131 static uint16_t U_CALLCONV
132 uprv_readDirectUInt16(uint16_t x
) {
136 static uint32_t U_CALLCONV
137 uprv_readSwapUInt32(uint32_t x
) {
138 return (uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
141 static uint32_t U_CALLCONV
142 uprv_readDirectUInt32(uint32_t x
) {
146 static void U_CALLCONV
147 uprv_writeSwapUInt16(uint16_t *p
, uint16_t x
) {
148 *p
=(uint16_t)((x
<<8)|(x
>>8));
151 static void U_CALLCONV
152 uprv_writeDirectUInt16(uint16_t *p
, uint16_t x
) {
156 static void U_CALLCONV
157 uprv_writeSwapUInt32(uint32_t *p
, uint32_t x
) {
158 *p
=(uint32_t)((x
<<24)|((x
<<8)&0xff0000)|((x
>>8)&0xff00)|(x
>>24));
161 static void U_CALLCONV
162 uprv_writeDirectUInt32(uint32_t *p
, uint32_t x
) {
166 U_CAPI
int16_t U_EXPORT2
167 udata_readInt16(const UDataSwapper
*ds
, int16_t x
) {
168 return (int16_t)ds
->readUInt16((uint16_t)x
);
171 U_CAPI
int32_t U_EXPORT2
172 udata_readInt32(const UDataSwapper
*ds
, int32_t x
) {
173 return (int32_t)ds
->readUInt32((uint32_t)x
);
177 * Swap a block of invariant, NUL-terminated strings, but not padding
178 * bytes after the last string.
181 U_CAPI
int32_t U_EXPORT2
182 udata_swapInvStringBlock(const UDataSwapper
*ds
,
183 const void *inData
, int32_t length
, void *outData
,
184 UErrorCode
*pErrorCode
) {
186 int32_t stringsLength
;
188 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
191 if(ds
==NULL
|| inData
==NULL
|| length
<0 || (length
>0 && outData
==NULL
)) {
192 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
196 /* reduce the strings length to not include bytes after the last NUL */
197 inChars
=(const char *)inData
;
198 stringsLength
=length
;
199 while(stringsLength
>0 && inChars
[stringsLength
-1]!=0) {
203 /* swap up to the last NUL */
204 ds
->swapInvChars(ds
, inData
, stringsLength
, outData
, pErrorCode
);
206 /* copy the bytes after the last NUL */
207 if(inData
!=outData
&& length
>stringsLength
) {
208 uprv_memcpy((char *)outData
+stringsLength
, inChars
+stringsLength
, length
-stringsLength
);
211 /* return the length including padding bytes */
212 if(U_SUCCESS(*pErrorCode
)) {
219 U_CAPI
void U_EXPORT2
220 udata_printError(const UDataSwapper
*ds
,
225 if(ds
->printError
!=NULL
) {
227 ds
->printError(ds
->printErrorContext
, fmt
, args
);
232 /* swap a data header ------------------------------------------------------- */
234 U_CAPI
int32_t U_EXPORT2
235 udata_swapDataHeader(const UDataSwapper
*ds
,
236 const void *inData
, int32_t length
, void *outData
,
237 UErrorCode
*pErrorCode
) {
238 const DataHeader
*pHeader
;
239 uint16_t headerSize
, infoSize
;
241 /* argument checking */
242 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
245 if(ds
==NULL
|| inData
==NULL
|| length
<-1 || (length
>0 && outData
==NULL
)) {
246 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
250 /* check minimum length and magic bytes */
251 pHeader
=(const DataHeader
*)inData
;
252 if( (length
>=0 && length
<sizeof(DataHeader
)) ||
253 pHeader
->dataHeader
.magic1
!=0xda ||
254 pHeader
->dataHeader
.magic2
!=0x27 ||
255 pHeader
->info
.sizeofUChar
!=2
257 udata_printError(ds
, "udata_swapDataHeader(): initial bytes do not look like ICU data\n");
258 *pErrorCode
=U_UNSUPPORTED_ERROR
;
262 headerSize
=ds
->readUInt16(pHeader
->dataHeader
.headerSize
);
263 infoSize
=ds
->readUInt16(pHeader
->info
.size
);
265 if( headerSize
<sizeof(DataHeader
) ||
266 infoSize
<sizeof(UDataInfo
) ||
267 headerSize
<(sizeof(pHeader
->dataHeader
)+infoSize
) ||
268 (length
>=0 && length
<headerSize
)
270 udata_printError(ds
, "udata_swapDataHeader(): header size mismatch - headerSize %d infoSize %d length %d\n",
271 headerSize
, infoSize
, length
);
272 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
277 DataHeader
*outHeader
;
281 /* Most of the fields are just bytes and need no swapping. */
282 if(inData
!=outData
) {
283 uprv_memcpy(outData
, inData
, headerSize
);
285 outHeader
=(DataHeader
*)outData
;
287 outHeader
->info
.isBigEndian
= ds
->outIsBigEndian
;
288 outHeader
->info
.charsetFamily
= ds
->outCharset
;
290 /* swap headerSize */
291 ds
->swapArray16(ds
, &pHeader
->dataHeader
.headerSize
, 2, &outHeader
->dataHeader
.headerSize
, pErrorCode
);
293 /* swap UDataInfo size and reservedWord */
294 ds
->swapArray16(ds
, &pHeader
->info
.size
, 4, &outHeader
->info
.size
, pErrorCode
);
296 /* swap copyright statement after the UDataInfo */
297 infoSize
+=sizeof(pHeader
->dataHeader
);
298 s
=(const char *)inData
+infoSize
;
299 maxLength
=headerSize
-infoSize
;
300 /* get the length of the string */
301 for(length
=0; length
<maxLength
&& s
[length
]!=0; ++length
) {}
302 /* swap the string contents */
303 ds
->swapInvChars(ds
, s
, length
, (char *)outData
+infoSize
, pErrorCode
);
309 /* API functions ------------------------------------------------------------ */
311 U_CAPI UDataSwapper
* U_EXPORT2
312 udata_openSwapper(UBool inIsBigEndian
, uint8_t inCharset
,
313 UBool outIsBigEndian
, uint8_t outCharset
,
314 UErrorCode
*pErrorCode
) {
315 UDataSwapper
*swapper
;
317 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
320 if(inCharset
>U_EBCDIC_FAMILY
|| outCharset
>U_EBCDIC_FAMILY
) {
321 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
325 /* allocate the swapper */
326 swapper
=uprv_malloc(sizeof(UDataSwapper
));
328 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
331 uprv_memset(swapper
, 0, sizeof(UDataSwapper
));
333 /* set values and functions pointers according to in/out parameters */
334 swapper
->inIsBigEndian
=inIsBigEndian
;
335 swapper
->inCharset
=inCharset
;
336 swapper
->outIsBigEndian
=outIsBigEndian
;
337 swapper
->outCharset
=outCharset
;
339 swapper
->readUInt16
= inIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_readDirectUInt16
: uprv_readSwapUInt16
;
340 swapper
->readUInt32
= inIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_readDirectUInt32
: uprv_readSwapUInt32
;
342 swapper
->writeUInt16
= outIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_writeDirectUInt16
: uprv_writeSwapUInt16
;
343 swapper
->writeUInt32
= outIsBigEndian
==U_IS_BIG_ENDIAN
? uprv_writeDirectUInt32
: uprv_writeSwapUInt32
;
345 swapper
->compareInvChars
= outCharset
==U_ASCII_FAMILY
? uprv_compareInvAscii
: uprv_compareInvEbcdic
;
347 swapper
->swapArray16
= inIsBigEndian
==outIsBigEndian
? uprv_copyArray16
: uprv_swapArray16
;
348 swapper
->swapArray32
= inIsBigEndian
==outIsBigEndian
? uprv_copyArray32
: uprv_swapArray32
;
350 if(inCharset
==U_ASCII_FAMILY
) {
351 swapper
->swapInvChars
= outCharset
==U_ASCII_FAMILY
? uprv_copyAscii
: uprv_ebcdicFromAscii
;
352 } else /* U_EBCDIC_FAMILY */ {
353 swapper
->swapInvChars
= outCharset
==U_EBCDIC_FAMILY
? uprv_copyEbcdic
: uprv_asciiFromEbcdic
;
359 U_CAPI UDataSwapper
* U_EXPORT2
360 udata_openSwapperForInputData(const void *data
, int32_t length
,
361 UBool outIsBigEndian
, uint8_t outCharset
,
362 UErrorCode
*pErrorCode
) {
363 const DataHeader
*pHeader
;
364 uint16_t headerSize
, infoSize
;
368 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
372 (length
>=0 && length
<sizeof(DataHeader
)) ||
373 outCharset
>U_EBCDIC_FAMILY
375 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
379 pHeader
=(const DataHeader
*)data
;
380 if( (length
>=0 && length
<sizeof(DataHeader
)) ||
381 pHeader
->dataHeader
.magic1
!=0xda ||
382 pHeader
->dataHeader
.magic2
!=0x27 ||
383 pHeader
->info
.sizeofUChar
!=2
385 *pErrorCode
=U_UNSUPPORTED_ERROR
;
389 inIsBigEndian
=(UBool
)pHeader
->info
.isBigEndian
;
390 inCharset
=pHeader
->info
.charsetFamily
;
392 if(inIsBigEndian
==U_IS_BIG_ENDIAN
) {
393 headerSize
=pHeader
->dataHeader
.headerSize
;
394 infoSize
=pHeader
->info
.size
;
396 headerSize
=uprv_readSwapUInt16(pHeader
->dataHeader
.headerSize
);
397 infoSize
=uprv_readSwapUInt16(pHeader
->info
.size
);
400 if( headerSize
<sizeof(DataHeader
) ||
401 infoSize
<sizeof(UDataInfo
) ||
402 headerSize
<(sizeof(pHeader
->dataHeader
)+infoSize
) ||
403 (length
>=0 && length
<headerSize
)
405 *pErrorCode
=U_UNSUPPORTED_ERROR
;
409 return udata_openSwapper(inIsBigEndian
, inCharset
, outIsBigEndian
, outCharset
, pErrorCode
);
412 U_CAPI
void U_EXPORT2
413 udata_closeSwapper(UDataSwapper
*ds
) {