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
calcPadding(uint32_t size)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
setIncludeCopyright(UBool val)60 void setIncludeCopyright(UBool val){
61 gIncludeCopyright=val;
62 }
63
getIncludeCopyright(void)64 UBool getIncludeCopyright(void){
65 return gIncludeCopyright;
66 }
67
68 /* Writing Functions */
string_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)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 */
alias_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)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
array_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)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
intvector_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)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
bin_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)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
int_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)174 static uint32_t int_write(UNewDataMemory *mem, struct SResource *res,
175 uint32_t usedOffset, UErrorCode *status) {
176 return usedOffset;
177 }
178
table_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)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
res_write(UNewDataMemory * mem,struct SResource * res,uint32_t usedOffset,UErrorCode * status)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
bundle_write(struct SRBRoot * bundle,const char * outputDir,const char * outputPkg,char * writtenFilename,int writtenFilenameLen,UErrorCode * status)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 */
res_open(const struct UString * comment,UErrorCode * status)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
res_none()464 struct SResource* res_none() {
465 return &kNoResource;
466 }
467
table_open(struct SRBRoot * bundle,char * tag,const struct UString * comment,UErrorCode * status)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
array_open(struct SRBRoot * bundle,const char * tag,const struct UString * comment,UErrorCode * status)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
string_open(struct SRBRoot * bundle,char * tag,const UChar * value,int32_t len,const struct UString * comment,UErrorCode * status)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 */
alias_open(struct SRBRoot * bundle,char * tag,UChar * value,int32_t len,const struct UString * comment,UErrorCode * status)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
intvector_open(struct SRBRoot * bundle,char * tag,const struct UString * comment,UErrorCode * status)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
int_open(struct SRBRoot * bundle,char * tag,int32_t value,const struct UString * comment,UErrorCode * status)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
bin_open(struct SRBRoot * bundle,const char * tag,uint32_t length,uint8_t * data,const char * fileName,const struct UString * comment,UErrorCode * status)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
bundle_open(const struct UString * comment,UErrorCode * status)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 */
table_close(struct SResource * table)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
array_close(struct SResource * array)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
string_close(struct SResource * string)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
alias_close(struct SResource * alias)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
intvector_close(struct SResource * intvector)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
int_close(struct SResource * intres)791 static void int_close(struct SResource *intres) {
792 /* Intentionally left blank */
793 }
794
bin_close(struct SResource * binres)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
res_close(struct SResource * res)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
bundle_close(struct SRBRoot * bundle,UErrorCode * status)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 */
table_add(struct SResource * table,struct SResource * res,int linenumber,UErrorCode * status)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
array_add(struct SResource * array,struct SResource * res,UErrorCode * status)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
intvector_add(struct SResource * intvector,int32_t value,UErrorCode * status)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
bundle_setlocale(struct SRBRoot * bundle,UChar * locale,UErrorCode * status)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
bundle_addtag(struct SRBRoot * bundle,const char * tag,UErrorCode * status)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