1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 2000-2014, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 * 7 ******************************************************************************* 8 * 9 * File reslist.c 10 * 11 * Modification History: 12 * 13 * Date Name Description 14 * 02/21/00 weiv Creation. 15 ******************************************************************************* 16 */ 17 18 #include <assert.h> 19 #include <stdio.h> 20 #include "reslist.h" 21 #include "unewdata.h" 22 #include "unicode/ures.h" 23 #include "unicode/putil.h" 24 #include "errmsg.h" 25 26 #include "uarrsort.h" 27 #include "uelement.h" 28 #include "uhash.h" 29 #include "uinvchar.h" 30 #include "ustr_imp.h" 31 #include "unicode/utf16.h" 32 /* 33 * Align binary data at a 16-byte offset from the start of the resource bundle, 34 * to be safe for any data type it may contain. 35 */ 36 #define BIN_ALIGNMENT 16 37 38 static UBool gIncludeCopyright = FALSE; 39 static UBool gUsePoolBundle = FALSE; 40 static int32_t gFormatVersion = 2; 41 42 static UChar gEmptyString = 0; 43 44 /* How do we store string values? */ 45 enum { 46 STRINGS_UTF16_V1, /* formatVersion 1: int length + UChars + NUL + padding to 4 bytes */ 47 STRINGS_UTF16_V2 /* formatVersion 2: optional length in 1..3 UChars + UChars + NUL */ 48 }; 49 50 enum { 51 MAX_IMPLICIT_STRING_LENGTH = 40 /* do not store the length explicitly for such strings */ 52 }; 53 54 /* 55 * res_none() returns the address of kNoResource, 56 * for use in non-error cases when no resource is to be added to the bundle. 57 * (NULL is used in error cases.) 58 */ 59 static const struct SResource kNoResource = { URES_NONE }; 60 61 static UDataInfo dataInfo= { 62 sizeof(UDataInfo), 63 0, 64 65 U_IS_BIG_ENDIAN, 66 U_CHARSET_FAMILY, 67 sizeof(UChar), 68 0, 69 70 {0x52, 0x65, 0x73, 0x42}, /* dataFormat="ResB" */ 71 {1, 3, 0, 0}, /* formatVersion */ 72 {1, 4, 0, 0} /* dataVersion take a look at version inside parsed resb*/ 73 }; 74 75 static const UVersionInfo gFormatVersions[3] = { /* indexed by a major-formatVersion integer */ 76 { 0, 0, 0, 0 }, 77 { 1, 3, 0, 0 }, 78 { 2, 0, 0, 0 } 79 }; 80 81 static uint8_t calcPadding(uint32_t size) { 82 /* returns space we need to pad */ 83 return (uint8_t) ((size % sizeof(uint32_t)) ? (sizeof(uint32_t) - (size % sizeof(uint32_t))) : 0); 84 85 } 86 87 void setIncludeCopyright(UBool val){ 88 gIncludeCopyright=val; 89 } 90 91 UBool getIncludeCopyright(void){ 92 return gIncludeCopyright; 93 } 94 95 void setFormatVersion(int32_t formatVersion) { 96 gFormatVersion = formatVersion; 97 } 98 99 void setUsePoolBundle(UBool use) { 100 gUsePoolBundle = use; 101 } 102 103 static void 104 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status); 105 106 /* Writing Functions */ 107 108 /* 109 * Preflight strings. 110 * Find duplicates and count the total number of string code units 111 * so that they can be written first to the 16-bit array, 112 * for minimal string and container storage. 113 * 114 * We walk the final parse tree, rather than collecting this information while building it, 115 * so that we need not deal with changes to the parse tree (especially removing resources). 116 */ 117 static void 118 res_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable *stringSet, 119 UErrorCode *status); 120 121 /* 122 * type_write16() functions write resource values into f16BitUnits 123 * and determine the resource item word, if possible. 124 */ 125 static void 126 res_write16(struct SRBRoot *bundle, struct SResource *res, 127 UErrorCode *status); 128 129 /* 130 * type_preWrite() functions calculate ("preflight") and advance the *byteOffset 131 * by the size of their data in the binary file and 132 * determine the resource item word. 133 * Most type_preWrite() functions may add any number of bytes, but res_preWrite() 134 * will always pad it to a multiple of 4. 135 * The resource item type may be a related subtype of the fType. 136 * 137 * The type_preWrite() and type_write() functions start and end at the same 138 * byteOffset values. 139 * Prewriting allows bundle_write() to determine the root resource item word, 140 * before actually writing the bundle contents to the file, 141 * which is necessary because the root item is stored at the beginning. 142 */ 143 static void 144 res_preWrite(uint32_t *byteOffset, 145 struct SRBRoot *bundle, struct SResource *res, 146 UErrorCode *status); 147 148 /* 149 * type_write() functions write their data to mem and update the byteOffset 150 * in parallel. 151 * (A kingdom for C++ and polymorphism...) 152 */ 153 static void 154 res_write(UNewDataMemory *mem, uint32_t *byteOffset, 155 struct SRBRoot *bundle, struct SResource *res, 156 UErrorCode *status); 157 158 static void 159 string_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable *stringSet, 160 UErrorCode *status) { 161 res->u.fString.fSame = uhash_get(stringSet, res); 162 if (res->u.fString.fSame != NULL) { 163 return; /* This is a duplicate of an earlier-visited string. */ 164 } 165 /* Put this string into the set for finding duplicates. */ 166 uhash_put(stringSet, res, res, status); 167 168 if (bundle->fStringsForm != STRINGS_UTF16_V1) { 169 const UChar *s = res->u.fString.fChars; 170 int32_t len = res->u.fString.fLength; 171 if (len <= MAX_IMPLICIT_STRING_LENGTH && !U16_IS_TRAIL(s[0]) && len == u_strlen(s)) { 172 /* 173 * This string will be stored without an explicit length. 174 * Runtime will detect !U16_IS_TRAIL(s[0]) and call u_strlen(). 175 */ 176 res->u.fString.fNumCharsForLength = 0; 177 } else if (len <= 0x3ee) { 178 res->u.fString.fNumCharsForLength = 1; 179 } else if (len <= 0xfffff) { 180 res->u.fString.fNumCharsForLength = 2; 181 } else { 182 res->u.fString.fNumCharsForLength = 3; 183 } 184 bundle->f16BitUnitsLength += res->u.fString.fNumCharsForLength + len + 1; /* +1 for the NUL */ 185 } 186 } 187 188 static void 189 array_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable *stringSet, 190 UErrorCode *status) { 191 struct SResource *current; 192 193 if (U_FAILURE(*status)) { 194 return; 195 } 196 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 197 res_preflightStrings(bundle, current, stringSet, status); 198 } 199 } 200 201 static void 202 table_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable *stringSet, 203 UErrorCode *status) { 204 struct SResource *current; 205 206 if (U_FAILURE(*status)) { 207 return; 208 } 209 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 210 res_preflightStrings(bundle, current, stringSet, status); 211 } 212 } 213 214 static void 215 res_preflightStrings(struct SRBRoot *bundle, struct SResource *res, UHashtable *stringSet, 216 UErrorCode *status) { 217 if (U_FAILURE(*status) || res == NULL) { 218 return; 219 } 220 if (res->fRes != RES_BOGUS) { 221 /* 222 * The resource item word was already precomputed, which means 223 * no further data needs to be written. 224 * This might be an integer, or an empty string/binary/etc. 225 */ 226 return; 227 } 228 switch (res->fType) { 229 case URES_STRING: 230 string_preflightStrings(bundle, res, stringSet, status); 231 break; 232 case URES_ARRAY: 233 array_preflightStrings(bundle, res, stringSet, status); 234 break; 235 case URES_TABLE: 236 table_preflightStrings(bundle, res, stringSet, status); 237 break; 238 default: 239 /* Neither a string nor a container. */ 240 break; 241 } 242 } 243 244 static uint16_t * 245 reserve16BitUnits(struct SRBRoot *bundle, int32_t length, UErrorCode *status) { 246 if (U_FAILURE(*status)) { 247 return NULL; 248 } 249 if ((bundle->f16BitUnitsLength + length) > bundle->f16BitUnitsCapacity) { 250 uint16_t *newUnits; 251 int32_t capacity = 2 * bundle->f16BitUnitsCapacity + length + 1024; 252 capacity &= ~1; /* ensures padding fits if f16BitUnitsLength needs it */ 253 newUnits = (uint16_t *)uprv_malloc(capacity * 2); 254 if (newUnits == NULL) { 255 *status = U_MEMORY_ALLOCATION_ERROR; 256 return NULL; 257 } 258 if (bundle->f16BitUnitsLength > 0) { 259 uprv_memcpy(newUnits, bundle->f16BitUnits, bundle->f16BitUnitsLength * 2); 260 } else { 261 newUnits[0] = 0; 262 bundle->f16BitUnitsLength = 1; 263 } 264 uprv_free(bundle->f16BitUnits); 265 bundle->f16BitUnits = newUnits; 266 bundle->f16BitUnitsCapacity = capacity; 267 } 268 return bundle->f16BitUnits + bundle->f16BitUnitsLength; 269 } 270 271 static int32_t 272 makeRes16(uint32_t resWord) { 273 uint32_t type, offset; 274 if (resWord == 0) { 275 return 0; /* empty string */ 276 } 277 type = RES_GET_TYPE(resWord); 278 offset = RES_GET_OFFSET(resWord); 279 if (type == URES_STRING_V2 && offset <= 0xffff) { 280 return (int32_t)offset; 281 } 282 return -1; 283 } 284 285 static int32_t 286 mapKey(struct SRBRoot *bundle, int32_t oldpos) { 287 const KeyMapEntry *map = bundle->fKeyMap; 288 int32_t i, start, limit; 289 290 /* do a binary search for the old, pre-bundle_compactKeys() key offset */ 291 start = bundle->fPoolBundleKeysCount; 292 limit = start + bundle->fKeysCount; 293 while (start < limit - 1) { 294 i = (start + limit) / 2; 295 if (oldpos < map[i].oldpos) { 296 limit = i; 297 } else { 298 start = i; 299 } 300 } 301 assert(oldpos == map[start].oldpos); 302 return map[start].newpos; 303 } 304 305 static uint16_t 306 makeKey16(struct SRBRoot *bundle, int32_t key) { 307 if (key >= 0) { 308 return (uint16_t)key; 309 } else { 310 return (uint16_t)(key + bundle->fLocalKeyLimit); /* offset in the pool bundle */ 311 } 312 } 313 314 /* 315 * Only called for UTF-16 v1 strings and duplicate UTF-16 v2 strings. 316 * For unique UTF-16 v2 strings, res_write16() sees fRes != RES_BOGUS 317 * and exits early. 318 */ 319 static void 320 string_write16(struct SRBRoot *bundle, struct SResource *res, UErrorCode *status) { 321 struct SResource *same; 322 if ((same = res->u.fString.fSame) != NULL) { 323 /* This is a duplicate. */ 324 assert(same->fRes != RES_BOGUS && same->fWritten); 325 res->fRes = same->fRes; 326 res->fWritten = same->fWritten; 327 } 328 } 329 330 static void 331 array_write16(struct SRBRoot *bundle, struct SResource *res, 332 UErrorCode *status) { 333 struct SResource *current; 334 int32_t res16 = 0; 335 336 if (U_FAILURE(*status)) { 337 return; 338 } 339 if (res->u.fArray.fCount == 0 && gFormatVersion > 1) { 340 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_ARRAY); 341 res->fWritten = TRUE; 342 return; 343 } 344 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 345 res_write16(bundle, current, status); 346 res16 |= makeRes16(current->fRes); 347 } 348 if (U_SUCCESS(*status) && res->u.fArray.fCount <= 0xffff && res16 >= 0 && gFormatVersion > 1) { 349 uint16_t *p16 = reserve16BitUnits(bundle, 1 + res->u.fArray.fCount, status); 350 if (U_SUCCESS(*status)) { 351 res->fRes = URES_MAKE_RESOURCE(URES_ARRAY16, bundle->f16BitUnitsLength); 352 *p16++ = (uint16_t)res->u.fArray.fCount; 353 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 354 *p16++ = (uint16_t)makeRes16(current->fRes); 355 } 356 bundle->f16BitUnitsLength += 1 + res->u.fArray.fCount; 357 res->fWritten = TRUE; 358 } 359 } 360 } 361 362 static void 363 table_write16(struct SRBRoot *bundle, struct SResource *res, 364 UErrorCode *status) { 365 struct SResource *current; 366 int32_t maxKey = 0, maxPoolKey = 0x80000000; 367 int32_t res16 = 0; 368 UBool hasLocalKeys = FALSE, hasPoolKeys = FALSE; 369 370 if (U_FAILURE(*status)) { 371 return; 372 } 373 if (res->u.fTable.fCount == 0 && gFormatVersion > 1) { 374 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_TABLE); 375 res->fWritten = TRUE; 376 return; 377 } 378 /* Find the smallest table type that fits the data. */ 379 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 380 int32_t key; 381 res_write16(bundle, current, status); 382 if (bundle->fKeyMap == NULL) { 383 key = current->fKey; 384 } else { 385 key = current->fKey = mapKey(bundle, current->fKey); 386 } 387 if (key >= 0) { 388 hasLocalKeys = TRUE; 389 if (key > maxKey) { 390 maxKey = key; 391 } 392 } else { 393 hasPoolKeys = TRUE; 394 if (key > maxPoolKey) { 395 maxPoolKey = key; 396 } 397 } 398 res16 |= makeRes16(current->fRes); 399 } 400 if (U_FAILURE(*status)) { 401 return; 402 } 403 if(res->u.fTable.fCount > (uint32_t)bundle->fMaxTableLength) { 404 bundle->fMaxTableLength = res->u.fTable.fCount; 405 } 406 maxPoolKey &= 0x7fffffff; 407 if (res->u.fTable.fCount <= 0xffff && 408 (!hasLocalKeys || maxKey < bundle->fLocalKeyLimit) && 409 (!hasPoolKeys || maxPoolKey < (0x10000 - bundle->fLocalKeyLimit)) 410 ) { 411 if (res16 >= 0 && gFormatVersion > 1) { 412 uint16_t *p16 = reserve16BitUnits(bundle, 1 + res->u.fTable.fCount * 2, status); 413 if (U_SUCCESS(*status)) { 414 /* 16-bit count, key offsets and values */ 415 res->fRes = URES_MAKE_RESOURCE(URES_TABLE16, bundle->f16BitUnitsLength); 416 *p16++ = (uint16_t)res->u.fTable.fCount; 417 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 418 *p16++ = makeKey16(bundle, current->fKey); 419 } 420 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 421 *p16++ = (uint16_t)makeRes16(current->fRes); 422 } 423 bundle->f16BitUnitsLength += 1 + res->u.fTable.fCount * 2; 424 res->fWritten = TRUE; 425 } 426 } else { 427 /* 16-bit count, 16-bit key offsets, 32-bit values */ 428 res->u.fTable.fType = URES_TABLE; 429 } 430 } else { 431 /* 32-bit count, key offsets and values */ 432 res->u.fTable.fType = URES_TABLE32; 433 } 434 } 435 436 static void 437 res_write16(struct SRBRoot *bundle, struct SResource *res, 438 UErrorCode *status) { 439 if (U_FAILURE(*status) || res == NULL) { 440 return; 441 } 442 if (res->fRes != RES_BOGUS) { 443 /* 444 * The resource item word was already precomputed, which means 445 * no further data needs to be written. 446 * This might be an integer, or an empty or UTF-16 v2 string, 447 * an empty binary, etc. 448 */ 449 return; 450 } 451 switch (res->fType) { 452 case URES_STRING: 453 string_write16(bundle, res, status); 454 break; 455 case URES_ARRAY: 456 array_write16(bundle, res, status); 457 break; 458 case URES_TABLE: 459 table_write16(bundle, res, status); 460 break; 461 default: 462 /* Only a few resource types write 16-bit units. */ 463 break; 464 } 465 } 466 467 /* 468 * Only called for UTF-16 v1 strings. 469 * For UTF-16 v2 strings, res_preWrite() sees fRes != RES_BOGUS 470 * and exits early. 471 */ 472 static void 473 string_preWrite(uint32_t *byteOffset, 474 struct SRBRoot *bundle, struct SResource *res, 475 UErrorCode *status) { 476 /* Write the UTF-16 v1 string. */ 477 res->fRes = URES_MAKE_RESOURCE(URES_STRING, *byteOffset >> 2); 478 *byteOffset += 4 + (res->u.fString.fLength + 1) * U_SIZEOF_UCHAR; 479 } 480 481 static void 482 bin_preWrite(uint32_t *byteOffset, 483 struct SRBRoot *bundle, struct SResource *res, 484 UErrorCode *status) { 485 uint32_t pad = 0; 486 uint32_t dataStart = *byteOffset + sizeof(res->u.fBinaryValue.fLength); 487 488 if (dataStart % BIN_ALIGNMENT) { 489 pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT); 490 *byteOffset += pad; /* pad == 4 or 8 or 12 */ 491 } 492 res->fRes = URES_MAKE_RESOURCE(URES_BINARY, *byteOffset >> 2); 493 *byteOffset += 4 + res->u.fBinaryValue.fLength; 494 } 495 496 static void 497 array_preWrite(uint32_t *byteOffset, 498 struct SRBRoot *bundle, struct SResource *res, 499 UErrorCode *status) { 500 struct SResource *current; 501 502 if (U_FAILURE(*status)) { 503 return; 504 } 505 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 506 res_preWrite(byteOffset, bundle, current, status); 507 } 508 res->fRes = URES_MAKE_RESOURCE(URES_ARRAY, *byteOffset >> 2); 509 *byteOffset += (1 + res->u.fArray.fCount) * 4; 510 } 511 512 static void 513 table_preWrite(uint32_t *byteOffset, 514 struct SRBRoot *bundle, struct SResource *res, 515 UErrorCode *status) { 516 struct SResource *current; 517 518 if (U_FAILURE(*status)) { 519 return; 520 } 521 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 522 res_preWrite(byteOffset, bundle, current, status); 523 } 524 if (res->u.fTable.fType == URES_TABLE) { 525 /* 16-bit count, 16-bit key offsets, 32-bit values */ 526 res->fRes = URES_MAKE_RESOURCE(URES_TABLE, *byteOffset >> 2); 527 *byteOffset += 2 + res->u.fTable.fCount * 6; 528 } else { 529 /* 32-bit count, key offsets and values */ 530 res->fRes = URES_MAKE_RESOURCE(URES_TABLE32, *byteOffset >> 2); 531 *byteOffset += 4 + res->u.fTable.fCount * 8; 532 } 533 } 534 535 static void 536 res_preWrite(uint32_t *byteOffset, 537 struct SRBRoot *bundle, struct SResource *res, 538 UErrorCode *status) { 539 if (U_FAILURE(*status) || res == NULL) { 540 return; 541 } 542 if (res->fRes != RES_BOGUS) { 543 /* 544 * The resource item word was already precomputed, which means 545 * no further data needs to be written. 546 * This might be an integer, or an empty or UTF-16 v2 string, 547 * an empty binary, etc. 548 */ 549 return; 550 } 551 switch (res->fType) { 552 case URES_STRING: 553 string_preWrite(byteOffset, bundle, res, status); 554 break; 555 case URES_ALIAS: 556 res->fRes = URES_MAKE_RESOURCE(URES_ALIAS, *byteOffset >> 2); 557 *byteOffset += 4 + (res->u.fString.fLength + 1) * U_SIZEOF_UCHAR; 558 break; 559 case URES_INT_VECTOR: 560 if (res->u.fIntVector.fCount == 0 && gFormatVersion > 1) { 561 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_INT_VECTOR); 562 res->fWritten = TRUE; 563 } else { 564 res->fRes = URES_MAKE_RESOURCE(URES_INT_VECTOR, *byteOffset >> 2); 565 *byteOffset += (1 + res->u.fIntVector.fCount) * 4; 566 } 567 break; 568 case URES_BINARY: 569 bin_preWrite(byteOffset, bundle, res, status); 570 break; 571 case URES_INT: 572 break; 573 case URES_ARRAY: 574 array_preWrite(byteOffset, bundle, res, status); 575 break; 576 case URES_TABLE: 577 table_preWrite(byteOffset, bundle, res, status); 578 break; 579 default: 580 *status = U_INTERNAL_PROGRAM_ERROR; 581 break; 582 } 583 *byteOffset += calcPadding(*byteOffset); 584 } 585 586 /* 587 * Only called for UTF-16 v1 strings. For UTF-16 v2 strings, 588 * res_write() sees fWritten and exits early. 589 */ 590 static void string_write(UNewDataMemory *mem, uint32_t *byteOffset, 591 struct SRBRoot *bundle, struct SResource *res, 592 UErrorCode *status) { 593 /* Write the UTF-16 v1 string. */ 594 int32_t length = res->u.fString.fLength; 595 udata_write32(mem, length); 596 udata_writeUString(mem, res->u.fString.fChars, length + 1); 597 *byteOffset += 4 + (length + 1) * U_SIZEOF_UCHAR; 598 res->fWritten = TRUE; 599 } 600 601 static void alias_write(UNewDataMemory *mem, uint32_t *byteOffset, 602 struct SRBRoot *bundle, struct SResource *res, 603 UErrorCode *status) { 604 int32_t length = res->u.fString.fLength; 605 udata_write32(mem, length); 606 udata_writeUString(mem, res->u.fString.fChars, length + 1); 607 *byteOffset += 4 + (length + 1) * U_SIZEOF_UCHAR; 608 } 609 610 static void array_write(UNewDataMemory *mem, uint32_t *byteOffset, 611 struct SRBRoot *bundle, struct SResource *res, 612 UErrorCode *status) { 613 uint32_t i; 614 615 struct SResource *current = NULL; 616 617 if (U_FAILURE(*status)) { 618 return; 619 } 620 for (i = 0, current = res->u.fArray.fFirst; current != NULL; ++i, current = current->fNext) { 621 res_write(mem, byteOffset, bundle, current, status); 622 } 623 assert(i == res->u.fArray.fCount); 624 625 udata_write32(mem, res->u.fArray.fCount); 626 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 627 udata_write32(mem, current->fRes); 628 } 629 *byteOffset += (1 + res->u.fArray.fCount) * 4; 630 } 631 632 static void intvector_write(UNewDataMemory *mem, uint32_t *byteOffset, 633 struct SRBRoot *bundle, struct SResource *res, 634 UErrorCode *status) { 635 uint32_t i = 0; 636 udata_write32(mem, res->u.fIntVector.fCount); 637 for(i = 0; i<res->u.fIntVector.fCount; i++) { 638 udata_write32(mem, res->u.fIntVector.fArray[i]); 639 } 640 *byteOffset += (1 + res->u.fIntVector.fCount) * 4; 641 } 642 643 static void bin_write(UNewDataMemory *mem, uint32_t *byteOffset, 644 struct SRBRoot *bundle, struct SResource *res, 645 UErrorCode *status) { 646 uint32_t pad = 0; 647 uint32_t dataStart = *byteOffset + sizeof(res->u.fBinaryValue.fLength); 648 649 if (dataStart % BIN_ALIGNMENT) { 650 pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT); 651 udata_writePadding(mem, pad); /* pad == 4 or 8 or 12 */ 652 *byteOffset += pad; 653 } 654 655 udata_write32(mem, res->u.fBinaryValue.fLength); 656 if (res->u.fBinaryValue.fLength > 0) { 657 udata_writeBlock(mem, res->u.fBinaryValue.fData, res->u.fBinaryValue.fLength); 658 } 659 *byteOffset += 4 + res->u.fBinaryValue.fLength; 660 } 661 662 static void table_write(UNewDataMemory *mem, uint32_t *byteOffset, 663 struct SRBRoot *bundle, struct SResource *res, 664 UErrorCode *status) { 665 struct SResource *current; 666 uint32_t i; 667 668 if (U_FAILURE(*status)) { 669 return; 670 } 671 for (i = 0, current = res->u.fTable.fFirst; current != NULL; ++i, current = current->fNext) { 672 assert(i < res->u.fTable.fCount); 673 res_write(mem, byteOffset, bundle, current, status); 674 } 675 assert(i == res->u.fTable.fCount); 676 677 if(res->u.fTable.fType == URES_TABLE) { 678 udata_write16(mem, (uint16_t)res->u.fTable.fCount); 679 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 680 udata_write16(mem, makeKey16(bundle, current->fKey)); 681 } 682 *byteOffset += (1 + res->u.fTable.fCount)* 2; 683 if ((res->u.fTable.fCount & 1) == 0) { 684 /* 16-bit count and even number of 16-bit key offsets need padding before 32-bit resource items */ 685 udata_writePadding(mem, 2); 686 *byteOffset += 2; 687 } 688 } else /* URES_TABLE32 */ { 689 udata_write32(mem, res->u.fTable.fCount); 690 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 691 udata_write32(mem, (uint32_t)current->fKey); 692 } 693 *byteOffset += (1 + res->u.fTable.fCount)* 4; 694 } 695 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 696 udata_write32(mem, current->fRes); 697 } 698 *byteOffset += res->u.fTable.fCount * 4; 699 } 700 701 void res_write(UNewDataMemory *mem, uint32_t *byteOffset, 702 struct SRBRoot *bundle, struct SResource *res, 703 UErrorCode *status) { 704 uint8_t paddingSize; 705 706 if (U_FAILURE(*status) || res == NULL) { 707 return; 708 } 709 if (res->fWritten) { 710 assert(res->fRes != RES_BOGUS); 711 return; 712 } 713 switch (res->fType) { 714 case URES_STRING: 715 string_write (mem, byteOffset, bundle, res, status); 716 break; 717 case URES_ALIAS: 718 alias_write (mem, byteOffset, bundle, res, status); 719 break; 720 case URES_INT_VECTOR: 721 intvector_write (mem, byteOffset, bundle, res, status); 722 break; 723 case URES_BINARY: 724 bin_write (mem, byteOffset, bundle, res, status); 725 break; 726 case URES_INT: 727 break; /* fRes was set by int_open() */ 728 case URES_ARRAY: 729 array_write (mem, byteOffset, bundle, res, status); 730 break; 731 case URES_TABLE: 732 table_write (mem, byteOffset, bundle, res, status); 733 break; 734 default: 735 *status = U_INTERNAL_PROGRAM_ERROR; 736 break; 737 } 738 paddingSize = calcPadding(*byteOffset); 739 if (paddingSize > 0) { 740 udata_writePadding(mem, paddingSize); 741 *byteOffset += paddingSize; 742 } 743 res->fWritten = TRUE; 744 } 745 746 void bundle_write(struct SRBRoot *bundle, 747 const char *outputDir, const char *outputPkg, 748 char *writtenFilename, int writtenFilenameLen, 749 UErrorCode *status) { 750 UNewDataMemory *mem = NULL; 751 uint32_t byteOffset = 0; 752 uint32_t top, size; 753 char dataName[1024]; 754 int32_t indexes[URES_INDEX_TOP]; 755 756 bundle_compactKeys(bundle, status); 757 /* 758 * Add padding bytes to fKeys so that fKeysTop is 4-aligned. 759 * Safe because the capacity is a multiple of 4. 760 */ 761 while (bundle->fKeysTop & 3) { 762 bundle->fKeys[bundle->fKeysTop++] = (char)0xaa; 763 } 764 /* 765 * In URES_TABLE, use all local key offsets that fit into 16 bits, 766 * and use the remaining 16-bit offsets for pool key offsets 767 * if there are any. 768 * If there are no local keys, then use the whole 16-bit space 769 * for pool key offsets. 770 * Note: This cannot be changed without changing the major formatVersion. 771 */ 772 if (bundle->fKeysBottom < bundle->fKeysTop) { 773 if (bundle->fKeysTop <= 0x10000) { 774 bundle->fLocalKeyLimit = bundle->fKeysTop; 775 } else { 776 bundle->fLocalKeyLimit = 0x10000; 777 } 778 } else { 779 bundle->fLocalKeyLimit = 0; 780 } 781 782 bundle_compactStrings(bundle, status); 783 res_write16(bundle, bundle->fRoot, status); 784 if (bundle->f16BitUnitsLength & 1) { 785 bundle->f16BitUnits[bundle->f16BitUnitsLength++] = 0xaaaa; /* pad to multiple of 4 bytes */ 786 } 787 /* all keys have been mapped */ 788 uprv_free(bundle->fKeyMap); 789 bundle->fKeyMap = NULL; 790 791 byteOffset = bundle->fKeysTop + bundle->f16BitUnitsLength * 2; 792 res_preWrite(&byteOffset, bundle, bundle->fRoot, status); 793 794 /* total size including the root item */ 795 top = byteOffset; 796 797 if (U_FAILURE(*status)) { 798 return; 799 } 800 801 if (writtenFilename && writtenFilenameLen) { 802 *writtenFilename = 0; 803 } 804 805 if (writtenFilename) { 806 int32_t off = 0, len = 0; 807 if (outputDir) { 808 len = (int32_t)uprv_strlen(outputDir); 809 if (len > writtenFilenameLen) { 810 len = writtenFilenameLen; 811 } 812 uprv_strncpy(writtenFilename, outputDir, len); 813 } 814 if (writtenFilenameLen -= len) { 815 off += len; 816 writtenFilename[off] = U_FILE_SEP_CHAR; 817 if (--writtenFilenameLen) { 818 ++off; 819 if(outputPkg != NULL) 820 { 821 uprv_strcpy(writtenFilename+off, outputPkg); 822 off += (int32_t)uprv_strlen(outputPkg); 823 writtenFilename[off] = '_'; 824 ++off; 825 } 826 827 len = (int32_t)uprv_strlen(bundle->fLocale); 828 if (len > writtenFilenameLen) { 829 len = writtenFilenameLen; 830 } 831 uprv_strncpy(writtenFilename + off, bundle->fLocale, len); 832 if (writtenFilenameLen -= len) { 833 off += len; 834 len = 5; 835 if (len > writtenFilenameLen) { 836 len = writtenFilenameLen; 837 } 838 uprv_strncpy(writtenFilename + off, ".res", len); 839 } 840 } 841 } 842 } 843 844 if(outputPkg) 845 { 846 uprv_strcpy(dataName, outputPkg); 847 uprv_strcat(dataName, "_"); 848 uprv_strcat(dataName, bundle->fLocale); 849 } 850 else 851 { 852 uprv_strcpy(dataName, bundle->fLocale); 853 } 854 855 uprv_memcpy(dataInfo.formatVersion, gFormatVersions + gFormatVersion, sizeof(UVersionInfo)); 856 857 mem = udata_create(outputDir, "res", dataName, &dataInfo, (gIncludeCopyright==TRUE)? U_COPYRIGHT_STRING:NULL, status); 858 if(U_FAILURE(*status)){ 859 return; 860 } 861 862 /* write the root item */ 863 udata_write32(mem, bundle->fRoot->fRes); 864 865 /* 866 * formatVersion 1.1 (ICU 2.8): 867 * write int32_t indexes[] after root and before the strings 868 * to make it easier to parse resource bundles in icuswap or from Java etc. 869 */ 870 uprv_memset(indexes, 0, sizeof(indexes)); 871 indexes[URES_INDEX_LENGTH]= bundle->fIndexLength; 872 indexes[URES_INDEX_KEYS_TOP]= bundle->fKeysTop>>2; 873 indexes[URES_INDEX_RESOURCES_TOP]= (int32_t)(top>>2); 874 indexes[URES_INDEX_BUNDLE_TOP]= indexes[URES_INDEX_RESOURCES_TOP]; 875 indexes[URES_INDEX_MAX_TABLE_LENGTH]= bundle->fMaxTableLength; 876 877 /* 878 * formatVersion 1.2 (ICU 3.6): 879 * write indexes[URES_INDEX_ATTRIBUTES] with URES_ATT_NO_FALLBACK set or not set 880 * the memset() above initialized all indexes[] to 0 881 */ 882 if (bundle->noFallback) { 883 indexes[URES_INDEX_ATTRIBUTES]=URES_ATT_NO_FALLBACK; 884 } 885 /* 886 * formatVersion 2.0 (ICU 4.4): 887 * more compact string value storage, optional pool bundle 888 */ 889 if (URES_INDEX_16BIT_TOP < bundle->fIndexLength) { 890 indexes[URES_INDEX_16BIT_TOP] = (bundle->fKeysTop>>2) + (bundle->f16BitUnitsLength>>1); 891 } 892 if (URES_INDEX_POOL_CHECKSUM < bundle->fIndexLength) { 893 if (bundle->fIsPoolBundle) { 894 indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_IS_POOL_BUNDLE | URES_ATT_NO_FALLBACK; 895 indexes[URES_INDEX_POOL_CHECKSUM] = 896 (int32_t)computeCRC((char *)(bundle->fKeys + bundle->fKeysBottom), 897 (uint32_t)(bundle->fKeysTop - bundle->fKeysBottom), 898 0); 899 } else if (gUsePoolBundle) { 900 indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_USES_POOL_BUNDLE; 901 indexes[URES_INDEX_POOL_CHECKSUM] = bundle->fPoolChecksum; 902 } 903 } 904 905 /* write the indexes[] */ 906 udata_writeBlock(mem, indexes, bundle->fIndexLength*4); 907 908 /* write the table key strings */ 909 udata_writeBlock(mem, bundle->fKeys+bundle->fKeysBottom, 910 bundle->fKeysTop-bundle->fKeysBottom); 911 912 /* write the v2 UTF-16 strings, URES_TABLE16 and URES_ARRAY16 */ 913 udata_writeBlock(mem, bundle->f16BitUnits, bundle->f16BitUnitsLength*2); 914 915 /* write all of the bundle contents: the root item and its children */ 916 byteOffset = bundle->fKeysTop + bundle->f16BitUnitsLength * 2; 917 res_write(mem, &byteOffset, bundle, bundle->fRoot, status); 918 assert(byteOffset == top); 919 920 size = udata_finish(mem, status); 921 if(top != size) { 922 fprintf(stderr, "genrb error: wrote %u bytes but counted %u\n", 923 (int)size, (int)top); 924 *status = U_INTERNAL_PROGRAM_ERROR; 925 } 926 } 927 928 /* Opening Functions */ 929 930 /* gcc 4.2 complained "no previous prototype for res_open" without this prototype... */ 931 struct SResource* res_open(struct SRBRoot *bundle, const char *tag, 932 const struct UString* comment, UErrorCode* status); 933 934 struct SResource* res_open(struct SRBRoot *bundle, const char *tag, 935 const struct UString* comment, UErrorCode* status){ 936 struct SResource *res; 937 int32_t key = bundle_addtag(bundle, tag, status); 938 if (U_FAILURE(*status)) { 939 return NULL; 940 } 941 942 res = (struct SResource *) uprv_malloc(sizeof(struct SResource)); 943 if (res == NULL) { 944 *status = U_MEMORY_ALLOCATION_ERROR; 945 return NULL; 946 } 947 uprv_memset(res, 0, sizeof(struct SResource)); 948 res->fKey = key; 949 res->fRes = RES_BOGUS; 950 951 ustr_init(&res->fComment); 952 if(comment != NULL){ 953 ustr_cpy(&res->fComment, comment, status); 954 if (U_FAILURE(*status)) { 955 res_close(res); 956 return NULL; 957 } 958 } 959 return res; 960 } 961 962 struct SResource* res_none() { 963 return (struct SResource*)&kNoResource; 964 } 965 966 struct SResource* table_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) { 967 struct SResource *res = res_open(bundle, tag, comment, status); 968 if (U_FAILURE(*status)) { 969 return NULL; 970 } 971 res->fType = URES_TABLE; 972 res->u.fTable.fRoot = bundle; 973 return res; 974 } 975 976 struct SResource* array_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) { 977 struct SResource *res = res_open(bundle, tag, comment, status); 978 if (U_FAILURE(*status)) { 979 return NULL; 980 } 981 res->fType = URES_ARRAY; 982 return res; 983 } 984 985 static int32_t U_CALLCONV 986 string_hash(const UElement key) { 987 const struct SResource *res = (struct SResource *)key.pointer; 988 return ustr_hashUCharsN(res->u.fString.fChars, res->u.fString.fLength); 989 } 990 991 static UBool U_CALLCONV 992 string_comp(const UElement key1, const UElement key2) { 993 const struct SResource *res1 = (struct SResource *)key1.pointer; 994 const struct SResource *res2 = (struct SResource *)key2.pointer; 995 return 0 == u_strCompare(res1->u.fString.fChars, res1->u.fString.fLength, 996 res2->u.fString.fChars, res2->u.fString.fLength, 997 FALSE); 998 } 999 1000 static struct SResource * 1001 stringbase_open(struct SRBRoot *bundle, const char *tag, int8_t type, 1002 const UChar *value, int32_t len, const struct UString* comment, 1003 UErrorCode *status) { 1004 struct SResource *res = res_open(bundle, tag, comment, status); 1005 if (U_FAILURE(*status)) { 1006 return NULL; 1007 } 1008 res->fType = type; 1009 1010 if (len == 0 && gFormatVersion > 1) { 1011 res->u.fString.fChars = &gEmptyString; 1012 res->fRes = URES_MAKE_EMPTY_RESOURCE(type); 1013 res->fWritten = TRUE; 1014 return res; 1015 } 1016 1017 res->u.fString.fLength = len; 1018 res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1)); 1019 if (res->u.fString.fChars == NULL) { 1020 *status = U_MEMORY_ALLOCATION_ERROR; 1021 uprv_free(res); 1022 return NULL; 1023 } 1024 uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * len); 1025 res->u.fString.fChars[len] = 0; 1026 return res; 1027 } 1028 1029 struct SResource *string_open(struct SRBRoot *bundle, const char *tag, const UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) { 1030 return stringbase_open(bundle, tag, URES_STRING, value, len, comment, status); 1031 } 1032 1033 struct SResource *alias_open(struct SRBRoot *bundle, const char *tag, UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) { 1034 return stringbase_open(bundle, tag, URES_ALIAS, value, len, comment, status); 1035 } 1036 1037 1038 struct SResource* intvector_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) { 1039 struct SResource *res = res_open(bundle, tag, comment, status); 1040 if (U_FAILURE(*status)) { 1041 return NULL; 1042 } 1043 res->fType = URES_INT_VECTOR; 1044 1045 res->u.fIntVector.fCount = 0; 1046 res->u.fIntVector.fArray = (uint32_t *) uprv_malloc(sizeof(uint32_t) * RESLIST_MAX_INT_VECTOR); 1047 if (res->u.fIntVector.fArray == NULL) { 1048 *status = U_MEMORY_ALLOCATION_ERROR; 1049 uprv_free(res); 1050 return NULL; 1051 } 1052 return res; 1053 } 1054 1055 struct SResource *int_open(struct SRBRoot *bundle, const char *tag, int32_t value, const struct UString* comment, UErrorCode *status) { 1056 struct SResource *res = res_open(bundle, tag, comment, status); 1057 if (U_FAILURE(*status)) { 1058 return NULL; 1059 } 1060 res->fType = URES_INT; 1061 res->u.fIntValue.fValue = value; 1062 res->fRes = URES_MAKE_RESOURCE(URES_INT, value & 0x0FFFFFFF); 1063 res->fWritten = TRUE; 1064 return res; 1065 } 1066 1067 struct SResource *bin_open(struct SRBRoot *bundle, const char *tag, uint32_t length, uint8_t *data, const char* fileName, const struct UString* comment, UErrorCode *status) { 1068 struct SResource *res = res_open(bundle, tag, comment, status); 1069 if (U_FAILURE(*status)) { 1070 return NULL; 1071 } 1072 res->fType = URES_BINARY; 1073 1074 res->u.fBinaryValue.fLength = length; 1075 res->u.fBinaryValue.fFileName = NULL; 1076 if(fileName!=NULL && uprv_strcmp(fileName, "") !=0){ 1077 res->u.fBinaryValue.fFileName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(fileName)+1)); 1078 uprv_strcpy(res->u.fBinaryValue.fFileName,fileName); 1079 } 1080 if (length > 0) { 1081 res->u.fBinaryValue.fData = (uint8_t *) uprv_malloc(sizeof(uint8_t) * length); 1082 1083 if (res->u.fBinaryValue.fData == NULL) { 1084 *status = U_MEMORY_ALLOCATION_ERROR; 1085 uprv_free(res); 1086 return NULL; 1087 } 1088 1089 uprv_memcpy(res->u.fBinaryValue.fData, data, length); 1090 } 1091 else { 1092 res->u.fBinaryValue.fData = NULL; 1093 if (gFormatVersion > 1) { 1094 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_BINARY); 1095 res->fWritten = TRUE; 1096 } 1097 } 1098 1099 return res; 1100 } 1101 1102 struct SRBRoot *bundle_open(const struct UString* comment, UBool isPoolBundle, UErrorCode *status) { 1103 struct SRBRoot *bundle; 1104 1105 if (U_FAILURE(*status)) { 1106 return NULL; 1107 } 1108 1109 bundle = (struct SRBRoot *) uprv_malloc(sizeof(struct SRBRoot)); 1110 if (bundle == NULL) { 1111 *status = U_MEMORY_ALLOCATION_ERROR; 1112 return 0; 1113 } 1114 uprv_memset(bundle, 0, sizeof(struct SRBRoot)); 1115 1116 bundle->fKeys = (char *) uprv_malloc(sizeof(char) * KEY_SPACE_SIZE); 1117 bundle->fRoot = table_open(bundle, NULL, comment, status); 1118 if (bundle->fKeys == NULL || bundle->fRoot == NULL || U_FAILURE(*status)) { 1119 if (U_SUCCESS(*status)) { 1120 *status = U_MEMORY_ALLOCATION_ERROR; 1121 } 1122 bundle_close(bundle, status); 1123 return NULL; 1124 } 1125 1126 bundle->fLocale = NULL; 1127 bundle->fKeysCapacity = KEY_SPACE_SIZE; 1128 /* formatVersion 1.1: start fKeysTop after the root item and indexes[] */ 1129 bundle->fIsPoolBundle = isPoolBundle; 1130 if (gUsePoolBundle || isPoolBundle) { 1131 bundle->fIndexLength = URES_INDEX_POOL_CHECKSUM + 1; 1132 } else if (gFormatVersion >= 2) { 1133 bundle->fIndexLength = URES_INDEX_16BIT_TOP + 1; 1134 } else /* formatVersion 1 */ { 1135 bundle->fIndexLength = URES_INDEX_ATTRIBUTES + 1; 1136 } 1137 bundle->fKeysBottom = (1 /* root */ + bundle->fIndexLength) * 4; 1138 uprv_memset(bundle->fKeys, 0, bundle->fKeysBottom); 1139 bundle->fKeysTop = bundle->fKeysBottom; 1140 1141 if (gFormatVersion == 1) { 1142 bundle->fStringsForm = STRINGS_UTF16_V1; 1143 } else { 1144 bundle->fStringsForm = STRINGS_UTF16_V2; 1145 } 1146 1147 return bundle; 1148 } 1149 1150 /* Closing Functions */ 1151 static void table_close(struct SResource *table) { 1152 struct SResource *current = NULL; 1153 struct SResource *prev = NULL; 1154 1155 current = table->u.fTable.fFirst; 1156 1157 while (current != NULL) { 1158 prev = current; 1159 current = current->fNext; 1160 1161 res_close(prev); 1162 } 1163 1164 table->u.fTable.fFirst = NULL; 1165 } 1166 1167 static void array_close(struct SResource *array) { 1168 struct SResource *current = NULL; 1169 struct SResource *prev = NULL; 1170 1171 if(array==NULL){ 1172 return; 1173 } 1174 current = array->u.fArray.fFirst; 1175 1176 while (current != NULL) { 1177 prev = current; 1178 current = current->fNext; 1179 1180 res_close(prev); 1181 } 1182 array->u.fArray.fFirst = NULL; 1183 } 1184 1185 static void string_close(struct SResource *string) { 1186 if (string->u.fString.fChars != NULL && 1187 string->u.fString.fChars != &gEmptyString) { 1188 uprv_free(string->u.fString.fChars); 1189 string->u.fString.fChars =NULL; 1190 } 1191 } 1192 1193 static void alias_close(struct SResource *alias) { 1194 if (alias->u.fString.fChars != NULL) { 1195 uprv_free(alias->u.fString.fChars); 1196 alias->u.fString.fChars =NULL; 1197 } 1198 } 1199 1200 static void intvector_close(struct SResource *intvector) { 1201 if (intvector->u.fIntVector.fArray != NULL) { 1202 uprv_free(intvector->u.fIntVector.fArray); 1203 intvector->u.fIntVector.fArray =NULL; 1204 } 1205 } 1206 1207 static void int_close(struct SResource *intres) { 1208 /* Intentionally left blank */ 1209 } 1210 1211 static void bin_close(struct SResource *binres) { 1212 if (binres->u.fBinaryValue.fData != NULL) { 1213 uprv_free(binres->u.fBinaryValue.fData); 1214 binres->u.fBinaryValue.fData = NULL; 1215 } 1216 if (binres->u.fBinaryValue.fFileName != NULL) { 1217 uprv_free(binres->u.fBinaryValue.fFileName); 1218 binres->u.fBinaryValue.fFileName = NULL; 1219 } 1220 } 1221 1222 void res_close(struct SResource *res) { 1223 if (res != NULL) { 1224 switch(res->fType) { 1225 case URES_STRING: 1226 string_close(res); 1227 break; 1228 case URES_ALIAS: 1229 alias_close(res); 1230 break; 1231 case URES_INT_VECTOR: 1232 intvector_close(res); 1233 break; 1234 case URES_BINARY: 1235 bin_close(res); 1236 break; 1237 case URES_INT: 1238 int_close(res); 1239 break; 1240 case URES_ARRAY: 1241 array_close(res); 1242 break; 1243 case URES_TABLE: 1244 table_close(res); 1245 break; 1246 default: 1247 /* Shouldn't happen */ 1248 break; 1249 } 1250 1251 ustr_deinit(&res->fComment); 1252 uprv_free(res); 1253 } 1254 } 1255 1256 void bundle_close(struct SRBRoot *bundle, UErrorCode *status) { 1257 res_close(bundle->fRoot); 1258 uprv_free(bundle->fLocale); 1259 uprv_free(bundle->fKeys); 1260 uprv_free(bundle->fKeyMap); 1261 uprv_free(bundle->f16BitUnits); 1262 uprv_free(bundle); 1263 } 1264 1265 /* Adding Functions */ 1266 void table_add(struct SResource *table, struct SResource *res, int linenumber, UErrorCode *status) { 1267 struct SResource *current = NULL; 1268 struct SResource *prev = NULL; 1269 struct SResTable *list; 1270 const char *resKeyString; 1271 1272 if (U_FAILURE(*status)) { 1273 return; 1274 } 1275 if (res == &kNoResource) { 1276 return; 1277 } 1278 1279 /* remember this linenumber to report to the user if there is a duplicate key */ 1280 res->line = linenumber; 1281 1282 /* here we need to traverse the list */ 1283 list = &(table->u.fTable); 1284 ++(list->fCount); 1285 1286 /* is list still empty? */ 1287 if (list->fFirst == NULL) { 1288 list->fFirst = res; 1289 res->fNext = NULL; 1290 return; 1291 } 1292 1293 resKeyString = list->fRoot->fKeys + res->fKey; 1294 1295 current = list->fFirst; 1296 1297 while (current != NULL) { 1298 const char *currentKeyString = list->fRoot->fKeys + current->fKey; 1299 int diff; 1300 /* 1301 * formatVersion 1: compare key strings in native-charset order 1302 * formatVersion 2 and up: compare key strings in ASCII order 1303 */ 1304 if (gFormatVersion == 1 || U_CHARSET_FAMILY == U_ASCII_FAMILY) { 1305 diff = uprv_strcmp(currentKeyString, resKeyString); 1306 } else { 1307 diff = uprv_compareInvCharsAsAscii(currentKeyString, resKeyString); 1308 } 1309 if (diff < 0) { 1310 prev = current; 1311 current = current->fNext; 1312 } else if (diff > 0) { 1313 /* we're either in front of list, or in middle */ 1314 if (prev == NULL) { 1315 /* front of the list */ 1316 list->fFirst = res; 1317 } else { 1318 /* middle of the list */ 1319 prev->fNext = res; 1320 } 1321 1322 res->fNext = current; 1323 return; 1324 } else { 1325 /* Key already exists! ERROR! */ 1326 error(linenumber, "duplicate key '%s' in table, first appeared at line %d", currentKeyString, current->line); 1327 *status = U_UNSUPPORTED_ERROR; 1328 return; 1329 } 1330 } 1331 1332 /* end of list */ 1333 prev->fNext = res; 1334 res->fNext = NULL; 1335 } 1336 1337 void array_add(struct SResource *array, struct SResource *res, UErrorCode *status) { 1338 if (U_FAILURE(*status)) { 1339 return; 1340 } 1341 1342 if (array->u.fArray.fFirst == NULL) { 1343 array->u.fArray.fFirst = res; 1344 array->u.fArray.fLast = res; 1345 } else { 1346 array->u.fArray.fLast->fNext = res; 1347 array->u.fArray.fLast = res; 1348 } 1349 1350 (array->u.fArray.fCount)++; 1351 } 1352 1353 void intvector_add(struct SResource *intvector, int32_t value, UErrorCode *status) { 1354 if (U_FAILURE(*status)) { 1355 return; 1356 } 1357 1358 *(intvector->u.fIntVector.fArray + intvector->u.fIntVector.fCount) = value; 1359 intvector->u.fIntVector.fCount++; 1360 } 1361 1362 /* Misc Functions */ 1363 1364 void bundle_setlocale(struct SRBRoot *bundle, UChar *locale, UErrorCode *status) { 1365 1366 if(U_FAILURE(*status)) { 1367 return; 1368 } 1369 1370 if (bundle->fLocale!=NULL) { 1371 uprv_free(bundle->fLocale); 1372 } 1373 1374 bundle->fLocale= (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1)); 1375 1376 if(bundle->fLocale == NULL) { 1377 *status = U_MEMORY_ALLOCATION_ERROR; 1378 return; 1379 } 1380 1381 /*u_strcpy(bundle->fLocale, locale);*/ 1382 u_UCharsToChars(locale, bundle->fLocale, u_strlen(locale)+1); 1383 1384 } 1385 1386 static const char * 1387 getKeyString(const struct SRBRoot *bundle, int32_t key) { 1388 if (key < 0) { 1389 return bundle->fPoolBundleKeys + (key & 0x7fffffff); 1390 } else { 1391 return bundle->fKeys + key; 1392 } 1393 } 1394 1395 const char * 1396 res_getKeyString(const struct SRBRoot *bundle, const struct SResource *res, char temp[8]) { 1397 if (res->fKey == -1) { 1398 return NULL; 1399 } 1400 return getKeyString(bundle, res->fKey); 1401 } 1402 1403 const char * 1404 bundle_getKeyBytes(struct SRBRoot *bundle, int32_t *pLength) { 1405 *pLength = bundle->fKeysTop - bundle->fKeysBottom; 1406 return bundle->fKeys + bundle->fKeysBottom; 1407 } 1408 1409 int32_t 1410 bundle_addKeyBytes(struct SRBRoot *bundle, const char *keyBytes, int32_t length, UErrorCode *status) { 1411 int32_t keypos; 1412 1413 if (U_FAILURE(*status)) { 1414 return -1; 1415 } 1416 if (length < 0 || (keyBytes == NULL && length != 0)) { 1417 *status = U_ILLEGAL_ARGUMENT_ERROR; 1418 return -1; 1419 } 1420 if (length == 0) { 1421 return bundle->fKeysTop; 1422 } 1423 1424 keypos = bundle->fKeysTop; 1425 bundle->fKeysTop += length; 1426 if (bundle->fKeysTop >= bundle->fKeysCapacity) { 1427 /* overflow - resize the keys buffer */ 1428 bundle->fKeysCapacity += KEY_SPACE_SIZE; 1429 bundle->fKeys = uprv_realloc(bundle->fKeys, bundle->fKeysCapacity); 1430 if(bundle->fKeys == NULL) { 1431 *status = U_MEMORY_ALLOCATION_ERROR; 1432 return -1; 1433 } 1434 } 1435 1436 uprv_memcpy(bundle->fKeys + keypos, keyBytes, length); 1437 1438 return keypos; 1439 } 1440 1441 int32_t 1442 bundle_addtag(struct SRBRoot *bundle, const char *tag, UErrorCode *status) { 1443 int32_t keypos; 1444 1445 if (U_FAILURE(*status)) { 1446 return -1; 1447 } 1448 1449 if (tag == NULL) { 1450 /* no error: the root table and array items have no keys */ 1451 return -1; 1452 } 1453 1454 keypos = bundle_addKeyBytes(bundle, tag, (int32_t)(uprv_strlen(tag) + 1), status); 1455 if (U_SUCCESS(*status)) { 1456 ++bundle->fKeysCount; 1457 } 1458 return keypos; 1459 } 1460 1461 static int32_t 1462 compareInt32(int32_t lPos, int32_t rPos) { 1463 /* 1464 * Compare possibly-negative key offsets. Don't just return lPos - rPos 1465 * because that is prone to negative-integer underflows. 1466 */ 1467 if (lPos < rPos) { 1468 return -1; 1469 } else if (lPos > rPos) { 1470 return 1; 1471 } else { 1472 return 0; 1473 } 1474 } 1475 1476 static int32_t U_CALLCONV 1477 compareKeySuffixes(const void *context, const void *l, const void *r) { 1478 const struct SRBRoot *bundle=(const struct SRBRoot *)context; 1479 int32_t lPos = ((const KeyMapEntry *)l)->oldpos; 1480 int32_t rPos = ((const KeyMapEntry *)r)->oldpos; 1481 const char *lStart = getKeyString(bundle, lPos); 1482 const char *lLimit = lStart; 1483 const char *rStart = getKeyString(bundle, rPos); 1484 const char *rLimit = rStart; 1485 int32_t diff; 1486 while (*lLimit != 0) { ++lLimit; } 1487 while (*rLimit != 0) { ++rLimit; } 1488 /* compare keys in reverse character order */ 1489 while (lStart < lLimit && rStart < rLimit) { 1490 diff = (int32_t)(uint8_t)*--lLimit - (int32_t)(uint8_t)*--rLimit; 1491 if (diff != 0) { 1492 return diff; 1493 } 1494 } 1495 /* sort equal suffixes by descending key length */ 1496 diff = (int32_t)(rLimit - rStart) - (int32_t)(lLimit - lStart); 1497 if (diff != 0) { 1498 return diff; 1499 } 1500 /* Sort pool bundle keys first (negative oldpos), and otherwise keys in parsing order. */ 1501 return compareInt32(lPos, rPos); 1502 } 1503 1504 static int32_t U_CALLCONV 1505 compareKeyNewpos(const void *context, const void *l, const void *r) { 1506 return compareInt32(((const KeyMapEntry *)l)->newpos, ((const KeyMapEntry *)r)->newpos); 1507 } 1508 1509 static int32_t U_CALLCONV 1510 compareKeyOldpos(const void *context, const void *l, const void *r) { 1511 return compareInt32(((const KeyMapEntry *)l)->oldpos, ((const KeyMapEntry *)r)->oldpos); 1512 } 1513 1514 void 1515 bundle_compactKeys(struct SRBRoot *bundle, UErrorCode *status) { 1516 KeyMapEntry *map; 1517 char *keys; 1518 int32_t i; 1519 int32_t keysCount = bundle->fPoolBundleKeysCount + bundle->fKeysCount; 1520 if (U_FAILURE(*status) || bundle->fKeysCount == 0 || bundle->fKeyMap != NULL) { 1521 return; 1522 } 1523 map = (KeyMapEntry *)uprv_malloc(keysCount * sizeof(KeyMapEntry)); 1524 if (map == NULL) { 1525 *status = U_MEMORY_ALLOCATION_ERROR; 1526 return; 1527 } 1528 keys = (char *)bundle->fPoolBundleKeys; 1529 for (i = 0; i < bundle->fPoolBundleKeysCount; ++i) { 1530 map[i].oldpos = 1531 (int32_t)(keys - bundle->fPoolBundleKeys) | 0x80000000; /* negative oldpos */ 1532 map[i].newpos = 0; 1533 while (*keys != 0) { ++keys; } /* skip the key */ 1534 ++keys; /* skip the NUL */ 1535 } 1536 keys = bundle->fKeys + bundle->fKeysBottom; 1537 for (; i < keysCount; ++i) { 1538 map[i].oldpos = (int32_t)(keys - bundle->fKeys); 1539 map[i].newpos = 0; 1540 while (*keys != 0) { ++keys; } /* skip the key */ 1541 ++keys; /* skip the NUL */ 1542 } 1543 /* Sort the keys so that each one is immediately followed by all of its suffixes. */ 1544 uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry), 1545 compareKeySuffixes, bundle, FALSE, status); 1546 /* 1547 * Make suffixes point into earlier, longer strings that contain them 1548 * and mark the old, now unused suffix bytes as deleted. 1549 */ 1550 if (U_SUCCESS(*status)) { 1551 keys = bundle->fKeys; 1552 for (i = 0; i < keysCount;) { 1553 /* 1554 * This key is not a suffix of the previous one; 1555 * keep this one and delete the following ones that are 1556 * suffixes of this one. 1557 */ 1558 const char *key; 1559 const char *keyLimit; 1560 int32_t j = i + 1; 1561 map[i].newpos = map[i].oldpos; 1562 if (j < keysCount && map[j].oldpos < 0) { 1563 /* Key string from the pool bundle, do not delete. */ 1564 i = j; 1565 continue; 1566 } 1567 key = getKeyString(bundle, map[i].oldpos); 1568 for (keyLimit = key; *keyLimit != 0; ++keyLimit) {} 1569 for (; j < keysCount && map[j].oldpos >= 0; ++j) { 1570 const char *k; 1571 char *suffix; 1572 const char *suffixLimit; 1573 int32_t offset; 1574 suffix = keys + map[j].oldpos; 1575 for (suffixLimit = suffix; *suffixLimit != 0; ++suffixLimit) {} 1576 offset = (int32_t)(keyLimit - key) - (suffixLimit - suffix); 1577 if (offset < 0) { 1578 break; /* suffix cannot be longer than the original */ 1579 } 1580 /* Is it a suffix of the earlier, longer key? */ 1581 for (k = keyLimit; suffix < suffixLimit && *--k == *--suffixLimit;) {} 1582 if (suffix == suffixLimit && *k == *suffixLimit) { 1583 map[j].newpos = map[i].oldpos + offset; /* yes, point to the earlier key */ 1584 /* mark the suffix as deleted */ 1585 while (*suffix != 0) { *suffix++ = 1; } 1586 *suffix = 1; 1587 } else { 1588 break; /* not a suffix, restart from here */ 1589 } 1590 } 1591 i = j; 1592 } 1593 /* 1594 * Re-sort by newpos, then modify the key characters array in-place 1595 * to squeeze out unused bytes, and readjust the newpos offsets. 1596 */ 1597 uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry), 1598 compareKeyNewpos, NULL, FALSE, status); 1599 if (U_SUCCESS(*status)) { 1600 int32_t oldpos, newpos, limit; 1601 oldpos = newpos = bundle->fKeysBottom; 1602 limit = bundle->fKeysTop; 1603 /* skip key offsets that point into the pool bundle rather than this new bundle */ 1604 for (i = 0; i < keysCount && map[i].newpos < 0; ++i) {} 1605 if (i < keysCount) { 1606 while (oldpos < limit) { 1607 if (keys[oldpos] == 1) { 1608 ++oldpos; /* skip unused bytes */ 1609 } else { 1610 /* adjust the new offsets for keys starting here */ 1611 while (i < keysCount && map[i].newpos == oldpos) { 1612 map[i++].newpos = newpos; 1613 } 1614 /* move the key characters to their new position */ 1615 keys[newpos++] = keys[oldpos++]; 1616 } 1617 } 1618 assert(i == keysCount); 1619 } 1620 bundle->fKeysTop = newpos; 1621 /* Re-sort once more, by old offsets for binary searching. */ 1622 uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry), 1623 compareKeyOldpos, NULL, FALSE, status); 1624 if (U_SUCCESS(*status)) { 1625 /* key size reduction by limit - newpos */ 1626 bundle->fKeyMap = map; 1627 map = NULL; 1628 } 1629 } 1630 } 1631 uprv_free(map); 1632 } 1633 1634 static int32_t U_CALLCONV 1635 compareStringSuffixes(const void *context, const void *l, const void *r) { 1636 struct SResource *left = *((struct SResource **)l); 1637 struct SResource *right = *((struct SResource **)r); 1638 const UChar *lStart = left->u.fString.fChars; 1639 const UChar *lLimit = lStart + left->u.fString.fLength; 1640 const UChar *rStart = right->u.fString.fChars; 1641 const UChar *rLimit = rStart + right->u.fString.fLength; 1642 int32_t diff; 1643 /* compare keys in reverse character order */ 1644 while (lStart < lLimit && rStart < rLimit) { 1645 diff = (int32_t)*--lLimit - (int32_t)*--rLimit; 1646 if (diff != 0) { 1647 return diff; 1648 } 1649 } 1650 /* sort equal suffixes by descending string length */ 1651 return right->u.fString.fLength - left->u.fString.fLength; 1652 } 1653 1654 static int32_t U_CALLCONV 1655 compareStringLengths(const void *context, const void *l, const void *r) { 1656 struct SResource *left = *((struct SResource **)l); 1657 struct SResource *right = *((struct SResource **)r); 1658 int32_t diff; 1659 /* Make "is suffix of another string" compare greater than a non-suffix. */ 1660 diff = (int)(left->u.fString.fSame != NULL) - (int)(right->u.fString.fSame != NULL); 1661 if (diff != 0) { 1662 return diff; 1663 } 1664 /* sort by ascending string length */ 1665 return left->u.fString.fLength - right->u.fString.fLength; 1666 } 1667 1668 static int32_t 1669 string_writeUTF16v2(struct SRBRoot *bundle, struct SResource *res, int32_t utf16Length) { 1670 int32_t length = res->u.fString.fLength; 1671 res->fRes = URES_MAKE_RESOURCE(URES_STRING_V2, utf16Length); 1672 res->fWritten = TRUE; 1673 switch(res->u.fString.fNumCharsForLength) { 1674 case 0: 1675 break; 1676 case 1: 1677 bundle->f16BitUnits[utf16Length++] = (uint16_t)(0xdc00 + length); 1678 break; 1679 case 2: 1680 bundle->f16BitUnits[utf16Length] = (uint16_t)(0xdfef + (length >> 16)); 1681 bundle->f16BitUnits[utf16Length + 1] = (uint16_t)length; 1682 utf16Length += 2; 1683 break; 1684 case 3: 1685 bundle->f16BitUnits[utf16Length] = 0xdfff; 1686 bundle->f16BitUnits[utf16Length + 1] = (uint16_t)(length >> 16); 1687 bundle->f16BitUnits[utf16Length + 2] = (uint16_t)length; 1688 utf16Length += 3; 1689 break; 1690 default: 1691 break; /* will not occur */ 1692 } 1693 u_memcpy(bundle->f16BitUnits + utf16Length, res->u.fString.fChars, length + 1); 1694 return utf16Length + length + 1; 1695 } 1696 1697 static void 1698 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status) { 1699 UHashtable *stringSet; 1700 if (gFormatVersion > 1) { 1701 stringSet = uhash_open(string_hash, string_comp, string_comp, status); 1702 res_preflightStrings(bundle, bundle->fRoot, stringSet, status); 1703 } else { 1704 stringSet = NULL; 1705 } 1706 if (U_FAILURE(*status)) { 1707 uhash_close(stringSet); 1708 return; 1709 } 1710 switch(bundle->fStringsForm) { 1711 case STRINGS_UTF16_V2: 1712 if (bundle->f16BitUnitsLength > 0) { 1713 struct SResource **array; 1714 int32_t count = uhash_count(stringSet); 1715 int32_t i, pos; 1716 /* 1717 * Allocate enough space for the initial NUL and the UTF-16 v2 strings, 1718 * and some extra for URES_TABLE16 and URES_ARRAY16 values. 1719 * Round down to an even number. 1720 */ 1721 int32_t utf16Length = (bundle->f16BitUnitsLength + 20000) & ~1; 1722 bundle->f16BitUnits = (UChar *)uprv_malloc(utf16Length * U_SIZEOF_UCHAR); 1723 array = (struct SResource **)uprv_malloc(count * sizeof(struct SResource **)); 1724 if (bundle->f16BitUnits == NULL || array == NULL) { 1725 uprv_free(bundle->f16BitUnits); 1726 bundle->f16BitUnits = NULL; 1727 uprv_free(array); 1728 uhash_close(stringSet); 1729 *status = U_MEMORY_ALLOCATION_ERROR; 1730 return; 1731 } 1732 bundle->f16BitUnitsCapacity = utf16Length; 1733 /* insert the initial NUL */ 1734 bundle->f16BitUnits[0] = 0; 1735 utf16Length = 1; 1736 ++bundle->f16BitUnitsLength; 1737 for (pos = -1, i = 0; i < count; ++i) { 1738 array[i] = (struct SResource *)uhash_nextElement(stringSet, &pos)->key.pointer; 1739 } 1740 /* Sort the strings so that each one is immediately followed by all of its suffixes. */ 1741 uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **), 1742 compareStringSuffixes, NULL, FALSE, status); 1743 /* 1744 * Make suffixes point into earlier, longer strings that contain them. 1745 * Temporarily use fSame and fSuffixOffset for suffix strings to 1746 * refer to the remaining ones. 1747 */ 1748 if (U_SUCCESS(*status)) { 1749 for (i = 0; i < count;) { 1750 /* 1751 * This string is not a suffix of the previous one; 1752 * write this one and subsume the following ones that are 1753 * suffixes of this one. 1754 */ 1755 struct SResource *res = array[i]; 1756 const UChar *strLimit = res->u.fString.fChars + res->u.fString.fLength; 1757 int32_t j; 1758 for (j = i + 1; j < count; ++j) { 1759 struct SResource *suffixRes = array[j]; 1760 const UChar *s; 1761 const UChar *suffix = suffixRes->u.fString.fChars; 1762 const UChar *suffixLimit = suffix + suffixRes->u.fString.fLength; 1763 int32_t offset = res->u.fString.fLength - suffixRes->u.fString.fLength; 1764 if (offset < 0) { 1765 break; /* suffix cannot be longer than the original */ 1766 } 1767 /* Is it a suffix of the earlier, longer key? */ 1768 for (s = strLimit; suffix < suffixLimit && *--s == *--suffixLimit;) {} 1769 if (suffix == suffixLimit && *s == *suffixLimit) { 1770 if (suffixRes->u.fString.fNumCharsForLength == 0) { 1771 /* yes, point to the earlier string */ 1772 suffixRes->u.fString.fSame = res; 1773 suffixRes->u.fString.fSuffixOffset = offset; 1774 } else { 1775 /* write the suffix by itself if we need explicit length */ 1776 } 1777 } else { 1778 break; /* not a suffix, restart from here */ 1779 } 1780 } 1781 i = j; 1782 } 1783 } 1784 /* 1785 * Re-sort the strings by ascending length (except suffixes last) 1786 * to optimize for URES_TABLE16 and URES_ARRAY16: 1787 * Keep as many as possible within reach of 16-bit offsets. 1788 */ 1789 uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **), 1790 compareStringLengths, NULL, FALSE, status); 1791 if (U_SUCCESS(*status)) { 1792 /* Write the non-suffix strings. */ 1793 for (i = 0; i < count && array[i]->u.fString.fSame == NULL; ++i) { 1794 utf16Length = string_writeUTF16v2(bundle, array[i], utf16Length); 1795 } 1796 /* Write the suffix strings. Make each point to the real string. */ 1797 for (; i < count; ++i) { 1798 struct SResource *res = array[i]; 1799 struct SResource *same = res->u.fString.fSame; 1800 res->fRes = same->fRes + same->u.fString.fNumCharsForLength + res->u.fString.fSuffixOffset; 1801 res->u.fString.fSame = NULL; 1802 res->fWritten = TRUE; 1803 } 1804 } 1805 assert(utf16Length <= bundle->f16BitUnitsLength); 1806 bundle->f16BitUnitsLength = utf16Length; 1807 uprv_free(array); 1808 } 1809 break; 1810 default: 1811 break; 1812 } 1813 uhash_close(stringSet); 1814 } 1815