OLD | NEW |
(Empty) | |
| 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 - hea
derSize %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->data
Header.headerSize, pErrorCode); |
| 292 |
| 293 /* swap UDataInfo size and reservedWord */ |
| 294 ds->swapArray16(ds, &pHeader->info.size, 4, &outHeader->info.size, pErro
rCode); |
| 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_writeDirectUInt
16 : uprv_writeSwapUInt16; |
| 343 swapper->writeUInt32= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt
32 : uprv_writeSwapUInt32; |
| 344 |
| 345 swapper->compareInvChars= outCharset==U_ASCII_FAMILY ? uprv_compareInvAscii
: uprv_compareInvEbcdic; |
| 346 |
| 347 swapper->swapArray16= inIsBigEndian==outIsBigEndian ? uprv_copyArray16 : upr
v_swapArray16; |
| 348 swapper->swapArray32= inIsBigEndian==outIsBigEndian ? uprv_copyArray32 : upr
v_swapArray32; |
| 349 |
| 350 if(inCharset==U_ASCII_FAMILY) { |
| 351 swapper->swapInvChars= outCharset==U_ASCII_FAMILY ? uprv_copyAscii : upr
v_ebcdicFromAscii; |
| 352 } else /* U_EBCDIC_FAMILY */ { |
| 353 swapper->swapInvChars= outCharset==U_EBCDIC_FAMILY ? uprv_copyEbcdic : u
prv_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, outCharse
t, pErrorCode); |
| 410 } |
| 411 |
| 412 U_CAPI void U_EXPORT2 |
| 413 udata_closeSwapper(UDataSwapper *ds) { |
| 414 uprv_free(ds); |
| 415 } |
OLD | NEW |