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