1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/tools/genrb/reslist.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1772 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* 1.7 +* Copyright (C) 2000-2012, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +******************************************************************************* 1.11 +* 1.12 +* File reslist.c 1.13 +* 1.14 +* Modification History: 1.15 +* 1.16 +* Date Name Description 1.17 +* 02/21/00 weiv Creation. 1.18 +******************************************************************************* 1.19 +*/ 1.20 + 1.21 +#include <assert.h> 1.22 +#include <stdio.h> 1.23 +#include "reslist.h" 1.24 +#include "unewdata.h" 1.25 +#include "unicode/ures.h" 1.26 +#include "unicode/putil.h" 1.27 +#include "errmsg.h" 1.28 + 1.29 +#include "uarrsort.h" 1.30 +#include "uelement.h" 1.31 +#include "uinvchar.h" 1.32 +#include "ustr_imp.h" 1.33 +#include "unicode/utf16.h" 1.34 +/* 1.35 + * Align binary data at a 16-byte offset from the start of the resource bundle, 1.36 + * to be safe for any data type it may contain. 1.37 + */ 1.38 +#define BIN_ALIGNMENT 16 1.39 + 1.40 +static UBool gIncludeCopyright = FALSE; 1.41 +static UBool gUsePoolBundle = FALSE; 1.42 +static int32_t gFormatVersion = 2; 1.43 + 1.44 +static UChar gEmptyString = 0; 1.45 + 1.46 +/* How do we store string values? */ 1.47 +enum { 1.48 + STRINGS_UTF16_V1, /* formatVersion 1: int length + UChars + NUL + padding to 4 bytes */ 1.49 + STRINGS_UTF16_V2 /* formatVersion 2: optional length in 1..3 UChars + UChars + NUL */ 1.50 +}; 1.51 + 1.52 +enum { 1.53 + MAX_IMPLICIT_STRING_LENGTH = 40 /* do not store the length explicitly for such strings */ 1.54 +}; 1.55 + 1.56 +/* 1.57 + * res_none() returns the address of kNoResource, 1.58 + * for use in non-error cases when no resource is to be added to the bundle. 1.59 + * (NULL is used in error cases.) 1.60 + */ 1.61 +static const struct SResource kNoResource = { URES_NONE }; 1.62 + 1.63 +static UDataInfo dataInfo= { 1.64 + sizeof(UDataInfo), 1.65 + 0, 1.66 + 1.67 + U_IS_BIG_ENDIAN, 1.68 + U_CHARSET_FAMILY, 1.69 + sizeof(UChar), 1.70 + 0, 1.71 + 1.72 + {0x52, 0x65, 0x73, 0x42}, /* dataFormat="ResB" */ 1.73 + {1, 3, 0, 0}, /* formatVersion */ 1.74 + {1, 4, 0, 0} /* dataVersion take a look at version inside parsed resb*/ 1.75 +}; 1.76 + 1.77 +static const UVersionInfo gFormatVersions[3] = { /* indexed by a major-formatVersion integer */ 1.78 + { 0, 0, 0, 0 }, 1.79 + { 1, 3, 0, 0 }, 1.80 + { 2, 0, 0, 0 } 1.81 +}; 1.82 + 1.83 +static uint8_t calcPadding(uint32_t size) { 1.84 + /* returns space we need to pad */ 1.85 + return (uint8_t) ((size % sizeof(uint32_t)) ? (sizeof(uint32_t) - (size % sizeof(uint32_t))) : 0); 1.86 + 1.87 +} 1.88 + 1.89 +void setIncludeCopyright(UBool val){ 1.90 + gIncludeCopyright=val; 1.91 +} 1.92 + 1.93 +UBool getIncludeCopyright(void){ 1.94 + return gIncludeCopyright; 1.95 +} 1.96 + 1.97 +void setFormatVersion(int32_t formatVersion) { 1.98 + gFormatVersion = formatVersion; 1.99 +} 1.100 + 1.101 +void setUsePoolBundle(UBool use) { 1.102 + gUsePoolBundle = use; 1.103 +} 1.104 + 1.105 +static void 1.106 +bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status); 1.107 + 1.108 +/* Writing Functions */ 1.109 + 1.110 +/* 1.111 + * type_write16() functions write resource values into f16BitUnits 1.112 + * and determine the resource item word, if possible. 1.113 + */ 1.114 +static void 1.115 +res_write16(struct SRBRoot *bundle, struct SResource *res, 1.116 + UErrorCode *status); 1.117 + 1.118 +/* 1.119 + * type_preWrite() functions calculate ("preflight") and advance the *byteOffset 1.120 + * by the size of their data in the binary file and 1.121 + * determine the resource item word. 1.122 + * Most type_preWrite() functions may add any number of bytes, but res_preWrite() 1.123 + * will always pad it to a multiple of 4. 1.124 + * The resource item type may be a related subtype of the fType. 1.125 + * 1.126 + * The type_preWrite() and type_write() functions start and end at the same 1.127 + * byteOffset values. 1.128 + * Prewriting allows bundle_write() to determine the root resource item word, 1.129 + * before actually writing the bundle contents to the file, 1.130 + * which is necessary because the root item is stored at the beginning. 1.131 + */ 1.132 +static void 1.133 +res_preWrite(uint32_t *byteOffset, 1.134 + struct SRBRoot *bundle, struct SResource *res, 1.135 + UErrorCode *status); 1.136 + 1.137 +/* 1.138 + * type_write() functions write their data to mem and update the byteOffset 1.139 + * in parallel. 1.140 + * (A kingdom for C++ and polymorphism...) 1.141 + */ 1.142 +static void 1.143 +res_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.144 + struct SRBRoot *bundle, struct SResource *res, 1.145 + UErrorCode *status); 1.146 + 1.147 +static uint16_t * 1.148 +reserve16BitUnits(struct SRBRoot *bundle, int32_t length, UErrorCode *status) { 1.149 + if (U_FAILURE(*status)) { 1.150 + return NULL; 1.151 + } 1.152 + if ((bundle->f16BitUnitsLength + length) > bundle->f16BitUnitsCapacity) { 1.153 + uint16_t *newUnits; 1.154 + int32_t capacity = 2 * bundle->f16BitUnitsCapacity + length + 1024; 1.155 + capacity &= ~1; /* ensures padding fits if f16BitUnitsLength needs it */ 1.156 + newUnits = (uint16_t *)uprv_malloc(capacity * 2); 1.157 + if (newUnits == NULL) { 1.158 + *status = U_MEMORY_ALLOCATION_ERROR; 1.159 + return NULL; 1.160 + } 1.161 + if (bundle->f16BitUnitsLength > 0) { 1.162 + uprv_memcpy(newUnits, bundle->f16BitUnits, bundle->f16BitUnitsLength * 2); 1.163 + } else { 1.164 + newUnits[0] = 0; 1.165 + bundle->f16BitUnitsLength = 1; 1.166 + } 1.167 + uprv_free(bundle->f16BitUnits); 1.168 + bundle->f16BitUnits = newUnits; 1.169 + bundle->f16BitUnitsCapacity = capacity; 1.170 + } 1.171 + return bundle->f16BitUnits + bundle->f16BitUnitsLength; 1.172 +} 1.173 + 1.174 +static int32_t 1.175 +makeRes16(uint32_t resWord) { 1.176 + uint32_t type, offset; 1.177 + if (resWord == 0) { 1.178 + return 0; /* empty string */ 1.179 + } 1.180 + type = RES_GET_TYPE(resWord); 1.181 + offset = RES_GET_OFFSET(resWord); 1.182 + if (type == URES_STRING_V2 && offset <= 0xffff) { 1.183 + return (int32_t)offset; 1.184 + } 1.185 + return -1; 1.186 +} 1.187 + 1.188 +static int32_t 1.189 +mapKey(struct SRBRoot *bundle, int32_t oldpos) { 1.190 + const KeyMapEntry *map = bundle->fKeyMap; 1.191 + int32_t i, start, limit; 1.192 + 1.193 + /* do a binary search for the old, pre-bundle_compactKeys() key offset */ 1.194 + start = bundle->fPoolBundleKeysCount; 1.195 + limit = start + bundle->fKeysCount; 1.196 + while (start < limit - 1) { 1.197 + i = (start + limit) / 2; 1.198 + if (oldpos < map[i].oldpos) { 1.199 + limit = i; 1.200 + } else { 1.201 + start = i; 1.202 + } 1.203 + } 1.204 + assert(oldpos == map[start].oldpos); 1.205 + return map[start].newpos; 1.206 +} 1.207 + 1.208 +static uint16_t 1.209 +makeKey16(struct SRBRoot *bundle, int32_t key) { 1.210 + if (key >= 0) { 1.211 + return (uint16_t)key; 1.212 + } else { 1.213 + return (uint16_t)(key + bundle->fLocalKeyLimit); /* offset in the pool bundle */ 1.214 + } 1.215 +} 1.216 + 1.217 +/* 1.218 + * Only called for UTF-16 v1 strings and duplicate UTF-16 v2 strings. 1.219 + * For unique UTF-16 v2 strings, res_write16() sees fRes != RES_BOGUS 1.220 + * and exits early. 1.221 + */ 1.222 +static void 1.223 +string_write16(struct SRBRoot *bundle, struct SResource *res, UErrorCode *status) { 1.224 + struct SResource *same; 1.225 + if ((same = res->u.fString.fSame) != NULL) { 1.226 + /* This is a duplicate. */ 1.227 + if (same->fRes == RES_BOGUS) { 1.228 + /* The original has not been visited yet. */ 1.229 + string_write16(bundle, same, status); 1.230 + } 1.231 + res->fRes = same->fRes; 1.232 + res->fWritten = same->fWritten; 1.233 + } 1.234 +} 1.235 + 1.236 +static void 1.237 +array_write16(struct SRBRoot *bundle, struct SResource *res, 1.238 + UErrorCode *status) { 1.239 + struct SResource *current; 1.240 + int32_t res16 = 0; 1.241 + 1.242 + if (U_FAILURE(*status)) { 1.243 + return; 1.244 + } 1.245 + if (res->u.fArray.fCount == 0 && gFormatVersion > 1) { 1.246 + res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_ARRAY); 1.247 + res->fWritten = TRUE; 1.248 + return; 1.249 + } 1.250 + for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 1.251 + res_write16(bundle, current, status); 1.252 + res16 |= makeRes16(current->fRes); 1.253 + } 1.254 + if (U_SUCCESS(*status) && res->u.fArray.fCount <= 0xffff && res16 >= 0 && gFormatVersion > 1) { 1.255 + uint16_t *p16 = reserve16BitUnits(bundle, 1 + res->u.fArray.fCount, status); 1.256 + if (U_SUCCESS(*status)) { 1.257 + res->fRes = URES_MAKE_RESOURCE(URES_ARRAY16, bundle->f16BitUnitsLength); 1.258 + *p16++ = (uint16_t)res->u.fArray.fCount; 1.259 + for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 1.260 + *p16++ = (uint16_t)makeRes16(current->fRes); 1.261 + } 1.262 + bundle->f16BitUnitsLength += 1 + res->u.fArray.fCount; 1.263 + res->fWritten = TRUE; 1.264 + } 1.265 + } 1.266 +} 1.267 + 1.268 +static void 1.269 +table_write16(struct SRBRoot *bundle, struct SResource *res, 1.270 + UErrorCode *status) { 1.271 + struct SResource *current; 1.272 + int32_t maxKey = 0, maxPoolKey = 0x80000000; 1.273 + int32_t res16 = 0; 1.274 + UBool hasLocalKeys = FALSE, hasPoolKeys = FALSE; 1.275 + 1.276 + if (U_FAILURE(*status)) { 1.277 + return; 1.278 + } 1.279 + if (res->u.fTable.fCount == 0 && gFormatVersion > 1) { 1.280 + res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_TABLE); 1.281 + res->fWritten = TRUE; 1.282 + return; 1.283 + } 1.284 + /* Find the smallest table type that fits the data. */ 1.285 + for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 1.286 + int32_t key; 1.287 + res_write16(bundle, current, status); 1.288 + if (bundle->fKeyMap == NULL) { 1.289 + key = current->fKey; 1.290 + } else { 1.291 + key = current->fKey = mapKey(bundle, current->fKey); 1.292 + } 1.293 + if (key >= 0) { 1.294 + hasLocalKeys = TRUE; 1.295 + if (key > maxKey) { 1.296 + maxKey = key; 1.297 + } 1.298 + } else { 1.299 + hasPoolKeys = TRUE; 1.300 + if (key > maxPoolKey) { 1.301 + maxPoolKey = key; 1.302 + } 1.303 + } 1.304 + res16 |= makeRes16(current->fRes); 1.305 + } 1.306 + if (U_FAILURE(*status)) { 1.307 + return; 1.308 + } 1.309 + if(res->u.fTable.fCount > (uint32_t)bundle->fMaxTableLength) { 1.310 + bundle->fMaxTableLength = res->u.fTable.fCount; 1.311 + } 1.312 + maxPoolKey &= 0x7fffffff; 1.313 + if (res->u.fTable.fCount <= 0xffff && 1.314 + (!hasLocalKeys || maxKey < bundle->fLocalKeyLimit) && 1.315 + (!hasPoolKeys || maxPoolKey < (0x10000 - bundle->fLocalKeyLimit)) 1.316 + ) { 1.317 + if (res16 >= 0 && gFormatVersion > 1) { 1.318 + uint16_t *p16 = reserve16BitUnits(bundle, 1 + res->u.fTable.fCount * 2, status); 1.319 + if (U_SUCCESS(*status)) { 1.320 + /* 16-bit count, key offsets and values */ 1.321 + res->fRes = URES_MAKE_RESOURCE(URES_TABLE16, bundle->f16BitUnitsLength); 1.322 + *p16++ = (uint16_t)res->u.fTable.fCount; 1.323 + for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 1.324 + *p16++ = makeKey16(bundle, current->fKey); 1.325 + } 1.326 + for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 1.327 + *p16++ = (uint16_t)makeRes16(current->fRes); 1.328 + } 1.329 + bundle->f16BitUnitsLength += 1 + res->u.fTable.fCount * 2; 1.330 + res->fWritten = TRUE; 1.331 + } 1.332 + } else { 1.333 + /* 16-bit count, 16-bit key offsets, 32-bit values */ 1.334 + res->u.fTable.fType = URES_TABLE; 1.335 + } 1.336 + } else { 1.337 + /* 32-bit count, key offsets and values */ 1.338 + res->u.fTable.fType = URES_TABLE32; 1.339 + } 1.340 +} 1.341 + 1.342 +static void 1.343 +res_write16(struct SRBRoot *bundle, struct SResource *res, 1.344 + UErrorCode *status) { 1.345 + if (U_FAILURE(*status) || res == NULL) { 1.346 + return; 1.347 + } 1.348 + if (res->fRes != RES_BOGUS) { 1.349 + /* 1.350 + * The resource item word was already precomputed, which means 1.351 + * no further data needs to be written. 1.352 + * This might be an integer, or an empty or UTF-16 v2 string, 1.353 + * an empty binary, etc. 1.354 + */ 1.355 + return; 1.356 + } 1.357 + switch (res->fType) { 1.358 + case URES_STRING: 1.359 + string_write16(bundle, res, status); 1.360 + break; 1.361 + case URES_ARRAY: 1.362 + array_write16(bundle, res, status); 1.363 + break; 1.364 + case URES_TABLE: 1.365 + table_write16(bundle, res, status); 1.366 + break; 1.367 + default: 1.368 + /* Only a few resource types write 16-bit units. */ 1.369 + break; 1.370 + } 1.371 +} 1.372 + 1.373 +/* 1.374 + * Only called for UTF-16 v1 strings. 1.375 + * For UTF-16 v2 strings, res_preWrite() sees fRes != RES_BOGUS 1.376 + * and exits early. 1.377 + */ 1.378 +static void 1.379 +string_preWrite(uint32_t *byteOffset, 1.380 + struct SRBRoot *bundle, struct SResource *res, 1.381 + UErrorCode *status) { 1.382 + /* Write the UTF-16 v1 string. */ 1.383 + res->fRes = URES_MAKE_RESOURCE(URES_STRING, *byteOffset >> 2); 1.384 + *byteOffset += 4 + (res->u.fString.fLength + 1) * U_SIZEOF_UCHAR; 1.385 +} 1.386 + 1.387 +static void 1.388 +bin_preWrite(uint32_t *byteOffset, 1.389 + struct SRBRoot *bundle, struct SResource *res, 1.390 + UErrorCode *status) { 1.391 + uint32_t pad = 0; 1.392 + uint32_t dataStart = *byteOffset + sizeof(res->u.fBinaryValue.fLength); 1.393 + 1.394 + if (dataStart % BIN_ALIGNMENT) { 1.395 + pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT); 1.396 + *byteOffset += pad; /* pad == 4 or 8 or 12 */ 1.397 + } 1.398 + res->fRes = URES_MAKE_RESOURCE(URES_BINARY, *byteOffset >> 2); 1.399 + *byteOffset += 4 + res->u.fBinaryValue.fLength; 1.400 +} 1.401 + 1.402 +static void 1.403 +array_preWrite(uint32_t *byteOffset, 1.404 + struct SRBRoot *bundle, struct SResource *res, 1.405 + UErrorCode *status) { 1.406 + struct SResource *current; 1.407 + 1.408 + if (U_FAILURE(*status)) { 1.409 + return; 1.410 + } 1.411 + for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 1.412 + res_preWrite(byteOffset, bundle, current, status); 1.413 + } 1.414 + res->fRes = URES_MAKE_RESOURCE(URES_ARRAY, *byteOffset >> 2); 1.415 + *byteOffset += (1 + res->u.fArray.fCount) * 4; 1.416 +} 1.417 + 1.418 +static void 1.419 +table_preWrite(uint32_t *byteOffset, 1.420 + struct SRBRoot *bundle, struct SResource *res, 1.421 + UErrorCode *status) { 1.422 + struct SResource *current; 1.423 + 1.424 + if (U_FAILURE(*status)) { 1.425 + return; 1.426 + } 1.427 + for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 1.428 + res_preWrite(byteOffset, bundle, current, status); 1.429 + } 1.430 + if (res->u.fTable.fType == URES_TABLE) { 1.431 + /* 16-bit count, 16-bit key offsets, 32-bit values */ 1.432 + res->fRes = URES_MAKE_RESOURCE(URES_TABLE, *byteOffset >> 2); 1.433 + *byteOffset += 2 + res->u.fTable.fCount * 6; 1.434 + } else { 1.435 + /* 32-bit count, key offsets and values */ 1.436 + res->fRes = URES_MAKE_RESOURCE(URES_TABLE32, *byteOffset >> 2); 1.437 + *byteOffset += 4 + res->u.fTable.fCount * 8; 1.438 + } 1.439 +} 1.440 + 1.441 +static void 1.442 +res_preWrite(uint32_t *byteOffset, 1.443 + struct SRBRoot *bundle, struct SResource *res, 1.444 + UErrorCode *status) { 1.445 + if (U_FAILURE(*status) || res == NULL) { 1.446 + return; 1.447 + } 1.448 + if (res->fRes != RES_BOGUS) { 1.449 + /* 1.450 + * The resource item word was already precomputed, which means 1.451 + * no further data needs to be written. 1.452 + * This might be an integer, or an empty or UTF-16 v2 string, 1.453 + * an empty binary, etc. 1.454 + */ 1.455 + return; 1.456 + } 1.457 + switch (res->fType) { 1.458 + case URES_STRING: 1.459 + string_preWrite(byteOffset, bundle, res, status); 1.460 + break; 1.461 + case URES_ALIAS: 1.462 + res->fRes = URES_MAKE_RESOURCE(URES_ALIAS, *byteOffset >> 2); 1.463 + *byteOffset += 4 + (res->u.fString.fLength + 1) * U_SIZEOF_UCHAR; 1.464 + break; 1.465 + case URES_INT_VECTOR: 1.466 + if (res->u.fIntVector.fCount == 0 && gFormatVersion > 1) { 1.467 + res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_INT_VECTOR); 1.468 + res->fWritten = TRUE; 1.469 + } else { 1.470 + res->fRes = URES_MAKE_RESOURCE(URES_INT_VECTOR, *byteOffset >> 2); 1.471 + *byteOffset += (1 + res->u.fIntVector.fCount) * 4; 1.472 + } 1.473 + break; 1.474 + case URES_BINARY: 1.475 + bin_preWrite(byteOffset, bundle, res, status); 1.476 + break; 1.477 + case URES_INT: 1.478 + break; 1.479 + case URES_ARRAY: 1.480 + array_preWrite(byteOffset, bundle, res, status); 1.481 + break; 1.482 + case URES_TABLE: 1.483 + table_preWrite(byteOffset, bundle, res, status); 1.484 + break; 1.485 + default: 1.486 + *status = U_INTERNAL_PROGRAM_ERROR; 1.487 + break; 1.488 + } 1.489 + *byteOffset += calcPadding(*byteOffset); 1.490 +} 1.491 + 1.492 +/* 1.493 + * Only called for UTF-16 v1 strings. For UTF-16 v2 strings, 1.494 + * res_write() sees fWritten and exits early. 1.495 + */ 1.496 +static void string_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.497 + struct SRBRoot *bundle, struct SResource *res, 1.498 + UErrorCode *status) { 1.499 + /* Write the UTF-16 v1 string. */ 1.500 + int32_t length = res->u.fString.fLength; 1.501 + udata_write32(mem, length); 1.502 + udata_writeUString(mem, res->u.fString.fChars, length + 1); 1.503 + *byteOffset += 4 + (length + 1) * U_SIZEOF_UCHAR; 1.504 + res->fWritten = TRUE; 1.505 +} 1.506 + 1.507 +static void alias_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.508 + struct SRBRoot *bundle, struct SResource *res, 1.509 + UErrorCode *status) { 1.510 + int32_t length = res->u.fString.fLength; 1.511 + udata_write32(mem, length); 1.512 + udata_writeUString(mem, res->u.fString.fChars, length + 1); 1.513 + *byteOffset += 4 + (length + 1) * U_SIZEOF_UCHAR; 1.514 +} 1.515 + 1.516 +static void array_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.517 + struct SRBRoot *bundle, struct SResource *res, 1.518 + UErrorCode *status) { 1.519 + uint32_t i; 1.520 + 1.521 + struct SResource *current = NULL; 1.522 + 1.523 + if (U_FAILURE(*status)) { 1.524 + return; 1.525 + } 1.526 + for (i = 0, current = res->u.fArray.fFirst; current != NULL; ++i, current = current->fNext) { 1.527 + res_write(mem, byteOffset, bundle, current, status); 1.528 + } 1.529 + assert(i == res->u.fArray.fCount); 1.530 + 1.531 + udata_write32(mem, res->u.fArray.fCount); 1.532 + for (current = res->u.fArray.fFirst; current != NULL; current = current->fNext) { 1.533 + udata_write32(mem, current->fRes); 1.534 + } 1.535 + *byteOffset += (1 + res->u.fArray.fCount) * 4; 1.536 +} 1.537 + 1.538 +static void intvector_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.539 + struct SRBRoot *bundle, struct SResource *res, 1.540 + UErrorCode *status) { 1.541 + uint32_t i = 0; 1.542 + udata_write32(mem, res->u.fIntVector.fCount); 1.543 + for(i = 0; i<res->u.fIntVector.fCount; i++) { 1.544 + udata_write32(mem, res->u.fIntVector.fArray[i]); 1.545 + } 1.546 + *byteOffset += (1 + res->u.fIntVector.fCount) * 4; 1.547 +} 1.548 + 1.549 +static void bin_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.550 + struct SRBRoot *bundle, struct SResource *res, 1.551 + UErrorCode *status) { 1.552 + uint32_t pad = 0; 1.553 + uint32_t dataStart = *byteOffset + sizeof(res->u.fBinaryValue.fLength); 1.554 + 1.555 + if (dataStart % BIN_ALIGNMENT) { 1.556 + pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT); 1.557 + udata_writePadding(mem, pad); /* pad == 4 or 8 or 12 */ 1.558 + *byteOffset += pad; 1.559 + } 1.560 + 1.561 + udata_write32(mem, res->u.fBinaryValue.fLength); 1.562 + if (res->u.fBinaryValue.fLength > 0) { 1.563 + udata_writeBlock(mem, res->u.fBinaryValue.fData, res->u.fBinaryValue.fLength); 1.564 + } 1.565 + *byteOffset += 4 + res->u.fBinaryValue.fLength; 1.566 +} 1.567 + 1.568 +static void table_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.569 + struct SRBRoot *bundle, struct SResource *res, 1.570 + UErrorCode *status) { 1.571 + struct SResource *current; 1.572 + uint32_t i; 1.573 + 1.574 + if (U_FAILURE(*status)) { 1.575 + return; 1.576 + } 1.577 + for (i = 0, current = res->u.fTable.fFirst; current != NULL; ++i, current = current->fNext) { 1.578 + assert(i < res->u.fTable.fCount); 1.579 + res_write(mem, byteOffset, bundle, current, status); 1.580 + } 1.581 + assert(i == res->u.fTable.fCount); 1.582 + 1.583 + if(res->u.fTable.fType == URES_TABLE) { 1.584 + udata_write16(mem, (uint16_t)res->u.fTable.fCount); 1.585 + for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 1.586 + udata_write16(mem, makeKey16(bundle, current->fKey)); 1.587 + } 1.588 + *byteOffset += (1 + res->u.fTable.fCount)* 2; 1.589 + if ((res->u.fTable.fCount & 1) == 0) { 1.590 + /* 16-bit count and even number of 16-bit key offsets need padding before 32-bit resource items */ 1.591 + udata_writePadding(mem, 2); 1.592 + *byteOffset += 2; 1.593 + } 1.594 + } else /* URES_TABLE32 */ { 1.595 + udata_write32(mem, res->u.fTable.fCount); 1.596 + for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 1.597 + udata_write32(mem, (uint32_t)current->fKey); 1.598 + } 1.599 + *byteOffset += (1 + res->u.fTable.fCount)* 4; 1.600 + } 1.601 + for (current = res->u.fTable.fFirst; current != NULL; current = current->fNext) { 1.602 + udata_write32(mem, current->fRes); 1.603 + } 1.604 + *byteOffset += res->u.fTable.fCount * 4; 1.605 +} 1.606 + 1.607 +void res_write(UNewDataMemory *mem, uint32_t *byteOffset, 1.608 + struct SRBRoot *bundle, struct SResource *res, 1.609 + UErrorCode *status) { 1.610 + uint8_t paddingSize; 1.611 + 1.612 + if (U_FAILURE(*status) || res == NULL) { 1.613 + return; 1.614 + } 1.615 + if (res->fWritten) { 1.616 + assert(res->fRes != RES_BOGUS); 1.617 + return; 1.618 + } 1.619 + switch (res->fType) { 1.620 + case URES_STRING: 1.621 + string_write (mem, byteOffset, bundle, res, status); 1.622 + break; 1.623 + case URES_ALIAS: 1.624 + alias_write (mem, byteOffset, bundle, res, status); 1.625 + break; 1.626 + case URES_INT_VECTOR: 1.627 + intvector_write (mem, byteOffset, bundle, res, status); 1.628 + break; 1.629 + case URES_BINARY: 1.630 + bin_write (mem, byteOffset, bundle, res, status); 1.631 + break; 1.632 + case URES_INT: 1.633 + break; /* fRes was set by int_open() */ 1.634 + case URES_ARRAY: 1.635 + array_write (mem, byteOffset, bundle, res, status); 1.636 + break; 1.637 + case URES_TABLE: 1.638 + table_write (mem, byteOffset, bundle, res, status); 1.639 + break; 1.640 + default: 1.641 + *status = U_INTERNAL_PROGRAM_ERROR; 1.642 + break; 1.643 + } 1.644 + paddingSize = calcPadding(*byteOffset); 1.645 + if (paddingSize > 0) { 1.646 + udata_writePadding(mem, paddingSize); 1.647 + *byteOffset += paddingSize; 1.648 + } 1.649 + res->fWritten = TRUE; 1.650 +} 1.651 + 1.652 +void bundle_write(struct SRBRoot *bundle, 1.653 + const char *outputDir, const char *outputPkg, 1.654 + char *writtenFilename, int writtenFilenameLen, 1.655 + UErrorCode *status) { 1.656 + UNewDataMemory *mem = NULL; 1.657 + uint32_t byteOffset = 0; 1.658 + uint32_t top, size; 1.659 + char dataName[1024]; 1.660 + int32_t indexes[URES_INDEX_TOP]; 1.661 + 1.662 + bundle_compactKeys(bundle, status); 1.663 + /* 1.664 + * Add padding bytes to fKeys so that fKeysTop is 4-aligned. 1.665 + * Safe because the capacity is a multiple of 4. 1.666 + */ 1.667 + while (bundle->fKeysTop & 3) { 1.668 + bundle->fKeys[bundle->fKeysTop++] = (char)0xaa; 1.669 + } 1.670 + /* 1.671 + * In URES_TABLE, use all local key offsets that fit into 16 bits, 1.672 + * and use the remaining 16-bit offsets for pool key offsets 1.673 + * if there are any. 1.674 + * If there are no local keys, then use the whole 16-bit space 1.675 + * for pool key offsets. 1.676 + * Note: This cannot be changed without changing the major formatVersion. 1.677 + */ 1.678 + if (bundle->fKeysBottom < bundle->fKeysTop) { 1.679 + if (bundle->fKeysTop <= 0x10000) { 1.680 + bundle->fLocalKeyLimit = bundle->fKeysTop; 1.681 + } else { 1.682 + bundle->fLocalKeyLimit = 0x10000; 1.683 + } 1.684 + } else { 1.685 + bundle->fLocalKeyLimit = 0; 1.686 + } 1.687 + 1.688 + bundle_compactStrings(bundle, status); 1.689 + res_write16(bundle, bundle->fRoot, status); 1.690 + if (bundle->f16BitUnitsLength & 1) { 1.691 + bundle->f16BitUnits[bundle->f16BitUnitsLength++] = 0xaaaa; /* pad to multiple of 4 bytes */ 1.692 + } 1.693 + /* all keys have been mapped */ 1.694 + uprv_free(bundle->fKeyMap); 1.695 + bundle->fKeyMap = NULL; 1.696 + 1.697 + byteOffset = bundle->fKeysTop + bundle->f16BitUnitsLength * 2; 1.698 + res_preWrite(&byteOffset, bundle, bundle->fRoot, status); 1.699 + 1.700 + /* total size including the root item */ 1.701 + top = byteOffset; 1.702 + 1.703 + if (U_FAILURE(*status)) { 1.704 + return; 1.705 + } 1.706 + 1.707 + if (writtenFilename && writtenFilenameLen) { 1.708 + *writtenFilename = 0; 1.709 + } 1.710 + 1.711 + if (writtenFilename) { 1.712 + int32_t off = 0, len = 0; 1.713 + if (outputDir) { 1.714 + len = (int32_t)uprv_strlen(outputDir); 1.715 + if (len > writtenFilenameLen) { 1.716 + len = writtenFilenameLen; 1.717 + } 1.718 + uprv_strncpy(writtenFilename, outputDir, len); 1.719 + } 1.720 + if (writtenFilenameLen -= len) { 1.721 + off += len; 1.722 + writtenFilename[off] = U_FILE_SEP_CHAR; 1.723 + if (--writtenFilenameLen) { 1.724 + ++off; 1.725 + if(outputPkg != NULL) 1.726 + { 1.727 + uprv_strcpy(writtenFilename+off, outputPkg); 1.728 + off += (int32_t)uprv_strlen(outputPkg); 1.729 + writtenFilename[off] = '_'; 1.730 + ++off; 1.731 + } 1.732 + 1.733 + len = (int32_t)uprv_strlen(bundle->fLocale); 1.734 + if (len > writtenFilenameLen) { 1.735 + len = writtenFilenameLen; 1.736 + } 1.737 + uprv_strncpy(writtenFilename + off, bundle->fLocale, len); 1.738 + if (writtenFilenameLen -= len) { 1.739 + off += len; 1.740 + len = 5; 1.741 + if (len > writtenFilenameLen) { 1.742 + len = writtenFilenameLen; 1.743 + } 1.744 + uprv_strncpy(writtenFilename + off, ".res", len); 1.745 + } 1.746 + } 1.747 + } 1.748 + } 1.749 + 1.750 + if(outputPkg) 1.751 + { 1.752 + uprv_strcpy(dataName, outputPkg); 1.753 + uprv_strcat(dataName, "_"); 1.754 + uprv_strcat(dataName, bundle->fLocale); 1.755 + } 1.756 + else 1.757 + { 1.758 + uprv_strcpy(dataName, bundle->fLocale); 1.759 + } 1.760 + 1.761 + uprv_memcpy(dataInfo.formatVersion, gFormatVersions + gFormatVersion, sizeof(UVersionInfo)); 1.762 + 1.763 + mem = udata_create(outputDir, "res", dataName, &dataInfo, (gIncludeCopyright==TRUE)? U_COPYRIGHT_STRING:NULL, status); 1.764 + if(U_FAILURE(*status)){ 1.765 + return; 1.766 + } 1.767 + 1.768 + /* write the root item */ 1.769 + udata_write32(mem, bundle->fRoot->fRes); 1.770 + 1.771 + /* 1.772 + * formatVersion 1.1 (ICU 2.8): 1.773 + * write int32_t indexes[] after root and before the strings 1.774 + * to make it easier to parse resource bundles in icuswap or from Java etc. 1.775 + */ 1.776 + uprv_memset(indexes, 0, sizeof(indexes)); 1.777 + indexes[URES_INDEX_LENGTH]= bundle->fIndexLength; 1.778 + indexes[URES_INDEX_KEYS_TOP]= bundle->fKeysTop>>2; 1.779 + indexes[URES_INDEX_RESOURCES_TOP]= (int32_t)(top>>2); 1.780 + indexes[URES_INDEX_BUNDLE_TOP]= indexes[URES_INDEX_RESOURCES_TOP]; 1.781 + indexes[URES_INDEX_MAX_TABLE_LENGTH]= bundle->fMaxTableLength; 1.782 + 1.783 + /* 1.784 + * formatVersion 1.2 (ICU 3.6): 1.785 + * write indexes[URES_INDEX_ATTRIBUTES] with URES_ATT_NO_FALLBACK set or not set 1.786 + * the memset() above initialized all indexes[] to 0 1.787 + */ 1.788 + if (bundle->noFallback) { 1.789 + indexes[URES_INDEX_ATTRIBUTES]=URES_ATT_NO_FALLBACK; 1.790 + } 1.791 + /* 1.792 + * formatVersion 2.0 (ICU 4.4): 1.793 + * more compact string value storage, optional pool bundle 1.794 + */ 1.795 + if (URES_INDEX_16BIT_TOP < bundle->fIndexLength) { 1.796 + indexes[URES_INDEX_16BIT_TOP] = (bundle->fKeysTop>>2) + (bundle->f16BitUnitsLength>>1); 1.797 + } 1.798 + if (URES_INDEX_POOL_CHECKSUM < bundle->fIndexLength) { 1.799 + if (bundle->fIsPoolBundle) { 1.800 + indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_IS_POOL_BUNDLE | URES_ATT_NO_FALLBACK; 1.801 + indexes[URES_INDEX_POOL_CHECKSUM] = 1.802 + (int32_t)computeCRC((char *)(bundle->fKeys + bundle->fKeysBottom), 1.803 + (uint32_t)(bundle->fKeysTop - bundle->fKeysBottom), 1.804 + 0); 1.805 + } else if (gUsePoolBundle) { 1.806 + indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_USES_POOL_BUNDLE; 1.807 + indexes[URES_INDEX_POOL_CHECKSUM] = bundle->fPoolChecksum; 1.808 + } 1.809 + } 1.810 + 1.811 + /* write the indexes[] */ 1.812 + udata_writeBlock(mem, indexes, bundle->fIndexLength*4); 1.813 + 1.814 + /* write the table key strings */ 1.815 + udata_writeBlock(mem, bundle->fKeys+bundle->fKeysBottom, 1.816 + bundle->fKeysTop-bundle->fKeysBottom); 1.817 + 1.818 + /* write the v2 UTF-16 strings, URES_TABLE16 and URES_ARRAY16 */ 1.819 + udata_writeBlock(mem, bundle->f16BitUnits, bundle->f16BitUnitsLength*2); 1.820 + 1.821 + /* write all of the bundle contents: the root item and its children */ 1.822 + byteOffset = bundle->fKeysTop + bundle->f16BitUnitsLength * 2; 1.823 + res_write(mem, &byteOffset, bundle, bundle->fRoot, status); 1.824 + assert(byteOffset == top); 1.825 + 1.826 + size = udata_finish(mem, status); 1.827 + if(top != size) { 1.828 + fprintf(stderr, "genrb error: wrote %u bytes but counted %u\n", 1.829 + (int)size, (int)top); 1.830 + *status = U_INTERNAL_PROGRAM_ERROR; 1.831 + } 1.832 +} 1.833 + 1.834 +/* Opening Functions */ 1.835 + 1.836 +/* gcc 4.2 complained "no previous prototype for res_open" without this prototype... */ 1.837 +struct SResource* res_open(struct SRBRoot *bundle, const char *tag, 1.838 + const struct UString* comment, UErrorCode* status); 1.839 + 1.840 +struct SResource* res_open(struct SRBRoot *bundle, const char *tag, 1.841 + const struct UString* comment, UErrorCode* status){ 1.842 + struct SResource *res; 1.843 + int32_t key = bundle_addtag(bundle, tag, status); 1.844 + if (U_FAILURE(*status)) { 1.845 + return NULL; 1.846 + } 1.847 + 1.848 + res = (struct SResource *) uprv_malloc(sizeof(struct SResource)); 1.849 + if (res == NULL) { 1.850 + *status = U_MEMORY_ALLOCATION_ERROR; 1.851 + return NULL; 1.852 + } 1.853 + uprv_memset(res, 0, sizeof(struct SResource)); 1.854 + res->fKey = key; 1.855 + res->fRes = RES_BOGUS; 1.856 + 1.857 + ustr_init(&res->fComment); 1.858 + if(comment != NULL){ 1.859 + ustr_cpy(&res->fComment, comment, status); 1.860 + if (U_FAILURE(*status)) { 1.861 + res_close(res); 1.862 + return NULL; 1.863 + } 1.864 + } 1.865 + return res; 1.866 +} 1.867 + 1.868 +struct SResource* res_none() { 1.869 + return (struct SResource*)&kNoResource; 1.870 +} 1.871 + 1.872 +struct SResource* table_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) { 1.873 + struct SResource *res = res_open(bundle, tag, comment, status); 1.874 + if (U_FAILURE(*status)) { 1.875 + return NULL; 1.876 + } 1.877 + res->fType = URES_TABLE; 1.878 + res->u.fTable.fRoot = bundle; 1.879 + return res; 1.880 +} 1.881 + 1.882 +struct SResource* array_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) { 1.883 + struct SResource *res = res_open(bundle, tag, comment, status); 1.884 + if (U_FAILURE(*status)) { 1.885 + return NULL; 1.886 + } 1.887 + res->fType = URES_ARRAY; 1.888 + return res; 1.889 +} 1.890 + 1.891 +static int32_t U_CALLCONV 1.892 +string_hash(const UElement key) { 1.893 + const struct SResource *res = (struct SResource *)key.pointer; 1.894 + return ustr_hashUCharsN(res->u.fString.fChars, res->u.fString.fLength); 1.895 +} 1.896 + 1.897 +static UBool U_CALLCONV 1.898 +string_comp(const UElement key1, const UElement key2) { 1.899 + const struct SResource *res1 = (struct SResource *)key1.pointer; 1.900 + const struct SResource *res2 = (struct SResource *)key2.pointer; 1.901 + return 0 == u_strCompare(res1->u.fString.fChars, res1->u.fString.fLength, 1.902 + res2->u.fString.fChars, res2->u.fString.fLength, 1.903 + FALSE); 1.904 +} 1.905 + 1.906 +struct SResource *string_open(struct SRBRoot *bundle, const char *tag, const UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) { 1.907 + struct SResource *res = res_open(bundle, tag, comment, status); 1.908 + if (U_FAILURE(*status)) { 1.909 + return NULL; 1.910 + } 1.911 + res->fType = URES_STRING; 1.912 + 1.913 + if (len == 0 && gFormatVersion > 1) { 1.914 + res->u.fString.fChars = &gEmptyString; 1.915 + res->fRes = 0; 1.916 + res->fWritten = TRUE; 1.917 + return res; 1.918 + } 1.919 + 1.920 + res->u.fString.fLength = len; 1.921 + 1.922 + if (gFormatVersion > 1) { 1.923 + /* check for duplicates */ 1.924 + res->u.fString.fChars = (UChar *)value; 1.925 + if (bundle->fStringSet == NULL) { 1.926 + UErrorCode localStatus = U_ZERO_ERROR; /* if failure: just don't detect dups */ 1.927 + bundle->fStringSet = uhash_open(string_hash, string_comp, string_comp, &localStatus); 1.928 + } else { 1.929 + res->u.fString.fSame = uhash_get(bundle->fStringSet, res); 1.930 + } 1.931 + } 1.932 + if (res->u.fString.fSame == NULL) { 1.933 + /* this is a new string */ 1.934 + res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1)); 1.935 + 1.936 + if (res->u.fString.fChars == NULL) { 1.937 + *status = U_MEMORY_ALLOCATION_ERROR; 1.938 + uprv_free(res); 1.939 + return NULL; 1.940 + } 1.941 + 1.942 + uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * len); 1.943 + res->u.fString.fChars[len] = 0; 1.944 + if (bundle->fStringSet != NULL) { 1.945 + /* put it into the set for finding duplicates */ 1.946 + uhash_put(bundle->fStringSet, res, res, status); 1.947 + } 1.948 + 1.949 + if (bundle->fStringsForm != STRINGS_UTF16_V1) { 1.950 + if (len <= MAX_IMPLICIT_STRING_LENGTH && !U16_IS_TRAIL(value[0]) && len == u_strlen(value)) { 1.951 + /* 1.952 + * This string will be stored without an explicit length. 1.953 + * Runtime will detect !U16_IS_TRAIL(value[0]) and call u_strlen(). 1.954 + */ 1.955 + res->u.fString.fNumCharsForLength = 0; 1.956 + } else if (len <= 0x3ee) { 1.957 + res->u.fString.fNumCharsForLength = 1; 1.958 + } else if (len <= 0xfffff) { 1.959 + res->u.fString.fNumCharsForLength = 2; 1.960 + } else { 1.961 + res->u.fString.fNumCharsForLength = 3; 1.962 + } 1.963 + bundle->f16BitUnitsLength += res->u.fString.fNumCharsForLength + len + 1; /* +1 for the NUL */ 1.964 + } 1.965 + } else { 1.966 + /* this is a duplicate of fSame */ 1.967 + struct SResource *same = res->u.fString.fSame; 1.968 + res->u.fString.fChars = same->u.fString.fChars; 1.969 + } 1.970 + return res; 1.971 +} 1.972 + 1.973 +/* TODO: make alias_open and string_open use the same code */ 1.974 +struct SResource *alias_open(struct SRBRoot *bundle, const char *tag, UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) { 1.975 + struct SResource *res = res_open(bundle, tag, comment, status); 1.976 + if (U_FAILURE(*status)) { 1.977 + return NULL; 1.978 + } 1.979 + res->fType = URES_ALIAS; 1.980 + if (len == 0 && gFormatVersion > 1) { 1.981 + res->u.fString.fChars = &gEmptyString; 1.982 + res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_ALIAS); 1.983 + res->fWritten = TRUE; 1.984 + return res; 1.985 + } 1.986 + 1.987 + res->u.fString.fLength = len; 1.988 + res->u.fString.fChars = (UChar *) uprv_malloc(sizeof(UChar) * (len + 1)); 1.989 + if (res->u.fString.fChars == NULL) { 1.990 + *status = U_MEMORY_ALLOCATION_ERROR; 1.991 + uprv_free(res); 1.992 + return NULL; 1.993 + } 1.994 + uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len + 1)); 1.995 + return res; 1.996 +} 1.997 + 1.998 + 1.999 +struct SResource* intvector_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) { 1.1000 + struct SResource *res = res_open(bundle, tag, comment, status); 1.1001 + if (U_FAILURE(*status)) { 1.1002 + return NULL; 1.1003 + } 1.1004 + res->fType = URES_INT_VECTOR; 1.1005 + 1.1006 + res->u.fIntVector.fCount = 0; 1.1007 + res->u.fIntVector.fArray = (uint32_t *) uprv_malloc(sizeof(uint32_t) * RESLIST_MAX_INT_VECTOR); 1.1008 + if (res->u.fIntVector.fArray == NULL) { 1.1009 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1010 + uprv_free(res); 1.1011 + return NULL; 1.1012 + } 1.1013 + return res; 1.1014 +} 1.1015 + 1.1016 +struct SResource *int_open(struct SRBRoot *bundle, const char *tag, int32_t value, const struct UString* comment, UErrorCode *status) { 1.1017 + struct SResource *res = res_open(bundle, tag, comment, status); 1.1018 + if (U_FAILURE(*status)) { 1.1019 + return NULL; 1.1020 + } 1.1021 + res->fType = URES_INT; 1.1022 + res->u.fIntValue.fValue = value; 1.1023 + res->fRes = URES_MAKE_RESOURCE(URES_INT, value & 0x0FFFFFFF); 1.1024 + res->fWritten = TRUE; 1.1025 + return res; 1.1026 +} 1.1027 + 1.1028 +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) { 1.1029 + struct SResource *res = res_open(bundle, tag, comment, status); 1.1030 + if (U_FAILURE(*status)) { 1.1031 + return NULL; 1.1032 + } 1.1033 + res->fType = URES_BINARY; 1.1034 + 1.1035 + res->u.fBinaryValue.fLength = length; 1.1036 + res->u.fBinaryValue.fFileName = NULL; 1.1037 + if(fileName!=NULL && uprv_strcmp(fileName, "") !=0){ 1.1038 + res->u.fBinaryValue.fFileName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(fileName)+1)); 1.1039 + uprv_strcpy(res->u.fBinaryValue.fFileName,fileName); 1.1040 + } 1.1041 + if (length > 0) { 1.1042 + res->u.fBinaryValue.fData = (uint8_t *) uprv_malloc(sizeof(uint8_t) * length); 1.1043 + 1.1044 + if (res->u.fBinaryValue.fData == NULL) { 1.1045 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1046 + uprv_free(res); 1.1047 + return NULL; 1.1048 + } 1.1049 + 1.1050 + uprv_memcpy(res->u.fBinaryValue.fData, data, length); 1.1051 + } 1.1052 + else { 1.1053 + res->u.fBinaryValue.fData = NULL; 1.1054 + if (gFormatVersion > 1) { 1.1055 + res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_BINARY); 1.1056 + res->fWritten = TRUE; 1.1057 + } 1.1058 + } 1.1059 + 1.1060 + return res; 1.1061 +} 1.1062 + 1.1063 +struct SRBRoot *bundle_open(const struct UString* comment, UBool isPoolBundle, UErrorCode *status) { 1.1064 + struct SRBRoot *bundle; 1.1065 + 1.1066 + if (U_FAILURE(*status)) { 1.1067 + return NULL; 1.1068 + } 1.1069 + 1.1070 + bundle = (struct SRBRoot *) uprv_malloc(sizeof(struct SRBRoot)); 1.1071 + if (bundle == NULL) { 1.1072 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1073 + return 0; 1.1074 + } 1.1075 + uprv_memset(bundle, 0, sizeof(struct SRBRoot)); 1.1076 + 1.1077 + bundle->fKeys = (char *) uprv_malloc(sizeof(char) * KEY_SPACE_SIZE); 1.1078 + bundle->fRoot = table_open(bundle, NULL, comment, status); 1.1079 + if (bundle->fKeys == NULL || bundle->fRoot == NULL || U_FAILURE(*status)) { 1.1080 + if (U_SUCCESS(*status)) { 1.1081 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1082 + } 1.1083 + bundle_close(bundle, status); 1.1084 + return NULL; 1.1085 + } 1.1086 + 1.1087 + bundle->fLocale = NULL; 1.1088 + bundle->fKeysCapacity = KEY_SPACE_SIZE; 1.1089 + /* formatVersion 1.1: start fKeysTop after the root item and indexes[] */ 1.1090 + bundle->fIsPoolBundle = isPoolBundle; 1.1091 + if (gUsePoolBundle || isPoolBundle) { 1.1092 + bundle->fIndexLength = URES_INDEX_POOL_CHECKSUM + 1; 1.1093 + } else if (gFormatVersion >= 2) { 1.1094 + bundle->fIndexLength = URES_INDEX_16BIT_TOP + 1; 1.1095 + } else /* formatVersion 1 */ { 1.1096 + bundle->fIndexLength = URES_INDEX_ATTRIBUTES + 1; 1.1097 + } 1.1098 + bundle->fKeysBottom = (1 /* root */ + bundle->fIndexLength) * 4; 1.1099 + uprv_memset(bundle->fKeys, 0, bundle->fKeysBottom); 1.1100 + bundle->fKeysTop = bundle->fKeysBottom; 1.1101 + 1.1102 + if (gFormatVersion == 1) { 1.1103 + bundle->fStringsForm = STRINGS_UTF16_V1; 1.1104 + } else { 1.1105 + bundle->fStringsForm = STRINGS_UTF16_V2; 1.1106 + } 1.1107 + 1.1108 + return bundle; 1.1109 +} 1.1110 + 1.1111 +/* Closing Functions */ 1.1112 +static void table_close(struct SResource *table) { 1.1113 + struct SResource *current = NULL; 1.1114 + struct SResource *prev = NULL; 1.1115 + 1.1116 + current = table->u.fTable.fFirst; 1.1117 + 1.1118 + while (current != NULL) { 1.1119 + prev = current; 1.1120 + current = current->fNext; 1.1121 + 1.1122 + res_close(prev); 1.1123 + } 1.1124 + 1.1125 + table->u.fTable.fFirst = NULL; 1.1126 +} 1.1127 + 1.1128 +static void array_close(struct SResource *array) { 1.1129 + struct SResource *current = NULL; 1.1130 + struct SResource *prev = NULL; 1.1131 + 1.1132 + if(array==NULL){ 1.1133 + return; 1.1134 + } 1.1135 + current = array->u.fArray.fFirst; 1.1136 + 1.1137 + while (current != NULL) { 1.1138 + prev = current; 1.1139 + current = current->fNext; 1.1140 + 1.1141 + res_close(prev); 1.1142 + } 1.1143 + array->u.fArray.fFirst = NULL; 1.1144 +} 1.1145 + 1.1146 +static void string_close(struct SResource *string) { 1.1147 + if (string->u.fString.fChars != NULL && 1.1148 + string->u.fString.fChars != &gEmptyString && 1.1149 + string->u.fString.fSame == NULL 1.1150 + ) { 1.1151 + uprv_free(string->u.fString.fChars); 1.1152 + string->u.fString.fChars =NULL; 1.1153 + } 1.1154 +} 1.1155 + 1.1156 +static void alias_close(struct SResource *alias) { 1.1157 + if (alias->u.fString.fChars != NULL) { 1.1158 + uprv_free(alias->u.fString.fChars); 1.1159 + alias->u.fString.fChars =NULL; 1.1160 + } 1.1161 +} 1.1162 + 1.1163 +static void intvector_close(struct SResource *intvector) { 1.1164 + if (intvector->u.fIntVector.fArray != NULL) { 1.1165 + uprv_free(intvector->u.fIntVector.fArray); 1.1166 + intvector->u.fIntVector.fArray =NULL; 1.1167 + } 1.1168 +} 1.1169 + 1.1170 +static void int_close(struct SResource *intres) { 1.1171 + /* Intentionally left blank */ 1.1172 +} 1.1173 + 1.1174 +static void bin_close(struct SResource *binres) { 1.1175 + if (binres->u.fBinaryValue.fData != NULL) { 1.1176 + uprv_free(binres->u.fBinaryValue.fData); 1.1177 + binres->u.fBinaryValue.fData = NULL; 1.1178 + } 1.1179 + if (binres->u.fBinaryValue.fFileName != NULL) { 1.1180 + uprv_free(binres->u.fBinaryValue.fFileName); 1.1181 + binres->u.fBinaryValue.fFileName = NULL; 1.1182 + } 1.1183 +} 1.1184 + 1.1185 +void res_close(struct SResource *res) { 1.1186 + if (res != NULL) { 1.1187 + switch(res->fType) { 1.1188 + case URES_STRING: 1.1189 + string_close(res); 1.1190 + break; 1.1191 + case URES_ALIAS: 1.1192 + alias_close(res); 1.1193 + break; 1.1194 + case URES_INT_VECTOR: 1.1195 + intvector_close(res); 1.1196 + break; 1.1197 + case URES_BINARY: 1.1198 + bin_close(res); 1.1199 + break; 1.1200 + case URES_INT: 1.1201 + int_close(res); 1.1202 + break; 1.1203 + case URES_ARRAY: 1.1204 + array_close(res); 1.1205 + break; 1.1206 + case URES_TABLE: 1.1207 + table_close(res); 1.1208 + break; 1.1209 + default: 1.1210 + /* Shouldn't happen */ 1.1211 + break; 1.1212 + } 1.1213 + 1.1214 + ustr_deinit(&res->fComment); 1.1215 + uprv_free(res); 1.1216 + } 1.1217 +} 1.1218 + 1.1219 +void bundle_close(struct SRBRoot *bundle, UErrorCode *status) { 1.1220 + res_close(bundle->fRoot); 1.1221 + uprv_free(bundle->fLocale); 1.1222 + uprv_free(bundle->fKeys); 1.1223 + uprv_free(bundle->fKeyMap); 1.1224 + uhash_close(bundle->fStringSet); 1.1225 + uprv_free(bundle->f16BitUnits); 1.1226 + uprv_free(bundle); 1.1227 +} 1.1228 + 1.1229 +void bundle_closeString(struct SRBRoot *bundle, struct SResource *string) { 1.1230 + if (bundle->fStringSet != NULL) { 1.1231 + uhash_remove(bundle->fStringSet, string); 1.1232 + } 1.1233 + string_close(string); 1.1234 +} 1.1235 + 1.1236 +/* Adding Functions */ 1.1237 +void table_add(struct SResource *table, struct SResource *res, int linenumber, UErrorCode *status) { 1.1238 + struct SResource *current = NULL; 1.1239 + struct SResource *prev = NULL; 1.1240 + struct SResTable *list; 1.1241 + const char *resKeyString; 1.1242 + 1.1243 + if (U_FAILURE(*status)) { 1.1244 + return; 1.1245 + } 1.1246 + if (res == &kNoResource) { 1.1247 + return; 1.1248 + } 1.1249 + 1.1250 + /* remember this linenumber to report to the user if there is a duplicate key */ 1.1251 + res->line = linenumber; 1.1252 + 1.1253 + /* here we need to traverse the list */ 1.1254 + list = &(table->u.fTable); 1.1255 + ++(list->fCount); 1.1256 + 1.1257 + /* is list still empty? */ 1.1258 + if (list->fFirst == NULL) { 1.1259 + list->fFirst = res; 1.1260 + res->fNext = NULL; 1.1261 + return; 1.1262 + } 1.1263 + 1.1264 + resKeyString = list->fRoot->fKeys + res->fKey; 1.1265 + 1.1266 + current = list->fFirst; 1.1267 + 1.1268 + while (current != NULL) { 1.1269 + const char *currentKeyString = list->fRoot->fKeys + current->fKey; 1.1270 + int diff; 1.1271 + /* 1.1272 + * formatVersion 1: compare key strings in native-charset order 1.1273 + * formatVersion 2 and up: compare key strings in ASCII order 1.1274 + */ 1.1275 + if (gFormatVersion == 1 || U_CHARSET_FAMILY == U_ASCII_FAMILY) { 1.1276 + diff = uprv_strcmp(currentKeyString, resKeyString); 1.1277 + } else { 1.1278 + diff = uprv_compareInvCharsAsAscii(currentKeyString, resKeyString); 1.1279 + } 1.1280 + if (diff < 0) { 1.1281 + prev = current; 1.1282 + current = current->fNext; 1.1283 + } else if (diff > 0) { 1.1284 + /* we're either in front of list, or in middle */ 1.1285 + if (prev == NULL) { 1.1286 + /* front of the list */ 1.1287 + list->fFirst = res; 1.1288 + } else { 1.1289 + /* middle of the list */ 1.1290 + prev->fNext = res; 1.1291 + } 1.1292 + 1.1293 + res->fNext = current; 1.1294 + return; 1.1295 + } else { 1.1296 + /* Key already exists! ERROR! */ 1.1297 + error(linenumber, "duplicate key '%s' in table, first appeared at line %d", currentKeyString, current->line); 1.1298 + *status = U_UNSUPPORTED_ERROR; 1.1299 + return; 1.1300 + } 1.1301 + } 1.1302 + 1.1303 + /* end of list */ 1.1304 + prev->fNext = res; 1.1305 + res->fNext = NULL; 1.1306 +} 1.1307 + 1.1308 +void array_add(struct SResource *array, struct SResource *res, UErrorCode *status) { 1.1309 + if (U_FAILURE(*status)) { 1.1310 + return; 1.1311 + } 1.1312 + 1.1313 + if (array->u.fArray.fFirst == NULL) { 1.1314 + array->u.fArray.fFirst = res; 1.1315 + array->u.fArray.fLast = res; 1.1316 + } else { 1.1317 + array->u.fArray.fLast->fNext = res; 1.1318 + array->u.fArray.fLast = res; 1.1319 + } 1.1320 + 1.1321 + (array->u.fArray.fCount)++; 1.1322 +} 1.1323 + 1.1324 +void intvector_add(struct SResource *intvector, int32_t value, UErrorCode *status) { 1.1325 + if (U_FAILURE(*status)) { 1.1326 + return; 1.1327 + } 1.1328 + 1.1329 + *(intvector->u.fIntVector.fArray + intvector->u.fIntVector.fCount) = value; 1.1330 + intvector->u.fIntVector.fCount++; 1.1331 +} 1.1332 + 1.1333 +/* Misc Functions */ 1.1334 + 1.1335 +void bundle_setlocale(struct SRBRoot *bundle, UChar *locale, UErrorCode *status) { 1.1336 + 1.1337 + if(U_FAILURE(*status)) { 1.1338 + return; 1.1339 + } 1.1340 + 1.1341 + if (bundle->fLocale!=NULL) { 1.1342 + uprv_free(bundle->fLocale); 1.1343 + } 1.1344 + 1.1345 + bundle->fLocale= (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1)); 1.1346 + 1.1347 + if(bundle->fLocale == NULL) { 1.1348 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1349 + return; 1.1350 + } 1.1351 + 1.1352 + /*u_strcpy(bundle->fLocale, locale);*/ 1.1353 + u_UCharsToChars(locale, bundle->fLocale, u_strlen(locale)+1); 1.1354 + 1.1355 +} 1.1356 + 1.1357 +static const char * 1.1358 +getKeyString(const struct SRBRoot *bundle, int32_t key) { 1.1359 + if (key < 0) { 1.1360 + return bundle->fPoolBundleKeys + (key & 0x7fffffff); 1.1361 + } else { 1.1362 + return bundle->fKeys + key; 1.1363 + } 1.1364 +} 1.1365 + 1.1366 +const char * 1.1367 +res_getKeyString(const struct SRBRoot *bundle, const struct SResource *res, char temp[8]) { 1.1368 + if (res->fKey == -1) { 1.1369 + return NULL; 1.1370 + } 1.1371 + return getKeyString(bundle, res->fKey); 1.1372 +} 1.1373 + 1.1374 +const char * 1.1375 +bundle_getKeyBytes(struct SRBRoot *bundle, int32_t *pLength) { 1.1376 + *pLength = bundle->fKeysTop - bundle->fKeysBottom; 1.1377 + return bundle->fKeys + bundle->fKeysBottom; 1.1378 +} 1.1379 + 1.1380 +int32_t 1.1381 +bundle_addKeyBytes(struct SRBRoot *bundle, const char *keyBytes, int32_t length, UErrorCode *status) { 1.1382 + int32_t keypos; 1.1383 + 1.1384 + if (U_FAILURE(*status)) { 1.1385 + return -1; 1.1386 + } 1.1387 + if (length < 0 || (keyBytes == NULL && length != 0)) { 1.1388 + *status = U_ILLEGAL_ARGUMENT_ERROR; 1.1389 + return -1; 1.1390 + } 1.1391 + if (length == 0) { 1.1392 + return bundle->fKeysTop; 1.1393 + } 1.1394 + 1.1395 + keypos = bundle->fKeysTop; 1.1396 + bundle->fKeysTop += length; 1.1397 + if (bundle->fKeysTop >= bundle->fKeysCapacity) { 1.1398 + /* overflow - resize the keys buffer */ 1.1399 + bundle->fKeysCapacity += KEY_SPACE_SIZE; 1.1400 + bundle->fKeys = uprv_realloc(bundle->fKeys, bundle->fKeysCapacity); 1.1401 + if(bundle->fKeys == NULL) { 1.1402 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1403 + return -1; 1.1404 + } 1.1405 + } 1.1406 + 1.1407 + uprv_memcpy(bundle->fKeys + keypos, keyBytes, length); 1.1408 + 1.1409 + return keypos; 1.1410 +} 1.1411 + 1.1412 +int32_t 1.1413 +bundle_addtag(struct SRBRoot *bundle, const char *tag, UErrorCode *status) { 1.1414 + int32_t keypos; 1.1415 + 1.1416 + if (U_FAILURE(*status)) { 1.1417 + return -1; 1.1418 + } 1.1419 + 1.1420 + if (tag == NULL) { 1.1421 + /* no error: the root table and array items have no keys */ 1.1422 + return -1; 1.1423 + } 1.1424 + 1.1425 + keypos = bundle_addKeyBytes(bundle, tag, (int32_t)(uprv_strlen(tag) + 1), status); 1.1426 + if (U_SUCCESS(*status)) { 1.1427 + ++bundle->fKeysCount; 1.1428 + } 1.1429 + return keypos; 1.1430 +} 1.1431 + 1.1432 +static int32_t 1.1433 +compareInt32(int32_t lPos, int32_t rPos) { 1.1434 + /* 1.1435 + * Compare possibly-negative key offsets. Don't just return lPos - rPos 1.1436 + * because that is prone to negative-integer underflows. 1.1437 + */ 1.1438 + if (lPos < rPos) { 1.1439 + return -1; 1.1440 + } else if (lPos > rPos) { 1.1441 + return 1; 1.1442 + } else { 1.1443 + return 0; 1.1444 + } 1.1445 +} 1.1446 + 1.1447 +static int32_t U_CALLCONV 1.1448 +compareKeySuffixes(const void *context, const void *l, const void *r) { 1.1449 + const struct SRBRoot *bundle=(const struct SRBRoot *)context; 1.1450 + int32_t lPos = ((const KeyMapEntry *)l)->oldpos; 1.1451 + int32_t rPos = ((const KeyMapEntry *)r)->oldpos; 1.1452 + const char *lStart = getKeyString(bundle, lPos); 1.1453 + const char *lLimit = lStart; 1.1454 + const char *rStart = getKeyString(bundle, rPos); 1.1455 + const char *rLimit = rStart; 1.1456 + int32_t diff; 1.1457 + while (*lLimit != 0) { ++lLimit; } 1.1458 + while (*rLimit != 0) { ++rLimit; } 1.1459 + /* compare keys in reverse character order */ 1.1460 + while (lStart < lLimit && rStart < rLimit) { 1.1461 + diff = (int32_t)(uint8_t)*--lLimit - (int32_t)(uint8_t)*--rLimit; 1.1462 + if (diff != 0) { 1.1463 + return diff; 1.1464 + } 1.1465 + } 1.1466 + /* sort equal suffixes by descending key length */ 1.1467 + diff = (int32_t)(rLimit - rStart) - (int32_t)(lLimit - lStart); 1.1468 + if (diff != 0) { 1.1469 + return diff; 1.1470 + } 1.1471 + /* Sort pool bundle keys first (negative oldpos), and otherwise keys in parsing order. */ 1.1472 + return compareInt32(lPos, rPos); 1.1473 +} 1.1474 + 1.1475 +static int32_t U_CALLCONV 1.1476 +compareKeyNewpos(const void *context, const void *l, const void *r) { 1.1477 + return compareInt32(((const KeyMapEntry *)l)->newpos, ((const KeyMapEntry *)r)->newpos); 1.1478 +} 1.1479 + 1.1480 +static int32_t U_CALLCONV 1.1481 +compareKeyOldpos(const void *context, const void *l, const void *r) { 1.1482 + return compareInt32(((const KeyMapEntry *)l)->oldpos, ((const KeyMapEntry *)r)->oldpos); 1.1483 +} 1.1484 + 1.1485 +void 1.1486 +bundle_compactKeys(struct SRBRoot *bundle, UErrorCode *status) { 1.1487 + KeyMapEntry *map; 1.1488 + char *keys; 1.1489 + int32_t i; 1.1490 + int32_t keysCount = bundle->fPoolBundleKeysCount + bundle->fKeysCount; 1.1491 + if (U_FAILURE(*status) || bundle->fKeysCount == 0 || bundle->fKeyMap != NULL) { 1.1492 + return; 1.1493 + } 1.1494 + map = (KeyMapEntry *)uprv_malloc(keysCount * sizeof(KeyMapEntry)); 1.1495 + if (map == NULL) { 1.1496 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1497 + return; 1.1498 + } 1.1499 + keys = (char *)bundle->fPoolBundleKeys; 1.1500 + for (i = 0; i < bundle->fPoolBundleKeysCount; ++i) { 1.1501 + map[i].oldpos = 1.1502 + (int32_t)(keys - bundle->fPoolBundleKeys) | 0x80000000; /* negative oldpos */ 1.1503 + map[i].newpos = 0; 1.1504 + while (*keys != 0) { ++keys; } /* skip the key */ 1.1505 + ++keys; /* skip the NUL */ 1.1506 + } 1.1507 + keys = bundle->fKeys + bundle->fKeysBottom; 1.1508 + for (; i < keysCount; ++i) { 1.1509 + map[i].oldpos = (int32_t)(keys - bundle->fKeys); 1.1510 + map[i].newpos = 0; 1.1511 + while (*keys != 0) { ++keys; } /* skip the key */ 1.1512 + ++keys; /* skip the NUL */ 1.1513 + } 1.1514 + /* Sort the keys so that each one is immediately followed by all of its suffixes. */ 1.1515 + uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry), 1.1516 + compareKeySuffixes, bundle, FALSE, status); 1.1517 + /* 1.1518 + * Make suffixes point into earlier, longer strings that contain them 1.1519 + * and mark the old, now unused suffix bytes as deleted. 1.1520 + */ 1.1521 + if (U_SUCCESS(*status)) { 1.1522 + keys = bundle->fKeys; 1.1523 + for (i = 0; i < keysCount;) { 1.1524 + /* 1.1525 + * This key is not a suffix of the previous one; 1.1526 + * keep this one and delete the following ones that are 1.1527 + * suffixes of this one. 1.1528 + */ 1.1529 + const char *key; 1.1530 + const char *keyLimit; 1.1531 + int32_t j = i + 1; 1.1532 + map[i].newpos = map[i].oldpos; 1.1533 + if (j < keysCount && map[j].oldpos < 0) { 1.1534 + /* Key string from the pool bundle, do not delete. */ 1.1535 + i = j; 1.1536 + continue; 1.1537 + } 1.1538 + key = getKeyString(bundle, map[i].oldpos); 1.1539 + for (keyLimit = key; *keyLimit != 0; ++keyLimit) {} 1.1540 + for (; j < keysCount && map[j].oldpos >= 0; ++j) { 1.1541 + const char *k; 1.1542 + char *suffix; 1.1543 + const char *suffixLimit; 1.1544 + int32_t offset; 1.1545 + suffix = keys + map[j].oldpos; 1.1546 + for (suffixLimit = suffix; *suffixLimit != 0; ++suffixLimit) {} 1.1547 + offset = (int32_t)(keyLimit - key) - (suffixLimit - suffix); 1.1548 + if (offset < 0) { 1.1549 + break; /* suffix cannot be longer than the original */ 1.1550 + } 1.1551 + /* Is it a suffix of the earlier, longer key? */ 1.1552 + for (k = keyLimit; suffix < suffixLimit && *--k == *--suffixLimit;) {} 1.1553 + if (suffix == suffixLimit && *k == *suffixLimit) { 1.1554 + map[j].newpos = map[i].oldpos + offset; /* yes, point to the earlier key */ 1.1555 + /* mark the suffix as deleted */ 1.1556 + while (*suffix != 0) { *suffix++ = 1; } 1.1557 + *suffix = 1; 1.1558 + } else { 1.1559 + break; /* not a suffix, restart from here */ 1.1560 + } 1.1561 + } 1.1562 + i = j; 1.1563 + } 1.1564 + /* 1.1565 + * Re-sort by newpos, then modify the key characters array in-place 1.1566 + * to squeeze out unused bytes, and readjust the newpos offsets. 1.1567 + */ 1.1568 + uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry), 1.1569 + compareKeyNewpos, NULL, FALSE, status); 1.1570 + if (U_SUCCESS(*status)) { 1.1571 + int32_t oldpos, newpos, limit; 1.1572 + oldpos = newpos = bundle->fKeysBottom; 1.1573 + limit = bundle->fKeysTop; 1.1574 + /* skip key offsets that point into the pool bundle rather than this new bundle */ 1.1575 + for (i = 0; i < keysCount && map[i].newpos < 0; ++i) {} 1.1576 + if (i < keysCount) { 1.1577 + while (oldpos < limit) { 1.1578 + if (keys[oldpos] == 1) { 1.1579 + ++oldpos; /* skip unused bytes */ 1.1580 + } else { 1.1581 + /* adjust the new offsets for keys starting here */ 1.1582 + while (i < keysCount && map[i].newpos == oldpos) { 1.1583 + map[i++].newpos = newpos; 1.1584 + } 1.1585 + /* move the key characters to their new position */ 1.1586 + keys[newpos++] = keys[oldpos++]; 1.1587 + } 1.1588 + } 1.1589 + assert(i == keysCount); 1.1590 + } 1.1591 + bundle->fKeysTop = newpos; 1.1592 + /* Re-sort once more, by old offsets for binary searching. */ 1.1593 + uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry), 1.1594 + compareKeyOldpos, NULL, FALSE, status); 1.1595 + if (U_SUCCESS(*status)) { 1.1596 + /* key size reduction by limit - newpos */ 1.1597 + bundle->fKeyMap = map; 1.1598 + map = NULL; 1.1599 + } 1.1600 + } 1.1601 + } 1.1602 + uprv_free(map); 1.1603 +} 1.1604 + 1.1605 +static int32_t U_CALLCONV 1.1606 +compareStringSuffixes(const void *context, const void *l, const void *r) { 1.1607 + struct SResource *left = *((struct SResource **)l); 1.1608 + struct SResource *right = *((struct SResource **)r); 1.1609 + const UChar *lStart = left->u.fString.fChars; 1.1610 + const UChar *lLimit = lStart + left->u.fString.fLength; 1.1611 + const UChar *rStart = right->u.fString.fChars; 1.1612 + const UChar *rLimit = rStart + right->u.fString.fLength; 1.1613 + int32_t diff; 1.1614 + /* compare keys in reverse character order */ 1.1615 + while (lStart < lLimit && rStart < rLimit) { 1.1616 + diff = (int32_t)*--lLimit - (int32_t)*--rLimit; 1.1617 + if (diff != 0) { 1.1618 + return diff; 1.1619 + } 1.1620 + } 1.1621 + /* sort equal suffixes by descending string length */ 1.1622 + return right->u.fString.fLength - left->u.fString.fLength; 1.1623 +} 1.1624 + 1.1625 +static int32_t U_CALLCONV 1.1626 +compareStringLengths(const void *context, const void *l, const void *r) { 1.1627 + struct SResource *left = *((struct SResource **)l); 1.1628 + struct SResource *right = *((struct SResource **)r); 1.1629 + int32_t diff; 1.1630 + /* Make "is suffix of another string" compare greater than a non-suffix. */ 1.1631 + diff = (int)(left->u.fString.fSame != NULL) - (int)(right->u.fString.fSame != NULL); 1.1632 + if (diff != 0) { 1.1633 + return diff; 1.1634 + } 1.1635 + /* sort by ascending string length */ 1.1636 + return left->u.fString.fLength - right->u.fString.fLength; 1.1637 +} 1.1638 + 1.1639 +static int32_t 1.1640 +string_writeUTF16v2(struct SRBRoot *bundle, struct SResource *res, int32_t utf16Length) { 1.1641 + int32_t length = res->u.fString.fLength; 1.1642 + res->fRes = URES_MAKE_RESOURCE(URES_STRING_V2, utf16Length); 1.1643 + res->fWritten = TRUE; 1.1644 + switch(res->u.fString.fNumCharsForLength) { 1.1645 + case 0: 1.1646 + break; 1.1647 + case 1: 1.1648 + bundle->f16BitUnits[utf16Length++] = (uint16_t)(0xdc00 + length); 1.1649 + break; 1.1650 + case 2: 1.1651 + bundle->f16BitUnits[utf16Length] = (uint16_t)(0xdfef + (length >> 16)); 1.1652 + bundle->f16BitUnits[utf16Length + 1] = (uint16_t)length; 1.1653 + utf16Length += 2; 1.1654 + break; 1.1655 + case 3: 1.1656 + bundle->f16BitUnits[utf16Length] = 0xdfff; 1.1657 + bundle->f16BitUnits[utf16Length + 1] = (uint16_t)(length >> 16); 1.1658 + bundle->f16BitUnits[utf16Length + 2] = (uint16_t)length; 1.1659 + utf16Length += 3; 1.1660 + break; 1.1661 + default: 1.1662 + break; /* will not occur */ 1.1663 + } 1.1664 + u_memcpy(bundle->f16BitUnits + utf16Length, res->u.fString.fChars, length + 1); 1.1665 + return utf16Length + length + 1; 1.1666 +} 1.1667 + 1.1668 +static void 1.1669 +bundle_compactStrings(struct SRBRoot *bundle, UErrorCode *status) { 1.1670 + if (U_FAILURE(*status)) { 1.1671 + return; 1.1672 + } 1.1673 + switch(bundle->fStringsForm) { 1.1674 + case STRINGS_UTF16_V2: 1.1675 + if (bundle->f16BitUnitsLength > 0) { 1.1676 + struct SResource **array; 1.1677 + int32_t count = uhash_count(bundle->fStringSet); 1.1678 + int32_t i, pos; 1.1679 + /* 1.1680 + * Allocate enough space for the initial NUL and the UTF-16 v2 strings, 1.1681 + * and some extra for URES_TABLE16 and URES_ARRAY16 values. 1.1682 + * Round down to an even number. 1.1683 + */ 1.1684 + int32_t utf16Length = (bundle->f16BitUnitsLength + 20000) & ~1; 1.1685 + bundle->f16BitUnits = (UChar *)uprv_malloc(utf16Length * U_SIZEOF_UCHAR); 1.1686 + array = (struct SResource **)uprv_malloc(count * sizeof(struct SResource **)); 1.1687 + if (bundle->f16BitUnits == NULL || array == NULL) { 1.1688 + uprv_free(bundle->f16BitUnits); 1.1689 + bundle->f16BitUnits = NULL; 1.1690 + uprv_free(array); 1.1691 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1692 + return; 1.1693 + } 1.1694 + bundle->f16BitUnitsCapacity = utf16Length; 1.1695 + /* insert the initial NUL */ 1.1696 + bundle->f16BitUnits[0] = 0; 1.1697 + utf16Length = 1; 1.1698 + ++bundle->f16BitUnitsLength; 1.1699 + for (pos = -1, i = 0; i < count; ++i) { 1.1700 + array[i] = (struct SResource *)uhash_nextElement(bundle->fStringSet, &pos)->key.pointer; 1.1701 + } 1.1702 + /* Sort the strings so that each one is immediately followed by all of its suffixes. */ 1.1703 + uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **), 1.1704 + compareStringSuffixes, NULL, FALSE, status); 1.1705 + /* 1.1706 + * Make suffixes point into earlier, longer strings that contain them. 1.1707 + * Temporarily use fSame and fSuffixOffset for suffix strings to 1.1708 + * refer to the remaining ones. 1.1709 + */ 1.1710 + if (U_SUCCESS(*status)) { 1.1711 + for (i = 0; i < count;) { 1.1712 + /* 1.1713 + * This string is not a suffix of the previous one; 1.1714 + * write this one and subsume the following ones that are 1.1715 + * suffixes of this one. 1.1716 + */ 1.1717 + struct SResource *res = array[i]; 1.1718 + const UChar *strLimit = res->u.fString.fChars + res->u.fString.fLength; 1.1719 + int32_t j; 1.1720 + for (j = i + 1; j < count; ++j) { 1.1721 + struct SResource *suffixRes = array[j]; 1.1722 + const UChar *s; 1.1723 + const UChar *suffix = suffixRes->u.fString.fChars; 1.1724 + const UChar *suffixLimit = suffix + suffixRes->u.fString.fLength; 1.1725 + int32_t offset = res->u.fString.fLength - suffixRes->u.fString.fLength; 1.1726 + if (offset < 0) { 1.1727 + break; /* suffix cannot be longer than the original */ 1.1728 + } 1.1729 + /* Is it a suffix of the earlier, longer key? */ 1.1730 + for (s = strLimit; suffix < suffixLimit && *--s == *--suffixLimit;) {} 1.1731 + if (suffix == suffixLimit && *s == *suffixLimit) { 1.1732 + if (suffixRes->u.fString.fNumCharsForLength == 0) { 1.1733 + /* yes, point to the earlier string */ 1.1734 + suffixRes->u.fString.fSame = res; 1.1735 + suffixRes->u.fString.fSuffixOffset = offset; 1.1736 + } else { 1.1737 + /* write the suffix by itself if we need explicit length */ 1.1738 + } 1.1739 + } else { 1.1740 + break; /* not a suffix, restart from here */ 1.1741 + } 1.1742 + } 1.1743 + i = j; 1.1744 + } 1.1745 + } 1.1746 + /* 1.1747 + * Re-sort the strings by ascending length (except suffixes last) 1.1748 + * to optimize for URES_TABLE16 and URES_ARRAY16: 1.1749 + * Keep as many as possible within reach of 16-bit offsets. 1.1750 + */ 1.1751 + uprv_sortArray(array, count, (int32_t)sizeof(struct SResource **), 1.1752 + compareStringLengths, NULL, FALSE, status); 1.1753 + if (U_SUCCESS(*status)) { 1.1754 + /* Write the non-suffix strings. */ 1.1755 + for (i = 0; i < count && array[i]->u.fString.fSame == NULL; ++i) { 1.1756 + utf16Length = string_writeUTF16v2(bundle, array[i], utf16Length); 1.1757 + } 1.1758 + /* Write the suffix strings. Make each point to the real string. */ 1.1759 + for (; i < count; ++i) { 1.1760 + struct SResource *res = array[i]; 1.1761 + struct SResource *same = res->u.fString.fSame; 1.1762 + res->fRes = same->fRes + same->u.fString.fNumCharsForLength + res->u.fString.fSuffixOffset; 1.1763 + res->u.fString.fSame = NULL; 1.1764 + res->fWritten = TRUE; 1.1765 + } 1.1766 + } 1.1767 + assert(utf16Length <= bundle->f16BitUnitsLength); 1.1768 + bundle->f16BitUnitsLength = utf16Length; 1.1769 + uprv_free(array); 1.1770 + } 1.1771 + break; 1.1772 + default: 1.1773 + break; 1.1774 + } 1.1775 +}