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