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#include "StringPool.h"
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/ByteOrder.h>
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/SortedVector.h>
100de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert
110de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert#include <algorithm>
120de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert
130de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert#include "ResourceTable.h"
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
152412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe// SSIZE: mingw does not have signed size_t == ssize_t.
16b12f2410c7bdbf90bd8a77b897846ee2763e3037Elliott Hughes#if !defined(_WIN32)
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD "%zd"
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD_TYPE ssize_t
192412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#  define SSIZE(x) x
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#else
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD "%ld"
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#  define ZD_TYPE long
232412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#  define SSIZE(x) (signed size_t)x
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
262412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe// Set to true for noisy debug output.
272412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampestatic const bool kIsDebug = false;
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
294bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski#if __cplusplus >= 201103L
30f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albertvoid strcpy16_htod(char16_t* dst, const char16_t* src)
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (*src) {
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        char16_t s = htods(*src);
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *dst++ = s;
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        src++;
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *dst = 0;
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
394bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski#endif
404bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski
414bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinskivoid strcpy16_htod(uint16_t* dst, const char16_t* src)
424bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski{
434bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    while (*src) {
444bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        uint16_t s = htods(static_cast<uint16_t>(*src));
454bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        *dst++ = s;
464bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski        src++;
474bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    }
484bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    *dst = 0;
494bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski}
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid printStringPool(const ResStringPool* pool)
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
5325e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    if (pool->getError() == NO_INIT) {
5425e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        printf("String pool is unitialized.\n");
5525e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        return;
5625e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    } else if (pool->getError() != NO_ERROR) {
5725e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        printf("String pool is corrupt/invalid.\n");
5825e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        return;
5925e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    }
6025e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SortedVector<const void*> uniqueStrings;
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = pool->size();
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t len;
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (pool->isUTF8()) {
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uniqueStrings.add(pool->string8At(i, &len));
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uniqueStrings.add(pool->stringAt(i, &len));
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ZD " styles using " ZD " bytes:\n",
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            pool->isSorted() ? "sorted" : "non-sorted",
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t NS = pool->size();
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t s=0; s<NS; s++) {
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8 str = pool->string8ObjectAt(s);
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString8 StringPool::entry::makeConfigsString() const {
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 configStr(configTypeName);
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (configStr.size() > 0) configStr.append(" ");
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (configs.size() > 0) {
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t j=0; j<configs.size(); j++) {
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (j > 0) configStr.append(", ");
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            configStr.append(configs[j].toString());
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        configStr = "(none)";
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return configStr;
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint StringPool::entry::compare(const entry& o) const {
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Strings with styles go first, to reduce the size of the styles array.
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // We don't care about the relative order of these strings.
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (hasStyles) {
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return o.hasStyles ? 0 : -1;
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (o.hasStyles) {
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Sort unstyled strings by type, then by logical configuration.
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int comp = configTypeName.compare(o.configTypeName);
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (comp != 0) {
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return comp;
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t LHN = configs.size();
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t RHN = o.configs.size();
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t i=0;
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (i < LHN && i < RHN) {
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        comp = configs[i].compareLogical(o.configs[i]);
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (comp != 0) {
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return comp;
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        i++;
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (LHN < RHN) return -1;
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else if (LHN > RHN) return 1;
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiStringPool::StringPool(bool utf8) :
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mUTF8(utf8), mValues(-1)
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String8* configTypeName, const ResTable_config* config)
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t res = add(value, false, configTypeName, config);
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (res >= 0) {
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        addStyleSpans(res, spans);
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return res;
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t StringPool::add(const String16& value,
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t vidx = mValues.indexOfKey(value);
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t pos = vidx >= 0 ? mValues.valueAt(vidx) : -1;
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t eidx = pos >= 0 ? mEntryArray.itemAt(pos) : -1;
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (eidx < 0) {
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        eidx = mEntries.add(entry(value));
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (eidx < 0) {
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Failure adding string %s\n", String8(value).string());
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return eidx;
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (configTypeName != NULL) {
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(eidx);
1602412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        if (kIsDebug) {
1612412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            printf("*** adding config type name %s, was %s\n",
1622412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    configTypeName->string(), ent.configTypeName.string());
1632412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        }
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (ent.configTypeName.size() <= 0) {
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ent.configTypeName = *configTypeName;
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (ent.configTypeName != *configTypeName) {
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ent.configTypeName = " ";
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (config != NULL) {
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Add this to the set of configs associated with the string.
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(eidx);
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t addPos;
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (addPos=0; addPos<ent.configs.size(); addPos++) {
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (cmp >= 0) {
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (cmp > 0) {
1792412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    if (kIsDebug) {
1802412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        printf("*** inserting config: %s\n", config->toString().string());
1812412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    }
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ent.configs.insertAt(*config, addPos);
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (addPos >= ent.configs.size()) {
1882412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            if (kIsDebug) {
1892412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                printf("*** adding config: %s\n", config->toString().string());
1902412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            }
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ent.configs.add(*config);
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const bool first = vidx < 0;
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ?
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mEntryStyleArray[pos].spans.size() : 0;
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (first || styled || !mergeDuplicates) {
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        pos = mEntryArray.add(eidx);
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (first) {
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            vidx = mValues.add(value, pos);
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(eidx);
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ent.indices.add(pos);
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2072412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
2082412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("Adding string %s to pool: pos=%zd eidx=%zd vidx=%zd\n",
2092412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(value).string(), SSIZE(pos), SSIZE(eidx), SSIZE(vidx));
2102412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
2112412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return pos;
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::addStyleSpan(size_t idx, const String16& name,
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  uint32_t start, uint32_t end)
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    entry_style_span span;
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    span.name = name;
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    span.span.firstChar = start;
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    span.span.lastChar = end;
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return addStyleSpan(idx, span);
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& spans)
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N=spans.size();
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        status_t err = addStyleSpan(idx, spans[i]);
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return err;
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span)
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Place blank entries in the span array up to this index.
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (mEntryStyleArray.size() <= idx) {
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mEntryStyleArray.add();
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    entry_style& style = mEntryStyleArray.editItemAt(idx);
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    style.spans.add(span);
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2500de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan AlbertStringPool::ConfigSorter::ConfigSorter(const StringPool& pool) : pool(pool)
2510de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert{
2520de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert}
2530de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert
2540de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albertbool StringPool::ConfigSorter::operator()(size_t l, size_t r)
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2560de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert    const StringPool::entry& lhe = pool.mEntries[pool.mEntryArray[l]];
2570de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert    const StringPool::entry& rhe = pool.mEntries[pool.mEntryArray[r]];
2580de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert    return lhe.compare(rhe) < 0;
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid StringPool::sortByConfig()
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = mEntryArray.size();
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // This is a vector that starts out with a 1:1 mapping to entries
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the array, which we will sort to come up with the desired order.
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At that point it maps from the new position in the array to the
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // original position the entry appeared.
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<size_t> newPosToOriginalPos;
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    newPosToOriginalPos.setCapacity(N);
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i < N; i++) {
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newPosToOriginalPos.add(i);
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Sort the array.
2782412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
2792412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("SORTING STRINGS BY CONFIGURATION...\n");
2802412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
2810de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert    ConfigSorter sorter(*this);
2820de19adc80d8caeac8ab5da79e70ed4adb18b1c1Dan Albert    std::sort(newPosToOriginalPos.begin(), newPosToOriginalPos.end(), sorter);
2832412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
2842412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("DONE SORTING STRINGS BY CONFIGURATION.\n");
2852412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Create the reverse mapping from the original position in the array
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to the new position where it appears in the sorted array.  This is
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // so that clients can re-map any positions they had previously stored.
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mOriginalPosToNewPos = newPosToOriginalPos;
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SortedVector<entry> entries;
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entries.add(mEntries[mEntryArray[i]]);
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<entries.size(); i++) {
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Sorted config #%d: %s\n", i,
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entries[i].makeConfigsString().string());
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Now we rebuild the arrays.
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<entry> newEntries;
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<size_t> newEntryArray;
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<entry_style> newEntryStyleArray;
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // We are filling in new offset 'i'; oldI is where we can find it
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // in the original data structure.
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t oldI = newPosToOriginalPos[i];
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // This is the actual entry associated with the old offset.
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry& oldEnt = mEntries[mEntryArray[oldI]];
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // This is the same entry the last time we added it to the
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // new entry array, if any.
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t newOffset;
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (newIndexOfOffset < 0) {
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This is the first time we have seen the entry, so add
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // it.
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            newOffset = newEntries.add(oldEnt);
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            newEntries.editItemAt(newOffset).indices.clear();
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // We have seen this entry before, use the existing one
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // instead of adding it again.
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Update the indices to include this new position.
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newEntries.editItemAt(newOffset).indices.add(i);
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // And add the offset of the entry to the new entry array.
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newEntryArray.add(newOffset);
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Add any old style to the new style array.
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mEntryStyleArray.size() > 0) {
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (oldI < mEntryStyleArray.size()) {
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                newEntryStyleArray.add(mEntryStyleArray[oldI]);
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                newEntryStyleArray.add(entry_style());
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Now trim any entries at the end of the new style array that are
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // not needed.
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry_style& style = newEntryStyleArray[i];
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (style.spans.size() > 0) {
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // That's it.
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // This one is not needed; remove.
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newEntryStyleArray.removeAt(i);
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // All done, install the new data structures and upate mValues with
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the new positions.
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntries = newEntries;
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntryArray = newEntryArray;
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntryStyleArray = newEntryStyleArray;
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mValues.clear();
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<mEntries.size(); i++) {
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry& ent = mEntries[i];
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mValues.add(ent.value, ent.indices[0]);
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("FINAL SORTED STRING CONFIGS:\n");
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<mEntries.size(); i++) {
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const entry& ent = mEntries[i];
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8(ent.value).string());
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<AaptFile> StringPool::createStringBlock()
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                     String8());
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = writeStringBlock(pool);
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err == NO_ERROR ? pool : NULL;
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define ENCODE_LENGTH(str, chrsz, strSize) \
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{ \
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t maxMask = 1 << ((chrsz*8)-1); \
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t maxSize = maxMask-1; \
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strSize > maxSize) { \
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } \
398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *str++ = strSize; \
399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Allow appending.  Sorry this is a little wacky.
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pool->getSize() > 0) {
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<AaptFile> block = createStringBlock();
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (block == NULL) {
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ssize_t res = pool->writeData(block->getData(), block->getSize());
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (res >= 0) ? (status_t)NO_ERROR : res;
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // First we need to add all style span names to the string pool.
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // We do this now (instead of when the span is added) so that these
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // will appear at the end of the pool, not disrupting the order
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // our client placed their own strings in it.
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t STYLES = mEntryStyleArray.size();
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t i;
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STYLES; i++) {
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry_style& style = mEntryStyleArray.editItemAt(i);
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = style.spans.size();
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            entry_style_span& span = style.spans.editItemAt(i);
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ssize_t idx = add(span.name, true);
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (idx < 0) {
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "Error adding span for style tag '%s'\n",
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(span.name).string());
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return idx;
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span.span.name.index = (uint32_t)idx;
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t ENTRIES = mEntryArray.size();
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Now build the pool of unique strings.
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t STRINGS = mEntries.size();
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t preSize = sizeof(ResStringPool_header)
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         + (sizeof(uint32_t)*ENTRIES)
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         + (sizeof(uint32_t)*STYLES);
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pool->editData(preSize) == NULL) {
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: Out of memory for string pool\n");
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_MEMORY;
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4494bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(uint16_t);
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t strPos = 0;
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STRINGS; i++) {
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(i);
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t strSize = (ent.value.size());
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ?
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            charSize*2 : charSize;
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8 encStr;
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mUTF8) {
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            encStr = String8(ent.value);
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t encSize = mUTF8 ? encStr.size() : 0;
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t encLenSize = mUTF8 ?
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (encSize > (size_t)(1<<((charSize*8)-1))-1 ?
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                charSize*2 : charSize) : 0;
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ent.offset = strPos;
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t totalSize = lenSize + encLenSize +
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ((mUTF8 ? encSize : strSize)+1)*charSize;
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        void* dat = (void*)pool->editData(preSize + strPos + totalSize);
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory for string pool\n");
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        dat = (uint8_t*)dat + preSize + strPos;
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mUTF8) {
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uint8_t* strings = (uint8_t*)dat;
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ENCODE_LENGTH(strings, sizeof(uint8_t), strSize)
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ENCODE_LENGTH(strings, sizeof(uint8_t), encSize)
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strncpy((char*)strings, encStr, encSize+1);
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
488f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albert            char16_t* strings = (char16_t*)dat;
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
490f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albert            ENCODE_LENGTH(strings, sizeof(char16_t), strSize)
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strcpy16_htod(strings, ent.value);
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strPos += totalSize;
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Pad ending string position up to a uint32_t boundary.
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strPos&0x3) {
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t padPos = ((strPos+3)&~0x3);
502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos);
503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory padding string pool\n");
505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memset(dat+preSize+strPos, 0, padPos-strPos);
508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strPos = padPos;
509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Build the pool of style spans.
512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t styPos = strPos;
514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STYLES; i++) {
515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry_style& ent = mEntryStyleArray.editItemAt(i);
516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = ent.spans.size();
517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t totalSize = (N*sizeof(ResStringPool_span))
518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               + sizeof(ResStringPool_ref);
519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ent.offset = styPos-strPos;
521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize);
522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory for string styles\n");
524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos);
527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span->name.index = htodl(ent.spans[i].span.name.index);
529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span->firstChar = htodl(ent.spans[i].span.firstChar);
530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span->lastChar = htodl(ent.spans[i].span.lastChar);
531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span++;
532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        span->name.index = htodl(ResStringPool_span::END);
534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        styPos += totalSize;
536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (STYLES > 0) {
539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Add full terminator at the end (when reading we validate that
540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the end of the pool is fully terminated to simplify error
541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // checking).
542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref);
543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra);
544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (dat == NULL) {
545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: Out of memory for string styles\n");
546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t* p = (uint32_t*)(dat+preSize+styPos);
549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (extra > 0) {
550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *p++ = htodl(ResStringPool_span::END);
551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            extra -= sizeof(uint32_t);
552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        styPos += extra;
554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write header.
557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResStringPool_header* header =
559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        (ResStringPool_header*)pool->padData(sizeof(uint32_t));
560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (header == NULL) {
561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: Out of memory for string pool\n");
562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_MEMORY;
563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    memset(header, 0, sizeof(*header));
565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->header.type = htods(RES_STRING_POOL_TYPE);
566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->header.headerSize = htods(sizeof(*header));
567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->header.size = htodl(pool->getSize());
568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->stringCount = htodl(ENTRIES);
569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->styleCount = htodl(STYLES);
570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mUTF8) {
571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->flags |= htodl(ResStringPool_header::UTF8_FLAG);
572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->stringsStart = htodl(preSize);
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0);
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write string index array.
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t* index = (uint32_t*)(header+1);
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<ENTRIES; i++) {
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry& ent = mEntries.editItemAt(mEntryArray[i]);
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *index++ = htodl(ent.offset);
5822412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        if (kIsDebug) {
5832412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            printf("Writing entry #%zu: \"%s\" ent=%zu off=%zu\n",
5842412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    i,
5852412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    String8(ent.value).string(),
5862412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    mEntryArray[i],
5872412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    ent.offset);
5882412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        }
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write style index array.
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<STYLES; i++) {
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *index++ = htodl(mEntryStyleArray[i].offset);
595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskissize_t StringPool::offsetForString(const String16& val) const
601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Vector<size_t>* indices = offsetsForString(val);
603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
6042412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
6052412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("Offset for string %s: %zd (%s)\n", String8(val).string(), SSIZE(res),
6062412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8());
6072412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return res;
609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst Vector<size_t>* StringPool::offsetsForString(const String16& val) const
612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t pos = mValues.valueFor(val);
614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pos < 0) {
615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return &mEntries[mEntryArray[pos]].indices;
618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
619