1 // Copyright (C) 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=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<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) {