19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Copyright 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Build resource files from raw assets.
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "StringPool.h"
86c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn#include "ResourceTable.h"
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/ByteOrder.h>
116c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn#include <utils/SortedVector.h>
12fe75d62eba3935d2d1a4a7790fc7459ded241ad3Jeff Brown#include <cutils/qsort_r_compat.h>
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael#if HAVE_PRINTF_ZD
15f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael#  define ZD "%zd"
16f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael#  define ZD_TYPE ssize_t
17f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael#else
18f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael#  define ZD "%ld"
19f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael#  define ZD_TYPE long
20f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael#endif
21f51125d8429ffa71c57ba6fbdca9effc72642a9bRaphael
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define NOISY(x) //x
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid strcpy16_htod(uint16_t* dst, const uint16_t* src)
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (*src) {
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char16_t s = htods(*src);
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *dst++ = s;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        src++;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *dst = 0;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid printStringPool(const ResStringPool* pool)
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
366c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    SortedVector<const void*> uniqueStrings;
376c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    const size_t N = pool->size();
386c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (size_t i=0; i<N; i++) {
396c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        size_t len;
406c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        if (pool->isUTF8()) {
416c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            uniqueStrings.add(pool->string8At(i, &len));
426c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        } else {
436c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            uniqueStrings.add(pool->stringAt(i, &len));
446c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
456c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
466c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
476c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
486c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            ZD " styles using " ZD " bytes:\n",
496c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
506c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            pool->isSorted() ? "sorted" : "non-sorted",
516c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
526c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const size_t NS = pool->size();
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (size_t s=0; s<NS; s++) {
556c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        String8 str = pool->string8ObjectAt(s);
566c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
576c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
586c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn}
596c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
606c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne HackbornString8 StringPool::entry::makeConfigsString() const {
616c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    String8 configStr(configTypeName);
626c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (configStr.size() > 0) configStr.append(" ");
636c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (configs.size() > 0) {
646c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        for (size_t j=0; j<configs.size(); j++) {
656c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            if (j > 0) configStr.append(", ");
666c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            configStr.append(configs[j].toString());
67780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root        }
686c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    } else {
696c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        configStr = "(none)";
706c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
716c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    return configStr;
726c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn}
73780d2a1b714724d85227141c76b3c64f543f00b4Kenny Root
746c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackbornint StringPool::entry::compare(const entry& o) const {
7561361f376b47d45966b1ca0d24d51622304c93c3Jeff Brown    // Strings with styles go first, to reduce the size of the styles array.
7661361f376b47d45966b1ca0d24d51622304c93c3Jeff Brown    // We don't care about the relative order of these strings.
776c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (hasStyles) {
786c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        return o.hasStyles ? 0 : -1;
796c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
806c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (o.hasStyles) {
816c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        return 1;
826c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
8361361f376b47d45966b1ca0d24d51622304c93c3Jeff Brown
8461361f376b47d45966b1ca0d24d51622304c93c3Jeff Brown    // Sort unstyled strings by type, then by logical configuration.
856c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    int comp = configTypeName.compare(o.configTypeName);
866c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (comp != 0) {
876c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        return comp;
886c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
896c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    const size_t LHN = configs.size();
906c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    const size_t RHN = o.configs.size();
916c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    size_t i=0;
926c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    while (i < LHN && i < RHN) {
936c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        comp = configs[i].compareLogical(o.configs[i]);
946c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        if (comp != 0) {
956c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            return comp;
966c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
976c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        i++;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
996c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (LHN < RHN) return -1;
1006c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    else if (LHN > RHN) return 1;
1016c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    return 0;
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
104345b7eb8749d6954942fd4e961fff9f2f854934cJeff BrownStringPool::StringPool(bool utf8) :
105345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown        mUTF8(utf8), mValues(-1)
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1096c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackbornssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
1106c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        const String8* configTypeName, const ResTable_config* config)
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
112345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown    ssize_t res = add(value, false, configTypeName, config);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (res >= 0) {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addStyleSpans(res, spans);
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return res;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
119345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brownssize_t StringPool::add(const String16& value,
1206c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ssize_t vidx = mValues.indexOfKey(value);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ssize_t pos = vidx >= 0 ? mValues.valueAt(vidx) : -1;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ssize_t eidx = pos >= 0 ? mEntryArray.itemAt(pos) : -1;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (eidx < 0) {
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        eidx = mEntries.add(entry(value));
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (eidx < 0) {
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fprintf(stderr, "Failure adding string %s\n", String8(value).string());
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return eidx;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1336c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (configTypeName != NULL) {
1346c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        entry& ent = mEntries.editItemAt(eidx);
1356c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        NOISY(printf("*** adding config type name %s, was %s\n",
1366c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                configTypeName->string(), ent.configTypeName.string()));
1376c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        if (ent.configTypeName.size() <= 0) {
1386c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            ent.configTypeName = *configTypeName;
1396c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        } else if (ent.configTypeName != *configTypeName) {
1406c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            ent.configTypeName = " ";
1416c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
1426c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
1436c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
1446c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    if (config != NULL) {
1456c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // Add this to the set of configs associated with the string.
1466c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        entry& ent = mEntries.editItemAt(eidx);
1476c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        size_t addPos;
1486c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        for (addPos=0; addPos<ent.configs.size(); addPos++) {
1496c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
1506c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            if (cmp >= 0) {
1516c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                if (cmp > 0) {
1526c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                    NOISY(printf("*** inserting config: %s\n", config->toString().string()));
1536c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                    ent.configs.insertAt(*config, addPos);
1546c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                }
1556c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                break;
1566c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            }
1576c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
1586c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        if (addPos >= ent.configs.size()) {
1596c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            NOISY(printf("*** adding config: %s\n", config->toString().string()));
1606c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            ent.configs.add(*config);
1616c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
1626c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
1636c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const bool first = vidx < 0;
165db6e67d8ec081f43bcf14155741e268a38915719Ben Gruver    const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ?
166db6e67d8ec081f43bcf14155741e268a38915719Ben Gruver        mEntryStyleArray[pos].spans.size() : 0;
167db6e67d8ec081f43bcf14155741e268a38915719Ben Gruver    if (first || styled || !mergeDuplicates) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pos = mEntryArray.add(eidx);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (first) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            vidx = mValues.add(value, pos);
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
172345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown        entry& ent = mEntries.editItemAt(eidx);
173345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown        ent.indices.add(pos);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n",
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String8(value).string(), pos, eidx, vidx));
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return pos;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t StringPool::addStyleSpan(size_t idx, const String16& name,
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                  uint32_t start, uint32_t end)
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    entry_style_span span;
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    span.name = name;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    span.span.firstChar = start;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    span.span.lastChar = end;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return addStyleSpan(idx, span);
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& spans)
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const size_t N=spans.size();
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (size_t i=0; i<N; i++) {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        status_t err = addStyleSpan(idx, spans[i]);
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != NO_ERROR) {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return err;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span)
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Place blank entries in the span array up to this index.
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (mEntryStyleArray.size() <= idx) {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntryStyleArray.add();
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    entry_style& style = mEntryStyleArray.editItemAt(idx);
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    style.spans.add(span);
2136c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
217c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brownint StringPool::config_sort(void* state, const void* lhs, const void* rhs)
2186c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn{
2196c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    StringPool* pool = (StringPool*)state;
220c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brown    const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]];
221c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brown    const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]];
2226c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    return lhe.compare(rhe);
2236c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn}
2246c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2256c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackbornvoid StringPool::sortByConfig()
2266c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn{
2276c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
2286c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2296c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    const size_t N = mEntryArray.size();
2306c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2316c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // This is a vector that starts out with a 1:1 mapping to entries
2326c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // in the array, which we will sort to come up with the desired order.
2336c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // At that point it maps from the new position in the array to the
2346c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // original position the entry appeared.
2356c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    Vector<size_t> newPosToOriginalPos;
236c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brown    newPosToOriginalPos.setCapacity(N);
237c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brown    for (size_t i=0; i < N; i++) {
2386c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        newPosToOriginalPos.add(i);
2396c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
2406c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2416c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // Sort the array.
2426c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
243c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brown    // Vector::sort uses insertion sort, which is very slow for this data set.
244c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brown    // Use quicksort instead because we don't need a stable sort here.
245fe75d62eba3935d2d1a4a7790fc7459ded241ad3Jeff Brown    qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort);
246c9fd9263feedac32e4f5b1f13a3246347efdc25fJeff Brown    //newPosToOriginalPos.sort(config_sort, this);
2476c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
2486c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2496c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // Create the reverse mapping from the original position in the array
2506c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // to the new position where it appears in the sorted array.  This is
2516c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // so that clients can re-map any positions they had previously stored.
2526c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    mOriginalPosToNewPos = newPosToOriginalPos;
2536c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (size_t i=0; i<N; i++) {
2546c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
2556c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
2566c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2576c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn#if 0
2586c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    SortedVector<entry> entries;
2596c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2606c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (size_t i=0; i<N; i++) {
2616c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
2626c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
2636c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        entries.add(mEntries[mEntryArray[i]]);
2646c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
2656c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2666c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (size_t i=0; i<entries.size(); i++) {
2676c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        printf("Sorted config #%d: %s\n", i,
2686c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                entries[i].makeConfigsString().string());
2696c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
2706c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn#endif
2716c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2726c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // Now we rebuild the arrays.
2736c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    Vector<entry> newEntries;
2746c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    Vector<size_t> newEntryArray;
2756c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    Vector<entry_style> newEntryStyleArray;
2766c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
2776c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
2786c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (size_t i=0; i<N; i++) {
2796c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // We are filling in new offset 'i'; oldI is where we can find it
2806c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // in the original data structure.
2816c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        size_t oldI = newPosToOriginalPos[i];
2826c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // This is the actual entry associated with the old offset.
2836c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        const entry& oldEnt = mEntries[mEntryArray[oldI]];
2846c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // This is the same entry the last time we added it to the
2856c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // new entry array, if any.
2866c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
2876c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        size_t newOffset;
2886c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        if (newIndexOfOffset < 0) {
2896c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            // This is the first time we have seen the entry, so add
2906c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            // it.
2916c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            newOffset = newEntries.add(oldEnt);
2926c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            newEntries.editItemAt(newOffset).indices.clear();
2936c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        } else {
2946c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            // We have seen this entry before, use the existing one
2956c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            // instead of adding it again.
2966c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
2976c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
2986c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // Update the indices to include this new position.
2996c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        newEntries.editItemAt(newOffset).indices.add(i);
3006c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // And add the offset of the entry to the new entry array.
3016c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        newEntryArray.add(newOffset);
3026c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // Add any old style to the new style array.
3036c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        if (mEntryStyleArray.size() > 0) {
3046c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            if (oldI < mEntryStyleArray.size()) {
3056c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                newEntryStyleArray.add(mEntryStyleArray[oldI]);
3066c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            } else {
3076c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                newEntryStyleArray.add(entry_style());
3086c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            }
3096c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
3106c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
3116c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
3126c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // Now trim any entries at the end of the new style array that are
3136c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // not needed.
3146c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
3156c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        const entry_style& style = newEntryStyleArray[i];
3166c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        if (style.spans.size() > 0) {
3176c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            // That's it.
3186c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn            break;
3196c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        }
3206c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        // This one is not needed; remove.
3216c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        newEntryStyleArray.removeAt(i);
3226c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
3236c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
3246c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // All done, install the new data structures and upate mValues with
3256c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    // the new positions.
3266c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    mEntries = newEntries;
3276c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    mEntryArray = newEntryArray;
3286c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    mEntryStyleArray = newEntryStyleArray;
3296c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    mValues.clear();
3306c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (size_t i=0; i<mEntries.size(); i++) {
3316c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        const entry& ent = mEntries[i];
3326c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        mValues.add(ent.value, ent.indices[0]);
3336c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
3346c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
3356c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn#if 0
3366c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    printf("FINAL SORTED STRING CONFIGS:\n");
3376c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    for (size_t i=0; i<mEntries.size(); i++) {
3386c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        const entry& ent = mEntries[i];
3396c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
3406c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn                String8(ent.value).string());
3416c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn    }
3426c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn#endif
3436c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn}
3446c997a9e880e08c354ffd809bd62df9e25e9c4d4Dianne Hackborn
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectsp<AaptFile> StringPool::createStringBlock()
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     String8());
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t err = writeStringBlock(pool);
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return err == NO_ERROR ? pool : NULL;
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35319138468caf7050d482dc15f35a344eab11bb756Kenny Root#define ENCODE_LENGTH(str, chrsz, strSize) \
35419138468caf7050d482dc15f35a344eab11bb756Kenny Root{ \
35519138468caf7050d482dc15f35a344eab11bb756Kenny Root    size_t maxMask = 1 << ((chrsz*8)-1); \
35619138468caf7050d482dc15f35a344eab11bb756Kenny Root    size_t maxSize = maxMask-1; \
35719138468caf7050d482dc15f35a344eab11bb756Kenny Root    if (strSize > maxSize) { \
35819138468caf7050d482dc15f35a344eab11bb756Kenny Root        *str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \
35919138468caf7050d482dc15f35a344eab11bb756Kenny Root    } \
36019138468caf7050d482dc15f35a344eab11bb756Kenny Root    *str++ = strSize; \
36119138468caf7050d482dc15f35a344eab11bb756Kenny Root}
36219138468caf7050d482dc15f35a344eab11bb756Kenny Root
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Allow appending.  Sorry this is a little wacky.
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pool->getSize() > 0) {
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sp<AaptFile> block = createStringBlock();
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (block == NULL) {
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return UNKNOWN_ERROR;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ssize_t res = pool->writeData(block->getData(), block->getSize());
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (res >= 0) ? (status_t)NO_ERROR : res;
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // First we need to add all style span names to the string pool.
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // We do this now (instead of when the span is added) so that these
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // will appear at the end of the pool, not disrupting the order
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // our client placed their own strings in it.
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const size_t STYLES = mEntryStyleArray.size();
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t i;
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i=0; i<STYLES; i++) {
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        entry_style& style = mEntryStyleArray.editItemAt(i);
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const size_t N = style.spans.size();
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (size_t i=0; i<N; i++) {
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            entry_style_span& span = style.spans.editItemAt(i);
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ssize_t idx = add(span.name, true);
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (idx < 0) {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fprintf(stderr, "Error adding span for style tag '%s'\n",
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        String8(span.name).string());
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return idx;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            span.span.name.index = (uint32_t)idx;
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
398345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown    const size_t ENTRIES = mEntryArray.size();
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Now build the pool of unique strings.
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const size_t STRINGS = mEntries.size();
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const size_t preSize = sizeof(ResStringPool_header)
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         + (sizeof(uint32_t)*ENTRIES)
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         + (sizeof(uint32_t)*STYLES);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pool->editData(preSize) == NULL) {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fprintf(stderr, "ERROR: Out of memory for string pool\n");
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NO_MEMORY;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41119138468caf7050d482dc15f35a344eab11bb756Kenny Root    const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t);
41219138468caf7050d482dc15f35a344eab11bb756Kenny Root
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t strPos = 0;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i=0; i<STRINGS; i++) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        entry& ent = mEntries.editItemAt(i);
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const size_t strSize = (ent.value.size());
41719138468caf7050d482dc15f35a344eab11bb756Kenny Root        const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ?
41819138468caf7050d482dc15f35a344eab11bb756Kenny Root            charSize*2 : charSize;
41919138468caf7050d482dc15f35a344eab11bb756Kenny Root
42019138468caf7050d482dc15f35a344eab11bb756Kenny Root        String8 encStr;
42119138468caf7050d482dc15f35a344eab11bb756Kenny Root        if (mUTF8) {
42219138468caf7050d482dc15f35a344eab11bb756Kenny Root            encStr = String8(ent.value);
42319138468caf7050d482dc15f35a344eab11bb756Kenny Root        }
42419138468caf7050d482dc15f35a344eab11bb756Kenny Root
42519138468caf7050d482dc15f35a344eab11bb756Kenny Root        const size_t encSize = mUTF8 ? encStr.size() : 0;
42619138468caf7050d482dc15f35a344eab11bb756Kenny Root        const size_t encLenSize = mUTF8 ?
42719138468caf7050d482dc15f35a344eab11bb756Kenny Root            (encSize > (size_t)(1<<((charSize*8)-1))-1 ?
42819138468caf7050d482dc15f35a344eab11bb756Kenny Root                charSize*2 : charSize) : 0;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ent.offset = strPos;
43119138468caf7050d482dc15f35a344eab11bb756Kenny Root
43219138468caf7050d482dc15f35a344eab11bb756Kenny Root        const size_t totalSize = lenSize + encLenSize +
43319138468caf7050d482dc15f35a344eab11bb756Kenny Root            ((mUTF8 ? encSize : strSize)+1)*charSize;
43419138468caf7050d482dc15f35a344eab11bb756Kenny Root
43519138468caf7050d482dc15f35a344eab11bb756Kenny Root        void* dat = (void*)pool->editData(preSize + strPos + totalSize);
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dat == NULL) {
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fprintf(stderr, "ERROR: Out of memory for string pool\n");
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return NO_MEMORY;
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
44019138468caf7050d482dc15f35a344eab11bb756Kenny Root        dat = (uint8_t*)dat + preSize + strPos;
44119138468caf7050d482dc15f35a344eab11bb756Kenny Root        if (mUTF8) {
44219138468caf7050d482dc15f35a344eab11bb756Kenny Root            uint8_t* strings = (uint8_t*)dat;
44319138468caf7050d482dc15f35a344eab11bb756Kenny Root
44419138468caf7050d482dc15f35a344eab11bb756Kenny Root            ENCODE_LENGTH(strings, sizeof(uint8_t), strSize)
44519138468caf7050d482dc15f35a344eab11bb756Kenny Root
44619138468caf7050d482dc15f35a344eab11bb756Kenny Root            ENCODE_LENGTH(strings, sizeof(uint8_t), encSize)
44719138468caf7050d482dc15f35a344eab11bb756Kenny Root
44819138468caf7050d482dc15f35a344eab11bb756Kenny Root            strncpy((char*)strings, encStr, encSize+1);
44919138468caf7050d482dc15f35a344eab11bb756Kenny Root        } else {
45019138468caf7050d482dc15f35a344eab11bb756Kenny Root            uint16_t* strings = (uint16_t*)dat;
45119138468caf7050d482dc15f35a344eab11bb756Kenny Root
45219138468caf7050d482dc15f35a344eab11bb756Kenny Root            ENCODE_LENGTH(strings, sizeof(uint16_t), strSize)
45319138468caf7050d482dc15f35a344eab11bb756Kenny Root
45419138468caf7050d482dc15f35a344eab11bb756Kenny Root            strcpy16_htod(strings, ent.value);
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
45719138468caf7050d482dc15f35a344eab11bb756Kenny Root        strPos += totalSize;
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Pad ending string position up to a uint32_t boundary.
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (strPos&0x3) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        size_t padPos = ((strPos+3)&~0x3);
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dat == NULL) {
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fprintf(stderr, "ERROR: Out of memory padding string pool\n");
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return NO_MEMORY;
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memset(dat+preSize+strPos, 0, padPos-strPos);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        strPos = padPos;
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Build the pool of style spans.
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t styPos = strPos;
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i=0; i<STYLES; i++) {
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        entry_style& ent = mEntryStyleArray.editItemAt(i);
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const size_t N = ent.spans.size();
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const size_t totalSize = (N*sizeof(ResStringPool_span))
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                               + sizeof(ResStringPool_ref);
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ent.offset = styPos-strPos;
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize);
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dat == NULL) {
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fprintf(stderr, "ERROR: Out of memory for string styles\n");
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return NO_MEMORY;
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos);
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (size_t i=0; i<N; i++) {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            span->name.index = htodl(ent.spans[i].span.name.index);
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            span->firstChar = htodl(ent.spans[i].span.firstChar);
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            span->lastChar = htodl(ent.spans[i].span.lastChar);
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            span++;
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        span->name.index = htodl(ResStringPool_span::END);
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        styPos += totalSize;
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (STYLES > 0) {
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Add full terminator at the end (when reading we validate that
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the end of the pool is fully terminated to simplify error
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // checking).
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref);
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra);
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dat == NULL) {
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fprintf(stderr, "ERROR: Out of memory for string styles\n");
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return NO_MEMORY;
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uint32_t* p = (uint32_t*)(dat+preSize+styPos);
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (extra > 0) {
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            *p++ = htodl(ResStringPool_span::END);
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extra -= sizeof(uint32_t);
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        styPos += extra;
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Write header.
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ResStringPool_header* header =
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        (ResStringPool_header*)pool->padData(sizeof(uint32_t));
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (header == NULL) {
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fprintf(stderr, "ERROR: Out of memory for string pool\n");
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NO_MEMORY;
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(header, 0, sizeof(*header));
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    header->header.type = htods(RES_STRING_POOL_TYPE);
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    header->header.headerSize = htods(sizeof(*header));
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    header->header.size = htodl(pool->getSize());
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    header->stringCount = htodl(ENTRIES);
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    header->styleCount = htodl(STYLES);
53219138468caf7050d482dc15f35a344eab11bb756Kenny Root    if (mUTF8) {
53319138468caf7050d482dc15f35a344eab11bb756Kenny Root        header->flags |= htodl(ResStringPool_header::UTF8_FLAG);
53419138468caf7050d482dc15f35a344eab11bb756Kenny Root    }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    header->stringsStart = htodl(preSize);
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0);
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Write string index array.
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint32_t* index = (uint32_t*)(header+1);
541345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown    for (i=0; i<ENTRIES; i++) {
542345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown        entry& ent = mEntries.editItemAt(mEntryArray[i]);
543345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown        *index++ = htodl(ent.offset);
544345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown        NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i,
545345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown                String8(ent.value).string(),
546345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown                mEntryArray[i], ent.offset));
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Write style index array.
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
551345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown    for (i=0; i<STYLES; i++) {
552345b7eb8749d6954942fd4e961fff9f2f854934cJeff Brown        *index++ = htodl(mEntryStyleArray[i].offset);
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectssize_t StringPool::offsetForString(const String16& val) const
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const Vector<size_t>* indices = offsetsForString(val);
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res,
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8()));
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return res;
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectconst Vector<size_t>* StringPool::offsetsForString(const String16& val) const
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ssize_t pos = mValues.valueFor(val);
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pos < 0) {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return &mEntries[mEntryArray[pos]].indices;
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
575