]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
3 | * | |
73c04bcf | 4 | * Copyright (C) 2000-2006, 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" */ | |
73c04bcf | 43 | {1, 2, 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 | */ | |
73c04bcf | 396 | uprv_memset(indexes, 0, sizeof(indexes)); |
374ca955 A |
397 | indexes[URES_INDEX_LENGTH]= URES_INDEX_TOP; |
398 | indexes[URES_INDEX_STRINGS_TOP]= (int32_t)(usedOffset>>2); | |
399 | indexes[URES_INDEX_RESOURCES_TOP]= (int32_t)(top>>2); | |
400 | indexes[URES_INDEX_BUNDLE_TOP]= indexes[URES_INDEX_RESOURCES_TOP]; | |
401 | indexes[URES_INDEX_MAX_TABLE_LENGTH]= bundle->fMaxTableLength; | |
402 | ||
73c04bcf A |
403 | /* |
404 | * formatVersion 1.2 (ICU 3.6): | |
405 | * write indexes[URES_INDEX_ATTRIBUTES] with URES_ATT_NO_FALLBACK set or not set | |
406 | * the memset() above initialized all indexes[] to 0 | |
407 | */ | |
408 | if(bundle->noFallback) { | |
409 | indexes[URES_INDEX_ATTRIBUTES]=URES_ATT_NO_FALLBACK; | |
410 | } | |
411 | ||
374ca955 A |
412 | /* write the indexes[] */ |
413 | udata_writeBlock(mem, indexes, sizeof(indexes)); | |
414 | ||
415 | /* write the table key strings */ | |
416 | udata_writeBlock(mem, bundle->fKeys+URES_STRINGS_BOTTOM, | |
417 | bundle->fKeyPoint-URES_STRINGS_BOTTOM); | |
418 | ||
419 | /* write the padding bytes after the table key strings */ | |
b75a7d8f A |
420 | udata_writePadding(mem, pad); |
421 | ||
374ca955 | 422 | /* write all of the bundle contents: the root item and its children */ |
b75a7d8f A |
423 | usedOffset = res_write(mem, bundle->fRoot, usedOffset, status); |
424 | ||
374ca955 A |
425 | size = udata_finish(mem, status); |
426 | if(top != size) { | |
427 | fprintf(stderr, "genrb error: wrote %u bytes but counted %u\n", | |
428 | (int)size, (int)top); | |
429 | *status = U_INTERNAL_PROGRAM_ERROR; | |
430 | } | |
b75a7d8f A |
431 | } |
432 | ||
433 | /* Opening Functions */ | |
374ca955 | 434 | struct SResource* res_open(const struct UString* comment, UErrorCode* status){ |
b75a7d8f A |
435 | struct SResource *res; |
436 | ||
437 | if (U_FAILURE(*status)) { | |
438 | return NULL; | |
439 | } | |
440 | ||
441 | res = (struct SResource *) uprv_malloc(sizeof(struct SResource)); | |
442 | ||
443 | if (res == NULL) { | |
444 | *status = U_MEMORY_ALLOCATION_ERROR; | |
445 | return NULL; | |
446 | } | |
374ca955 A |
447 | uprv_memset(res, 0, sizeof(struct SResource)); |
448 | ||
449 | res->fComment = NULL; | |
450 | if(comment != NULL){ | |
451 | res->fComment = (struct UString *) uprv_malloc(sizeof(struct UString)); | |
452 | if(res->fComment == NULL){ | |
453 | *status = U_MEMORY_ALLOCATION_ERROR; | |
73c04bcf | 454 | uprv_free(res); |
374ca955 A |
455 | return NULL; |
456 | } | |
457 | ustr_init(res->fComment); | |
458 | ustr_cpy(res->fComment, comment, status); | |
459 | } | |
460 | return res; | |
461 | ||
462 | } | |
463 | struct SResource* table_open(struct SRBRoot *bundle, char *tag, const struct UString* comment, UErrorCode *status) { | |
464 | ||
465 | struct SResource *res = res_open(comment, status); | |
b75a7d8f | 466 | |
b75a7d8f A |
467 | res->fKey = bundle_addtag(bundle, tag, status); |
468 | ||
469 | if (U_FAILURE(*status)) { | |
374ca955 | 470 | uprv_free(res->fComment); |
b75a7d8f A |
471 | uprv_free(res); |
472 | return NULL; | |
473 | } | |
474 | ||
475 | res->fNext = NULL; | |
374ca955 A |
476 | |
477 | /* | |
478 | * always open a table not a table32 in case it remains empty - | |
479 | * try to use table32 only when necessary | |
480 | */ | |
481 | res->fType = URES_TABLE; | |
b75a7d8f A |
482 | res->fSize = sizeof(uint16_t); |
483 | ||
484 | res->u.fTable.fCount = 0; | |
485 | res->u.fTable.fChildrenSize = 0; | |
486 | res->u.fTable.fFirst = NULL; | |
487 | res->u.fTable.fRoot = bundle; | |
488 | ||
489 | return res; | |
490 | } | |
491 | ||
73c04bcf | 492 | struct SResource* array_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) { |
b75a7d8f | 493 | |
374ca955 | 494 | struct SResource *res = res_open(comment, status); |
b75a7d8f | 495 | |
374ca955 | 496 | if (U_FAILURE(*status)) { |
b75a7d8f A |
497 | return NULL; |
498 | } | |
499 | ||
500 | res->fType = URES_ARRAY; | |
501 | res->fKey = bundle_addtag(bundle, tag, status); | |
502 | ||
503 | if (U_FAILURE(*status)) { | |
374ca955 | 504 | uprv_free(res->fComment); |
b75a7d8f A |
505 | uprv_free(res); |
506 | return NULL; | |
507 | } | |
508 | ||
509 | res->fNext = NULL; | |
510 | res->fSize = sizeof(int32_t); | |
511 | ||
512 | res->u.fArray.fCount = 0; | |
513 | res->u.fArray.fChildrenSize = 0; | |
514 | res->u.fArray.fFirst = NULL; | |
515 | res->u.fArray.fLast = NULL; | |
516 | ||
517 | return res; | |
518 | } | |
519 | ||
374ca955 A |
520 | struct SResource *string_open(struct SRBRoot *bundle, char *tag, const UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) { |
521 | struct SResource *res = res_open(comment, status); | |
b75a7d8f A |
522 | |
523 | if (U_FAILURE(*status)) { | |
524 | return NULL; | |
525 | } | |
526 | ||
b75a7d8f A |
527 | res->fType = URES_STRING; |
528 | res->fKey = bundle_addtag(bundle, tag, status); | |
529 | ||
530 | if (U_FAILURE(*status)) { | |
374ca955 | 531 | uprv_free(res->fComment); |
b75a7d8f A |
532 | uprv_free(res); |
533 | return NULL; | |
534 | } | |
535 | ||
536 | res->fNext = NULL; | |
537 | ||
538 | res->u.fString.fLength = len; | |
539 | res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1)); | |
540 | ||
541 | if (res->u.fString.fChars == NULL) { | |
542 | *status = U_MEMORY_ALLOCATION_ERROR; | |
543 | uprv_free(res); | |
544 | return NULL; | |
545 | } | |
546 | ||
547 | uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len + 1)); | |
548 | res->fSize = sizeof(int32_t) + sizeof(UChar) * (len+1); | |
549 | ||
550 | return res; | |
551 | } | |
552 | ||
553 | /* TODO: make alias_open and string_open use the same code */ | |
374ca955 A |
554 | struct SResource *alias_open(struct SRBRoot *bundle, char *tag, UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) { |
555 | struct SResource *res = res_open(comment, status); | |
b75a7d8f A |
556 | |
557 | if (U_FAILURE(*status)) { | |
558 | return NULL; | |
559 | } | |
560 | ||
b75a7d8f A |
561 | res->fType = URES_ALIAS; |
562 | res->fKey = bundle_addtag(bundle, tag, status); | |
563 | ||
564 | if (U_FAILURE(*status)) { | |
374ca955 | 565 | uprv_free(res->fComment); |
b75a7d8f A |
566 | uprv_free(res); |
567 | return NULL; | |
568 | } | |
569 | ||
570 | res->fNext = NULL; | |
571 | ||
572 | res->u.fString.fLength = len; | |
573 | res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1)); | |
574 | ||
575 | if (res->u.fString.fChars == NULL) { | |
576 | *status = U_MEMORY_ALLOCATION_ERROR; | |
577 | uprv_free(res); | |
578 | return NULL; | |
579 | } | |
580 | ||
581 | uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len + 1)); | |
582 | res->fSize = sizeof(int32_t) + sizeof(UChar) * (len + 1); | |
583 | ||
584 | return res; | |
585 | } | |
586 | ||
587 | ||
374ca955 A |
588 | struct SResource* intvector_open(struct SRBRoot *bundle, char *tag, const struct UString* comment, UErrorCode *status) { |
589 | struct SResource *res = res_open(comment, status); | |
b75a7d8f A |
590 | |
591 | if (U_FAILURE(*status)) { | |
592 | return NULL; | |
593 | } | |
594 | ||
b75a7d8f A |
595 | res->fType = URES_INT_VECTOR; |
596 | res->fKey = bundle_addtag(bundle, tag, status); | |
597 | ||
598 | if (U_FAILURE(*status)) { | |
374ca955 | 599 | uprv_free(res->fComment); |
b75a7d8f A |
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 | ||
374ca955 A |
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); | |
b75a7d8f A |
621 | |
622 | if (U_FAILURE(*status)) { | |
623 | return NULL; | |
624 | } | |
625 | ||
b75a7d8f A |
626 | res->fType = URES_INT; |
627 | res->fKey = bundle_addtag(bundle, tag, status); | |
628 | ||
629 | if (U_FAILURE(*status)) { | |
374ca955 | 630 | uprv_free(res->fComment); |
b75a7d8f A |
631 | uprv_free(res); |
632 | return NULL; | |
633 | } | |
634 | ||
635 | res->fSize = 0; | |
636 | res->fNext = NULL; | |
637 | res->u.fIntValue.fValue = value; | |
638 | ||
639 | return res; | |
640 | } | |
641 | ||
374ca955 A |
642 | 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) { |
643 | struct SResource *res = res_open(comment, status); | |
b75a7d8f A |
644 | |
645 | if (U_FAILURE(*status)) { | |
646 | return NULL; | |
647 | } | |
648 | ||
b75a7d8f A |
649 | res->fType = URES_BINARY; |
650 | res->fKey = bundle_addtag(bundle, tag, status); | |
651 | ||
652 | if (U_FAILURE(*status)) { | |
374ca955 | 653 | uprv_free(res->fComment); |
b75a7d8f A |
654 | uprv_free(res); |
655 | return NULL; | |
656 | } | |
374ca955 | 657 | |
b75a7d8f A |
658 | res->fNext = NULL; |
659 | ||
660 | res->u.fBinaryValue.fLength = length; | |
661 | res->u.fBinaryValue.fFileName = NULL; | |
662 | if(fileName!=NULL && uprv_strcmp(fileName, "") !=0){ | |
663 | res->u.fBinaryValue.fFileName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(fileName)+1)); | |
664 | uprv_strcpy(res->u.fBinaryValue.fFileName,fileName); | |
665 | } | |
666 | if (length > 0) { | |
667 | res->u.fBinaryValue.fData = (uint8_t *) uprv_malloc(sizeof(uint8_t) * length); | |
668 | ||
669 | if (res->u.fBinaryValue.fData == NULL) { | |
670 | *status = U_MEMORY_ALLOCATION_ERROR; | |
671 | uprv_free(res); | |
672 | return NULL; | |
673 | } | |
674 | ||
675 | uprv_memcpy(res->u.fBinaryValue.fData, data, length); | |
676 | } | |
677 | else { | |
678 | res->u.fBinaryValue.fData = NULL; | |
679 | } | |
680 | ||
681 | res->fSize = sizeof(int32_t) + sizeof(uint8_t) * length + BIN_ALIGNMENT; | |
682 | ||
683 | return res; | |
684 | } | |
685 | ||
374ca955 | 686 | struct SRBRoot *bundle_open(const struct UString* comment, UErrorCode *status) { |
b75a7d8f A |
687 | struct SRBRoot *bundle = NULL; |
688 | ||
689 | if (U_FAILURE(*status)) { | |
690 | return NULL; | |
691 | } | |
692 | ||
693 | bundle = (struct SRBRoot *) uprv_malloc(sizeof(struct SRBRoot)); | |
694 | ||
695 | if (bundle == NULL) { | |
696 | *status = U_MEMORY_ALLOCATION_ERROR; | |
697 | return 0; | |
698 | } | |
374ca955 | 699 | uprv_memset(bundle, 0, sizeof(struct SRBRoot)); |
b75a7d8f A |
700 | |
701 | bundle->fLocale = NULL; | |
374ca955 | 702 | |
b75a7d8f | 703 | bundle->fKeys = (char *) uprv_malloc(sizeof(char) * KEY_SPACE_SIZE); |
374ca955 A |
704 | bundle->fKeysCapacity = KEY_SPACE_SIZE; |
705 | ||
706 | if(comment != NULL){ | |
707 | ||
708 | } | |
b75a7d8f A |
709 | |
710 | if (bundle->fKeys == NULL) { | |
711 | *status = U_MEMORY_ALLOCATION_ERROR; | |
712 | uprv_free(bundle); | |
713 | return NULL; | |
714 | } | |
715 | ||
374ca955 A |
716 | /* formatVersion 1.1: start fKeyPoint after the root item and indexes[] */ |
717 | bundle->fKeyPoint = URES_STRINGS_BOTTOM; | |
718 | uprv_memset(bundle->fKeys, 0, URES_STRINGS_BOTTOM); | |
719 | ||
b75a7d8f | 720 | bundle->fCount = 0; |
374ca955 | 721 | bundle->fRoot = table_open(bundle, NULL, comment, status); |
b75a7d8f A |
722 | |
723 | if (bundle->fRoot == NULL || U_FAILURE(*status)) { | |
374ca955 A |
724 | if (U_SUCCESS(*status)) { |
725 | *status = U_MEMORY_ALLOCATION_ERROR; | |
726 | } | |
b75a7d8f A |
727 | |
728 | uprv_free(bundle->fKeys); | |
729 | uprv_free(bundle); | |
730 | ||
731 | return NULL; | |
732 | } | |
733 | ||
734 | return bundle; | |
735 | } | |
736 | ||
737 | /* Closing Functions */ | |
738 | void table_close(struct SResource *table, UErrorCode *status) { | |
739 | struct SResource *current = NULL; | |
740 | struct SResource *prev = NULL; | |
741 | ||
742 | current = table->u.fTable.fFirst; | |
743 | ||
744 | while (current != NULL) { | |
745 | prev = current; | |
746 | current = current->fNext; | |
747 | ||
748 | res_close(prev, status); | |
749 | } | |
750 | ||
751 | table->u.fTable.fFirst = NULL; | |
752 | } | |
753 | ||
754 | void array_close(struct SResource *array, UErrorCode *status) { | |
755 | struct SResource *current = NULL; | |
756 | struct SResource *prev = NULL; | |
73c04bcf A |
757 | |
758 | if(array==NULL){ | |
759 | return; | |
760 | } | |
b75a7d8f | 761 | current = array->u.fArray.fFirst; |
73c04bcf | 762 | |
b75a7d8f A |
763 | while (current != NULL) { |
764 | prev = current; | |
765 | current = current->fNext; | |
766 | ||
767 | res_close(prev, status); | |
768 | } | |
769 | array->u.fArray.fFirst = NULL; | |
770 | } | |
771 | ||
772 | void string_close(struct SResource *string, UErrorCode *status) { | |
773 | if (string->u.fString.fChars != NULL) { | |
774 | uprv_free(string->u.fString.fChars); | |
775 | string->u.fString.fChars =NULL; | |
776 | } | |
777 | } | |
778 | ||
779 | void alias_close(struct SResource *alias, UErrorCode *status) { | |
780 | if (alias->u.fString.fChars != NULL) { | |
781 | uprv_free(alias->u.fString.fChars); | |
782 | alias->u.fString.fChars =NULL; | |
783 | } | |
784 | } | |
785 | ||
786 | void intvector_close(struct SResource *intvector, UErrorCode *status) { | |
787 | if (intvector->u.fIntVector.fArray != NULL) { | |
788 | uprv_free(intvector->u.fIntVector.fArray); | |
789 | intvector->u.fIntVector.fArray =NULL; | |
790 | } | |
791 | } | |
792 | ||
793 | void int_close(struct SResource *intres, UErrorCode *status) { | |
794 | /* Intentionally left blank */ | |
795 | } | |
796 | ||
797 | void bin_close(struct SResource *binres, UErrorCode *status) { | |
798 | if (binres->u.fBinaryValue.fData != NULL) { | |
799 | uprv_free(binres->u.fBinaryValue.fData); | |
800 | binres->u.fBinaryValue.fData = NULL; | |
801 | } | |
802 | } | |
803 | ||
804 | void res_close(struct SResource *res, UErrorCode *status) { | |
805 | if (res != NULL) { | |
806 | switch(res->fType) { | |
807 | case URES_STRING: | |
808 | string_close(res, status); | |
809 | break; | |
810 | case URES_ALIAS: | |
811 | alias_close(res, status); | |
812 | break; | |
813 | case URES_INT_VECTOR: | |
814 | intvector_close(res, status); | |
815 | break; | |
816 | case URES_BINARY: | |
817 | bin_close(res, status); | |
818 | break; | |
819 | case URES_INT: | |
820 | int_close(res, status); | |
821 | break; | |
822 | case URES_ARRAY: | |
823 | array_close(res, status); | |
824 | break; | |
374ca955 A |
825 | case URES_TABLE: |
826 | case URES_TABLE32: | |
b75a7d8f A |
827 | table_close(res, status); |
828 | break; | |
829 | default: | |
830 | /* Shouldn't happen */ | |
831 | break; | |
832 | } | |
833 | ||
834 | uprv_free(res); | |
835 | } | |
836 | } | |
837 | ||
838 | void bundle_close(struct SRBRoot *bundle, UErrorCode *status) { | |
839 | struct SResource *current = NULL; | |
840 | struct SResource *prev = NULL; | |
841 | ||
842 | if (bundle->fRoot != NULL) { | |
843 | current = bundle->fRoot->u.fTable.fFirst; | |
844 | ||
845 | while (current != NULL) { | |
846 | prev = current; | |
847 | current = current->fNext; | |
848 | ||
849 | res_close(prev, status); | |
850 | } | |
851 | ||
852 | uprv_free(bundle->fRoot); | |
853 | } | |
854 | ||
855 | if (bundle->fLocale != NULL) { | |
856 | uprv_free(bundle->fLocale); | |
857 | } | |
858 | ||
859 | if (bundle->fKeys != NULL) { | |
860 | uprv_free(bundle->fKeys); | |
861 | } | |
862 | ||
863 | uprv_free(bundle); | |
864 | } | |
865 | ||
866 | /* Adding Functions */ | |
867 | void table_add(struct SResource *table, struct SResource *res, int linenumber, UErrorCode *status) { | |
868 | struct SResource *current = NULL; | |
869 | struct SResource *prev = NULL; | |
870 | struct SResTable *list; | |
871 | ||
872 | if (U_FAILURE(*status)) { | |
873 | return; | |
874 | } | |
875 | ||
876 | /* remember this linenumber to report to the user if there is a duplicate key */ | |
877 | res->line = linenumber; | |
878 | ||
879 | /* here we need to traverse the list */ | |
880 | list = &(table->u.fTable); | |
881 | ||
374ca955 A |
882 | if(table->fType == URES_TABLE && res->fKey > 0xffff) { |
883 | /* this table straddles the 64k strings boundary, update to a table32 */ | |
884 | table->fType = URES_TABLE32; | |
885 | ||
886 | /* | |
887 | * increase the size because count and each string offset | |
888 | * increase from uint16_t to int32_t | |
889 | */ | |
890 | table->fSize += (1 + list->fCount) * 2; | |
891 | } | |
892 | ||
b75a7d8f | 893 | ++(list->fCount); |
374ca955 A |
894 | if(list->fCount > (uint32_t)list->fRoot->fMaxTableLength) { |
895 | list->fRoot->fMaxTableLength = list->fCount; | |
896 | } | |
897 | ||
898 | /* | |
899 | * URES_TABLE: 6 bytes = 1 uint16_t key string offset + 1 uint32_t Resource | |
900 | * URES_TABLE32: 8 bytes = 1 int32_t key string offset + 1 uint32_t Resource | |
901 | */ | |
902 | table->fSize += table->fType == URES_TABLE ? 6 : 8; | |
b75a7d8f A |
903 | |
904 | table->u.fTable.fChildrenSize += res->fSize + calcPadding(res->fSize); | |
905 | ||
374ca955 | 906 | if (res->fType == URES_TABLE || res->fType == URES_TABLE32) { |
b75a7d8f A |
907 | table->u.fTable.fChildrenSize += res->u.fTable.fChildrenSize; |
908 | } else if (res->fType == URES_ARRAY) { | |
909 | table->u.fTable.fChildrenSize += res->u.fArray.fChildrenSize; | |
910 | } | |
911 | ||
912 | /* is list still empty? */ | |
913 | if (list->fFirst == NULL) { | |
914 | list->fFirst = res; | |
915 | res->fNext = NULL; | |
916 | return; | |
917 | } | |
918 | ||
919 | current = list->fFirst; | |
920 | ||
921 | while (current != NULL) { | |
922 | if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), ((list->fRoot->fKeys) + (res->fKey))) < 0) { | |
923 | prev = current; | |
924 | current = current->fNext; | |
925 | } else if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), ((list->fRoot->fKeys) + (res->fKey))) > 0) { | |
926 | /* we're either in front of list, or in middle */ | |
927 | if (prev == NULL) { | |
928 | /* front of the list */ | |
929 | list->fFirst = res; | |
930 | } else { | |
931 | /* middle of the list */ | |
932 | prev->fNext = res; | |
933 | } | |
934 | ||
935 | res->fNext = current; | |
936 | return; | |
937 | } else { | |
938 | /* Key already exists! ERROR! */ | |
939 | error(linenumber, "duplicate key '%s' in table, first appeared at line %d", list->fRoot->fKeys + current->fKey, current->line); | |
940 | *status = U_UNSUPPORTED_ERROR; | |
941 | return; | |
942 | } | |
943 | } | |
944 | ||
945 | /* end of list */ | |
946 | prev->fNext = res; | |
947 | res->fNext = NULL; | |
948 | } | |
949 | ||
950 | void array_add(struct SResource *array, struct SResource *res, UErrorCode *status) { | |
951 | if (U_FAILURE(*status)) { | |
952 | return; | |
953 | } | |
954 | ||
955 | if (array->u.fArray.fFirst == NULL) { | |
956 | array->u.fArray.fFirst = res; | |
957 | array->u.fArray.fLast = res; | |
958 | } else { | |
959 | array->u.fArray.fLast->fNext = res; | |
960 | array->u.fArray.fLast = res; | |
961 | } | |
962 | ||
963 | (array->u.fArray.fCount)++; | |
964 | ||
965 | array->fSize += sizeof(uint32_t); | |
966 | array->u.fArray.fChildrenSize += res->fSize + calcPadding(res->fSize); | |
967 | ||
374ca955 | 968 | if (res->fType == URES_TABLE || res->fType == URES_TABLE32) { |
b75a7d8f A |
969 | array->u.fArray.fChildrenSize += res->u.fTable.fChildrenSize; |
970 | } else if (res->fType == URES_ARRAY) { | |
971 | array->u.fArray.fChildrenSize += res->u.fArray.fChildrenSize; | |
972 | } | |
973 | } | |
974 | ||
975 | void intvector_add(struct SResource *intvector, int32_t value, UErrorCode *status) { | |
976 | if (U_FAILURE(*status)) { | |
977 | return; | |
978 | } | |
979 | ||
980 | *(intvector->u.fIntVector.fArray + intvector->u.fIntVector.fCount) = value; | |
981 | intvector->u.fIntVector.fCount++; | |
982 | ||
983 | intvector->fSize += sizeof(uint32_t); | |
984 | } | |
985 | ||
986 | /* Misc Functions */ | |
987 | ||
988 | void bundle_setlocale(struct SRBRoot *bundle, UChar *locale, UErrorCode *status) { | |
989 | ||
990 | if(U_FAILURE(*status)) { | |
991 | return; | |
992 | } | |
993 | ||
994 | if (bundle->fLocale!=NULL) { | |
995 | uprv_free(bundle->fLocale); | |
996 | } | |
997 | ||
998 | bundle->fLocale= (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1)); | |
999 | ||
1000 | if(bundle->fLocale == NULL) { | |
1001 | *status = U_MEMORY_ALLOCATION_ERROR; | |
1002 | return; | |
1003 | } | |
1004 | ||
1005 | /*u_strcpy(bundle->fLocale, locale);*/ | |
1006 | u_UCharsToChars(locale, bundle->fLocale, u_strlen(locale)+1); | |
1007 | ||
1008 | } | |
1009 | ||
374ca955 A |
1010 | |
1011 | int32_t | |
1012 | bundle_addtag(struct SRBRoot *bundle, const char *tag, UErrorCode *status) { | |
1013 | int32_t keypos, length; | |
b75a7d8f A |
1014 | |
1015 | if (U_FAILURE(*status)) { | |
374ca955 | 1016 | return -1; |
b75a7d8f A |
1017 | } |
1018 | ||
1019 | if (tag == NULL) { | |
374ca955 A |
1020 | /* do not set an error: the root table has a NULL tag */ |
1021 | return -1; | |
b75a7d8f A |
1022 | } |
1023 | ||
374ca955 | 1024 | keypos = bundle->fKeyPoint; |
b75a7d8f | 1025 | |
374ca955 | 1026 | bundle->fKeyPoint += length = (int32_t) (uprv_strlen(tag) + 1); |
b75a7d8f | 1027 | |
374ca955 A |
1028 | if (bundle->fKeyPoint >= bundle->fKeysCapacity) { |
1029 | /* overflow - resize the keys buffer */ | |
1030 | bundle->fKeysCapacity += KEY_SPACE_SIZE; | |
1031 | bundle->fKeys = uprv_realloc(bundle->fKeys, bundle->fKeysCapacity); | |
1032 | if(bundle->fKeys == NULL) { | |
1033 | *status = U_MEMORY_ALLOCATION_ERROR; | |
1034 | return -1; | |
1035 | } | |
b75a7d8f A |
1036 | } |
1037 | ||
374ca955 | 1038 | uprv_memcpy(bundle->fKeys + keypos, tag, length); |
b75a7d8f A |
1039 | |
1040 | return keypos; | |
1041 | } |