StringPool.cpp revision 46fc395386f2277a0425b2c46be08fd91f6554f4
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt//
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Copyright 2006 The Android Open Source Project
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt//
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Build resource files from raw assets.
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt//
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "StringPool.h"
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ResourceTable.h"
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <utils/ByteOrder.h>
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <utils/SortedVector.h>
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if HAVE_PRINTF_ZD
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#  define ZD "%zd"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#  define ZD_TYPE ssize_t
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#  define ZD "%ld"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#  define ZD_TYPE long
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define NOISY(x) //x
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid strcpy16_htod(uint16_t* dst, const uint16_t* src)
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    while (*src) {
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        char16_t s = htods(*src);
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        *dst++ = s;
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        src++;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    *dst = 0;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid printStringPool(const ResStringPool* pool)
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    SortedVector<const void*> uniqueStrings;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const size_t N = pool->size();
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<N; i++) {
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        size_t len;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (pool->isUTF8()) {
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            uniqueStrings.add(pool->string8At(i, &len));
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        } else {
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            uniqueStrings.add(pool->stringAt(i, &len));
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            ZD " styles using " ZD " bytes:\n",
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            pool->isSorted() ? "sorted" : "non-sorted",
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const size_t NS = pool->size();
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t s=0; s<NS; s++) {
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        String8 str = pool->string8ObjectAt(s);
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtString8 StringPool::entry::makeConfigsString() const {
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    String8 configStr(configTypeName);
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (configStr.size() > 0) configStr.append(" ");
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (configs.size() > 0) {
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        for (size_t j=0; j<configs.size(); j++) {
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (j > 0) configStr.append(", ");
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            configStr.append(configs[j].toString());
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } else {
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        configStr = "(none)";
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return configStr;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint StringPool::entry::compare(const entry& o) const {
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Strings with styles go first, to reduce the size of the styles array.
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // We don't care about the relative order of these strings.
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (hasStyles) {
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return o.hasStyles ? 0 : -1;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (o.hasStyles) {
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return 1;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Sort unstyled strings by type, then by logical configuration.
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    int comp = configTypeName.compare(o.configTypeName);
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (comp != 0) {
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return comp;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const size_t LHN = configs.size();
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const size_t RHN = o.configs.size();
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    size_t i=0;
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    while (i < LHN && i < RHN) {
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        comp = configs[i].compareLogical(o.configs[i]);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (comp != 0) {
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            return comp;
9551b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt        }
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        i++;
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (LHN < RHN) return -1;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    else if (LHN > RHN) return 1;
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return 0;
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtStringPool::StringPool(bool utf8) :
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mUTF8(utf8), mValues(-1)
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        const String8* configTypeName, const ResTable_config* config)
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ssize_t res = add(value, false, configTypeName, config);
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (res >= 0) {
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        addStyleSpans(res, spans);
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return res;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtssize_t StringPool::add(const String16& value,
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ssize_t vidx = mValues.indexOfKey(value);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ssize_t pos = vidx >= 0 ? mValues.valueAt(vidx) : -1;
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ssize_t eidx = pos >= 0 ? mEntryArray.itemAt(pos) : -1;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (eidx < 0) {
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        eidx = mEntries.add(entry(value));
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (eidx < 0) {
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            fprintf(stderr, "Failure adding string %s\n", String8(value).string());
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            return eidx;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (configTypeName != NULL) {
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        entry& ent = mEntries.editItemAt(eidx);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        NOISY(printf("*** adding config type name %s, was %s\n",
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                configTypeName->string(), ent.configTypeName.string()));
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (ent.configTypeName.size() <= 0) {
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            ent.configTypeName = *configTypeName;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        } else if (ent.configTypeName != *configTypeName) {
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            ent.configTypeName = " ";
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (config != NULL) {
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // Add this to the set of configs associated with the string.
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        entry& ent = mEntries.editItemAt(eidx);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        size_t addPos;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        for (addPos=0; addPos<ent.configs.size(); addPos++) {
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (cmp >= 0) {
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (cmp > 0) {
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    NOISY(printf("*** inserting config: %s\n", config->toString().string()));
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    ent.configs.insertAt(*config, addPos);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                }
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                break;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (addPos >= ent.configs.size()) {
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            NOISY(printf("*** adding config: %s\n", config->toString().string()));
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            ent.configs.add(*config);
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const bool first = vidx < 0;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ?
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mEntryStyleArray[pos].spans.size() : 0;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (first || styled || !mergeDuplicates) {
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        pos = mEntryArray.add(eidx);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (first) {
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            vidx = mValues.add(value, pos);
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        entry& ent = mEntries.editItemAt(eidx);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ent.indices.add(pos);
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n",
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            String8(value).string(), pos, eidx, vidx));
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return pos;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatus_t StringPool::addStyleSpan(size_t idx, const String16& name,
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                  uint32_t start, uint32_t end)
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    entry_style_span span;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    span.name = name;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    span.span.firstChar = start;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    span.span.lastChar = end;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return addStyleSpan(idx, span);
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatus_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& spans)
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const size_t N=spans.size();
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<N; i++) {
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        status_t err = addStyleSpan(idx, spans[i]);
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (err != NO_ERROR) {
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            return err;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return NO_ERROR;
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatus_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span)
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Place blank entries in the span array up to this index.
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    while (mEntryStyleArray.size() <= idx) {
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mEntryStyleArray.add();
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    entry_style& style = mEntryStyleArray.editItemAt(idx);
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    style.spans.add(span);
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return NO_ERROR;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef __GLIBC__
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint StringPool::config_sort(const void* lhs, const void* rhs, void* state)
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint StringPool::config_sort(void* state, const void* lhs, const void* rhs)
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    StringPool* pool = (StringPool*)state;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]];
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]];
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return lhe.compare(rhe);
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid StringPool::sortByConfig()
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    const size_t N = mEntryArray.size();
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // This is a vector that starts out with a 1:1 mapping to entries
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // in the array, which we will sort to come up with the desired order.
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // At that point it maps from the new position in the array to the
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // original position the entry appeared.
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    Vector<size_t> newPosToOriginalPos;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    newPosToOriginalPos.setCapacity(N);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i < N; i++) {
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        newPosToOriginalPos.add(i);
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Sort the array.
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Vector::sort uses insertion sort, which is very slow for this data set.
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Use quicksort instead because we don't need a stable sort here.
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // For more fun, GLibC took qsort_r from BSD but then decided to swap the
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // order the last two parameters.
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef __GLIBC__
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    qsort_r(newPosToOriginalPos.editArray(), N, sizeof(size_t), config_sort, this);
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    qsort_r(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort);
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    //newPosToOriginalPos.sort(config_sort, this);
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Create the reverse mapping from the original position in the array
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // to the new position where it appears in the sorted array.  This is
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // so that clients can re-map any positions they had previously stored.
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mOriginalPosToNewPos = newPosToOriginalPos;
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<N; i++) {
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    SortedVector<entry> entries;
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<N; i++) {
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        entries.add(mEntries[mEntryArray[i]]);
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<entries.size(); i++) {
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        printf("Sorted config #%d: %s\n", i,
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                entries[i].makeConfigsString().string());
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Now we rebuild the arrays.
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    Vector<entry> newEntries;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    Vector<size_t> newEntryArray;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    Vector<entry_style> newEntryStyleArray;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<N; i++) {
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // We are filling in new offset 'i'; oldI is where we can find it
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // in the original data structure.
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        size_t oldI = newPosToOriginalPos[i];
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // This is the actual entry associated with the old offset.
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        const entry& oldEnt = mEntries[mEntryArray[oldI]];
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // This is the same entry the last time we added it to the
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // new entry array, if any.
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        size_t newOffset;
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (newIndexOfOffset < 0) {
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            // This is the first time we have seen the entry, so add
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            // it.
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            newOffset = newEntries.add(oldEnt);
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            newEntries.editItemAt(newOffset).indices.clear();
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        } else {
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            // We have seen this entry before, use the existing one
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            // instead of adding it again.
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // Update the indices to include this new position.
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        newEntries.editItemAt(newOffset).indices.add(i);
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // And add the offset of the entry to the new entry array.
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        newEntryArray.add(newOffset);
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // Add any old style to the new style array.
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (mEntryStyleArray.size() > 0) {
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (oldI < mEntryStyleArray.size()) {
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                newEntryStyleArray.add(mEntryStyleArray[oldI]);
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            } else {
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                newEntryStyleArray.add(entry_style());
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Now trim any entries at the end of the new style array that are
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // not needed.
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        const entry_style& style = newEntryStyleArray[i];
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (style.spans.size() > 0) {
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            // That's it.
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            break;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // This one is not needed; remove.
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        newEntryStyleArray.removeAt(i);
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // All done, install the new data structures and upate mValues with
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // the new positions.
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mEntries = newEntries;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mEntryArray = newEntryArray;
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mEntryStyleArray = newEntryStyleArray;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    mValues.clear();
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<mEntries.size(); i++) {
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        const entry& ent = mEntries[i];
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mValues.add(ent.value, ent.indices[0]);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    printf("FINAL SORTED STRING CONFIGS:\n");
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    for (size_t i=0; i<mEntries.size(); i++) {
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        const entry& ent = mEntries[i];
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                String8(ent.value).string());
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtsp<AaptFile> StringPool::createStringBlock()
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                     String8());
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    status_t err = writeStringBlock(pool);
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    return err == NO_ERROR ? pool : NULL;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define ENCODE_LENGTH(str, chrsz, strSize) \
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ \
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    size_t maxMask = 1 << ((chrsz*8)-1); \
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    size_t maxSize = maxMask-1; \
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    if (strSize > maxSize) { \
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        *str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    } \
369    *str++ = strSize; \
370}
371
372status_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
373{
374    // Allow appending.  Sorry this is a little wacky.
375    if (pool->getSize() > 0) {
376        sp<AaptFile> block = createStringBlock();
377        if (block == NULL) {
378            return UNKNOWN_ERROR;
379        }
380        ssize_t res = pool->writeData(block->getData(), block->getSize());
381        return (res >= 0) ? (status_t)NO_ERROR : res;
382    }
383
384    // First we need to add all style span names to the string pool.
385    // We do this now (instead of when the span is added) so that these
386    // will appear at the end of the pool, not disrupting the order
387    // our client placed their own strings in it.
388
389    const size_t STYLES = mEntryStyleArray.size();
390    size_t i;
391
392    for (i=0; i<STYLES; i++) {
393        entry_style& style = mEntryStyleArray.editItemAt(i);
394        const size_t N = style.spans.size();
395        for (size_t i=0; i<N; i++) {
396            entry_style_span& span = style.spans.editItemAt(i);
397            ssize_t idx = add(span.name, true);
398            if (idx < 0) {
399                fprintf(stderr, "Error adding span for style tag '%s'\n",
400                        String8(span.name).string());
401                return idx;
402            }
403            span.span.name.index = (uint32_t)idx;
404        }
405    }
406
407    const size_t ENTRIES = mEntryArray.size();
408
409    // Now build the pool of unique strings.
410
411    const size_t STRINGS = mEntries.size();
412    const size_t preSize = sizeof(ResStringPool_header)
413                         + (sizeof(uint32_t)*ENTRIES)
414                         + (sizeof(uint32_t)*STYLES);
415    if (pool->editData(preSize) == NULL) {
416        fprintf(stderr, "ERROR: Out of memory for string pool\n");
417        return NO_MEMORY;
418    }
419
420    const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t);
421
422    size_t strPos = 0;
423    for (i=0; i<STRINGS; i++) {
424        entry& ent = mEntries.editItemAt(i);
425        const size_t strSize = (ent.value.size());
426        const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ?
427            charSize*2 : charSize;
428
429        String8 encStr;
430        if (mUTF8) {
431            encStr = String8(ent.value);
432        }
433
434        const size_t encSize = mUTF8 ? encStr.size() : 0;
435        const size_t encLenSize = mUTF8 ?
436            (encSize > (size_t)(1<<((charSize*8)-1))-1 ?
437                charSize*2 : charSize) : 0;
438
439        ent.offset = strPos;
440
441        const size_t totalSize = lenSize + encLenSize +
442            ((mUTF8 ? encSize : strSize)+1)*charSize;
443
444        void* dat = (void*)pool->editData(preSize + strPos + totalSize);
445        if (dat == NULL) {
446            fprintf(stderr, "ERROR: Out of memory for string pool\n");
447            return NO_MEMORY;
448        }
449        dat = (uint8_t*)dat + preSize + strPos;
450        if (mUTF8) {
451            uint8_t* strings = (uint8_t*)dat;
452
453            ENCODE_LENGTH(strings, sizeof(uint8_t), strSize)
454
455            ENCODE_LENGTH(strings, sizeof(uint8_t), encSize)
456
457            strncpy((char*)strings, encStr, encSize+1);
458        } else {
459            uint16_t* strings = (uint16_t*)dat;
460
461            ENCODE_LENGTH(strings, sizeof(uint16_t), strSize)
462
463            strcpy16_htod(strings, ent.value);
464        }
465
466        strPos += totalSize;
467    }
468
469    // Pad ending string position up to a uint32_t boundary.
470
471    if (strPos&0x3) {
472        size_t padPos = ((strPos+3)&~0x3);
473        uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos);
474        if (dat == NULL) {
475            fprintf(stderr, "ERROR: Out of memory padding string pool\n");
476            return NO_MEMORY;
477        }
478        memset(dat+preSize+strPos, 0, padPos-strPos);
479        strPos = padPos;
480    }
481
482    // Build the pool of style spans.
483
484    size_t styPos = strPos;
485    for (i=0; i<STYLES; i++) {
486        entry_style& ent = mEntryStyleArray.editItemAt(i);
487        const size_t N = ent.spans.size();
488        const size_t totalSize = (N*sizeof(ResStringPool_span))
489                               + sizeof(ResStringPool_ref);
490
491        ent.offset = styPos-strPos;
492        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize);
493        if (dat == NULL) {
494            fprintf(stderr, "ERROR: Out of memory for string styles\n");
495            return NO_MEMORY;
496        }
497        ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos);
498        for (size_t i=0; i<N; i++) {
499            span->name.index = htodl(ent.spans[i].span.name.index);
500            span->firstChar = htodl(ent.spans[i].span.firstChar);
501            span->lastChar = htodl(ent.spans[i].span.lastChar);
502            span++;
503        }
504        span->name.index = htodl(ResStringPool_span::END);
505
506        styPos += totalSize;
507    }
508
509    if (STYLES > 0) {
510        // Add full terminator at the end (when reading we validate that
511        // the end of the pool is fully terminated to simplify error
512        // checking).
513        size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref);
514        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra);
515        if (dat == NULL) {
516            fprintf(stderr, "ERROR: Out of memory for string styles\n");
517            return NO_MEMORY;
518        }
519        uint32_t* p = (uint32_t*)(dat+preSize+styPos);
520        while (extra > 0) {
521            *p++ = htodl(ResStringPool_span::END);
522            extra -= sizeof(uint32_t);
523        }
524        styPos += extra;
525    }
526
527    // Write header.
528
529    ResStringPool_header* header =
530        (ResStringPool_header*)pool->padData(sizeof(uint32_t));
531    if (header == NULL) {
532        fprintf(stderr, "ERROR: Out of memory for string pool\n");
533        return NO_MEMORY;
534    }
535    memset(header, 0, sizeof(*header));
536    header->header.type = htods(RES_STRING_POOL_TYPE);
537    header->header.headerSize = htods(sizeof(*header));
538    header->header.size = htodl(pool->getSize());
539    header->stringCount = htodl(ENTRIES);
540    header->styleCount = htodl(STYLES);
541    if (mUTF8) {
542        header->flags |= htodl(ResStringPool_header::UTF8_FLAG);
543    }
544    header->stringsStart = htodl(preSize);
545    header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0);
546
547    // Write string index array.
548
549    uint32_t* index = (uint32_t*)(header+1);
550    for (i=0; i<ENTRIES; i++) {
551        entry& ent = mEntries.editItemAt(mEntryArray[i]);
552        *index++ = htodl(ent.offset);
553        NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i,
554                String8(ent.value).string(),
555                mEntryArray[i], ent.offset));
556    }
557
558    // Write style index array.
559
560    for (i=0; i<STYLES; i++) {
561        *index++ = htodl(mEntryStyleArray[i].offset);
562    }
563
564    return NO_ERROR;
565}
566
567ssize_t StringPool::offsetForString(const String16& val) const
568{
569    const Vector<size_t>* indices = offsetsForString(val);
570    ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
571    NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res,
572            res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8()));
573    return res;
574}
575
576const Vector<size_t>* StringPool::offsetsForString(const String16& val) const
577{
578    ssize_t pos = mValues.valueFor(val);
579    if (pos < 0) {
580        return NULL;
581    }
582    return &mEntries[mEntryArray[pos]].indices;
583}
584