intl/icu/source/common/udataswp.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial