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