LCOV - code coverage report
Current view: top level - intl/icu/source/common - uresdata.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 91 693 13.1 %
Date: 2017-07-14 16:53:18 Functions: 9 42 21.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : * Copyright (C) 1999-2016, International Business Machines Corporation
       6             : *               and others. All Rights Reserved.
       7             : *******************************************************************************
       8             : *   file name:  uresdata.cpp
       9             : *   encoding:   UTF-8
      10             : *   tab size:   8 (not used)
      11             : *   indentation:4
      12             : *
      13             : *   created on: 1999dec08
      14             : *   created by: Markus W. Scherer
      15             : * Modification History:
      16             : *
      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
      20             : */
      21             : 
      22             : #include "unicode/utypes.h"
      23             : #include "unicode/udata.h"
      24             : #include "unicode/ustring.h"
      25             : #include "unicode/utf16.h"
      26             : #include "cmemory.h"
      27             : #include "cstring.h"
      28             : #include "resource.h"
      29             : #include "uarrsort.h"
      30             : #include "uassert.h"
      31             : #include "ucol_swp.h"
      32             : #include "udataswp.h"
      33             : #include "uinvchar.h"
      34             : #include "uresdata.h"
      35             : #include "uresimp.h"
      36             : 
      37             : /*
      38             :  * Resource access helpers
      39             :  */
      40             : 
      41             : /* get a const char* pointer to the key with the keyOffset byte offset from pRoot */
      42             : #define RES_GET_KEY16(pResData, keyOffset) \
      43             :     ((keyOffset)<(pResData)->localKeyLimit ? \
      44             :         (const char *)(pResData)->pRoot+(keyOffset) : \
      45             :         (pResData)->poolBundleKeys+(keyOffset)-(pResData)->localKeyLimit)
      46             : 
      47             : #define RES_GET_KEY32(pResData, keyOffset) \
      48             :     ((keyOffset)>=0 ? \
      49             :         (const char *)(pResData)->pRoot+(keyOffset) : \
      50             :         (pResData)->poolBundleKeys+((keyOffset)&0x7fffffff))
      51             : 
      52             : #define URESDATA_ITEM_NOT_FOUND -1
      53             : 
      54             : /* empty resources, returned when the resource offset is 0 */
      55             : static const uint16_t gEmpty16=0;
      56             : 
      57             : static const struct {
      58             :     int32_t length;
      59             :     int32_t res;
      60             : } gEmpty32={ 0, 0 };
      61             : 
      62             : static const struct {
      63             :     int32_t length;
      64             :     UChar nul;
      65             :     UChar pad;
      66             : } gEmptyString={ 0, 0, 0 };
      67             : 
      68             : /*
      69             :  * All the type-access functions assume that
      70             :  * the resource is of the expected type.
      71             :  */
      72             : 
      73             : static int32_t
      74           5 : _res_findTableItem(const ResourceData *pResData, const uint16_t *keyOffsets, int32_t length,
      75             :                    const char *key, const char **realKey) {
      76             :     const char *tableKey;
      77             :     int32_t mid, start, limit;
      78             :     int result;
      79             : 
      80             :     /* do a binary search for the key */
      81           5 :     start=0;
      82           5 :     limit=length;
      83         107 :     while(start<limit) {
      84          53 :         mid = (start + limit) / 2;
      85          53 :         tableKey = RES_GET_KEY16(pResData, keyOffsets[mid]);
      86          53 :         if (pResData->useNativeStrcmp) {
      87          53 :             result = uprv_strcmp(key, tableKey);
      88             :         } else {
      89           0 :             result = uprv_compareInvCharsAsAscii(key, tableKey);
      90             :         }
      91          53 :         if (result < 0) {
      92          33 :             limit = mid;
      93          20 :         } else if (result > 0) {
      94          18 :             start = mid + 1;
      95             :         } else {
      96             :             /* We found it! */
      97           2 :             *realKey=tableKey;
      98           2 :             return mid;
      99             :         }
     100             :     }
     101           3 :     return URESDATA_ITEM_NOT_FOUND;  /* not found or table is empty. */
     102             : }
     103             : 
     104             : static int32_t
     105           0 : _res_findTable32Item(const ResourceData *pResData, const int32_t *keyOffsets, int32_t length,
     106             :                      const char *key, const char **realKey) {
     107             :     const char *tableKey;
     108             :     int32_t mid, start, limit;
     109             :     int result;
     110             : 
     111             :     /* do a binary search for the key */
     112           0 :     start=0;
     113           0 :     limit=length;
     114           0 :     while(start<limit) {
     115           0 :         mid = (start + limit) / 2;
     116           0 :         tableKey = RES_GET_KEY32(pResData, keyOffsets[mid]);
     117           0 :         if (pResData->useNativeStrcmp) {
     118           0 :             result = uprv_strcmp(key, tableKey);
     119             :         } else {
     120           0 :             result = uprv_compareInvCharsAsAscii(key, tableKey);
     121             :         }
     122           0 :         if (result < 0) {
     123           0 :             limit = mid;
     124           0 :         } else if (result > 0) {
     125           0 :             start = mid + 1;
     126             :         } else {
     127             :             /* We found it! */
     128           0 :             *realKey=tableKey;
     129           0 :             return mid;
     130             :         }
     131             :     }
     132           0 :     return URESDATA_ITEM_NOT_FOUND;  /* not found or table is empty. */
     133             : }
     134             : 
     135             : /* helper for res_load() ---------------------------------------------------- */
     136             : 
     137             : static UBool U_CALLCONV
     138           1 : isAcceptable(void *context,
     139             :              const char * /*type*/, const char * /*name*/,
     140             :              const UDataInfo *pInfo) {
     141           1 :     uprv_memcpy(context, pInfo->formatVersion, 4);
     142             :     return (UBool)(
     143           2 :         pInfo->size>=20 &&
     144           2 :         pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
     145           2 :         pInfo->charsetFamily==U_CHARSET_FAMILY &&
     146           2 :         pInfo->sizeofUChar==U_SIZEOF_UCHAR &&
     147           2 :         pInfo->dataFormat[0]==0x52 &&   /* dataFormat="ResB" */
     148           2 :         pInfo->dataFormat[1]==0x65 &&
     149           2 :         pInfo->dataFormat[2]==0x73 &&
     150           4 :         pInfo->dataFormat[3]==0x42 &&
     151           3 :         (1<=pInfo->formatVersion[0] && pInfo->formatVersion[0]<=3));
     152             : }
     153             : 
     154             : /* semi-public functions ---------------------------------------------------- */
     155             : 
     156             : static void
     157           1 : res_init(ResourceData *pResData,
     158             :          UVersionInfo formatVersion, const void *inBytes, int32_t length,
     159             :          UErrorCode *errorCode) {
     160             :     UResType rootType;
     161             : 
     162             :     /* get the root resource */
     163           1 :     pResData->pRoot=(const int32_t *)inBytes;
     164           1 :     pResData->rootRes=(Resource)*pResData->pRoot;
     165           1 :     pResData->p16BitUnits=&gEmpty16;
     166             : 
     167             :     /* formatVersion 1.1 must have a root item and at least 5 indexes */
     168           1 :     if(length>=0 && (length/4)<((formatVersion[0]==1 && formatVersion[1]==0) ? 1 : 1+5)) {
     169           0 :         *errorCode=U_INVALID_FORMAT_ERROR;
     170           0 :         res_unload(pResData);
     171           0 :         return;
     172             :     }
     173             : 
     174             :     /* currently, we accept only resources that have a Table as their roots */
     175           1 :     rootType=(UResType)RES_GET_TYPE(pResData->rootRes);
     176           1 :     if(!URES_IS_TABLE(rootType)) {
     177           0 :         *errorCode=U_INVALID_FORMAT_ERROR;
     178           0 :         res_unload(pResData);
     179           0 :         return;
     180             :     }
     181             : 
     182           1 :     if(formatVersion[0]==1 && formatVersion[1]==0) {
     183           0 :         pResData->localKeyLimit=0x10000;  /* greater than any 16-bit key string offset */
     184             :     } else {
     185             :         /* bundles with formatVersion 1.1 and later contain an indexes[] array */
     186           1 :         const int32_t *indexes=pResData->pRoot+1;
     187           1 :         int32_t indexLength=indexes[URES_INDEX_LENGTH]&0xff;
     188           1 :         if(indexLength<=URES_INDEX_MAX_TABLE_LENGTH) {
     189           0 :             *errorCode=U_INVALID_FORMAT_ERROR;
     190           0 :             res_unload(pResData);
     191           0 :             return;
     192             :         }
     193           1 :         if( length>=0 &&
     194           0 :             (length<((1+indexLength)<<2) ||
     195           0 :              length<(indexes[URES_INDEX_BUNDLE_TOP]<<2))
     196             :         ) {
     197           0 :             *errorCode=U_INVALID_FORMAT_ERROR;
     198           0 :             res_unload(pResData);
     199           0 :             return;
     200             :         }
     201           1 :         if(indexes[URES_INDEX_KEYS_TOP]>(1+indexLength)) {
     202           1 :             pResData->localKeyLimit=indexes[URES_INDEX_KEYS_TOP]<<2;
     203             :         }
     204           1 :         if(formatVersion[0]>=3) {
     205             :             // In formatVersion 1, the indexLength took up this whole int.
     206             :             // In version 2, bits 31..8 were reserved and always 0.
     207             :             // In version 3, they contain bits 23..0 of the poolStringIndexLimit.
     208             :             // Bits 27..24 are in indexes[URES_INDEX_ATTRIBUTES] bits 15..12.
     209           0 :             pResData->poolStringIndexLimit=(int32_t)((uint32_t)indexes[URES_INDEX_LENGTH]>>8);
     210             :         }
     211           1 :         if(indexLength>URES_INDEX_ATTRIBUTES) {
     212           1 :             int32_t att=indexes[URES_INDEX_ATTRIBUTES];
     213           1 :             pResData->noFallback=(UBool)(att&URES_ATT_NO_FALLBACK);
     214           1 :             pResData->isPoolBundle=(UBool)((att&URES_ATT_IS_POOL_BUNDLE)!=0);
     215           1 :             pResData->usesPoolBundle=(UBool)((att&URES_ATT_USES_POOL_BUNDLE)!=0);
     216           1 :             pResData->poolStringIndexLimit|=(att&0xf000)<<12;  // bits 15..12 -> 27..24
     217           1 :             pResData->poolStringIndex16Limit=(int32_t)((uint32_t)att>>16);
     218             :         }
     219           1 :         if((pResData->isPoolBundle || pResData->usesPoolBundle) && indexLength<=URES_INDEX_POOL_CHECKSUM) {
     220           0 :             *errorCode=U_INVALID_FORMAT_ERROR;
     221           0 :             res_unload(pResData);
     222           0 :             return;
     223             :         }
     224           2 :         if( indexLength>URES_INDEX_16BIT_TOP &&
     225           1 :             indexes[URES_INDEX_16BIT_TOP]>indexes[URES_INDEX_KEYS_TOP]
     226             :         ) {
     227           1 :             pResData->p16BitUnits=(const uint16_t *)(pResData->pRoot+indexes[URES_INDEX_KEYS_TOP]);
     228             :         }
     229             :     }
     230             : 
     231             :     if(formatVersion[0]==1 || U_CHARSET_FAMILY==U_ASCII_FAMILY) {
     232             :         /*
     233             :          * formatVersion 1: compare key strings in native-charset order
     234             :          * formatVersion 2 and up: compare key strings in ASCII order
     235             :          */
     236           1 :         pResData->useNativeStrcmp=TRUE;
     237             :     }
     238             : }
     239             : 
     240             : U_CAPI void U_EXPORT2
     241           0 : res_read(ResourceData *pResData,
     242             :          const UDataInfo *pInfo, const void *inBytes, int32_t length,
     243             :          UErrorCode *errorCode) {
     244             :     UVersionInfo formatVersion;
     245             : 
     246           0 :     uprv_memset(pResData, 0, sizeof(ResourceData));
     247           0 :     if(U_FAILURE(*errorCode)) {
     248           0 :         return;
     249             :     }
     250           0 :     if(!isAcceptable(formatVersion, NULL, NULL, pInfo)) {
     251           0 :         *errorCode=U_INVALID_FORMAT_ERROR;
     252           0 :         return;
     253             :     }
     254           0 :     res_init(pResData, formatVersion, inBytes, length, errorCode);
     255             : }
     256             : 
     257             : U_CFUNC void
     258           1 : res_load(ResourceData *pResData,
     259             :          const char *path, const char *name, UErrorCode *errorCode) {
     260             :     UVersionInfo formatVersion;
     261             : 
     262           1 :     uprv_memset(pResData, 0, sizeof(ResourceData));
     263             : 
     264             :     /* load the ResourceBundle file */
     265           1 :     pResData->data=udata_openChoice(path, "res", name, isAcceptable, formatVersion, errorCode);
     266           1 :     if(U_FAILURE(*errorCode)) {
     267           0 :         return;
     268             :     }
     269             : 
     270             :     /* get its memory and initialize *pResData */
     271           1 :     res_init(pResData, formatVersion, udata_getMemory(pResData->data), -1, errorCode);
     272             : }
     273             : 
     274             : U_CFUNC void
     275           0 : res_unload(ResourceData *pResData) {
     276           0 :     if(pResData->data!=NULL) {
     277           0 :         udata_close(pResData->data);
     278           0 :         pResData->data=NULL;
     279             :     }
     280           0 : }
     281             : 
     282             : static const int8_t gPublicTypes[URES_LIMIT] = {
     283             :     URES_STRING,
     284             :     URES_BINARY,
     285             :     URES_TABLE,
     286             :     URES_ALIAS,
     287             : 
     288             :     URES_TABLE,     /* URES_TABLE32 */
     289             :     URES_TABLE,     /* URES_TABLE16 */
     290             :     URES_STRING,    /* URES_STRING_V2 */
     291             :     URES_INT,
     292             : 
     293             :     URES_ARRAY,
     294             :     URES_ARRAY,     /* URES_ARRAY16 */
     295             :     URES_NONE,
     296             :     URES_NONE,
     297             : 
     298             :     URES_NONE,
     299             :     URES_NONE,
     300             :     URES_INT_VECTOR,
     301             :     URES_NONE
     302             : };
     303             : 
     304             : U_CAPI UResType U_EXPORT2
     305           0 : res_getPublicType(Resource res) {
     306           0 :     return (UResType)gPublicTypes[RES_GET_TYPE(res)];
     307             : }
     308             : 
     309             : U_CAPI const UChar * U_EXPORT2
     310           2 : res_getString(const ResourceData *pResData, Resource res, int32_t *pLength) {
     311             :     const UChar *p;
     312           2 :     uint32_t offset=RES_GET_OFFSET(res);
     313             :     int32_t length;
     314           2 :     if(RES_GET_TYPE(res)==URES_STRING_V2) {
     315             :         int32_t first;
     316           2 :         if((int32_t)offset<pResData->poolStringIndexLimit) {
     317           0 :             p=(const UChar *)pResData->poolBundleStrings+offset;
     318             :         } else {
     319           2 :             p=(const UChar *)pResData->p16BitUnits+(offset-pResData->poolStringIndexLimit);
     320             :         }
     321           2 :         first=*p;
     322           2 :         if(!U16_IS_TRAIL(first)) {
     323           2 :             length=u_strlen(p);
     324           0 :         } else if(first<0xdfef) {
     325           0 :             length=first&0x3ff;
     326           0 :             ++p;
     327           0 :         } else if(first<0xdfff) {
     328           0 :             length=((first-0xdfef)<<16)|p[1];
     329           0 :             p+=2;
     330             :         } else {
     331           0 :             length=((int32_t)p[1]<<16)|p[2];
     332           0 :             p+=3;
     333             :         }
     334           0 :     } else if(res==offset) /* RES_GET_TYPE(res)==URES_STRING */ {
     335           0 :         const int32_t *p32= res==0 ? &gEmptyString.length : pResData->pRoot+res;
     336           0 :         length=*p32++;
     337           0 :         p=(const UChar *)p32;
     338             :     } else {
     339           0 :         p=NULL;
     340           0 :         length=0;
     341             :     }
     342           2 :     if(pLength) {
     343           2 :         *pLength=length;
     344             :     }
     345           2 :     return p;
     346             : }
     347             : 
     348             : namespace {
     349             : 
     350             : /**
     351             :  * CLDR string value (three empty-set symbols)=={2205, 2205, 2205}
     352             :  * prevents fallback to the parent bundle.
     353             :  * TODO: combine with other code that handles this marker, use EMPTY_SET constant.
     354             :  * TODO: maybe move to uresbund.cpp?
     355             :  */
     356           0 : UBool isNoInheritanceMarker(const ResourceData *pResData, Resource res) {
     357           0 :     uint32_t offset=RES_GET_OFFSET(res);
     358           0 :     if (offset == 0) {
     359             :         // empty string
     360           0 :     } else if (res == offset) {
     361           0 :         const int32_t *p32=pResData->pRoot+res;
     362           0 :         int32_t length=*p32;
     363           0 :         const UChar *p=(const UChar *)p32;
     364           0 :         return length == 3 && p[2] == 0x2205 && p[3] == 0x2205 && p[4] == 0x2205;
     365           0 :     } else if (RES_GET_TYPE(res) == URES_STRING_V2) {
     366             :         const UChar *p;
     367           0 :         if((int32_t)offset<pResData->poolStringIndexLimit) {
     368           0 :             p=(const UChar *)pResData->poolBundleStrings+offset;
     369             :         } else {
     370           0 :             p=(const UChar *)pResData->p16BitUnits+(offset-pResData->poolStringIndexLimit);
     371             :         }
     372           0 :         int32_t first=*p;
     373           0 :         if (first == 0x2205) {  // implicit length
     374           0 :             return p[1] == 0x2205 && p[2] == 0x2205 && p[3] == 0;
     375           0 :         } else if (first == 0xdc03) {  // explicit length 3 (should not occur)
     376           0 :             return p[1] == 0x2205 && p[2] == 0x2205 && p[3] == 0x2205;
     377             :         } else {
     378             :             // Assume that the string has not been stored with more length units than necessary.
     379           0 :             return FALSE;
     380             :         }
     381             :     }
     382           0 :     return FALSE;
     383             : }
     384             : 
     385           0 : int32_t getStringArray(const ResourceData *pResData, const icu::ResourceArray &array,
     386             :                        icu::UnicodeString *dest, int32_t capacity,
     387             :                        UErrorCode &errorCode) {
     388           0 :     if(U_FAILURE(errorCode)) {
     389           0 :         return 0;
     390             :     }
     391           0 :     if(dest == NULL ? capacity != 0 : capacity < 0) {
     392           0 :         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
     393           0 :         return 0;
     394             :     }
     395           0 :     int32_t length = array.getSize();
     396           0 :     if(length == 0) {
     397           0 :         return 0;
     398             :     }
     399           0 :     if(length > capacity) {
     400           0 :         errorCode = U_BUFFER_OVERFLOW_ERROR;
     401           0 :         return length;
     402             :     }
     403           0 :     for(int32_t i = 0; i < length; ++i) {
     404             :         int32_t sLength;
     405           0 :         const UChar *s = res_getString(pResData, array.internalGetResource(pResData, i), &sLength);
     406           0 :         if(s == NULL) {
     407           0 :             errorCode = U_RESOURCE_TYPE_MISMATCH;
     408           0 :             return 0;
     409             :         }
     410           0 :         dest[i].setTo(TRUE, s, sLength);
     411             :     }
     412           0 :     return length;
     413             : }
     414             : 
     415             : }  // namespace
     416             : 
     417             : U_CAPI const UChar * U_EXPORT2
     418           0 : res_getAlias(const ResourceData *pResData, Resource res, int32_t *pLength) {
     419             :     const UChar *p;
     420           0 :     uint32_t offset=RES_GET_OFFSET(res);
     421             :     int32_t length;
     422           0 :     if(RES_GET_TYPE(res)==URES_ALIAS) {
     423           0 :         const int32_t *p32= offset==0 ? &gEmptyString.length : pResData->pRoot+offset;
     424           0 :         length=*p32++;
     425           0 :         p=(const UChar *)p32;
     426             :     } else {
     427           0 :         p=NULL;
     428           0 :         length=0;
     429             :     }
     430           0 :     if(pLength) {
     431           0 :         *pLength=length;
     432             :     }
     433           0 :     return p;
     434             : }
     435             : 
     436             : U_CAPI const uint8_t * U_EXPORT2
     437           0 : res_getBinary(const ResourceData *pResData, Resource res, int32_t *pLength) {
     438             :     const uint8_t *p;
     439           0 :     uint32_t offset=RES_GET_OFFSET(res);
     440             :     int32_t length;
     441           0 :     if(RES_GET_TYPE(res)==URES_BINARY) {
     442           0 :         const int32_t *p32= offset==0 ? (const int32_t*)&gEmpty32 : pResData->pRoot+offset;
     443           0 :         length=*p32++;
     444           0 :         p=(const uint8_t *)p32;
     445             :     } else {
     446           0 :         p=NULL;
     447           0 :         length=0;
     448             :     }
     449           0 :     if(pLength) {
     450           0 :         *pLength=length;
     451             :     }
     452           0 :     return p;
     453             : }
     454             : 
     455             : 
     456             : U_CAPI const int32_t * U_EXPORT2
     457           0 : res_getIntVector(const ResourceData *pResData, Resource res, int32_t *pLength) {
     458             :     const int32_t *p;
     459           0 :     uint32_t offset=RES_GET_OFFSET(res);
     460             :     int32_t length;
     461           0 :     if(RES_GET_TYPE(res)==URES_INT_VECTOR) {
     462           0 :         p= offset==0 ? (const int32_t *)&gEmpty32 : pResData->pRoot+offset;
     463           0 :         length=*p++;
     464             :     } else {
     465           0 :         p=NULL;
     466           0 :         length=0;
     467             :     }
     468           0 :     if(pLength) {
     469           0 :         *pLength=length;
     470             :     }
     471           0 :     return p;
     472             : }
     473             : 
     474             : U_CAPI int32_t U_EXPORT2
     475           4 : res_countArrayItems(const ResourceData *pResData, Resource res) {
     476           4 :     uint32_t offset=RES_GET_OFFSET(res);
     477           4 :     switch(RES_GET_TYPE(res)) {
     478             :     case URES_STRING:
     479             :     case URES_STRING_V2:
     480             :     case URES_BINARY:
     481             :     case URES_ALIAS:
     482             :     case URES_INT:
     483             :     case URES_INT_VECTOR:
     484           0 :         return 1;
     485             :     case URES_ARRAY:
     486             :     case URES_TABLE32:
     487           0 :         return offset==0 ? 0 : *(pResData->pRoot+offset);
     488             :     case URES_TABLE:
     489           0 :         return offset==0 ? 0 : *((const uint16_t *)(pResData->pRoot+offset));
     490             :     case URES_ARRAY16:
     491             :     case URES_TABLE16:
     492           4 :         return pResData->p16BitUnits[offset];
     493             :     default:
     494           0 :         return 0;
     495             :     }
     496             : }
     497             : 
     498             : U_NAMESPACE_BEGIN
     499             : 
     500           0 : ResourceDataValue::~ResourceDataValue() {}
     501             : 
     502           0 : UResType ResourceDataValue::getType() const {
     503           0 :     return res_getPublicType(res);
     504             : }
     505             : 
     506           0 : const UChar *ResourceDataValue::getString(int32_t &length, UErrorCode &errorCode) const {
     507           0 :     if(U_FAILURE(errorCode)) {
     508           0 :         return NULL;
     509             :     }
     510           0 :     const UChar *s = res_getString(pResData, res, &length);
     511           0 :     if(s == NULL) {
     512           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     513             :     }
     514           0 :     return s;
     515             : }
     516             : 
     517           0 : const UChar *ResourceDataValue::getAliasString(int32_t &length, UErrorCode &errorCode) const {
     518           0 :     if(U_FAILURE(errorCode)) {
     519           0 :         return NULL;
     520             :     }
     521           0 :     const UChar *s = res_getAlias(pResData, res, &length);
     522           0 :     if(s == NULL) {
     523           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     524             :     }
     525           0 :     return s;
     526             : }
     527             : 
     528           0 : int32_t ResourceDataValue::getInt(UErrorCode &errorCode) const {
     529           0 :     if(U_FAILURE(errorCode)) {
     530           0 :         return 0;
     531             :     }
     532           0 :     if(RES_GET_TYPE(res) != URES_INT) {
     533           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     534             :     }
     535           0 :     return RES_GET_INT(res);
     536             : }
     537             : 
     538           0 : uint32_t ResourceDataValue::getUInt(UErrorCode &errorCode) const {
     539           0 :     if(U_FAILURE(errorCode)) {
     540           0 :         return 0;
     541             :     }
     542           0 :     if(RES_GET_TYPE(res) != URES_INT) {
     543           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     544             :     }
     545           0 :     return RES_GET_UINT(res);
     546             : }
     547             : 
     548           0 : const int32_t *ResourceDataValue::getIntVector(int32_t &length, UErrorCode &errorCode) const {
     549           0 :     if(U_FAILURE(errorCode)) {
     550           0 :         return NULL;
     551             :     }
     552           0 :     const int32_t *iv = res_getIntVector(pResData, res, &length);
     553           0 :     if(iv == NULL) {
     554           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     555             :     }
     556           0 :     return iv;
     557             : }
     558             : 
     559           0 : const uint8_t *ResourceDataValue::getBinary(int32_t &length, UErrorCode &errorCode) const {
     560           0 :     if(U_FAILURE(errorCode)) {
     561           0 :         return NULL;
     562             :     }
     563           0 :     const uint8_t *b = res_getBinary(pResData, res, &length);
     564           0 :     if(b == NULL) {
     565           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     566             :     }
     567           0 :     return b;
     568             : }
     569             : 
     570           0 : ResourceArray ResourceDataValue::getArray(UErrorCode &errorCode) const {
     571           0 :     if(U_FAILURE(errorCode)) {
     572           0 :         return ResourceArray();
     573             :     }
     574           0 :     const uint16_t *items16 = NULL;
     575           0 :     const Resource *items32 = NULL;
     576           0 :     uint32_t offset=RES_GET_OFFSET(res);
     577           0 :     int32_t length = 0;
     578           0 :     switch(RES_GET_TYPE(res)) {
     579             :     case URES_ARRAY:
     580           0 :         if (offset!=0) {  // empty if offset==0
     581           0 :             items32 = (const Resource *)pResData->pRoot+offset;
     582           0 :             length = *items32++;
     583             :         }
     584           0 :         break;
     585             :     case URES_ARRAY16:
     586           0 :         items16 = pResData->p16BitUnits+offset;
     587           0 :         length = *items16++;
     588           0 :         break;
     589             :     default:
     590           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     591           0 :         return ResourceArray();
     592             :     }
     593           0 :     return ResourceArray(items16, items32, length);
     594             : }
     595             : 
     596           0 : ResourceTable ResourceDataValue::getTable(UErrorCode &errorCode) const {
     597           0 :     if(U_FAILURE(errorCode)) {
     598           0 :         return ResourceTable();
     599             :     }
     600           0 :     const uint16_t *keys16 = NULL;
     601           0 :     const int32_t *keys32 = NULL;
     602           0 :     const uint16_t *items16 = NULL;
     603           0 :     const Resource *items32 = NULL;
     604           0 :     uint32_t offset = RES_GET_OFFSET(res);
     605           0 :     int32_t length = 0;
     606           0 :     switch(RES_GET_TYPE(res)) {
     607             :     case URES_TABLE:
     608           0 :         if (offset != 0) {  // empty if offset==0
     609           0 :             keys16 = (const uint16_t *)(pResData->pRoot+offset);
     610           0 :             length = *keys16++;
     611           0 :             items32 = (const Resource *)(keys16+length+(~length&1));
     612             :         }
     613           0 :         break;
     614             :     case URES_TABLE16:
     615           0 :         keys16 = pResData->p16BitUnits+offset;
     616           0 :         length = *keys16++;
     617           0 :         items16 = keys16 + length;
     618           0 :         break;
     619             :     case URES_TABLE32:
     620           0 :         if (offset != 0) {  // empty if offset==0
     621           0 :             keys32 = pResData->pRoot+offset;
     622           0 :             length = *keys32++;
     623           0 :             items32 = (const Resource *)keys32 + length;
     624             :         }
     625           0 :         break;
     626             :     default:
     627           0 :         errorCode = U_RESOURCE_TYPE_MISMATCH;
     628           0 :         return ResourceTable();
     629             :     }
     630           0 :     return ResourceTable(keys16, keys32, items16, items32, length);
     631             : }
     632             : 
     633           0 : UBool ResourceDataValue::isNoInheritanceMarker() const {
     634           0 :     return ::isNoInheritanceMarker(pResData, res);
     635             : }
     636             : 
     637           0 : int32_t ResourceDataValue::getStringArray(UnicodeString *dest, int32_t capacity,
     638             :                                           UErrorCode &errorCode) const {
     639           0 :     return ::getStringArray(pResData, getArray(errorCode), dest, capacity, errorCode);
     640             : }
     641             : 
     642           0 : int32_t ResourceDataValue::getStringArrayOrStringAsArray(UnicodeString *dest, int32_t capacity,
     643             :                                                          UErrorCode &errorCode) const {
     644           0 :     if(URES_IS_ARRAY(res)) {
     645           0 :         return ::getStringArray(pResData, getArray(errorCode), dest, capacity, errorCode);
     646             :     }
     647           0 :     if(U_FAILURE(errorCode)) {
     648           0 :         return 0;
     649             :     }
     650           0 :     if(dest == NULL ? capacity != 0 : capacity < 0) {
     651           0 :         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
     652           0 :         return 0;
     653             :     }
     654           0 :     if(capacity < 1) {
     655           0 :         errorCode = U_BUFFER_OVERFLOW_ERROR;
     656           0 :         return 1;
     657             :     }
     658             :     int32_t sLength;
     659           0 :     const UChar *s = res_getString(pResData, res, &sLength);
     660           0 :     if(s != NULL) {
     661           0 :         dest[0].setTo(TRUE, s, sLength);
     662           0 :         return 1;
     663             :     }
     664           0 :     errorCode = U_RESOURCE_TYPE_MISMATCH;
     665           0 :     return 0;
     666             : }
     667             : 
     668           0 : UnicodeString ResourceDataValue::getStringOrFirstOfArray(UErrorCode &errorCode) const {
     669           0 :     UnicodeString us;
     670           0 :     if(U_FAILURE(errorCode)) {
     671           0 :         return us;
     672             :     }
     673             :     int32_t sLength;
     674           0 :     const UChar *s = res_getString(pResData, res, &sLength);
     675           0 :     if(s != NULL) {
     676           0 :         us.setTo(TRUE, s, sLength);
     677           0 :         return us;
     678             :     }
     679           0 :     ResourceArray array = getArray(errorCode);
     680           0 :     if(U_FAILURE(errorCode)) {
     681           0 :         return us;
     682             :     }
     683           0 :     if(array.getSize() > 0) {
     684           0 :         s = res_getString(pResData, array.internalGetResource(pResData, 0), &sLength);
     685           0 :         if(s != NULL) {
     686           0 :             us.setTo(TRUE, s, sLength);
     687           0 :             return us;
     688             :         }
     689             :     }
     690           0 :     errorCode = U_RESOURCE_TYPE_MISMATCH;
     691           0 :     return us;
     692             : }
     693             : 
     694             : U_NAMESPACE_END
     695             : 
     696             : static Resource
     697           2 : makeResourceFrom16(const ResourceData *pResData, int32_t res16) {
     698           2 :     if(res16<pResData->poolStringIndex16Limit) {
     699             :         // Pool string, nothing to do.
     700             :     } else {
     701             :         // Local string, adjust the 16-bit offset to a regular one,
     702             :         // with a larger pool string index limit.
     703           2 :         res16=res16-pResData->poolStringIndex16Limit+pResData->poolStringIndexLimit;
     704             :     }
     705           2 :     return URES_MAKE_RESOURCE(URES_STRING_V2, res16);
     706             : }
     707             : 
     708             : U_CAPI Resource U_EXPORT2
     709           5 : res_getTableItemByKey(const ResourceData *pResData, Resource table,
     710             :                       int32_t *indexR, const char **key) {
     711           5 :     uint32_t offset=RES_GET_OFFSET(table);
     712             :     int32_t length;
     713             :     int32_t idx;
     714           5 :     if(key == NULL || *key == NULL) {
     715           0 :         return RES_BOGUS;
     716             :     }
     717           5 :     switch(RES_GET_TYPE(table)) {
     718             :     case URES_TABLE: {
     719           0 :         if (offset!=0) { /* empty if offset==0 */
     720           0 :             const uint16_t *p= (const uint16_t *)(pResData->pRoot+offset);
     721           0 :             length=*p++;
     722           0 :             *indexR=idx=_res_findTableItem(pResData, p, length, *key, key);
     723           0 :             if(idx>=0) {
     724           0 :                 const Resource *p32=(const Resource *)(p+length+(~length&1));
     725           0 :                 return p32[idx];
     726             :             }
     727             :         }
     728           0 :         break;
     729             :     }
     730             :     case URES_TABLE16: {
     731           5 :         const uint16_t *p=pResData->p16BitUnits+offset;
     732           5 :         length=*p++;
     733           5 :         *indexR=idx=_res_findTableItem(pResData, p, length, *key, key);
     734           5 :         if(idx>=0) {
     735           2 :             return makeResourceFrom16(pResData, p[length+idx]);
     736             :         }
     737           3 :         break;
     738             :     }
     739             :     case URES_TABLE32: {
     740           0 :         if (offset!=0) { /* empty if offset==0 */
     741           0 :             const int32_t *p= pResData->pRoot+offset;
     742           0 :             length=*p++;
     743           0 :             *indexR=idx=_res_findTable32Item(pResData, p, length, *key, key);
     744           0 :             if(idx>=0) {
     745           0 :                 return (Resource)p[length+idx];
     746             :             }
     747             :         }
     748           0 :         break;
     749             :     }
     750             :     default:
     751           0 :         break;
     752             :     }
     753           3 :     return RES_BOGUS;
     754             : }
     755             : 
     756             : U_CAPI Resource U_EXPORT2
     757           0 : res_getTableItemByIndex(const ResourceData *pResData, Resource table,
     758             :                         int32_t indexR, const char **key) {
     759           0 :     uint32_t offset=RES_GET_OFFSET(table);
     760             :     int32_t length;
     761           0 :     if (indexR < 0) {
     762           0 :         return RES_BOGUS;
     763             :     }
     764           0 :     switch(RES_GET_TYPE(table)) {
     765             :     case URES_TABLE: {
     766           0 :         if (offset != 0) { /* empty if offset==0 */
     767           0 :             const uint16_t *p= (const uint16_t *)(pResData->pRoot+offset);
     768           0 :             length=*p++;
     769           0 :             if(indexR<length) {
     770           0 :                 const Resource *p32=(const Resource *)(p+length+(~length&1));
     771           0 :                 if(key!=NULL) {
     772           0 :                     *key=RES_GET_KEY16(pResData, p[indexR]);
     773             :                 }
     774           0 :                 return p32[indexR];
     775             :             }
     776             :         }
     777           0 :         break;
     778             :     }
     779             :     case URES_TABLE16: {
     780           0 :         const uint16_t *p=pResData->p16BitUnits+offset;
     781           0 :         length=*p++;
     782           0 :         if(indexR<length) {
     783           0 :             if(key!=NULL) {
     784           0 :                 *key=RES_GET_KEY16(pResData, p[indexR]);
     785             :             }
     786           0 :             return makeResourceFrom16(pResData, p[length+indexR]);
     787             :         }
     788           0 :         break;
     789             :     }
     790             :     case URES_TABLE32: {
     791           0 :         if (offset != 0) { /* empty if offset==0 */
     792           0 :             const int32_t *p= pResData->pRoot+offset;
     793           0 :             length=*p++;
     794           0 :             if(indexR<length) {
     795           0 :                 if(key!=NULL) {
     796           0 :                     *key=RES_GET_KEY32(pResData, p[indexR]);
     797             :                 }
     798           0 :                 return (Resource)p[length+indexR];
     799             :             }
     800             :         }
     801           0 :         break;
     802             :     }
     803             :     default:
     804           0 :         break;
     805             :     }
     806           0 :     return RES_BOGUS;
     807             : }
     808             : 
     809             : U_CAPI Resource U_EXPORT2
     810           1 : res_getResource(const ResourceData *pResData, const char *key) {
     811           1 :     const char *realKey=key;
     812             :     int32_t idx;
     813           1 :     return res_getTableItemByKey(pResData, pResData->rootRes, &idx, &realKey);
     814             : }
     815             : 
     816             : 
     817           0 : UBool icu::ResourceTable::getKeyAndValue(int32_t i,
     818             :                                          const char *&key, icu::ResourceValue &value) const {
     819           0 :     if(0 <= i && i < length) {
     820           0 :         icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value);
     821           0 :         if (keys16 != NULL) {
     822           0 :             key = RES_GET_KEY16(rdValue.pResData, keys16[i]);
     823             :         } else {
     824           0 :             key = RES_GET_KEY32(rdValue.pResData, keys32[i]);
     825             :         }
     826             :         Resource res;
     827           0 :         if (items16 != NULL) {
     828           0 :             res = makeResourceFrom16(rdValue.pResData, items16[i]);
     829             :         } else {
     830           0 :             res = items32[i];
     831             :         }
     832           0 :         rdValue.setResource(res);
     833           0 :         return TRUE;
     834             :     }
     835           0 :     return FALSE;
     836             : }
     837             : 
     838             : U_CAPI Resource U_EXPORT2
     839           0 : res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
     840           0 :     uint32_t offset=RES_GET_OFFSET(array);
     841           0 :     if (indexR < 0) {
     842           0 :         return RES_BOGUS;
     843             :     }
     844           0 :     switch(RES_GET_TYPE(array)) {
     845             :     case URES_ARRAY: {
     846           0 :         if (offset!=0) { /* empty if offset==0 */
     847           0 :             const int32_t *p= pResData->pRoot+offset;
     848           0 :             if(indexR<*p) {
     849           0 :                 return (Resource)p[1+indexR];
     850             :             }
     851             :         }
     852           0 :         break;
     853             :     }
     854             :     case URES_ARRAY16: {
     855           0 :         const uint16_t *p=pResData->p16BitUnits+offset;
     856           0 :         if(indexR<*p) {
     857           0 :             return makeResourceFrom16(pResData, p[1+indexR]);
     858             :         }
     859           0 :         break;
     860             :     }
     861             :     default:
     862           0 :         break;
     863             :     }
     864           0 :     return RES_BOGUS;
     865             : }
     866             : 
     867           0 : uint32_t icu::ResourceArray::internalGetResource(const ResourceData *pResData, int32_t i) const {
     868           0 :     if (items16 != NULL) {
     869           0 :         return makeResourceFrom16(pResData, items16[i]);
     870             :     } else {
     871           0 :         return items32[i];
     872             :     }
     873             : }
     874             : 
     875           0 : UBool icu::ResourceArray::getValue(int32_t i, icu::ResourceValue &value) const {
     876           0 :     if(0 <= i && i < length) {
     877           0 :         icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value);
     878           0 :         rdValue.setResource(internalGetResource(rdValue.pResData, i));
     879           0 :         return TRUE;
     880             :     }
     881           0 :     return FALSE;
     882             : }
     883             : 
     884             : U_CFUNC Resource
     885           0 : res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key) {
     886           0 :   char *pathP = *path, *nextSepP = *path;
     887           0 :   char *closeIndex = NULL;
     888           0 :   Resource t1 = r;
     889             :   Resource t2;
     890           0 :   int32_t indexR = 0;
     891           0 :   UResType type = (UResType)RES_GET_TYPE(t1);
     892             : 
     893             :   /* if you come in with an empty path, you'll be getting back the same resource */
     894           0 :   if(!uprv_strlen(pathP)) {
     895           0 :       return r;
     896             :   }
     897             : 
     898             :   /* one needs to have an aggregate resource in order to search in it */
     899           0 :   if(!URES_IS_CONTAINER(type)) {
     900           0 :       return RES_BOGUS;
     901             :   }
     902             :   
     903           0 :   while(nextSepP && *pathP && t1 != RES_BOGUS && URES_IS_CONTAINER(type)) {
     904             :     /* Iteration stops if: the path has been consumed, we found a non-existing
     905             :      * resource (t1 == RES_BOGUS) or we found a scalar resource (including alias)
     906             :      */
     907           0 :     nextSepP = uprv_strchr(pathP, RES_PATH_SEPARATOR);
     908             :     /* if there are more separators, terminate string 
     909             :      * and set path to the remaining part of the string
     910             :      */
     911           0 :     if(nextSepP != NULL) {
     912           0 :       if(nextSepP == pathP) {
     913             :         // Empty key string.
     914           0 :         return RES_BOGUS;
     915             :       }
     916           0 :       *nextSepP = 0; /* overwrite the separator with a NUL to terminate the key */
     917           0 :       *path = nextSepP+1;
     918             :     } else {
     919           0 :       *path = uprv_strchr(pathP, 0);
     920             :     }
     921             : 
     922             :     /* if the resource is a table */
     923             :     /* try the key based access */
     924           0 :     if(URES_IS_TABLE(type)) {
     925           0 :       *key = pathP;
     926           0 :       t2 = res_getTableItemByKey(pResData, t1, &indexR, key);
     927           0 :       if(t2 == RES_BOGUS) { 
     928             :         /* if we fail to get the resource by key, maybe we got an index */
     929           0 :         indexR = uprv_strtol(pathP, &closeIndex, 10);
     930           0 :         if(indexR >= 0 && *closeIndex == 0) {
     931             :           /* if we indeed have an index, try to get the item by index */
     932           0 :           t2 = res_getTableItemByIndex(pResData, t1, indexR, key);
     933             :         } // else t2 is already RES_BOGUS
     934             :       }
     935           0 :     } else if(URES_IS_ARRAY(type)) {
     936           0 :       indexR = uprv_strtol(pathP, &closeIndex, 10);
     937           0 :       if(indexR >= 0 && *closeIndex == 0) {
     938           0 :         t2 = res_getArrayItem(pResData, t1, indexR);
     939             :       } else {
     940           0 :         t2 = RES_BOGUS; /* have an array, but don't have a valid index */
     941             :       }
     942           0 :       *key = NULL;
     943             :     } else { /* can't do much here, except setting t2 to bogus */
     944           0 :       t2 = RES_BOGUS;
     945             :     }
     946           0 :     t1 = t2;
     947           0 :     type = (UResType)RES_GET_TYPE(t1);
     948             :     /* position pathP to next resource key/index */
     949           0 :     pathP = *path;
     950             :   }
     951             : 
     952           0 :   return t1;
     953             : }
     954             : 
     955             : /* resource bundle swapping ------------------------------------------------- */
     956             : 
     957             : /*
     958             :  * Need to always enumerate the entire item tree,
     959             :  * track the lowest address of any item to use as the limit for char keys[],
     960             :  * track the highest address of any item to return the size of the data.
     961             :  *
     962             :  * We should have thought of storing those in the data...
     963             :  * It is possible to extend the data structure by putting additional values
     964             :  * in places that are inaccessible by ordinary enumeration of the item tree.
     965             :  * For example, additional integers could be stored at the beginning or
     966             :  * end of the key strings; this could be indicated by a minor version number,
     967             :  * and the data swapping would have to know about these values.
     968             :  *
     969             :  * The data structure does not forbid keys to be shared, so we must swap
     970             :  * all keys once instead of each key when it is referenced.
     971             :  *
     972             :  * These swapping functions assume that a resource bundle always has a length
     973             :  * that is a multiple of 4 bytes.
     974             :  * Currently, this is trivially true because genrb writes bundle tree leaves
     975             :  * physically first, before their branches, so that the root table with its
     976             :  * array of resource items (uint32_t values) is always last.
     977             :  */
     978             : 
     979             : /* definitions for table sorting ------------------------ */
     980             : 
     981             : /*
     982             :  * row of a temporary array
     983             :  *
     984             :  * gets platform-endian key string indexes and sorting indexes;
     985             :  * after sorting this array by keys, the actual key/value arrays are permutated
     986             :  * according to the sorting indexes
     987             :  */
     988             : typedef struct Row {
     989             :     int32_t keyIndex, sortIndex;
     990             : } Row;
     991             : 
     992             : static int32_t U_CALLCONV
     993           0 : ures_compareRows(const void *context, const void *left, const void *right) {
     994           0 :     const char *keyChars=(const char *)context;
     995           0 :     return (int32_t)uprv_strcmp(keyChars+((const Row *)left)->keyIndex,
     996             :                                 keyChars+((const Row *)right)->keyIndex);
     997             : }
     998             : 
     999             : typedef struct TempTable {
    1000             :     const char *keyChars;
    1001             :     Row *rows;
    1002             :     int32_t *resort;
    1003             :     uint32_t *resFlags;
    1004             :     int32_t localKeyLimit;
    1005             :     uint8_t majorFormatVersion;
    1006             : } TempTable;
    1007             : 
    1008             : enum {
    1009             :     STACK_ROW_CAPACITY=200
    1010             : };
    1011             : 
    1012             : /* The table item key string is not locally available. */
    1013             : static const char *const gUnknownKey="";
    1014             : 
    1015             : /* resource table key for collation binaries: "%%CollationBin" */
    1016             : static const UChar gCollationBinKey[]={
    1017             :     0x25, 0x25,
    1018             :     0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
    1019             :     0x42, 0x69, 0x6e,
    1020             :     0
    1021             : };
    1022             : 
    1023             : /*
    1024             :  * swap one resource item
    1025             :  */
    1026             : static void
    1027           0 : ures_swapResource(const UDataSwapper *ds,
    1028             :                   const Resource *inBundle, Resource *outBundle,
    1029             :                   Resource res, /* caller swaps res itself */
    1030             :                   const char *key,
    1031             :                   TempTable *pTempTable,
    1032             :                   UErrorCode *pErrorCode) {
    1033             :     const Resource *p;
    1034             :     Resource *q;
    1035             :     int32_t offset, count;
    1036             : 
    1037           0 :     switch(RES_GET_TYPE(res)) {
    1038             :     case URES_TABLE16:
    1039             :     case URES_STRING_V2:
    1040             :     case URES_INT:
    1041             :     case URES_ARRAY16:
    1042             :         /* integer, or points to 16-bit units, nothing to do here */
    1043           0 :         return;
    1044             :     default:
    1045           0 :         break;
    1046             :     }
    1047             : 
    1048             :     /* all other types use an offset to point to their data */
    1049           0 :     offset=(int32_t)RES_GET_OFFSET(res);
    1050           0 :     if(offset==0) {
    1051             :         /* special offset indicating an empty item */
    1052           0 :         return;
    1053             :     }
    1054           0 :     if(pTempTable->resFlags[offset>>5]&((uint32_t)1<<(offset&0x1f))) {
    1055             :         /* we already swapped this resource item */
    1056           0 :         return;
    1057             :     } else {
    1058             :         /* mark it as swapped now */
    1059           0 :         pTempTable->resFlags[offset>>5]|=((uint32_t)1<<(offset&0x1f));
    1060             :     }
    1061             : 
    1062           0 :     p=inBundle+offset;
    1063           0 :     q=outBundle+offset;
    1064             : 
    1065           0 :     switch(RES_GET_TYPE(res)) {
    1066             :     case URES_ALIAS:
    1067             :         /* physically same value layout as string, fall through */
    1068             :         U_FALLTHROUGH;
    1069             :     case URES_STRING:
    1070           0 :         count=udata_readInt32(ds, (int32_t)*p);
    1071             :         /* swap length */
    1072           0 :         ds->swapArray32(ds, p, 4, q, pErrorCode);
    1073             :         /* swap each UChar (the terminating NUL would not change) */
    1074           0 :         ds->swapArray16(ds, p+1, 2*count, q+1, pErrorCode);
    1075           0 :         break;
    1076             :     case URES_BINARY:
    1077           0 :         count=udata_readInt32(ds, (int32_t)*p);
    1078             :         /* swap length */
    1079           0 :         ds->swapArray32(ds, p, 4, q, pErrorCode);
    1080             :         /* no need to swap or copy bytes - ures_swap() copied them all */
    1081             : 
    1082             :         /* swap known formats */
    1083             : #if !UCONFIG_NO_COLLATION
    1084           0 :         if( key!=NULL &&  /* the binary is in a table */
    1085             :             (key!=gUnknownKey ?
    1086             :                 /* its table key string is "%%CollationBin" */
    1087           0 :                 0==ds->compareInvChars(ds, key, -1,
    1088             :                                        gCollationBinKey, UPRV_LENGTHOF(gCollationBinKey)-1) :
    1089             :                 /* its table key string is unknown but it looks like a collation binary */
    1090           0 :                 ucol_looksLikeCollationBinary(ds, p+1, count))
    1091             :         ) {
    1092           0 :             ucol_swap(ds, p+1, count, q+1, pErrorCode);
    1093             :         }
    1094             : #endif
    1095           0 :         break;
    1096             :     case URES_TABLE:
    1097             :     case URES_TABLE32:
    1098             :         {
    1099             :             const uint16_t *pKey16;
    1100             :             uint16_t *qKey16;
    1101             : 
    1102             :             const int32_t *pKey32;
    1103             :             int32_t *qKey32;
    1104             : 
    1105             :             Resource item;
    1106             :             int32_t i, oldIndex;
    1107             : 
    1108           0 :             if(RES_GET_TYPE(res)==URES_TABLE) {
    1109             :                 /* get table item count */
    1110           0 :                 pKey16=(const uint16_t *)p;
    1111           0 :                 qKey16=(uint16_t *)q;
    1112           0 :                 count=ds->readUInt16(*pKey16);
    1113             : 
    1114           0 :                 pKey32=qKey32=NULL;
    1115             : 
    1116             :                 /* swap count */
    1117           0 :                 ds->swapArray16(ds, pKey16++, 2, qKey16++, pErrorCode);
    1118             : 
    1119           0 :                 offset+=((1+count)+1)/2;
    1120             :             } else {
    1121             :                 /* get table item count */
    1122           0 :                 pKey32=(const int32_t *)p;
    1123           0 :                 qKey32=(int32_t *)q;
    1124           0 :                 count=udata_readInt32(ds, *pKey32);
    1125             : 
    1126           0 :                 pKey16=qKey16=NULL;
    1127             : 
    1128             :                 /* swap count */
    1129           0 :                 ds->swapArray32(ds, pKey32++, 4, qKey32++, pErrorCode);
    1130             : 
    1131           0 :                 offset+=1+count;
    1132             :             }
    1133             : 
    1134           0 :             if(count==0) {
    1135           0 :                 break;
    1136             :             }
    1137             : 
    1138           0 :             p=inBundle+offset; /* pointer to table resources */
    1139           0 :             q=outBundle+offset;
    1140             : 
    1141             :             /* recurse */
    1142           0 :             for(i=0; i<count; ++i) {
    1143           0 :                 const char *itemKey=gUnknownKey;
    1144           0 :                 if(pKey16!=NULL) {
    1145           0 :                     int32_t keyOffset=ds->readUInt16(pKey16[i]);
    1146           0 :                     if(keyOffset<pTempTable->localKeyLimit) {
    1147           0 :                         itemKey=(const char *)outBundle+keyOffset;
    1148             :                     }
    1149             :                 } else {
    1150           0 :                     int32_t keyOffset=udata_readInt32(ds, pKey32[i]);
    1151           0 :                     if(keyOffset>=0) {
    1152           0 :                         itemKey=(const char *)outBundle+keyOffset;
    1153             :                     }
    1154             :                 }
    1155           0 :                 item=ds->readUInt32(p[i]);
    1156           0 :                 ures_swapResource(ds, inBundle, outBundle, item, itemKey, pTempTable, pErrorCode);
    1157           0 :                 if(U_FAILURE(*pErrorCode)) {
    1158             :                     udata_printError(ds, "ures_swapResource(table res=%08x)[%d].recurse(%08x) failed\n",
    1159           0 :                                      res, i, item);
    1160           0 :                     return;
    1161             :                 }
    1162             :             }
    1163             : 
    1164           0 :             if(pTempTable->majorFormatVersion>1 || ds->inCharset==ds->outCharset) {
    1165             :                 /* no need to sort, just swap the offset/value arrays */
    1166           0 :                 if(pKey16!=NULL) {
    1167           0 :                     ds->swapArray16(ds, pKey16, count*2, qKey16, pErrorCode);
    1168           0 :                     ds->swapArray32(ds, p, count*4, q, pErrorCode);
    1169             :                 } else {
    1170             :                     /* swap key offsets and items as one array */
    1171           0 :                     ds->swapArray32(ds, pKey32, count*2*4, qKey32, pErrorCode);
    1172             :                 }
    1173           0 :                 break;
    1174             :             }
    1175             : 
    1176             :             /*
    1177             :              * We need to sort tables by outCharset key strings because they
    1178             :              * sort differently for different charset families.
    1179             :              * ures_swap() already set pTempTable->keyChars appropriately.
    1180             :              * First we set up a temporary table with the key indexes and
    1181             :              * sorting indexes and sort that.
    1182             :              * Then we permutate and copy/swap the actual values.
    1183             :              */
    1184           0 :             if(pKey16!=NULL) {
    1185           0 :                 for(i=0; i<count; ++i) {
    1186           0 :                     pTempTable->rows[i].keyIndex=ds->readUInt16(pKey16[i]);
    1187           0 :                     pTempTable->rows[i].sortIndex=i;
    1188             :                 }
    1189             :             } else {
    1190           0 :                 for(i=0; i<count; ++i) {
    1191           0 :                     pTempTable->rows[i].keyIndex=udata_readInt32(ds, pKey32[i]);
    1192           0 :                     pTempTable->rows[i].sortIndex=i;
    1193             :                 }
    1194             :             }
    1195           0 :             uprv_sortArray(pTempTable->rows, count, sizeof(Row),
    1196           0 :                            ures_compareRows, pTempTable->keyChars,
    1197           0 :                            FALSE, pErrorCode);
    1198           0 :             if(U_FAILURE(*pErrorCode)) {
    1199             :                 udata_printError(ds, "ures_swapResource(table res=%08x).uprv_sortArray(%d items) failed\n",
    1200           0 :                                  res, count);
    1201           0 :                 return;
    1202             :             }
    1203             : 
    1204             :             /*
    1205             :              * copy/swap/permutate items
    1206             :              *
    1207             :              * If we swap in-place, then the permutation must use another
    1208             :              * temporary array (pTempTable->resort)
    1209             :              * before the results are copied to the outBundle.
    1210             :              */
    1211             :             /* keys */
    1212           0 :             if(pKey16!=NULL) {
    1213             :                 uint16_t *rKey16;
    1214             : 
    1215           0 :                 if(pKey16!=qKey16) {
    1216           0 :                     rKey16=qKey16;
    1217             :                 } else {
    1218           0 :                     rKey16=(uint16_t *)pTempTable->resort;
    1219             :                 }
    1220           0 :                 for(i=0; i<count; ++i) {
    1221           0 :                     oldIndex=pTempTable->rows[i].sortIndex;
    1222           0 :                     ds->swapArray16(ds, pKey16+oldIndex, 2, rKey16+i, pErrorCode);
    1223             :                 }
    1224           0 :                 if(qKey16!=rKey16) {
    1225           0 :                     uprv_memcpy(qKey16, rKey16, 2*count);
    1226             :                 }
    1227             :             } else {
    1228             :                 int32_t *rKey32;
    1229             : 
    1230           0 :                 if(pKey32!=qKey32) {
    1231           0 :                     rKey32=qKey32;
    1232             :                 } else {
    1233           0 :                     rKey32=pTempTable->resort;
    1234             :                 }
    1235           0 :                 for(i=0; i<count; ++i) {
    1236           0 :                     oldIndex=pTempTable->rows[i].sortIndex;
    1237           0 :                     ds->swapArray32(ds, pKey32+oldIndex, 4, rKey32+i, pErrorCode);
    1238             :                 }
    1239           0 :                 if(qKey32!=rKey32) {
    1240           0 :                     uprv_memcpy(qKey32, rKey32, 4*count);
    1241             :                 }
    1242             :             }
    1243             : 
    1244             :             /* resources */
    1245             :             {
    1246             :                 Resource *r;
    1247             : 
    1248             : 
    1249           0 :                 if(p!=q) {
    1250           0 :                     r=q;
    1251             :                 } else {
    1252           0 :                     r=(Resource *)pTempTable->resort;
    1253             :                 }
    1254           0 :                 for(i=0; i<count; ++i) {
    1255           0 :                     oldIndex=pTempTable->rows[i].sortIndex;
    1256           0 :                     ds->swapArray32(ds, p+oldIndex, 4, r+i, pErrorCode);
    1257             :                 }
    1258           0 :                 if(q!=r) {
    1259           0 :                     uprv_memcpy(q, r, 4*count);
    1260             :                 }
    1261             :             }
    1262             :         }
    1263           0 :         break;
    1264             :     case URES_ARRAY:
    1265             :         {
    1266             :             Resource item;
    1267             :             int32_t i;
    1268             : 
    1269           0 :             count=udata_readInt32(ds, (int32_t)*p);
    1270             :             /* swap length */
    1271           0 :             ds->swapArray32(ds, p++, 4, q++, pErrorCode);
    1272             : 
    1273             :             /* recurse */
    1274           0 :             for(i=0; i<count; ++i) {
    1275           0 :                 item=ds->readUInt32(p[i]);
    1276           0 :                 ures_swapResource(ds, inBundle, outBundle, item, NULL, pTempTable, pErrorCode);
    1277           0 :                 if(U_FAILURE(*pErrorCode)) {
    1278             :                     udata_printError(ds, "ures_swapResource(array res=%08x)[%d].recurse(%08x) failed\n",
    1279           0 :                                      res, i, item);
    1280           0 :                     return;
    1281             :                 }
    1282             :             }
    1283             : 
    1284             :             /* swap items */
    1285           0 :             ds->swapArray32(ds, p, 4*count, q, pErrorCode);
    1286             :         }
    1287           0 :         break;
    1288             :     case URES_INT_VECTOR:
    1289           0 :         count=udata_readInt32(ds, (int32_t)*p);
    1290             :         /* swap length and each integer */
    1291           0 :         ds->swapArray32(ds, p, 4*(1+count), q, pErrorCode);
    1292           0 :         break;
    1293             :     default:
    1294             :         /* also catches RES_BOGUS */
    1295           0 :         *pErrorCode=U_UNSUPPORTED_ERROR;
    1296           0 :         break;
    1297             :     }
    1298             : }
    1299             : 
    1300             : U_CAPI int32_t U_EXPORT2
    1301           0 : ures_swap(const UDataSwapper *ds,
    1302             :           const void *inData, int32_t length, void *outData,
    1303             :           UErrorCode *pErrorCode) {
    1304             :     const UDataInfo *pInfo;
    1305             :     const Resource *inBundle;
    1306             :     Resource rootRes;
    1307             :     int32_t headerSize, maxTableLength;
    1308             : 
    1309             :     Row rows[STACK_ROW_CAPACITY];
    1310             :     int32_t resort[STACK_ROW_CAPACITY];
    1311             :     TempTable tempTable;
    1312             : 
    1313             :     const int32_t *inIndexes;
    1314             : 
    1315             :     /* the following integers count Resource item offsets (4 bytes each), not bytes */
    1316             :     int32_t bundleLength, indexLength, keysBottom, keysTop, resBottom, top;
    1317             : 
    1318             :     /* udata_swapDataHeader checks the arguments */
    1319           0 :     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
    1320           0 :     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    1321           0 :         return 0;
    1322             :     }
    1323             : 
    1324             :     /* check data format and format version */
    1325           0 :     pInfo=(const UDataInfo *)((const char *)inData+4);
    1326           0 :     if(!(
    1327           0 :         pInfo->dataFormat[0]==0x52 &&   /* dataFormat="ResB" */
    1328           0 :         pInfo->dataFormat[1]==0x65 &&
    1329           0 :         pInfo->dataFormat[2]==0x73 &&
    1330           0 :         pInfo->dataFormat[3]==0x42 &&
    1331             :         /* formatVersion 1.1+ or 2.x or 3.x */
    1332           0 :         ((pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1) ||
    1333           0 :             pInfo->formatVersion[0]==2 || pInfo->formatVersion[0]==3)
    1334             :     )) {
    1335           0 :         udata_printError(ds, "ures_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not a resource bundle\n",
    1336           0 :                          pInfo->dataFormat[0], pInfo->dataFormat[1],
    1337           0 :                          pInfo->dataFormat[2], pInfo->dataFormat[3],
    1338           0 :                          pInfo->formatVersion[0], pInfo->formatVersion[1]);
    1339           0 :         *pErrorCode=U_UNSUPPORTED_ERROR;
    1340           0 :         return 0;
    1341             :     }
    1342           0 :     tempTable.majorFormatVersion=pInfo->formatVersion[0];
    1343             : 
    1344             :     /* a resource bundle must contain at least one resource item */
    1345           0 :     if(length<0) {
    1346           0 :         bundleLength=-1;
    1347             :     } else {
    1348           0 :         bundleLength=(length-headerSize)/4;
    1349             : 
    1350             :         /* formatVersion 1.1 must have a root item and at least 5 indexes */
    1351           0 :         if(bundleLength<(1+5)) {
    1352           0 :             udata_printError(ds, "ures_swap(): too few bytes (%d after header) for a resource bundle\n",
    1353           0 :                              length-headerSize);
    1354           0 :             *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    1355           0 :             return 0;
    1356             :         }
    1357             :     }
    1358             : 
    1359           0 :     inBundle=(const Resource *)((const char *)inData+headerSize);
    1360           0 :     rootRes=ds->readUInt32(*inBundle);
    1361             : 
    1362             :     /* formatVersion 1.1 adds the indexes[] array */
    1363           0 :     inIndexes=(const int32_t *)(inBundle+1);
    1364             : 
    1365           0 :     indexLength=udata_readInt32(ds, inIndexes[URES_INDEX_LENGTH])&0xff;
    1366           0 :     if(indexLength<=URES_INDEX_MAX_TABLE_LENGTH) {
    1367           0 :         udata_printError(ds, "ures_swap(): too few indexes for a 1.1+ resource bundle\n");
    1368           0 :         *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    1369           0 :         return 0;
    1370             :     }
    1371           0 :     keysBottom=1+indexLength;
    1372           0 :     keysTop=udata_readInt32(ds, inIndexes[URES_INDEX_KEYS_TOP]);
    1373           0 :     if(indexLength>URES_INDEX_16BIT_TOP) {
    1374           0 :         resBottom=udata_readInt32(ds, inIndexes[URES_INDEX_16BIT_TOP]);
    1375             :     } else {
    1376           0 :         resBottom=keysTop;
    1377             :     }
    1378           0 :     top=udata_readInt32(ds, inIndexes[URES_INDEX_BUNDLE_TOP]);
    1379           0 :     maxTableLength=udata_readInt32(ds, inIndexes[URES_INDEX_MAX_TABLE_LENGTH]);
    1380             : 
    1381           0 :     if(0<=bundleLength && bundleLength<top) {
    1382             :         udata_printError(ds, "ures_swap(): resource top %d exceeds bundle length %d\n",
    1383           0 :                          top, bundleLength);
    1384           0 :         *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
    1385           0 :         return 0;
    1386             :     }
    1387           0 :     if(keysTop>(1+indexLength)) {
    1388           0 :         tempTable.localKeyLimit=keysTop<<2;
    1389             :     } else {
    1390           0 :         tempTable.localKeyLimit=0;
    1391             :     }
    1392             : 
    1393           0 :     if(length>=0) {
    1394           0 :         Resource *outBundle=(Resource *)((char *)outData+headerSize);
    1395             : 
    1396             :         /* track which resources we have already swapped */
    1397             :         uint32_t stackResFlags[STACK_ROW_CAPACITY];
    1398             :         int32_t resFlagsLength;
    1399             : 
    1400             :         /*
    1401             :          * We need one bit per 4 resource bundle bytes so that we can track
    1402             :          * every possible Resource for whether we have swapped it already.
    1403             :          * Multiple Resource words can refer to the same bundle offsets
    1404             :          * for sharing identical values.
    1405             :          * We could optimize this by allocating only for locations above
    1406             :          * where Resource values are stored (above keys & strings).
    1407             :          */
    1408           0 :         resFlagsLength=(length+31)>>5;          /* number of bytes needed */
    1409           0 :         resFlagsLength=(resFlagsLength+3)&~3;   /* multiple of 4 bytes for uint32_t */
    1410           0 :         if(resFlagsLength<=(int32_t)sizeof(stackResFlags)) {
    1411           0 :             tempTable.resFlags=stackResFlags;
    1412             :         } else {
    1413           0 :             tempTable.resFlags=(uint32_t *)uprv_malloc(resFlagsLength);
    1414           0 :             if(tempTable.resFlags==NULL) {
    1415           0 :                 udata_printError(ds, "ures_swap(): unable to allocate memory for tracking resources\n");
    1416           0 :                 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    1417           0 :                 return 0;
    1418             :             }
    1419             :         }
    1420           0 :         uprv_memset(tempTable.resFlags, 0, resFlagsLength);
    1421             : 
    1422             :         /* copy the bundle for binary and inaccessible data */
    1423           0 :         if(inData!=outData) {
    1424           0 :             uprv_memcpy(outBundle, inBundle, 4*top);
    1425             :         }
    1426             : 
    1427             :         /* swap the key strings, but not the padding bytes (0xaa) after the last string and its NUL */
    1428           0 :         udata_swapInvStringBlock(ds, inBundle+keysBottom, 4*(keysTop-keysBottom),
    1429           0 :                                     outBundle+keysBottom, pErrorCode);
    1430           0 :         if(U_FAILURE(*pErrorCode)) {
    1431           0 :             udata_printError(ds, "ures_swap().udata_swapInvStringBlock(keys[%d]) failed\n", 4*(keysTop-keysBottom));
    1432           0 :             return 0;
    1433             :         }
    1434             : 
    1435             :         /* swap the 16-bit units (strings, table16, array16) */
    1436           0 :         if(keysTop<resBottom) {
    1437           0 :             ds->swapArray16(ds, inBundle+keysTop, (resBottom-keysTop)*4, outBundle+keysTop, pErrorCode);
    1438           0 :             if(U_FAILURE(*pErrorCode)) {
    1439           0 :                 udata_printError(ds, "ures_swap().swapArray16(16-bit units[%d]) failed\n", 2*(resBottom-keysTop));
    1440           0 :                 return 0;
    1441             :             }
    1442             :         }
    1443             : 
    1444             :         /* allocate the temporary table for sorting resource tables */
    1445           0 :         tempTable.keyChars=(const char *)outBundle; /* sort by outCharset */
    1446           0 :         if(tempTable.majorFormatVersion>1 || maxTableLength<=STACK_ROW_CAPACITY) {
    1447           0 :             tempTable.rows=rows;
    1448           0 :             tempTable.resort=resort;
    1449             :         } else {
    1450           0 :             tempTable.rows=(Row *)uprv_malloc(maxTableLength*sizeof(Row)+maxTableLength*4);
    1451           0 :             if(tempTable.rows==NULL) {
    1452             :                 udata_printError(ds, "ures_swap(): unable to allocate memory for sorting tables (max length: %d)\n",
    1453           0 :                                  maxTableLength);
    1454           0 :                 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    1455           0 :                 if(tempTable.resFlags!=stackResFlags) {
    1456           0 :                     uprv_free(tempTable.resFlags);
    1457             :                 }
    1458           0 :                 return 0;
    1459             :             }
    1460           0 :             tempTable.resort=(int32_t *)(tempTable.rows+maxTableLength);
    1461             :         }
    1462             : 
    1463             :         /* swap the resources */
    1464           0 :         ures_swapResource(ds, inBundle, outBundle, rootRes, NULL, &tempTable, pErrorCode);
    1465           0 :         if(U_FAILURE(*pErrorCode)) {
    1466             :             udata_printError(ds, "ures_swapResource(root res=%08x) failed\n",
    1467           0 :                              rootRes);
    1468             :         }
    1469             : 
    1470           0 :         if(tempTable.rows!=rows) {
    1471           0 :             uprv_free(tempTable.rows);
    1472             :         }
    1473           0 :         if(tempTable.resFlags!=stackResFlags) {
    1474           0 :             uprv_free(tempTable.resFlags);
    1475             :         }
    1476             : 
    1477             :         /* swap the root resource and indexes */
    1478           0 :         ds->swapArray32(ds, inBundle, keysBottom*4, outBundle, pErrorCode);
    1479             :     }
    1480             : 
    1481           0 :     return headerSize+4*top;
    1482             : }

Generated by: LCOV version 1.13