intl/icu/source/common/uresdata.c

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 * *
michael@0 4 * Copyright (C) 1999-2012, International Business Machines Corporation *
michael@0 5 * and others. All Rights Reserved. *
michael@0 6 * *
michael@0 7 *******************************************************************************
michael@0 8 * file name: uresdata.c
michael@0 9 * encoding: US-ASCII
michael@0 10 * tab size: 8 (not used)
michael@0 11 * indentation:4
michael@0 12 *
michael@0 13 * created on: 1999dec08
michael@0 14 * created by: Markus W. Scherer
michael@0 15 * Modification History:
michael@0 16 *
michael@0 17 * Date Name Description
michael@0 18 * 06/20/2000 helena OS/400 port changes; mostly typecast.
michael@0 19 * 06/24/02 weiv Added support for resource sharing
michael@0 20 */
michael@0 21
michael@0 22 #include "unicode/utypes.h"
michael@0 23 #include "unicode/udata.h"
michael@0 24 #include "unicode/ustring.h"
michael@0 25 #include "unicode/utf16.h"
michael@0 26 #include "cmemory.h"
michael@0 27 #include "cstring.h"
michael@0 28 #include "uarrsort.h"
michael@0 29 #include "udataswp.h"
michael@0 30 #include "ucol_swp.h"
michael@0 31 #include "uinvchar.h"
michael@0 32 #include "uresdata.h"
michael@0 33 #include "uresimp.h"
michael@0 34 #include "uassert.h"
michael@0 35
michael@0 36 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
michael@0 37
michael@0 38 /*
michael@0 39 * Resource access helpers
michael@0 40 */
michael@0 41
michael@0 42 /* get a const char* pointer to the key with the keyOffset byte offset from pRoot */
michael@0 43 #define RES_GET_KEY16(pResData, keyOffset) \
michael@0 44 ((keyOffset)<(pResData)->localKeyLimit ? \
michael@0 45 (const char *)(pResData)->pRoot+(keyOffset) : \
michael@0 46 (pResData)->poolBundleKeys+(keyOffset)-(pResData)->localKeyLimit)
michael@0 47
michael@0 48 #define RES_GET_KEY32(pResData, keyOffset) \
michael@0 49 ((keyOffset)>=0 ? \
michael@0 50 (const char *)(pResData)->pRoot+(keyOffset) : \
michael@0 51 (pResData)->poolBundleKeys+((keyOffset)&0x7fffffff))
michael@0 52
michael@0 53 #define URESDATA_ITEM_NOT_FOUND -1
michael@0 54
michael@0 55 /* empty resources, returned when the resource offset is 0 */
michael@0 56 static const uint16_t gEmpty16=0;
michael@0 57
michael@0 58 static const struct {
michael@0 59 int32_t length;
michael@0 60 int32_t res;
michael@0 61 } gEmpty32={ 0, 0 };
michael@0 62
michael@0 63 static const struct {
michael@0 64 int32_t length;
michael@0 65 UChar nul;
michael@0 66 UChar pad;
michael@0 67 } gEmptyString={ 0, 0, 0 };
michael@0 68
michael@0 69 /*
michael@0 70 * All the type-access functions assume that
michael@0 71 * the resource is of the expected type.
michael@0 72 */
michael@0 73
michael@0 74 static int32_t
michael@0 75 _res_findTableItem(const ResourceData *pResData, const uint16_t *keyOffsets, int32_t length,
michael@0 76 const char *key, const char **realKey) {
michael@0 77 const char *tableKey;
michael@0 78 int32_t mid, start, limit;
michael@0 79 int result;
michael@0 80
michael@0 81 /* do a binary search for the key */
michael@0 82 start=0;
michael@0 83 limit=length;
michael@0 84 while(start<limit) {
michael@0 85 mid = (start + limit) / 2;
michael@0 86 tableKey = RES_GET_KEY16(pResData, keyOffsets[mid]);
michael@0 87 if (pResData->useNativeStrcmp) {
michael@0 88 result = uprv_strcmp(key, tableKey);
michael@0 89 } else {
michael@0 90 result = uprv_compareInvCharsAsAscii(key, tableKey);
michael@0 91 }
michael@0 92 if (result < 0) {
michael@0 93 limit = mid;
michael@0 94 } else if (result > 0) {
michael@0 95 start = mid + 1;
michael@0 96 } else {
michael@0 97 /* We found it! */
michael@0 98 *realKey=tableKey;
michael@0 99 return mid;
michael@0 100 }
michael@0 101 }
michael@0 102 return URESDATA_ITEM_NOT_FOUND; /* not found or table is empty. */
michael@0 103 }
michael@0 104
michael@0 105 static int32_t
michael@0 106 _res_findTable32Item(const ResourceData *pResData, const int32_t *keyOffsets, int32_t length,
michael@0 107 const char *key, const char **realKey) {
michael@0 108 const char *tableKey;
michael@0 109 int32_t mid, start, limit;
michael@0 110 int result;
michael@0 111
michael@0 112 /* do a binary search for the key */
michael@0 113 start=0;
michael@0 114 limit=length;
michael@0 115 while(start<limit) {
michael@0 116 mid = (start + limit) / 2;
michael@0 117 tableKey = RES_GET_KEY32(pResData, keyOffsets[mid]);
michael@0 118 if (pResData->useNativeStrcmp) {
michael@0 119 result = uprv_strcmp(key, tableKey);
michael@0 120 } else {
michael@0 121 result = uprv_compareInvCharsAsAscii(key, tableKey);
michael@0 122 }
michael@0 123 if (result < 0) {
michael@0 124 limit = mid;
michael@0 125 } else if (result > 0) {
michael@0 126 start = mid + 1;
michael@0 127 } else {
michael@0 128 /* We found it! */
michael@0 129 *realKey=tableKey;
michael@0 130 return mid;
michael@0 131 }
michael@0 132 }
michael@0 133 return URESDATA_ITEM_NOT_FOUND; /* not found or table is empty. */
michael@0 134 }
michael@0 135
michael@0 136 /* helper for res_load() ---------------------------------------------------- */
michael@0 137
michael@0 138 static UBool U_CALLCONV
michael@0 139 isAcceptable(void *context,
michael@0 140 const char *type, const char *name,
michael@0 141 const UDataInfo *pInfo) {
michael@0 142 uprv_memcpy(context, pInfo->formatVersion, 4);
michael@0 143 return (UBool)(
michael@0 144 pInfo->size>=20 &&
michael@0 145 pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
michael@0 146 pInfo->charsetFamily==U_CHARSET_FAMILY &&
michael@0 147 pInfo->sizeofUChar==U_SIZEOF_UCHAR &&
michael@0 148 pInfo->dataFormat[0]==0x52 && /* dataFormat="ResB" */
michael@0 149 pInfo->dataFormat[1]==0x65 &&
michael@0 150 pInfo->dataFormat[2]==0x73 &&
michael@0 151 pInfo->dataFormat[3]==0x42 &&
michael@0 152 (pInfo->formatVersion[0]==1 || pInfo->formatVersion[0]==2));
michael@0 153 }
michael@0 154
michael@0 155 /* semi-public functions ---------------------------------------------------- */
michael@0 156
michael@0 157 static void
michael@0 158 res_init(ResourceData *pResData,
michael@0 159 UVersionInfo formatVersion, const void *inBytes, int32_t length,
michael@0 160 UErrorCode *errorCode) {
michael@0 161 UResType rootType;
michael@0 162
michael@0 163 /* get the root resource */
michael@0 164 pResData->pRoot=(const int32_t *)inBytes;
michael@0 165 pResData->rootRes=(Resource)*pResData->pRoot;
michael@0 166 pResData->p16BitUnits=&gEmpty16;
michael@0 167
michael@0 168 /* formatVersion 1.1 must have a root item and at least 5 indexes */
michael@0 169 if(length>=0 && (length/4)<((formatVersion[0]==1 && formatVersion[1]==0) ? 1 : 1+5)) {
michael@0 170 *errorCode=U_INVALID_FORMAT_ERROR;
michael@0 171 res_unload(pResData);
michael@0 172 return;
michael@0 173 }
michael@0 174
michael@0 175 /* currently, we accept only resources that have a Table as their roots */
michael@0 176 rootType=(UResType)RES_GET_TYPE(pResData->rootRes);
michael@0 177 if(!URES_IS_TABLE(rootType)) {
michael@0 178 *errorCode=U_INVALID_FORMAT_ERROR;
michael@0 179 res_unload(pResData);
michael@0 180 return;
michael@0 181 }
michael@0 182
michael@0 183 if(formatVersion[0]==1 && formatVersion[1]==0) {
michael@0 184 pResData->localKeyLimit=0x10000; /* greater than any 16-bit key string offset */
michael@0 185 } else {
michael@0 186 /* bundles with formatVersion 1.1 and later contain an indexes[] array */
michael@0 187 const int32_t *indexes=pResData->pRoot+1;
michael@0 188 int32_t indexLength=indexes[URES_INDEX_LENGTH]&0xff;
michael@0 189 if(indexLength<=URES_INDEX_MAX_TABLE_LENGTH) {
michael@0 190 *errorCode=U_INVALID_FORMAT_ERROR;
michael@0 191 res_unload(pResData);
michael@0 192 return;
michael@0 193 }
michael@0 194 if( length>=0 &&
michael@0 195 (length<((1+indexLength)<<2) ||
michael@0 196 length<(indexes[URES_INDEX_BUNDLE_TOP]<<2))
michael@0 197 ) {
michael@0 198 *errorCode=U_INVALID_FORMAT_ERROR;
michael@0 199 res_unload(pResData);
michael@0 200 return;
michael@0 201 }
michael@0 202 if(indexes[URES_INDEX_KEYS_TOP]>(1+indexLength)) {
michael@0 203 pResData->localKeyLimit=indexes[URES_INDEX_KEYS_TOP]<<2;
michael@0 204 }
michael@0 205 if(indexLength>URES_INDEX_ATTRIBUTES) {
michael@0 206 int32_t att=indexes[URES_INDEX_ATTRIBUTES];
michael@0 207 pResData->noFallback=(UBool)(att&URES_ATT_NO_FALLBACK);
michael@0 208 pResData->isPoolBundle=(UBool)((att&URES_ATT_IS_POOL_BUNDLE)!=0);
michael@0 209 pResData->usesPoolBundle=(UBool)((att&URES_ATT_USES_POOL_BUNDLE)!=0);
michael@0 210 }
michael@0 211 if((pResData->isPoolBundle || pResData->usesPoolBundle) && indexLength<=URES_INDEX_POOL_CHECKSUM) {
michael@0 212 *errorCode=U_INVALID_FORMAT_ERROR;
michael@0 213 res_unload(pResData);
michael@0 214 return;
michael@0 215 }
michael@0 216 if( indexLength>URES_INDEX_16BIT_TOP &&
michael@0 217 indexes[URES_INDEX_16BIT_TOP]>indexes[URES_INDEX_KEYS_TOP]
michael@0 218 ) {
michael@0 219 pResData->p16BitUnits=(const uint16_t *)(pResData->pRoot+indexes[URES_INDEX_KEYS_TOP]);
michael@0 220 }
michael@0 221 }
michael@0 222
michael@0 223 if(formatVersion[0]==1 || U_CHARSET_FAMILY==U_ASCII_FAMILY) {
michael@0 224 /*
michael@0 225 * formatVersion 1: compare key strings in native-charset order
michael@0 226 * formatVersion 2 and up: compare key strings in ASCII order
michael@0 227 */
michael@0 228 pResData->useNativeStrcmp=TRUE;
michael@0 229 }
michael@0 230 }
michael@0 231
michael@0 232 U_CAPI void U_EXPORT2
michael@0 233 res_read(ResourceData *pResData,
michael@0 234 const UDataInfo *pInfo, const void *inBytes, int32_t length,
michael@0 235 UErrorCode *errorCode) {
michael@0 236 UVersionInfo formatVersion;
michael@0 237
michael@0 238 uprv_memset(pResData, 0, sizeof(ResourceData));
michael@0 239 if(U_FAILURE(*errorCode)) {
michael@0 240 return;
michael@0 241 }
michael@0 242 if(!isAcceptable(formatVersion, NULL, NULL, pInfo)) {
michael@0 243 *errorCode=U_INVALID_FORMAT_ERROR;
michael@0 244 return;
michael@0 245 }
michael@0 246 res_init(pResData, formatVersion, inBytes, length, errorCode);
michael@0 247 }
michael@0 248
michael@0 249 U_CFUNC void
michael@0 250 res_load(ResourceData *pResData,
michael@0 251 const char *path, const char *name, UErrorCode *errorCode) {
michael@0 252 UVersionInfo formatVersion;
michael@0 253
michael@0 254 uprv_memset(pResData, 0, sizeof(ResourceData));
michael@0 255
michael@0 256 /* load the ResourceBundle file */
michael@0 257 pResData->data=udata_openChoice(path, "res", name, isAcceptable, formatVersion, errorCode);
michael@0 258 if(U_FAILURE(*errorCode)) {
michael@0 259 return;
michael@0 260 }
michael@0 261
michael@0 262 /* get its memory and initialize *pResData */
michael@0 263 res_init(pResData, formatVersion, udata_getMemory(pResData->data), -1, errorCode);
michael@0 264 }
michael@0 265
michael@0 266 U_CFUNC void
michael@0 267 res_unload(ResourceData *pResData) {
michael@0 268 if(pResData->data!=NULL) {
michael@0 269 udata_close(pResData->data);
michael@0 270 pResData->data=NULL;
michael@0 271 }
michael@0 272 }
michael@0 273
michael@0 274 static const int8_t gPublicTypes[URES_LIMIT] = {
michael@0 275 URES_STRING,
michael@0 276 URES_BINARY,
michael@0 277 URES_TABLE,
michael@0 278 URES_ALIAS,
michael@0 279
michael@0 280 URES_TABLE, /* URES_TABLE32 */
michael@0 281 URES_TABLE, /* URES_TABLE16 */
michael@0 282 URES_STRING, /* URES_STRING_V2 */
michael@0 283 URES_INT,
michael@0 284
michael@0 285 URES_ARRAY,
michael@0 286 URES_ARRAY, /* URES_ARRAY16 */
michael@0 287 URES_NONE,
michael@0 288 URES_NONE,
michael@0 289
michael@0 290 URES_NONE,
michael@0 291 URES_NONE,
michael@0 292 URES_INT_VECTOR,
michael@0 293 URES_NONE
michael@0 294 };
michael@0 295
michael@0 296 U_CAPI UResType U_EXPORT2
michael@0 297 res_getPublicType(Resource res) {
michael@0 298 return (UResType)gPublicTypes[RES_GET_TYPE(res)];
michael@0 299 }
michael@0 300
michael@0 301 U_CAPI const UChar * U_EXPORT2
michael@0 302 res_getString(const ResourceData *pResData, Resource res, int32_t *pLength) {
michael@0 303 const UChar *p;
michael@0 304 uint32_t offset=RES_GET_OFFSET(res);
michael@0 305 int32_t length;
michael@0 306 if(RES_GET_TYPE(res)==URES_STRING_V2) {
michael@0 307 int32_t first;
michael@0 308 p=(const UChar *)(pResData->p16BitUnits+offset);
michael@0 309 first=*p;
michael@0 310 if(!U16_IS_TRAIL(first)) {
michael@0 311 length=u_strlen(p);
michael@0 312 } else if(first<0xdfef) {
michael@0 313 length=first&0x3ff;
michael@0 314 ++p;
michael@0 315 } else if(first<0xdfff) {
michael@0 316 length=((first-0xdfef)<<16)|p[1];
michael@0 317 p+=2;
michael@0 318 } else {
michael@0 319 length=((int32_t)p[1]<<16)|p[2];
michael@0 320 p+=3;
michael@0 321 }
michael@0 322 } else if(res==offset) /* RES_GET_TYPE(res)==URES_STRING */ {
michael@0 323 const int32_t *p32= res==0 ? &gEmptyString.length : pResData->pRoot+res;
michael@0 324 length=*p32++;
michael@0 325 p=(const UChar *)p32;
michael@0 326 } else {
michael@0 327 p=NULL;
michael@0 328 length=0;
michael@0 329 }
michael@0 330 if(pLength) {
michael@0 331 *pLength=length;
michael@0 332 }
michael@0 333 return p;
michael@0 334 }
michael@0 335
michael@0 336 U_CAPI const UChar * U_EXPORT2
michael@0 337 res_getAlias(const ResourceData *pResData, Resource res, int32_t *pLength) {
michael@0 338 const UChar *p;
michael@0 339 uint32_t offset=RES_GET_OFFSET(res);
michael@0 340 int32_t length;
michael@0 341 if(RES_GET_TYPE(res)==URES_ALIAS) {
michael@0 342 const int32_t *p32= offset==0 ? &gEmptyString.length : pResData->pRoot+offset;
michael@0 343 length=*p32++;
michael@0 344 p=(const UChar *)p32;
michael@0 345 } else {
michael@0 346 p=NULL;
michael@0 347 length=0;
michael@0 348 }
michael@0 349 if(pLength) {
michael@0 350 *pLength=length;
michael@0 351 }
michael@0 352 return p;
michael@0 353 }
michael@0 354
michael@0 355 U_CAPI const uint8_t * U_EXPORT2
michael@0 356 res_getBinary(const ResourceData *pResData, Resource res, int32_t *pLength) {
michael@0 357 const uint8_t *p;
michael@0 358 uint32_t offset=RES_GET_OFFSET(res);
michael@0 359 int32_t length;
michael@0 360 if(RES_GET_TYPE(res)==URES_BINARY) {
michael@0 361 const int32_t *p32= offset==0 ? (const int32_t*)&gEmpty32 : pResData->pRoot+offset;
michael@0 362 length=*p32++;
michael@0 363 p=(const uint8_t *)p32;
michael@0 364 } else {
michael@0 365 p=NULL;
michael@0 366 length=0;
michael@0 367 }
michael@0 368 if(pLength) {
michael@0 369 *pLength=length;
michael@0 370 }
michael@0 371 return p;
michael@0 372 }
michael@0 373
michael@0 374
michael@0 375 U_CAPI const int32_t * U_EXPORT2
michael@0 376 res_getIntVector(const ResourceData *pResData, Resource res, int32_t *pLength) {
michael@0 377 const int32_t *p;
michael@0 378 uint32_t offset=RES_GET_OFFSET(res);
michael@0 379 int32_t length;
michael@0 380 if(RES_GET_TYPE(res)==URES_INT_VECTOR) {
michael@0 381 p= offset==0 ? (const int32_t *)&gEmpty32 : pResData->pRoot+offset;
michael@0 382 length=*p++;
michael@0 383 } else {
michael@0 384 p=NULL;
michael@0 385 length=0;
michael@0 386 }
michael@0 387 if(pLength) {
michael@0 388 *pLength=length;
michael@0 389 }
michael@0 390 return p;
michael@0 391 }
michael@0 392
michael@0 393 U_CAPI int32_t U_EXPORT2
michael@0 394 res_countArrayItems(const ResourceData *pResData, Resource res) {
michael@0 395 uint32_t offset=RES_GET_OFFSET(res);
michael@0 396 switch(RES_GET_TYPE(res)) {
michael@0 397 case URES_STRING:
michael@0 398 case URES_STRING_V2:
michael@0 399 case URES_BINARY:
michael@0 400 case URES_ALIAS:
michael@0 401 case URES_INT:
michael@0 402 case URES_INT_VECTOR:
michael@0 403 return 1;
michael@0 404 case URES_ARRAY:
michael@0 405 case URES_TABLE32:
michael@0 406 return offset==0 ? 0 : *(pResData->pRoot+offset);
michael@0 407 case URES_TABLE:
michael@0 408 return offset==0 ? 0 : *((const uint16_t *)(pResData->pRoot+offset));
michael@0 409 case URES_ARRAY16:
michael@0 410 case URES_TABLE16:
michael@0 411 return pResData->p16BitUnits[offset];
michael@0 412 default:
michael@0 413 return 0;
michael@0 414 }
michael@0 415 }
michael@0 416
michael@0 417 U_CAPI Resource U_EXPORT2
michael@0 418 res_getTableItemByKey(const ResourceData *pResData, Resource table,
michael@0 419 int32_t *indexR, const char **key) {
michael@0 420 uint32_t offset=RES_GET_OFFSET(table);
michael@0 421 int32_t length;
michael@0 422 int32_t idx;
michael@0 423 if(key == NULL || *key == NULL) {
michael@0 424 return RES_BOGUS;
michael@0 425 }
michael@0 426 switch(RES_GET_TYPE(table)) {
michael@0 427 case URES_TABLE: {
michael@0 428 if (offset!=0) { /* empty if offset==0 */
michael@0 429 const uint16_t *p= (const uint16_t *)(pResData->pRoot+offset);
michael@0 430 length=*p++;
michael@0 431 *indexR=idx=_res_findTableItem(pResData, p, length, *key, key);
michael@0 432 if(idx>=0) {
michael@0 433 const Resource *p32=(const Resource *)(p+length+(~length&1));
michael@0 434 return p32[idx];
michael@0 435 }
michael@0 436 }
michael@0 437 break;
michael@0 438 }
michael@0 439 case URES_TABLE16: {
michael@0 440 const uint16_t *p=pResData->p16BitUnits+offset;
michael@0 441 length=*p++;
michael@0 442 *indexR=idx=_res_findTableItem(pResData, p, length, *key, key);
michael@0 443 if(idx>=0) {
michael@0 444 return URES_MAKE_RESOURCE(URES_STRING_V2, p[length+idx]);
michael@0 445 }
michael@0 446 break;
michael@0 447 }
michael@0 448 case URES_TABLE32: {
michael@0 449 if (offset!=0) { /* empty if offset==0 */
michael@0 450 const int32_t *p= pResData->pRoot+offset;
michael@0 451 length=*p++;
michael@0 452 *indexR=idx=_res_findTable32Item(pResData, p, length, *key, key);
michael@0 453 if(idx>=0) {
michael@0 454 return (Resource)p[length+idx];
michael@0 455 }
michael@0 456 }
michael@0 457 break;
michael@0 458 }
michael@0 459 default:
michael@0 460 break;
michael@0 461 }
michael@0 462 return RES_BOGUS;
michael@0 463 }
michael@0 464
michael@0 465 U_CAPI Resource U_EXPORT2
michael@0 466 res_getTableItemByIndex(const ResourceData *pResData, Resource table,
michael@0 467 int32_t indexR, const char **key) {
michael@0 468 uint32_t offset=RES_GET_OFFSET(table);
michael@0 469 int32_t length;
michael@0 470 U_ASSERT(indexR>=0); /* to ensure the index is not negative */
michael@0 471 switch(RES_GET_TYPE(table)) {
michael@0 472 case URES_TABLE: {
michael@0 473 if (offset != 0) { /* empty if offset==0 */
michael@0 474 const uint16_t *p= (const uint16_t *)(pResData->pRoot+offset);
michael@0 475 length=*p++;
michael@0 476 if(indexR<length) {
michael@0 477 const Resource *p32=(const Resource *)(p+length+(~length&1));
michael@0 478 if(key!=NULL) {
michael@0 479 *key=RES_GET_KEY16(pResData, p[indexR]);
michael@0 480 }
michael@0 481 return p32[indexR];
michael@0 482 }
michael@0 483 }
michael@0 484 break;
michael@0 485 }
michael@0 486 case URES_TABLE16: {
michael@0 487 const uint16_t *p=pResData->p16BitUnits+offset;
michael@0 488 length=*p++;
michael@0 489 if(indexR<length) {
michael@0 490 if(key!=NULL) {
michael@0 491 *key=RES_GET_KEY16(pResData, p[indexR]);
michael@0 492 }
michael@0 493 return URES_MAKE_RESOURCE(URES_STRING_V2, p[length+indexR]);
michael@0 494 }
michael@0 495 break;
michael@0 496 }
michael@0 497 case URES_TABLE32: {
michael@0 498 if (offset != 0) { /* empty if offset==0 */
michael@0 499 const int32_t *p= pResData->pRoot+offset;
michael@0 500 length=*p++;
michael@0 501 if(indexR<length) {
michael@0 502 if(key!=NULL) {
michael@0 503 *key=RES_GET_KEY32(pResData, p[indexR]);
michael@0 504 }
michael@0 505 return (Resource)p[length+indexR];
michael@0 506 }
michael@0 507 }
michael@0 508 break;
michael@0 509 }
michael@0 510 default:
michael@0 511 break;
michael@0 512 }
michael@0 513 return RES_BOGUS;
michael@0 514 }
michael@0 515
michael@0 516 U_CAPI Resource U_EXPORT2
michael@0 517 res_getResource(const ResourceData *pResData, const char *key) {
michael@0 518 const char *realKey=key;
michael@0 519 int32_t idx;
michael@0 520 return res_getTableItemByKey(pResData, pResData->rootRes, &idx, &realKey);
michael@0 521 }
michael@0 522
michael@0 523 U_CAPI Resource U_EXPORT2
michael@0 524 res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
michael@0 525 uint32_t offset=RES_GET_OFFSET(array);
michael@0 526 U_ASSERT(indexR>=0); /* to ensure the index is not negative */
michael@0 527 switch(RES_GET_TYPE(array)) {
michael@0 528 case URES_ARRAY: {
michael@0 529 if (offset!=0) { /* empty if offset==0 */
michael@0 530 const int32_t *p= pResData->pRoot+offset;
michael@0 531 if(indexR<*p) {
michael@0 532 return (Resource)p[1+indexR];
michael@0 533 }
michael@0 534 }
michael@0 535 break;
michael@0 536 }
michael@0 537 case URES_ARRAY16: {
michael@0 538 const uint16_t *p=pResData->p16BitUnits+offset;
michael@0 539 if(indexR<*p) {
michael@0 540 return URES_MAKE_RESOURCE(URES_STRING_V2, p[1+indexR]);
michael@0 541 }
michael@0 542 break;
michael@0 543 }
michael@0 544 default:
michael@0 545 break;
michael@0 546 }
michael@0 547 return RES_BOGUS;
michael@0 548 }
michael@0 549
michael@0 550 U_CFUNC Resource
michael@0 551 res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key) {
michael@0 552 /* we pass in a path. CollationElements/Sequence or zoneStrings/3/2 etc.
michael@0 553 * iterates over a path and stops when a scalar resource is found. This
michael@0 554 * CAN be an alias. Path gets set to the part that has not yet been processed.
michael@0 555 */
michael@0 556
michael@0 557 char *pathP = *path, *nextSepP = *path;
michael@0 558 char *closeIndex = NULL;
michael@0 559 Resource t1 = r;
michael@0 560 Resource t2;
michael@0 561 int32_t indexR = 0;
michael@0 562 UResType type = (UResType)RES_GET_TYPE(t1);
michael@0 563
michael@0 564 /* if you come in with an empty path, you'll be getting back the same resource */
michael@0 565 if(!uprv_strlen(pathP)) {
michael@0 566 return r;
michael@0 567 }
michael@0 568
michael@0 569 /* one needs to have an aggregate resource in order to search in it */
michael@0 570 if(!URES_IS_CONTAINER(type)) {
michael@0 571 return RES_BOGUS;
michael@0 572 }
michael@0 573
michael@0 574 while(nextSepP && *pathP && t1 != RES_BOGUS && URES_IS_CONTAINER(type)) {
michael@0 575 /* Iteration stops if: the path has been consumed, we found a non-existing
michael@0 576 * resource (t1 == RES_BOGUS) or we found a scalar resource (including alias)
michael@0 577 */
michael@0 578 nextSepP = uprv_strchr(pathP, RES_PATH_SEPARATOR);
michael@0 579 /* if there are more separators, terminate string
michael@0 580 * and set path to the remaining part of the string
michael@0 581 */
michael@0 582 if(nextSepP != NULL) {
michael@0 583 *nextSepP = 0; /* overwrite the separator with a NUL to terminate the key */
michael@0 584 *path = nextSepP+1;
michael@0 585 } else {
michael@0 586 *path = uprv_strchr(pathP, 0);
michael@0 587 }
michael@0 588
michael@0 589 /* if the resource is a table */
michael@0 590 /* try the key based access */
michael@0 591 if(URES_IS_TABLE(type)) {
michael@0 592 *key = pathP;
michael@0 593 t2 = res_getTableItemByKey(pResData, t1, &indexR, key);
michael@0 594 if(t2 == RES_BOGUS) {
michael@0 595 /* if we fail to get the resource by key, maybe we got an index */
michael@0 596 indexR = uprv_strtol(pathP, &closeIndex, 10);
michael@0 597 if(closeIndex != pathP) {
michael@0 598 /* if we indeed have an index, try to get the item by index */
michael@0 599 t2 = res_getTableItemByIndex(pResData, t1, indexR, key);
michael@0 600 }
michael@0 601 }
michael@0 602 } else if(URES_IS_ARRAY(type)) {
michael@0 603 indexR = uprv_strtol(pathP, &closeIndex, 10);
michael@0 604 if(closeIndex != pathP) {
michael@0 605 t2 = res_getArrayItem(pResData, t1, indexR);
michael@0 606 } else {
michael@0 607 t2 = RES_BOGUS; /* have an array, but don't have a valid index */
michael@0 608 }
michael@0 609 *key = NULL;
michael@0 610 } else { /* can't do much here, except setting t2 to bogus */
michael@0 611 t2 = RES_BOGUS;
michael@0 612 }
michael@0 613 t1 = t2;
michael@0 614 type = (UResType)RES_GET_TYPE(t1);
michael@0 615 /* position pathP to next resource key/index */
michael@0 616 pathP = *path;
michael@0 617 }
michael@0 618
michael@0 619 return t1;
michael@0 620 }
michael@0 621
michael@0 622 /* resource bundle swapping ------------------------------------------------- */
michael@0 623
michael@0 624 /*
michael@0 625 * Need to always enumerate the entire item tree,
michael@0 626 * track the lowest address of any item to use as the limit for char keys[],
michael@0 627 * track the highest address of any item to return the size of the data.
michael@0 628 *
michael@0 629 * We should have thought of storing those in the data...
michael@0 630 * It is possible to extend the data structure by putting additional values
michael@0 631 * in places that are inaccessible by ordinary enumeration of the item tree.
michael@0 632 * For example, additional integers could be stored at the beginning or
michael@0 633 * end of the key strings; this could be indicated by a minor version number,
michael@0 634 * and the data swapping would have to know about these values.
michael@0 635 *
michael@0 636 * The data structure does not forbid keys to be shared, so we must swap
michael@0 637 * all keys once instead of each key when it is referenced.
michael@0 638 *
michael@0 639 * These swapping functions assume that a resource bundle always has a length
michael@0 640 * that is a multiple of 4 bytes.
michael@0 641 * Currently, this is trivially true because genrb writes bundle tree leaves
michael@0 642 * physically first, before their branches, so that the root table with its
michael@0 643 * array of resource items (uint32_t values) is always last.
michael@0 644 */
michael@0 645
michael@0 646 /* definitions for table sorting ------------------------ */
michael@0 647
michael@0 648 /*
michael@0 649 * row of a temporary array
michael@0 650 *
michael@0 651 * gets platform-endian key string indexes and sorting indexes;
michael@0 652 * after sorting this array by keys, the actual key/value arrays are permutated
michael@0 653 * according to the sorting indexes
michael@0 654 */
michael@0 655 typedef struct Row {
michael@0 656 int32_t keyIndex, sortIndex;
michael@0 657 } Row;
michael@0 658
michael@0 659 static int32_t
michael@0 660 ures_compareRows(const void *context, const void *left, const void *right) {
michael@0 661 const char *keyChars=(const char *)context;
michael@0 662 return (int32_t)uprv_strcmp(keyChars+((const Row *)left)->keyIndex,
michael@0 663 keyChars+((const Row *)right)->keyIndex);
michael@0 664 }
michael@0 665
michael@0 666 typedef struct TempTable {
michael@0 667 const char *keyChars;
michael@0 668 Row *rows;
michael@0 669 int32_t *resort;
michael@0 670 uint32_t *resFlags;
michael@0 671 int32_t localKeyLimit;
michael@0 672 uint8_t majorFormatVersion;
michael@0 673 } TempTable;
michael@0 674
michael@0 675 enum {
michael@0 676 STACK_ROW_CAPACITY=200
michael@0 677 };
michael@0 678
michael@0 679 /* The table item key string is not locally available. */
michael@0 680 static const char *const gUnknownKey="";
michael@0 681
michael@0 682 /* resource table key for collation binaries: "%%CollationBin" */
michael@0 683 static const UChar gCollationBinKey[]={
michael@0 684 0x25, 0x25,
michael@0 685 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
michael@0 686 0x42, 0x69, 0x6e,
michael@0 687 0
michael@0 688 };
michael@0 689
michael@0 690 /*
michael@0 691 * swap one resource item
michael@0 692 */
michael@0 693 static void
michael@0 694 ures_swapResource(const UDataSwapper *ds,
michael@0 695 const Resource *inBundle, Resource *outBundle,
michael@0 696 Resource res, /* caller swaps res itself */
michael@0 697 const char *key,
michael@0 698 TempTable *pTempTable,
michael@0 699 UErrorCode *pErrorCode) {
michael@0 700 const Resource *p;
michael@0 701 Resource *q;
michael@0 702 int32_t offset, count;
michael@0 703
michael@0 704 switch(RES_GET_TYPE(res)) {
michael@0 705 case URES_TABLE16:
michael@0 706 case URES_STRING_V2:
michael@0 707 case URES_INT:
michael@0 708 case URES_ARRAY16:
michael@0 709 /* integer, or points to 16-bit units, nothing to do here */
michael@0 710 return;
michael@0 711 default:
michael@0 712 break;
michael@0 713 }
michael@0 714
michael@0 715 /* all other types use an offset to point to their data */
michael@0 716 offset=(int32_t)RES_GET_OFFSET(res);
michael@0 717 if(offset==0) {
michael@0 718 /* special offset indicating an empty item */
michael@0 719 return;
michael@0 720 }
michael@0 721 if(pTempTable->resFlags[offset>>5]&((uint32_t)1<<(offset&0x1f))) {
michael@0 722 /* we already swapped this resource item */
michael@0 723 return;
michael@0 724 } else {
michael@0 725 /* mark it as swapped now */
michael@0 726 pTempTable->resFlags[offset>>5]|=((uint32_t)1<<(offset&0x1f));
michael@0 727 }
michael@0 728
michael@0 729 p=inBundle+offset;
michael@0 730 q=outBundle+offset;
michael@0 731
michael@0 732 switch(RES_GET_TYPE(res)) {
michael@0 733 case URES_ALIAS:
michael@0 734 /* physically same value layout as string, fall through */
michael@0 735 case URES_STRING:
michael@0 736 count=udata_readInt32(ds, (int32_t)*p);
michael@0 737 /* swap length */
michael@0 738 ds->swapArray32(ds, p, 4, q, pErrorCode);
michael@0 739 /* swap each UChar (the terminating NUL would not change) */
michael@0 740 ds->swapArray16(ds, p+1, 2*count, q+1, pErrorCode);
michael@0 741 break;
michael@0 742 case URES_BINARY:
michael@0 743 count=udata_readInt32(ds, (int32_t)*p);
michael@0 744 /* swap length */
michael@0 745 ds->swapArray32(ds, p, 4, q, pErrorCode);
michael@0 746 /* no need to swap or copy bytes - ures_swap() copied them all */
michael@0 747
michael@0 748 /* swap known formats */
michael@0 749 #if !UCONFIG_NO_COLLATION
michael@0 750 if( key!=NULL && /* the binary is in a table */
michael@0 751 (key!=gUnknownKey ?
michael@0 752 /* its table key string is "%%CollationBin" */
michael@0 753 0==ds->compareInvChars(ds, key, -1,
michael@0 754 gCollationBinKey, LENGTHOF(gCollationBinKey)-1) :
michael@0 755 /* its table key string is unknown but it looks like a collation binary */
michael@0 756 ucol_looksLikeCollationBinary(ds, p+1, count))
michael@0 757 ) {
michael@0 758 ucol_swapBinary(ds, p+1, count, q+1, pErrorCode);
michael@0 759 }
michael@0 760 #endif
michael@0 761 break;
michael@0 762 case URES_TABLE:
michael@0 763 case URES_TABLE32:
michael@0 764 {
michael@0 765 const uint16_t *pKey16;
michael@0 766 uint16_t *qKey16;
michael@0 767
michael@0 768 const int32_t *pKey32;
michael@0 769 int32_t *qKey32;
michael@0 770
michael@0 771 Resource item;
michael@0 772 int32_t i, oldIndex;
michael@0 773
michael@0 774 if(RES_GET_TYPE(res)==URES_TABLE) {
michael@0 775 /* get table item count */
michael@0 776 pKey16=(const uint16_t *)p;
michael@0 777 qKey16=(uint16_t *)q;
michael@0 778 count=ds->readUInt16(*pKey16);
michael@0 779
michael@0 780 pKey32=qKey32=NULL;
michael@0 781
michael@0 782 /* swap count */
michael@0 783 ds->swapArray16(ds, pKey16++, 2, qKey16++, pErrorCode);
michael@0 784
michael@0 785 offset+=((1+count)+1)/2;
michael@0 786 } else {
michael@0 787 /* get table item count */
michael@0 788 pKey32=(const int32_t *)p;
michael@0 789 qKey32=(int32_t *)q;
michael@0 790 count=udata_readInt32(ds, *pKey32);
michael@0 791
michael@0 792 pKey16=qKey16=NULL;
michael@0 793
michael@0 794 /* swap count */
michael@0 795 ds->swapArray32(ds, pKey32++, 4, qKey32++, pErrorCode);
michael@0 796
michael@0 797 offset+=1+count;
michael@0 798 }
michael@0 799
michael@0 800 if(count==0) {
michael@0 801 break;
michael@0 802 }
michael@0 803
michael@0 804 p=inBundle+offset; /* pointer to table resources */
michael@0 805 q=outBundle+offset;
michael@0 806
michael@0 807 /* recurse */
michael@0 808 for(i=0; i<count; ++i) {
michael@0 809 const char *itemKey=gUnknownKey;
michael@0 810 if(pKey16!=NULL) {
michael@0 811 int32_t keyOffset=ds->readUInt16(pKey16[i]);
michael@0 812 if(keyOffset<pTempTable->localKeyLimit) {
michael@0 813 itemKey=(const char *)outBundle+keyOffset;
michael@0 814 }
michael@0 815 } else {
michael@0 816 int32_t keyOffset=udata_readInt32(ds, pKey32[i]);
michael@0 817 if(keyOffset>=0) {
michael@0 818 itemKey=(const char *)outBundle+keyOffset;
michael@0 819 }
michael@0 820 }
michael@0 821 item=ds->readUInt32(p[i]);
michael@0 822 ures_swapResource(ds, inBundle, outBundle, item, itemKey, pTempTable, pErrorCode);
michael@0 823 if(U_FAILURE(*pErrorCode)) {
michael@0 824 udata_printError(ds, "ures_swapResource(table res=%08x)[%d].recurse(%08x) failed\n",
michael@0 825 res, i, item);
michael@0 826 return;
michael@0 827 }
michael@0 828 }
michael@0 829
michael@0 830 if(pTempTable->majorFormatVersion>1 || ds->inCharset==ds->outCharset) {
michael@0 831 /* no need to sort, just swap the offset/value arrays */
michael@0 832 if(pKey16!=NULL) {
michael@0 833 ds->swapArray16(ds, pKey16, count*2, qKey16, pErrorCode);
michael@0 834 ds->swapArray32(ds, p, count*4, q, pErrorCode);
michael@0 835 } else {
michael@0 836 /* swap key offsets and items as one array */
michael@0 837 ds->swapArray32(ds, pKey32, count*2*4, qKey32, pErrorCode);
michael@0 838 }
michael@0 839 break;
michael@0 840 }
michael@0 841
michael@0 842 /*
michael@0 843 * We need to sort tables by outCharset key strings because they
michael@0 844 * sort differently for different charset families.
michael@0 845 * ures_swap() already set pTempTable->keyChars appropriately.
michael@0 846 * First we set up a temporary table with the key indexes and
michael@0 847 * sorting indexes and sort that.
michael@0 848 * Then we permutate and copy/swap the actual values.
michael@0 849 */
michael@0 850 if(pKey16!=NULL) {
michael@0 851 for(i=0; i<count; ++i) {
michael@0 852 pTempTable->rows[i].keyIndex=ds->readUInt16(pKey16[i]);
michael@0 853 pTempTable->rows[i].sortIndex=i;
michael@0 854 }
michael@0 855 } else {
michael@0 856 for(i=0; i<count; ++i) {
michael@0 857 pTempTable->rows[i].keyIndex=udata_readInt32(ds, pKey32[i]);
michael@0 858 pTempTable->rows[i].sortIndex=i;
michael@0 859 }
michael@0 860 }
michael@0 861 uprv_sortArray(pTempTable->rows, count, sizeof(Row),
michael@0 862 ures_compareRows, pTempTable->keyChars,
michael@0 863 FALSE, pErrorCode);
michael@0 864 if(U_FAILURE(*pErrorCode)) {
michael@0 865 udata_printError(ds, "ures_swapResource(table res=%08x).uprv_sortArray(%d items) failed\n",
michael@0 866 res, count);
michael@0 867 return;
michael@0 868 }
michael@0 869
michael@0 870 /*
michael@0 871 * copy/swap/permutate items
michael@0 872 *
michael@0 873 * If we swap in-place, then the permutation must use another
michael@0 874 * temporary array (pTempTable->resort)
michael@0 875 * before the results are copied to the outBundle.
michael@0 876 */
michael@0 877 /* keys */
michael@0 878 if(pKey16!=NULL) {
michael@0 879 uint16_t *rKey16;
michael@0 880
michael@0 881 if(pKey16!=qKey16) {
michael@0 882 rKey16=qKey16;
michael@0 883 } else {
michael@0 884 rKey16=(uint16_t *)pTempTable->resort;
michael@0 885 }
michael@0 886 for(i=0; i<count; ++i) {
michael@0 887 oldIndex=pTempTable->rows[i].sortIndex;
michael@0 888 ds->swapArray16(ds, pKey16+oldIndex, 2, rKey16+i, pErrorCode);
michael@0 889 }
michael@0 890 if(qKey16!=rKey16) {
michael@0 891 uprv_memcpy(qKey16, rKey16, 2*count);
michael@0 892 }
michael@0 893 } else {
michael@0 894 int32_t *rKey32;
michael@0 895
michael@0 896 if(pKey32!=qKey32) {
michael@0 897 rKey32=qKey32;
michael@0 898 } else {
michael@0 899 rKey32=pTempTable->resort;
michael@0 900 }
michael@0 901 for(i=0; i<count; ++i) {
michael@0 902 oldIndex=pTempTable->rows[i].sortIndex;
michael@0 903 ds->swapArray32(ds, pKey32+oldIndex, 4, rKey32+i, pErrorCode);
michael@0 904 }
michael@0 905 if(qKey32!=rKey32) {
michael@0 906 uprv_memcpy(qKey32, rKey32, 4*count);
michael@0 907 }
michael@0 908 }
michael@0 909
michael@0 910 /* resources */
michael@0 911 {
michael@0 912 Resource *r;
michael@0 913
michael@0 914
michael@0 915 if(p!=q) {
michael@0 916 r=q;
michael@0 917 } else {
michael@0 918 r=(Resource *)pTempTable->resort;
michael@0 919 }
michael@0 920 for(i=0; i<count; ++i) {
michael@0 921 oldIndex=pTempTable->rows[i].sortIndex;
michael@0 922 ds->swapArray32(ds, p+oldIndex, 4, r+i, pErrorCode);
michael@0 923 }
michael@0 924 if(q!=r) {
michael@0 925 uprv_memcpy(q, r, 4*count);
michael@0 926 }
michael@0 927 }
michael@0 928 }
michael@0 929 break;
michael@0 930 case URES_ARRAY:
michael@0 931 {
michael@0 932 Resource item;
michael@0 933 int32_t i;
michael@0 934
michael@0 935 count=udata_readInt32(ds, (int32_t)*p);
michael@0 936 /* swap length */
michael@0 937 ds->swapArray32(ds, p++, 4, q++, pErrorCode);
michael@0 938
michael@0 939 /* recurse */
michael@0 940 for(i=0; i<count; ++i) {
michael@0 941 item=ds->readUInt32(p[i]);
michael@0 942 ures_swapResource(ds, inBundle, outBundle, item, NULL, pTempTable, pErrorCode);
michael@0 943 if(U_FAILURE(*pErrorCode)) {
michael@0 944 udata_printError(ds, "ures_swapResource(array res=%08x)[%d].recurse(%08x) failed\n",
michael@0 945 res, i, item);
michael@0 946 return;
michael@0 947 }
michael@0 948 }
michael@0 949
michael@0 950 /* swap items */
michael@0 951 ds->swapArray32(ds, p, 4*count, q, pErrorCode);
michael@0 952 }
michael@0 953 break;
michael@0 954 case URES_INT_VECTOR:
michael@0 955 count=udata_readInt32(ds, (int32_t)*p);
michael@0 956 /* swap length and each integer */
michael@0 957 ds->swapArray32(ds, p, 4*(1+count), q, pErrorCode);
michael@0 958 break;
michael@0 959 default:
michael@0 960 /* also catches RES_BOGUS */
michael@0 961 *pErrorCode=U_UNSUPPORTED_ERROR;
michael@0 962 break;
michael@0 963 }
michael@0 964 }
michael@0 965
michael@0 966 U_CAPI int32_t U_EXPORT2
michael@0 967 ures_swap(const UDataSwapper *ds,
michael@0 968 const void *inData, int32_t length, void *outData,
michael@0 969 UErrorCode *pErrorCode) {
michael@0 970 const UDataInfo *pInfo;
michael@0 971 const Resource *inBundle;
michael@0 972 Resource rootRes;
michael@0 973 int32_t headerSize, maxTableLength;
michael@0 974
michael@0 975 Row rows[STACK_ROW_CAPACITY];
michael@0 976 int32_t resort[STACK_ROW_CAPACITY];
michael@0 977 TempTable tempTable;
michael@0 978
michael@0 979 const int32_t *inIndexes;
michael@0 980
michael@0 981 /* the following integers count Resource item offsets (4 bytes each), not bytes */
michael@0 982 int32_t bundleLength, indexLength, keysBottom, keysTop, resBottom, top;
michael@0 983
michael@0 984 /* udata_swapDataHeader checks the arguments */
michael@0 985 headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
michael@0 986 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
michael@0 987 return 0;
michael@0 988 }
michael@0 989
michael@0 990 /* check data format and format version */
michael@0 991 pInfo=(const UDataInfo *)((const char *)inData+4);
michael@0 992 if(!(
michael@0 993 pInfo->dataFormat[0]==0x52 && /* dataFormat="ResB" */
michael@0 994 pInfo->dataFormat[1]==0x65 &&
michael@0 995 pInfo->dataFormat[2]==0x73 &&
michael@0 996 pInfo->dataFormat[3]==0x42 &&
michael@0 997 ((pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1) || /* formatVersion 1.1+ or 2.x */
michael@0 998 pInfo->formatVersion[0]==2)
michael@0 999 )) {
michael@0 1000 udata_printError(ds, "ures_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not a resource bundle\n",
michael@0 1001 pInfo->dataFormat[0], pInfo->dataFormat[1],
michael@0 1002 pInfo->dataFormat[2], pInfo->dataFormat[3],
michael@0 1003 pInfo->formatVersion[0], pInfo->formatVersion[1]);
michael@0 1004 *pErrorCode=U_UNSUPPORTED_ERROR;
michael@0 1005 return 0;
michael@0 1006 }
michael@0 1007 tempTable.majorFormatVersion=pInfo->formatVersion[0];
michael@0 1008
michael@0 1009 /* a resource bundle must contain at least one resource item */
michael@0 1010 if(length<0) {
michael@0 1011 bundleLength=-1;
michael@0 1012 } else {
michael@0 1013 bundleLength=(length-headerSize)/4;
michael@0 1014
michael@0 1015 /* formatVersion 1.1 must have a root item and at least 5 indexes */
michael@0 1016 if(bundleLength<(1+5)) {
michael@0 1017 udata_printError(ds, "ures_swap(): too few bytes (%d after header) for a resource bundle\n",
michael@0 1018 length-headerSize);
michael@0 1019 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
michael@0 1020 return 0;
michael@0 1021 }
michael@0 1022 }
michael@0 1023
michael@0 1024 inBundle=(const Resource *)((const char *)inData+headerSize);
michael@0 1025 rootRes=ds->readUInt32(*inBundle);
michael@0 1026
michael@0 1027 /* formatVersion 1.1 adds the indexes[] array */
michael@0 1028 inIndexes=(const int32_t *)(inBundle+1);
michael@0 1029
michael@0 1030 indexLength=udata_readInt32(ds, inIndexes[URES_INDEX_LENGTH])&0xff;
michael@0 1031 if(indexLength<=URES_INDEX_MAX_TABLE_LENGTH) {
michael@0 1032 udata_printError(ds, "ures_swap(): too few indexes for a 1.1+ resource bundle\n");
michael@0 1033 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
michael@0 1034 return 0;
michael@0 1035 }
michael@0 1036 keysBottom=1+indexLength;
michael@0 1037 keysTop=udata_readInt32(ds, inIndexes[URES_INDEX_KEYS_TOP]);
michael@0 1038 if(indexLength>URES_INDEX_16BIT_TOP) {
michael@0 1039 resBottom=udata_readInt32(ds, inIndexes[URES_INDEX_16BIT_TOP]);
michael@0 1040 } else {
michael@0 1041 resBottom=keysTop;
michael@0 1042 }
michael@0 1043 top=udata_readInt32(ds, inIndexes[URES_INDEX_BUNDLE_TOP]);
michael@0 1044 maxTableLength=udata_readInt32(ds, inIndexes[URES_INDEX_MAX_TABLE_LENGTH]);
michael@0 1045
michael@0 1046 if(0<=bundleLength && bundleLength<top) {
michael@0 1047 udata_printError(ds, "ures_swap(): resource top %d exceeds bundle length %d\n",
michael@0 1048 top, bundleLength);
michael@0 1049 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
michael@0 1050 return 0;
michael@0 1051 }
michael@0 1052 if(keysTop>(1+indexLength)) {
michael@0 1053 tempTable.localKeyLimit=keysTop<<2;
michael@0 1054 } else {
michael@0 1055 tempTable.localKeyLimit=0;
michael@0 1056 }
michael@0 1057
michael@0 1058 if(length>=0) {
michael@0 1059 Resource *outBundle=(Resource *)((char *)outData+headerSize);
michael@0 1060
michael@0 1061 /* track which resources we have already swapped */
michael@0 1062 uint32_t stackResFlags[STACK_ROW_CAPACITY];
michael@0 1063 int32_t resFlagsLength;
michael@0 1064
michael@0 1065 /*
michael@0 1066 * We need one bit per 4 resource bundle bytes so that we can track
michael@0 1067 * every possible Resource for whether we have swapped it already.
michael@0 1068 * Multiple Resource words can refer to the same bundle offsets
michael@0 1069 * for sharing identical values.
michael@0 1070 * We could optimize this by allocating only for locations above
michael@0 1071 * where Resource values are stored (above keys & strings).
michael@0 1072 */
michael@0 1073 resFlagsLength=(length+31)>>5; /* number of bytes needed */
michael@0 1074 resFlagsLength=(resFlagsLength+3)&~3; /* multiple of 4 bytes for uint32_t */
michael@0 1075 if(resFlagsLength<=sizeof(stackResFlags)) {
michael@0 1076 tempTable.resFlags=stackResFlags;
michael@0 1077 } else {
michael@0 1078 tempTable.resFlags=(uint32_t *)uprv_malloc(resFlagsLength);
michael@0 1079 if(tempTable.resFlags==NULL) {
michael@0 1080 udata_printError(ds, "ures_swap(): unable to allocate memory for tracking resources\n");
michael@0 1081 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
michael@0 1082 return 0;
michael@0 1083 }
michael@0 1084 }
michael@0 1085 uprv_memset(tempTable.resFlags, 0, resFlagsLength);
michael@0 1086
michael@0 1087 /* copy the bundle for binary and inaccessible data */
michael@0 1088 if(inData!=outData) {
michael@0 1089 uprv_memcpy(outBundle, inBundle, 4*top);
michael@0 1090 }
michael@0 1091
michael@0 1092 /* swap the key strings, but not the padding bytes (0xaa) after the last string and its NUL */
michael@0 1093 udata_swapInvStringBlock(ds, inBundle+keysBottom, 4*(keysTop-keysBottom),
michael@0 1094 outBundle+keysBottom, pErrorCode);
michael@0 1095 if(U_FAILURE(*pErrorCode)) {
michael@0 1096 udata_printError(ds, "ures_swap().udata_swapInvStringBlock(keys[%d]) failed\n", 4*(keysTop-keysBottom));
michael@0 1097 return 0;
michael@0 1098 }
michael@0 1099
michael@0 1100 /* swap the 16-bit units (strings, table16, array16) */
michael@0 1101 if(keysTop<resBottom) {
michael@0 1102 ds->swapArray16(ds, inBundle+keysTop, (resBottom-keysTop)*4, outBundle+keysTop, pErrorCode);
michael@0 1103 if(U_FAILURE(*pErrorCode)) {
michael@0 1104 udata_printError(ds, "ures_swap().swapArray16(16-bit units[%d]) failed\n", 2*(resBottom-keysTop));
michael@0 1105 return 0;
michael@0 1106 }
michael@0 1107 }
michael@0 1108
michael@0 1109 /* allocate the temporary table for sorting resource tables */
michael@0 1110 tempTable.keyChars=(const char *)outBundle; /* sort by outCharset */
michael@0 1111 if(tempTable.majorFormatVersion>1 || maxTableLength<=STACK_ROW_CAPACITY) {
michael@0 1112 tempTable.rows=rows;
michael@0 1113 tempTable.resort=resort;
michael@0 1114 } else {
michael@0 1115 tempTable.rows=(Row *)uprv_malloc(maxTableLength*sizeof(Row)+maxTableLength*4);
michael@0 1116 if(tempTable.rows==NULL) {
michael@0 1117 udata_printError(ds, "ures_swap(): unable to allocate memory for sorting tables (max length: %d)\n",
michael@0 1118 maxTableLength);
michael@0 1119 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
michael@0 1120 if(tempTable.resFlags!=stackResFlags) {
michael@0 1121 uprv_free(tempTable.resFlags);
michael@0 1122 }
michael@0 1123 return 0;
michael@0 1124 }
michael@0 1125 tempTable.resort=(int32_t *)(tempTable.rows+maxTableLength);
michael@0 1126 }
michael@0 1127
michael@0 1128 /* swap the resources */
michael@0 1129 ures_swapResource(ds, inBundle, outBundle, rootRes, NULL, &tempTable, pErrorCode);
michael@0 1130 if(U_FAILURE(*pErrorCode)) {
michael@0 1131 udata_printError(ds, "ures_swapResource(root res=%08x) failed\n",
michael@0 1132 rootRes);
michael@0 1133 }
michael@0 1134
michael@0 1135 if(tempTable.rows!=rows) {
michael@0 1136 uprv_free(tempTable.rows);
michael@0 1137 }
michael@0 1138 if(tempTable.resFlags!=stackResFlags) {
michael@0 1139 uprv_free(tempTable.resFlags);
michael@0 1140 }
michael@0 1141
michael@0 1142 /* swap the root resource and indexes */
michael@0 1143 ds->swapArray32(ds, inBundle, keysBottom*4, outBundle, pErrorCode);
michael@0 1144 }
michael@0 1145
michael@0 1146 return headerSize+4*top;
michael@0 1147 }

mercurial