1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/udataswp.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,415 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* 1.7 +* Copyright (C) 2003, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +******************************************************************************* 1.11 +* file name: udataswp.c 1.12 +* encoding: US-ASCII 1.13 +* tab size: 8 (not used) 1.14 +* indentation:4 1.15 +* 1.16 +* created on: 2003jun05 1.17 +* created by: Markus W. Scherer 1.18 +* 1.19 +* Definitions for ICU data transformations for different platforms, 1.20 +* changing between big- and little-endian data and/or between 1.21 +* charset families (ASCII<->EBCDIC). 1.22 +*/ 1.23 + 1.24 +#include <stdarg.h> 1.25 +#include "unicode/utypes.h" 1.26 +#include "unicode/udata.h" /* UDataInfo */ 1.27 +#include "ucmndata.h" /* DataHeader */ 1.28 +#include "cmemory.h" 1.29 +#include "udataswp.h" 1.30 + 1.31 +/* swapping primitives ------------------------------------------------------ */ 1.32 + 1.33 +static int32_t U_CALLCONV 1.34 +uprv_swapArray16(const UDataSwapper *ds, 1.35 + const void *inData, int32_t length, void *outData, 1.36 + UErrorCode *pErrorCode) { 1.37 + const uint16_t *p; 1.38 + uint16_t *q; 1.39 + int32_t count; 1.40 + uint16_t x; 1.41 + 1.42 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.43 + return 0; 1.44 + } 1.45 + if(ds==NULL || inData==NULL || length<0 || (length&1)!=0 || outData==NULL) { 1.46 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.47 + return 0; 1.48 + } 1.49 + 1.50 + /* setup and swapping */ 1.51 + p=(const uint16_t *)inData; 1.52 + q=(uint16_t *)outData; 1.53 + count=length/2; 1.54 + while(count>0) { 1.55 + x=*p++; 1.56 + *q++=(uint16_t)((x<<8)|(x>>8)); 1.57 + --count; 1.58 + } 1.59 + 1.60 + return length; 1.61 +} 1.62 + 1.63 +static int32_t U_CALLCONV 1.64 +uprv_copyArray16(const UDataSwapper *ds, 1.65 + const void *inData, int32_t length, void *outData, 1.66 + UErrorCode *pErrorCode) { 1.67 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.68 + return 0; 1.69 + } 1.70 + if(ds==NULL || inData==NULL || length<0 || (length&1)!=0 || outData==NULL) { 1.71 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.72 + return 0; 1.73 + } 1.74 + 1.75 + if(length>0 && inData!=outData) { 1.76 + uprv_memcpy(outData, inData, length); 1.77 + } 1.78 + return length; 1.79 +} 1.80 + 1.81 +static int32_t U_CALLCONV 1.82 +uprv_swapArray32(const UDataSwapper *ds, 1.83 + const void *inData, int32_t length, void *outData, 1.84 + UErrorCode *pErrorCode) { 1.85 + const uint32_t *p; 1.86 + uint32_t *q; 1.87 + int32_t count; 1.88 + uint32_t x; 1.89 + 1.90 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.91 + return 0; 1.92 + } 1.93 + if(ds==NULL || inData==NULL || length<0 || (length&3)!=0 || outData==NULL) { 1.94 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.95 + return 0; 1.96 + } 1.97 + 1.98 + /* setup and swapping */ 1.99 + p=(const uint32_t *)inData; 1.100 + q=(uint32_t *)outData; 1.101 + count=length/4; 1.102 + while(count>0) { 1.103 + x=*p++; 1.104 + *q++=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24)); 1.105 + --count; 1.106 + } 1.107 + 1.108 + return length; 1.109 +} 1.110 + 1.111 +static int32_t U_CALLCONV 1.112 +uprv_copyArray32(const UDataSwapper *ds, 1.113 + const void *inData, int32_t length, void *outData, 1.114 + UErrorCode *pErrorCode) { 1.115 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.116 + return 0; 1.117 + } 1.118 + if(ds==NULL || inData==NULL || length<0 || (length&3)!=0 || outData==NULL) { 1.119 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.120 + return 0; 1.121 + } 1.122 + 1.123 + if(length>0 && inData!=outData) { 1.124 + uprv_memcpy(outData, inData, length); 1.125 + } 1.126 + return length; 1.127 +} 1.128 + 1.129 +static uint16_t U_CALLCONV 1.130 +uprv_readSwapUInt16(uint16_t x) { 1.131 + return (uint16_t)((x<<8)|(x>>8)); 1.132 +} 1.133 + 1.134 +static uint16_t U_CALLCONV 1.135 +uprv_readDirectUInt16(uint16_t x) { 1.136 + return x; 1.137 +} 1.138 + 1.139 +static uint32_t U_CALLCONV 1.140 +uprv_readSwapUInt32(uint32_t x) { 1.141 + return (uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24)); 1.142 +} 1.143 + 1.144 +static uint32_t U_CALLCONV 1.145 +uprv_readDirectUInt32(uint32_t x) { 1.146 + return x; 1.147 +} 1.148 + 1.149 +static void U_CALLCONV 1.150 +uprv_writeSwapUInt16(uint16_t *p, uint16_t x) { 1.151 + *p=(uint16_t)((x<<8)|(x>>8)); 1.152 +} 1.153 + 1.154 +static void U_CALLCONV 1.155 +uprv_writeDirectUInt16(uint16_t *p, uint16_t x) { 1.156 + *p=x; 1.157 +} 1.158 + 1.159 +static void U_CALLCONV 1.160 +uprv_writeSwapUInt32(uint32_t *p, uint32_t x) { 1.161 + *p=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24)); 1.162 +} 1.163 + 1.164 +static void U_CALLCONV 1.165 +uprv_writeDirectUInt32(uint32_t *p, uint32_t x) { 1.166 + *p=x; 1.167 +} 1.168 + 1.169 +U_CAPI int16_t U_EXPORT2 1.170 +udata_readInt16(const UDataSwapper *ds, int16_t x) { 1.171 + return (int16_t)ds->readUInt16((uint16_t)x); 1.172 +} 1.173 + 1.174 +U_CAPI int32_t U_EXPORT2 1.175 +udata_readInt32(const UDataSwapper *ds, int32_t x) { 1.176 + return (int32_t)ds->readUInt32((uint32_t)x); 1.177 +} 1.178 + 1.179 +/** 1.180 + * Swap a block of invariant, NUL-terminated strings, but not padding 1.181 + * bytes after the last string. 1.182 + * @internal 1.183 + */ 1.184 +U_CAPI int32_t U_EXPORT2 1.185 +udata_swapInvStringBlock(const UDataSwapper *ds, 1.186 + const void *inData, int32_t length, void *outData, 1.187 + UErrorCode *pErrorCode) { 1.188 + const char *inChars; 1.189 + int32_t stringsLength; 1.190 + 1.191 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.192 + return 0; 1.193 + } 1.194 + if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) { 1.195 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.196 + return 0; 1.197 + } 1.198 + 1.199 + /* reduce the strings length to not include bytes after the last NUL */ 1.200 + inChars=(const char *)inData; 1.201 + stringsLength=length; 1.202 + while(stringsLength>0 && inChars[stringsLength-1]!=0) { 1.203 + --stringsLength; 1.204 + } 1.205 + 1.206 + /* swap up to the last NUL */ 1.207 + ds->swapInvChars(ds, inData, stringsLength, outData, pErrorCode); 1.208 + 1.209 + /* copy the bytes after the last NUL */ 1.210 + if(inData!=outData && length>stringsLength) { 1.211 + uprv_memcpy((char *)outData+stringsLength, inChars+stringsLength, length-stringsLength); 1.212 + } 1.213 + 1.214 + /* return the length including padding bytes */ 1.215 + if(U_SUCCESS(*pErrorCode)) { 1.216 + return length; 1.217 + } else { 1.218 + return 0; 1.219 + } 1.220 +} 1.221 + 1.222 +U_CAPI void U_EXPORT2 1.223 +udata_printError(const UDataSwapper *ds, 1.224 + const char *fmt, 1.225 + ...) { 1.226 + va_list args; 1.227 + 1.228 + if(ds->printError!=NULL) { 1.229 + va_start(args, fmt); 1.230 + ds->printError(ds->printErrorContext, fmt, args); 1.231 + va_end(args); 1.232 + } 1.233 +} 1.234 + 1.235 +/* swap a data header ------------------------------------------------------- */ 1.236 + 1.237 +U_CAPI int32_t U_EXPORT2 1.238 +udata_swapDataHeader(const UDataSwapper *ds, 1.239 + const void *inData, int32_t length, void *outData, 1.240 + UErrorCode *pErrorCode) { 1.241 + const DataHeader *pHeader; 1.242 + uint16_t headerSize, infoSize; 1.243 + 1.244 + /* argument checking */ 1.245 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.246 + return 0; 1.247 + } 1.248 + if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) { 1.249 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.250 + return 0; 1.251 + } 1.252 + 1.253 + /* check minimum length and magic bytes */ 1.254 + pHeader=(const DataHeader *)inData; 1.255 + if( (length>=0 && length<sizeof(DataHeader)) || 1.256 + pHeader->dataHeader.magic1!=0xda || 1.257 + pHeader->dataHeader.magic2!=0x27 || 1.258 + pHeader->info.sizeofUChar!=2 1.259 + ) { 1.260 + udata_printError(ds, "udata_swapDataHeader(): initial bytes do not look like ICU data\n"); 1.261 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.262 + return 0; 1.263 + } 1.264 + 1.265 + headerSize=ds->readUInt16(pHeader->dataHeader.headerSize); 1.266 + infoSize=ds->readUInt16(pHeader->info.size); 1.267 + 1.268 + if( headerSize<sizeof(DataHeader) || 1.269 + infoSize<sizeof(UDataInfo) || 1.270 + headerSize<(sizeof(pHeader->dataHeader)+infoSize) || 1.271 + (length>=0 && length<headerSize) 1.272 + ) { 1.273 + udata_printError(ds, "udata_swapDataHeader(): header size mismatch - headerSize %d infoSize %d length %d\n", 1.274 + headerSize, infoSize, length); 1.275 + *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; 1.276 + return 0; 1.277 + } 1.278 + 1.279 + if(length>0) { 1.280 + DataHeader *outHeader; 1.281 + const char *s; 1.282 + int32_t maxLength; 1.283 + 1.284 + /* Most of the fields are just bytes and need no swapping. */ 1.285 + if(inData!=outData) { 1.286 + uprv_memcpy(outData, inData, headerSize); 1.287 + } 1.288 + outHeader=(DataHeader *)outData; 1.289 + 1.290 + outHeader->info.isBigEndian = ds->outIsBigEndian; 1.291 + outHeader->info.charsetFamily = ds->outCharset; 1.292 + 1.293 + /* swap headerSize */ 1.294 + ds->swapArray16(ds, &pHeader->dataHeader.headerSize, 2, &outHeader->dataHeader.headerSize, pErrorCode); 1.295 + 1.296 + /* swap UDataInfo size and reservedWord */ 1.297 + ds->swapArray16(ds, &pHeader->info.size, 4, &outHeader->info.size, pErrorCode); 1.298 + 1.299 + /* swap copyright statement after the UDataInfo */ 1.300 + infoSize+=sizeof(pHeader->dataHeader); 1.301 + s=(const char *)inData+infoSize; 1.302 + maxLength=headerSize-infoSize; 1.303 + /* get the length of the string */ 1.304 + for(length=0; length<maxLength && s[length]!=0; ++length) {} 1.305 + /* swap the string contents */ 1.306 + ds->swapInvChars(ds, s, length, (char *)outData+infoSize, pErrorCode); 1.307 + } 1.308 + 1.309 + return headerSize; 1.310 +} 1.311 + 1.312 +/* API functions ------------------------------------------------------------ */ 1.313 + 1.314 +U_CAPI UDataSwapper * U_EXPORT2 1.315 +udata_openSwapper(UBool inIsBigEndian, uint8_t inCharset, 1.316 + UBool outIsBigEndian, uint8_t outCharset, 1.317 + UErrorCode *pErrorCode) { 1.318 + UDataSwapper *swapper; 1.319 + 1.320 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.321 + return NULL; 1.322 + } 1.323 + if(inCharset>U_EBCDIC_FAMILY || outCharset>U_EBCDIC_FAMILY) { 1.324 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.325 + return NULL; 1.326 + } 1.327 + 1.328 + /* allocate the swapper */ 1.329 + swapper=uprv_malloc(sizeof(UDataSwapper)); 1.330 + if(swapper==NULL) { 1.331 + *pErrorCode=U_MEMORY_ALLOCATION_ERROR; 1.332 + return NULL; 1.333 + } 1.334 + uprv_memset(swapper, 0, sizeof(UDataSwapper)); 1.335 + 1.336 + /* set values and functions pointers according to in/out parameters */ 1.337 + swapper->inIsBigEndian=inIsBigEndian; 1.338 + swapper->inCharset=inCharset; 1.339 + swapper->outIsBigEndian=outIsBigEndian; 1.340 + swapper->outCharset=outCharset; 1.341 + 1.342 + swapper->readUInt16= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt16 : uprv_readSwapUInt16; 1.343 + swapper->readUInt32= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt32 : uprv_readSwapUInt32; 1.344 + 1.345 + swapper->writeUInt16= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt16 : uprv_writeSwapUInt16; 1.346 + swapper->writeUInt32= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt32 : uprv_writeSwapUInt32; 1.347 + 1.348 + swapper->compareInvChars= outCharset==U_ASCII_FAMILY ? uprv_compareInvAscii : uprv_compareInvEbcdic; 1.349 + 1.350 + swapper->swapArray16= inIsBigEndian==outIsBigEndian ? uprv_copyArray16 : uprv_swapArray16; 1.351 + swapper->swapArray32= inIsBigEndian==outIsBigEndian ? uprv_copyArray32 : uprv_swapArray32; 1.352 + 1.353 + if(inCharset==U_ASCII_FAMILY) { 1.354 + swapper->swapInvChars= outCharset==U_ASCII_FAMILY ? uprv_copyAscii : uprv_ebcdicFromAscii; 1.355 + } else /* U_EBCDIC_FAMILY */ { 1.356 + swapper->swapInvChars= outCharset==U_EBCDIC_FAMILY ? uprv_copyEbcdic : uprv_asciiFromEbcdic; 1.357 + } 1.358 + 1.359 + return swapper; 1.360 +} 1.361 + 1.362 +U_CAPI UDataSwapper * U_EXPORT2 1.363 +udata_openSwapperForInputData(const void *data, int32_t length, 1.364 + UBool outIsBigEndian, uint8_t outCharset, 1.365 + UErrorCode *pErrorCode) { 1.366 + const DataHeader *pHeader; 1.367 + uint16_t headerSize, infoSize; 1.368 + UBool inIsBigEndian; 1.369 + int8_t inCharset; 1.370 + 1.371 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.372 + return NULL; 1.373 + } 1.374 + if( data==NULL || 1.375 + (length>=0 && length<sizeof(DataHeader)) || 1.376 + outCharset>U_EBCDIC_FAMILY 1.377 + ) { 1.378 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.379 + return NULL; 1.380 + } 1.381 + 1.382 + pHeader=(const DataHeader *)data; 1.383 + if( (length>=0 && length<sizeof(DataHeader)) || 1.384 + pHeader->dataHeader.magic1!=0xda || 1.385 + pHeader->dataHeader.magic2!=0x27 || 1.386 + pHeader->info.sizeofUChar!=2 1.387 + ) { 1.388 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.389 + return 0; 1.390 + } 1.391 + 1.392 + inIsBigEndian=(UBool)pHeader->info.isBigEndian; 1.393 + inCharset=pHeader->info.charsetFamily; 1.394 + 1.395 + if(inIsBigEndian==U_IS_BIG_ENDIAN) { 1.396 + headerSize=pHeader->dataHeader.headerSize; 1.397 + infoSize=pHeader->info.size; 1.398 + } else { 1.399 + headerSize=uprv_readSwapUInt16(pHeader->dataHeader.headerSize); 1.400 + infoSize=uprv_readSwapUInt16(pHeader->info.size); 1.401 + } 1.402 + 1.403 + if( headerSize<sizeof(DataHeader) || 1.404 + infoSize<sizeof(UDataInfo) || 1.405 + headerSize<(sizeof(pHeader->dataHeader)+infoSize) || 1.406 + (length>=0 && length<headerSize) 1.407 + ) { 1.408 + *pErrorCode=U_UNSUPPORTED_ERROR; 1.409 + return 0; 1.410 + } 1.411 + 1.412 + return udata_openSwapper(inIsBigEndian, inCharset, outIsBigEndian, outCharset, pErrorCode); 1.413 +} 1.414 + 1.415 +U_CAPI void U_EXPORT2 1.416 +udata_closeSwapper(UDataSwapper *ds) { 1.417 + uprv_free(ds); 1.418 +}