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