Home | History | Annotate | Download | only in genrb
      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