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
28static 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 */
35static struct SResource kNoResource = { RES_NONE };
36
37uint32_t res_write(UNewDataMemory *mem, struct SResource *res,
38                   uint32_t usedOffset, UErrorCode *status);
39
40static 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
54static 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
60void setIncludeCopyright(UBool val){
61    gIncludeCopyright=val;
62}
63
64UBool getIncludeCopyright(void){
65    return gIncludeCopyright;
66}
67
68/* Writing Functions */
69static 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 */
79static 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
88static 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
142static 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
153static 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
174static uint32_t int_write(UNewDataMemory *mem, struct SResource *res,
175                          uint32_t usedOffset, UErrorCode *status) {
176    return usedOffset;
177}
178
179static 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
279uint32_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
312void 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 */
441struct 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
464struct SResource* res_none() {
465    return &kNoResource;
466}
467
468struct 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
496struct 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
523struct 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 */
556struct 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
589struct 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
619struct 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
641struct 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
684struct 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 */
736static 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
752static 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
770static 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
777static 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
784static 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
791static void int_close(struct SResource *intres) {
792    /* Intentionally left blank */
793}
794
795static 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
802void 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
837void 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 */
854void 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
940void 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
965void 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
978void 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
1001int32_t
1002bundle_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