intl/icu/source/common/udataswp.c

changeset 0
6474c204b198
     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 +}

mercurial