Home | History | Annotate | Download | only in common
      1 /*
      2 *******************************************************************************
      3 *
      4 *   Copyright (C) 2003-2014, 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 int32_t U_CALLCONV
    127 uprv_swapArray64(const UDataSwapper *ds,
    128                  const void *inData, int32_t length, void *outData,
    129                  UErrorCode *pErrorCode) {
    130     const uint64_t *p;
    131     uint64_t *q;
    132     int32_t count;
    133 
    134     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    135         return 0;
    136     }
    137     if(ds==NULL || inData==NULL || length<0 || (length&7)!=0 || outData==NULL) {
    138         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    139         return 0;
    140     }
    141 
    142     /* setup and swapping */
    143     p=(const uint64_t *)inData;
    144     q=(uint64_t *)outData;
    145     count=length/8;
    146     while(count>0) {
    147         uint64_t x=*p++;
    148         x=(x<<56)|((x&0xff00)<<40)|((x&0xff0000)<<24)|((x&0xff000000)<<8)|
    149             ((x>>8)&0xff000000)|((x>>24)&0xff0000)|((x>>40)&0xff00)|(x>>56);
    150         *q++=x;
    151         --count;
    152     }
    153 
    154     return length;
    155 }
    156 
    157 static int32_t U_CALLCONV
    158 uprv_copyArray64(const UDataSwapper *ds,
    159                  const void *inData, int32_t length, void *outData,
    160                  UErrorCode *pErrorCode) {
    161     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    162         return 0;
    163     }
    164     if(ds==NULL || inData==NULL || length<0 || (length&7)!=0 || outData==NULL) {
    165         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    166         return 0;
    167     }
    168 
    169     if(length>0 && inData!=outData) {
    170         uprv_memcpy(outData, inData, length);
    171     }
    172     return length;
    173 }
    174 
    175 static uint16_t U_CALLCONV
    176 uprv_readSwapUInt16(uint16_t x) {
    177     return (uint16_t)((x<<8)|(x>>8));
    178 }
    179 
    180 static uint16_t U_CALLCONV
    181 uprv_readDirectUInt16(uint16_t x) {
    182     return x;
    183 }
    184 
    185 static uint32_t U_CALLCONV
    186 uprv_readSwapUInt32(uint32_t x) {
    187     return (uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
    188 }
    189 
    190 static uint32_t U_CALLCONV
    191 uprv_readDirectUInt32(uint32_t x) {
    192     return x;
    193 }
    194 
    195 static void U_CALLCONV
    196 uprv_writeSwapUInt16(uint16_t *p, uint16_t x) {
    197     *p=(uint16_t)((x<<8)|(x>>8));
    198 }
    199 
    200 static void U_CALLCONV
    201 uprv_writeDirectUInt16(uint16_t *p, uint16_t x) {
    202     *p=x;
    203 }
    204 
    205 static void U_CALLCONV
    206 uprv_writeSwapUInt32(uint32_t *p, uint32_t x) {
    207     *p=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
    208 }
    209 
    210 static void U_CALLCONV
    211 uprv_writeDirectUInt32(uint32_t *p, uint32_t x) {
    212     *p=x;
    213 }
    214 
    215 U_CAPI int16_t U_EXPORT2
    216 udata_readInt16(const UDataSwapper *ds, int16_t x) {
    217     return (int16_t)ds->readUInt16((uint16_t)x);
    218 }
    219 
    220 U_CAPI int32_t U_EXPORT2
    221 udata_readInt32(const UDataSwapper *ds, int32_t x) {
    222     return (int32_t)ds->readUInt32((uint32_t)x);
    223 }
    224 
    225 /**
    226  * Swap a block of invariant, NUL-terminated strings, but not padding
    227  * bytes after the last string.
    228  * @internal
    229  */
    230 U_CAPI int32_t U_EXPORT2
    231 udata_swapInvStringBlock(const UDataSwapper *ds,
    232                          const void *inData, int32_t length, void *outData,
    233                          UErrorCode *pErrorCode) {
    234     const char *inChars;
    235     int32_t stringsLength;
    236 
    237     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    238         return 0;
    239     }
    240     if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) {
    241         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    242         return 0;
    243     }
    244 
    245     /* reduce the strings length to not include bytes after the last NUL */
    246     inChars=(const char *)inData;
    247     stringsLength=length;
    248     while(stringsLength>0 && inChars[stringsLength-1]!=0) {
    249         --stringsLength;
    250     }
    251 
    252     /* swap up to the last NUL */
    253     ds->swapInvChars(ds, inData, stringsLength, outData, pErrorCode);
    254 
    255     /* copy the bytes after the last NUL */
    256     if(inData!=outData && length>stringsLength) {
    257         uprv_memcpy((char *)outData+stringsLength, inChars+stringsLength, length-stringsLength);
    258     }
    259 
    260     /* return the length including padding bytes */
    261     if(U_SUCCESS(*pErrorCode)) {
    262         return length;
    263     } else {
    264         return 0;
    265     }
    266 }
    267 
    268 U_CAPI void U_EXPORT2
    269 udata_printError(const UDataSwapper *ds,
    270                  const char *fmt,
    271                  ...) {
    272     va_list args;
    273 
    274     if(ds->printError!=NULL) {
    275         va_start(args, fmt);
    276         ds->printError(ds->printErrorContext, fmt, args);
    277         va_end(args);
    278     }
    279 }
    280 
    281 /* swap a data header ------------------------------------------------------- */
    282 
    283 U_CAPI int32_t U_EXPORT2
    284 udata_swapDataHeader(const UDataSwapper *ds,
    285                      const void *inData, int32_t length, void *outData,
    286                      UErrorCode *pErrorCode) {
    287     const DataHeader *pHeader;
    288     uint16_t headerSize, infoSize;
    289 
    290     /* argument checking */
    291     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    292         return 0;
    293     }
    294     if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
    295         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    296         return 0;
    297     }
    298 
    299     /* check minimum length and magic bytes */
    300     pHeader=(const DataHeader *)inData;
    301     if( (length>=0 && length<sizeof(DataHeader)) ||
    302         pHeader->dataHeader.magic1!=0xda ||
    303         pHeader->dataHeader.magic2!=0x27 ||
    304         pHeader->info.sizeofUChar!=2
    305     ) {
    306         udata_printError(ds, "udata_swapDataHeader(): initial bytes do not look like ICU data\n");
    307         *pErrorCode=U_UNSUPPORTED_ERROR;
    308         return 0;
    309     }
    310 
    311     headerSize=ds->readUInt16(pHeader->dataHeader.headerSize);
    312     infoSize=ds->readUInt16(pHeader->info.size);
    313 
    314     if( headerSize<sizeof(DataHeader) ||
    315         infoSize<sizeof(UDataInfo) ||
    316         headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
    317         (length>=0 && length<headerSize)
    318     ) {
    319         udata_printError(ds, "udata_swapDataHeader(): header size mismatch - headerSize %d infoSize %d length %d\n",
    320                          headerSize, infoSize, length);
    321         *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    322         return 0;
    323     }
    324 
    325     if(length>0) {
    326         DataHeader *outHeader;
    327         const char *s;
    328         int32_t maxLength;
    329 
    330         /* Most of the fields are just bytes and need no swapping. */
    331         if(inData!=outData) {
    332             uprv_memcpy(outData, inData, headerSize);
    333         }
    334         outHeader=(DataHeader *)outData;
    335 
    336         outHeader->info.isBigEndian = ds->outIsBigEndian;
    337         outHeader->info.charsetFamily = ds->outCharset;
    338 
    339         /* swap headerSize */
    340         ds->swapArray16(ds, &pHeader->dataHeader.headerSize, 2, &outHeader->dataHeader.headerSize, pErrorCode);
    341 
    342         /* swap UDataInfo size and reservedWord */
    343         ds->swapArray16(ds, &pHeader->info.size, 4, &outHeader->info.size, pErrorCode);
    344 
    345         /* swap copyright statement after the UDataInfo */
    346         infoSize+=sizeof(pHeader->dataHeader);
    347         s=(const char *)inData+infoSize;
    348         maxLength=headerSize-infoSize;
    349         /* get the length of the string */
    350         for(length=0; length<maxLength && s[length]!=0; ++length) {}
    351         /* swap the string contents */
    352         ds->swapInvChars(ds, s, length, (char *)outData+infoSize, pErrorCode);
    353     }
    354 
    355     return headerSize;
    356 }
    357 
    358 /* API functions ------------------------------------------------------------ */
    359 
    360 U_CAPI UDataSwapper * U_EXPORT2
    361 udata_openSwapper(UBool inIsBigEndian, uint8_t inCharset,
    362                   UBool outIsBigEndian, uint8_t outCharset,
    363                   UErrorCode *pErrorCode) {
    364     UDataSwapper *swapper;
    365 
    366     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    367         return NULL;
    368     }
    369     if(inCharset>U_EBCDIC_FAMILY || outCharset>U_EBCDIC_FAMILY) {
    370         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    371         return NULL;
    372     }
    373 
    374     /* allocate the swapper */
    375     swapper=uprv_malloc(sizeof(UDataSwapper));
    376     if(swapper==NULL) {
    377         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    378         return NULL;
    379     }
    380     uprv_memset(swapper, 0, sizeof(UDataSwapper));
    381 
    382     /* set values and functions pointers according to in/out parameters */
    383     swapper->inIsBigEndian=inIsBigEndian;
    384     swapper->inCharset=inCharset;
    385     swapper->outIsBigEndian=outIsBigEndian;
    386     swapper->outCharset=outCharset;
    387 
    388     swapper->readUInt16= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt16 : uprv_readSwapUInt16;
    389     swapper->readUInt32= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt32 : uprv_readSwapUInt32;
    390 
    391     swapper->writeUInt16= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt16 : uprv_writeSwapUInt16;
    392     swapper->writeUInt32= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt32 : uprv_writeSwapUInt32;
    393 
    394     swapper->compareInvChars= outCharset==U_ASCII_FAMILY ? uprv_compareInvAscii : uprv_compareInvEbcdic;
    395 
    396     if(inIsBigEndian==outIsBigEndian) {
    397         swapper->swapArray16=uprv_copyArray16;
    398         swapper->swapArray32=uprv_copyArray32;
    399         swapper->swapArray64=uprv_copyArray64;
    400     } else {
    401         swapper->swapArray16=uprv_swapArray16;
    402         swapper->swapArray32=uprv_swapArray32;
    403         swapper->swapArray64=uprv_swapArray64;
    404     }
    405 
    406     if(inCharset==U_ASCII_FAMILY) {
    407         swapper->swapInvChars= outCharset==U_ASCII_FAMILY ? uprv_copyAscii : uprv_ebcdicFromAscii;
    408     } else /* U_EBCDIC_FAMILY */ {
    409         swapper->swapInvChars= outCharset==U_EBCDIC_FAMILY ? uprv_copyEbcdic : uprv_asciiFromEbcdic;
    410     }
    411 
    412     return swapper;
    413 }
    414 
    415 U_CAPI UDataSwapper * U_EXPORT2
    416 udata_openSwapperForInputData(const void *data, int32_t length,
    417                               UBool outIsBigEndian, uint8_t outCharset,
    418                               UErrorCode *pErrorCode) {
    419     const DataHeader *pHeader;
    420     uint16_t headerSize, infoSize;
    421     UBool inIsBigEndian;
    422     int8_t inCharset;
    423 
    424     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    425         return NULL;
    426     }
    427     if( data==NULL ||
    428         (length>=0 && length<sizeof(DataHeader)) ||
    429         outCharset>U_EBCDIC_FAMILY
    430     ) {
    431         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    432         return NULL;
    433     }
    434 
    435     pHeader=(const DataHeader *)data;
    436     if( (length>=0 && length<sizeof(DataHeader)) ||
    437         pHeader->dataHeader.magic1!=0xda ||
    438         pHeader->dataHeader.magic2!=0x27 ||
    439         pHeader->info.sizeofUChar!=2
    440     ) {
    441         *pErrorCode=U_UNSUPPORTED_ERROR;
    442         return 0;
    443     }
    444 
    445     inIsBigEndian=(UBool)pHeader->info.isBigEndian;
    446     inCharset=pHeader->info.charsetFamily;
    447 
    448     if(inIsBigEndian==U_IS_BIG_ENDIAN) {
    449         headerSize=pHeader->dataHeader.headerSize;
    450         infoSize=pHeader->info.size;
    451     } else {
    452         headerSize=uprv_readSwapUInt16(pHeader->dataHeader.headerSize);
    453         infoSize=uprv_readSwapUInt16(pHeader->info.size);
    454     }
    455 
    456     if( headerSize<sizeof(DataHeader) ||
    457         infoSize<sizeof(UDataInfo) ||
    458         headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
    459         (length>=0 && length<headerSize)
    460     ) {
    461         *pErrorCode=U_UNSUPPORTED_ERROR;
    462         return 0;
    463     }
    464 
    465     return udata_openSwapper(inIsBigEndian, inCharset, outIsBigEndian, outCharset, pErrorCode);
    466 }
    467 
    468 U_CAPI void U_EXPORT2
    469 udata_closeSwapper(UDataSwapper *ds) {
    470     uprv_free(ds);
    471 }
    472