1/*
2**********************************************************************
3* Copyright (c) 2002-2009, 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
20U_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 */
27static inline int32_t
28getASCIIPropertyNameChar(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 */
50static inline int32_t
51getEBCDICPropertyNameChar(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
85U_CAPI int32_t U_EXPORT2
86uprv_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
111U_CAPI int32_t U_EXPORT2
112uprv_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
137U_CDECL_END
138
139U_NAMESPACE_BEGIN
140
141//----------------------------------------------------------------------
142// PropertyAliases implementation
143
144const char*
145PropertyAliases::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
160const ValueMap*
161PropertyAliases::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
167inline const char*
168PropertyAliases::getPropertyName(EnumValue prop,
169                                 UPropertyNameChoice choice) const {
170    NonContiguousEnumToOffset* e2n = (NonContiguousEnumToOffset*) getPointer(enumToName_offset);
171    return chooseNameInGroup(e2n->getOffset(prop), choice);
172}
173
174inline EnumValue
175PropertyAliases::getPropertyEnum(const char* alias) const {
176    NameToEnum* n2e = (NameToEnum*) getPointer(nameToEnum_offset);
177    return n2e->getEnum(alias, *this);
178}
179
180inline const char*
181PropertyAliases::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
197inline EnumValue
198PropertyAliases::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
206U_NAMESPACE_END
207U_NAMESPACE_USE
208
209//----------------------------------------------------------------------
210// UDataMemory structures
211
212static const PropertyAliases* PNAME = NULL;
213static UDataMemory* UDATA = NULL;
214
215//----------------------------------------------------------------------
216// UDataMemory loading/unloading
217
218/**
219 * udata callback to verify the zone data.
220 */
221U_CDECL_BEGIN
222static UBool U_CALLCONV
223isPNameAcceptable(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
237static UBool U_CALLCONV pname_cleanup(void) {
238    if (UDATA) {
239        udata_close(UDATA);
240        UDATA = NULL;
241    }
242    PNAME = NULL;
243    return TRUE;
244}
245U_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 */
252static 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 */
279static 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
293U_CAPI const char* U_EXPORT2
294u_getPropertyName(UProperty property,
295                  UPropertyNameChoice nameChoice) {
296    return load() ? PNAME->getPropertyName(property, nameChoice)
297                  : NULL;
298}
299
300U_CAPI UProperty U_EXPORT2
301u_getPropertyEnum(const char* alias) {
302    UProperty p = load() ? (UProperty) PNAME->getPropertyEnum(alias)
303                         : UCHAR_INVALID_CODE;
304    return p;
305}
306
307U_CAPI const char* U_EXPORT2
308u_getPropertyValueName(UProperty property,
309                       int32_t value,
310                       UPropertyNameChoice nameChoice) {
311    return load() ? PNAME->getPropertyValueName(property, value, nameChoice)
312                  : NULL;
313}
314
315U_CAPI int32_t U_EXPORT2
316u_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
332int32_t
333EnumToOffset::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
377int32_t
378NonContiguousEnumToOffset::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
424struct NameAndIndex {
425    Offset name, index;
426};
427
428U_CDECL_BEGIN
429typedef int32_t U_CALLCONV PropNameCompareFn(const char *name1, const char *name2);
430
431struct CompareContext {
432    const char *chars;
433    PropNameCompareFn *propCompare;
434};
435
436static int32_t U_CALLCONV
437upname_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}
442U_CDECL_END
443
444int32_t
445NameToEnum::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
589int32_t
590PropertyAliases::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    int32_t i;
602
603    inAliases=(const PropertyAliases *)inBytes;
604    outAliases=(PropertyAliases *)outBytes;
605
606    /* read the input PropertyAliases - all 16-bit values */
607    for(i=0; i<(int32_t)sizeof(PropertyAliases)/2; ++i) {
608        ((uint16_t *)&aliases)[i]=ds->readUInt16(((const uint16_t *)inBytes)[i]);
609    }
610
611    if(length>=0) {
612        if(length<aliases.total_size) {
613            udata_printError(ds, "upname_swap(): too few bytes (%d after header) for all of pnames.icu\n",
614                             length);
615            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
616            return 0;
617        }
618
619        /* copy the data for inaccessible bytes */
620        if(inBytes!=outBytes) {
621            uprv_memcpy(outBytes, inBytes, aliases.total_size);
622        }
623
624        /* swap the PropertyAliases class fields */
625        ds->swapArray16(ds, inAliases, sizeof(PropertyAliases), outAliases, pErrorCode);
626
627        /* swap the name groups */
628        ds->swapArray16(ds, inBytes+aliases.nameGroupPool_offset,
629                                aliases.stringPool_offset-aliases.nameGroupPool_offset,
630                           outBytes+aliases.nameGroupPool_offset, pErrorCode);
631
632        /* swap the strings */
633        udata_swapInvStringBlock(ds, inBytes+aliases.stringPool_offset,
634                                        aliases.total_size-aliases.stringPool_offset,
635                                    outBytes+aliases.stringPool_offset, pErrorCode);
636
637        /*
638         * alloc uint8_t temp[total_size] and reset it
639         * swap each top-level struct, put at least the count fields into temp
640         *   use subclass-specific swap() functions
641         * enumerate value maps, for each
642         *   if temp does not have count!=0 yet
643         *     read count, put it into temp
644         *     swap the array(s)
645         *     resort strings in name->enum maps
646         * swap value maps
647         */
648        LocalMemory<uint8_t> temp;
649        if(temp.allocateInsteadAndReset(aliases.total_size)==NULL) {
650            udata_printError(ds, "upname_swap(): unable to allocate temp memory (%d bytes)\n",
651                             aliases.total_size);
652            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
653            return 0;
654        }
655
656        /* swap properties->name groups map */
657        NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
658                                        temp.getAlias(), aliases.enumToName_offset, pErrorCode);
659
660        /* swap name->properties map */
661        NameToEnum::swap(ds, inBytes, length, outBytes,
662                         temp.getAlias(), aliases.nameToEnum_offset, pErrorCode);
663
664        /* swap properties->value maps map */
665        NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
666                                        temp.getAlias(), aliases.enumToValue_offset, pErrorCode);
667
668        /* enumerate all ValueMaps and swap them */
669        inValueMaps=(const ValueMap *)(inBytes+aliases.valueMap_offset);
670        outValueMaps=(ValueMap *)(outBytes+aliases.valueMap_offset);
671
672        for(i=0; i<aliases.valueMap_count; ++i) {
673            valueMap.enumToName_offset=udata_readInt16(ds, inValueMaps[i].enumToName_offset);
674            valueMap.ncEnumToName_offset=udata_readInt16(ds, inValueMaps[i].ncEnumToName_offset);
675            valueMap.nameToEnum_offset=udata_readInt16(ds, inValueMaps[i].nameToEnum_offset);
676
677            if(valueMap.enumToName_offset!=0) {
678                EnumToOffset::swap(ds, inBytes, length, outBytes,
679                                   temp.getAlias(), valueMap.enumToName_offset,
680                                   pErrorCode);
681            } else if(valueMap.ncEnumToName_offset!=0) {
682                NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
683                                                temp.getAlias(), valueMap.ncEnumToName_offset,
684                                                pErrorCode);
685            }
686            if(valueMap.nameToEnum_offset!=0) {
687                NameToEnum::swap(ds, inBytes, length, outBytes,
688                                 temp.getAlias(), valueMap.nameToEnum_offset,
689                                 pErrorCode);
690            }
691        }
692
693        /* swap the ValueMaps array itself */
694        ds->swapArray16(ds, inValueMaps, aliases.valueMap_count*sizeof(ValueMap),
695                           outValueMaps, pErrorCode);
696
697        /* name groups and strings were swapped above */
698    }
699
700    return aliases.total_size;
701}
702
703U_CAPI int32_t U_EXPORT2
704upname_swap(const UDataSwapper *ds,
705            const void *inData, int32_t length, void *outData,
706            UErrorCode *pErrorCode) {
707    const UDataInfo *pInfo;
708    int32_t headerSize;
709
710    const uint8_t *inBytes;
711    uint8_t *outBytes;
712
713    /* udata_swapDataHeader checks the arguments */
714    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
715    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
716        return 0;
717    }
718
719    /* check data format and format version */
720    pInfo=(const UDataInfo *)((const char *)inData+4);
721    if(!(
722        pInfo->dataFormat[0]==0x70 &&   /* dataFormat="pnam" */
723        pInfo->dataFormat[1]==0x6e &&
724        pInfo->dataFormat[2]==0x61 &&
725        pInfo->dataFormat[3]==0x6d &&
726        pInfo->formatVersion[0]==1
727    )) {
728        udata_printError(ds, "upname_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as pnames.icu\n",
729                         pInfo->dataFormat[0], pInfo->dataFormat[1],
730                         pInfo->dataFormat[2], pInfo->dataFormat[3],
731                         pInfo->formatVersion[0]);
732        *pErrorCode=U_UNSUPPORTED_ERROR;
733        return 0;
734    }
735
736    inBytes=(const uint8_t *)inData+headerSize;
737    outBytes=(uint8_t *)outData+headerSize;
738
739    if(length>=0) {
740        length-=headerSize;
741        if(length<(int32_t)sizeof(PropertyAliases)) {
742            udata_printError(ds, "upname_swap(): too few bytes (%d after header) for pnames.icu\n",
743                             length);
744            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
745            return 0;
746        }
747    }
748
749    return headerSize+PropertyAliases::swap(ds, inBytes, length, outBytes, pErrorCode);
750}
751
752//eof
753