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