]> git.saurik.com Git - apple/icu.git/blob - icuSources/tools/genrb/reslist.c
ICU-491.11.3.tar.gz
[apple/icu.git] / icuSources / tools / genrb / reslist.c
1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 2000-2011, 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 #include "uarrsort.h"
27 #include "uelement.h"
28 #include "uinvchar.h"
29 #include "ustr_imp.h"
30
31 /*
32 * Align binary data at a 16-byte offset from the start of the resource bundle,
33 * to be safe for any data type it may contain.
34 */
35 #define BIN_ALIGNMENT 16
36
37 static UBool gIncludeCopyright = FALSE;
38 static UBool gUsePoolBundle = FALSE;
39 static int32_t gFormatVersion = 2;
40
41 static UChar gEmptyString = 0;
42
43 /* How do we store string values? */
44 enum {
45 STRINGS_UTF16_V1, /* formatVersion 1: int length + UChars + NUL + padding to 4 bytes */
46 STRINGS_UTF16_V2 /* formatVersion 2: optional length in 1..3 UChars + UChars + NUL */
47 };
48
49 enum {
50 MAX_IMPLICIT_STRING_LENGTH = 40 /* do not store the length explicitly for such strings */
51 };
52
53 /*
54 * res_none() returns the address of kNoResource,
55 * for use in non-error cases when no resource is to be added to the bundle.
56 * (NULL is used in error cases.)
57 */
58 static const struct SResource kNoResource = { URES_NONE };
59
60 static UDataInfo dataInfo= {
61 sizeof(UDataInfo),
62 0,
63
64 U_IS_BIG_ENDIAN,
65 U_CHARSET_FAMILY,
66 sizeof(UChar),
67 0,
68
69 {0x52, 0x65, 0x73, 0x42}, /* dataFormat="ResB" */
70 {1, 3, 0, 0}, /* formatVersion */
71 {1, 4, 0, 0} /* dataVersion take a look at version inside parsed resb*/
72 };
73
74 static const UVersionInfo gFormatVersions[3] = { /* indexed by a major-formatVersion integer */
75 { 0, 0, 0, 0 },
76 { 1, 3, 0, 0 },
77 { 2, 0, 0, 0 }
78 };
79
80 static uint8_t calcPadding(uint32_t size) {
81 /* returns space we need to pad */
82 return (uint8_t) ((size % sizeof(uint32_t)) ? (sizeof(uint32_t) - (size % sizeof(uint32_t))) : 0);
83
84 }
85
86 void setIncludeCopyright(UBool val){
87 gIncludeCopyright=val;
88 }
89
90 UBool getIncludeCopyright(void){
91 return gIncludeCopyright;
92 }
93
94 void setFormatVersion(int32_t formatVersion) {
95 gFormatVersion = formatVersion;
96 }
97
98 void setUsePoolBundle(UBool use) {
99 gUsePoolBundle = use;
100 }
101
102 static void
103 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status);
104
105 /* Writing Functions */
106
107 /*
108 * type_write16() functions write resource values into f16BitUnits
109 * and determine the resource item word, if possible.
110 */
111 static void
112 res_write16(struct SRBRoot *bundle, struct SResource *res,
113 UErrorCode *status);
114
115 /*
116 * type_preWrite() functions calculate ("preflight") and advance the *byteOffset
117 * by the size of their data in the binary file and
118 * determine the resource item word.
119 * Most type_preWrite() functions may add any number of bytes, but res_preWrite()
120 * will always pad it to a multiple of 4.
121 * The resource item type may be a related subtype of the fType.
122 *
123 * The type_preWrite() and type_write() functions start and end at the same
124 * byteOffset values.
125 * Prewriting allows bundle_write() to determine the root resource item word,
126 * before actually writing the bundle contents to the file,
127 * which is necessary because the root item is stored at the beginning.
128 */
129 static void
130 res_preWrite(uint32_t *byteOffset,
131 struct SRBRoot *bundle, struct SResource *res,
132 UErrorCode *status);
133
134 /*
135 * type_write() functions write their data to mem and update the byteOffset
136 * in parallel.
137 * (A kingdom for C++ and polymorphism...)
138 */
139 static void
140 res_write(UNewDataMemory *mem, uint32_t *byteOffset,
141 struct SRBRoot *bundle, struct SResource *res,
142 UErrorCode *status);
143
144 static uint16_t *
145 reserve16BitUnits(struct SRBRoot *bundle, int32_t length, UErrorCode *status) {
146 if (U_FAILURE(*status)) {
147 return NULL;
148 }
149 if ((bundle->f16BitUnitsLength + length) > bundle->f16BitUnitsCapacity) {
150 uint16_t *newUnits;
151 int32_t capacity = 2 * bundle->f16BitUnitsCapacity + length + 1024;
152 capacity &= ~1; /* ensures padding fits if f16BitUnitsLength needs it */
153 newUnits = (uint16_t *)uprv_malloc(capacity * 2);
154 if (newUnits == NULL) {
155 *status = U_MEMORY_ALLOCATION_ERROR;
156 return NULL;
157 }
158 if (bundle->f16BitUnitsLength > 0) {
159 uprv_memcpy(newUnits, bundle->f16BitUnits, bundle->f16BitUnitsLength * 2);
160 } else {
161 newUnits[0] = 0;
162 bundle->f16BitUnitsLength = 1;
163 }
164 uprv_free(bundle->f16BitUnits);
165 bundle->f16BitUnits = newUnits;
166 bundle->f16BitUnitsCapacity = capacity;
167 }
168 return bundle->f16BitUnits + bundle->f16BitUnitsLength;
169 }
170
171 static int32_t
172 makeRes16(uint32_t resWord) {
173 uint32_t type, offset;
174 if (resWord == 0) {
175 return 0; /* empty string */
176 }
177 type = RES_GET_TYPE(resWord);
178 offset = RES_GET_OFFSET(resWord);
179 if (type == URES_STRING_V2 && offset <= 0xffff) {
180 return (int32_t)offset;
181 }
182 return -1;
183 }
184
185 static int32_t
186 mapKey(struct SRBRoot *bundle, int32_t oldpos) {
187 const KeyMapEntry *map = bundle->fKeyMap;
188 int32_t i, start, limit;
189
190 /* do a binary search for the old, pre-bundle_compactKeys() key offset */
191 start = bundle->fPoolBundleKeysCount;
192 limit = start + bundle->fKeysCount;
193 while (start < limit - 1) {
194 i = (start + limit) / 2;
195 if (oldpos < map[i].oldpos) {
196 limit = i;
197 } else {
198 start = i;
199 }
200 }
201 assert(oldpos == map[start].oldpos);
202 return map[start].newpos;
203 }
204
205 static uint16_t
206 makeKey16(struct SRBRoot *bundle, int32_t key) {
207 if (key >= 0) {
208 return (uint16_t)key;
209 } else {
210 return (uint16_t)(key + bundle->fLocalKeyLimit); /* offset in the pool bundle */
211 }
212 }
213
214 /*
215 * Only called for UTF-16 v1 strings and duplicate UTF-16 v2 strings.
216 * For unique UTF-16 v2 strings, res_write16() sees fRes != RES_BOGUS
217 * and exits early.
218 */
219 static void
220 string_write16(struct SRBRoot *bundle, struct SResource *res, UErrorCode *status) {
221 struct SResource *same;
222 if ((same = res->u.fString.fSame) != NULL) {
223 /* This is a duplicate. */
224 if (same->fRes == RES_BOGUS) {
225 /* The original has not been visited yet. */
226 string_write16(bundle, same, status);
227 }
228 res->fRes = same->fRes;
229 res->fWritten = same->fWritten;
230 }
231 }
232
233 static void
234 array_write16(struct SRBRoot *bundle, struct SResource *res,
235 UErrorCode *status) {
236 struct SResource *current;
237 int32_t res16 = 0;
238
239 if (U_FAILURE(*status)) {
240 return;
241 }
242 if (res->u.fArray.fCount == 0 && gFormatVersion > 1) {
243 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_ARRAY);
244 res->fWritten = TRUE;
245 return;
246 }
247 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) {
248 res_write16(bundle, current, status);
249 res16 |= makeRes16(current->fRes);
250 }
251 if (U_SUCCESS(*status) && res->u.fArray.fCount <= 0xffff && res16 >= 0 && gFormatVersion > 1) {
252 uint16_t *p16 = reserve16BitUnits(bundle, 1 + res->u.fArray.fCount, status);
253 if (U_SUCCESS(*status)) {
254 res->fRes = URES_MAKE_RESOURCE(URES_ARRAY16, bundle->f16BitUnitsLength);
255 *p16++ = (uint16_t)res->u.fArray.fCount;
256 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) {
257 *p16++ = (uint16_t)makeRes16(current->fRes);
258 }
259 bundle->f16BitUnitsLength += 1 + res->u.fArray.fCount;
260 res->fWritten = TRUE;
261 }
262 }
263 }
264
265 static void
266 table_write16(struct SRBRoot *bundle, struct SResource *res,
267 UErrorCode *status) {
268 struct SResource *current;
269 int32_t maxKey = 0, maxPoolKey = 0x80000000;
270 int32_t res16 = 0;
271 UBool hasLocalKeys = FALSE, hasPoolKeys = FALSE;
272
273 if (U_FAILURE(*status)) {
274 return;
275 }
276 if (res->u.fTable.fCount == 0 && gFormatVersion > 1) {
277 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_TABLE);
278 res->fWritten = TRUE;
279 return;
280 }
281 /* Find the smallest table type that fits the data. */
282 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) {
283 int32_t key;
284 res_write16(bundle, current, status);
285 if (bundle->fKeyMap == NULL) {
286 key = current->fKey;
287 } else {
288 key = current->fKey = mapKey(bundle, current->fKey);
289 }
290 if (key >= 0) {
291 hasLocalKeys = TRUE;
292 if (key > maxKey) {
293 maxKey = key;
294 }
295 } else {
296 hasPoolKeys = TRUE;
297 if (key > maxPoolKey) {
298 maxPoolKey = key;
299 }
300 }
301 res16 |= makeRes16(current->fRes);
302 }
303 if (U_FAILURE(*status)) {
304 return;
305 }
306 if(res->u.fTable.fCount > (uint32_t)bundle->fMaxTableLength) {
307 bundle->fMaxTableLength = res->u.fTable.fCount;
308 }
309 maxPoolKey &= 0x7fffffff;
310 if (res->u.fTable.fCount <= 0xffff &&
311 (!hasLocalKeys || maxKey < bundle->fLocalKeyLimit) &&
312 (!hasPoolKeys || maxPoolKey < (0x10000 - bundle->fLocalKeyLimit))
313 ) {
314 if (res16 >= 0 && gFormatVersion > 1) {
315 uint16_t *p16 = reserve16BitUnits(bundle, 1 + res->u.fTable.fCount * 2, status);
316 if (U_SUCCESS(*status)) {
317 /* 16-bit count, key offsets and values */
318 res->fRes = URES_MAKE_RESOURCE(URES_TABLE16, bundle->f16BitUnitsLength);
319 *p16++ = (uint16_t)res->u.fTable.fCount;
320 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) {
321 *p16++ = makeKey16(bundle, current->fKey);
322 }
323 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) {
324 *p16++ = (uint16_t)makeRes16(current->fRes);
325 }
326 bundle->f16BitUnitsLength += 1 + res->u.fTable.fCount * 2;
327 res->fWritten = TRUE;
328 }
329 } else {
330 /* 16-bit count, 16-bit key offsets, 32-bit values */
331 res->u.fTable.fType = URES_TABLE;
332 }
333 } else {
334 /* 32-bit count, key offsets and values */
335 res->u.fTable.fType = URES_TABLE32;
336 }
337 }
338
339 static void
340 res_write16(struct SRBRoot *bundle, struct SResource *res,
341 UErrorCode *status) {
342 if (U_FAILURE(*status) || res == NULL) {
343 return;
344 }
345 if (res->fRes != RES_BOGUS) {
346 /*
347 * The resource item word was already precomputed, which means
348 * no further data needs to be written.
349 * This might be an integer, or an empty or UTF-16 v2 string,
350 * an empty binary, etc.
351 */
352 return;
353 }
354 switch (res->fType) {
355 case URES_STRING:
356 string_write16(bundle, res, status);
357 break;
358 case URES_ARRAY:
359 array_write16(bundle, res, status);
360 break;
361 case URES_TABLE:
362 table_write16(bundle, res, status);
363 break;
364 default:
365 /* Only a few resource types write 16-bit units. */
366 break;
367 }
368 }
369
370 /*
371 * Only called for UTF-16 v1 strings.
372 * For UTF-16 v2 strings, res_preWrite() sees fRes != RES_BOGUS
373 * and exits early.
374 */
375 static void
376 string_preWrite(uint32_t *byteOffset,
377 struct SRBRoot *bundle, struct SResource *res,
378 UErrorCode *status) {
379 /* Write the UTF-16 v1 string. */
380 res->fRes = URES_MAKE_RESOURCE(URES_STRING, *byteOffset >> 2);
381 *byteOffset += 4 + (res->u.fString.fLength + 1) * U_SIZEOF_UCHAR;
382 }
383
384 static void
385 bin_preWrite(uint32_t *byteOffset,
386 struct SRBRoot *bundle, struct SResource *res,
387 UErrorCode *status) {
388 uint32_t pad = 0;
389 uint32_t dataStart = *byteOffset + sizeof(res->u.fBinaryValue.fLength);
390
391 if (dataStart % BIN_ALIGNMENT) {
392 pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT);
393 *byteOffset += pad; /* pad == 4 or 8 or 12 */
394 }
395 res->fRes = URES_MAKE_RESOURCE(URES_BINARY, *byteOffset >> 2);
396 *byteOffset += 4 + res->u.fBinaryValue.fLength;
397 }
398
399 static void
400 array_preWrite(uint32_t *byteOffset,
401 struct SRBRoot *bundle, struct SResource *res,
402 UErrorCode *status) {
403 struct SResource *current;
404
405 if (U_FAILURE(*status)) {
406 return;
407 }
408 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) {
409 res_preWrite(byteOffset, bundle, current, status);
410 }
411 res->fRes = URES_MAKE_RESOURCE(URES_ARRAY, *byteOffset >> 2);
412 *byteOffset += (1 + res->u.fArray.fCount) * 4;
413 }
414
415 static void
416 table_preWrite(uint32_t *byteOffset,
417 struct SRBRoot *bundle, struct SResource *res,
418 UErrorCode *status) {
419 struct SResource *current;
420
421 if (U_FAILURE(*status)) {
422 return;
423 }
424 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) {
425 res_preWrite(byteOffset, bundle, current, status);
426 }
427 if (res->u.fTable.fType == URES_TABLE) {
428 /* 16-bit count, 16-bit key offsets, 32-bit values */
429 res->fRes = URES_MAKE_RESOURCE(URES_TABLE, *byteOffset >> 2);
430 *byteOffset += 2 + res->u.fTable.fCount * 6;
431 } else {
432 /* 32-bit count, key offsets and values */
433 res->fRes = URES_MAKE_RESOURCE(URES_TABLE32, *byteOffset >> 2);
434 *byteOffset += 4 + res->u.fTable.fCount * 8;
435 }
436 }
437
438 static void
439 res_preWrite(uint32_t *byteOffset,
440 struct SRBRoot *bundle, struct SResource *res,
441 UErrorCode *status) {
442 if (U_FAILURE(*status) || res == NULL) {
443 return;
444 }
445 if (res->fRes != RES_BOGUS) {
446 /*
447 * The resource item word was already precomputed, which means
448 * no further data needs to be written.
449 * This might be an integer, or an empty or UTF-16 v2 string,
450 * an empty binary, etc.
451 */
452 return;
453 }
454 switch (res->fType) {
455 case URES_STRING:
456 string_preWrite(byteOffset, bundle, res, status);
457 break;
458 case URES_ALIAS:
459 res->fRes = URES_MAKE_RESOURCE(URES_ALIAS, *byteOffset >> 2);
460 *byteOffset += 4 + (res->u.fString.fLength + 1) * U_SIZEOF_UCHAR;
461 break;
462 case URES_INT_VECTOR:
463 if (res->u.fIntVector.fCount == 0 && gFormatVersion > 1) {
464 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_INT_VECTOR);
465 res->fWritten = TRUE;
466 } else {
467 res->fRes = URES_MAKE_RESOURCE(URES_INT_VECTOR, *byteOffset >> 2);
468 *byteOffset += (1 + res->u.fIntVector.fCount) * 4;
469 }
470 break;
471 case URES_BINARY:
472 bin_preWrite(byteOffset, bundle, res, status);
473 break;
474 case URES_INT:
475 break;
476 case URES_ARRAY:
477 array_preWrite(byteOffset, bundle, res, status);
478 break;
479 case URES_TABLE:
480 table_preWrite(byteOffset, bundle, res, status);
481 break;
482 default:
483 *status = U_INTERNAL_PROGRAM_ERROR;
484 break;
485 }
486 *byteOffset += calcPadding(*byteOffset);
487 }
488
489 /*
490 * Only called for UTF-16 v1 strings. For UTF-16 v2 strings,
491 * res_write() sees fWritten and exits early.
492 */
493 static void string_write(UNewDataMemory *mem, uint32_t *byteOffset,
494 struct SRBRoot *bundle, struct SResource *res,
495 UErrorCode *status) {
496 /* Write the UTF-16 v1 string. */
497 int32_t length = res->u.fString.fLength;
498 udata_write32(mem, length);
499 udata_writeUString(mem, res->u.fString.fChars, length + 1);
500 *byteOffset += 4 + (length + 1) * U_SIZEOF_UCHAR;
501 res->fWritten = TRUE;
502 }
503
504 static void alias_write(UNewDataMemory *mem, uint32_t *byteOffset,
505 struct SRBRoot *bundle, struct SResource *res,
506 UErrorCode *status) {
507 int32_t length = res->u.fString.fLength;
508 udata_write32(mem, length);
509 udata_writeUString(mem, res->u.fString.fChars, length + 1);
510 *byteOffset += 4 + (length + 1) * U_SIZEOF_UCHAR;
511 }
512
513 static void array_write(UNewDataMemory *mem, uint32_t *byteOffset,
514 struct SRBRoot *bundle, struct SResource *res,
515 UErrorCode *status) {
516 uint32_t i;
517
518 struct SResource *current = NULL;
519
520 if (U_FAILURE(*status)) {
521 return;
522 }
523 for (i = 0, current = res->u.fArray.fFirst; current != NULL; ++i, current = current->fNext) {
524 res_write(mem, byteOffset, bundle, current, status);
525 }
526 assert(i == res->u.fArray.fCount);
527
528 udata_write32(mem, res->u.fArray.fCount);
529 for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) {
530 udata_write32(mem, current->fRes);
531 }
532 *byteOffset += (1 + res->u.fArray.fCount) * 4;
533 }
534
535 static void intvector_write(UNewDataMemory *mem, uint32_t *byteOffset,
536 struct SRBRoot *bundle, struct SResource *res,
537 UErrorCode *status) {
538 uint32_t i = 0;
539 udata_write32(mem, res->u.fIntVector.fCount);
540 for(i = 0; i<res->u.fIntVector.fCount; i++) {
541 udata_write32(mem, res->u.fIntVector.fArray[i]);
542 }
543 *byteOffset += (1 + res->u.fIntVector.fCount) * 4;
544 }
545
546 static void bin_write(UNewDataMemory *mem, uint32_t *byteOffset,
547 struct SRBRoot *bundle, struct SResource *res,
548 UErrorCode *status) {
549 uint32_t pad = 0;
550 uint32_t dataStart = *byteOffset + sizeof(res->u.fBinaryValue.fLength);
551
552 if (dataStart % BIN_ALIGNMENT) {
553 pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT);
554 udata_writePadding(mem, pad); /* pad == 4 or 8 or 12 */
555 *byteOffset += pad;
556 }
557
558 udata_write32(mem, res->u.fBinaryValue.fLength);
559 if (res->u.fBinaryValue.fLength > 0) {
560 udata_writeBlock(mem, res->u.fBinaryValue.fData, res->u.fBinaryValue.fLength);
561 }
562 *byteOffset += 4 + res->u.fBinaryValue.fLength;
563 }
564
565 static void table_write(UNewDataMemory *mem, uint32_t *byteOffset,
566 struct SRBRoot *bundle, struct SResource *res,
567 UErrorCode *status) {
568 struct SResource *current;
569 uint32_t i;
570
571 if (U_FAILURE(*status)) {
572 return;
573 }
574 for (i = 0, current = res->u.fTable.fFirst; current != NULL; ++i, current = current->fNext) {
575 assert(i < res->u.fTable.fCount);
576 res_write(mem, byteOffset, bundle, current, status);
577 }
578 assert(i == res->u.fTable.fCount);
579
580 if(res->u.fTable.fType == URES_TABLE) {
581 udata_write16(mem, (uint16_t)res->u.fTable.fCount);
582 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) {
583 udata_write16(mem, makeKey16(bundle, current->fKey));
584 }
585 *byteOffset += (1 + res->u.fTable.fCount)* 2;
586 if ((res->u.fTable.fCount & 1) == 0) {
587 /* 16-bit count and even number of 16-bit key offsets need padding before 32-bit resource items */
588 udata_writePadding(mem, 2);
589 *byteOffset += 2;
590 }
591 } else /* URES_TABLE32 */ {
592 udata_write32(mem, res->u.fTable.fCount);
593 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) {
594 udata_write32(mem, (uint32_t)current->fKey);
595 }
596 *byteOffset += (1 + res->u.fTable.fCount)* 4;
597 }
598 for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) {
599 udata_write32(mem, current->fRes);
600 }
601 *byteOffset += res->u.fTable.fCount * 4;
602 }
603
604 void res_write(UNewDataMemory *mem, uint32_t *byteOffset,
605 struct SRBRoot *bundle, struct SResource *res,
606 UErrorCode *status) {
607 uint8_t paddingSize;
608
609 if (U_FAILURE(*status) || res == NULL) {
610 return;
611 }
612 if (res->fWritten) {
613 assert(res->fRes != RES_BOGUS);
614 return;
615 }
616 switch (res->fType) {
617 case URES_STRING:
618 string_write (mem, byteOffset, bundle, res, status);
619 break;
620 case URES_ALIAS:
621 alias_write (mem, byteOffset, bundle, res, status);
622 break;
623 case URES_INT_VECTOR:
624 intvector_write (mem, byteOffset, bundle, res, status);
625 break;
626 case URES_BINARY:
627 bin_write (mem, byteOffset, bundle, res, status);
628 break;
629 case URES_INT:
630 break; /* fRes was set by int_open() */
631 case URES_ARRAY:
632 array_write (mem, byteOffset, bundle, res, status);
633 break;
634 case URES_TABLE:
635 table_write (mem, byteOffset, bundle, res, status);
636 break;
637 default:
638 *status = U_INTERNAL_PROGRAM_ERROR;
639 break;
640 }
641 paddingSize = calcPadding(*byteOffset);
642 if (paddingSize > 0) {
643 udata_writePadding(mem, paddingSize);
644 *byteOffset += paddingSize;
645 }
646 res->fWritten = TRUE;
647 }
648
649 void bundle_write(struct SRBRoot *bundle,
650 const char *outputDir, const char *outputPkg,
651 char *writtenFilename, int writtenFilenameLen,
652 UErrorCode *status) {
653 UNewDataMemory *mem = NULL;
654 uint32_t byteOffset = 0;
655 uint32_t top, size;
656 char dataName[1024];
657 int32_t indexes[URES_INDEX_TOP];
658
659 bundle_compactKeys(bundle, status);
660 /*
661 * Add padding bytes to fKeys so that fKeysTop is 4-aligned.
662 * Safe because the capacity is a multiple of 4.
663 */
664 while (bundle->fKeysTop & 3) {
665 bundle->fKeys[bundle->fKeysTop++] = (char)0xaa;
666 }
667 /*
668 * In URES_TABLE, use all local key offsets that fit into 16 bits,
669 * and use the remaining 16-bit offsets for pool key offsets
670 * if there are any.
671 * If there are no local keys, then use the whole 16-bit space
672 * for pool key offsets.
673 * Note: This cannot be changed without changing the major formatVersion.
674 */
675 if (bundle->fKeysBottom < bundle->fKeysTop) {
676 if (bundle->fKeysTop <= 0x10000) {
677 bundle->fLocalKeyLimit = bundle->fKeysTop;
678 } else {
679 bundle->fLocalKeyLimit = 0x10000;
680 }
681 } else {
682 bundle->fLocalKeyLimit = 0;
683 }
684
685 bundle_compactStrings(bundle, status);
686 res_write16(bundle, bundle->fRoot, status);
687 if (bundle->f16BitUnitsLength & 1) {
688 bundle->f16BitUnits[bundle->f16BitUnitsLength++] = 0xaaaa; /* pad to multiple of 4 bytes */
689 }
690 /* all keys have been mapped */
691 uprv_free(bundle->fKeyMap);
692 bundle->fKeyMap = NULL;
693
694 byteOffset = bundle->fKeysTop + bundle->f16BitUnitsLength * 2;
695 res_preWrite(&byteOffset, bundle, bundle->fRoot, status);
696
697 /* total size including the root item */
698 top = byteOffset;
699
700 if (U_FAILURE(*status)) {
701 return;
702 }
703
704 if (writtenFilename && writtenFilenameLen) {
705 *writtenFilename = 0;
706 }
707
708 if (writtenFilename) {
709 int32_t off = 0, len = 0;
710 if (outputDir) {
711 len = (int32_t)uprv_strlen(outputDir);
712 if (len > writtenFilenameLen) {
713 len = writtenFilenameLen;
714 }
715 uprv_strncpy(writtenFilename, outputDir, len);
716 }
717 if (writtenFilenameLen -= len) {
718 off += len;
719 writtenFilename[off] = U_FILE_SEP_CHAR;
720 if (--writtenFilenameLen) {
721 ++off;
722 if(outputPkg != NULL)
723 {
724 uprv_strcpy(writtenFilename+off, outputPkg);
725 off += (int32_t)uprv_strlen(outputPkg);
726 writtenFilename[off] = '_';
727 ++off;
728 }
729
730 len = (int32_t)uprv_strlen(bundle->fLocale);
731 if (len > writtenFilenameLen) {
732 len = writtenFilenameLen;
733 }
734 uprv_strncpy(writtenFilename + off, bundle->fLocale, len);
735 if (writtenFilenameLen -= len) {
736 off += len;
737 len = 5;
738 if (len > writtenFilenameLen) {
739 len = writtenFilenameLen;
740 }
741 uprv_strncpy(writtenFilename + off, ".res", len);
742 }
743 }
744 }
745 }
746
747 if(outputPkg)
748 {
749 uprv_strcpy(dataName, outputPkg);
750 uprv_strcat(dataName, "_");
751 uprv_strcat(dataName, bundle->fLocale);
752 }
753 else
754 {
755 uprv_strcpy(dataName, bundle->fLocale);
756 }
757
758 uprv_memcpy(dataInfo.formatVersion, gFormatVersions + gFormatVersion, sizeof(UVersionInfo));
759
760 mem = udata_create(outputDir, "res", dataName, &dataInfo, (gIncludeCopyright==TRUE)? U_COPYRIGHT_STRING:NULL, status);
761 if(U_FAILURE(*status)){
762 return;
763 }
764
765 /* write the root item */
766 udata_write32(mem, bundle->fRoot->fRes);
767
768 /*
769 * formatVersion 1.1 (ICU 2.8):
770 * write int32_t indexes[] after root and before the strings
771 * to make it easier to parse resource bundles in icuswap or from Java etc.
772 */
773 uprv_memset(indexes, 0, sizeof(indexes));
774 indexes[URES_INDEX_LENGTH]= bundle->fIndexLength;
775 indexes[URES_INDEX_KEYS_TOP]= bundle->fKeysTop>>2;
776 indexes[URES_INDEX_RESOURCES_TOP]= (int32_t)(top>>2);
777 indexes[URES_INDEX_BUNDLE_TOP]= indexes[URES_INDEX_RESOURCES_TOP];
778 indexes[URES_INDEX_MAX_TABLE_LENGTH]= bundle->fMaxTableLength;
779
780 /*
781 * formatVersion 1.2 (ICU 3.6):
782 * write indexes[URES_INDEX_ATTRIBUTES] with URES_ATT_NO_FALLBACK set or not set
783 * the memset() above initialized all indexes[] to 0
784 */
785 if (bundle->noFallback) {
786 indexes[URES_INDEX_ATTRIBUTES]=URES_ATT_NO_FALLBACK;
787 }
788 /*
789 * formatVersion 2.0 (ICU 4.4):
790 * more compact string value storage, optional pool bundle
791 */
792 if (URES_INDEX_16BIT_TOP < bundle->fIndexLength) {
793 indexes[URES_INDEX_16BIT_TOP] = (bundle->fKeysTop>>2) + (bundle->f16BitUnitsLength>>1);
794 }
795 if (URES_INDEX_POOL_CHECKSUM < bundle->fIndexLength) {
796 if (bundle->fIsPoolBundle) {
797 indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_IS_POOL_BUNDLE | URES_ATT_NO_FALLBACK;
798 indexes[URES_INDEX_POOL_CHECKSUM] =
799 (int32_t)computeCRC((char *)(bundle->fKeys + bundle->fKeysBottom),
800 (uint32_t)(bundle->fKeysTop - bundle->fKeysBottom),
801 0);
802 } else if (gUsePoolBundle) {
803 indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_USES_POOL_BUNDLE;
804 indexes[URES_INDEX_POOL_CHECKSUM] = bundle->fPoolChecksum;
805 }
806 }
807
808 /* write the indexes[] */
809 udata_writeBlock(mem, indexes, bundle->fIndexLength*4);
810
811 /* write the table key strings */
812 udata_writeBlock(mem, bundle->fKeys+bundle->fKeysBottom,
813 bundle->fKeysTop-bundle->fKeysBottom);
814
815 /* write the v2 UTF-16 strings, URES_TABLE16 and URES_ARRAY16 */
816 udata_writeBlock(mem, bundle->f16BitUnits, bundle->f16BitUnitsLength*2);
817
818 /* write all of the bundle contents: the root item and its children */
819 byteOffset = bundle->fKeysTop + bundle->f16BitUnitsLength * 2;
820 res_write(mem, &byteOffset, bundle, bundle->fRoot, status);
821 assert(byteOffset == top);
822
823 size = udata_finish(mem, status);
824 if(top != size) {
825 fprintf(stderr, "genrb error: wrote %u bytes but counted %u\n",
826 (int)size, (int)top);
827 *status = U_INTERNAL_PROGRAM_ERROR;
828 }
829 }
830
831 /* Opening Functions */
832
833 /* gcc 4.2 complained "no previous prototype for res_open" without this prototype... */
834 struct SResource* res_open(struct SRBRoot *bundle, const char *tag,
835 const struct UString* comment, UErrorCode* status);
836
837 struct SResource* res_open(struct SRBRoot *bundle, const char *tag,
838 const struct UString* comment, UErrorCode* status){
839 struct SResource *res;
840 int32_t key = bundle_addtag(bundle, tag, status);
841 if (U_FAILURE(*status)) {
842 return NULL;
843 }
844
845 res = (struct SResource *) uprv_malloc(sizeof(struct SResource));
846 if (res == NULL) {
847 *status = U_MEMORY_ALLOCATION_ERROR;
848 return NULL;
849 }
850 uprv_memset(res, 0, sizeof(struct SResource));
851 res->fKey = key;
852 res->fRes = RES_BOGUS;
853
854 ustr_init(&res->fComment);
855 if(comment != NULL){
856 ustr_cpy(&res->fComment, comment, status);
857 if (U_FAILURE(*status)) {
858 res_close(res);
859 return NULL;
860 }
861 }
862 return res;
863 }
864
865 struct SResource* res_none() {
866 return (struct SResource*)&kNoResource;
867 }
868
869 struct SResource* table_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) {
870 struct SResource *res = res_open(bundle, tag, comment, status);
871 if (U_FAILURE(*status)) {
872 return NULL;
873 }
874 res->fType = URES_TABLE;
875 res->u.fTable.fRoot = bundle;
876 return res;
877 }
878
879 struct SResource* array_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) {
880 struct SResource *res = res_open(bundle, tag, comment, status);
881 if (U_FAILURE(*status)) {
882 return NULL;
883 }
884 res->fType = URES_ARRAY;
885 return res;
886 }
887
888 static int32_t U_CALLCONV
889 string_hash(const UElement key) {
890 const struct SResource *res = (struct SResource *)key.pointer;
891 return ustr_hashUCharsN(res->u.fString.fChars, res->u.fString.fLength);
892 }
893
894 static UBool U_CALLCONV
895 string_comp(const UElement key1, const UElement key2) {
896 const struct SResource *res1 = (struct SResource *)key1.pointer;
897 const struct SResource *res2 = (struct SResource *)key2.pointer;
898 return 0 == u_strCompare(res1->u.fString.fChars, res1->u.fString.fLength,
899 res2->u.fString.fChars, res2->u.fString.fLength,
900 FALSE);
901 }
902
903 struct SResource *string_open(struct SRBRoot *bundle, const char *tag, const UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) {
904 struct SResource *res = res_open(bundle, tag, comment, status);
905 if (U_FAILURE(*status)) {
906 return NULL;
907 }
908 res->fType = URES_STRING;
909
910 if (len == 0 && gFormatVersion > 1) {
911 res->u.fString.fChars = &gEmptyString;
912 res->fRes = 0;
913 res->fWritten = TRUE;
914 return res;
915 }
916
917 res->u.fString.fLength = len;
918
919 if (gFormatVersion > 1) {
920 /* check for duplicates */
921 res->u.fString.fChars = (UChar *)value;
922 if (bundle->fStringSet == NULL) {
923 UErrorCode localStatus = U_ZERO_ERROR; /* if failure: just don't detect dups */
924 bundle->fStringSet = uhash_open(string_hash, string_comp, string_comp, &localStatus);
925 } else {
926 res->u.fString.fSame = uhash_get(bundle->fStringSet, res);
927 }
928 }
929 if (res->u.fString.fSame == NULL) {
930 /* this is a new string */
931 res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1));
932
933 if (res->u.fString.fChars == NULL) {
934 *status = U_MEMORY_ALLOCATION_ERROR;
935 uprv_free(res);
936 return NULL;
937 }
938
939 uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * len);
940 res->u.fString.fChars[len] = 0;
941 if (bundle->fStringSet != NULL) {
942 /* put it into the set for finding duplicates */
943 uhash_put(bundle->fStringSet, res, res, status);
944 }
945
946 if (bundle->fStringsForm != STRINGS_UTF16_V1) {
947 if (len <= MAX_IMPLICIT_STRING_LENGTH && !U16_IS_TRAIL(value[0]) && len == u_strlen(value)) {
948 /*
949 * This string will be stored without an explicit length.
950 * Runtime will detect !U16_IS_TRAIL(value[0]) and call u_strlen().
951 */
952 res->u.fString.fNumCharsForLength = 0;
953 } else if (len <= 0x3ee) {
954 res->u.fString.fNumCharsForLength = 1;
955 } else if (len <= 0xfffff) {
956 res->u.fString.fNumCharsForLength = 2;
957 } else {
958 res->u.fString.fNumCharsForLength = 3;
959 }
960 bundle->f16BitUnitsLength += res->u.fString.fNumCharsForLength + len + 1; /* +1 for the NUL */
961 }
962 } else {
963 /* this is a duplicate of fSame */
964 struct SResource *same = res->u.fString.fSame;
965 res->u.fString.fChars = same->u.fString.fChars;
966 }
967 return res;
968 }
969
970 /* TODO: make alias_open and string_open use the same code */
971 struct SResource *alias_open(struct SRBRoot *bundle, const char *tag, UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) {
972 struct SResource *res = res_open(bundle, tag, comment, status);
973 if (U_FAILURE(*status)) {
974 return NULL;
975 }
976 res->fType = URES_ALIAS;
977 if (len == 0 && gFormatVersion > 1) {
978 res->u.fString.fChars = &gEmptyString;
979 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_ALIAS);
980 res->fWritten = TRUE;
981 return res;
982 }
983
984 res->u.fString.fLength = len;
985 res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1));
986 if (res->u.fString.fChars == NULL) {
987 *status = U_MEMORY_ALLOCATION_ERROR;
988 uprv_free(res);
989 return NULL;
990 }
991 uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len + 1));
992 return res;
993 }
994
995
996 struct SResource* intvector_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) {
997 struct SResource *res = res_open(bundle, tag, comment, status);
998 if (U_FAILURE(*status)) {
999 return NULL;
1000 }
1001 res->fType = URES_INT_VECTOR;
1002
1003 res->u.fIntVector.fCount = 0;
1004 res->u.fIntVector.fArray = (uint32_t *) uprv_malloc(sizeof(uint32_t) * RESLIST_MAX_INT_VECTOR);
1005 if (res->u.fIntVector.fArray == NULL) {
1006 *status = U_MEMORY_ALLOCATION_ERROR;
1007 uprv_free(res);
1008 return NULL;
1009 }
1010 return res;
1011 }
1012
1013 struct SResource *int_open(struct SRBRoot *bundle, const char *tag, int32_t value, const struct UString* comment, UErrorCode *status) {
1014 struct SResource *res = res_open(bundle, tag, comment, status);
1015 if (U_FAILURE(*status)) {
1016 return NULL;
1017 }
1018 res->fType = URES_INT;
1019 res->u.fIntValue.fValue = value;
1020 res->fRes = URES_MAKE_RESOURCE(URES_INT, value & 0x0FFFFFFF);
1021 res->fWritten = TRUE;
1022 return res;
1023 }
1024
1025 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) {
1026 struct SResource *res = res_open(bundle, tag, comment, status);
1027 if (U_FAILURE(*status)) {
1028 return NULL;
1029 }
1030 res->fType = URES_BINARY;
1031
1032 res->u.fBinaryValue.fLength = length;
1033 res->u.fBinaryValue.fFileName = NULL;
1034 if(fileName!=NULL && uprv_strcmp(fileName, "") !=0){
1035 res->u.fBinaryValue.fFileName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(fileName)+1));
1036 uprv_strcpy(res->u.fBinaryValue.fFileName,fileName);
1037 }
1038 if (length > 0) {
1039 res->u.fBinaryValue.fData = (uint8_t *) uprv_malloc(sizeof(uint8_t) * length);
1040
1041 if (res->u.fBinaryValue.fData == NULL) {
1042 *status = U_MEMORY_ALLOCATION_ERROR;
1043 uprv_free(res);
1044 return NULL;
1045 }
1046
1047 uprv_memcpy(res->u.fBinaryValue.fData, data, length);
1048 }
1049 else {
1050 res->u.fBinaryValue.fData = NULL;
1051 if (gFormatVersion > 1) {
1052 res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_BINARY);
1053 res->fWritten = TRUE;
1054 }
1055 }
1056
1057 return res;
1058 }
1059
1060 struct SRBRoot *bundle_open(const struct UString* comment, UBool isPoolBundle, UErrorCode *status) {
1061 struct SRBRoot *bundle;
1062
1063 if (U_FAILURE(*status)) {
1064 return NULL;
1065 }
1066
1067 bundle = (struct SRBRoot *) uprv_malloc(sizeof(struct SRBRoot));
1068 if (bundle == NULL) {
1069 *status = U_MEMORY_ALLOCATION_ERROR;
1070 return 0;
1071 }
1072 uprv_memset(bundle, 0, sizeof(struct SRBRoot));
1073
1074 bundle->fKeys = (char *) uprv_malloc(sizeof(char) * KEY_SPACE_SIZE);
1075 bundle->fRoot = table_open(bundle, NULL, comment, status);
1076 if (bundle->fKeys == NULL || bundle->fRoot == NULL || U_FAILURE(*status)) {
1077 if (U_SUCCESS(*status)) {
1078 *status = U_MEMORY_ALLOCATION_ERROR;
1079 }
1080 bundle_close(bundle, status);
1081 return NULL;
1082 }
1083
1084 bundle->fLocale = NULL;
1085 bundle->fKeysCapacity = KEY_SPACE_SIZE;
1086 /* formatVersion 1.1: start fKeysTop after the root item and indexes[] */
1087 bundle->fIsPoolBundle = isPoolBundle;
1088 if (gUsePoolBundle || isPoolBundle) {
1089 bundle->fIndexLength = URES_INDEX_POOL_CHECKSUM + 1;
1090 } else if (gFormatVersion >= 2) {
1091 bundle->fIndexLength = URES_INDEX_16BIT_TOP + 1;
1092 } else /* formatVersion 1 */ {
1093 bundle->fIndexLength = URES_INDEX_ATTRIBUTES + 1;
1094 }
1095 bundle->fKeysBottom = (1 /* root */ + bundle->fIndexLength) * 4;
1096 uprv_memset(bundle->fKeys, 0, bundle->fKeysBottom);
1097 bundle->fKeysTop = bundle->fKeysBottom;
1098
1099 if (gFormatVersion == 1) {
1100 bundle->fStringsForm = STRINGS_UTF16_V1;
1101 } else {
1102 bundle->fStringsForm = STRINGS_UTF16_V2;
1103 }
1104
1105 return bundle;
1106 }
1107
1108 /* Closing Functions */
1109 static void table_close(struct SResource *table) {
1110 struct SResource *current = NULL;
1111 struct SResource *prev = NULL;
1112
1113 current = table->u.fTable.fFirst;
1114
1115 while (current != NULL) {
1116 prev = current;
1117 current = current->fNext;
1118
1119 res_close(prev);
1120 }
1121
1122 table->u.fTable.fFirst = NULL;
1123 }
1124
1125 static void array_close(struct SResource *array) {
1126 struct SResource *current = NULL;
1127 struct SResource *prev = NULL;
1128
1129 if(array==NULL){
1130 return;
1131 }
1132 current = array->u.fArray.fFirst;
1133
1134 while (current != NULL) {
1135 prev = current;
1136 current = current->fNext;
1137
1138 res_close(prev);
1139 }
1140 array->u.fArray.fFirst = NULL;
1141 }
1142
1143 static void string_close(struct SResource *string) {
1144 if (string->u.fString.fChars != NULL &&
1145 string->u.fString.fChars != &gEmptyString &&
1146 string->u.fString.fSame == NULL
1147 ) {
1148 uprv_free(string->u.fString.fChars);
1149 string->u.fString.fChars =NULL;
1150 }
1151 }
1152
1153 static void alias_close(struct SResource *alias) {
1154 if (alias->u.fString.fChars != NULL) {
1155 uprv_free(alias->u.fString.fChars);
1156 alias->u.fString.fChars =NULL;
1157 }
1158 }
1159
1160 static void intvector_close(struct SResource *intvector) {
1161 if (intvector->u.fIntVector.fArray != NULL) {
1162 uprv_free(intvector->u.fIntVector.fArray);
1163 intvector->u.fIntVector.fArray =NULL;
1164 }
1165 }
1166
1167 static void int_close(struct SResource *intres) {
1168 /* Intentionally left blank */
1169 }
1170
1171 static void bin_close(struct SResource *binres) {
1172 if (binres->u.fBinaryValue.fData != NULL) {
1173 uprv_free(binres->u.fBinaryValue.fData);
1174 binres->u.fBinaryValue.fData = NULL;
1175 }
1176 }
1177
1178 void res_close(struct SResource *res) {
1179 if (res != NULL) {
1180 switch(res->fType) {
1181 case URES_STRING:
1182 string_close(res);
1183 break;
1184 case URES_ALIAS:
1185 alias_close(res);
1186 break;
1187 case URES_INT_VECTOR:
1188 intvector_close(res);
1189 break;
1190 case URES_BINARY:
1191 bin_close(res);
1192 break;
1193 case URES_INT:
1194 int_close(res);
1195 break;
1196 case URES_ARRAY:
1197 array_close(res);
1198 break;
1199 case URES_TABLE:
1200 table_close(res);
1201 break;
1202 default:
1203 /* Shouldn't happen */
1204 break;
1205 }
1206
1207 ustr_deinit(&res->fComment);
1208 uprv_free(res);
1209 }
1210 }
1211
1212 void bundle_close(struct SRBRoot *bundle, UErrorCode *status) {
1213 res_close(bundle->fRoot);
1214 uprv_free(bundle->fLocale);
1215 uprv_free(bundle->fKeys);
1216 uprv_free(bundle->fKeyMap);
1217 uhash_close(bundle->fStringSet);
1218 uprv_free(bundle->f16BitUnits);
1219 uprv_free(bundle);
1220 }
1221
1222 void bundle_closeString(struct SRBRoot *bundle, struct SResource *string) {
1223 if (bundle->fStringSet != NULL) {
1224 uhash_remove(bundle->fStringSet, string);
1225 }
1226 string_close(string);
1227 }
1228
1229 /* Adding Functions */
1230 void table_add(struct SResource *table, struct SResource *res, int linenumber, UErrorCode *status) {
1231 struct SResource *current = NULL;
1232 struct SResource *prev = NULL;
1233 struct SResTable *list;
1234 const char *resKeyString;
1235
1236 if (U_FAILURE(*status)) {
1237 return;
1238 }
1239 if (res == &kNoResource) {
1240 return;
1241 }
1242
1243 /* remember this linenumber to report to the user if there is a duplicate key */
1244 res->line = linenumber;
1245
1246 /* here we need to traverse the list */
1247 list = &(table->u.fTable);
1248 ++(list->fCount);
1249
1250 /* is list still empty? */
1251 if (list->fFirst == NULL) {
1252 list->fFirst = res;
1253 res->fNext = NULL;
1254 return;
1255 }
1256
1257 resKeyString = list->fRoot->fKeys + res->fKey;
1258
1259 current = list->fFirst;
1260
1261 while (current != NULL) {
1262 const char *currentKeyString = list->fRoot->fKeys + current->fKey;
1263 int diff;
1264 /*
1265 * formatVersion 1: compare key strings in native-charset order
1266 * formatVersion 2 and up: compare key strings in ASCII order
1267 */
1268 if (gFormatVersion == 1 || U_CHARSET_FAMILY == U_ASCII_FAMILY) {
1269 diff = uprv_strcmp(currentKeyString, resKeyString);
1270 } else {
1271 diff = uprv_compareInvCharsAsAscii(currentKeyString, resKeyString);
1272 }
1273 if (diff < 0) {
1274 prev = current;
1275 current = current->fNext;
1276 } else if (diff > 0) {
1277 /* we're either in front of list, or in middle */
1278 if (prev == NULL) {
1279 /* front of the list */
1280 list->fFirst = res;
1281 } else {
1282 /* middle of the list */
1283 prev->fNext = res;
1284 }
1285
1286 res->fNext = current;
1287 return;
1288 } else {
1289 /* Key already exists! ERROR! */
1290 error(linenumber, "duplicate key '%s' in table, first appeared at line %d", currentKeyString, current->line);
1291 *status = U_UNSUPPORTED_ERROR;
1292 return;
1293 }
1294 }
1295
1296 /* end of list */
1297 prev->fNext = res;
1298 res->fNext = NULL;
1299 }
1300
1301 void array_add(struct SResource *array, struct SResource *res, UErrorCode *status) {
1302 if (U_FAILURE(*status)) {
1303 return;
1304 }
1305
1306 if (array->u.fArray.fFirst == NULL) {
1307 array->u.fArray.fFirst = res;
1308 array->u.fArray.fLast = res;
1309 } else {
1310 array->u.fArray.fLast->fNext = res;
1311 array->u.fArray.fLast = res;
1312 }
1313
1314 (array->u.fArray.fCount)++;
1315 }
1316
1317 void intvector_add(struct SResource *intvector, int32_t value, UErrorCode *status) {
1318 if (U_FAILURE(*status)) {
1319 return;
1320 }
1321
1322 *(intvector->u.fIntVector.fArray + intvector->u.fIntVector.fCount) = value;
1323 intvector->u.fIntVector.fCount++;
1324 }
1325
1326 /* Misc Functions */
1327
1328 void bundle_setlocale(struct SRBRoot *bundle, UChar *locale, UErrorCode *status) {
1329
1330 if(U_FAILURE(*status)) {
1331 return;
1332 }
1333
1334 if (bundle->fLocale!=NULL) {
1335 uprv_free(bundle->fLocale);
1336 }
1337
1338 bundle->fLocale= (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1));
1339
1340 if(bundle->fLocale == NULL) {
1341 *status = U_MEMORY_ALLOCATION_ERROR;
1342 return;
1343 }
1344
1345 /*u_strcpy(bundle->fLocale, locale);*/
1346 u_UCharsToChars(locale, bundle->fLocale, u_strlen(locale)+1);
1347
1348 }
1349
1350 static const char *
1351 getKeyString(const struct SRBRoot *bundle, int32_t key) {
1352 if (key < 0) {
1353 return bundle->fPoolBundleKeys + (key & 0x7fffffff);
1354 } else {
1355 return bundle->fKeys + key;
1356 }
1357 }
1358
1359 const char *
1360 res_getKeyString(const struct SRBRoot *bundle, const struct SResource *res, char temp[8]) {
1361 if (res->fKey == -1) {
1362 return NULL;
1363 }
1364 return getKeyString(bundle, res->fKey);
1365 }
1366
1367 const char *
1368 bundle_getKeyBytes(struct SRBRoot *bundle, int32_t *pLength) {
1369 *pLength = bundle->fKeysTop - bundle->fKeysBottom;
1370 return bundle->fKeys + bundle->fKeysBottom;
1371 }
1372
1373 int32_t
1374 bundle_addKeyBytes(struct SRBRoot *bundle, const char *keyBytes, int32_t length, UErrorCode *status) {
1375 int32_t keypos;
1376
1377 if (U_FAILURE(*status)) {
1378 return -1;
1379 }
1380 if (length < 0 || (keyBytes == NULL && length != 0)) {
1381 *status = U_ILLEGAL_ARGUMENT_ERROR;
1382 return -1;
1383 }
1384 if (length == 0) {
1385 return bundle->fKeysTop;
1386 }
1387
1388 keypos = bundle->fKeysTop;
1389 bundle->fKeysTop += length;
1390 if (bundle->fKeysTop >= bundle->fKeysCapacity) {
1391 /* overflow - resize the keys buffer */
1392 bundle->fKeysCapacity += KEY_SPACE_SIZE;
1393 bundle->fKeys = uprv_realloc(bundle->fKeys, bundle->fKeysCapacity);
1394 if(bundle->fKeys == NULL) {
1395 *status = U_MEMORY_ALLOCATION_ERROR;
1396 return -1;
1397 }
1398 }
1399
1400 uprv_memcpy(bundle->fKeys + keypos, keyBytes, length);
1401
1402 return keypos;
1403 }
1404
1405 int32_t
1406 bundle_addtag(struct SRBRoot *bundle, const char *tag, UErrorCode *status) {
1407 int32_t keypos;
1408
1409 if (U_FAILURE(*status)) {
1410 return -1;
1411 }
1412
1413 if (tag == NULL) {
1414 /* no error: the root table and array items have no keys */
1415 return -1;
1416 }
1417
1418 keypos = bundle_addKeyBytes(bundle, tag, (int32_t)(uprv_strlen(tag) + 1), status);
1419 if (U_SUCCESS(*status)) {
1420 ++bundle->fKeysCount;
1421 }
1422 return keypos;
1423 }
1424
1425 static int32_t
1426 compareInt32(int32_t lPos, int32_t rPos) {
1427 /*
1428 * Compare possibly-negative key offsets. Don't just return lPos - rPos
1429 * because that is prone to negative-integer underflows.
1430 */
1431 if (lPos < rPos) {
1432 return -1;
1433 } else if (lPos > rPos) {
1434 return 1;
1435 } else {
1436 return 0;
1437 }
1438 }
1439
1440 static int32_t U_CALLCONV
1441 compareKeySuffixes(const void *context, const void *l, const void *r) {
1442 const struct SRBRoot *bundle=(const struct SRBRoot *)context;
1443 int32_t lPos = ((const KeyMapEntry *)l)->oldpos;
1444 int32_t rPos = ((const KeyMapEntry *)r)->oldpos;
1445 const char *lStart = getKeyString(bundle, lPos);
1446 const char *lLimit = lStart;
1447 const char *rStart = getKeyString(bundle, rPos);
1448 const char *rLimit = rStart;
1449 int32_t diff;
1450 while (*lLimit != 0) { ++lLimit; }
1451 while (*rLimit != 0) { ++rLimit; }
1452 /* compare keys in reverse character order */
1453 while (lStart < lLimit && rStart < rLimit) {
1454 diff = (int32_t)(uint8_t)*--lLimit - (int32_t)(uint8_t)*--rLimit;
1455 if (diff != 0) {
1456 return diff;
1457 }
1458 }
1459 /* sort equal suffixes by descending key length */
1460 diff = (int32_t)(rLimit - rStart) - (int32_t)(lLimit - lStart);
1461 if (diff != 0) {
1462 return diff;
1463 }
1464 /* Sort pool bundle keys first (negative oldpos), and otherwise keys in parsing order. */
1465 return compareInt32(lPos, rPos);
1466 }
1467
1468 static int32_t U_CALLCONV
1469 compareKeyNewpos(const void *context, const void *l, const void *r) {
1470 return compareInt32(((const KeyMapEntry *)l)->newpos, ((const KeyMapEntry *)r)->newpos);
1471 }
1472
1473 static int32_t U_CALLCONV
1474 compareKeyOldpos(const void *context, const void *l, const void *r) {
1475 return compareInt32(((const KeyMapEntry *)l)->oldpos, ((const KeyMapEntry *)r)->oldpos);
1476 }
1477
1478 void
1479 bundle_compactKeys(struct SRBRoot *bundle, UErrorCode *status) {
1480 KeyMapEntry *map;
1481 char *keys;
1482 int32_t i;
1483 int32_t keysCount = bundle->fPoolBundleKeysCount + bundle->fKeysCount;
1484 if (U_FAILURE(*status) || bundle->fKeysCount == 0 || bundle->fKeyMap != NULL) {
1485 return;
1486 }
1487 map = (KeyMapEntry *)uprv_malloc(keysCount * sizeof(KeyMapEntry));
1488 if (map == NULL) {
1489 *status = U_MEMORY_ALLOCATION_ERROR;
1490 return;
1491 }
1492 keys = (char *)bundle->fPoolBundleKeys;
1493 for (i = 0; i < bundle->fPoolBundleKeysCount; ++i) {
1494 map[i].oldpos =
1495 (int32_t)(keys - bundle->fPoolBundleKeys) | 0x80000000; /* negative oldpos */
1496 map[i].newpos = 0;
1497 while (*keys != 0) { ++keys; } /* skip the key */
1498 ++keys; /* skip the NUL */
1499 }
1500 keys = bundle->fKeys + bundle->fKeysBottom;
1501 for (; i < keysCount; ++i) {
1502 map[i].oldpos = (int32_t)(keys - bundle->fKeys);
1503 map[i].newpos = 0;
1504 while (*keys != 0) { ++keys; } /* skip the key */
1505 ++keys; /* skip the NUL */
1506 }
1507 /* Sort the keys so that each one is immediately followed by all of its suffixes. */
1508 uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry),
1509 compareKeySuffixes, bundle, FALSE, status);
1510 /*
1511 * Make suffixes point into earlier, longer strings that contain them
1512 * and mark the old, now unused suffix bytes as deleted.
1513 */
1514 if (U_SUCCESS(*status)) {
1515 keys = bundle->fKeys;
1516 for (i = 0; i < keysCount;) {
1517 /*
1518 * This key is not a suffix of the previous one;
1519 * keep this one and delete the following ones that are
1520 * suffixes of this one.
1521 */
1522 const char *key;
1523 const char *keyLimit;
1524 int32_t j = i + 1;
1525 map[i].newpos = map[i].oldpos;
1526 if (j < keysCount && map[j].oldpos < 0) {
1527 /* Key string from the pool bundle, do not delete. */
1528 i = j;
1529 continue;
1530 }
1531 key = getKeyString(bundle, map[i].oldpos);
1532 for (keyLimit = key; *keyLimit != 0; ++keyLimit) {}
1533 for (; j < keysCount && map[j].oldpos >= 0; ++j) {
1534 const char *k;
1535 char *suffix;
1536 const char *suffixLimit;
1537 int32_t offset;
1538 suffix = keys + map[j].oldpos;
1539 for (suffixLimit = suffix; *suffixLimit != 0; ++suffixLimit) {}
1540 offset = (int32_t)(keyLimit - key) - (suffixLimit - suffix);
1541 if (offset < 0) {
1542 break; /* suffix cannot be longer than the original */
1543 }
1544 /* Is it a suffix of the earlier, longer key? */
1545 for (k = keyLimit; suffix < suffixLimit && *--k == *--suffixLimit;) {}
1546 if (suffix == suffixLimit && *k == *suffixLimit) {
1547 map[j].newpos = map[i].oldpos + offset; /* yes, point to the earlier key */
1548 /* mark the suffix as deleted */
1549 while (*suffix != 0) { *suffix++ = 1; }
1550 *suffix = 1;
1551 } else {
1552 break; /* not a suffix, restart from here */
1553 }
1554 }
1555 i = j;
1556 }
1557 /*
1558 * Re-sort by newpos, then modify the key characters array in-place
1559 * to squeeze out unused bytes, and readjust the newpos offsets.
1560 */
1561 uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry),
1562 compareKeyNewpos, NULL, FALSE, status);
1563 if (U_SUCCESS(*status)) {
1564 int32_t oldpos, newpos, limit;
1565 oldpos = newpos = bundle->fKeysBottom;
1566 limit = bundle->fKeysTop;
1567 /* skip key offsets that point into the pool bundle rather than this new bundle */
1568 for (i = 0; i < keysCount && map[i].newpos < 0; ++i) {}
1569 if (i < keysCount) {
1570 while (oldpos < limit) {
1571 if (keys[oldpos] == 1) {
1572 ++oldpos; /* skip unused bytes */
1573 } else {
1574 /* adjust the new offsets for keys starting here */
1575 while (i < keysCount && map[i].newpos == oldpos) {
1576 map[i++].newpos = newpos;
1577 }
1578 /* move the key characters to their new position */
1579 keys[newpos++] = keys[oldpos++];
1580 }
1581 }
1582 assert(i == keysCount);
1583 }
1584 bundle->fKeysTop = newpos;
1585 /* Re-sort once more, by old offsets for binary searching. */
1586 uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry),
1587 compareKeyOldpos, NULL, FALSE, status);
1588 if (U_SUCCESS(*status)) {
1589 /* key size reduction by limit - newpos */
1590 bundle->fKeyMap = map;
1591 map = NULL;
1592 }
1593 }
1594 }
1595 uprv_free(map);
1596 }
1597
1598 static int32_t U_CALLCONV
1599 compareStringSuffixes(const void *context, const void *l, const void *r) {
1600 struct SResource *left = *((struct SResource **)l);
1601 struct SResource *right = *((struct SResource **)r);
1602 const UChar *lStart = left->u.fString.fChars;
1603 const UChar *lLimit = lStart + left->u.fString.fLength;
1604 const UChar *rStart = right->u.fString.fChars;
1605 const UChar *rLimit = rStart + right->u.fString.fLength;
1606 int32_t diff;
1607 /* compare keys in reverse character order */
1608 while (lStart < lLimit && rStart < rLimit) {
1609 diff = (int32_t)*--lLimit - (int32_t)*--rLimit;
1610 if (diff != 0) {
1611 return diff;
1612 }
1613 }
1614 /* sort equal suffixes by descending string length */
1615 return right->u.fString.fLength - left->u.fString.fLength;
1616 }
1617
1618 static int32_t U_CALLCONV
1619 compareStringLengths(const void *context, const void *l, const void *r) {
1620 struct SResource *left = *((struct SResource **)l);
1621 struct SResource *right = *((struct SResource **)r);
1622 int32_t diff;
1623 /* Make "is suffix of another string" compare greater than a non-suffix. */
1624 diff = (int)(left->u.fString.fSame != NULL) - (int)(right->u.fString.fSame != NULL);
1625 if (diff != 0) {
1626 return diff;
1627 }
1628 /* sort by ascending string length */
1629 return left->u.fString.fLength - right->u.fString.fLength;
1630 }
1631
1632 static int32_t
1633 string_writeUTF16v2(struct SRBRoot *bundle, struct SResource *res, int32_t utf16Length) {
1634 int32_t length = res->u.fString.fLength;
1635 res->fRes = URES_MAKE_RESOURCE(URES_STRING_V2, utf16Length);
1636 res->fWritten = TRUE;
1637 switch(res->u.fString.fNumCharsForLength) {
1638 case 0:
1639 break;
1640 case 1:
1641 bundle->f16BitUnits[utf16Length++] = (uint16_t)(0xdc00 + length);
1642 break;
1643 case 2:
1644 bundle->f16BitUnits[utf16Length] = (uint16_t)(0xdfef + (length >> 16));
1645 bundle->f16BitUnits[utf16Length + 1] = (uint16_t)length;
1646 utf16Length += 2;
1647 break;
1648 case 3:
1649 bundle->f16BitUnits[utf16Length] = 0xdfff;
1650 bundle->f16BitUnits[utf16Length + 1] = (uint16_t)(length >> 16);
1651 bundle->f16BitUnits[utf16Length + 2] = (uint16_t)length;
1652 utf16Length += 3;
1653 break;
1654 default:
1655 break; /* will not occur */
1656 }
1657 u_memcpy(bundle->f16BitUnits + utf16Length, res->u.fString.fChars, length + 1);
1658 return utf16Length + length + 1;
1659 }
1660
1661 static void
1662 bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status) {
1663 if (U_FAILURE(*status)) {
1664 return;
1665 }
1666 switch(bundle->fStringsForm) {
1667 case STRINGS_UTF16_V2:
1668 if (bundle->f16BitUnitsLength > 0) {
1669 struct SResource **array;
1670 int32_t count = uhash_count(bundle->fStringSet);
1671 int32_t i, pos;
1672 /*
1673 * Allocate enough space for the initial NUL and the UTF-16 v2 strings,
1674 * and some extra for URES_TABLE16 and URES_ARRAY16 values.
1675 * Round down to an even number.
1676 */
1677 int32_t utf16Length = (bundle->f16BitUnitsLength + 20000) & ~1;
1678 bundle->f16BitUnits = (UChar *)uprv_malloc(utf16Length * U_SIZEOF_UCHAR);
1679 array = (struct SResource **)uprv_malloc(count * sizeof(struct SResource **));
1680 if (bundle->f16BitUnits == NULL || array == NULL) {
1681 uprv_free(bundle->f16BitUnits);
1682 bundle->f16BitUnits = NULL;
1683 uprv_free(array);
1684 *status = U_MEMORY_ALLOCATION_ERROR;
1685 return;
1686 }
1687 bundle->f16BitUnitsCapacity = utf16Length;
1688 /* insert the initial NUL */
1689 bundle->f16BitUnits[0] = 0;
1690 utf16Length = 1;
1691 ++bundle->f16BitUnitsLength;
1692 for (pos = -1, i = 0; i < count; ++i) {
1693 array[i] = (struct SResource *)uhash_nextElement(bundle->fStringSet, &pos)->key.pointer;
1694 }
1695 /* Sort the strings so that each one is immediately followed by all of its suffixes. */
1696 uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **),
1697 compareStringSuffixes, NULL, FALSE, status);
1698 /*
1699 * Make suffixes point into earlier, longer strings that contain them.
1700 * Temporarily use fSame and fSuffixOffset for suffix strings to
1701 * refer to the remaining ones.
1702 */
1703 if (U_SUCCESS(*status)) {
1704 for (i = 0; i < count;) {
1705 /*
1706 * This string is not a suffix of the previous one;
1707 * write this one and subsume the following ones that are
1708 * suffixes of this one.
1709 */
1710 struct SResource *res = array[i];
1711 const UChar *strLimit = res->u.fString.fChars + res->u.fString.fLength;
1712 int32_t j;
1713 for (j = i + 1; j < count; ++j) {
1714 struct SResource *suffixRes = array[j];
1715 const UChar *s;
1716 const UChar *suffix = suffixRes->u.fString.fChars;
1717 const UChar *suffixLimit = suffix + suffixRes->u.fString.fLength;
1718 int32_t offset = res->u.fString.fLength - suffixRes->u.fString.fLength;
1719 if (offset < 0) {
1720 break; /* suffix cannot be longer than the original */
1721 }
1722 /* Is it a suffix of the earlier, longer key? */
1723 for (s = strLimit; suffix < suffixLimit && *--s == *--suffixLimit;) {}
1724 if (suffix == suffixLimit && *s == *suffixLimit) {
1725 if (suffixRes->u.fString.fNumCharsForLength == 0) {
1726 /* yes, point to the earlier string */
1727 suffixRes->u.fString.fSame = res;
1728 suffixRes->u.fString.fSuffixOffset = offset;
1729 } else {
1730 /* write the suffix by itself if we need explicit length */
1731 }
1732 } else {
1733 break; /* not a suffix, restart from here */
1734 }
1735 }
1736 i = j;
1737 }
1738 }
1739 /*
1740 * Re-sort the strings by ascending length (except suffixes last)
1741 * to optimize for URES_TABLE16 and URES_ARRAY16:
1742 * Keep as many as possible within reach of 16-bit offsets.
1743 */
1744 uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **),
1745 compareStringLengths, NULL, FALSE, status);
1746 if (U_SUCCESS(*status)) {
1747 /* Write the non-suffix strings. */
1748 for (i = 0; i < count && array[i]->u.fString.fSame == NULL; ++i) {
1749 utf16Length = string_writeUTF16v2(bundle, array[i], utf16Length);
1750 }
1751 /* Write the suffix strings. Make each point to the real string. */
1752 for (; i < count; ++i) {
1753 struct SResource *res = array[i];
1754 struct SResource *same = res->u.fString.fSame;
1755 res->fRes = same->fRes + same->u.fString.fNumCharsForLength + res->u.fString.fSuffixOffset;
1756 res->u.fString.fSame = NULL;
1757 res->fWritten = TRUE;
1758 }
1759 }
1760 assert(utf16Length <= bundle->f16BitUnitsLength);
1761 bundle->f16BitUnitsLength = utf16Length;
1762 uprv_free(array);
1763 }
1764 break;
1765 default:
1766 break;
1767 }
1768 }