|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
127 uprv_readSwapUInt16(uint16_t x) { |
|
128 return (uint16_t)((x<<8)|(x>>8)); |
|
129 } |
|
130 |
|
131 static uint16_t U_CALLCONV |
|
132 uprv_readDirectUInt16(uint16_t x) { |
|
133 return x; |
|
134 } |
|
135 |
|
136 static uint32_t U_CALLCONV |
|
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 |
|
142 uprv_readDirectUInt32(uint32_t x) { |
|
143 return x; |
|
144 } |
|
145 |
|
146 static void U_CALLCONV |
|
147 uprv_writeSwapUInt16(uint16_t *p, uint16_t x) { |
|
148 *p=(uint16_t)((x<<8)|(x>>8)); |
|
149 } |
|
150 |
|
151 static void U_CALLCONV |
|
152 uprv_writeDirectUInt16(uint16_t *p, uint16_t x) { |
|
153 *p=x; |
|
154 } |
|
155 |
|
156 static void U_CALLCONV |
|
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 |
|
162 uprv_writeDirectUInt32(uint32_t *p, uint32_t x) { |
|
163 *p=x; |
|
164 } |
|
165 |
|
166 U_CAPI int16_t U_EXPORT2 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
413 udata_closeSwapper(UDataSwapper *ds) { |
|
414 uprv_free(ds); |
|
415 } |