Home | History | Annotate | Download | only in common
      1 /*
      2 **********************************************************************
      3 * Copyright (c) 2002-2006, International Business Machines
      4 * Corporation and others.  All Rights Reserved.
      5 **********************************************************************
      6 * Author: Alan Liu
      7 * Created: October 30 2002
      8 * Since: ICU 2.4
      9 **********************************************************************
     10 */
     11 #include "propname.h"
     12 #include "unicode/uchar.h"
     13 #include "unicode/udata.h"
     14 #include "umutex.h"
     15 #include "cmemory.h"
     16 #include "cstring.h"
     17 #include "ucln_cmn.h"
     18 #include "uarrsort.h"
     19 
     20 U_CDECL_BEGIN
     21 
     22 /**
     23  * Get the next non-ignorable ASCII character from a property name
     24  * and lowercases it.
     25  * @return ((advance count for the name)<<8)|character
     26  */
     27 static inline int32_t
     28 getASCIIPropertyNameChar(const char *name) {
     29     int32_t i;
     30     char c;
     31 
     32     /* Ignore delimiters '-', '_', and ASCII White_Space */
     33     for(i=0;
     34         (c=name[i++])==0x2d || c==0x5f ||
     35         c==0x20 || (0x09<=c && c<=0x0d);
     36     ) {}
     37 
     38     if(c!=0) {
     39         return (i<<8)|(uint8_t)uprv_asciitolower((char)c);
     40     } else {
     41         return i<<8;
     42     }
     43 }
     44 
     45 /**
     46  * Get the next non-ignorable EBCDIC character from a property name
     47  * and lowercases it.
     48  * @return ((advance count for the name)<<8)|character
     49  */
     50 static inline int32_t
     51 getEBCDICPropertyNameChar(const char *name) {
     52     int32_t i;
     53     char c;
     54 
     55     /* Ignore delimiters '-', '_', and EBCDIC White_Space */
     56     for(i=0;
     57         (c=name[i++])==0x60 || c==0x6d ||
     58         c==0x40 || c==0x05 || c==0x15 || c==0x25 || c==0x0b || c==0x0c || c==0x0d;
     59     ) {}
     60 
     61     if(c!=0) {
     62         return (i<<8)|(uint8_t)uprv_ebcdictolower((char)c);
     63     } else {
     64         return i<<8;
     65     }
     66 }
     67 
     68 /**
     69  * Unicode property names and property value names are compared "loosely".
     70  *
     71  * UCD.html 4.0.1 says:
     72  *   For all property names, property value names, and for property values for
     73  *   Enumerated, Binary, or Catalog properties, use the following
     74  *   loose matching rule:
     75  *
     76  *   LM3. Ignore case, whitespace, underscore ('_'), and hyphens.
     77  *
     78  * This function does just that, for (char *) name strings.
     79  * It is almost identical to ucnv_compareNames() but also ignores
     80  * C0 White_Space characters (U+0009..U+000d, and U+0085 on EBCDIC).
     81  *
     82  * @internal
     83  */
     84 
     85 U_CAPI int32_t U_EXPORT2
     86 uprv_compareASCIIPropertyNames(const char *name1, const char *name2) {
     87     int32_t rc, r1, r2;
     88 
     89     for(;;) {
     90         r1=getASCIIPropertyNameChar(name1);
     91         r2=getASCIIPropertyNameChar(name2);
     92 
     93         /* If we reach the ends of both strings then they match */
     94         if(((r1|r2)&0xff)==0) {
     95             return 0;
     96         }
     97 
     98         /* Compare the lowercased characters */
     99         if(r1!=r2) {
    100             rc=(r1&0xff)-(r2&0xff);
    101             if(rc!=0) {
    102                 return rc;
    103             }
    104         }
    105 
    106         name1+=r1>>8;
    107         name2+=r2>>8;
    108     }
    109 }
    110 
    111 U_CAPI int32_t U_EXPORT2
    112 uprv_compareEBCDICPropertyNames(const char *name1, const char *name2) {
    113     int32_t rc, r1, r2;
    114 
    115     for(;;) {
    116         r1=getEBCDICPropertyNameChar(name1);
    117         r2=getEBCDICPropertyNameChar(name2);
    118 
    119         /* If we reach the ends of both strings then they match */
    120         if(((r1|r2)&0xff)==0) {
    121             return 0;
    122         }
    123 
    124         /* Compare the lowercased characters */
    125         if(r1!=r2) {
    126             rc=(r1&0xff)-(r2&0xff);
    127             if(rc!=0) {
    128                 return rc;
    129             }
    130         }
    131 
    132         name1+=r1>>8;
    133         name2+=r2>>8;
    134     }
    135 }
    136 
    137 U_CDECL_END
    138 
    139 U_NAMESPACE_BEGIN
    140 
    141 //----------------------------------------------------------------------
    142 // PropertyAliases implementation
    143 
    144 const char*
    145 PropertyAliases::chooseNameInGroup(Offset offset,
    146                                    UPropertyNameChoice choice) const {
    147     int32_t c = choice;
    148     if (!offset || c < 0) {
    149         return NULL;
    150     }
    151     const Offset* p = (const Offset*) getPointer(offset);
    152     while (c-- > 0) {
    153         if (*p++ < 0) return NULL;
    154     }
    155     Offset a = *p;
    156     if (a < 0) a = -a;
    157     return (const char*) getPointerNull(a);
    158 }
    159 
    160 const ValueMap*
    161 PropertyAliases::getValueMap(EnumValue prop) const {
    162     NonContiguousEnumToOffset* e2o = (NonContiguousEnumToOffset*) getPointer(enumToValue_offset);
    163     Offset a = e2o->getOffset(prop);
    164     return (const ValueMap*) (a ? getPointerNull(a) : NULL);
    165 }
    166 
    167 inline const char*
    168 PropertyAliases::getPropertyName(EnumValue prop,
    169                                  UPropertyNameChoice choice) const {
    170     NonContiguousEnumToOffset* e2n = (NonContiguousEnumToOffset*) getPointer(enumToName_offset);
    171     return chooseNameInGroup(e2n->getOffset(prop), choice);
    172 }
    173 
    174 inline EnumValue
    175 PropertyAliases::getPropertyEnum(const char* alias) const {
    176     NameToEnum* n2e = (NameToEnum*) getPointer(nameToEnum_offset);
    177     return n2e->getEnum(alias, *this);
    178 }
    179 
    180 inline const char*
    181 PropertyAliases::getPropertyValueName(EnumValue prop,
    182                                       EnumValue value,
    183                                       UPropertyNameChoice choice) const {
    184     const ValueMap* vm = getValueMap(prop);
    185     if (!vm) return NULL;
    186     Offset a;
    187     if (vm->enumToName_offset) {
    188         a = ((EnumToOffset*) getPointer(vm->enumToName_offset))->
    189             getOffset(value);
    190     } else {
    191         a = ((NonContiguousEnumToOffset*) getPointer(vm->ncEnumToName_offset))->
    192             getOffset(value);
    193     }
    194     return chooseNameInGroup(a, choice);
    195 }
    196 
    197 inline EnumValue
    198 PropertyAliases::getPropertyValueEnum(EnumValue prop,
    199                                       const char* alias) const {
    200     const ValueMap* vm = getValueMap(prop);
    201     if (!vm) return UCHAR_INVALID_CODE;
    202     NameToEnum* n2e = (NameToEnum*) getPointer(vm->nameToEnum_offset);
    203     return n2e->getEnum(alias, *this);
    204 }
    205 
    206 U_NAMESPACE_END
    207 U_NAMESPACE_USE
    208 
    209 //----------------------------------------------------------------------
    210 // UDataMemory structures
    211 
    212 static const PropertyAliases* PNAME = NULL;
    213 static UDataMemory* UDATA = NULL;
    214 
    215 //----------------------------------------------------------------------
    216 // UDataMemory loading/unloading
    217 
    218 /**
    219  * udata callback to verify the zone data.
    220  */
    221 U_CDECL_BEGIN
    222 static UBool U_CALLCONV
    223 isPNameAcceptable(void* /*context*/,
    224              const char* /*type*/, const char* /*name*/,
    225              const UDataInfo* info) {
    226     return
    227         info->size >= sizeof(UDataInfo) &&
    228         info->isBigEndian == U_IS_BIG_ENDIAN &&
    229         info->charsetFamily == U_CHARSET_FAMILY &&
    230         info->dataFormat[0] == PNAME_SIG_0 &&
    231         info->dataFormat[1] == PNAME_SIG_1 &&
    232         info->dataFormat[2] == PNAME_SIG_2 &&
    233         info->dataFormat[3] == PNAME_SIG_3 &&
    234         info->formatVersion[0] == PNAME_FORMAT_VERSION;
    235 }
    236 
    237 static UBool U_CALLCONV pname_cleanup(void) {
    238     if (UDATA) {
    239         udata_close(UDATA);
    240         UDATA = NULL;
    241     }
    242     PNAME = NULL;
    243     return TRUE;
    244 }
    245 U_CDECL_END
    246 
    247 /**
    248  * Load the property names data.  Caller should check that data is
    249  * not loaded BEFORE calling this function.  Returns TRUE if the load
    250  * succeeds.
    251  */
    252 static UBool _load() {
    253     UErrorCode ec = U_ZERO_ERROR;
    254     UDataMemory* data =
    255         udata_openChoice(0, PNAME_DATA_TYPE, PNAME_DATA_NAME,
    256                          isPNameAcceptable, 0, &ec);
    257     if (U_SUCCESS(ec)) {
    258         umtx_lock(NULL);
    259         if (UDATA == NULL) {
    260             UDATA = data;
    261             PNAME = (const PropertyAliases*) udata_getMemory(UDATA);
    262             ucln_common_registerCleanup(UCLN_COMMON_PNAME, pname_cleanup);
    263             data = NULL;
    264         }
    265         umtx_unlock(NULL);
    266     }
    267     if (data) {
    268         udata_close(data);
    269     }
    270     return PNAME!=NULL;
    271 }
    272 
    273 /**
    274  * Inline function that expands to code that does a lazy load of the
    275  * property names data.  If the data is already loaded, avoids an
    276  * unnecessary function call.  If the data is not loaded, call _load()
    277  * to load it, and return TRUE if the load succeeds.
    278  */
    279 static inline UBool load() {
    280     UBool f;
    281     UMTX_CHECK(NULL, (PNAME!=NULL), f);
    282     return f || _load();
    283 }
    284 
    285 //----------------------------------------------------------------------
    286 // Public API implementation
    287 
    288 // The C API is just a thin wrapper.  Each function obtains a pointer
    289 // to the singleton PropertyAliases, and calls the appropriate method
    290 // on it.  If it cannot obtain a pointer, because valid data is not
    291 // available, then it returns NULL or UCHAR_INVALID_CODE.
    292 
    293 U_CAPI const char* U_EXPORT2
    294 u_getPropertyName(UProperty property,
    295                   UPropertyNameChoice nameChoice) {
    296     return load() ? PNAME->getPropertyName(property, nameChoice)
    297                   : NULL;
    298 }
    299 
    300 U_CAPI UProperty U_EXPORT2
    301 u_getPropertyEnum(const char* alias) {
    302     UProperty p = load() ? (UProperty) PNAME->getPropertyEnum(alias)
    303                          : UCHAR_INVALID_CODE;
    304     return p;
    305 }
    306 
    307 U_CAPI const char* U_EXPORT2
    308 u_getPropertyValueName(UProperty property,
    309                        int32_t value,
    310                        UPropertyNameChoice nameChoice) {
    311     return load() ? PNAME->getPropertyValueName(property, value, nameChoice)
    312                   : NULL;
    313 }
    314 
    315 U_CAPI int32_t U_EXPORT2
    316 u_getPropertyValueEnum(UProperty property,
    317                        const char* alias) {
    318     return load() ? PNAME->getPropertyValueEnum(property, alias)
    319                   : (int32_t)UCHAR_INVALID_CODE;
    320 }
    321 
    322 /* data swapping ------------------------------------------------------------ */
    323 
    324 /*
    325  * Sub-structure-swappers use the temp array (which is as large as the
    326  * actual data) for intermediate storage,
    327  * as well as to indicate if a particular structure has been swapped already.
    328  * The temp array is initially reset to all 0.
    329  * pos is the byte offset of the sub-structure in the inBytes/outBytes/temp arrays.
    330  */
    331 
    332 int32_t
    333 EnumToOffset::swap(const UDataSwapper *ds,
    334                    const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
    335                    uint8_t *temp, int32_t pos,
    336                    UErrorCode *pErrorCode) {
    337     const EnumToOffset *inMap;
    338     EnumToOffset *outMap, *tempMap;
    339     int32_t size;
    340 
    341     tempMap=(EnumToOffset *)(temp+pos);
    342     if(tempMap->enumStart!=0 || tempMap->enumLimit!=0) {
    343         /* this map was swapped already */
    344         size=tempMap->getSize();
    345         return size;
    346     }
    347 
    348     inMap=(const EnumToOffset *)(inBytes+pos);
    349     outMap=(EnumToOffset *)(outBytes+pos);
    350 
    351     tempMap->enumStart=udata_readInt32(ds, inMap->enumStart);
    352     tempMap->enumLimit=udata_readInt32(ds, inMap->enumLimit);
    353     size=tempMap->getSize();
    354 
    355     if(length>=0) {
    356         if(length<(pos+size)) {
    357             if(length<(int32_t)sizeof(PropertyAliases)) {
    358                 udata_printError(ds, "upname_swap(EnumToOffset): too few bytes (%d after header)\n"
    359                                      "    for pnames.icu EnumToOffset{%d..%d} at %d\n",
    360                                  length, tempMap->enumStart, tempMap->enumLimit, pos);
    361                 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    362                 return 0;
    363             }
    364         }
    365 
    366         /* swap enumStart and enumLimit */
    367         ds->swapArray32(ds, inMap, 2*sizeof(EnumValue), outMap, pErrorCode);
    368 
    369         /* swap _offsetArray[] */
    370         ds->swapArray16(ds, inMap->getOffsetArray(), (tempMap->enumLimit-tempMap->enumStart)*sizeof(Offset),
    371                            outMap->getOffsetArray(), pErrorCode);
    372     }
    373 
    374     return size;
    375 }
    376 
    377 int32_t
    378 NonContiguousEnumToOffset::swap(const UDataSwapper *ds,
    379                    const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
    380                    uint8_t *temp, int32_t pos,
    381                    UErrorCode *pErrorCode) {
    382     const NonContiguousEnumToOffset *inMap;
    383     NonContiguousEnumToOffset *outMap, *tempMap;
    384     int32_t size;
    385 
    386     tempMap=(NonContiguousEnumToOffset *)(temp+pos);
    387     if(tempMap->count!=0) {
    388         /* this map was swapped already */
    389         size=tempMap->getSize();
    390         return size;
    391     }
    392 
    393     inMap=(const NonContiguousEnumToOffset *)(inBytes+pos);
    394     outMap=(NonContiguousEnumToOffset *)(outBytes+pos);
    395 
    396     tempMap->count=udata_readInt32(ds, inMap->count);
    397     size=tempMap->getSize();
    398 
    399     if(length>=0) {
    400         if(length<(pos+size)) {
    401             if(length<(int32_t)sizeof(PropertyAliases)) {
    402                 udata_printError(ds, "upname_swap(NonContiguousEnumToOffset): too few bytes (%d after header)\n"
    403                                      "    for pnames.icu NonContiguousEnumToOffset[%d] at %d\n",
    404                                  length, tempMap->count, pos);
    405                 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    406                 return 0;
    407             }
    408         }
    409 
    410         /* swap count and _enumArray[] */
    411         length=(1+tempMap->count)*sizeof(EnumValue);
    412         ds->swapArray32(ds, inMap, length,
    413                            outMap, pErrorCode);
    414 
    415         /* swap _offsetArray[] */
    416         pos+=length;
    417         ds->swapArray16(ds, inBytes+pos, tempMap->count*sizeof(Offset),
    418                            outBytes+pos, pErrorCode);
    419     }
    420 
    421     return size;
    422 }
    423 
    424 struct NameAndIndex {
    425     Offset name, index;
    426 };
    427 
    428 U_CDECL_BEGIN
    429 typedef int32_t U_CALLCONV PropNameCompareFn(const char *name1, const char *name2);
    430 
    431 struct CompareContext {
    432     const char *chars;
    433     PropNameCompareFn *propCompare;
    434 };
    435 
    436 static int32_t U_CALLCONV
    437 upname_compareRows(const void *context, const void *left, const void *right) {
    438     CompareContext *cmp=(CompareContext *)context;
    439     return cmp->propCompare(cmp->chars+((const NameAndIndex *)left)->name,
    440                             cmp->chars+((const NameAndIndex *)right)->name);
    441 }
    442 U_CDECL_END
    443 
    444 int32_t
    445 NameToEnum::swap(const UDataSwapper *ds,
    446                    const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
    447                    uint8_t *temp, int32_t pos,
    448                    UErrorCode *pErrorCode) {
    449     const NameToEnum *inMap;
    450     NameToEnum *outMap, *tempMap;
    451 
    452     const EnumValue *inEnumArray;
    453     EnumValue *outEnumArray;
    454 
    455     const Offset *inNameArray;
    456     Offset *outNameArray;
    457 
    458     NameAndIndex *sortArray;
    459     CompareContext cmp;
    460 
    461     int32_t i, size, oldIndex;
    462 
    463     tempMap=(NameToEnum *)(temp+pos);
    464     if(tempMap->count!=0) {
    465         /* this map was swapped already */
    466         size=tempMap->getSize();
    467         return size;
    468     }
    469 
    470     inMap=(const NameToEnum *)(inBytes+pos);
    471     outMap=(NameToEnum *)(outBytes+pos);
    472 
    473     tempMap->count=udata_readInt32(ds, inMap->count);
    474     size=tempMap->getSize();
    475 
    476     if(length>=0) {
    477         if(length<(pos+size)) {
    478             if(length<(int32_t)sizeof(PropertyAliases)) {
    479                 udata_printError(ds, "upname_swap(NameToEnum): too few bytes (%d after header)\n"
    480                                      "    for pnames.icu NameToEnum[%d] at %d\n",
    481                                  length, tempMap->count, pos);
    482                 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    483                 return 0;
    484             }
    485         }
    486 
    487         /* swap count */
    488         ds->swapArray32(ds, inMap, 4, outMap, pErrorCode);
    489 
    490         inEnumArray=inMap->getEnumArray();
    491         outEnumArray=outMap->getEnumArray();
    492 
    493         inNameArray=(const Offset *)(inEnumArray+tempMap->count);
    494         outNameArray=(Offset *)(outEnumArray+tempMap->count);
    495 
    496         if(ds->inCharset==ds->outCharset) {
    497             /* no need to sort, just swap the enum/name arrays */
    498             ds->swapArray32(ds, inEnumArray, tempMap->count*4, outEnumArray, pErrorCode);
    499             ds->swapArray16(ds, inNameArray, tempMap->count*2, outNameArray, pErrorCode);
    500             return size;
    501         }
    502 
    503         /*
    504          * The name and enum arrays are sorted by names and must be resorted
    505          * if inCharset!=outCharset.
    506          * We use the corresponding part of the temp array to sort an array
    507          * of pairs of name offsets and sorting indexes.
    508          * Then the sorting indexes are used to permutate-swap the name and enum arrays.
    509          *
    510          * The outBytes must already contain the swapped strings.
    511          */
    512         sortArray=(NameAndIndex *)tempMap->getEnumArray();
    513         for(i=0; i<tempMap->count; ++i) {
    514             sortArray[i].name=udata_readInt16(ds, inNameArray[i]);
    515             sortArray[i].index=(Offset)i;
    516         }
    517 
    518         /*
    519          * use a stable sort to avoid shuffling of equal strings,
    520          * which makes testing harder
    521          */
    522         cmp.chars=(const char *)outBytes;
    523         if (ds->outCharset==U_ASCII_FAMILY) {
    524             cmp.propCompare=uprv_compareASCIIPropertyNames;
    525         }
    526         else {
    527             cmp.propCompare=uprv_compareEBCDICPropertyNames;
    528         }
    529         uprv_sortArray(sortArray, tempMap->count, sizeof(NameAndIndex),
    530                        upname_compareRows, &cmp,
    531                        TRUE, pErrorCode);
    532         if(U_FAILURE(*pErrorCode)) {
    533             udata_printError(ds, "upname_swap(NameToEnum).uprv_sortArray(%d items) failed\n",
    534                              tempMap->count);
    535             return 0;
    536         }
    537 
    538         /* copy/swap/permutate _enumArray[] and _nameArray[] */
    539         if(inEnumArray!=outEnumArray) {
    540             for(i=0; i<tempMap->count; ++i) {
    541                 oldIndex=sortArray[i].index;
    542                 ds->swapArray32(ds, inEnumArray+oldIndex, 4, outEnumArray+i, pErrorCode);
    543                 ds->swapArray16(ds, inNameArray+oldIndex, 2, outNameArray+i, pErrorCode);
    544             }
    545         } else {
    546             /*
    547              * in-place swapping: need to permutate into a temporary array
    548              * and then copy back to not destroy the data
    549              */
    550             EnumValue *tempEnumArray;
    551             Offset *oldIndexes;
    552 
    553             /* write name offsets directly from sortArray */
    554             for(i=0; i<tempMap->count; ++i) {
    555                 ds->writeUInt16((uint16_t *)outNameArray+i, (uint16_t)sortArray[i].name);
    556             }
    557 
    558             /*
    559              * compress the oldIndexes into a separate array to make space for tempEnumArray
    560              * the tempMap _nameArray becomes oldIndexes[], getting the index
    561              *   values from the 2D sortArray[],
    562              * while sortArray=tempMap _enumArray[] becomes tempEnumArray[]
    563              * this saves us allocating more memory
    564              *
    565              * it works because sizeof(NameAndIndex)<=sizeof(EnumValue)
    566              * and because the nameArray[] can be used for oldIndexes[]
    567              */
    568             tempEnumArray=(EnumValue *)sortArray;
    569             oldIndexes=(Offset *)(sortArray+tempMap->count);
    570 
    571             /* copy sortArray[].index values into oldIndexes[] */
    572             for(i=0; i<tempMap->count; ++i) {
    573                 oldIndexes[i]=sortArray[i].index;
    574             }
    575 
    576             /* permutate inEnumArray[] into tempEnumArray[] */
    577             for(i=0; i<tempMap->count; ++i) {
    578                 ds->swapArray32(ds, inEnumArray+oldIndexes[i], 4, tempEnumArray+i, pErrorCode);
    579             }
    580 
    581             /* copy tempEnumArray[] to outEnumArray[] */
    582             uprv_memcpy(outEnumArray, tempEnumArray, tempMap->count*4);
    583         }
    584     }
    585 
    586     return size;
    587 }
    588 
    589 int32_t
    590 PropertyAliases::swap(const UDataSwapper *ds,
    591                       const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
    592                       UErrorCode *pErrorCode) {
    593     const PropertyAliases *inAliases;
    594     PropertyAliases *outAliases;
    595     PropertyAliases aliases;
    596 
    597     const ValueMap *inValueMaps;
    598     ValueMap *outValueMaps;
    599     ValueMap valueMap;
    600 
    601     uint8_t *temp;
    602 
    603     int32_t i;
    604 
    605     inAliases=(const PropertyAliases *)inBytes;
    606     outAliases=(PropertyAliases *)outBytes;
    607 
    608     /* read the input PropertyAliases - all 16-bit values */
    609     for(i=0; i<(int32_t)sizeof(PropertyAliases)/2; ++i) {
    610         ((uint16_t *)&aliases)[i]=ds->readUInt16(((const uint16_t *)inBytes)[i]);
    611     }
    612 
    613     if(length>=0) {
    614         if(length<aliases.total_size) {
    615             udata_printError(ds, "upname_swap(): too few bytes (%d after header) for all of pnames.icu\n",
    616                              length);
    617             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    618             return 0;
    619         }
    620 
    621         /* copy the data for inaccessible bytes */
    622         if(inBytes!=outBytes) {
    623             uprv_memcpy(outBytes, inBytes, aliases.total_size);
    624         }
    625 
    626         /* swap the PropertyAliases class fields */
    627         ds->swapArray16(ds, inAliases, sizeof(PropertyAliases), outAliases, pErrorCode);
    628 
    629         /* swap the name groups */
    630         ds->swapArray16(ds, inBytes+aliases.nameGroupPool_offset,
    631                                 aliases.stringPool_offset-aliases.nameGroupPool_offset,
    632                            outBytes+aliases.nameGroupPool_offset, pErrorCode);
    633 
    634         /* swap the strings */
    635         udata_swapInvStringBlock(ds, inBytes+aliases.stringPool_offset,
    636                                         aliases.total_size-aliases.stringPool_offset,
    637                                     outBytes+aliases.stringPool_offset, pErrorCode);
    638 
    639         /*
    640          * alloc uint8_t temp[total_size] and reset it
    641          * swap each top-level struct, put at least the count fields into temp
    642          *   use subclass-specific swap() functions
    643          * enumerate value maps, for each
    644          *   if temp does not have count!=0 yet
    645          *     read count, put it into temp
    646          *     swap the array(s)
    647          *     resort strings in name->enum maps
    648          * swap value maps
    649          */
    650         temp=(uint8_t *)uprv_malloc(aliases.total_size);
    651         if(temp==NULL) {
    652             udata_printError(ds, "upname_swap(): unable to allocate temp memory (%d bytes)\n",
    653                              aliases.total_size);
    654             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    655             return 0;
    656         }
    657         uprv_memset(temp, 0, aliases.total_size);
    658 
    659         /* swap properties->name groups map */
    660         NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
    661                                         temp, aliases.enumToName_offset, pErrorCode);
    662 
    663         /* swap name->properties map */
    664         NameToEnum::swap(ds, inBytes, length, outBytes,
    665                          temp, aliases.nameToEnum_offset, pErrorCode);
    666 
    667         /* swap properties->value maps map */
    668         NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
    669                                         temp, aliases.enumToValue_offset, pErrorCode);
    670 
    671         /* enumerate all ValueMaps and swap them */
    672         inValueMaps=(const ValueMap *)(inBytes+aliases.valueMap_offset);
    673         outValueMaps=(ValueMap *)(outBytes+aliases.valueMap_offset);
    674 
    675         for(i=0; i<aliases.valueMap_count; ++i) {
    676             valueMap.enumToName_offset=udata_readInt16(ds, inValueMaps[i].enumToName_offset);
    677             valueMap.ncEnumToName_offset=udata_readInt16(ds, inValueMaps[i].ncEnumToName_offset);
    678             valueMap.nameToEnum_offset=udata_readInt16(ds, inValueMaps[i].nameToEnum_offset);
    679 
    680             if(valueMap.enumToName_offset!=0) {
    681                 EnumToOffset::swap(ds, inBytes, length, outBytes,
    682                                    temp, valueMap.enumToName_offset,
    683                                    pErrorCode);
    684             } else if(valueMap.ncEnumToName_offset!=0) {
    685                 NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
    686                                                 temp, valueMap.ncEnumToName_offset,
    687                                                 pErrorCode);
    688             }
    689             if(valueMap.nameToEnum_offset!=0) {
    690                 NameToEnum::swap(ds, inBytes, length, outBytes,
    691                                  temp, valueMap.nameToEnum_offset,
    692                                  pErrorCode);
    693             }
    694         }
    695 
    696         /* swap the ValueMaps array itself */
    697         ds->swapArray16(ds, inValueMaps, aliases.valueMap_count*sizeof(ValueMap),
    698                            outValueMaps, pErrorCode);
    699 
    700         /* name groups and strings were swapped above */
    701 
    702         /* release temp */
    703         uprv_free(temp);
    704     }
    705 
    706     return aliases.total_size;
    707 }
    708 
    709 U_CAPI int32_t U_EXPORT2
    710 upname_swap(const UDataSwapper *ds,
    711             const void *inData, int32_t length, void *outData,
    712             UErrorCode *pErrorCode) {
    713     const UDataInfo *pInfo;
    714     int32_t headerSize;
    715 
    716     const uint8_t *inBytes;
    717     uint8_t *outBytes;
    718 
    719     /* udata_swapDataHeader checks the arguments */
    720     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
    721     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    722         return 0;
    723     }
    724 
    725     /* check data format and format version */
    726     pInfo=(const UDataInfo *)((const char *)inData+4);
    727     if(!(
    728         pInfo->dataFormat[0]==0x70 &&   /* dataFormat="pnam" */
    729         pInfo->dataFormat[1]==0x6e &&
    730         pInfo->dataFormat[2]==0x61 &&
    731         pInfo->dataFormat[3]==0x6d &&
    732         pInfo->formatVersion[0]==1
    733     )) {
    734         udata_printError(ds, "upname_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as pnames.icu\n",
    735                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    736                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    737                          pInfo->formatVersion[0]);
    738         *pErrorCode=U_UNSUPPORTED_ERROR;
    739         return 0;
    740     }
    741 
    742     inBytes=(const uint8_t *)inData+headerSize;
    743     outBytes=(uint8_t *)outData+headerSize;
    744 
    745     if(length>=0) {
    746         length-=headerSize;
    747         if(length<(int32_t)sizeof(PropertyAliases)) {
    748             udata_printError(ds, "upname_swap(): too few bytes (%d after header) for pnames.icu\n",
    749                              length);
    750             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    751             return 0;
    752         }
    753     }
    754 
    755     return headerSize+PropertyAliases::swap(ds, inBytes, length, outBytes, pErrorCode);
    756 }
    757 
    758 //eof
    759