summaryrefslogtreecommitdiff
path: root/deps/node/deps/icu-small/source/tools/genrb/reslist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/node/deps/icu-small/source/tools/genrb/reslist.cpp')
-rw-r--r--deps/node/deps/icu-small/source/tools/genrb/reslist.cpp1693
1 files changed, 0 insertions, 1693 deletions
diff --git a/deps/node/deps/icu-small/source/tools/genrb/reslist.cpp b/deps/node/deps/icu-small/source/tools/genrb/reslist.cpp
deleted file mode 100644
index 0493347e..00000000
--- a/deps/node/deps/icu-small/source/tools/genrb/reslist.cpp
+++ /dev/null
@@ -1,1693 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-*
-* Copyright (C) 2000-2015, International Business Machines
-* Corporation and others. All Rights Reserved.
-*
-*******************************************************************************
-*
-* File reslist.cpp
-*
-* Modification History:
-*
-* Date Name Description
-* 02/21/00 weiv Creation.
-*******************************************************************************
-*/
-
-// Safer use of UnicodeString.
-#ifndef UNISTR_FROM_CHAR_EXPLICIT
-# define UNISTR_FROM_CHAR_EXPLICIT explicit
-#endif
-
-// Less important, but still a good idea.
-#ifndef UNISTR_FROM_STRING_EXPLICIT
-# define UNISTR_FROM_STRING_EXPLICIT explicit
-#endif
-
-#include <assert.h>
-#include <stdio.h>
-#include "unicode/localpointer.h"
-#include "reslist.h"
-#include "unewdata.h"
-#include "unicode/ures.h"
-#include "unicode/putil.h"
-#include "errmsg.h"
-
-#include "uarrsort.h"
-#include "uelement.h"
-#include "uhash.h"
-#include "uinvchar.h"
-#include "ustr_imp.h"
-#include "unicode/utf16.h"
-/*
- * Align binary data at a 16-byte offset from the start of the resource bundle,
- * to be safe for any data type it may contain.
- */
-#define BIN_ALIGNMENT 16
-
-// This numeric constant must be at least 1.
-// If StringResource.fNumUnitsSaved == 0 then the string occurs only once,
-// and it makes no sense to move it to the pool bundle.
-// The larger the threshold for fNumUnitsSaved
-// the smaller the savings, and the smaller the pool bundle.
-// We trade some total size reduction to reduce the pool bundle a bit,
-// so that one can reasonably save data size by
-// removing bundle files without rebuilding the pool bundle.
-// This can also help to keep the pool and total (pool+local) string indexes
-// within 16 bits, that is, within range of Table16 and Array16 containers.
-#ifndef GENRB_MIN_16BIT_UNITS_SAVED_FOR_POOL_STRING
-# define GENRB_MIN_16BIT_UNITS_SAVED_FOR_POOL_STRING 10
-#endif
-
-U_NAMESPACE_USE
-
-static UBool gIncludeCopyright = FALSE;
-static UBool gUsePoolBundle = FALSE;
-static UBool gIsDefaultFormatVersion = TRUE;
-static int32_t gFormatVersion = 3;
-
-/* How do we store string values? */
-enum {
- STRINGS_UTF16_V1, /* formatVersion 1: int length + UChars + NUL + padding to 4 bytes */
- STRINGS_UTF16_V2 /* formatVersion 2 & up: optional length in 1..3 UChars + UChars + NUL */
-};
-
-static const int32_t MAX_IMPLICIT_STRING_LENGTH = 40; /* do not store the length explicitly for such strings */
-
-static const ResFile kNoPoolBundle;
-
-/*
- * res_none() returns the address of kNoResource,
- * for use in non-error cases when no resource is to be added to the bundle.
- * (NULL is used in error cases.)
- */
-static SResource kNoResource; // TODO: const
-
-static UDataInfo dataInfo= {
- sizeof(UDataInfo),
- 0,
-
- U_IS_BIG_ENDIAN,
- U_CHARSET_FAMILY,
- sizeof(UChar),
- 0,
-
- {0x52, 0x65, 0x73, 0x42}, /* dataFormat="ResB" */
- {1, 3, 0, 0}, /* formatVersion */
- {1, 4, 0, 0} /* dataVersion take a look at version inside parsed resb*/
-};
-
-static const UVersionInfo gFormatVersions[4] = { /* indexed by a major-formatVersion integer */
- { 0, 0, 0, 0 },
- { 1, 3, 0, 0 },
- { 2, 0, 0, 0 },
- { 3, 0, 0, 0 }
-};
-// Remember to update genrb.h GENRB_VERSION when changing the data format.
-// (Or maybe we should remove GENRB_VERSION and report the ICU version number?)
-
-static uint8_t calcPadding(uint32_t size) {
- /* returns space we need to pad */
- return (uint8_t) ((size % sizeof(uint32_t)) ? (sizeof(uint32_t) - (size % sizeof(uint32_t))) : 0);
-
-}
-
-void setIncludeCopyright(UBool val){
- gIncludeCopyright=val;
-}
-
-UBool getIncludeCopyright(void){
- return gIncludeCopyright;
-}
-
-void setFormatVersion(int32_t formatVersion) {
- gIsDefaultFormatVersion = FALSE;
- gFormatVersion = formatVersion;
-}
-
-int32_t getFormatVersion() {
- return gFormatVersion;
-}
-
-void setUsePoolBundle(UBool use) {
- gUsePoolBundle = use;
-}
-
-// TODO: return const pointer, or find another way to express "none"
-struct SResource* res_none() {
- return &kNoResource;
-}
-
-SResource::SResource()
- : fType(URES_NONE), fWritten(FALSE), fRes(RES_BOGUS), fRes16(-1), fKey(-1), fKey16(-1),
- line(0), fNext(NULL) {
- ustr_init(&fComment);
-}
-
-SResource::SResource(SRBRoot *bundle, const char *tag, int8_t type, const UString* comment,
- UErrorCode &errorCode)
- : fType(type), fWritten(FALSE), fRes(RES_BOGUS), fRes16(-1),
- fKey(bundle != NULL ? bundle->addTag(tag, errorCode) : -1), fKey16(-1),
- line(0), fNext(NULL) {
- ustr_init(&fComment);
- if(comment != NULL) {
- ustr_cpy(&fComment, comment, &errorCode);
- }
-}
-
-SResource::~SResource() {
- ustr_deinit(&fComment);
-}
-
-ContainerResource::~ContainerResource() {
- SResource *current = fFirst;
- while (current != NULL) {
- SResource *next = current->fNext;
- delete current;
- current = next;
- }
-}
-
-TableResource::~TableResource() {}
-
-// TODO: clarify that containers adopt new items, even in error cases; use LocalPointer
-void TableResource::add(SResource *res, int linenumber, UErrorCode &errorCode) {
- if (U_FAILURE(errorCode) || res == NULL || res == &kNoResource) {
- return;
- }
-
- /* remember this linenumber to report to the user if there is a duplicate key */
- res->line = linenumber;
-
- /* here we need to traverse the list */
- ++fCount;
-
- /* is the list still empty? */
- if (fFirst == NULL) {
- fFirst = res;
- res->fNext = NULL;
- return;
- }
-
- const char *resKeyString = fRoot->fKeys + res->fKey;
-
- SResource *current = fFirst;
-
- SResource *prev = NULL;
- while (current != NULL) {
- const char *currentKeyString = fRoot->fKeys + current->fKey;
- int diff;
- /*
- * formatVersion 1: compare key strings in native-charset order
- * formatVersion 2 and up: compare key strings in ASCII order
- */
- if (gFormatVersion == 1 || U_CHARSET_FAMILY == U_ASCII_FAMILY) {
- diff = uprv_strcmp(currentKeyString, resKeyString);
- } else {
- diff = uprv_compareInvCharsAsAscii(currentKeyString, resKeyString);
- }
- if (diff < 0) {
- prev = current;
- current = current->fNext;
- } else if (diff > 0) {
- /* we're either in front of the list, or in the middle */
- if (prev == NULL) {
- /* front of the list */
- fFirst = res;
- } else {
- /* middle of the list */
- prev->fNext = res;
- }
-
- res->fNext = current;
- return;
- } else {
- /* Key already exists! ERROR! */
- error(linenumber, "duplicate key '%s' in table, first appeared at line %d", currentKeyString, current->line);
- errorCode = U_UNSUPPORTED_ERROR;
- return;
- }
- }
-
- /* end of list */
- prev->fNext = res;
- res->fNext = NULL;
-}
-
-ArrayResource::~ArrayResource() {}
-
-void ArrayResource::add(SResource *res) {
- if (res != NULL && res != &kNoResource) {
- if (fFirst == NULL) {
- fFirst = res;
- } else {
- fLast->fNext = res;
- }
- fLast = res;
- ++fCount;
- }
-}
-
-PseudoListResource::~PseudoListResource() {}
-
-void PseudoListResource::add(SResource *res) {
- if (res != NULL && res != &kNoResource) {
- res->fNext = fFirst;
- fFirst = res;
- ++fCount;
- }
-}
-
-StringBaseResource::StringBaseResource(SRBRoot *bundle, const char *tag, int8_t type,
- const UChar *value, int32_t len,
- const UString* comment, UErrorCode &errorCode)
- : SResource(bundle, tag, type, comment, errorCode) {
- if (len == 0 && gFormatVersion > 1) {
- fRes = URES_MAKE_EMPTY_RESOURCE(type);
- fWritten = TRUE;
- return;
- }
-
- fString.setTo(ConstChar16Ptr(value), len);
- fString.getTerminatedBuffer(); // Some code relies on NUL-termination.
- if (U_SUCCESS(errorCode) && fString.isBogus()) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- }
-}
-
-StringBaseResource::StringBaseResource(SRBRoot *bundle, int8_t type,
- const icu::UnicodeString &value, UErrorCode &errorCode)
- : SResource(bundle, NULL, type, NULL, errorCode), fString(value) {
- if (value.isEmpty() && gFormatVersion > 1) {
- fRes = URES_MAKE_EMPTY_RESOURCE(type);
- fWritten = TRUE;
- return;
- }
-
- fString.getTerminatedBuffer(); // Some code relies on NUL-termination.
- if (U_SUCCESS(errorCode) && fString.isBogus()) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- }
-}
-
-// Pool bundle string, alias the buffer. Guaranteed NUL-terminated and not empty.
-StringBaseResource::StringBaseResource(int8_t type, const UChar *value, int32_t len,
- UErrorCode &errorCode)
- : SResource(NULL, NULL, type, NULL, errorCode), fString(TRUE, value, len) {
- assert(len > 0);
- assert(!fString.isBogus());
-}
-
-StringBaseResource::~StringBaseResource() {}
-
-static int32_t U_CALLCONV
-string_hash(const UElement key) {
- const StringResource *res = static_cast<const StringResource *>(key.pointer);
- return res->fString.hashCode();
-}
-
-static UBool U_CALLCONV
-string_comp(const UElement key1, const UElement key2) {
- const StringResource *res1 = static_cast<const StringResource *>(key1.pointer);
- const StringResource *res2 = static_cast<const StringResource *>(key2.pointer);
- return res1->fString == res2->fString;
-}
-
-StringResource::~StringResource() {}
-
-AliasResource::~AliasResource() {}
-
-IntResource::IntResource(SRBRoot *bundle, const char *tag, int32_t value,
- const UString* comment, UErrorCode &errorCode)
- : SResource(bundle, tag, URES_INT, comment, errorCode) {
- fValue = value;
- fRes = URES_MAKE_RESOURCE(URES_INT, value & RES_MAX_OFFSET);
- fWritten = TRUE;
-}
-
-IntResource::~IntResource() {}
-
-IntVectorResource::IntVectorResource(SRBRoot *bundle, const char *tag,
- const UString* comment, UErrorCode &errorCode)
- : SResource(bundle, tag, URES_INT_VECTOR, comment, errorCode),
- fCount(0), fArray(new uint32_t[RESLIST_MAX_INT_VECTOR]) {
- if (fArray == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-}
-
-IntVectorResource::~IntVectorResource() {
- delete[] fArray;
-}
-
-void IntVectorResource::add(int32_t value, UErrorCode &errorCode) {
- if (U_SUCCESS(errorCode)) {
- fArray[fCount++] = value;
- }
-}
-
-BinaryResource::BinaryResource(SRBRoot *bundle, const char *tag,
- uint32_t length, uint8_t *data, const char* fileName,
- const UString* comment, UErrorCode &errorCode)
- : SResource(bundle, tag, URES_BINARY, comment, errorCode),
- fLength(length), fData(NULL), fFileName(NULL) {
- if (U_FAILURE(errorCode)) {
- return;
- }
- if (fileName != NULL && *fileName != 0){
- fFileName = new char[uprv_strlen(fileName)+1];
- if (fFileName == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- uprv_strcpy(fFileName, fileName);
- }
- if (length > 0) {
- fData = new uint8_t[length];
- if (fData == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- uprv_memcpy(fData, data, length);
- } else {
- if (gFormatVersion > 1) {
- fRes = URES_MAKE_EMPTY_RESOURCE(URES_BINARY);
- fWritten = TRUE;
- }
- }
-}
-
-BinaryResource::~BinaryResource() {
- delete[] fData;
- delete[] fFileName;
-}
-
-/* Writing Functions */
-
-void
-StringResource::handlePreflightStrings(SRBRoot *bundle, UHashtable *stringSet,
- UErrorCode &errorCode) {
- assert(fSame == NULL);
- fSame = static_cast<StringResource *>(uhash_get(stringSet, this));
- if (fSame != NULL) {
- // This is a duplicate of a pool bundle string or of an earlier-visited string.
- if (++fSame->fNumCopies == 1) {
- assert(fSame->fWritten);
- int32_t poolStringIndex = (int32_t)RES_GET_OFFSET(fSame->fRes);
- if (poolStringIndex >= bundle->fPoolStringIndexLimit) {
- bundle->fPoolStringIndexLimit = poolStringIndex + 1;
- }
- }
- return;
- }
- /* Put this string into the set for finding duplicates. */
- fNumCopies = 1;
- uhash_put(stringSet, this, this, &errorCode);
-
- if (bundle->fStringsForm != STRINGS_UTF16_V1) {
- int32_t len = length();
- if (len <= MAX_IMPLICIT_STRING_LENGTH &&
- !U16_IS_TRAIL(fString[0]) && fString.indexOf((UChar)0) < 0) {
- /*
- * This string will be stored without an explicit length.
- * Runtime will detect !U16_IS_TRAIL(s[0]) and call u_strlen().
- */
- fNumCharsForLength = 0;
- } else if (len <= 0x3ee) {
- fNumCharsForLength = 1;
- } else if (len <= 0xfffff) {
- fNumCharsForLength = 2;
- } else {
- fNumCharsForLength = 3;
- }
- bundle->f16BitStringsLength += fNumCharsForLength + len + 1; /* +1 for the NUL */
- }
-}
-
-void
-ContainerResource::handlePreflightStrings(SRBRoot *bundle, UHashtable *stringSet,
- UErrorCode &errorCode) {
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- current->preflightStrings(bundle, stringSet, errorCode);
- }
-}
-
-void
-SResource::preflightStrings(SRBRoot *bundle, UHashtable *stringSet, UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) {
- return;
- }
- if (fRes != RES_BOGUS) {
- /*
- * The resource item word was already precomputed, which means
- * no further data needs to be written.
- * This might be an integer, or an empty string/binary/etc.
- */
- return;
- }
- handlePreflightStrings(bundle, stringSet, errorCode);
-}
-
-void
-SResource::handlePreflightStrings(SRBRoot * /*bundle*/, UHashtable * /*stringSet*/,
- UErrorCode & /*errorCode*/) {
- /* Neither a string nor a container. */
-}
-
-int32_t
-SRBRoot::makeRes16(uint32_t resWord) const {
- if (resWord == 0) {
- return 0; /* empty string */
- }
- uint32_t type = RES_GET_TYPE(resWord);
- int32_t offset = (int32_t)RES_GET_OFFSET(resWord);
- if (type == URES_STRING_V2) {
- assert(offset > 0);
- if (offset < fPoolStringIndexLimit) {
- if (offset < fPoolStringIndex16Limit) {
- return offset;
- }
- } else {
- offset = offset - fPoolStringIndexLimit + fPoolStringIndex16Limit;
- if (offset <= 0xffff) {
- return offset;
- }
- }
- }
- return -1;
-}
-
-int32_t
-SRBRoot::mapKey(int32_t oldpos) const {
- const KeyMapEntry *map = fKeyMap;
- if (map == NULL) {
- return oldpos;
- }
- int32_t i, start, limit;
-
- /* do a binary search for the old, pre-compactKeys() key offset */
- start = fUsePoolBundle->fKeysCount;
- limit = start + fKeysCount;
- while (start < limit - 1) {
- i = (start + limit) / 2;
- if (oldpos < map[i].oldpos) {
- limit = i;
- } else {
- start = i;
- }
- }
- assert(oldpos == map[start].oldpos);
- return map[start].newpos;
-}
-
-/*
- * Only called for UTF-16 v1 strings and duplicate UTF-16 v2 strings.
- * For unique UTF-16 v2 strings, write16() sees fRes != RES_BOGUS
- * and exits early.
- */
-void
-StringResource::handleWrite16(SRBRoot * /*bundle*/) {
- SResource *same;
- if ((same = fSame) != NULL) {
- /* This is a duplicate. */
- assert(same->fRes != RES_BOGUS && same->fWritten);
- fRes = same->fRes;
- fWritten = same->fWritten;
- }
-}
-
-void
-ContainerResource::writeAllRes16(SRBRoot *bundle) {
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- bundle->f16BitUnits.append((UChar)current->fRes16);
- }
- fWritten = TRUE;
-}
-
-void
-ArrayResource::handleWrite16(SRBRoot *bundle) {
- if (fCount == 0 && gFormatVersion > 1) {
- fRes = URES_MAKE_EMPTY_RESOURCE(URES_ARRAY);
- fWritten = TRUE;
- return;
- }
-
- int32_t res16 = 0;
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- current->write16(bundle);
- res16 |= current->fRes16;
- }
- if (fCount <= 0xffff && res16 >= 0 && gFormatVersion > 1) {
- fRes = URES_MAKE_RESOURCE(URES_ARRAY16, bundle->f16BitUnits.length());
- bundle->f16BitUnits.append((UChar)fCount);
- writeAllRes16(bundle);
- }
-}
-
-void
-TableResource::handleWrite16(SRBRoot *bundle) {
- if (fCount == 0 && gFormatVersion > 1) {
- fRes = URES_MAKE_EMPTY_RESOURCE(URES_TABLE);
- fWritten = TRUE;
- return;
- }
- /* Find the smallest table type that fits the data. */
- int32_t key16 = 0;
- int32_t res16 = 0;
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- current->write16(bundle);
- key16 |= current->fKey16;
- res16 |= current->fRes16;
- }
- if(fCount > (uint32_t)bundle->fMaxTableLength) {
- bundle->fMaxTableLength = fCount;
- }
- if (fCount <= 0xffff && key16 >= 0) {
- if (res16 >= 0 && gFormatVersion > 1) {
- /* 16-bit count, key offsets and values */
- fRes = URES_MAKE_RESOURCE(URES_TABLE16, bundle->f16BitUnits.length());
- bundle->f16BitUnits.append((UChar)fCount);
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- bundle->f16BitUnits.append((UChar)current->fKey16);
- }
- writeAllRes16(bundle);
- } else {
- /* 16-bit count, 16-bit key offsets, 32-bit values */
- fTableType = URES_TABLE;
- }
- } else {
- /* 32-bit count, key offsets and values */
- fTableType = URES_TABLE32;
- }
-}
-
-void
-PseudoListResource::handleWrite16(SRBRoot * /*bundle*/) {
- fRes = URES_MAKE_EMPTY_RESOURCE(URES_TABLE);
- fWritten = TRUE;
-}
-
-void
-SResource::write16(SRBRoot *bundle) {
- if (fKey >= 0) {
- // A tagged resource has a non-negative key index into the parsed key strings.
- // compactKeys() built a map from parsed key index to the final key index.
- // After the mapping, negative key indexes are used for shared pool bundle keys.
- fKey = bundle->mapKey(fKey);
- // If the key index fits into a Key16 for a Table or Table16,
- // then set the fKey16 field accordingly.
- // Otherwise keep it at -1.
- if (fKey >= 0) {
- if (fKey < bundle->fLocalKeyLimit) {
- fKey16 = fKey;
- }
- } else {
- int32_t poolKeyIndex = fKey & 0x7fffffff;
- if (poolKeyIndex <= 0xffff) {
- poolKeyIndex += bundle->fLocalKeyLimit;
- if (poolKeyIndex <= 0xffff) {
- fKey16 = poolKeyIndex;
- }
- }
- }
- }
- /*
- * fRes != RES_BOGUS:
- * The resource item word was already precomputed, which means
- * no further data needs to be written.
- * This might be an integer, or an empty or UTF-16 v2 string,
- * an empty binary, etc.
- */
- if (fRes == RES_BOGUS) {
- handleWrite16(bundle);
- }
- // Compute fRes16 for precomputed as well as just-computed fRes.
- fRes16 = bundle->makeRes16(fRes);
-}
-
-void
-SResource::handleWrite16(SRBRoot * /*bundle*/) {
- /* Only a few resource types write 16-bit units. */
-}
-
-/*
- * Only called for UTF-16 v1 strings, and for aliases.
- * For UTF-16 v2 strings, preWrite() sees fRes != RES_BOGUS
- * and exits early.
- */
-void
-StringBaseResource::handlePreWrite(uint32_t *byteOffset) {
- /* Write the UTF-16 v1 string. */
- fRes = URES_MAKE_RESOURCE(fType, *byteOffset >> 2);
- *byteOffset += 4 + (length() + 1) * U_SIZEOF_UCHAR;
-}
-
-void
-IntVectorResource::handlePreWrite(uint32_t *byteOffset) {
- if (fCount == 0 && gFormatVersion > 1) {
- fRes = URES_MAKE_EMPTY_RESOURCE(URES_INT_VECTOR);
- fWritten = TRUE;
- } else {
- fRes = URES_MAKE_RESOURCE(URES_INT_VECTOR, *byteOffset >> 2);
- *byteOffset += (1 + fCount) * 4;
- }
-}
-
-void
-BinaryResource::handlePreWrite(uint32_t *byteOffset) {
- uint32_t pad = 0;
- uint32_t dataStart = *byteOffset + sizeof(fLength);
-
- if (dataStart % BIN_ALIGNMENT) {
- pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT);
- *byteOffset += pad; /* pad == 4 or 8 or 12 */
- }
- fRes = URES_MAKE_RESOURCE(URES_BINARY, *byteOffset >> 2);
- *byteOffset += 4 + fLength;
-}
-
-void
-ContainerResource::preWriteAllRes(uint32_t *byteOffset) {
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- current->preWrite(byteOffset);
- }
-}
-
-void
-ArrayResource::handlePreWrite(uint32_t *byteOffset) {
- preWriteAllRes(byteOffset);
- fRes = URES_MAKE_RESOURCE(URES_ARRAY, *byteOffset >> 2);
- *byteOffset += (1 + fCount) * 4;
-}
-
-void
-TableResource::handlePreWrite(uint32_t *byteOffset) {
- preWriteAllRes(byteOffset);
- if (fTableType == URES_TABLE) {
- /* 16-bit count, 16-bit key offsets, 32-bit values */
- fRes = URES_MAKE_RESOURCE(URES_TABLE, *byteOffset >> 2);
- *byteOffset += 2 + fCount * 6;
- } else {
- /* 32-bit count, key offsets and values */
- fRes = URES_MAKE_RESOURCE(URES_TABLE32, *byteOffset >> 2);
- *byteOffset += 4 + fCount * 8;
- }
-}
-
-void
-SResource::preWrite(uint32_t *byteOffset) {
- if (fRes != RES_BOGUS) {
- /*
- * The resource item word was already precomputed, which means
- * no further data needs to be written.
- * This might be an integer, or an empty or UTF-16 v2 string,
- * an empty binary, etc.
- */
- return;
- }
- handlePreWrite(byteOffset);
- *byteOffset += calcPadding(*byteOffset);
-}
-
-void
-SResource::handlePreWrite(uint32_t * /*byteOffset*/) {
- assert(FALSE);
-}
-
-/*
- * Only called for UTF-16 v1 strings, and for aliases. For UTF-16 v2 strings,
- * write() sees fWritten and exits early.
- */
-void
-StringBaseResource::handleWrite(UNewDataMemory *mem, uint32_t *byteOffset) {
- /* Write the UTF-16 v1 string. */
- int32_t len = length();
- udata_write32(mem, len);
- udata_writeUString(mem, getBuffer(), len + 1);
- *byteOffset += 4 + (len + 1) * U_SIZEOF_UCHAR;
- fWritten = TRUE;
-}
-
-void
-ContainerResource::writeAllRes(UNewDataMemory *mem, uint32_t *byteOffset) {
- uint32_t i = 0;
- for (SResource *current = fFirst; current != NULL; ++i, current = current->fNext) {
- current->write(mem, byteOffset);
- }
- assert(i == fCount);
-}
-
-void
-ContainerResource::writeAllRes32(UNewDataMemory *mem, uint32_t *byteOffset) {
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- udata_write32(mem, current->fRes);
- }
- *byteOffset += fCount * 4;
-}
-
-void
-ArrayResource::handleWrite(UNewDataMemory *mem, uint32_t *byteOffset) {
- writeAllRes(mem, byteOffset);
- udata_write32(mem, fCount);
- *byteOffset += 4;
- writeAllRes32(mem, byteOffset);
-}
-
-void
-IntVectorResource::handleWrite(UNewDataMemory *mem, uint32_t *byteOffset) {
- udata_write32(mem, fCount);
- for(uint32_t i = 0; i < fCount; ++i) {
- udata_write32(mem, fArray[i]);
- }
- *byteOffset += (1 + fCount) * 4;
-}
-
-void
-BinaryResource::handleWrite(UNewDataMemory *mem, uint32_t *byteOffset) {
- uint32_t pad = 0;
- uint32_t dataStart = *byteOffset + sizeof(fLength);
-
- if (dataStart % BIN_ALIGNMENT) {
- pad = (BIN_ALIGNMENT - dataStart % BIN_ALIGNMENT);
- udata_writePadding(mem, pad); /* pad == 4 or 8 or 12 */
- *byteOffset += pad;
- }
-
- udata_write32(mem, fLength);
- if (fLength > 0) {
- udata_writeBlock(mem, fData, fLength);
- }
- *byteOffset += 4 + fLength;
-}
-
-void
-TableResource::handleWrite(UNewDataMemory *mem, uint32_t *byteOffset) {
- writeAllRes(mem, byteOffset);
- if(fTableType == URES_TABLE) {
- udata_write16(mem, (uint16_t)fCount);
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- udata_write16(mem, current->fKey16);
- }
- *byteOffset += (1 + fCount)* 2;
- if ((fCount & 1) == 0) {
- /* 16-bit count and even number of 16-bit key offsets need padding before 32-bit resource items */
- udata_writePadding(mem, 2);
- *byteOffset += 2;
- }
- } else /* URES_TABLE32 */ {
- udata_write32(mem, fCount);
- for (SResource *current = fFirst; current != NULL; current = current->fNext) {
- udata_write32(mem, (uint32_t)current->fKey);
- }
- *byteOffset += (1 + fCount)* 4;
- }
- writeAllRes32(mem, byteOffset);
-}
-
-void
-SResource::write(UNewDataMemory *mem, uint32_t *byteOffset) {
- if (fWritten) {
- assert(fRes != RES_BOGUS);
- return;
- }
- handleWrite(mem, byteOffset);
- uint8_t paddingSize = calcPadding(*byteOffset);
- if (paddingSize > 0) {
- udata_writePadding(mem, paddingSize);
- *byteOffset += paddingSize;
- }
- fWritten = TRUE;
-}
-
-void
-SResource::handleWrite(UNewDataMemory * /*mem*/, uint32_t * /*byteOffset*/) {
- assert(FALSE);
-}
-
-void SRBRoot::write(const char *outputDir, const char *outputPkg,
- char *writtenFilename, int writtenFilenameLen,
- UErrorCode &errorCode) {
- UNewDataMemory *mem = NULL;
- uint32_t byteOffset = 0;
- uint32_t top, size;
- char dataName[1024];
- int32_t indexes[URES_INDEX_TOP];
-
- compactKeys(errorCode);
- /*
- * Add padding bytes to fKeys so that fKeysTop is 4-aligned.
- * Safe because the capacity is a multiple of 4.
- */
- while (fKeysTop & 3) {
- fKeys[fKeysTop++] = (char)0xaa;
- }
- /*
- * In URES_TABLE, use all local key offsets that fit into 16 bits,
- * and use the remaining 16-bit offsets for pool key offsets
- * if there are any.
- * If there are no local keys, then use the whole 16-bit space
- * for pool key offsets.
- * Note: This cannot be changed without changing the major formatVersion.
- */
- if (fKeysBottom < fKeysTop) {
- if (fKeysTop <= 0x10000) {
- fLocalKeyLimit = fKeysTop;
- } else {
- fLocalKeyLimit = 0x10000;
- }
- } else {
- fLocalKeyLimit = 0;
- }
-
- UHashtable *stringSet;
- if (gFormatVersion > 1) {
- stringSet = uhash_open(string_hash, string_comp, string_comp, &errorCode);
- if (U_SUCCESS(errorCode) &&
- fUsePoolBundle != NULL && fUsePoolBundle->fStrings != NULL) {
- for (SResource *current = fUsePoolBundle->fStrings->fFirst;
- current != NULL;
- current = current->fNext) {
- StringResource *sr = static_cast<StringResource *>(current);
- sr->fNumCopies = 0;
- sr->fNumUnitsSaved = 0;
- uhash_put(stringSet, sr, sr, &errorCode);
- }
- }
- fRoot->preflightStrings(this, stringSet, errorCode);
- } else {
- stringSet = NULL;
- }
- if (fStringsForm == STRINGS_UTF16_V2 && f16BitStringsLength > 0) {
- compactStringsV2(stringSet, errorCode);
- }
- uhash_close(stringSet);
- if (U_FAILURE(errorCode)) {
- return;
- }
-
- int32_t formatVersion = gFormatVersion;
- if (fPoolStringIndexLimit != 0) {
- int32_t sum = fPoolStringIndexLimit + fLocalStringIndexLimit;
- if ((sum - 1) > RES_MAX_OFFSET) {
- errorCode = U_BUFFER_OVERFLOW_ERROR;
- return;
- }
- if (fPoolStringIndexLimit < 0x10000 && sum <= 0x10000) {
- // 16-bit indexes work for all pool + local strings.
- fPoolStringIndex16Limit = fPoolStringIndexLimit;
- } else {
- // Set the pool index threshold so that 16-bit indexes work
- // for some pool strings and some local strings.
- fPoolStringIndex16Limit = (int32_t)(
- ((int64_t)fPoolStringIndexLimit * 0xffff) / sum);
- }
- } else if (gIsDefaultFormatVersion && formatVersion == 3 && !fIsPoolBundle) {
- // If we just default to formatVersion 3
- // but there are no pool bundle strings to share
- // and we do not write a pool bundle,
- // then write formatVersion 2 which is just as good.
- formatVersion = 2;
- }
-
- fRoot->write16(this);
- if (f16BitUnits.isBogus()) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- if (f16BitUnits.length() & 1) {
- f16BitUnits.append((UChar)0xaaaa); /* pad to multiple of 4 bytes */
- }
- /* all keys have been mapped */
- uprv_free(fKeyMap);
- fKeyMap = NULL;
-
- byteOffset = fKeysTop + f16BitUnits.length() * 2;
- fRoot->preWrite(&byteOffset);
-
- /* total size including the root item */
- top = byteOffset;
-
- if (writtenFilename && writtenFilenameLen) {
- *writtenFilename = 0;
- }
-
- if (writtenFilename) {
- int32_t off = 0, len = 0;
- if (outputDir) {
- len = (int32_t)uprv_strlen(outputDir);
- if (len > writtenFilenameLen) {
- len = writtenFilenameLen;
- }
- uprv_strncpy(writtenFilename, outputDir, len);
- }
- if (writtenFilenameLen -= len) {
- off += len;
- writtenFilename[off] = U_FILE_SEP_CHAR;
- if (--writtenFilenameLen) {
- ++off;
- if(outputPkg != NULL)
- {
- uprv_strcpy(writtenFilename+off, outputPkg);
- off += (int32_t)uprv_strlen(outputPkg);
- writtenFilename[off] = '_';
- ++off;
- }
-
- len = (int32_t)uprv_strlen(fLocale);
- if (len > writtenFilenameLen) {
- len = writtenFilenameLen;
- }
- uprv_strncpy(writtenFilename + off, fLocale, len);
- if (writtenFilenameLen -= len) {
- off += len;
- len = 5;
- if (len > writtenFilenameLen) {
- len = writtenFilenameLen;
- }
- uprv_strncpy(writtenFilename + off, ".res", len);
- }
- }
- }
- }
-
- if(outputPkg)
- {
- uprv_strcpy(dataName, outputPkg);
- uprv_strcat(dataName, "_");
- uprv_strcat(dataName, fLocale);
- }
- else
- {
- uprv_strcpy(dataName, fLocale);
- }
-
- uprv_memcpy(dataInfo.formatVersion, gFormatVersions + formatVersion, sizeof(UVersionInfo));
-
- mem = udata_create(outputDir, "res", dataName,
- &dataInfo, (gIncludeCopyright==TRUE)? U_COPYRIGHT_STRING:NULL, &errorCode);
- if(U_FAILURE(errorCode)){
- return;
- }
-
- /* write the root item */
- udata_write32(mem, fRoot->fRes);
-
- /*
- * formatVersion 1.1 (ICU 2.8):
- * write int32_t indexes[] after root and before the key strings
- * to make it easier to parse resource bundles in icuswap or from Java etc.
- */
- uprv_memset(indexes, 0, sizeof(indexes));
- indexes[URES_INDEX_LENGTH]= fIndexLength;
- indexes[URES_INDEX_KEYS_TOP]= fKeysTop>>2;
- indexes[URES_INDEX_RESOURCES_TOP]= (int32_t)(top>>2);
- indexes[URES_INDEX_BUNDLE_TOP]= indexes[URES_INDEX_RESOURCES_TOP];
- indexes[URES_INDEX_MAX_TABLE_LENGTH]= fMaxTableLength;
-
- /*
- * formatVersion 1.2 (ICU 3.6):
- * write indexes[URES_INDEX_ATTRIBUTES] with URES_ATT_NO_FALLBACK set or not set
- * the memset() above initialized all indexes[] to 0
- */
- if (fNoFallback) {
- indexes[URES_INDEX_ATTRIBUTES]=URES_ATT_NO_FALLBACK;
- }
- /*
- * formatVersion 2.0 (ICU 4.4):
- * more compact string value storage, optional pool bundle
- */
- if (URES_INDEX_16BIT_TOP < fIndexLength) {
- indexes[URES_INDEX_16BIT_TOP] = (fKeysTop>>2) + (f16BitUnits.length()>>1);
- }
- if (URES_INDEX_POOL_CHECKSUM < fIndexLength) {
- if (fIsPoolBundle) {
- indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_IS_POOL_BUNDLE | URES_ATT_NO_FALLBACK;
- uint32_t checksum = computeCRC((const char *)(fKeys + fKeysBottom),
- (uint32_t)(fKeysTop - fKeysBottom), 0);
- if (f16BitUnits.length() <= 1) {
- // no pool strings to checksum
- } else if (U_IS_BIG_ENDIAN) {
- checksum = computeCRC(reinterpret_cast<const char *>(f16BitUnits.getBuffer()),
- (uint32_t)f16BitUnits.length() * 2, checksum);
- } else {
- // Swap to big-endian so we get the same checksum on all platforms
- // (except for charset family, due to the key strings).
- UnicodeString s(f16BitUnits);
- s.append((UChar)1); // Ensure that we own this buffer.
- assert(!s.isBogus());
- uint16_t *p = const_cast<uint16_t *>(reinterpret_cast<const uint16_t *>(s.getBuffer()));
- for (int32_t count = f16BitUnits.length(); count > 0; --count) {
- uint16_t x = *p;
- *p++ = (uint16_t)((x << 8) | (x >> 8));
- }
- checksum = computeCRC((const char *)p,
- (uint32_t)f16BitUnits.length() * 2, checksum);
- }
- indexes[URES_INDEX_POOL_CHECKSUM] = (int32_t)checksum;
- } else if (gUsePoolBundle) {
- indexes[URES_INDEX_ATTRIBUTES] |= URES_ATT_USES_POOL_BUNDLE;
- indexes[URES_INDEX_POOL_CHECKSUM] = fUsePoolBundle->fChecksum;
- }
- }
- // formatVersion 3 (ICU 56):
- // share string values via pool bundle strings
- indexes[URES_INDEX_LENGTH] |= fPoolStringIndexLimit << 8; // bits 23..0 -> 31..8
- indexes[URES_INDEX_ATTRIBUTES] |= (fPoolStringIndexLimit >> 12) & 0xf000; // bits 27..24 -> 15..12
- indexes[URES_INDEX_ATTRIBUTES] |= fPoolStringIndex16Limit << 16;
-
- /* write the indexes[] */
- udata_writeBlock(mem, indexes, fIndexLength*4);
-
- /* write the table key strings */
- udata_writeBlock(mem, fKeys+fKeysBottom,
- fKeysTop-fKeysBottom);
-
- /* write the v2 UTF-16 strings, URES_TABLE16 and URES_ARRAY16 */
- udata_writeBlock(mem, f16BitUnits.getBuffer(), f16BitUnits.length()*2);
-
- /* write all of the bundle contents: the root item and its children */
- byteOffset = fKeysTop + f16BitUnits.length() * 2;
- fRoot->write(mem, &byteOffset);
- assert(byteOffset == top);
-
- size = udata_finish(mem, &errorCode);
- if(top != size) {
- fprintf(stderr, "genrb error: wrote %u bytes but counted %u\n",
- (int)size, (int)top);
- errorCode = U_INTERNAL_PROGRAM_ERROR;
- }
-}
-
-/* Opening Functions */
-
-TableResource* table_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) {
- LocalPointer<TableResource> res(new TableResource(bundle, tag, comment, *status), *status);
- return U_SUCCESS(*status) ? res.orphan() : NULL;
-}
-
-ArrayResource* array_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) {
- LocalPointer<ArrayResource> res(new ArrayResource(bundle, tag, comment, *status), *status);
- return U_SUCCESS(*status) ? res.orphan() : NULL;
-}
-
-struct SResource *string_open(struct SRBRoot *bundle, const char *tag, const UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) {
- LocalPointer<SResource> res(
- new StringResource(bundle, tag, value, len, comment, *status), *status);
- return U_SUCCESS(*status) ? res.orphan() : NULL;
-}
-
-struct SResource *alias_open(struct SRBRoot *bundle, const char *tag, UChar *value, int32_t len, const struct UString* comment, UErrorCode *status) {
- LocalPointer<SResource> res(
- new AliasResource(bundle, tag, value, len, comment, *status), *status);
- return U_SUCCESS(*status) ? res.orphan() : NULL;
-}
-
-IntVectorResource *intvector_open(struct SRBRoot *bundle, const char *tag, const struct UString* comment, UErrorCode *status) {
- LocalPointer<IntVectorResource> res(
- new IntVectorResource(bundle, tag, comment, *status), *status);
- return U_SUCCESS(*status) ? res.orphan() : NULL;
-}
-
-struct SResource *int_open(struct SRBRoot *bundle, const char *tag, int32_t value, const struct UString* comment, UErrorCode *status) {
- LocalPointer<SResource> res(new IntResource(bundle, tag, value, comment, *status), *status);
- return U_SUCCESS(*status) ? res.orphan() : NULL;
-}
-
-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) {
- LocalPointer<SResource> res(
- new BinaryResource(bundle, tag, length, data, fileName, comment, *status), *status);
- return U_SUCCESS(*status) ? res.orphan() : NULL;
-}
-
-SRBRoot::SRBRoot(const UString *comment, UBool isPoolBundle, UErrorCode &errorCode)
- : fRoot(NULL), fLocale(NULL), fIndexLength(0), fMaxTableLength(0), fNoFallback(FALSE),
- fStringsForm(STRINGS_UTF16_V1), fIsPoolBundle(isPoolBundle),
- fKeys(NULL), fKeyMap(NULL),
- fKeysBottom(0), fKeysTop(0), fKeysCapacity(0), fKeysCount(0), fLocalKeyLimit(0),
- f16BitUnits(), f16BitStringsLength(0),
- fUsePoolBundle(&kNoPoolBundle),
- fPoolStringIndexLimit(0), fPoolStringIndex16Limit(0), fLocalStringIndexLimit(0),
- fWritePoolBundle(NULL) {
- if (U_FAILURE(errorCode)) {
- return;
- }
-
- if (gFormatVersion > 1) {
- // f16BitUnits must start with a zero for empty resources.
- // We might be able to omit it if there are no empty 16-bit resources.
- f16BitUnits.append((UChar)0);
- }
-
- fKeys = (char *) uprv_malloc(sizeof(char) * KEY_SPACE_SIZE);
- if (isPoolBundle) {
- fRoot = new PseudoListResource(this, errorCode);
- } else {
- fRoot = new TableResource(this, NULL, comment, errorCode);
- }
- if (fKeys == NULL || fRoot == NULL || U_FAILURE(errorCode)) {
- if (U_SUCCESS(errorCode)) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- }
- return;
- }
-
- fKeysCapacity = KEY_SPACE_SIZE;
- /* formatVersion 1.1 and up: start fKeysTop after the root item and indexes[] */
- if (gUsePoolBundle || isPoolBundle) {
- fIndexLength = URES_INDEX_POOL_CHECKSUM + 1;
- } else if (gFormatVersion >= 2) {
- fIndexLength = URES_INDEX_16BIT_TOP + 1;
- } else /* formatVersion 1 */ {
- fIndexLength = URES_INDEX_ATTRIBUTES + 1;
- }
- fKeysBottom = (1 /* root */ + fIndexLength) * 4;
- uprv_memset(fKeys, 0, fKeysBottom);
- fKeysTop = fKeysBottom;
-
- if (gFormatVersion == 1) {
- fStringsForm = STRINGS_UTF16_V1;
- } else {
- fStringsForm = STRINGS_UTF16_V2;
- }
-}
-
-/* Closing Functions */
-
-void res_close(struct SResource *res) {
- delete res;
-}
-
-SRBRoot::~SRBRoot() {
- delete fRoot;
- uprv_free(fLocale);
- uprv_free(fKeys);
- uprv_free(fKeyMap);
-}
-
-/* Misc Functions */
-
-void SRBRoot::setLocale(UChar *locale, UErrorCode &errorCode) {
- if(U_FAILURE(errorCode)) {
- return;
- }
-
- uprv_free(fLocale);
- fLocale = (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1));
- if(fLocale == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-
- u_UCharsToChars(locale, fLocale, u_strlen(locale)+1);
-}
-
-const char *
-SRBRoot::getKeyString(int32_t key) const {
- if (key < 0) {
- return fUsePoolBundle->fKeys + (key & 0x7fffffff);
- } else {
- return fKeys + key;
- }
-}
-
-const char *
-SResource::getKeyString(const SRBRoot *bundle) const {
- if (fKey == -1) {
- return NULL;
- }
- return bundle->getKeyString(fKey);
-}
-
-const char *
-SRBRoot::getKeyBytes(int32_t *pLength) const {
- *pLength = fKeysTop - fKeysBottom;
- return fKeys + fKeysBottom;
-}
-
-int32_t
-SRBRoot::addKeyBytes(const char *keyBytes, int32_t length, UErrorCode &errorCode) {
- int32_t keypos;
-
- if (U_FAILURE(errorCode)) {
- return -1;
- }
- if (length < 0 || (keyBytes == NULL && length != 0)) {
- errorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return -1;
- }
- if (length == 0) {
- return fKeysTop;
- }
-
- keypos = fKeysTop;
- fKeysTop += length;
- if (fKeysTop >= fKeysCapacity) {
- /* overflow - resize the keys buffer */
- fKeysCapacity += KEY_SPACE_SIZE;
- fKeys = static_cast<char *>(uprv_realloc(fKeys, fKeysCapacity));
- if(fKeys == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return -1;
- }
- }
-
- uprv_memcpy(fKeys + keypos, keyBytes, length);
-
- return keypos;
-}
-
-int32_t
-SRBRoot::addTag(const char *tag, UErrorCode &errorCode) {
- int32_t keypos;
-
- if (U_FAILURE(errorCode)) {
- return -1;
- }
-
- if (tag == NULL) {
- /* no error: the root table and array items have no keys */
- return -1;
- }
-
- keypos = addKeyBytes(tag, (int32_t)(uprv_strlen(tag) + 1), errorCode);
- if (U_SUCCESS(errorCode)) {
- ++fKeysCount;
- }
- return keypos;
-}
-
-static int32_t
-compareInt32(int32_t lPos, int32_t rPos) {
- /*
- * Compare possibly-negative key offsets. Don't just return lPos - rPos
- * because that is prone to negative-integer underflows.
- */
- if (lPos < rPos) {
- return -1;
- } else if (lPos > rPos) {
- return 1;
- } else {
- return 0;
- }
-}
-
-static int32_t U_CALLCONV
-compareKeySuffixes(const void *context, const void *l, const void *r) {
- const struct SRBRoot *bundle=(const struct SRBRoot *)context;
- int32_t lPos = ((const KeyMapEntry *)l)->oldpos;
- int32_t rPos = ((const KeyMapEntry *)r)->oldpos;
- const char *lStart = bundle->getKeyString(lPos);
- const char *lLimit = lStart;
- const char *rStart = bundle->getKeyString(rPos);
- const char *rLimit = rStart;
- int32_t diff;
- while (*lLimit != 0) { ++lLimit; }
- while (*rLimit != 0) { ++rLimit; }
- /* compare keys in reverse character order */
- while (lStart < lLimit && rStart < rLimit) {
- diff = (int32_t)(uint8_t)*--lLimit - (int32_t)(uint8_t)*--rLimit;
- if (diff != 0) {
- return diff;
- }
- }
- /* sort equal suffixes by descending key length */
- diff = (int32_t)(rLimit - rStart) - (int32_t)(lLimit - lStart);
- if (diff != 0) {
- return diff;
- }
- /* Sort pool bundle keys first (negative oldpos), and otherwise keys in parsing order. */
- return compareInt32(lPos, rPos);
-}
-
-static int32_t U_CALLCONV
-compareKeyNewpos(const void * /*context*/, const void *l, const void *r) {
- return compareInt32(((const KeyMapEntry *)l)->newpos, ((const KeyMapEntry *)r)->newpos);
-}
-
-static int32_t U_CALLCONV
-compareKeyOldpos(const void * /*context*/, const void *l, const void *r) {
- return compareInt32(((const KeyMapEntry *)l)->oldpos, ((const KeyMapEntry *)r)->oldpos);
-}
-
-void
-SRBRoot::compactKeys(UErrorCode &errorCode) {
- KeyMapEntry *map;
- char *keys;
- int32_t i;
- int32_t keysCount = fUsePoolBundle->fKeysCount + fKeysCount;
- if (U_FAILURE(errorCode) || fKeysCount == 0 || fKeyMap != NULL) {
- return;
- }
- map = (KeyMapEntry *)uprv_malloc(keysCount * sizeof(KeyMapEntry));
- if (map == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- keys = (char *)fUsePoolBundle->fKeys;
- for (i = 0; i < fUsePoolBundle->fKeysCount; ++i) {
- map[i].oldpos =
- (int32_t)(keys - fUsePoolBundle->fKeys) | 0x80000000; /* negative oldpos */
- map[i].newpos = 0;
- while (*keys != 0) { ++keys; } /* skip the key */
- ++keys; /* skip the NUL */
- }
- keys = fKeys + fKeysBottom;
- for (; i < keysCount; ++i) {
- map[i].oldpos = (int32_t)(keys - fKeys);
- map[i].newpos = 0;
- while (*keys != 0) { ++keys; } /* skip the key */
- ++keys; /* skip the NUL */
- }
- /* Sort the keys so that each one is immediately followed by all of its suffixes. */
- uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry),
- compareKeySuffixes, this, FALSE, &errorCode);
- /*
- * Make suffixes point into earlier, longer strings that contain them
- * and mark the old, now unused suffix bytes as deleted.
- */
- if (U_SUCCESS(errorCode)) {
- keys = fKeys;
- for (i = 0; i < keysCount;) {
- /*
- * This key is not a suffix of the previous one;
- * keep this one and delete the following ones that are
- * suffixes of this one.
- */
- const char *key;
- const char *keyLimit;
- int32_t j = i + 1;
- map[i].newpos = map[i].oldpos;
- if (j < keysCount && map[j].oldpos < 0) {
- /* Key string from the pool bundle, do not delete. */
- i = j;
- continue;
- }
- key = getKeyString(map[i].oldpos);
- for (keyLimit = key; *keyLimit != 0; ++keyLimit) {}
- for (; j < keysCount && map[j].oldpos >= 0; ++j) {
- const char *k;
- char *suffix;
- const char *suffixLimit;
- int32_t offset;
- suffix = keys + map[j].oldpos;
- for (suffixLimit = suffix; *suffixLimit != 0; ++suffixLimit) {}
- offset = static_cast<int32_t>((keyLimit - key) - (suffixLimit - suffix));
- if (offset < 0) {
- break; /* suffix cannot be longer than the original */
- }
- /* Is it a suffix of the earlier, longer key? */
- for (k = keyLimit; suffix < suffixLimit && *--k == *--suffixLimit;) {}
- if (suffix == suffixLimit && *k == *suffixLimit) {
- map[j].newpos = map[i].oldpos + offset; /* yes, point to the earlier key */
- /* mark the suffix as deleted */
- while (*suffix != 0) { *suffix++ = 1; }
- *suffix = 1;
- } else {
- break; /* not a suffix, restart from here */
- }
- }
- i = j;
- }
- /*
- * Re-sort by newpos, then modify the key characters array in-place
- * to squeeze out unused bytes, and readjust the newpos offsets.
- */
- uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry),
- compareKeyNewpos, NULL, FALSE, &errorCode);
- if (U_SUCCESS(errorCode)) {
- int32_t oldpos, newpos, limit;
- oldpos = newpos = fKeysBottom;
- limit = fKeysTop;
- /* skip key offsets that point into the pool bundle rather than this new bundle */
- for (i = 0; i < keysCount && map[i].newpos < 0; ++i) {}
- if (i < keysCount) {
- while (oldpos < limit) {
- if (keys[oldpos] == 1) {
- ++oldpos; /* skip unused bytes */
- } else {
- /* adjust the new offsets for keys starting here */
- while (i < keysCount && map[i].newpos == oldpos) {
- map[i++].newpos = newpos;
- }
- /* move the key characters to their new position */
- keys[newpos++] = keys[oldpos++];
- }
- }
- assert(i == keysCount);
- }
- fKeysTop = newpos;
- /* Re-sort once more, by old offsets for binary searching. */
- uprv_sortArray(map, keysCount, (int32_t)sizeof(KeyMapEntry),
- compareKeyOldpos, NULL, FALSE, &errorCode);
- if (U_SUCCESS(errorCode)) {
- /* key size reduction by limit - newpos */
- fKeyMap = map;
- map = NULL;
- }
- }
- }
- uprv_free(map);
-}
-
-static int32_t U_CALLCONV
-compareStringSuffixes(const void * /*context*/, const void *l, const void *r) {
- const StringResource *left = *((const StringResource **)l);
- const StringResource *right = *((const StringResource **)r);
- const UChar *lStart = left->getBuffer();
- const UChar *lLimit = lStart + left->length();
- const UChar *rStart = right->getBuffer();
- const UChar *rLimit = rStart + right->length();
- int32_t diff;
- /* compare keys in reverse character order */
- while (lStart < lLimit && rStart < rLimit) {
- diff = (int32_t)*--lLimit - (int32_t)*--rLimit;
- if (diff != 0) {
- return diff;
- }
- }
- /* sort equal suffixes by descending string length */
- return right->length() - left->length();
-}
-
-static int32_t U_CALLCONV
-compareStringLengths(const void * /*context*/, const void *l, const void *r) {
- const StringResource *left = *((const StringResource **)l);
- const StringResource *right = *((const StringResource **)r);
- int32_t diff;
- /* Make "is suffix of another string" compare greater than a non-suffix. */
- diff = (int)(left->fSame != NULL) - (int)(right->fSame != NULL);
- if (diff != 0) {
- return diff;
- }
- /* sort by ascending string length */
- diff = left->length() - right->length();
- if (diff != 0) {
- return diff;
- }
- // sort by descending size reduction
- diff = right->fNumUnitsSaved - left->fNumUnitsSaved;
- if (diff != 0) {
- return diff;
- }
- // sort lexically
- return left->fString.compare(right->fString);
-}
-
-void
-StringResource::writeUTF16v2(int32_t base, UnicodeString &dest) {
- int32_t len = length();
- fRes = URES_MAKE_RESOURCE(URES_STRING_V2, base + dest.length());
- fWritten = TRUE;
- switch(fNumCharsForLength) {
- case 0:
- break;
- case 1:
- dest.append((UChar)(0xdc00 + len));
- break;
- case 2:
- dest.append((UChar)(0xdfef + (len >> 16)));
- dest.append((UChar)len);
- break;
- case 3:
- dest.append((UChar)0xdfff);
- dest.append((UChar)(len >> 16));
- dest.append((UChar)len);
- break;
- default:
- break; /* will not occur */
- }
- dest.append(fString);
- dest.append((UChar)0);
-}
-
-void
-SRBRoot::compactStringsV2(UHashtable *stringSet, UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) {
- return;
- }
- // Store the StringResource pointers in an array for
- // easy sorting and processing.
- // We enumerate a set of strings, so there are no duplicates.
- int32_t count = uhash_count(stringSet);
- LocalArray<StringResource *> array(new StringResource *[count], errorCode);
- if (U_FAILURE(errorCode)) {
- return;
- }
- for (int32_t pos = UHASH_FIRST, i = 0; i < count; ++i) {
- array[i] = (StringResource *)uhash_nextElement(stringSet, &pos)->key.pointer;
- }
- /* Sort the strings so that each one is immediately followed by all of its suffixes. */
- uprv_sortArray(array.getAlias(), count, (int32_t)sizeof(struct SResource **),
- compareStringSuffixes, NULL, FALSE, &errorCode);
- if (U_FAILURE(errorCode)) {
- return;
- }
- /*
- * Make suffixes point into earlier, longer strings that contain them.
- * Temporarily use fSame and fSuffixOffset for suffix strings to
- * refer to the remaining ones.
- */
- for (int32_t i = 0; i < count;) {
- /*
- * This string is not a suffix of the previous one;
- * write this one and subsume the following ones that are
- * suffixes of this one.
- */
- StringResource *res = array[i];
- res->fNumUnitsSaved = (res->fNumCopies - 1) * res->get16BitStringsLength();
- // Whole duplicates of pool strings are already account for in fPoolStringIndexLimit,
- // see StringResource::handlePreflightStrings().
- int32_t j;
- for (j = i + 1; j < count; ++j) {
- StringResource *suffixRes = array[j];
- /* Is it a suffix of the earlier, longer string? */
- if (res->fString.endsWith(suffixRes->fString)) {
- assert(res->length() != suffixRes->length()); // Set strings are unique.
- if (suffixRes->fWritten) {
- // Pool string, skip.
- } else if (suffixRes->fNumCharsForLength == 0) {
- /* yes, point to the earlier string */
- suffixRes->fSame = res;
- suffixRes->fSuffixOffset = res->length() - suffixRes->length();
- if (res->fWritten) {
- // Suffix-share res which is a pool string.
- // Compute the resource word and collect the maximum.
- suffixRes->fRes =
- res->fRes + res->fNumCharsForLength + suffixRes->fSuffixOffset;
- int32_t poolStringIndex = (int32_t)RES_GET_OFFSET(suffixRes->fRes);
- if (poolStringIndex >= fPoolStringIndexLimit) {
- fPoolStringIndexLimit = poolStringIndex + 1;
- }
- suffixRes->fWritten = TRUE;
- }
- res->fNumUnitsSaved += suffixRes->fNumCopies * suffixRes->get16BitStringsLength();
- } else {
- /* write the suffix by itself if we need explicit length */
- }
- } else {
- break; /* not a suffix, restart from here */
- }
- }
- i = j;
- }
- /*
- * Re-sort the strings by ascending length (except suffixes last)
- * to optimize for URES_TABLE16 and URES_ARRAY16:
- * Keep as many as possible within reach of 16-bit offsets.
- */
- uprv_sortArray(array.getAlias(), count, (int32_t)sizeof(struct SResource **),
- compareStringLengths, NULL, FALSE, &errorCode);
- if (U_FAILURE(errorCode)) {
- return;
- }
- if (fIsPoolBundle) {
- // Write strings that are sufficiently shared.
- // Avoid writing other strings.
- int32_t numStringsWritten = 0;
- int32_t numUnitsSaved = 0;
- int32_t numUnitsNotSaved = 0;
- for (int32_t i = 0; i < count; ++i) {
- StringResource *res = array[i];
- // Maximum pool string index when suffix-sharing the last character.
- int32_t maxStringIndex =
- f16BitUnits.length() + res->fNumCharsForLength + res->length() - 1;
- if (res->fNumUnitsSaved >= GENRB_MIN_16BIT_UNITS_SAVED_FOR_POOL_STRING &&
- maxStringIndex < RES_MAX_OFFSET) {
- res->writeUTF16v2(0, f16BitUnits);
- ++numStringsWritten;
- numUnitsSaved += res->fNumUnitsSaved;
- } else {
- numUnitsNotSaved += res->fNumUnitsSaved;
- res->fRes = URES_MAKE_EMPTY_RESOURCE(URES_STRING);
- res->fWritten = TRUE;
- }
- }
- if (f16BitUnits.isBogus()) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- }
- if (getShowWarning()) { // not quiet
- printf("number of shared strings: %d\n", (int)numStringsWritten);
- printf("16-bit units for strings: %6d = %6d bytes\n",
- (int)f16BitUnits.length(), (int)f16BitUnits.length() * 2);
- printf("16-bit units saved: %6d = %6d bytes\n",
- (int)numUnitsSaved, (int)numUnitsSaved * 2);
- printf("16-bit units not saved: %6d = %6d bytes\n",
- (int)numUnitsNotSaved, (int)numUnitsNotSaved * 2);
- }
- } else {
- assert(fPoolStringIndexLimit <= fUsePoolBundle->fStringIndexLimit);
- /* Write the non-suffix strings. */
- int32_t i;
- for (i = 0; i < count && array[i]->fSame == NULL; ++i) {
- StringResource *res = array[i];
- if (!res->fWritten) {
- int32_t localStringIndex = f16BitUnits.length();
- if (localStringIndex >= fLocalStringIndexLimit) {
- fLocalStringIndexLimit = localStringIndex + 1;
- }
- res->writeUTF16v2(fPoolStringIndexLimit, f16BitUnits);
- }
- }
- if (f16BitUnits.isBogus()) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- if (fWritePoolBundle != NULL && gFormatVersion >= 3) {
- PseudoListResource *poolStrings =
- static_cast<PseudoListResource *>(fWritePoolBundle->fRoot);
- for (i = 0; i < count && array[i]->fSame == NULL; ++i) {
- assert(!array[i]->fString.isEmpty());
- StringResource *poolString =
- new StringResource(fWritePoolBundle, array[i]->fString, errorCode);
- if (poolString == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- break;
- }
- poolStrings->add(poolString);
- }
- }
- /* Write the suffix strings. Make each point to the real string. */
- for (; i < count; ++i) {
- StringResource *res = array[i];
- if (res->fWritten) {
- continue;
- }
- StringResource *same = res->fSame;
- assert(res->length() != same->length()); // Set strings are unique.
- res->fRes = same->fRes + same->fNumCharsForLength + res->fSuffixOffset;
- int32_t localStringIndex = (int32_t)RES_GET_OFFSET(res->fRes) - fPoolStringIndexLimit;
- // Suffixes of pool strings have been set already.
- assert(localStringIndex >= 0);
- if (localStringIndex >= fLocalStringIndexLimit) {
- fLocalStringIndexLimit = localStringIndex + 1;
- }
- res->fWritten = TRUE;
- }
- }
- // +1 to account for the initial zero in f16BitUnits
- assert(f16BitUnits.length() <= (f16BitStringsLength + 1));
-}