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