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