Home | History | Annotate | Download | only in toolutil
      1 /*
      2 *******************************************************************************
      3 *
      4 *   Copyright (C) 2005-2009, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 *******************************************************************************
      8 *   file name:  swapimpl.cpp
      9 *   encoding:   US-ASCII
     10 *   tab size:   8 (not used)
     11 *   indentation:4
     12 *
     13 *   created on: 2005may05
     14 *   created by: Markus W. Scherer
     15 *
     16 *   Data file swapping functions moved here from the common library
     17 *   because some data is hardcoded in ICU4C and needs not be swapped any more.
     18 *   Moving the functions here simplifies testing (for code coverage) because
     19 *   we need not jump through hoops (like adding snapshots of these files
     20 *   to testdata).
     21 *
     22 *   The declarations for these functions remain in the internal header files
     23 *   in icu/source/common/
     24 */
     25 
     26 #include "unicode/utypes.h"
     27 #include "unicode/putil.h"
     28 #include "unicode/udata.h"
     29 
     30 /* Explicit include statement for std_string.h is needed
     31  * for compilation on certain platforms. (e.g. AIX/VACPP)
     32  */
     33 #include "unicode/std_string.h"
     34 
     35 #include "cmemory.h"
     36 #include "cstring.h"
     37 #include "uinvchar.h"
     38 #include "uassert.h"
     39 #include "uarrsort.h"
     40 #include "ucmndata.h"
     41 #include "udataswp.h"
     42 
     43 /* swapping implementations in common */
     44 
     45 #include "uresdata.h"
     46 #include "ucnv_io.h"
     47 #include "uprops.h"
     48 #include "ucase.h"
     49 #include "ubidi_props.h"
     50 #include "ucol_swp.h"
     51 #include "ucnv_bld.h"
     52 #include "unormimp.h"
     53 #include "sprpimpl.h"
     54 #include "propname.h"
     55 #include "rbbidata.h"
     56 #include "triedict.h"
     57 
     58 /* swapping implementations in i18n */
     59 
     60 #if !UCONFIG_NO_NORMALIZATION
     61 #include "uspoof_impl.h"
     62 #endif
     63 
     64 
     65 /* definitions */
     66 
     67 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
     68 
     69 /* Unicode properties data swapping ----------------------------------------- */
     70 
     71 U_CAPI int32_t U_EXPORT2
     72 uprops_swap(const UDataSwapper *ds,
     73             const void *inData, int32_t length, void *outData,
     74             UErrorCode *pErrorCode) {
     75     const UDataInfo *pInfo;
     76     int32_t headerSize, i;
     77 
     78     int32_t dataIndexes[UPROPS_INDEX_COUNT];
     79     const int32_t *inData32;
     80 
     81     /* udata_swapDataHeader checks the arguments */
     82     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
     83     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
     84         return 0;
     85     }
     86 
     87     /* check data format and format version */
     88     pInfo=(const UDataInfo *)((const char *)inData+4);
     89     if(!(
     90         pInfo->dataFormat[0]==0x55 &&   /* dataFormat="UPro" */
     91         pInfo->dataFormat[1]==0x50 &&
     92         pInfo->dataFormat[2]==0x72 &&
     93         pInfo->dataFormat[3]==0x6f &&
     94         (pInfo->formatVersion[0]==3 || pInfo->formatVersion[0]==4 || pInfo->formatVersion[0]==5) &&
     95         pInfo->formatVersion[2]==UTRIE_SHIFT &&
     96         pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
     97     )) {
     98         udata_printError(ds, "uprops_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not a Unicode properties file\n",
     99                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    100                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    101                          pInfo->formatVersion[0]);
    102         *pErrorCode=U_UNSUPPORTED_ERROR;
    103         return 0;
    104     }
    105 
    106     /* the properties file must contain at least the indexes array */
    107     if(length>=0 && (length-headerSize)<(int32_t)sizeof(dataIndexes)) {
    108         udata_printError(ds, "uprops_swap(): too few bytes (%d after header) for a Unicode properties file\n",
    109                          length-headerSize);
    110         *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    111         return 0;
    112     }
    113 
    114     /* read the indexes */
    115     inData32=(const int32_t *)((const char *)inData+headerSize);
    116     for(i=0; i<UPROPS_INDEX_COUNT; ++i) {
    117         dataIndexes[i]=udata_readInt32(ds, inData32[i]);
    118     }
    119 
    120     /*
    121      * comments are copied from the data format description in genprops/store.c
    122      * indexes[] constants are in uprops.h
    123      */
    124     if(length>=0) {
    125         int32_t *outData32;
    126 
    127         if((length-headerSize)<(4*dataIndexes[UPROPS_RESERVED_INDEX])) {
    128             udata_printError(ds, "uprops_swap(): too few bytes (%d after header) for a Unicode properties file\n",
    129                              length-headerSize);
    130             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    131             return 0;
    132         }
    133 
    134         outData32=(int32_t *)((char *)outData+headerSize);
    135 
    136         /* copy everything for inaccessible data (padding) */
    137         if(inData32!=outData32) {
    138             uprv_memcpy(outData32, inData32, 4*dataIndexes[UPROPS_RESERVED_INDEX]);
    139         }
    140 
    141         /* swap the indexes[16] */
    142         ds->swapArray32(ds, inData32, 4*UPROPS_INDEX_COUNT, outData32, pErrorCode);
    143 
    144         /*
    145          * swap the main properties UTrie
    146          * PT serialized properties trie, see utrie.h (byte size: 4*(i0-16))
    147          */
    148         utrie_swap(ds,
    149             inData32+UPROPS_INDEX_COUNT,
    150             4*(dataIndexes[UPROPS_PROPS32_INDEX]-UPROPS_INDEX_COUNT),
    151             outData32+UPROPS_INDEX_COUNT,
    152             pErrorCode);
    153 
    154         /*
    155          * swap the properties and exceptions words
    156          * P  const uint32_t props32[i1-i0];
    157          * E  const uint32_t exceptions[i2-i1];
    158          */
    159         ds->swapArray32(ds,
    160             inData32+dataIndexes[UPROPS_PROPS32_INDEX],
    161             4*(dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX]-dataIndexes[UPROPS_PROPS32_INDEX]),
    162             outData32+dataIndexes[UPROPS_PROPS32_INDEX],
    163             pErrorCode);
    164 
    165         /*
    166          * swap the UChars
    167          * U  const UChar uchars[2*(i3-i2)];
    168          */
    169         ds->swapArray16(ds,
    170             inData32+dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX],
    171             4*(dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX]-dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX]),
    172             outData32+dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX],
    173             pErrorCode);
    174 
    175         /*
    176          * swap the additional UTrie
    177          * i3 additionalTrieIndex; -- 32-bit unit index to the additional trie for more properties
    178          */
    179         utrie_swap(ds,
    180             inData32+dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX],
    181             4*(dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX]-dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX]),
    182             outData32+dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX],
    183             pErrorCode);
    184 
    185         /*
    186          * swap the properties vectors
    187          * PV const uint32_t propsVectors[(i6-i4)/i5][i5]==uint32_t propsVectors[i6-i4];
    188          */
    189         ds->swapArray32(ds,
    190             inData32+dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX],
    191             4*(dataIndexes[UPROPS_RESERVED_INDEX]-dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX]),
    192             outData32+dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX],
    193             pErrorCode);
    194     }
    195 
    196     /* i6 reservedItemIndex; -- 32-bit unit index to the top of the properties vectors table */
    197     return headerSize+4*dataIndexes[UPROPS_RESERVED_INDEX];
    198 }
    199 
    200 /* Unicode case mapping data swapping --------------------------------------- */
    201 
    202 U_CAPI int32_t U_EXPORT2
    203 ucase_swap(const UDataSwapper *ds,
    204            const void *inData, int32_t length, void *outData,
    205            UErrorCode *pErrorCode) {
    206     const UDataInfo *pInfo;
    207     int32_t headerSize;
    208 
    209     const uint8_t *inBytes;
    210     uint8_t *outBytes;
    211 
    212     const int32_t *inIndexes;
    213     int32_t indexes[16];
    214 
    215     int32_t i, offset, count, size;
    216 
    217     /* udata_swapDataHeader checks the arguments */
    218     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
    219     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    220         return 0;
    221     }
    222 
    223     /* check data format and format version */
    224     pInfo=(const UDataInfo *)((const char *)inData+4);
    225     if(!(
    226         pInfo->dataFormat[0]==UCASE_FMT_0 &&    /* dataFormat="cAsE" */
    227         pInfo->dataFormat[1]==UCASE_FMT_1 &&
    228         pInfo->dataFormat[2]==UCASE_FMT_2 &&
    229         pInfo->dataFormat[3]==UCASE_FMT_3 &&
    230         pInfo->formatVersion[0]==1 &&
    231         pInfo->formatVersion[2]==UTRIE_SHIFT &&
    232         pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
    233     )) {
    234         udata_printError(ds, "ucase_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as case mapping data\n",
    235                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    236                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    237                          pInfo->formatVersion[0]);
    238         *pErrorCode=U_UNSUPPORTED_ERROR;
    239         return 0;
    240     }
    241 
    242     inBytes=(const uint8_t *)inData+headerSize;
    243     outBytes=(uint8_t *)outData+headerSize;
    244 
    245     inIndexes=(const int32_t *)inBytes;
    246 
    247     if(length>=0) {
    248         length-=headerSize;
    249         if(length<16*4) {
    250             udata_printError(ds, "ucase_swap(): too few bytes (%d after header) for case mapping data\n",
    251                              length);
    252             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    253             return 0;
    254         }
    255     }
    256 
    257     /* read the first 16 indexes (ICU 3.2/format version 1: UCASE_IX_TOP==16, might grow) */
    258     for(i=0; i<16; ++i) {
    259         indexes[i]=udata_readInt32(ds, inIndexes[i]);
    260     }
    261 
    262     /* get the total length of the data */
    263     size=indexes[UCASE_IX_LENGTH];
    264 
    265     if(length>=0) {
    266         if(length<size) {
    267             udata_printError(ds, "ucase_swap(): too few bytes (%d after header) for all of case mapping data\n",
    268                              length);
    269             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    270             return 0;
    271         }
    272 
    273         /* copy the data for inaccessible bytes */
    274         if(inBytes!=outBytes) {
    275             uprv_memcpy(outBytes, inBytes, size);
    276         }
    277 
    278         offset=0;
    279 
    280         /* swap the int32_t indexes[] */
    281         count=indexes[UCASE_IX_INDEX_TOP]*4;
    282         ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
    283         offset+=count;
    284 
    285         /* swap the UTrie */
    286         count=indexes[UCASE_IX_TRIE_SIZE];
    287         utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    288         offset+=count;
    289 
    290         /* swap the uint16_t exceptions[] and unfold[] */
    291         count=(indexes[UCASE_IX_EXC_LENGTH]+indexes[UCASE_IX_UNFOLD_LENGTH])*2;
    292         ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    293         offset+=count;
    294 
    295         U_ASSERT(offset==size);
    296     }
    297 
    298     return headerSize+size;
    299 }
    300 
    301 /* Unicode bidi/shaping data swapping --------------------------------------- */
    302 
    303 U_CAPI int32_t U_EXPORT2
    304 ubidi_swap(const UDataSwapper *ds,
    305            const void *inData, int32_t length, void *outData,
    306            UErrorCode *pErrorCode) {
    307     const UDataInfo *pInfo;
    308     int32_t headerSize;
    309 
    310     const uint8_t *inBytes;
    311     uint8_t *outBytes;
    312 
    313     const int32_t *inIndexes;
    314     int32_t indexes[16];
    315 
    316     int32_t i, offset, count, size;
    317 
    318     /* udata_swapDataHeader checks the arguments */
    319     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
    320     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    321         return 0;
    322     }
    323 
    324     /* check data format and format version */
    325     pInfo=(const UDataInfo *)((const char *)inData+4);
    326     if(!(
    327         pInfo->dataFormat[0]==UBIDI_FMT_0 &&    /* dataFormat="BiDi" */
    328         pInfo->dataFormat[1]==UBIDI_FMT_1 &&
    329         pInfo->dataFormat[2]==UBIDI_FMT_2 &&
    330         pInfo->dataFormat[3]==UBIDI_FMT_3 &&
    331         pInfo->formatVersion[0]==1 &&
    332         pInfo->formatVersion[2]==UTRIE_SHIFT &&
    333         pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
    334     )) {
    335         udata_printError(ds, "ubidi_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as bidi/shaping data\n",
    336                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    337                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    338                          pInfo->formatVersion[0]);
    339         *pErrorCode=U_UNSUPPORTED_ERROR;
    340         return 0;
    341     }
    342 
    343     inBytes=(const uint8_t *)inData+headerSize;
    344     outBytes=(uint8_t *)outData+headerSize;
    345 
    346     inIndexes=(const int32_t *)inBytes;
    347 
    348     if(length>=0) {
    349         length-=headerSize;
    350         if(length<16*4) {
    351             udata_printError(ds, "ubidi_swap(): too few bytes (%d after header) for bidi/shaping data\n",
    352                              length);
    353             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    354             return 0;
    355         }
    356     }
    357 
    358     /* read the first 16 indexes (ICU 3.4/format version 1: UBIDI_IX_TOP==16, might grow) */
    359     for(i=0; i<16; ++i) {
    360         indexes[i]=udata_readInt32(ds, inIndexes[i]);
    361     }
    362 
    363     /* get the total length of the data */
    364     size=indexes[UBIDI_IX_LENGTH];
    365 
    366     if(length>=0) {
    367         if(length<size) {
    368             udata_printError(ds, "ubidi_swap(): too few bytes (%d after header) for all of bidi/shaping data\n",
    369                              length);
    370             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    371             return 0;
    372         }
    373 
    374         /* copy the data for inaccessible bytes */
    375         if(inBytes!=outBytes) {
    376             uprv_memcpy(outBytes, inBytes, size);
    377         }
    378 
    379         offset=0;
    380 
    381         /* swap the int32_t indexes[] */
    382         count=indexes[UBIDI_IX_INDEX_TOP]*4;
    383         ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
    384         offset+=count;
    385 
    386         /* swap the UTrie */
    387         count=indexes[UBIDI_IX_TRIE_SIZE];
    388         utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    389         offset+=count;
    390 
    391         /* swap the uint32_t mirrors[] */
    392         count=indexes[UBIDI_IX_MIRROR_LENGTH]*4;
    393         ds->swapArray32(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    394         offset+=count;
    395 
    396         /* just skip the uint8_t jgArray[] */
    397         count=indexes[UBIDI_IX_JG_LIMIT]-indexes[UBIDI_IX_JG_START];
    398         offset+=count;
    399 
    400         U_ASSERT(offset==size);
    401     }
    402 
    403     return headerSize+size;
    404 }
    405 
    406 /* Unicode normalization data swapping -------------------------------------- */
    407 
    408 #if !UCONFIG_NO_NORMALIZATION
    409 
    410 U_CAPI int32_t U_EXPORT2
    411 unorm_swap(const UDataSwapper *ds,
    412            const void *inData, int32_t length, void *outData,
    413            UErrorCode *pErrorCode) {
    414     const UDataInfo *pInfo;
    415     int32_t headerSize;
    416 
    417     const uint8_t *inBytes;
    418     uint8_t *outBytes;
    419 
    420     const int32_t *inIndexes;
    421     int32_t indexes[32];
    422 
    423     int32_t i, offset, count, size;
    424 
    425     /* udata_swapDataHeader checks the arguments */
    426     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
    427     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    428         return 0;
    429     }
    430 
    431     /* check data format and format version */
    432     pInfo=(const UDataInfo *)((const char *)inData+4);
    433     if(!(
    434         pInfo->dataFormat[0]==0x4e &&   /* dataFormat="Norm" */
    435         pInfo->dataFormat[1]==0x6f &&
    436         pInfo->dataFormat[2]==0x72 &&
    437         pInfo->dataFormat[3]==0x6d &&
    438         pInfo->formatVersion[0]==2
    439     )) {
    440         udata_printError(ds, "unorm_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as unorm.icu\n",
    441                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    442                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    443                          pInfo->formatVersion[0]);
    444         *pErrorCode=U_UNSUPPORTED_ERROR;
    445         return 0;
    446     }
    447 
    448     inBytes=(const uint8_t *)inData+headerSize;
    449     outBytes=(uint8_t *)outData+headerSize;
    450 
    451     inIndexes=(const int32_t *)inBytes;
    452 
    453     if(length>=0) {
    454         length-=headerSize;
    455         if(length<32*4) {
    456             udata_printError(ds, "unorm_swap(): too few bytes (%d after header) for unorm.icu\n",
    457                              length);
    458             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    459             return 0;
    460         }
    461     }
    462 
    463     /* read the first 32 indexes (ICU 2.8/format version 2.2: _NORM_INDEX_TOP==32, might grow) */
    464     for(i=0; i<32; ++i) {
    465         indexes[i]=udata_readInt32(ds, inIndexes[i]);
    466     }
    467 
    468     /* calculate the total length of the data */
    469     size=
    470         32*4+ /* size of indexes[] */
    471         indexes[_NORM_INDEX_TRIE_SIZE]+
    472         indexes[_NORM_INDEX_UCHAR_COUNT]*2+
    473         indexes[_NORM_INDEX_COMBINE_DATA_COUNT]*2+
    474         indexes[_NORM_INDEX_FCD_TRIE_SIZE]+
    475         indexes[_NORM_INDEX_AUX_TRIE_SIZE]+
    476         indexes[_NORM_INDEX_CANON_SET_COUNT]*2;
    477 
    478     if(length>=0) {
    479         if(length<size) {
    480             udata_printError(ds, "unorm_swap(): too few bytes (%d after header) for all of unorm.icu\n",
    481                              length);
    482             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    483             return 0;
    484         }
    485 
    486         /* copy the data for inaccessible bytes */
    487         if(inBytes!=outBytes) {
    488             uprv_memcpy(outBytes, inBytes, size);
    489         }
    490 
    491         offset=0;
    492 
    493         /* swap the indexes[] */
    494         count=32*4;
    495         ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
    496         offset+=count;
    497 
    498         /* swap the main UTrie */
    499         count=indexes[_NORM_INDEX_TRIE_SIZE];
    500         utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    501         offset+=count;
    502 
    503         /* swap the uint16_t extraData[] and the uint16_t combiningTable[] */
    504         count=(indexes[_NORM_INDEX_UCHAR_COUNT]+indexes[_NORM_INDEX_COMBINE_DATA_COUNT])*2;
    505         ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    506         offset+=count;
    507 
    508         /* swap the FCD UTrie */
    509         count=indexes[_NORM_INDEX_FCD_TRIE_SIZE];
    510         if(count!=0) {
    511             utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    512             offset+=count;
    513         }
    514 
    515         /* swap the aux UTrie */
    516         count=indexes[_NORM_INDEX_AUX_TRIE_SIZE];
    517         if(count!=0) {
    518             utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    519             offset+=count;
    520         }
    521 
    522         /* swap the uint16_t combiningTable[] */
    523         count=indexes[_NORM_INDEX_CANON_SET_COUNT]*2;
    524         ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
    525         offset+=count;
    526     }
    527 
    528     return headerSize+size;
    529 }
    530 
    531 #endif
    532 
    533 /* Swap 'Test' data from gentest */
    534 U_CAPI int32_t U_EXPORT2
    535 test_swap(const UDataSwapper *ds,
    536            const void *inData, int32_t length, void *outData,
    537            UErrorCode *pErrorCode) {
    538     const UDataInfo *pInfo;
    539     int32_t headerSize;
    540 
    541     const uint8_t *inBytes;
    542     uint8_t *outBytes;
    543 
    544     const int32_t *inIndexes;
    545     int32_t indexes[32];
    546 
    547     int32_t i, offset, count;
    548 
    549     /* udata_swapDataHeader checks the arguments */
    550     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
    551     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    552         udata_printError(ds, "test_swap(): data header swap failed %s\n", u_errorName(*pErrorCode));
    553         return 0;
    554     }
    555 
    556     /* check data format and format version */
    557     pInfo=(const UDataInfo *)((const char *)inData+4);
    558     if(!(
    559         pInfo->dataFormat[0]==0x54 &&   /* dataFormat="Norm" */
    560         pInfo->dataFormat[1]==0x65 &&
    561         pInfo->dataFormat[2]==0x73 &&
    562         pInfo->dataFormat[3]==0x74 &&
    563         pInfo->formatVersion[0]==1
    564     )) {
    565         udata_printError(ds, "test_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as testdata\n",
    566                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    567                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    568                          pInfo->formatVersion[0]);
    569         *pErrorCode=U_UNSUPPORTED_ERROR;
    570         return 0;
    571     }
    572 
    573     inBytes=(const uint8_t *)inData+headerSize;
    574     outBytes=(uint8_t *)outData+headerSize;
    575 
    576     int32_t size16 = 2; // 16bit plus padding
    577     int32_t sizeStr = 5; // 4 char inv-str plus null
    578     int32_t size = size16 + sizeStr;
    579 
    580     if(length>=0) {
    581         if(length<size) {
    582             udata_printError(ds, "test_swap(): too few bytes (%d after header, wanted %d) for all of testdata\n",
    583                              length, size);
    584             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    585             return 0;
    586         }
    587 
    588 	offset =0;
    589 	/* swap a 1 entry array */
    590         ds->swapArray16(ds, inBytes+offset, size16, outBytes+offset, pErrorCode);
    591 	offset+=size16;
    592 	ds->swapInvChars(ds, inBytes+offset, sizeStr, outBytes+offset, pErrorCode);
    593     }
    594 
    595     return headerSize+size;
    596 }
    597 /* swap any data (except a .dat package) ------------------------------------ */
    598 
    599 static const struct {
    600     uint8_t dataFormat[4];
    601     UDataSwapFn *swapFn;
    602 } swapFns[]={
    603     { { 0x52, 0x65, 0x73, 0x42 }, ures_swap },          /* dataFormat="ResB" */
    604 #if !UCONFIG_NO_LEGACY_CONVERSION
    605     { { 0x63, 0x6e, 0x76, 0x74 }, ucnv_swap },          /* dataFormat="cnvt" */
    606 #endif
    607 #if !UCONFIG_NO_CONVERSION
    608     { { 0x43, 0x76, 0x41, 0x6c }, ucnv_swapAliases },   /* dataFormat="CvAl" */
    609 #endif
    610 #if !UCONFIG_NO_IDNA
    611     { { 0x53, 0x50, 0x52, 0x50 }, usprep_swap },        /* dataFormat="SPRP" */
    612 #endif
    613     /* insert data formats here, descending by expected frequency of occurrence */
    614     { { 0x55, 0x50, 0x72, 0x6f }, uprops_swap },        /* dataFormat="UPro" */
    615 
    616     { { UCASE_FMT_0, UCASE_FMT_1, UCASE_FMT_2, UCASE_FMT_3 },
    617                                   ucase_swap },         /* dataFormat="cAsE" */
    618 
    619     { { UBIDI_FMT_0, UBIDI_FMT_1, UBIDI_FMT_2, UBIDI_FMT_3 },
    620                                   ubidi_swap },         /* dataFormat="BiDi" */
    621 
    622 #if !UCONFIG_NO_NORMALIZATION
    623     { { 0x4e, 0x6f, 0x72, 0x6d }, unorm_swap },         /* dataFormat="Norm" */
    624 #endif
    625 #if !UCONFIG_NO_COLLATION
    626     { { 0x55, 0x43, 0x6f, 0x6c }, ucol_swap },          /* dataFormat="UCol" */
    627     { { 0x49, 0x6e, 0x76, 0x43 }, ucol_swapInverseUCA },/* dataFormat="InvC" */
    628 #endif
    629 #if !UCONFIG_NO_BREAK_ITERATION
    630     { { 0x42, 0x72, 0x6b, 0x20 }, ubrk_swap },          /* dataFormat="Brk " */
    631     { { 0x54, 0x72, 0x44, 0x63 }, triedict_swap },      /* dataFormat="TrDc " */
    632 #endif
    633     { { 0x70, 0x6e, 0x61, 0x6d }, upname_swap },        /* dataFormat="pnam" */
    634     { { 0x75, 0x6e, 0x61, 0x6d }, uchar_swapNames },    /* dataFormat="unam" */
    635 
    636     { { 0x43, 0x66, 0x75, 0x20 }, uspoof_swap },         /* dataFormat="Cfu " */
    637 
    638     { { 0x54, 0x65, 0x73, 0x74 }, test_swap }            /* dataFormat="Test" */
    639 };
    640 
    641 U_CAPI int32_t U_EXPORT2
    642 udata_swap(const UDataSwapper *ds,
    643            const void *inData, int32_t length, void *outData,
    644            UErrorCode *pErrorCode) {
    645     char dataFormatChars[4];
    646     const UDataInfo *pInfo;
    647     int32_t headerSize, i, swappedLength;
    648 
    649     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    650         return 0;
    651     }
    652 
    653     /*
    654      * Preflight the header first; checks for illegal arguments, too.
    655      * Do not swap the header right away because the format-specific swapper
    656      * will swap it, get the headerSize again, and also use the header
    657      * information. Otherwise we would have to pass some of the information
    658      * and not be able to use the UDataSwapFn signature.
    659      */
    660     headerSize=udata_swapDataHeader(ds, inData, -1, NULL, pErrorCode);
    661 
    662     /*
    663      * If we wanted udata_swap() to also handle non-loadable data like a UTrie,
    664      * then we could check here for further known magic values and structures.
    665      */
    666     if(U_FAILURE(*pErrorCode)) {
    667         return 0; /* the data format was not recognized */
    668     }
    669 
    670     pInfo=(const UDataInfo *)((const char *)inData+4);
    671 
    672     {
    673         /* convert the data format from ASCII to Unicode to the system charset */
    674         UChar u[4]={
    675              pInfo->dataFormat[0], pInfo->dataFormat[1],
    676              pInfo->dataFormat[2], pInfo->dataFormat[3]
    677         };
    678 
    679         if(uprv_isInvariantUString(u, 4)) {
    680             u_UCharsToChars(u, dataFormatChars, 4);
    681         } else {
    682             dataFormatChars[0]=dataFormatChars[1]=dataFormatChars[2]=dataFormatChars[3]='?';
    683         }
    684     }
    685 
    686     /* dispatch to the swap function for the dataFormat */
    687     for(i=0; i<LENGTHOF(swapFns); ++i) {
    688         if(0==memcmp(swapFns[i].dataFormat, pInfo->dataFormat, 4)) {
    689             swappedLength=swapFns[i].swapFn(ds, inData, length, outData, pErrorCode);
    690 
    691             if(U_FAILURE(*pErrorCode)) {
    692                 udata_printError(ds, "udata_swap(): failure swapping data format %02x.%02x.%02x.%02x (\"%c%c%c%c\") - %s\n",
    693                                  pInfo->dataFormat[0], pInfo->dataFormat[1],
    694                                  pInfo->dataFormat[2], pInfo->dataFormat[3],
    695                                  dataFormatChars[0], dataFormatChars[1],
    696                                  dataFormatChars[2], dataFormatChars[3],
    697                                  u_errorName(*pErrorCode));
    698             } else if(swappedLength<(length-15)) {
    699                 /* swapped less than expected */
    700                 udata_printError(ds, "udata_swap() warning: swapped only %d out of %d bytes - data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
    701                                  swappedLength, length,
    702                                  pInfo->dataFormat[0], pInfo->dataFormat[1],
    703                                  pInfo->dataFormat[2], pInfo->dataFormat[3],
    704                                  dataFormatChars[0], dataFormatChars[1],
    705                                  dataFormatChars[2], dataFormatChars[3],
    706                                  u_errorName(*pErrorCode));
    707             }
    708 
    709             return swappedLength;
    710         }
    711     }
    712 
    713     /* the dataFormat was not recognized */
    714     udata_printError(ds, "udata_swap(): unknown data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
    715                      pInfo->dataFormat[0], pInfo->dataFormat[1],
    716                      pInfo->dataFormat[2], pInfo->dataFormat[3],
    717                      dataFormatChars[0], dataFormatChars[1],
    718                      dataFormatChars[2], dataFormatChars[3]);
    719 
    720     *pErrorCode=U_UNSUPPORTED_ERROR;
    721     return 0;
    722 }
    723