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 30static int32_t U_CALLCONV 31uprv_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 60static int32_t U_CALLCONV 61uprv_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 78static int32_t U_CALLCONV 79uprv_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 108static int32_t U_CALLCONV 109uprv_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 126static uint16_t U_CALLCONV 127uprv_readSwapUInt16(uint16_t x) { 128 return (uint16_t)((x<<8)|(x>>8)); 129} 130 131static uint16_t U_CALLCONV 132uprv_readDirectUInt16(uint16_t x) { 133 return x; 134} 135 136static uint32_t U_CALLCONV 137uprv_readSwapUInt32(uint32_t x) { 138 return (uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24)); 139} 140 141static uint32_t U_CALLCONV 142uprv_readDirectUInt32(uint32_t x) { 143 return x; 144} 145 146static void U_CALLCONV 147uprv_writeSwapUInt16(uint16_t *p, uint16_t x) { 148 *p=(uint16_t)((x<<8)|(x>>8)); 149} 150 151static void U_CALLCONV 152uprv_writeDirectUInt16(uint16_t *p, uint16_t x) { 153 *p=x; 154} 155 156static void U_CALLCONV 157uprv_writeSwapUInt32(uint32_t *p, uint32_t x) { 158 *p=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24)); 159} 160 161static void U_CALLCONV 162uprv_writeDirectUInt32(uint32_t *p, uint32_t x) { 163 *p=x; 164} 165 166U_CAPI int16_t U_EXPORT2 167udata_readInt16(const UDataSwapper *ds, int16_t x) { 168 return (int16_t)ds->readUInt16((uint16_t)x); 169} 170 171U_CAPI int32_t U_EXPORT2 172udata_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 */ 181U_CAPI int32_t U_EXPORT2 182udata_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 219U_CAPI void U_EXPORT2 220udata_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 234U_CAPI int32_t U_EXPORT2 235udata_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 311U_CAPI UDataSwapper * U_EXPORT2 312udata_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 359U_CAPI UDataSwapper * U_EXPORT2 360udata_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 412U_CAPI void U_EXPORT2 413udata_closeSwapper(UDataSwapper *ds) { 414 uprv_free(ds); 415} 416