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