1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Copyright 2006 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Build resource files from raw assets.
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "StringPool.h"
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h"
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/ByteOrder.h>
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/SortedVector.h>
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "qsort_r_compat.h"
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if HAVE_PRINTF_ZD
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD "%zd"
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD_TYPE ssize_t
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#else
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD "%ld"
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD_TYPE long
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define NOISY(x) //x
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski#if __cplusplus >= 201103L
254bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinskivoid strcpy16_htod(char16_t* dst, const char16_t* src)
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (*src) {
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        char16_t s = htods(*src);
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *dst++ = s;
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        src++;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *dst = 0;
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
344bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski#endif
354bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski
364bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinskivoid strcpy16_htod(uint16_t* dst, const char16_t* src)
374bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski{
384bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    while (*src) {
394bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        uint16_t s = htods(static_cast<uint16_t>(*src));
404bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        *dst++ = s;
414bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        src++;
424bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    }
434bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    *dst = 0;
444bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski}
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid printStringPool(const ResStringPool* pool)
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4825e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    if (pool->getError() == NO_INIT) {
4925e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        printf("String pool is unitialized.\n");
5025e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        return;
5125e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    } else if (pool->getError() != NO_ERROR) {
5225e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        printf("String pool is corrupt/invalid.\n");
5325e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        return;
5425e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    }
5525e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SortedVector<const void*> uniqueStrings;
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = pool->size();
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t len;
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (pool->isUTF8()) {
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uniqueStrings.add(pool->string8At(i, &len));
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uniqueStrings.add(pool->stringAt(i, &len));
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ZD " styles using " ZD " bytes:\n",
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            pool->isSorted() ? "sorted" : "non-sorted",
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t NS = pool->size();
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t s=0; s<NS; s++) {
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8 str = pool->string8ObjectAt(s);
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString8 StringPool::entry::makeConfigsString() const {
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 configStr(configTypeName);
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (configStr.size() > 0) configStr.append(" ");
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (configs.size() > 0) {
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t j=0; j<configs.size(); j++) {
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (j > 0) configStr.append(", ");
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            configStr.append(configs[j].toString());
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        configStr = "(none)";
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return configStr;
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint StringPool::entry::compare(const entry& o) const {
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Strings with styles go first, to reduce the size of the styles array.
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // We don't care about the relative order of these strings.
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (hasStyles) {
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return o.hasStyles ? 0 : -1;
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (o.hasStyles) {
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Sort unstyled strings by type, then by logical configuration.
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int comp = configTypeName.compare(o.configTypeName);
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (comp != 0) {
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return comp;
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t LHN = configs.size();
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t RHN = o.configs.size();
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t i=0;
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (i < LHN && i < RHN) {
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        comp = configs[i].compareLogical(o.configs[i]);
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (comp != 0) {
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return comp;
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        i++;
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (LHN < RHN) return -1;
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else if (LHN > RHN) return 1;
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiStringPool::StringPool(bool utf8) :
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mUTF8(utf8), mValues(-1)
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String8* configTypeName, const ResTable_config* config)
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t res = add(value, false, configTypeName, config);
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (res >= 0) {
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        addStyleSpans(res, spans);
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return res;
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t StringPool::add(const String16& value,
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t vidx = mValues.indexOfKey(value);
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t pos = vidx >= 0 ? mValues.valueAt(vidx) : -1;
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t eidx = pos >= 0 ? mEntryArray.itemAt(pos) : -1;
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (eidx < 0) {
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        eidx = mEntries.add(entry(value));
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (eidx < 0) {
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Failure adding string %s\n", String8(value).string());
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return eidx;
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (configTypeName != NULL) {
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(eidx);
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        NOISY(printf("*** adding config type name %s, was %s\n",
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                configTypeName->string(), ent.configTypeName.string()));
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (ent.configTypeName.size() <= 0) {
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ent.configTypeName = *configTypeName;
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (ent.configTypeName != *configTypeName) {
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ent.configTypeName = " ";
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (config != NULL) {
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Add this to the set of configs associated with the string.
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(eidx);
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t addPos;
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (addPos=0; addPos<ent.configs.size(); addPos++) {
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (cmp >= 0) {
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (cmp > 0) {
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    NOISY(printf("*** inserting config: %s\n", config->toString().string()));
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ent.configs.insertAt(*config, addPos);
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (addPos >= ent.configs.size()) {
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            NOISY(printf("*** adding config: %s\n", config->toString().string()));
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ent.configs.add(*config);
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const bool first = vidx < 0;
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ?
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mEntryStyleArray[pos].spans.size() : 0;
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (first || styled || !mergeDuplicates) {
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        pos = mEntryArray.add(eidx);
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (first) {
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            vidx = mValues.add(value, pos);
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(eidx);
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ent.indices.add(pos);
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n",
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8(value).string(), pos, eidx, vidx));
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return pos;
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::addStyleSpan(size_t idx, const String16& name,
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  uint32_t start, uint32_t end)
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    entry_style_span span;
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    span.name = name;
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    span.span.firstChar = start;
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    span.span.lastChar = end;
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return addStyleSpan(idx, span);
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& spans)
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N=spans.size();
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        status_t err = addStyleSpan(idx, spans[i]);
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return err;
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span)
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Place blank entries in the span array up to this index.
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (mEntryStyleArray.size() <= idx) {
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mEntryStyleArray.add();
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    entry_style& style = mEntryStyleArray.editItemAt(idx);
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    style.spans.add(span);
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint StringPool::config_sort(void* state, const void* lhs, const void* rhs)
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    StringPool* pool = (StringPool*)state;
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]];
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]];
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return lhe.compare(rhe);
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid StringPool::sortByConfig()
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = mEntryArray.size();
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // This is a vector that starts out with a 1:1 mapping to entries
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the array, which we will sort to come up with the desired order.
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At that point it maps from the new position in the array to the
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // original position the entry appeared.
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<size_t> newPosToOriginalPos;
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    newPosToOriginalPos.setCapacity(N);
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i < N; i++) {
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newPosToOriginalPos.add(i);
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Sort the array.
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Vector::sort uses insertion sort, which is very slow for this data set.
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Use quicksort instead because we don't need a stable sort here.
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort);
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //newPosToOriginalPos.sort(config_sort, this);
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Create the reverse mapping from the original position in the array
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to the new position where it appears in the sorted array.  This is
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // so that clients can re-map any positions they had previously stored.
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mOriginalPosToNewPos = newPosToOriginalPos;
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SortedVector<entry> entries;
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entries.add(mEntries[mEntryArray[i]]);
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<entries.size(); i++) {
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Sorted config #%d: %s\n", i,
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entries[i].makeConfigsString().string());
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Now we rebuild the arrays.
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<entry> newEntries;
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<size_t> newEntryArray;
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<entry_style> newEntryStyleArray;
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // We are filling in new offset 'i'; oldI is where we can find it
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // in the original data structure.
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t oldI = newPosToOriginalPos[i];
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // This is the actual entry associated with the old offset.
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry& oldEnt = mEntries[mEntryArray[oldI]];
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // This is the same entry the last time we added it to the
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // new entry array, if any.
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t newOffset;
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (newIndexOfOffset < 0) {
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This is the first time we have seen the entry, so add
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // it.
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            newOffset = newEntries.add(oldEnt);
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            newEntries.editItemAt(newOffset).indices.clear();
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // We have seen this entry before, use the existing one
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // instead of adding it again.
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Update the indices to include this new position.
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newEntries.editItemAt(newOffset).indices.add(i);
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // And add the offset of the entry to the new entry array.
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newEntryArray.add(newOffset);
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Add any old style to the new style array.
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mEntryStyleArray.size() > 0) {
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (oldI < mEntryStyleArray.size()) {
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                newEntryStyleArray.add(mEntryStyleArray[oldI]);
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                newEntryStyleArray.add(entry_style());
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Now trim any entries at the end of the new style array that are
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // not needed.
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry_style& style = newEntryStyleArray[i];
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (style.spans.size() > 0) {
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // That's it.
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // This one is not needed; remove.
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newEntryStyleArray.removeAt(i);
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // All done, install the new data structures and upate mValues with
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the new positions.
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntries = newEntries;
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntryArray = newEntryArray;
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntryStyleArray = newEntryStyleArray;
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mValues.clear();
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<mEntries.size(); i++) {
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry& ent = mEntries[i];
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mValues.add(ent.value, ent.indices[0]);
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("FINAL SORTED STRING CONFIGS:\n");
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<mEntries.size(); i++) {
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry& ent = mEntries[i];
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8(ent.value).string());
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<AaptFile> StringPool::createStringBlock()
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                     String8());
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = writeStringBlock(pool);
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err == NO_ERROR ? pool : NULL;
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define ENCODE_LENGTH(str, chrsz, strSize) \
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ \
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t maxMask = 1 << ((chrsz*8)-1); \
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t maxSize = maxMask-1; \
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strSize > maxSize) { \
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } \
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *str++ = strSize; \
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Allow appending.  Sorry this is a little wacky.
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pool->getSize() > 0) {
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<AaptFile> block = createStringBlock();
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (block == NULL) {
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ssize_t res = pool->writeData(block->getData(), block->getSize());
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (res >= 0) ? (status_t)NO_ERROR : res;
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // First we need to add all style span names to the string pool.
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // We do this now (instead of when the span is added) so that these
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // will appear at the end of the pool, not disrupting the order
398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // our client placed their own strings in it.
399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t STYLES = mEntryStyleArray.size();
401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t i;
402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STYLES; i++) {
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry_style& style = mEntryStyleArray.editItemAt(i);
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = style.spans.size();
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            entry_style_span& span = style.spans.editItemAt(i);
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ssize_t idx = add(span.name, true);
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (idx < 0) {
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "Error adding span for style tag '%s'\n",
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(span.name).string());
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return idx;
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span.span.name.index = (uint32_t)idx;
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t ENTRIES = mEntryArray.size();
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Now build the pool of unique strings.
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t STRINGS = mEntries.size();
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t preSize = sizeof(ResStringPool_header)
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         + (sizeof(uint32_t)*ENTRIES)
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         + (sizeof(uint32_t)*STYLES);
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pool->editData(preSize) == NULL) {
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: Out of memory for string pool\n");
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_MEMORY;
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4314bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(uint16_t);
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t strPos = 0;
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STRINGS; i++) {
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(i);
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t strSize = (ent.value.size());
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ?
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            charSize*2 : charSize;
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8 encStr;
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mUTF8) {
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            encStr = String8(ent.value);
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t encSize = mUTF8 ? encStr.size() : 0;
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t encLenSize = mUTF8 ?
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (encSize > (size_t)(1<<((charSize*8)-1))-1 ?
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                charSize*2 : charSize) : 0;
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ent.offset = strPos;
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t totalSize = lenSize + encLenSize +
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ((mUTF8 ? encSize : strSize)+1)*charSize;
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        void* dat = (void*)pool->editData(preSize + strPos + totalSize);
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory for string pool\n");
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        dat = (uint8_t*)dat + preSize + strPos;
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mUTF8) {
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uint8_t* strings = (uint8_t*)dat;
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ENCODE_LENGTH(strings, sizeof(uint8_t), strSize)
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ENCODE_LENGTH(strings, sizeof(uint8_t), encSize)
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strncpy((char*)strings, encStr, encSize+1);
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uint16_t* strings = (uint16_t*)dat;
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ENCODE_LENGTH(strings, sizeof(uint16_t), strSize)
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strcpy16_htod(strings, ent.value);
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strPos += totalSize;
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Pad ending string position up to a uint32_t boundary.
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strPos&0x3) {
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t padPos = ((strPos+3)&~0x3);
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos);
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory padding string pool\n");
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memset(dat+preSize+strPos, 0, padPos-strPos);
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strPos = padPos;
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Build the pool of style spans.
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t styPos = strPos;
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STYLES; i++) {
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry_style& ent = mEntryStyleArray.editItemAt(i);
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = ent.spans.size();
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t totalSize = (N*sizeof(ResStringPool_span))
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               + sizeof(ResStringPool_ref);
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ent.offset = styPos-strPos;
503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize);
504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory for string styles\n");
506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos);
509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span->name.index = htodl(ent.spans[i].span.name.index);
511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span->firstChar = htodl(ent.spans[i].span.firstChar);
512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span->lastChar = htodl(ent.spans[i].span.lastChar);
513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span++;
514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        span->name.index = htodl(ResStringPool_span::END);
516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        styPos += totalSize;
518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (STYLES > 0) {
521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Add full terminator at the end (when reading we validate that
522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the end of the pool is fully terminated to simplify error
523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // checking).
524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref);
525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra);
526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory for string styles\n");
528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t* p = (uint32_t*)(dat+preSize+styPos);
531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (extra > 0) {
532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *p++ = htodl(ResStringPool_span::END);
533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            extra -= sizeof(uint32_t);
534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        styPos += extra;
536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write header.
539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResStringPool_header* header =
541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        (ResStringPool_header*)pool->padData(sizeof(uint32_t));
542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (header == NULL) {
543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: Out of memory for string pool\n");
544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_MEMORY;
545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    memset(header, 0, sizeof(*header));
547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->header.type = htods(RES_STRING_POOL_TYPE);
548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->header.headerSize = htods(sizeof(*header));
549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->header.size = htodl(pool->getSize());
550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->stringCount = htodl(ENTRIES);
551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->styleCount = htodl(STYLES);
552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mUTF8) {
553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->flags |= htodl(ResStringPool_header::UTF8_FLAG);
554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->stringsStart = htodl(preSize);
556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0);
557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write string index array.
559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t* index = (uint32_t*)(header+1);
561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<ENTRIES; i++) {
562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(mEntryArray[i]);
563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *index++ = htodl(ent.offset);
564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i,
565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8(ent.value).string(),
566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                mEntryArray[i], ent.offset));
567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write style index array.
570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STYLES; i++) {
572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *index++ = htodl(mEntryStyleArray[i].offset);
573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t StringPool::offsetForString(const String16& val) const
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Vector<size_t>* indices = offsetsForString(val);
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res,
583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8()));
584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return res;
585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst Vector<size_t>* StringPool::offsetsForString(const String16& val) const
588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t pos = mValues.valueFor(val);
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pos < 0) {
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return &mEntries[mEntryArray[pos]].indices;
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
595