Home | History | Annotate | Download | only in genrb
      1 /*
      2 *******************************************************************************
      3 *
      4 *   Copyright (C) 2000-2008, 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 #define BIN_ALIGNMENT 16
     27 
     28 static UBool gIncludeCopyright = FALSE;
     29 
     30 /*
     31  * res_none() returns the address of kNoResource,
     32  * for use in non-error cases when no resource is to be added to the bundle.
     33  * (NULL is used in error cases.)
     34  */
     35 static struct SResource kNoResource = { RES_NONE };
     36 
     37 uint32_t res_write(UNewDataMemory *mem, struct SResource *res,
     38                    uint32_t usedOffset, UErrorCode *status);
     39 
     40 static const UDataInfo dataInfo= {
     41     sizeof(UDataInfo),
     42     0,
     43 
     44     U_IS_BIG_ENDIAN,
     45     U_CHARSET_FAMILY,
     46     sizeof(UChar),
     47     0,
     48 
     49     {0x52, 0x65, 0x73, 0x42},     /* dataFormat="resb" */
     50     {1, 2, 0, 0},                 /* formatVersion */
     51     {1, 4, 0, 0}                  /* dataVersion take a look at version inside parsed resb*/
     52 };
     53 
     54 static uint8_t calcPadding(uint32_t size) {
     55     /* returns space we need to pad */
     56     return (uint8_t) ((size % sizeof(uint32_t)) ? (sizeof(uint32_t) - (size % sizeof(uint32_t))) : 0);
     57 
     58 }
     59 
     60 void setIncludeCopyright(UBool val){
     61     gIncludeCopyright=val;
     62 }
     63 
     64 UBool getIncludeCopyright(void){
     65     return gIncludeCopyright;
     66 }
     67 
     68 /* Writing Functions */
     69 static uint32_t string_write(UNewDataMemory *mem, struct SResource *res,
     70                              uint32_t usedOffset, UErrorCode *status) {
     71     udata_write32(mem, res->u.fString.fLength);
     72     udata_writeUString(mem, res->u.fString.fChars, res->u.fString.fLength + 1);
     73     udata_writePadding(mem, calcPadding(res->fSize));
     74 
     75     return usedOffset;
     76 }
     77 
     78 /* Writing Functions */
     79 static uint32_t alias_write(UNewDataMemory *mem, struct SResource *res,
     80                              uint32_t usedOffset, UErrorCode *status) {
     81     udata_write32(mem, res->u.fString.fLength);
     82     udata_writeUString(mem, res->u.fString.fChars, res->u.fString.fLength + 1);
     83     udata_writePadding(mem, calcPadding(res->fSize));
     84 
     85     return usedOffset;
     86 }
     87 
     88 static uint32_t array_write(UNewDataMemory *mem, struct SResource *res,
     89                             uint32_t usedOffset, UErrorCode *status) {
     90     uint32_t *resources = NULL;
     91     uint32_t  i         = 0;
     92 
     93     struct SResource *current = NULL;
     94 
     95     if (U_FAILURE(*status)) {
     96         return 0;
     97     }
     98 
     99     if (res->u.fArray.fCount > 0) {
    100         resources = (uint32_t *) uprv_malloc(sizeof(uint32_t) * res->u.fArray.fCount);
    101 
    102         if (resources == NULL) {
    103             *status = U_MEMORY_ALLOCATION_ERROR;
    104             return 0;
    105         }
    106 
    107         current = res->u.fArray.fFirst;
    108         i = 0;
    109 
    110         while (current != NULL) {
    111             if (current->fType == URES_INT) {
    112                 resources[i] = (current->fType << 28) | (current->u.fIntValue.fValue & 0xFFFFFFF);
    113             } else if (current->fType == URES_BINARY) {
    114                 uint32_t uo = usedOffset;
    115 
    116                 usedOffset    = res_write(mem, current, usedOffset, status);
    117                 resources[i]  = (current->fType << 28) | (usedOffset >> 2);
    118                 usedOffset   += current->fSize + calcPadding(current->fSize) - (usedOffset - uo);
    119             } else {
    120                 usedOffset    = res_write(mem, current, usedOffset, status);
    121                 resources[i]  = (current->fType << 28) | (usedOffset >> 2);
    122                 usedOffset   += current->fSize + calcPadding(current->fSize);
    123             }
    124 
    125             i++;
    126             current = current->fNext;
    127         }
    128 
    129         /* usedOffset += res->fSize + pad; */
    130 
    131         udata_write32(mem, res->u.fArray.fCount);
    132         udata_writeBlock(mem, resources, sizeof(uint32_t) * res->u.fArray.fCount);
    133         uprv_free(resources);
    134     } else {
    135         /* array is empty */
    136         udata_write32(mem, 0);
    137     }
    138 
    139     return usedOffset;
    140 }
    141 
    142 static uint32_t intvector_write(UNewDataMemory *mem, struct SResource *res,
    143                                 uint32_t usedOffset, UErrorCode *status) {
    144   uint32_t i = 0;
    145     udata_write32(mem, res->u.fIntVector.fCount);
    146     for(i = 0; i<res->u.fIntVector.fCount; i++) {
    147       udata_write32(mem, res->u.fIntVector.fArray[i]);
    148     }
    149 
    150     return usedOffset;
    151 }
    152 
    153 static uint32_t bin_write(UNewDataMemory *mem, struct SResource *res,
    154                           uint32_t usedOffset, UErrorCode *status) {
    155     uint32_t pad       = 0;
    156     uint32_t extrapad  = calcPadding(res->fSize);
    157     uint32_t dataStart = usedOffset + sizeof(res->u.fBinaryValue.fLength);
    158 
    159     if (dataStart % BIN_ALIGNMENT) {
    160         pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT);
    161         udata_writePadding(mem, pad);
    162         usedOffset += pad;
    163     }
    164 
    165     udata_write32(mem, res->u.fBinaryValue.fLength);
    166     if (res->u.fBinaryValue.fLength > 0) {
    167         udata_writeBlock(mem, res->u.fBinaryValue.fData, res->u.fBinaryValue.fLength);
    168     }
    169     udata_writePadding(mem, (BIN_ALIGNMENT - pad + extrapad));
    170 
    171     return usedOffset;
    172 }
    173 
    174 static uint32_t int_write(UNewDataMemory *mem, struct SResource *res,
    175                           uint32_t usedOffset, UErrorCode *status) {
    176     return usedOffset;
    177 }
    178 
    179 static uint32_t table_write(UNewDataMemory *mem, struct SResource *res,
    180                             uint32_t usedOffset, UErrorCode *status) {
    181     uint8_t   pad       = 0;
    182     uint32_t  i         = 0;
    183     uint16_t *keys16    = NULL;
    184     int32_t  *keys32    = NULL;
    185     uint32_t *resources = NULL;
    186 
    187     struct SResource *current = NULL;
    188 
    189     if (U_FAILURE(*status)) {
    190         return 0;
    191     }
    192 
    193     pad = calcPadding(res->fSize);
    194 
    195     if (res->u.fTable.fCount > 0) {
    196         if(res->fType == URES_TABLE) {
    197             keys16 = (uint16_t *) uprv_malloc(sizeof(uint16_t) * res->u.fTable.fCount);
    198             if (keys16 == NULL) {
    199                 *status = U_MEMORY_ALLOCATION_ERROR;
    200                 return 0;
    201             }
    202         } else {
    203             keys32 = (int32_t *) uprv_malloc(sizeof(int32_t) * res->u.fTable.fCount);
    204             if (keys32 == NULL) {
    205                 *status = U_MEMORY_ALLOCATION_ERROR;
    206                 return 0;
    207             }
    208         }
    209 
    210         resources = (uint32_t *) uprv_malloc(sizeof(uint32_t) * res->u.fTable.fCount);
    211 
    212         if (resources == NULL) {
    213             uprv_free(keys16);
    214             uprv_free(keys32);
    215             *status = U_MEMORY_ALLOCATION_ERROR;
    216             return 0;
    217         }
    218 
    219         current = res->u.fTable.fFirst;
    220         i       = 0;
    221 
    222         while (current != NULL) {
    223             assert(i < res->u.fTable.fCount);
    224 
    225             /* where the key is */
    226             if(res->fType == URES_TABLE) {
    227                 keys16[i] = (uint16_t) current->fKey;
    228             } else {
    229                 keys32[i] = current->fKey;
    230             }
    231 
    232             if (current->fType == URES_INT) {
    233                 resources[i] = (current->fType << 28) | (current->u.fIntValue.fValue & 0xFFFFFFF);
    234             } else if (current->fType == URES_BINARY) {
    235                 uint32_t uo = usedOffset;
    236 
    237                 usedOffset    = res_write(mem, current, usedOffset, status);
    238                 resources[i]  = (current->fType << 28) | (usedOffset >> 2);
    239                 usedOffset   += current->fSize + calcPadding(current->fSize) - (usedOffset - uo);
    240             } else {
    241                 usedOffset    = res_write(mem, current, usedOffset, status);
    242                 resources[i]  = (current->fType << 28) | (usedOffset >> 2);
    243                 usedOffset   += current->fSize + calcPadding(current->fSize);
    244             }
    245 
    246             i++;
    247             current = current->fNext;
    248         }
    249 
    250         if(res->fType == URES_TABLE) {
    251             udata_write16(mem, (uint16_t)res->u.fTable.fCount);
    252 
    253             udata_writeBlock(mem, keys16, sizeof(uint16_t) * res->u.fTable.fCount);
    254             udata_writePadding(mem, pad);
    255         } else {
    256             udata_write32(mem, res->u.fTable.fCount);
    257 
    258             udata_writeBlock(mem, keys32, sizeof(int32_t) * res->u.fTable.fCount);
    259         }
    260 
    261         udata_writeBlock(mem, resources, sizeof(uint32_t) * res->u.fTable.fCount);
    262 
    263         uprv_free(keys16);
    264         uprv_free(keys32);
    265         uprv_free(resources);
    266     } else {
    267         /* table is empty */
    268         if(res->fType == URES_TABLE) {
    269             udata_write16(mem, 0);
    270             udata_writePadding(mem, pad);
    271         } else {
    272             udata_write32(mem, 0);
    273         }
    274     }
    275 
    276     return usedOffset;
    277 }
    278 
    279 uint32_t res_write(UNewDataMemory *mem, struct SResource *res,
    280                    uint32_t usedOffset, UErrorCode *status) {
    281     if (U_FAILURE(*status)) {
    282         return 0;
    283     }
    284 
    285     if (res != NULL) {
    286         switch (res->fType) {
    287         case URES_STRING:
    288             return string_write    (mem, res, usedOffset, status);
    289         case URES_ALIAS:
    290             return alias_write    (mem, res, usedOffset, status);
    291         case URES_INT_VECTOR:
    292             return intvector_write (mem, res, usedOffset, status);
    293         case URES_BINARY:
    294             return bin_write       (mem, res, usedOffset, status);
    295         case URES_INT:
    296             return int_write       (mem, res, usedOffset, status);
    297         case URES_ARRAY:
    298             return array_write     (mem, res, usedOffset, status);
    299         case URES_TABLE:
    300         case URES_TABLE32:
    301             return table_write     (mem, res, usedOffset, status);
    302 
    303         default:
    304             break;
    305         }
    306     }
    307 
    308     *status = U_INTERNAL_PROGRAM_ERROR;
    309     return 0;
    310 }
    311 
    312 void bundle_write(struct SRBRoot *bundle, const char *outputDir, const char *outputPkg, char *writtenFilename, int writtenFilenameLen, UErrorCode *status) {
    313     UNewDataMemory *mem        = NULL;
    314     uint8_t         pad        = 0;
    315     uint32_t        root       = 0;
    316     uint32_t        usedOffset = 0;
    317     uint32_t        top, size;
    318     char            dataName[1024];
    319     int32_t         indexes[URES_INDEX_TOP];
    320 
    321     if (writtenFilename && writtenFilenameLen) {
    322         *writtenFilename = 0;
    323     }
    324 
    325     if (U_FAILURE(*status)) {
    326         return;
    327     }
    328 
    329     if (writtenFilename) {
    330        int32_t off = 0, len = 0;
    331        if (outputDir) {
    332            len = (int32_t)uprv_strlen(outputDir);
    333            if (len > writtenFilenameLen) {
    334                len = writtenFilenameLen;
    335            }
    336            uprv_strncpy(writtenFilename, outputDir, len);
    337        }
    338        if (writtenFilenameLen -= len) {
    339            off += len;
    340            writtenFilename[off] = U_FILE_SEP_CHAR;
    341            if (--writtenFilenameLen) {
    342                ++off;
    343                if(outputPkg != NULL)
    344                {
    345                    uprv_strcpy(writtenFilename+off, outputPkg);
    346                    off += (int32_t)uprv_strlen(outputPkg);
    347                    writtenFilename[off] = '_';
    348                    ++off;
    349                }
    350 
    351                len = (int32_t)uprv_strlen(bundle->fLocale);
    352                if (len > writtenFilenameLen) {
    353                    len = writtenFilenameLen;
    354                }
    355                uprv_strncpy(writtenFilename + off, bundle->fLocale, len);
    356                if (writtenFilenameLen -= len) {
    357                    off += len;
    358                    len = 5;
    359                    if (len > writtenFilenameLen) {
    360                        len = writtenFilenameLen;
    361                    }
    362                    uprv_strncpy(writtenFilename +  off, ".res", len);
    363                }
    364            }
    365        }
    366     }
    367 
    368     if(outputPkg)
    369     {
    370         uprv_strcpy(dataName, outputPkg);
    371         uprv_strcat(dataName, "_");
    372         uprv_strcat(dataName, bundle->fLocale);
    373     }
    374     else
    375     {
    376         uprv_strcpy(dataName, bundle->fLocale);
    377     }
    378 
    379     mem = udata_create(outputDir, "res", dataName, &dataInfo, (gIncludeCopyright==TRUE)? U_COPYRIGHT_STRING:NULL, status);
    380     if(U_FAILURE(*status)){
    381         return;
    382     }
    383     pad = calcPadding(bundle->fKeyPoint);
    384 
    385     usedOffset = bundle->fKeyPoint + pad ; /* top of the strings */
    386 
    387     /* we're gonna put the main table at the end */
    388     top = usedOffset + bundle->fRoot->u.fTable.fChildrenSize;
    389     root = (top) >> 2 | (bundle->fRoot->fType << 28);
    390 
    391     /* write the root item */
    392     udata_write32(mem, root);
    393 
    394     /* add to top the size of the root item */
    395     top += bundle->fRoot->fSize;
    396     top += calcPadding(top);
    397 
    398     /*
    399      * formatVersion 1.1 (ICU 2.8):
    400      * write int32_t indexes[] after root and before the strings
    401      * to make it easier to parse resource bundles in icuswap or from Java etc.
    402      */
    403     uprv_memset(indexes, 0, sizeof(indexes));
    404     indexes[URES_INDEX_LENGTH]=             URES_INDEX_TOP;
    405     indexes[URES_INDEX_STRINGS_TOP]=        (int32_t)(usedOffset>>2);
    406     indexes[URES_INDEX_RESOURCES_TOP]=      (int32_t)(top>>2);
    407     indexes[URES_INDEX_BUNDLE_TOP]=         indexes[URES_INDEX_RESOURCES_TOP];
    408     indexes[URES_INDEX_MAX_TABLE_LENGTH]=   bundle->fMaxTableLength;
    409 
    410     /*
    411      * formatVersion 1.2 (ICU 3.6):
    412      * write indexes[URES_INDEX_ATTRIBUTES] with URES_ATT_NO_FALLBACK set or not set
    413      * the memset() above initialized all indexes[] to 0
    414      */
    415     if(bundle->noFallback) {
    416         indexes[URES_INDEX_ATTRIBUTES]=URES_ATT_NO_FALLBACK;
    417     }
    418 
    419     /* write the indexes[] */
    420     udata_writeBlock(mem, indexes, sizeof(indexes));
    421 
    422     /* write the table key strings */
    423     udata_writeBlock(mem, bundle->fKeys+URES_STRINGS_BOTTOM,
    424                           bundle->fKeyPoint-URES_STRINGS_BOTTOM);
    425 
    426     /* write the padding bytes after the table key strings */
    427     udata_writePadding(mem, pad);
    428 
    429     /* write all of the bundle contents: the root item and its children */
    430     usedOffset = res_write(mem, bundle->fRoot, usedOffset, status);
    431 
    432     size = udata_finish(mem, status);
    433     if(top != size) {
    434         fprintf(stderr, "genrb error: wrote %u bytes but counted %u\n",
    435                 (int)size, (int)top);
    436         *status = U_INTERNAL_PROGRAM_ERROR;
    437     }
    438 }
    439 
    440 /* Opening Functions */
    441 struct SResource* res_open(const struct UString* comment, UErrorCode* status){
    442     struct SResource *res;
    443 
    444     if (U_FAILURE(*status)) {
    445         return NULL;
    446     }
    447 
    448     res = (struct SResource *) uprv_malloc(sizeof(struct SResource));
    449 
    450     if (res == NULL) {
    451         *status = U_MEMORY_ALLOCATION_ERROR;
    452         return NULL;
    453     }
    454     uprv_memset(res, 0, sizeof(struct SResource));
    455 
    456     ustr_init(&res->fComment);
    457     if(comment != NULL){
    458         ustr_cpy(&res->fComment, comment, status);
    459     }
    460     return res;
    461 
    462 }
    463 
    464 struct SResource* res_none() {
    465     return &kNoResource;
    466 }
    467 
    468 struct SResource* table_open(struct SRBRoot *bundle, char *tag,  const struct UString* comment, UErrorCode *status) {
    469 
    470     struct SResource *res = res_open(comment, status);
    471 
    472     res->fKey  = bundle_addtag(bundle, tag, status);
    473 
    474     if (U_FAILURE(*status)) {
    475         res_close(res);
    476         return NULL;
    477     }
    478 
    479     res->fNext = NULL;
    480 
    481     /*
    482      * always open a table not a table32 in case it remains empty -
    483      * try to use table32 only when necessary
    484      */
    485     res->fType = URES_TABLE;
    486     res->fSize = sizeof(uint16_t);
    487 
    488     res->u.fTable.fCount        = 0;
    489     res->u.fTable.fChildrenSize = 0;
    490     res->u.fTable.fFirst        = NULL;
    491     res->u.fTable.fRoot         = bundle;
    492 
    493     return res;
    494 }
    495 
    496 struct SResource* array_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) {
    497 
    498     struct SResource *res = res_open(comment, status);
    499 
    500     if (U_FAILURE(*status)) {
    501         return NULL;
    502     }
    503 
    504     res->fType = URES_ARRAY;
    505     res->fKey  = bundle_addtag(bundle, tag, status);
    506 
    507     if (U_FAILURE(*status)) {
    508         uprv_free(res);
    509         return NULL;
    510     }
    511 
    512     res->fNext = NULL;
    513     res->fSize = sizeof(int32_t);
    514 
    515     res->u.fArray.fCount        = 0;
    516     res->u.fArray.fChildrenSize = 0;
    517     res->u.fArray.fFirst        = NULL;
    518     res->u.fArray.fLast         = NULL;
    519 
    520     return res;
    521 }
    522 
    523 struct SResource *string_open(struct SRBRoot *bundle, char *tag, const UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) {
    524     struct SResource *res = res_open(comment, status);
    525 
    526     if (U_FAILURE(*status)) {
    527         return NULL;
    528     }
    529 
    530     res->fType = URES_STRING;
    531     res->fKey  = bundle_addtag(bundle, tag, status);
    532 
    533     if (U_FAILURE(*status)) {
    534         uprv_free(res);
    535         return NULL;
    536     }
    537 
    538     res->fNext = NULL;
    539 
    540     res->u.fString.fLength = len;
    541     res->u.fString.fChars  = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1));
    542 
    543     if (res->u.fString.fChars == NULL) {
    544         *status = U_MEMORY_ALLOCATION_ERROR;
    545         uprv_free(res);
    546         return NULL;
    547     }
    548 
    549     uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len + 1));
    550     res->fSize = sizeof(int32_t) + sizeof(UChar) * (len+1);
    551 
    552     return res;
    553 }
    554 
    555 /* TODO: make alias_open and string_open use the same code */
    556 struct SResource *alias_open(struct SRBRoot *bundle, char *tag, UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) {
    557     struct SResource *res = res_open(comment, status);
    558 
    559     if (U_FAILURE(*status)) {
    560         return NULL;
    561     }
    562 
    563     res->fType = URES_ALIAS;
    564     res->fKey  = bundle_addtag(bundle, tag, status);
    565 
    566     if (U_FAILURE(*status)) {
    567         uprv_free(res);
    568         return NULL;
    569     }
    570 
    571     res->fNext = NULL;
    572 
    573     res->u.fString.fLength = len;
    574     res->u.fString.fChars  = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1));
    575 
    576     if (res->u.fString.fChars == NULL) {
    577         *status = U_MEMORY_ALLOCATION_ERROR;
    578         uprv_free(res);
    579         return NULL;
    580     }
    581 
    582     uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len + 1));
    583     res->fSize = sizeof(int32_t) + sizeof(UChar) * (len + 1);
    584 
    585     return res;
    586 }
    587 
    588 
    589 struct SResource* intvector_open(struct SRBRoot *bundle, char *tag, const struct UString* comment, UErrorCode *status) {
    590     struct SResource *res = res_open(comment, status);
    591 
    592     if (U_FAILURE(*status)) {
    593         return NULL;
    594     }
    595 
    596     res->fType = URES_INT_VECTOR;
    597     res->fKey  = bundle_addtag(bundle, tag, status);
    598 
    599     if (U_FAILURE(*status)) {
    600         uprv_free(res);
    601         return NULL;
    602     }
    603 
    604     res->fNext = NULL;
    605     res->fSize = sizeof(int32_t);
    606 
    607     res->u.fIntVector.fCount = 0;
    608     res->u.fIntVector.fArray = (uint32_t *) uprv_malloc(sizeof(uint32_t) * RESLIST_MAX_INT_VECTOR);
    609 
    610     if (res->u.fIntVector.fArray == NULL) {
    611         *status = U_MEMORY_ALLOCATION_ERROR;
    612         uprv_free(res);
    613         return NULL;
    614     }
    615 
    616     return res;
    617 }
    618 
    619 struct SResource *int_open(struct SRBRoot *bundle, char *tag, int32_t value, const struct UString* comment, UErrorCode *status) {
    620     struct SResource *res = res_open(comment, status);
    621 
    622     if (U_FAILURE(*status)) {
    623         return NULL;
    624     }
    625 
    626     res->fType = URES_INT;
    627     res->fKey  = bundle_addtag(bundle, tag, status);
    628 
    629     if (U_FAILURE(*status)) {
    630         uprv_free(res);
    631         return NULL;
    632     }
    633 
    634     res->fSize              = 0;
    635     res->fNext              = NULL;
    636     res->u.fIntValue.fValue = value;
    637 
    638     return res;
    639 }
    640 
    641 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) {
    642     struct SResource *res = res_open(comment, status);
    643 
    644     if (U_FAILURE(*status)) {
    645         return NULL;
    646     }
    647 
    648     res->fType = URES_BINARY;
    649     res->fKey  = bundle_addtag(bundle, tag, status);
    650 
    651     if (U_FAILURE(*status)) {
    652         uprv_free(res);
    653         return NULL;
    654     }
    655 
    656     res->fNext = NULL;
    657 
    658     res->u.fBinaryValue.fLength = length;
    659     res->u.fBinaryValue.fFileName = NULL;
    660     if(fileName!=NULL && uprv_strcmp(fileName, "") !=0){
    661         res->u.fBinaryValue.fFileName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(fileName)+1));
    662         uprv_strcpy(res->u.fBinaryValue.fFileName,fileName);
    663     }
    664     if (length > 0) {
    665         res->u.fBinaryValue.fData   = (uint8_t *) uprv_malloc(sizeof(uint8_t) * length);
    666 
    667         if (res->u.fBinaryValue.fData == NULL) {
    668             *status = U_MEMORY_ALLOCATION_ERROR;
    669             uprv_free(res);
    670             return NULL;
    671         }
    672 
    673         uprv_memcpy(res->u.fBinaryValue.fData, data, length);
    674     }
    675     else {
    676         res->u.fBinaryValue.fData = NULL;
    677     }
    678 
    679     res->fSize = sizeof(int32_t) + sizeof(uint8_t) * length + BIN_ALIGNMENT;
    680 
    681     return res;
    682 }
    683 
    684 struct SRBRoot *bundle_open(const struct UString* comment, UErrorCode *status) {
    685     struct SRBRoot *bundle = NULL;
    686 
    687     if (U_FAILURE(*status)) {
    688         return NULL;
    689     }
    690 
    691     bundle = (struct SRBRoot *) uprv_malloc(sizeof(struct SRBRoot));
    692 
    693     if (bundle == NULL) {
    694         *status = U_MEMORY_ALLOCATION_ERROR;
    695         return 0;
    696     }
    697     uprv_memset(bundle, 0, sizeof(struct SRBRoot));
    698 
    699     bundle->fLocale   = NULL;
    700 
    701     bundle->fKeys     = (char *) uprv_malloc(sizeof(char) * KEY_SPACE_SIZE);
    702     bundle->fKeysCapacity = KEY_SPACE_SIZE;
    703 
    704     if(comment != NULL){
    705 
    706     }
    707 
    708     if (bundle->fKeys == NULL) {
    709         *status = U_MEMORY_ALLOCATION_ERROR;
    710         uprv_free(bundle);
    711         return NULL;
    712     }
    713 
    714     /* formatVersion 1.1: start fKeyPoint after the root item and indexes[] */
    715     bundle->fKeyPoint = URES_STRINGS_BOTTOM;
    716     uprv_memset(bundle->fKeys, 0, URES_STRINGS_BOTTOM);
    717 
    718     bundle->fCount = 0;
    719     bundle->fRoot  = table_open(bundle, NULL, comment, status);
    720 
    721     if (bundle->fRoot == NULL || U_FAILURE(*status)) {
    722         if (U_SUCCESS(*status)) {
    723             *status = U_MEMORY_ALLOCATION_ERROR;
    724         }
    725 
    726         uprv_free(bundle->fKeys);
    727         uprv_free(bundle);
    728 
    729         return NULL;
    730     }
    731 
    732     return bundle;
    733 }
    734 
    735 /* Closing Functions */
    736 static void table_close(struct SResource *table) {
    737     struct SResource *current = NULL;
    738     struct SResource *prev    = NULL;
    739 
    740     current = table->u.fTable.fFirst;
    741 
    742     while (current != NULL) {
    743         prev    = current;
    744         current = current->fNext;
    745 
    746         res_close(prev);
    747     }
    748 
    749     table->u.fTable.fFirst = NULL;
    750 }
    751 
    752 static void array_close(struct SResource *array) {
    753     struct SResource *current = NULL;
    754     struct SResource *prev    = NULL;
    755 
    756     if(array==NULL){
    757         return;
    758     }
    759     current = array->u.fArray.fFirst;
    760 
    761     while (current != NULL) {
    762         prev    = current;
    763         current = current->fNext;
    764 
    765         res_close(prev);
    766     }
    767     array->u.fArray.fFirst = NULL;
    768 }
    769 
    770 static void string_close(struct SResource *string) {
    771     if (string->u.fString.fChars != NULL) {
    772         uprv_free(string->u.fString.fChars);
    773         string->u.fString.fChars =NULL;
    774     }
    775 }
    776 
    777 static void alias_close(struct SResource *alias) {
    778     if (alias->u.fString.fChars != NULL) {
    779         uprv_free(alias->u.fString.fChars);
    780         alias->u.fString.fChars =NULL;
    781     }
    782 }
    783 
    784 static void intvector_close(struct SResource *intvector) {
    785     if (intvector->u.fIntVector.fArray != NULL) {
    786         uprv_free(intvector->u.fIntVector.fArray);
    787         intvector->u.fIntVector.fArray =NULL;
    788     }
    789 }
    790 
    791 static void int_close(struct SResource *intres) {
    792     /* Intentionally left blank */
    793 }
    794 
    795 static void bin_close(struct SResource *binres) {
    796     if (binres->u.fBinaryValue.fData != NULL) {
    797         uprv_free(binres->u.fBinaryValue.fData);
    798         binres->u.fBinaryValue.fData = NULL;
    799     }
    800 }
    801 
    802 void res_close(struct SResource *res) {
    803     if (res != NULL) {
    804         switch(res->fType) {
    805         case URES_STRING:
    806             string_close(res);
    807             break;
    808         case URES_ALIAS:
    809             alias_close(res);
    810             break;
    811         case URES_INT_VECTOR:
    812             intvector_close(res);
    813             break;
    814         case URES_BINARY:
    815             bin_close(res);
    816             break;
    817         case URES_INT:
    818             int_close(res);
    819             break;
    820         case URES_ARRAY:
    821             array_close(res);
    822             break;
    823         case URES_TABLE:
    824         case URES_TABLE32:
    825             table_close(res);
    826             break;
    827         default:
    828             /* Shouldn't happen */
    829             break;
    830         }
    831 
    832         ustr_deinit(&res->fComment);
    833         uprv_free(res);
    834     }
    835 }
    836 
    837 void bundle_close(struct SRBRoot *bundle, UErrorCode *status) {
    838     if (bundle->fRoot != NULL) {
    839         res_close(bundle->fRoot);
    840     }
    841 
    842     if (bundle->fLocale != NULL) {
    843         uprv_free(bundle->fLocale);
    844     }
    845 
    846     if (bundle->fKeys != NULL) {
    847         uprv_free(bundle->fKeys);
    848     }
    849 
    850     uprv_free(bundle);
    851 }
    852 
    853 /* Adding Functions */
    854 void table_add(struct SResource *table, struct SResource *res, int linenumber, UErrorCode *status) {
    855     struct SResource *current = NULL;
    856     struct SResource *prev    = NULL;
    857     struct SResTable *list;
    858 
    859     if (U_FAILURE(*status)) {
    860         return;
    861     }
    862     if (res == &kNoResource) {
    863         return;
    864     }
    865 
    866     /* remember this linenumber to report to the user if there is a duplicate key */
    867     res->line = linenumber;
    868 
    869     /* here we need to traverse the list */
    870     list = &(table->u.fTable);
    871 
    872     if(table->fType == URES_TABLE && res->fKey > 0xffff) {
    873         /* this table straddles the 64k strings boundary, update to a table32 */
    874         table->fType = URES_TABLE32;
    875 
    876         /*
    877          * increase the size because count and each string offset
    878          * increase from uint16_t to int32_t
    879          */
    880         table->fSize += (1 + list->fCount) * 2;
    881     }
    882 
    883     ++(list->fCount);
    884     if(list->fCount > (uint32_t)list->fRoot->fMaxTableLength) {
    885         list->fRoot->fMaxTableLength = list->fCount;
    886     }
    887 
    888     /*
    889      * URES_TABLE:   6 bytes = 1 uint16_t key string offset + 1 uint32_t Resource
    890      * URES_TABLE32: 8 bytes = 1 int32_t key string offset + 1 uint32_t Resource
    891      */
    892     table->fSize += table->fType == URES_TABLE ? 6 : 8;
    893 
    894     table->u.fTable.fChildrenSize += res->fSize + calcPadding(res->fSize);
    895 
    896     if (res->fType == URES_TABLE || res->fType == URES_TABLE32) {
    897         table->u.fTable.fChildrenSize += res->u.fTable.fChildrenSize;
    898     } else if (res->fType == URES_ARRAY) {
    899         table->u.fTable.fChildrenSize += res->u.fArray.fChildrenSize;
    900     }
    901 
    902     /* is list still empty? */
    903     if (list->fFirst == NULL) {
    904         list->fFirst = res;
    905         res->fNext   = NULL;
    906         return;
    907     }
    908 
    909     current = list->fFirst;
    910 
    911     while (current != NULL) {
    912         if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), ((list->fRoot->fKeys) + (res->fKey))) < 0) {
    913             prev    = current;
    914             current = current->fNext;
    915         } else if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), ((list->fRoot->fKeys) + (res->fKey))) > 0) {
    916             /* we're either in front of list, or in middle */
    917             if (prev == NULL) {
    918                 /* front of the list */
    919                 list->fFirst = res;
    920             } else {
    921                 /* middle of the list */
    922                 prev->fNext = res;
    923             }
    924 
    925             res->fNext = current;
    926             return;
    927         } else {
    928             /* Key already exists! ERROR! */
    929             error(linenumber, "duplicate key '%s' in table, first appeared at line %d", list->fRoot->fKeys + current->fKey, current->line);
    930             *status = U_UNSUPPORTED_ERROR;
    931             return;
    932         }
    933     }
    934 
    935     /* end of list */
    936     prev->fNext = res;
    937     res->fNext  = NULL;
    938 }
    939 
    940 void array_add(struct SResource *array, struct SResource *res, UErrorCode *status) {
    941     if (U_FAILURE(*status)) {
    942         return;
    943     }
    944 
    945     if (array->u.fArray.fFirst == NULL) {
    946         array->u.fArray.fFirst = res;
    947         array->u.fArray.fLast  = res;
    948     } else {
    949         array->u.fArray.fLast->fNext = res;
    950         array->u.fArray.fLast        = res;
    951     }
    952 
    953     (array->u.fArray.fCount)++;
    954 
    955     array->fSize += sizeof(uint32_t);
    956     array->u.fArray.fChildrenSize += res->fSize + calcPadding(res->fSize);
    957 
    958     if (res->fType == URES_TABLE || res->fType == URES_TABLE32) {
    959         array->u.fArray.fChildrenSize += res->u.fTable.fChildrenSize;
    960     } else if (res->fType == URES_ARRAY) {
    961         array->u.fArray.fChildrenSize += res->u.fArray.fChildrenSize;
    962     }
    963 }
    964 
    965 void intvector_add(struct SResource *intvector, int32_t value, UErrorCode *status) {
    966     if (U_FAILURE(*status)) {
    967         return;
    968     }
    969 
    970     *(intvector->u.fIntVector.fArray + intvector->u.fIntVector.fCount) = value;
    971     intvector->u.fIntVector.fCount++;
    972 
    973     intvector->fSize += sizeof(uint32_t);
    974 }
    975 
    976 /* Misc Functions */
    977 
    978 void bundle_setlocale(struct SRBRoot *bundle, UChar *locale, UErrorCode *status) {
    979 
    980     if(U_FAILURE(*status)) {
    981         return;
    982     }
    983 
    984     if (bundle->fLocale!=NULL) {
    985         uprv_free(bundle->fLocale);
    986     }
    987 
    988     bundle->fLocale= (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1));
    989 
    990     if(bundle->fLocale == NULL) {
    991         *status = U_MEMORY_ALLOCATION_ERROR;
    992         return;
    993     }
    994 
    995     /*u_strcpy(bundle->fLocale, locale);*/
    996     u_UCharsToChars(locale, bundle->fLocale, u_strlen(locale)+1);
    997 
    998 }
    999 
   1000 
   1001 int32_t
   1002 bundle_addtag(struct SRBRoot *bundle, const char *tag, UErrorCode *status) {
   1003     int32_t keypos, length;
   1004 
   1005     if (U_FAILURE(*status)) {
   1006         return -1;
   1007     }
   1008 
   1009     if (tag == NULL) {
   1010         /* do not set an error: the root table has a NULL tag */
   1011         return -1;
   1012     }
   1013 
   1014     keypos = bundle->fKeyPoint;
   1015 
   1016     bundle->fKeyPoint += length = (int32_t) (uprv_strlen(tag) + 1);
   1017 
   1018     if (bundle->fKeyPoint >= bundle->fKeysCapacity) {
   1019         /* overflow - resize the keys buffer */
   1020         bundle->fKeysCapacity += KEY_SPACE_SIZE;
   1021         bundle->fKeys = uprv_realloc(bundle->fKeys, bundle->fKeysCapacity);
   1022         if(bundle->fKeys == NULL) {
   1023             *status = U_MEMORY_ALLOCATION_ERROR;
   1024             return -1;
   1025         }
   1026     }
   1027 
   1028     uprv_memcpy(bundle->fKeys + keypos, tag, length);
   1029 
   1030     return keypos;
   1031 }
   1032