2 ******************************************************************************* 
   4 * Copyright (C) 1999-2004, International Business Machines Corporation        * 
   5 *               and others. All Rights Reserved.                              * 
   7 ******************************************************************************* 
   8 *   file name:  uresdata.c 
  10 *   tab size:   8 (not used) 
  13 *   created on: 1999dec08 
  14 *   created by: Markus W. Scherer 
  15 * Modification History: 
  17 *   Date        Name        Description 
  18 *   06/20/2000  helena      OS/400 port changes; mostly typecast. 
  19 *   06/24/02    weiv        Added support for resource sharing 
  22 #include "unicode/utypes.h" 
  23 #include "unicode/udata.h" 
  32 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 
  35  * Resource access helpers 
  38 /* get a const char* pointer to the key with the keyOffset byte offset from pRoot */ 
  39 #define RES_GET_KEY(pRoot, keyOffset) ((const char *)(pRoot)+(keyOffset)) 
  40 #define URESDATA_ITEM_NOT_FOUND -1 
  43  * All the type-access functions assume that 
  44  * the resource is of the expected type. 
  52 _res_getArrayItem(Resource 
*pRoot
, Resource res
, int32_t indexR
) { 
  53     const int32_t *p
=(const int32_t *)RES_GET_POINTER(pRoot
, res
); 
  55         return ((const Resource 
*)(p
))[1+indexR
]; 
  57         return RES_BOGUS
;   /* indexR>itemCount */ 
  64  * Important: the key offsets are 16-bit byte offsets from pRoot, 
  65  * and the itemCount is one more 16-bit, too. 
  66  * Thus, there are (count+1) uint16_t values. 
  67  * In order to 4-align the Resource item values, there is a padding 
  68  * word if count is even, i.e., there is exactly (~count&1) 
  69  * 16-bit padding words. 
  71  * For Table32, both the count and the key offsets are int32_t's 
  72  * and need not alignment. 
  75 _res_getTableKey(const Resource 
*pRoot
, const Resource res
, int32_t indexS
) { 
  76     const uint16_t *p
=(const uint16_t *)RES_GET_POINTER(pRoot
, res
); 
  77     if((uint32_t)indexS
<(uint32_t)*p
) { 
  78         return RES_GET_KEY(pRoot
, p
[indexS
+1]); 
  80         return NULL
;    /* indexS>itemCount */ 
  85 _res_getTable32Key(const Resource 
*pRoot
, const Resource res
, int32_t indexS
) { 
  86     const int32_t *p
=(const int32_t *)RES_GET_POINTER(pRoot
, res
); 
  87     if((uint32_t)indexS
<(uint32_t)*p
) { 
  88         return RES_GET_KEY(pRoot
, p
[indexS
+1]); 
  90         return NULL
;    /* indexS>itemCount */ 
  96 _res_getTableItem(const Resource 
*pRoot
, const Resource res
, int32_t indexR
) { 
  97     const uint16_t *p
=(const uint16_t *)RES_GET_POINTER(pRoot
, res
); 
  99     if((uint32_t)indexR
<(uint32_t)count
) { 
 100         return ((const Resource 
*)(p
+1+count
+(~count
&1)))[indexR
]; 
 102         return RES_BOGUS
;   /* indexR>itemCount */ 
 107 _res_getTable32Item(const Resource 
*pRoot
, const Resource res
, int32_t indexR
) { 
 108     const int32_t *p
=(const int32_t *)RES_GET_POINTER(pRoot
, res
); 
 110     if((uint32_t)indexR
<(uint32_t)count
) { 
 111         return ((const Resource 
*)(p
+1+count
))[indexR
]; 
 113         return RES_BOGUS
;   /* indexR>itemCount */ 
 119 _res_findTableItem(const Resource 
*pRoot
, const Resource res
, const char *key
, 
 120                    int32_t *index
, const char **realKey
) { 
 121     const uint16_t *p
=(const uint16_t *)RES_GET_POINTER(pRoot
, res
); 
 122     int32_t i
, start
, limit
; 
 124     limit
=*p
++; /* number of entries */ 
 126     if(limit 
== 0) { /* this table is empty */ 
 127         *index
=URESDATA_ITEM_NOT_FOUND
; 
 131     /* do a binary search for the key */ 
 133     while(start
<limit
-1) { 
 134         i
=(int32_t)((start
+limit
)/2); 
 135         if(uprv_strcmp(key
, RES_GET_KEY(pRoot
, p
[i
]))<0) { 
 142     /* did we really find it? */ 
 143     if(uprv_strcmp(key
, RES_GET_KEY(pRoot
, p
[start
]))==0) { 
 145         *realKey
=RES_GET_KEY(pRoot
, p
[start
]); 
 146         limit
=*(p
-1);   /* itemCount */ 
 147         return ((const Resource 
*)(p
+limit
+(~limit
&1)))[start
]; 
 149         *index
=URESDATA_ITEM_NOT_FOUND
; 
 150         return RES_BOGUS
;   /* not found */ 
 155 _res_findTable32Item(const Resource 
*pRoot
, const Resource res
, const char *key
, 
 156                      int32_t *index
, const char **realKey
) { 
 157     const int32_t *p
=(const int32_t *)RES_GET_POINTER(pRoot
, res
); 
 158     int32_t i
, start
, limit
; 
 160     limit
=*p
++; /* number of entries */ 
 162     if(limit 
== 0) { /* this table is empty */ 
 163         *index
=URESDATA_ITEM_NOT_FOUND
; 
 167     /* do a binary search for the key */ 
 169     while(start
<limit
-1) { 
 170         i
=(int32_t)((start
+limit
)/2); 
 171         if(uprv_strcmp(key
, RES_GET_KEY(pRoot
, p
[i
]))<0) { 
 178     /* did we really find it? */ 
 179     if(uprv_strcmp(key
, RES_GET_KEY(pRoot
, p
[start
]))==0) { 
 181         *realKey
=RES_GET_KEY(pRoot
, p
[start
]); 
 182         limit
=*(p
-1);   /* itemCount */ 
 183         return ((const Resource 
*)(p
+limit
))[start
]; 
 185         *index
=URESDATA_ITEM_NOT_FOUND
; 
 186         return RES_BOGUS
;   /* not found */ 
 190 /* helper for res_load() ---------------------------------------------------- */ 
 192 static UBool U_CALLCONV
 
 193 isAcceptable(void *context
, 
 194              const char *type
, const char *name
, 
 195              const UDataInfo 
*pInfo
) { 
 198         pInfo
->isBigEndian
==U_IS_BIG_ENDIAN 
&& 
 199         pInfo
->charsetFamily
==U_CHARSET_FAMILY 
&& 
 200         pInfo
->sizeofUChar
==U_SIZEOF_UCHAR 
&& 
 201         pInfo
->dataFormat
[0]==0x52 &&   /* dataFormat="ResB" */ 
 202         pInfo
->dataFormat
[1]==0x65 && 
 203         pInfo
->dataFormat
[2]==0x73 && 
 204         pInfo
->dataFormat
[3]==0x42 && 
 205         pInfo
->formatVersion
[0]==1); 
 208 /* semi-public functions ---------------------------------------------------- */ 
 211 res_load(ResourceData 
*pResData
, 
 212          const char *path
, const char *name
, UErrorCode 
*errorCode
) { 
 215     /* load the ResourceBundle file */ 
 216     pResData
->data
=udata_openChoice(path
, "res", name
, isAcceptable
, NULL
, errorCode
); 
 217     if(U_FAILURE(*errorCode
)) { 
 221     /* get its memory and root resource */ 
 222     pResData
->pRoot
=(Resource 
*)udata_getMemory(pResData
->data
); 
 223     pResData
->rootRes
=*pResData
->pRoot
; 
 225     /* currently, we accept only resources that have a Table as their roots */ 
 226     rootType
=RES_GET_TYPE(pResData
->rootRes
); 
 227     if(rootType
!=URES_TABLE 
&& rootType
!=URES_TABLE32
) { 
 228         *errorCode
=U_INVALID_FORMAT_ERROR
; 
 229         udata_close(pResData
->data
); 
 238 res_unload(ResourceData 
*pResData
) { 
 239     if(pResData
->data
!=NULL
) { 
 240         udata_close(pResData
->data
); 
 245 U_CFUNC 
const UChar 
* 
 246 res_getString(const ResourceData 
*pResData
, const Resource res
, int32_t *pLength
) { 
 247     if(res
!=RES_BOGUS 
&& RES_GET_TYPE(res
)==URES_STRING
) { 
 248         const int32_t *p
=(const int32_t *)RES_GET_POINTER(pResData
->pRoot
, res
); 
 252         return (const UChar 
*)++p
; 
 261 U_CFUNC 
const UChar 
* 
 262 res_getAlias(const ResourceData 
*pResData
, const Resource res
, int32_t *pLength
) { 
 263     if(res
!=RES_BOGUS 
&& RES_GET_TYPE(res
)==URES_ALIAS
) { 
 264         const int32_t *p
=(const int32_t *)RES_GET_POINTER(pResData
->pRoot
, res
); 
 268         return (const UChar 
*)++p
; 
 277 U_CFUNC 
const uint8_t * 
 278 res_getBinary(const ResourceData 
*pResData
, const Resource res
, int32_t *pLength
) { 
 280         const int32_t *p
=(const int32_t *)RES_GET_POINTER(pResData
->pRoot
, res
); 
 285         return (const uint8_t *)p
; 
 293 U_CFUNC 
const int32_t * 
 294 res_getIntVector(const ResourceData 
*pResData
, const Resource res
, int32_t *pLength
) { 
 295     if(res
!=RES_BOGUS 
&& RES_GET_TYPE(res
)==URES_INT_VECTOR
) { 
 296         const int32_t *p
=(const int32_t *)RES_GET_POINTER(pResData
->pRoot
, res
); 
 301         return (const int32_t *)p
; 
 309 res_countArrayItems(const ResourceData 
*pResData
, const Resource res
) { 
 311         switch(RES_GET_TYPE(res
)) { 
 316         case URES_INT_VECTOR
: 
 320             const int32_t *p
=(const int32_t *)RES_GET_POINTER(pResData
->pRoot
, res
); 
 324             const uint16_t *p
=(const uint16_t *)RES_GET_POINTER(pResData
->pRoot
, res
); 
 335 res_getResource(const ResourceData 
*pResData
, const char *key
) { 
 338     if(RES_GET_TYPE(pResData
->rootRes
)==URES_TABLE
) { 
 339         return _res_findTableItem(pResData
->pRoot
, pResData
->rootRes
, key
, &index
, &realKey
); 
 341         return _res_findTable32Item(pResData
->pRoot
, pResData
->rootRes
, key
, &index
, &realKey
); 
 346 res_getArrayItem(const ResourceData 
*pResData
, Resource array
, const int32_t indexR
) { 
 347     return _res_getArrayItem(pResData
->pRoot
, array
, indexR
); 
 351 res_findResource(const ResourceData 
*pResData
, Resource r
, char** path
, const char** key
) { 
 352   /* we pass in a path. CollationElements/Sequence or zoneStrings/3/2 etc.  
 353    * iterates over a path and stops when a scalar resource is found. This   
 354    * CAN be an alias. Path gets set to the part that has not yet been processed.  
 357   char *pathP 
= *path
, *nextSepP 
= *path
; 
 358   char *closeIndex 
= NULL
; 
 362   UResType type 
= RES_GET_TYPE(t1
); 
 364   /* if you come in with an empty path, you'll be getting back the same resource */ 
 365   if(!uprv_strlen(pathP
)) { 
 369   /* one needs to have an aggregate resource in order to search in it */ 
 370   if(!(type 
== URES_TABLE 
|| type 
== URES_TABLE32 
|| type 
== URES_ARRAY
)) { 
 374   while(nextSepP 
&& *pathP 
&& t1 
!= RES_BOGUS 
&& 
 375         (type 
== URES_TABLE 
|| type 
== URES_TABLE32 
|| type 
== URES_ARRAY
) 
 377     /* Iteration stops if: the path has been consumed, we found a non-existing 
 378      * resource (t1 == RES_BOGUS) or we found a scalar resource (including alias) 
 380     nextSepP 
= uprv_strchr(pathP
, RES_PATH_SEPARATOR
); 
 381     /* if there are more separators, terminate string  
 382      * and set path to the remaining part of the string 
 384     if(nextSepP 
!= NULL
) { 
 385       *nextSepP 
= 0; /* overwrite the separator with a NUL to terminate the key */ 
 388       *path 
= uprv_strchr(pathP
, 0); 
 391     /* if the resource is a table */ 
 392     /* try the key based access */ 
 393     if(type 
== URES_TABLE
) { 
 394       t2 
= _res_findTableItem(pResData
->pRoot
, t1
, pathP
, &indexR
, key
); 
 395       if(t2 
== RES_BOGUS
) {  
 396         /* if we fail to get the resource by key, maybe we got an index */ 
 397         indexR 
= uprv_strtol(pathP
, &closeIndex
, 10); 
 398         if(closeIndex 
!= pathP
) { 
 399           /* if we indeed have an index, try to get the item by index */ 
 400           t2 
= res_getTableItemByIndex(pResData
, t1
, indexR
, key
); 
 403     } else if(type 
== URES_TABLE32
) { 
 404       t2 
= _res_findTable32Item(pResData
->pRoot
, t1
, pathP
, &indexR
, key
); 
 405       if(t2 
== RES_BOGUS
) {  
 406         /* if we fail to get the resource by key, maybe we got an index */ 
 407         indexR 
= uprv_strtol(pathP
, &closeIndex
, 10); 
 408         if(closeIndex 
!= pathP
) { 
 409           /* if we indeed have an index, try to get the item by index */ 
 410           t2 
= res_getTableItemByIndex(pResData
, t1
, indexR
, key
); 
 413     } else if(type 
== URES_ARRAY
) { 
 414       indexR 
= uprv_strtol(pathP
, &closeIndex
, 10); 
 415       if(closeIndex 
!= pathP
) { 
 416         t2 
= _res_getArrayItem(pResData
->pRoot
, t1
, indexR
); 
 418         t2 
= RES_BOGUS
; /* have an array, but don't have a valid index */ 
 421     } else { /* can't do much here, except setting t2 to bogus */ 
 425     type 
= RES_GET_TYPE(t1
); 
 426     /* position pathP to next resource key/index */ 
 434 res_getTableItemByKey(const ResourceData 
*pResData
, Resource table
, 
 435                       int32_t *indexR
, const char **key
) { 
 436     if(key 
!= NULL 
&& *key 
!= NULL
) { 
 437         if(RES_GET_TYPE(table
)==URES_TABLE
) { 
 438             return _res_findTableItem(pResData
->pRoot
, table
, *key
, indexR
, key
); 
 440             return _res_findTable32Item(pResData
->pRoot
, table
, *key
, indexR
, key
); 
 448 res_getTableItemByIndex(const ResourceData 
*pResData
, Resource table
, 
 449                         int32_t indexR
, const char **key
) { 
 451         if(RES_GET_TYPE(table
)==URES_TABLE
) { 
 453                 *key 
= _res_getTableKey(pResData
->pRoot
, table
, indexR
); 
 455             return _res_getTableItem(pResData
->pRoot
, table
, indexR
); 
 458                 *key 
= _res_getTable32Key(pResData
->pRoot
, table
, indexR
); 
 460             return _res_getTable32Item(pResData
->pRoot
, table
, indexR
); 
 467 /* resource bundle swapping ------------------------------------------------- */ 
 470  * Need to always enumerate the entire item tree, 
 471  * track the lowest address of any item to use as the limit for char keys[], 
 472  * track the highest address of any item to return the size of the data. 
 474  * We should have thought of storing those in the data... 
 475  * It is possible to extend the data structure by putting additional values 
 476  * in places that are inaccessible by ordinary enumeration of the item tree. 
 477  * For example, additional integers could be stored at the beginning or 
 478  * end of the key strings; this could be indicated by a minor version number, 
 479  * and the data swapping would have to know about these values. 
 481  * The data structure does not forbid keys to be shared, so we must swap 
 482  * all keys once instead of each key when it is referenced. 
 484  * These swapping functions assume that a resource bundle always has a length 
 485  * that is a multiple of 4 bytes. 
 486  * Currently, this is trivially true because genrb writes bundle tree leaves 
 487  * physically first, before their branches, so that the root table with its 
 488  * array of resource items (uint32_t values) is always last. 
 491 /* definitions for table sorting ------------------------ */ 
 494  * row of a temporary array 
 496  * gets platform-endian key string indexes and sorting indexes; 
 497  * after sorting this array by keys, the actual key/value arrays are permutated 
 498  * according to the sorting indexes 
 501     int32_t keyIndex
, sortIndex
; 
 505 ures_compareRows(const void *context
, const void *left
, const void *right
) { 
 506     const char *keyChars
=(const char *)context
; 
 507     return (int32_t)uprv_strcmp(keyChars
+((const Row 
*)left
)->keyIndex
, 
 508                                 keyChars
+((const Row 
*)right
)->keyIndex
); 
 511 typedef struct TempTable 
{ 
 512     const char *keyChars
; 
 518     STACK_ROW_CAPACITY
=200 
 521 /* binary data with known formats is swapped too */ 
 522 typedef enum UResSpecialType 
{ 
 523     URES_NO_SPECIAL_TYPE
, 
 524     URES_COLLATION_BINARY
, 
 525     URES_SPECIAL_TYPE_COUNT
 
 528 /* resource table key for collation binaries: "%%CollationBin" */ 
 529 static const UChar gCollationBinKey
[]={ 
 531     0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 
 537  * preflight one resource item and set bottom and top values; 
 538  * length, bottom, and top count Resource item offsets (4 bytes each), not bytes 
 541 ures_preflightResource(const UDataSwapper 
*ds
, 
 542                        const Resource 
*inBundle
, int32_t length
, 
 544                        int32_t *pBottom
, int32_t *pTop
, int32_t *pMaxTableLength
, 
 545                        UErrorCode 
*pErrorCode
) { 
 549     if(res
==0 || RES_GET_TYPE(res
)==URES_INT
) { 
 550         /* empty string or integer, nothing to do */ 
 554     /* all other types use an offset to point to their data */ 
 555     offset
=(int32_t)RES_GET_OFFSET(res
); 
 556     if(0<=length 
&& length
<=offset
) { 
 557         udata_printError(ds
, "ures_preflightResource(res=%08x) resource offset exceeds bundle length %d\n", 
 559         *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
; 
 561     } else if(offset
<*pBottom
) { 
 566     switch(RES_GET_TYPE(res
)) { 
 568         /* physically same value layout as string, fall through */ 
 570         /* top=offset+1+(string length +1)/2 rounded up */ 
 571         offset
+=1+((udata_readInt32(ds
, (int32_t)*p
)+1)+1)/2; 
 574         /* top=offset+1+(binary length)/4 rounded up */ 
 575         offset
+=1+(udata_readInt32(ds
, (int32_t)*p
)+3)/4; 
 583             if(RES_GET_TYPE(res
)==URES_TABLE
) { 
 584                 /* get table item count */ 
 585                 const uint16_t *pKey16
=(const uint16_t *)p
; 
 586                 count
=ds
->readUInt16(*pKey16
++); 
 588                 /* top=((1+ table item count)/2 rounded up)+(table item count) */ 
 589                 offset
+=((1+count
)+1)/2; 
 591                 /* get table item count */ 
 592                 const int32_t *pKey32
=(const int32_t *)p
; 
 593                 count
=udata_readInt32(ds
, *pKey32
++); 
 595                 /* top=(1+ table item count)+(table item count) */ 
 599             if(count
>*pMaxTableLength
) { 
 600                 *pMaxTableLength
=count
; 
 603             p
=inBundle
+offset
; /* pointer to table resources */ 
 608                 for(i
=0; i
<count
; ++i
) { 
 609                     item
=ds
->readUInt32(*p
++); 
 610                     ures_preflightResource(ds
, inBundle
, length
, item
, 
 611                                            pBottom
, pTop
, pMaxTableLength
, 
 613                     if(U_FAILURE(*pErrorCode
)) { 
 614                         udata_printError(ds
, "ures_preflightResource(table res=%08x)[%d].recurse(%08x) failed - %s\n", 
 615                                          res
, i
, item
, u_errorName(*pErrorCode
)); 
 627             /* top=offset+1+(array length) */ 
 628             count
=udata_readInt32(ds
, (int32_t)*p
++); 
 633                 for(i
=0; i
<count
; ++i
) { 
 634                     item
=ds
->readUInt32(*p
++); 
 635                     ures_preflightResource(ds
, inBundle
, length
, item
, 
 636                                            pBottom
, pTop
, pMaxTableLength
, 
 638                     if(U_FAILURE(*pErrorCode
)) { 
 639                         udata_printError(ds
, "ures_preflightResource(array res=%08x)[%d].recurse(%08x) failed - %s\n", 
 640                                          res
, i
, item
, u_errorName(*pErrorCode
)); 
 647     case URES_INT_VECTOR
: 
 648         /* top=offset+1+(vector length) */ 
 649         offset
+=1+udata_readInt32(ds
, (int32_t)*p
); 
 652         /* also catches RES_BOGUS */ 
 653         udata_printError(ds
, "ures_preflightResource(res=%08x) unknown resource type\n", res
); 
 654         *pErrorCode
=U_UNSUPPORTED_ERROR
; 
 658     if(U_FAILURE(*pErrorCode
)) { 
 660     } else if(0<=length 
&& length
<offset
) { 
 661         udata_printError(ds
, "ures_preflightResource(res=%08x) resource limit exceeds bundle length %d\n", 
 663         *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
; 
 664     } else if(offset
>*pTop
) { 
 670  * swap one resource item 
 671  * since preflighting succeeded, we need not check offsets against length any more 
 674 ures_swapResource(const UDataSwapper 
*ds
, 
 675                   const Resource 
*inBundle
, Resource 
*outBundle
, 
 676                   Resource res
, /* caller swaps res itself */ 
 677                   UResSpecialType specialType
, 
 678                   TempTable 
*pTempTable
, 
 679                   UErrorCode 
*pErrorCode
) { 
 682     int32_t offset
, count
; 
 684     if(res
==0 || RES_GET_TYPE(res
)==URES_INT
) { 
 685         /* empty string or integer, nothing to do */ 
 689     /* all other types use an offset to point to their data */ 
 690     offset
=(int32_t)RES_GET_OFFSET(res
); 
 694     switch(RES_GET_TYPE(res
)) { 
 696         /* physically same value layout as string, fall through */ 
 698         count
=udata_readInt32(ds
, (int32_t)*p
); 
 700         ds
->swapArray32(ds
, p
, 4, q
, pErrorCode
); 
 701         /* swap each UChar (the terminating NUL would not change) */ 
 702         ds
->swapArray16(ds
, p
+1, 2*count
, q
+1, pErrorCode
); 
 705         count
=udata_readInt32(ds
, (int32_t)*p
); 
 707         ds
->swapArray32(ds
, p
, 4, q
, pErrorCode
); 
 708         /* no need to swap or copy bytes - ures_swap() copied them all */ 
 710         /* swap known formats */ 
 711         if(specialType
==URES_COLLATION_BINARY
) { 
 712 #if !UCONFIG_NO_COLLATION 
 713             ucol_swapBinary(ds
, p
+1, count
, q
+1, pErrorCode
); 
 720             const uint16_t *pKey16
; 
 723             const int32_t *pKey32
; 
 729             if(RES_GET_TYPE(res
)==URES_TABLE
) { 
 730                 /* get table item count */ 
 731                 pKey16
=(const uint16_t *)p
; 
 732                 qKey16
=(uint16_t *)q
; 
 733                 count
=ds
->readUInt16(*pKey16
); 
 738                 ds
->swapArray16(ds
, pKey16
++, 2, qKey16
++, pErrorCode
); 
 740                 offset
+=((1+count
)+1)/2; 
 742                 /* get table item count */ 
 743                 pKey32
=(const int32_t *)p
; 
 745                 count
=udata_readInt32(ds
, *pKey32
); 
 750                 ds
->swapArray32(ds
, pKey32
++, 4, qKey32
++, pErrorCode
); 
 759             p
=inBundle
+offset
; /* pointer to table resources */ 
 763             for(i
=0; i
<count
; ++i
) { 
 765                  * detect a collation binary that is to be swapped via 
 766                  * ds->compareInvChars(ds, outData+readUInt16(pKey[i]), "%%CollationBin") 
 769                  * use some UDataSwapFn pointer from somewhere for collation swapping 
 770                  * because the common library cannot directly call into the i18n library 
 772                 if(0==ds
->compareInvChars(ds
, 
 773                             ((const char *)outBundle
)+ 
 775                                     ds
->readUInt16(pKey16
[i
]) : 
 776                                     udata_readInt32(ds
, pKey32
[i
])), 
 778                             gCollationBinKey
, LENGTHOF(gCollationBinKey
)-1) 
 780                     specialType
=URES_COLLATION_BINARY
; 
 782                     specialType
=URES_NO_SPECIAL_TYPE
; 
 785                 item
=ds
->readUInt32(p
[i
]); 
 786                 ures_swapResource(ds
, inBundle
, outBundle
, item
, specialType
, pTempTable
, pErrorCode
); 
 787                 if(U_FAILURE(*pErrorCode
)) { 
 788                     udata_printError(ds
, "ures_swapResource(table res=%08x)[%d].recurse(%08x) failed - %s\n", 
 789                                      res
, i
, item
, u_errorName(*pErrorCode
)); 
 794             if(ds
->inCharset
==ds
->outCharset
) { 
 795                 /* no need to sort, just swap the offset/value arrays */ 
 797                     ds
->swapArray16(ds
, pKey16
, count
*2, qKey16
, pErrorCode
); 
 798                     ds
->swapArray32(ds
, p
, count
*4, q
, pErrorCode
); 
 800                     /* swap key offsets and items as one array */ 
 801                     ds
->swapArray32(ds
, pKey32
, count
*2*4, qKey32
, pErrorCode
); 
 807              * We need to sort tables by outCharset key strings because they 
 808              * sort differently for different charset families. 
 809              * ures_swap() already set pTempTable->keyChars appropriately. 
 810              * First we set up a temporary table with the key indexes and 
 811              * sorting indexes and sort that. 
 812              * Then we permutate and copy/swap the actual values. 
 815                 for(i
=0; i
<count
; ++i
) { 
 816                     pTempTable
->rows
[i
].keyIndex
=ds
->readUInt16(pKey16
[i
]); 
 817                     pTempTable
->rows
[i
].sortIndex
=i
; 
 820                 for(i
=0; i
<count
; ++i
) { 
 821                     pTempTable
->rows
[i
].keyIndex
=udata_readInt32(ds
, pKey32
[i
]); 
 822                     pTempTable
->rows
[i
].sortIndex
=i
; 
 825             uprv_sortArray(pTempTable
->rows
, count
, sizeof(Row
), 
 826                            ures_compareRows
, pTempTable
->keyChars
, 
 828             if(U_FAILURE(*pErrorCode
)) { 
 829                 udata_printError(ds
, "ures_swapResource(table res=%08x).uprv_sortArray(%d items) failed - %s\n", 
 830                                  res
, count
, u_errorName(*pErrorCode
)); 
 835              * copy/swap/permutate items 
 837              * If we swap in-place, then the permutation must use another 
 838              * temporary array (pTempTable->resort) 
 839              * before the results are copied to the outBundle. 
 848                     rKey16
=(uint16_t *)pTempTable
->resort
; 
 850                 for(i
=0; i
<count
; ++i
) { 
 851                     oldIndex
=pTempTable
->rows
[i
].sortIndex
; 
 852                     ds
->swapArray16(ds
, pKey16
+oldIndex
, 2, rKey16
+i
, pErrorCode
); 
 855                     uprv_memcpy(qKey16
, rKey16
, 2*count
); 
 863                     rKey32
=pTempTable
->resort
; 
 865                 for(i
=0; i
<count
; ++i
) { 
 866                     oldIndex
=pTempTable
->rows
[i
].sortIndex
; 
 867                     ds
->swapArray32(ds
, pKey32
+oldIndex
, 4, rKey32
+i
, pErrorCode
); 
 870                     uprv_memcpy(qKey32
, rKey32
, 4*count
); 
 882                     r
=(Resource 
*)pTempTable
->resort
; 
 884                 for(i
=0; i
<count
; ++i
) { 
 885                     oldIndex
=pTempTable
->rows
[i
].sortIndex
; 
 886                     ds
->swapArray32(ds
, p
+oldIndex
, 4, r
+i
, pErrorCode
); 
 889                     uprv_memcpy(q
, r
, 4*count
); 
 899             count
=udata_readInt32(ds
, (int32_t)*p
); 
 901             ds
->swapArray32(ds
, p
++, 4, q
++, pErrorCode
); 
 904             for(i
=0; i
<count
; ++i
) { 
 905                 item
=ds
->readUInt32(p
[i
]); 
 906                 ures_swapResource(ds
, inBundle
, outBundle
, item
, URES_NO_SPECIAL_TYPE
, pTempTable
, pErrorCode
); 
 907                 if(U_FAILURE(*pErrorCode
)) { 
 908                     udata_printError(ds
, "ures_swapResource(array res=%08x)[%d].recurse(%08x) failed - %s\n", 
 909                                      res
, i
, item
, u_errorName(*pErrorCode
)); 
 915             ds
->swapArray32(ds
, p
, 4*count
, q
, pErrorCode
); 
 918     case URES_INT_VECTOR
: 
 919         count
=udata_readInt32(ds
, (int32_t)*p
); 
 920         /* swap length and each integer */ 
 921         ds
->swapArray32(ds
, p
, 4*(1+count
), q
, pErrorCode
); 
 924         /* also catches RES_BOGUS */ 
 925         *pErrorCode
=U_UNSUPPORTED_ERROR
; 
 930 U_CAPI 
int32_t U_EXPORT2
 
 931 ures_swap(const UDataSwapper 
*ds
, 
 932           const void *inData
, int32_t length
, void *outData
, 
 933           UErrorCode 
*pErrorCode
) { 
 934     const UDataInfo 
*pInfo
; 
 935     const Resource 
*inBundle
; 
 937     int32_t headerSize
, maxTableLength
; 
 939     Row rows
[STACK_ROW_CAPACITY
]; 
 940     int32_t resort
[STACK_ROW_CAPACITY
]; 
 943     /* the following integers count Resource item offsets (4 bytes each), not bytes */ 
 944     int32_t bundleLength
, stringsBottom
, bottom
, top
; 
 946     /* udata_swapDataHeader checks the arguments */ 
 947     headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
); 
 948     if(pErrorCode
==NULL 
|| U_FAILURE(*pErrorCode
)) { 
 952     /* check data format and format version */ 
 953     pInfo
=(const UDataInfo 
*)((const char *)inData
+4); 
 955         pInfo
->dataFormat
[0]==0x52 &&   /* dataFormat="ResB" */ 
 956         pInfo
->dataFormat
[1]==0x65 && 
 957         pInfo
->dataFormat
[2]==0x73 && 
 958         pInfo
->dataFormat
[3]==0x42 && 
 959         pInfo
->formatVersion
[0]==1 
 961         udata_printError(ds
, "ures_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not a resource bundle\n", 
 962                          pInfo
->dataFormat
[0], pInfo
->dataFormat
[1], 
 963                          pInfo
->dataFormat
[2], pInfo
->dataFormat
[3], 
 964                          pInfo
->formatVersion
[0]); 
 965         *pErrorCode
=U_UNSUPPORTED_ERROR
; 
 969     /* a resource bundle must contain at least one resource item */ 
 973         bundleLength
=(length
-headerSize
)/4; 
 975         /* formatVersion 1.1 must have a root item and at least 5 indexes */ 
 977                 (pInfo
->formatVersion
[1]==0 ? 1 : 1+5) 
 979             udata_printError(ds
, "ures_swap(): too few bytes (%d after header) for a resource bundle\n", 
 981             *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
; 
 986     inBundle
=(const Resource 
*)((const char *)inData
+headerSize
); 
 987     rootRes
=ds
->readUInt32(*inBundle
); 
 989     if(pInfo
->formatVersion
[1]==0) { 
 990         /* preflight to get the bottom, top and maxTableLength values */ 
 991         stringsBottom
=1; /* just past root */ 
 993         top
=maxTableLength
=0; 
 994         ures_preflightResource(ds
, inBundle
, bundleLength
, rootRes
, 
 995                                &bottom
, &top
, &maxTableLength
, 
 997         if(U_FAILURE(*pErrorCode
)) { 
 998             udata_printError(ds
, "ures_preflightResource(root res=%08x) failed - %s\n", 
 999                              rootRes
, u_errorName(*pErrorCode
)); 
1003         /* formatVersion 1.1 adds the indexes[] array */ 
1004         const int32_t *inIndexes
; 
1006         inIndexes
=(const int32_t *)(inBundle
+1); 
1008         stringsBottom
=1+udata_readInt32(ds
, inIndexes
[URES_INDEX_LENGTH
]); 
1009         bottom
=udata_readInt32(ds
, inIndexes
[URES_INDEX_STRINGS_TOP
]); 
1010         top
=udata_readInt32(ds
, inIndexes
[URES_INDEX_BUNDLE_TOP
]); 
1011         maxTableLength
=udata_readInt32(ds
, inIndexes
[URES_INDEX_MAX_TABLE_LENGTH
]); 
1013         if(0<=bundleLength 
&& bundleLength
<top
) { 
1014             udata_printError(ds
, "ures_swap(): resource top %d exceeds bundle length %d\n", 
1016             *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
; 
1022         Resource 
*outBundle
=(Resource 
*)((char *)outData
+headerSize
); 
1024         /* copy the bundle for binary and inaccessible data */ 
1025         if(inData
!=outData
) { 
1026             uprv_memcpy(outBundle
, inBundle
, 4*top
); 
1029         /* swap the key strings, but not the padding bytes (0xaa) after the last string and its NUL */ 
1030         udata_swapInvStringBlock(ds
, inBundle
+stringsBottom
, 4*(bottom
-stringsBottom
), 
1031                                     outBundle
+stringsBottom
, pErrorCode
); 
1032         if(U_FAILURE(*pErrorCode
)) { 
1033             udata_printError(ds
, "ures_swap().udata_swapInvStringBlock(keys[%d]) failed - %s\n", 4*(bottom
-1), 
1034                              u_errorName(*pErrorCode
)); 
1038         /* allocate the temporary table for sorting resource tables */ 
1039         tempTable
.keyChars
=(const char *)outBundle
; /* sort by outCharset */ 
1040         if(maxTableLength
<=STACK_ROW_CAPACITY
) { 
1041             tempTable
.rows
=rows
; 
1042             tempTable
.resort
=resort
; 
1044             tempTable
.rows
=(Row 
*)uprv_malloc(maxTableLength
*sizeof(Row
)+maxTableLength
*4); 
1045             if(tempTable
.rows
==NULL
) { 
1046                 udata_printError(ds
, "ures_swap(): unable to allocate memory for sorting tables (max length: %d)\n", 
1048                 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
; 
1051             tempTable
.resort
=(int32_t *)(tempTable
.rows
+maxTableLength
); 
1054         /* swap the resources */ 
1055         ures_swapResource(ds
, inBundle
, outBundle
, rootRes
, URES_NO_SPECIAL_TYPE
, &tempTable
, pErrorCode
); 
1056         if(U_FAILURE(*pErrorCode
)) { 
1057             udata_printError(ds
, "ures_swapResource(root res=%08x) failed - %s\n", 
1058                              rootRes
, u_errorName(*pErrorCode
)); 
1061         if(tempTable
.rows
!=rows
) { 
1062             uprv_free(tempTable
.rows
); 
1065         /* swap the root resource and indexes */ 
1066         ds
->swapArray32(ds
, inBundle
, stringsBottom
*4, outBundle
, pErrorCode
); 
1069     return headerSize
+4*top
;