intl/icu/source/tools/genrb/reslist.c

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

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

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

     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 */
    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"
    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
    37 static UBool gIncludeCopyright = FALSE;
    38 static UBool gUsePoolBundle = FALSE;
    39 static int32_t gFormatVersion = 2;
    41 static UChar gEmptyString = 0;
    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 };
    49 enum {
    50     MAX_IMPLICIT_STRING_LENGTH = 40  /* do not store the length explicitly for such strings */
    51 };
    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 };
    60 static UDataInfo dataInfo= {
    61     sizeof(UDataInfo),
    62     0,
    64     U_IS_BIG_ENDIAN,
    65     U_CHARSET_FAMILY,
    66     sizeof(UChar),
    67     0,
    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 };
    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 };
    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);
    84 }
    86 void setIncludeCopyright(UBool val){
    87     gIncludeCopyright=val;
    88 }
    90 UBool getIncludeCopyright(void){
    91     return gIncludeCopyright;
    92 }
    94 void setFormatVersion(int32_t formatVersion) {
    95     gFormatVersion = formatVersion;
    96 }
    98 void setUsePoolBundle(UBool use) {
    99     gUsePoolBundle = use;
   100 }
   102 static void
   103 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status);
   105 /* Writing Functions */
   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);
   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);
   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);
   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 }
   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 }
   185 static int32_t
   186 mapKey(struct SRBRoot *bundle, int32_t oldpos) {
   187     const KeyMapEntry *map = bundle->fKeyMap;
   188     int32_t i, start, limit;
   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 }
   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 }
   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 }
   233 static void
   234 array_write16(struct SRBRoot *bundle, struct SResource *res,
   235               UErrorCode *status) {
   236     struct SResource *current;
   237     int32_t res16 = 0;
   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 }
   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;
   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 }
   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 }
   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 }
   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);
   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 }
   399 static void
   400 array_preWrite(uint32_t *byteOffset,
   401                struct SRBRoot *bundle, struct SResource *res,
   402                UErrorCode *status) {
   403     struct SResource *current;
   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 }
   415 static void
   416 table_preWrite(uint32_t *byteOffset,
   417                struct SRBRoot *bundle, struct SResource *res,
   418                UErrorCode *status) {
   419     struct SResource *current;
   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 }
   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 }
   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 }
   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 }
   513 static void array_write(UNewDataMemory *mem, uint32_t *byteOffset,
   514                         struct SRBRoot *bundle, struct SResource *res,
   515                         UErrorCode *status) {
   516     uint32_t  i;
   518     struct SResource *current = NULL;
   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);
   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 }
   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 }
   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);
   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     }
   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 }
   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;
   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);
   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 }
   604 void res_write(UNewDataMemory *mem, uint32_t *byteOffset,
   605                struct SRBRoot *bundle, struct SResource *res,
   606                UErrorCode *status) {
   607     uint8_t paddingSize;
   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 }
   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];
   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     }
   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;
   694     byteOffset = bundle->fKeysTop + bundle->f16BitUnitsLength * 2;
   695     res_preWrite(&byteOffset, bundle, bundle->fRoot, status);
   697     /* total size including the root item */
   698     top = byteOffset;
   700     if (U_FAILURE(*status)) {
   701         return;
   702     }
   704     if (writtenFilename && writtenFilenameLen) {
   705         *writtenFilename = 0;
   706     }
   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                }
   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     }
   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     }
   758     uprv_memcpy(dataInfo.formatVersion, gFormatVersions + gFormatVersion, sizeof(UVersionInfo));
   760     mem = udata_create(outputDir, "res", dataName, &dataInfo, (gIncludeCopyright==TRUE)? U_COPYRIGHT_STRING:NULL, status);
   761     if(U_FAILURE(*status)){
   762         return;
   763     }
   765     /* write the root item */
   766     udata_write32(mem, bundle->fRoot->fRes);
   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;
   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     }
   808     /* write the indexes[] */
   809     udata_writeBlock(mem, indexes, bundle->fIndexLength*4);
   811     /* write the table key strings */
   812     udata_writeBlock(mem, bundle->fKeys+bundle->fKeysBottom,
   813                           bundle->fKeysTop-bundle->fKeysBottom);
   815     /* write the v2 UTF-16 strings, URES_TABLE16 and URES_ARRAY16 */
   816     udata_writeBlock(mem, bundle->f16BitUnits, bundle->f16BitUnitsLength*2);
   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);
   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 }
   831 /* Opening Functions */
   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);
   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     }
   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;
   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 }
   865 struct SResource* res_none() {
   866     return (struct SResource*)&kNoResource;
   867 }
   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 }
   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 }
   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 }
   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 }
   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;
   910     if (len == 0 && gFormatVersion > 1) {
   911         res->u.fString.fChars = &gEmptyString;
   912         res->fRes = 0;
   913         res->fWritten = TRUE;
   914         return res;
   915     }
   917     res->u.fString.fLength = len;
   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));
   933         if (res->u.fString.fChars == NULL) {
   934             *status = U_MEMORY_ALLOCATION_ERROR;
   935             uprv_free(res);
   936             return NULL;
   937         }
   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         }
   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 }
   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     }
   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 }
   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;
  1001     res->fType = URES_INT_VECTOR;
  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;
  1010     return res;
  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;
  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;
  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;
  1030     res->fType = URES_BINARY;
  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);
  1038     if (length > 0) {
  1039         res->u.fBinaryValue.fData   = (uint8_t *) uprv_malloc(sizeof(uint8_t) * length);
  1041         if (res->u.fBinaryValue.fData == NULL) {
  1042             *status = U_MEMORY_ALLOCATION_ERROR;
  1043             uprv_free(res);
  1044             return NULL;
  1047         uprv_memcpy(res->u.fBinaryValue.fData, data, length);
  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;
  1057     return res;
  1060 struct SRBRoot *bundle_open(const struct UString* comment, UBool isPoolBundle, UErrorCode *status) {
  1061     struct SRBRoot *bundle;
  1063     if (U_FAILURE(*status)) {
  1064         return NULL;
  1067     bundle = (struct SRBRoot *) uprv_malloc(sizeof(struct SRBRoot));
  1068     if (bundle == NULL) {
  1069         *status = U_MEMORY_ALLOCATION_ERROR;
  1070         return 0;
  1072     uprv_memset(bundle, 0, sizeof(struct SRBRoot));
  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;
  1080         bundle_close(bundle, status);
  1081         return NULL;
  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;
  1095     bundle->fKeysBottom = (1 /* root */ + bundle->fIndexLength) * 4;
  1096     uprv_memset(bundle->fKeys, 0, bundle->fKeysBottom);
  1097     bundle->fKeysTop = bundle->fKeysBottom;
  1099     if (gFormatVersion == 1) {
  1100         bundle->fStringsForm = STRINGS_UTF16_V1;
  1101     } else {
  1102         bundle->fStringsForm = STRINGS_UTF16_V2;
  1105     return bundle;
  1108 /* Closing Functions */
  1109 static void table_close(struct SResource *table) {
  1110     struct SResource *current = NULL;
  1111     struct SResource *prev    = NULL;
  1113     current = table->u.fTable.fFirst;
  1115     while (current != NULL) {
  1116         prev    = current;
  1117         current = current->fNext;
  1119         res_close(prev);
  1122     table->u.fTable.fFirst = NULL;
  1125 static void array_close(struct SResource *array) {
  1126     struct SResource *current = NULL;
  1127     struct SResource *prev    = NULL;
  1129     if(array==NULL){
  1130         return;
  1132     current = array->u.fArray.fFirst;
  1134     while (current != NULL) {
  1135         prev    = current;
  1136         current = current->fNext;
  1138         res_close(prev);
  1140     array->u.fArray.fFirst = NULL;
  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;
  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;
  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;
  1167 static void int_close(struct SResource *intres) {
  1168     /* Intentionally left blank */
  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;
  1176     if (binres->u.fBinaryValue.fFileName != NULL) {
  1177         uprv_free(binres->u.fBinaryValue.fFileName);
  1178         binres->u.fBinaryValue.fFileName = NULL;
  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;
  1211         ustr_deinit(&res->fComment);
  1212         uprv_free(res);
  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);
  1226 void bundle_closeString(struct SRBRoot *bundle, struct SResource *string) {
  1227     if (bundle->fStringSet != NULL) {
  1228         uhash_remove(bundle->fStringSet, string);
  1230     string_close(string);
  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;
  1240     if (U_FAILURE(*status)) {
  1241         return;
  1243     if (res == &kNoResource) {
  1244         return;
  1247     /* remember this linenumber to report to the user if there is a duplicate key */
  1248     res->line = linenumber;
  1250     /* here we need to traverse the list */
  1251     list = &(table->u.fTable);
  1252     ++(list->fCount);
  1254     /* is list still empty? */
  1255     if (list->fFirst == NULL) {
  1256         list->fFirst = res;
  1257         res->fNext   = NULL;
  1258         return;
  1261     resKeyString = list->fRoot->fKeys + res->fKey;
  1263     current = list->fFirst;
  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);
  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;
  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;
  1300     /* end of list */
  1301     prev->fNext = res;
  1302     res->fNext  = NULL;
  1305 void array_add(struct SResource *array, struct SResource *res, UErrorCode *status) {
  1306     if (U_FAILURE(*status)) {
  1307         return;
  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;
  1318     (array->u.fArray.fCount)++;
  1321 void intvector_add(struct SResource *intvector, int32_t value, UErrorCode *status) {
  1322     if (U_FAILURE(*status)) {
  1323         return;
  1326     *(intvector->u.fIntVector.fArray + intvector->u.fIntVector.fCount) = value;
  1327     intvector->u.fIntVector.fCount++;
  1330 /* Misc Functions */
  1332 void bundle_setlocale(struct SRBRoot *bundle, UChar *locale, UErrorCode *status) {
  1334     if(U_FAILURE(*status)) {
  1335         return;
  1338     if (bundle->fLocale!=NULL) {
  1339         uprv_free(bundle->fLocale);
  1342     bundle->fLocale= (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1));
  1344     if(bundle->fLocale == NULL) {
  1345         *status = U_MEMORY_ALLOCATION_ERROR;
  1346         return;
  1349     /*u_strcpy(bundle->fLocale, locale);*/
  1350     u_UCharsToChars(locale, bundle->fLocale, u_strlen(locale)+1);
  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;
  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;
  1368     return getKeyString(bundle, res->fKey);
  1371 const char *
  1372 bundle_getKeyBytes(struct SRBRoot *bundle, int32_t *pLength) {
  1373     *pLength = bundle->fKeysTop - bundle->fKeysBottom;
  1374     return bundle->fKeys + bundle->fKeysBottom;
  1377 int32_t
  1378 bundle_addKeyBytes(struct SRBRoot *bundle, const char *keyBytes, int32_t length, UErrorCode *status) {
  1379     int32_t keypos;
  1381     if (U_FAILURE(*status)) {
  1382         return -1;
  1384     if (length < 0 || (keyBytes == NULL && length != 0)) {
  1385         *status = U_ILLEGAL_ARGUMENT_ERROR;
  1386         return -1;
  1388     if (length == 0) {
  1389         return bundle->fKeysTop;
  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;
  1404     uprv_memcpy(bundle->fKeys + keypos, keyBytes, length);
  1406     return keypos;
  1409 int32_t
  1410 bundle_addtag(struct SRBRoot *bundle, const char *tag, UErrorCode *status) {
  1411     int32_t keypos;
  1413     if (U_FAILURE(*status)) {
  1414         return -1;
  1417     if (tag == NULL) {
  1418         /* no error: the root table and array items have no keys */
  1419         return -1;
  1422     keypos = bundle_addKeyBytes(bundle, tag, (int32_t)(uprv_strlen(tag) + 1), status);
  1423     if (U_SUCCESS(*status)) {
  1424         ++bundle->fKeysCount;
  1426     return keypos;
  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;
  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;
  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;
  1468     /* Sort pool bundle keys first (negative oldpos), and otherwise keys in parsing order. */
  1469     return compareInt32(lPos, rPos);
  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);
  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);
  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;
  1491     map = (KeyMapEntry *)uprv_malloc(keysCount * sizeof(KeyMapEntry));
  1492     if (map == NULL) {
  1493         *status = U_MEMORY_ALLOCATION_ERROR;
  1494         return;
  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 */
  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 */
  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;
  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 */
  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 */
  1559             i = j;
  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;
  1582                         /* move the key characters to their new position */
  1583                         keys[newpos++] = keys[oldpos++];
  1586                 assert(i == keysCount);
  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;
  1599     uprv_free(map);
  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;
  1618     /* sort equal suffixes by descending string length */
  1619     return right->u.fString.fLength - left->u.fString.fLength;
  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;
  1632     /* sort by ascending string length */
  1633     return left->u.fString.fLength - right->u.fString.fLength;
  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 */
  1661     u_memcpy(bundle->f16BitUnits + utf16Length, res->u.fString.fChars, length + 1);
  1662     return utf16Length + length + 1;
  1665 static void
  1666 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status) {
  1667     if (U_FAILURE(*status)) {
  1668         return;
  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;
  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;
  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 */
  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 */
  1736                         } else {
  1737                             break;  /* not a suffix, restart from here */
  1740                     i = j;
  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);
  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;
  1764             assert(utf16Length <= bundle->f16BitUnitsLength);
  1765             bundle->f16BitUnitsLength = utf16Length;
  1766             uprv_free(array);
  1768         break;
  1769     default:
  1770         break;

mercurial