• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 *******************************************************************************
3 *
4 *   Copyright (C) 2003, 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 uint16_t U_CALLCONV
uprv_readSwapUInt16(uint16_t x)127 uprv_readSwapUInt16(uint16_t x) {
128     return (uint16_t)((x<<8)|(x>>8));
129 }
130 
131 static uint16_t U_CALLCONV
uprv_readDirectUInt16(uint16_t x)132 uprv_readDirectUInt16(uint16_t x) {
133     return x;
134 }
135 
136 static uint32_t U_CALLCONV
uprv_readSwapUInt32(uint32_t x)137 uprv_readSwapUInt32(uint32_t x) {
138     return (uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
139 }
140 
141 static uint32_t U_CALLCONV
uprv_readDirectUInt32(uint32_t x)142 uprv_readDirectUInt32(uint32_t x) {
143     return x;
144 }
145 
146 static void U_CALLCONV
uprv_writeSwapUInt16(uint16_t * p,uint16_t x)147 uprv_writeSwapUInt16(uint16_t *p, uint16_t x) {
148     *p=(uint16_t)((x<<8)|(x>>8));
149 }
150 
151 static void U_CALLCONV
uprv_writeDirectUInt16(uint16_t * p,uint16_t x)152 uprv_writeDirectUInt16(uint16_t *p, uint16_t x) {
153     *p=x;
154 }
155 
156 static void U_CALLCONV
uprv_writeSwapUInt32(uint32_t * p,uint32_t x)157 uprv_writeSwapUInt32(uint32_t *p, uint32_t x) {
158     *p=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
159 }
160 
161 static void U_CALLCONV
uprv_writeDirectUInt32(uint32_t * p,uint32_t x)162 uprv_writeDirectUInt32(uint32_t *p, uint32_t x) {
163     *p=x;
164 }
165 
166 U_CAPI int16_t U_EXPORT2
udata_readInt16(const UDataSwapper * ds,int16_t x)167 udata_readInt16(const UDataSwapper *ds, int16_t x) {
168     return (int16_t)ds->readUInt16((uint16_t)x);
169 }
170 
171 U_CAPI int32_t U_EXPORT2
udata_readInt32(const UDataSwapper * ds,int32_t x)172 udata_readInt32(const UDataSwapper *ds, int32_t x) {
173     return (int32_t)ds->readUInt32((uint32_t)x);
174 }
175 
176 /**
177  * Swap a block of invariant, NUL-terminated strings, but not padding
178  * bytes after the last string.
179  * @internal
180  */
181 U_CAPI int32_t U_EXPORT2
udata_swapInvStringBlock(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)182 udata_swapInvStringBlock(const UDataSwapper *ds,
183                          const void *inData, int32_t length, void *outData,
184                          UErrorCode *pErrorCode) {
185     const char *inChars;
186     int32_t stringsLength;
187 
188     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
189         return 0;
190     }
191     if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) {
192         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
193         return 0;
194     }
195 
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) {
200         --stringsLength;
201     }
202 
203     /* swap up to the last NUL */
204     ds->swapInvChars(ds, inData, stringsLength, outData, pErrorCode);
205 
206     /* copy the bytes after the last NUL */
207     if(inData!=outData && length>stringsLength) {
208         uprv_memcpy((char *)outData+stringsLength, inChars+stringsLength, length-stringsLength);
209     }
210 
211     /* return the length including padding bytes */
212     if(U_SUCCESS(*pErrorCode)) {
213         return length;
214     } else {
215         return 0;
216     }
217 }
218 
219 U_CAPI void U_EXPORT2
udata_printError(const UDataSwapper * ds,const char * fmt,...)220 udata_printError(const UDataSwapper *ds,
221                  const char *fmt,
222                  ...) {
223     va_list args;
224 
225     if(ds->printError!=NULL) {
226         va_start(args, fmt);
227         ds->printError(ds->printErrorContext, fmt, args);
228         va_end(args);
229     }
230 }
231 
232 /* swap a data header ------------------------------------------------------- */
233 
234 U_CAPI int32_t U_EXPORT2
udata_swapDataHeader(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)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;
240 
241     /* argument checking */
242     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
243         return 0;
244     }
245     if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
246         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
247         return 0;
248     }
249 
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
256     ) {
257         udata_printError(ds, "udata_swapDataHeader(): initial bytes do not look like ICU data\n");
258         *pErrorCode=U_UNSUPPORTED_ERROR;
259         return 0;
260     }
261 
262     headerSize=ds->readUInt16(pHeader->dataHeader.headerSize);
263     infoSize=ds->readUInt16(pHeader->info.size);
264 
265     if( headerSize<sizeof(DataHeader) ||
266         infoSize<sizeof(UDataInfo) ||
267         headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
268         (length>=0 && length<headerSize)
269     ) {
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;
273         return 0;
274     }
275 
276     if(length>0) {
277         DataHeader *outHeader;
278         const char *s;
279         int32_t maxLength;
280 
281         /* Most of the fields are just bytes and need no swapping. */
282         if(inData!=outData) {
283             uprv_memcpy(outData, inData, headerSize);
284         }
285         outHeader=(DataHeader *)outData;
286 
287         outHeader->info.isBigEndian = ds->outIsBigEndian;
288         outHeader->info.charsetFamily = ds->outCharset;
289 
290         /* swap headerSize */
291         ds->swapArray16(ds, &pHeader->dataHeader.headerSize, 2, &outHeader->dataHeader.headerSize, pErrorCode);
292 
293         /* swap UDataInfo size and reservedWord */
294         ds->swapArray16(ds, &pHeader->info.size, 4, &outHeader->info.size, pErrorCode);
295 
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);
304     }
305 
306     return headerSize;
307 }
308 
309 /* API functions ------------------------------------------------------------ */
310 
311 U_CAPI UDataSwapper * U_EXPORT2
udata_openSwapper(UBool inIsBigEndian,uint8_t inCharset,UBool outIsBigEndian,uint8_t outCharset,UErrorCode * pErrorCode)312 udata_openSwapper(UBool inIsBigEndian, uint8_t inCharset,
313                   UBool outIsBigEndian, uint8_t outCharset,
314                   UErrorCode *pErrorCode) {
315     UDataSwapper *swapper;
316 
317     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
318         return NULL;
319     }
320     if(inCharset>U_EBCDIC_FAMILY || outCharset>U_EBCDIC_FAMILY) {
321         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
322         return NULL;
323     }
324 
325     /* allocate the swapper */
326     swapper=uprv_malloc(sizeof(UDataSwapper));
327     if(swapper==NULL) {
328         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
329         return NULL;
330     }
331     uprv_memset(swapper, 0, sizeof(UDataSwapper));
332 
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;
338 
339     swapper->readUInt16= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt16 : uprv_readSwapUInt16;
340     swapper->readUInt32= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt32 : uprv_readSwapUInt32;
341 
342     swapper->writeUInt16= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt16 : uprv_writeSwapUInt16;
343     swapper->writeUInt32= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt32 : uprv_writeSwapUInt32;
344 
345     swapper->compareInvChars= outCharset==U_ASCII_FAMILY ? uprv_compareInvAscii : uprv_compareInvEbcdic;
346 
347     swapper->swapArray16= inIsBigEndian==outIsBigEndian ? uprv_copyArray16 : uprv_swapArray16;
348     swapper->swapArray32= inIsBigEndian==outIsBigEndian ? uprv_copyArray32 : uprv_swapArray32;
349 
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;
354     }
355 
356     return swapper;
357 }
358 
359 U_CAPI UDataSwapper * U_EXPORT2
udata_openSwapperForInputData(const void * data,int32_t length,UBool outIsBigEndian,uint8_t outCharset,UErrorCode * pErrorCode)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;
365     UBool inIsBigEndian;
366     int8_t inCharset;
367 
368     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
369         return NULL;
370     }
371     if( data==NULL ||
372         (length>=0 && length<sizeof(DataHeader)) ||
373         outCharset>U_EBCDIC_FAMILY
374     ) {
375         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
376         return NULL;
377     }
378 
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
384     ) {
385         *pErrorCode=U_UNSUPPORTED_ERROR;
386         return 0;
387     }
388 
389     inIsBigEndian=(UBool)pHeader->info.isBigEndian;
390     inCharset=pHeader->info.charsetFamily;
391 
392     if(inIsBigEndian==U_IS_BIG_ENDIAN) {
393         headerSize=pHeader->dataHeader.headerSize;
394         infoSize=pHeader->info.size;
395     } else {
396         headerSize=uprv_readSwapUInt16(pHeader->dataHeader.headerSize);
397         infoSize=uprv_readSwapUInt16(pHeader->info.size);
398     }
399 
400     if( headerSize<sizeof(DataHeader) ||
401         infoSize<sizeof(UDataInfo) ||
402         headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
403         (length>=0 && length<headerSize)
404     ) {
405         *pErrorCode=U_UNSUPPORTED_ERROR;
406         return 0;
407     }
408 
409     return udata_openSwapper(inIsBigEndian, inCharset, outIsBigEndian, outCharset, pErrorCode);
410 }
411 
412 U_CAPI void U_EXPORT2
udata_closeSwapper(UDataSwapper * ds)413 udata_closeSwapper(UDataSwapper *ds) {
414     uprv_free(ds);
415 }
416