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 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 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 703 U_CAPI int32_t U_EXPORT2 704 upname_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