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