1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 2003-2014, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 * file name: udataswp.c
9 * encoding: US-ASCII
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * created on: 2003jun05
14 * created by: Markus W. Scherer
15 *
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).
19 */
20
21 #include <stdarg.h>
22 #include "unicode/utypes.h"
23 #include "unicode/udata.h" /* UDataInfo */
24 #include "ucmndata.h" /* DataHeader */
25 #include "cmemory.h"
26 #include "udataswp.h"
27
28 /* swapping primitives ------------------------------------------------------ */
29
30 static int32_t U_CALLCONV
uprv_swapArray16(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)31 uprv_swapArray16(const UDataSwapper *ds,
32 const void *inData, int32_t length, void *outData,
33 UErrorCode *pErrorCode) {
34 const uint16_t *p;
35 uint16_t *q;
36 int32_t count;
37 uint16_t x;
38
39 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
40 return 0;
41 }
42 if(ds==NULL || inData==NULL || length<0 || (length&1)!=0 || outData==NULL) {
43 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
44 return 0;
45 }
46
47 /* setup and swapping */
48 p=(const uint16_t *)inData;
49 q=(uint16_t *)outData;
50 count=length/2;
51 while(count>0) {
52 x=*p++;
53 *q++=(uint16_t)((x<<8)|(x>>8));
54 --count;
55 }
56
57 return length;
58 }
59
60 static int32_t U_CALLCONV
uprv_copyArray16(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)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)) {
65 return 0;
66 }
67 if(ds==NULL || inData==NULL || length<0 || (length&1)!=0 || outData==NULL) {
68 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
69 return 0;
70 }
71
72 if(length>0 && inData!=outData) {
73 uprv_memcpy(outData, inData, length);
74 }
75 return length;
76 }
77
78 static int32_t U_CALLCONV
uprv_swapArray32(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)79 uprv_swapArray32(const UDataSwapper *ds,
80 const void *inData, int32_t length, void *outData,
81 UErrorCode *pErrorCode) {
82 const uint32_t *p;
83 uint32_t *q;
84 int32_t count;
85 uint32_t x;
86
87 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
88 return 0;
89 }
90 if(ds==NULL || inData==NULL || length<0 || (length&3)!=0 || outData==NULL) {
91 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
92 return 0;
93 }
94
95 /* setup and swapping */
96 p=(const uint32_t *)inData;
97 q=(uint32_t *)outData;
98 count=length/4;
99 while(count>0) {
100 x=*p++;
101 *q++=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
102 --count;
103 }
104
105 return length;
106 }
107
108 static int32_t U_CALLCONV
uprv_copyArray32(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)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)) {
113 return 0;
114 }
115 if(ds==NULL || inData==NULL || length<0 || (length&3)!=0 || outData==NULL) {
116 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
117 return 0;
118 }
119
120 if(length>0 && inData!=outData) {
121 uprv_memcpy(outData, inData, length);
122 }
123 return length;
124 }
125
126 static int32_t U_CALLCONV
uprv_swapArray64(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)127 uprv_swapArray64(const UDataSwapper *ds,
128 const void *inData, int32_t length, void *outData,
129 UErrorCode *pErrorCode) {
130 const uint64_t *p;
131 uint64_t *q;
132 int32_t count;
133
134 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
135 return 0;
136 }
137 if(ds==NULL || inData==NULL || length<0 || (length&7)!=0 || outData==NULL) {
138 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
139 return 0;
140 }
141
142 /* setup and swapping */
143 p=(const uint64_t *)inData;
144 q=(uint64_t *)outData;
145 count=length/8;
146 while(count>0) {
147 uint64_t x=*p++;
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);
150 *q++=x;
151 --count;
152 }
153
154 return length;
155 }
156
157 static int32_t U_CALLCONV
uprv_copyArray64(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)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)) {
162 return 0;
163 }
164 if(ds==NULL || inData==NULL || length<0 || (length&7)!=0 || outData==NULL) {
165 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
166 return 0;
167 }
168
169 if(length>0 && inData!=outData) {
170 uprv_memcpy(outData, inData, length);
171 }
172 return length;
173 }
174
175 static uint16_t U_CALLCONV
uprv_readSwapUInt16(uint16_t x)176 uprv_readSwapUInt16(uint16_t x) {
177 return (uint16_t)((x<<8)|(x>>8));
178 }
179
180 static uint16_t U_CALLCONV
uprv_readDirectUInt16(uint16_t x)181 uprv_readDirectUInt16(uint16_t x) {
182 return x;
183 }
184
185 static uint32_t U_CALLCONV
uprv_readSwapUInt32(uint32_t x)186 uprv_readSwapUInt32(uint32_t x) {
187 return (uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
188 }
189
190 static uint32_t U_CALLCONV
uprv_readDirectUInt32(uint32_t x)191 uprv_readDirectUInt32(uint32_t x) {
192 return x;
193 }
194
195 static void U_CALLCONV
uprv_writeSwapUInt16(uint16_t * p,uint16_t x)196 uprv_writeSwapUInt16(uint16_t *p, uint16_t x) {
197 *p=(uint16_t)((x<<8)|(x>>8));
198 }
199
200 static void U_CALLCONV
uprv_writeDirectUInt16(uint16_t * p,uint16_t x)201 uprv_writeDirectUInt16(uint16_t *p, uint16_t x) {
202 *p=x;
203 }
204
205 static void U_CALLCONV
uprv_writeSwapUInt32(uint32_t * p,uint32_t x)206 uprv_writeSwapUInt32(uint32_t *p, uint32_t x) {
207 *p=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
208 }
209
210 static void U_CALLCONV
uprv_writeDirectUInt32(uint32_t * p,uint32_t x)211 uprv_writeDirectUInt32(uint32_t *p, uint32_t x) {
212 *p=x;
213 }
214
215 U_CAPI int16_t U_EXPORT2
udata_readInt16(const UDataSwapper * ds,int16_t x)216 udata_readInt16(const UDataSwapper *ds, int16_t x) {
217 return (int16_t)ds->readUInt16((uint16_t)x);
218 }
219
220 U_CAPI int32_t U_EXPORT2
udata_readInt32(const UDataSwapper * ds,int32_t x)221 udata_readInt32(const UDataSwapper *ds, int32_t x) {
222 return (int32_t)ds->readUInt32((uint32_t)x);
223 }
224
225 /**
226 * Swap a block of invariant, NUL-terminated strings, but not padding
227 * bytes after the last string.
228 * @internal
229 */
230 U_CAPI int32_t U_EXPORT2
udata_swapInvStringBlock(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)231 udata_swapInvStringBlock(const UDataSwapper *ds,
232 const void *inData, int32_t length, void *outData,
233 UErrorCode *pErrorCode) {
234 const char *inChars;
235 int32_t stringsLength;
236
237 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
238 return 0;
239 }
240 if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) {
241 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
242 return 0;
243 }
244
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) {
249 --stringsLength;
250 }
251
252 /* swap up to the last NUL */
253 ds->swapInvChars(ds, inData, stringsLength, outData, pErrorCode);
254
255 /* copy the bytes after the last NUL */
256 if(inData!=outData && length>stringsLength) {
257 uprv_memcpy((char *)outData+stringsLength, inChars+stringsLength, length-stringsLength);
258 }
259
260 /* return the length including padding bytes */
261 if(U_SUCCESS(*pErrorCode)) {
262 return length;
263 } else {
264 return 0;
265 }
266 }
267
268 U_CAPI void U_EXPORT2
udata_printError(const UDataSwapper * ds,const char * fmt,...)269 udata_printError(const UDataSwapper *ds,
270 const char *fmt,
271 ...) {
272 va_list args;
273
274 if(ds->printError!=NULL) {
275 va_start(args, fmt);
276 ds->printError(ds->printErrorContext, fmt, args);
277 va_end(args);
278 }
279 }
280
281 /* swap a data header ------------------------------------------------------- */
282
283 U_CAPI int32_t U_EXPORT2
udata_swapDataHeader(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)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;
289
290 /* argument checking */
291 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
292 return 0;
293 }
294 if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
295 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
296 return 0;
297 }
298
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
305 ) {
306 udata_printError(ds, "udata_swapDataHeader(): initial bytes do not look like ICU data\n");
307 *pErrorCode=U_UNSUPPORTED_ERROR;
308 return 0;
309 }
310
311 headerSize=ds->readUInt16(pHeader->dataHeader.headerSize);
312 infoSize=ds->readUInt16(pHeader->info.size);
313
314 if( headerSize<sizeof(DataHeader) ||
315 infoSize<sizeof(UDataInfo) ||
316 headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
317 (length>=0 && length<headerSize)
318 ) {
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;
322 return 0;
323 }
324
325 if(length>0) {
326 DataHeader *outHeader;
327 const char *s;
328 int32_t maxLength;
329
330 /* Most of the fields are just bytes and need no swapping. */
331 if(inData!=outData) {
332 uprv_memcpy(outData, inData, headerSize);
333 }
334 outHeader=(DataHeader *)outData;
335
336 outHeader->info.isBigEndian = ds->outIsBigEndian;
337 outHeader->info.charsetFamily = ds->outCharset;
338
339 /* swap headerSize */
340 ds->swapArray16(ds, &pHeader->dataHeader.headerSize, 2, &outHeader->dataHeader.headerSize, pErrorCode);
341
342 /* swap UDataInfo size and reservedWord */
343 ds->swapArray16(ds, &pHeader->info.size, 4, &outHeader->info.size, pErrorCode);
344
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);
353 }
354
355 return headerSize;
356 }
357
358 /* API functions ------------------------------------------------------------ */
359
360 U_CAPI UDataSwapper * U_EXPORT2
udata_openSwapper(UBool inIsBigEndian,uint8_t inCharset,UBool outIsBigEndian,uint8_t outCharset,UErrorCode * pErrorCode)361 udata_openSwapper(UBool inIsBigEndian, uint8_t inCharset,
362 UBool outIsBigEndian, uint8_t outCharset,
363 UErrorCode *pErrorCode) {
364 UDataSwapper *swapper;
365
366 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
367 return NULL;
368 }
369 if(inCharset>U_EBCDIC_FAMILY || outCharset>U_EBCDIC_FAMILY) {
370 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
371 return NULL;
372 }
373
374 /* allocate the swapper */
375 swapper=uprv_malloc(sizeof(UDataSwapper));
376 if(swapper==NULL) {
377 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
378 return NULL;
379 }
380 uprv_memset(swapper, 0, sizeof(UDataSwapper));
381
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;
387
388 swapper->readUInt16= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt16 : uprv_readSwapUInt16;
389 swapper->readUInt32= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt32 : uprv_readSwapUInt32;
390
391 swapper->writeUInt16= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt16 : uprv_writeSwapUInt16;
392 swapper->writeUInt32= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt32 : uprv_writeSwapUInt32;
393
394 swapper->compareInvChars= outCharset==U_ASCII_FAMILY ? uprv_compareInvAscii : uprv_compareInvEbcdic;
395
396 if(inIsBigEndian==outIsBigEndian) {
397 swapper->swapArray16=uprv_copyArray16;
398 swapper->swapArray32=uprv_copyArray32;
399 swapper->swapArray64=uprv_copyArray64;
400 } else {
401 swapper->swapArray16=uprv_swapArray16;
402 swapper->swapArray32=uprv_swapArray32;
403 swapper->swapArray64=uprv_swapArray64;
404 }
405
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;
410 }
411
412 return swapper;
413 }
414
415 U_CAPI UDataSwapper * U_EXPORT2
udata_openSwapperForInputData(const void * data,int32_t length,UBool outIsBigEndian,uint8_t outCharset,UErrorCode * pErrorCode)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;
421 UBool inIsBigEndian;
422 int8_t inCharset;
423
424 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
425 return NULL;
426 }
427 if( data==NULL ||
428 (length>=0 && length<sizeof(DataHeader)) ||
429 outCharset>U_EBCDIC_FAMILY
430 ) {
431 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
432 return NULL;
433 }
434
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
440 ) {
441 *pErrorCode=U_UNSUPPORTED_ERROR;
442 return 0;
443 }
444
445 inIsBigEndian=(UBool)pHeader->info.isBigEndian;
446 inCharset=pHeader->info.charsetFamily;
447
448 if(inIsBigEndian==U_IS_BIG_ENDIAN) {
449 headerSize=pHeader->dataHeader.headerSize;
450 infoSize=pHeader->info.size;
451 } else {
452 headerSize=uprv_readSwapUInt16(pHeader->dataHeader.headerSize);
453 infoSize=uprv_readSwapUInt16(pHeader->info.size);
454 }
455
456 if( headerSize<sizeof(DataHeader) ||
457 infoSize<sizeof(UDataInfo) ||
458 headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
459 (length>=0 && length<headerSize)
460 ) {
461 *pErrorCode=U_UNSUPPORTED_ERROR;
462 return 0;
463 }
464
465 return udata_openSwapper(inIsBigEndian, inCharset, outIsBigEndian, outCharset, pErrorCode);
466 }
467
468 U_CAPI void U_EXPORT2
udata_closeSwapper(UDataSwapper * ds)469 udata_closeSwapper(UDataSwapper *ds) {
470 uprv_free(ds);
471 }
472