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

     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 */
    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"
    28 /* swapping primitives ------------------------------------------------------ */
    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;
    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     }
    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     }
    57     return length;
    58 }
    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     }
    72     if(length>0 && inData!=outData) {
    73         uprv_memcpy(outData, inData, length);
    74     }
    75     return length;
    76 }
    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;
    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     }
    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     }
   105     return length;
   106 }
   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     }
   120     if(length>0 && inData!=outData) {
   121         uprv_memcpy(outData, inData, length);
   122     }
   123     return length;
   124 }
   126 static uint16_t U_CALLCONV
   127 uprv_readSwapUInt16(uint16_t x) {
   128     return (uint16_t)((x<<8)|(x>>8));
   129 }
   131 static uint16_t U_CALLCONV
   132 uprv_readDirectUInt16(uint16_t x) {
   133     return x;
   134 }
   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 }
   141 static uint32_t U_CALLCONV
   142 uprv_readDirectUInt32(uint32_t x) {
   143     return x;
   144 }
   146 static void U_CALLCONV
   147 uprv_writeSwapUInt16(uint16_t *p, uint16_t x) {
   148     *p=(uint16_t)((x<<8)|(x>>8));
   149 }
   151 static void U_CALLCONV
   152 uprv_writeDirectUInt16(uint16_t *p, uint16_t x) {
   153     *p=x;
   154 }
   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 }
   161 static void U_CALLCONV
   162 uprv_writeDirectUInt32(uint32_t *p, uint32_t x) {
   163     *p=x;
   164 }
   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 }
   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 }
   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;
   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     }
   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     }
   203     /* swap up to the last NUL */
   204     ds->swapInvChars(ds, inData, stringsLength, outData, pErrorCode);
   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     }
   211     /* return the length including padding bytes */
   212     if(U_SUCCESS(*pErrorCode)) {
   213         return length;
   214     } else {
   215         return 0;
   216     }
   217 }
   219 U_CAPI void U_EXPORT2
   220 udata_printError(const UDataSwapper *ds,
   221                  const char *fmt,
   222                  ...) {
   223     va_list args;
   225     if(ds->printError!=NULL) {
   226         va_start(args, fmt);
   227         ds->printError(ds->printErrorContext, fmt, args);
   228         va_end(args);
   229     }
   230 }
   232 /* swap a data header ------------------------------------------------------- */
   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;
   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     }
   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     }
   262     headerSize=ds->readUInt16(pHeader->dataHeader.headerSize);
   263     infoSize=ds->readUInt16(pHeader->info.size);
   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     }
   276     if(length>0) {
   277         DataHeader *outHeader;
   278         const char *s;
   279         int32_t maxLength;
   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;
   287         outHeader->info.isBigEndian = ds->outIsBigEndian;
   288         outHeader->info.charsetFamily = ds->outCharset;
   290         /* swap headerSize */
   291         ds->swapArray16(ds, &pHeader->dataHeader.headerSize, 2, &outHeader->dataHeader.headerSize, pErrorCode);
   293         /* swap UDataInfo size and reservedWord */
   294         ds->swapArray16(ds, &pHeader->info.size, 4, &outHeader->info.size, pErrorCode);
   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     }
   306     return headerSize;
   307 }
   309 /* API functions ------------------------------------------------------------ */
   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;
   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     }
   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));
   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;
   339     swapper->readUInt16= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt16 : uprv_readSwapUInt16;
   340     swapper->readUInt32= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt32 : uprv_readSwapUInt32;
   342     swapper->writeUInt16= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt16 : uprv_writeSwapUInt16;
   343     swapper->writeUInt32= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt32 : uprv_writeSwapUInt32;
   345     swapper->compareInvChars= outCharset==U_ASCII_FAMILY ? uprv_compareInvAscii : uprv_compareInvEbcdic;
   347     swapper->swapArray16= inIsBigEndian==outIsBigEndian ? uprv_copyArray16 : uprv_swapArray16;
   348     swapper->swapArray32= inIsBigEndian==outIsBigEndian ? uprv_copyArray32 : uprv_swapArray32;
   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     }
   356     return swapper;
   357 }
   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;
   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     }
   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     }
   389     inIsBigEndian=(UBool)pHeader->info.isBigEndian;
   390     inCharset=pHeader->info.charsetFamily;
   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     }
   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     }
   409     return udata_openSwapper(inIsBigEndian, inCharset, outIsBigEndian, outCharset, pErrorCode);
   410 }
   412 U_CAPI void U_EXPORT2
   413 udata_closeSwapper(UDataSwapper *ds) {
   414     uprv_free(ds);
   415 }

mercurial