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