• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getASCIIPropertyNameChar(const char * name)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
getEBCDICPropertyNameChar(const char * name)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
uprv_compareASCIIPropertyNames(const char * name1,const char * name2)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
uprv_compareEBCDICPropertyNames(const char * name1,const char * name2)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*
chooseNameInGroup(Offset offset,UPropertyNameChoice choice) const145 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*
getValueMap(EnumValue prop) const161 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*
getPropertyName(EnumValue prop,UPropertyNameChoice choice) const168 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
getPropertyEnum(const char * alias) const175 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*
getPropertyValueName(EnumValue prop,EnumValue value,UPropertyNameChoice choice) const181 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
getPropertyValueEnum(EnumValue prop,const char * alias) const198 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
isPNameAcceptable(void *,const char *,const char *,const UDataInfo * info)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 
pname_cleanup(void)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  */
_load()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  */
load()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
u_getPropertyName(UProperty property,UPropertyNameChoice nameChoice)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
u_getPropertyEnum(const char * alias)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
u_getPropertyValueName(UProperty property,int32_t value,UPropertyNameChoice nameChoice)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
u_getPropertyValueEnum(UProperty property,const char * alias)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
swap(const UDataSwapper * ds,const uint8_t * inBytes,int32_t length,uint8_t * outBytes,uint8_t * temp,int32_t pos,UErrorCode * pErrorCode)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
swap(const UDataSwapper * ds,const uint8_t * inBytes,int32_t length,uint8_t * outBytes,uint8_t * temp,int32_t pos,UErrorCode * pErrorCode)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
upname_compareRows(const void * context,const void * left,const void * right)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
swap(const UDataSwapper * ds,const uint8_t * inBytes,int32_t length,uint8_t * outBytes,uint8_t * temp,int32_t pos,UErrorCode * pErrorCode)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
swap(const UDataSwapper * ds,const uint8_t * inBytes,int32_t length,uint8_t * outBytes,UErrorCode * pErrorCode)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
upname_swap(const UDataSwapper * ds,const void * inData,int32_t length,void * outData,UErrorCode * pErrorCode)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