StringPool.cpp revision 345b7eb8749d6954942fd4e961fff9f2f854934c
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Copyright 2006 The Android Open Source Project 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Build resource files from raw assets. 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "StringPool.h" 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "ResourceTable.h" 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org#include <utils/ByteOrder.h> 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <utils/SortedVector.h> 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com#if HAVE_PRINTF_ZD 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com# define ZD "%zd" 150456e0b7b85060e9b9597ce414c4c2b19aff4f58robertphillips@google.com# define ZD_TYPE ssize_t 160456e0b7b85060e9b9597ce414c4c2b19aff4f58robertphillips@google.com#else 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com# define ZD "%ld" 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com# define ZD_TYPE long 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define NOISY(x) //x 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid strcpy16_htod(uint16_t* dst, const uint16_t* src) 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 252b2ede3e713065e1bac461787b0aafb03eaf871fdjsollen@google.com while (*src) { 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com char16_t s = htods(*src); 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *dst++ = s; 288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com src++; 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *dst = 0; 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid printStringPool(const ResStringPool* pool) 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SortedVector<const void*> uniqueStrings; 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const size_t N = pool->size(); 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i=0; i<N; i++) { 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size_t len; 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (pool->isUTF8()) { 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uniqueStrings.add(pool->string8At(i, &len)); 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uniqueStrings.add(pool->stringAt(i, &len)); 438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4654924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com printf("String pool of " ZD " unique %s %s strings, " ZD " entries and " 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ZD " styles using " ZD " bytes:\n", 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16", 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pool->isSorted() ? "sorted" : "non-sorted", 502b2ede3e713065e1bac461787b0aafb03eaf871fdjsollen@google.com (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes()); 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const size_t NS = pool->size(); 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t s=0; s<NS; s++) { 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com String8 str = pool->string8ObjectAt(s); 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string()); 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comString8 StringPool::entry::makeConfigsString() const { 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com String8 configStr(configTypeName); 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (configStr.size() > 0) configStr.append(" "); 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (configs.size() > 0) { 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t j=0; j<configs.size(); j++) { 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (j > 0) configStr.append(", "); 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com configStr.append(configs[j].toString()); 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com configStr = "(none)"; 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return configStr; 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint StringPool::entry::compare(const entry& o) const { 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Strings with styles go first, to reduce the size of the 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // styles array. 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (hasStyles) { 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return o.hasStyles ? 0 : -1; 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (o.hasStyles) { 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 1; 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int comp = configTypeName.compare(o.configTypeName); 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (comp != 0) { 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return comp; 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const size_t LHN = configs.size(); 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const size_t RHN = o.configs.size(); 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size_t i=0; 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while (i < LHN && i < RHN) { 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com comp = configs[i].compareLogical(o.configs[i]); 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (comp != 0) { 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return comp; 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com i++; 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (LHN < RHN) return -1; 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com else if (LHN > RHN) return 1; 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comStringPool::StringPool(bool utf8) : 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mUTF8(utf8), mValues(-1) 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans, 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const String8* configTypeName, const ResTable_config* config) 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ssize_t res = add(value, false, configTypeName, config); 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (res >= 0) { 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com addStyleSpans(res, spans); 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1130c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com return res; 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comssize_t StringPool::add(const String16& value, 1177c2f27d788fff9dbf66a6d52753e47f786a313c0reed@google.com bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config) 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ssize_t vidx = mValues.indexOfKey(value); 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ssize_t pos = vidx >= 0 ? mValues.valueAt(vidx) : -1; 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ssize_t eidx = pos >= 0 ? mEntryArray.itemAt(pos) : -1; 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (eidx < 0) { 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com eidx = mEntries.add(entry(value)); 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (eidx < 0) { 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fprintf(stderr, "Failure adding string %s\n", String8(value).string()); 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return eidx; 1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (configTypeName != NULL) { 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com entry& ent = mEntries.editItemAt(eidx); 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com NOISY(printf("*** adding config type name %s, was %s\n", 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com configTypeName->string(), ent.configTypeName.string())); 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (ent.configTypeName.size() <= 0) { 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ent.configTypeName = *configTypeName; 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else if (ent.configTypeName != *configTypeName) { 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ent.configTypeName = " "; 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (config != NULL) { 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Add this to the set of configs associated with the string. 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com entry& ent = mEntries.editItemAt(eidx); 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size_t addPos; 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (addPos=0; addPos<ent.configs.size(); addPos++) { 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int cmp = ent.configs.itemAt(addPos).compareLogical(*config); 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (cmp >= 0) { 1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (cmp > 0) { 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com NOISY(printf("*** inserting config: %s\n", config->toString().string())); 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ent.configs.insertAt(*config, addPos); 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (addPos >= ent.configs.size()) { 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com NOISY(printf("*** adding config: %s\n", config->toString().string())); 1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ent.configs.add(*config); 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const bool first = vidx < 0; 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ? 1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mEntryStyleArray[pos].spans.size() : 0; 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (first || styled || !mergeDuplicates) { 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pos = mEntryArray.add(eidx); 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (first) { 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com vidx = mValues.add(value, pos); 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com entry& ent = mEntries.editItemAt(eidx); 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ent.indices.add(pos); 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n", 1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com String8(value).string(), pos, eidx, vidx)); 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return pos; 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatus_t StringPool::addStyleSpan(size_t idx, const String16& name, 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t start, uint32_t end) 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1828d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com entry_style_span span; 1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com span.name = name; 1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com span.span.firstChar = start; 1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com span.span.lastChar = end; 1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return addStyleSpan(idx, span); 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatus_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& spans) 1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const size_t N=spans.size(); 1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i=0; i<N; i++) { 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com status_t err = addStyleSpan(idx, spans[i]); 194d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org if (err != NO_ERROR) { 1957c2f27d788fff9dbf66a6d52753e47f786a313c0reed@google.com return err; 196f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return NO_ERROR; 199d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org} 200d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org 201d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.orgstatus_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span) 202d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org{ 20303c1c359b336ad20d23ab07004cdafafd14c90a5rileya@google.com // Place blank entries in the span array up to this index. 20403c1c359b336ad20d23ab07004cdafafd14c90a5rileya@google.com while (mEntryStyleArray.size() <= idx) { 20503c1c359b336ad20d23ab07004cdafafd14c90a5rileya@google.com mEntryStyleArray.add(); 20603c1c359b336ad20d23ab07004cdafafd14c90a5rileya@google.com } 20703c1c359b336ad20d23ab07004cdafafd14c90a5rileya@google.com 2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com entry_style& style = mEntryStyleArray.editItemAt(idx); 2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com style.spans.add(span); 2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mEntries.editItemAt(mEntryArray[idx]).hasStyles = true; 2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return NO_ERROR; 2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint StringPool::config_sort(const size_t* lhs, const size_t* rhs, void* state) 2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com StringPool* pool = (StringPool*)state; 2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const entry& lhe = pool->mEntries[pool->mEntryArray[*lhs]]; 218f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com const entry& rhe = pool->mEntries[pool->mEntryArray[*rhs]]; 219f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com return lhe.compare(rhe); 220f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com} 221f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com 222f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid StringPool::sortByConfig() 223f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com{ 224f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted."); 225f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com 226f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com const size_t N = mEntryArray.size(); 227f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com 228f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com // This is a vector that starts out with a 1:1 mapping to entries 2292be9e8b407624fa696854b78b407b97a01dbb703reed@google.com // in the array, which we will sort to come up with the desired order. 230f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com // At that point it maps from the new position in the array to the 231b6e161937bc890f0aa12ac5e27415d4d260ea6e0junov@chromium.org // original position the entry appeared. 232b6e161937bc890f0aa12ac5e27415d4d260ea6e0junov@chromium.org Vector<size_t> newPosToOriginalPos; 233b6e161937bc890f0aa12ac5e27415d4d260ea6e0junov@chromium.org for (size_t i=0; i<mEntryArray.size(); i++) { 234b6e161937bc890f0aa12ac5e27415d4d260ea6e0junov@chromium.org newPosToOriginalPos.add(i); 235b6e161937bc890f0aa12ac5e27415d4d260ea6e0junov@chromium.org } 236b6e161937bc890f0aa12ac5e27415d4d260ea6e0junov@chromium.org 237b6e161937bc890f0aa12ac5e27415d4d260ea6e0junov@chromium.org // Sort the array. 2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n")); 2395119bdb952025a30f115b9c6a187173956e55097reed@android.com newPosToOriginalPos.sort(config_sort, this); 240f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n")); 241f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com 2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Create the reverse mapping from the original position in the array 2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // to the new position where it appears in the sorted array. This is 2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // so that clients can re-map any positions they had previously stored. 2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mOriginalPosToNewPos = newPosToOriginalPos; 2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i=0; i<N; i++) { 2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i; 24854924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com } 2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0 2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SortedVector<entry> entries; 2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i=0; i<N; i++) { 2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com printf("#%d was %d: %s\n", i, newPosToOriginalPos[i], 2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string()); 2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com entries.add(mEntries[mEntryArray[i]]); 25759ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com } 25859ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com 25959ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com for (size_t i=0; i<entries.size(); i++) { 26059ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com printf("Sorted config #%d: %s\n", i, 2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com entries[i].makeConfigsString().string()); 2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Now we rebuild the arrays. 2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Vector<entry> newEntries; 2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Vector<size_t> newEntryArray; 2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Vector<entry_style> newEntryStyleArray; 2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset; 2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i=0; i<N; i++) { 272d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org // We are filling in new offset 'i'; oldI is where we can find it 2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // in the original data structure. 274d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org size_t oldI = newPosToOriginalPos[i]; 275d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org // This is the actual entry associated with the old offset. 2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const entry& oldEnt = mEntries[mEntryArray[oldI]]; 277d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org // This is the same entry the last time we added it to the 2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // new entry array, if any. 2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI); 280d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org size_t newOffset; 281d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org if (newIndexOfOffset < 0) { 282d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org // This is the first time we have seen the entry, so add 2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // it. 2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newOffset = newEntries.add(oldEnt); 2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newEntries.editItemAt(newOffset).indices.clear(); 2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // We have seen this entry before, use the existing one 2888f073382bb6a9b3998a74e6b58654476b77b4c86reed@android.com // instead of adding it again. 2898f073382bb6a9b3998a74e6b58654476b77b4c86reed@android.com newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset); 2908f073382bb6a9b3998a74e6b58654476b77b4c86reed@android.com } 2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Update the indices to include this new position. 2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newEntries.editItemAt(newOffset).indices.add(i); 2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // And add the offset of the entry to the new entry array. 2948f073382bb6a9b3998a74e6b58654476b77b4c86reed@android.com newEntryArray.add(newOffset); 2955b81535014f545f6498f5c8721723b81576989b1reed@android.com // Add any old style to the new style array. 2965119bdb952025a30f115b9c6a187173956e55097reed@android.com if (mEntryStyleArray.size() > 0) { 2975b81535014f545f6498f5c8721723b81576989b1reed@android.com if (oldI < mEntryStyleArray.size()) { 2985b81535014f545f6498f5c8721723b81576989b1reed@android.com newEntryStyleArray.add(mEntryStyleArray[oldI]); 2995b81535014f545f6498f5c8721723b81576989b1reed@android.com } else { 3005119bdb952025a30f115b9c6a187173956e55097reed@android.com newEntryStyleArray.add(entry_style()); 3015119bdb952025a30f115b9c6a187173956e55097reed@android.com } 3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Now trim any entries at the end of the new style array that are 3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // not needed. 3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) { 3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const entry_style& style = newEntryStyleArray[i]; 3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (style.spans.size() > 0) { 3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // That's it. 3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // This one is not needed; remove. 3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com newEntryStyleArray.removeAt(i); 3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 317f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com // All done, install the new data structures and upate mValues with 318f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com // the new positions. 3197c2f27d788fff9dbf66a6d52753e47f786a313c0reed@google.com mEntries = newEntries; 3208cad58624bc194390b14a21d0578dfcdd6fbad6freed@google.com mEntryArray = newEntryArray; 3212be9e8b407624fa696854b78b407b97a01dbb703reed@google.com mEntryStyleArray = newEntryStyleArray; 322f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com mValues.clear(); 323f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com for (size_t i=0; i<mEntries.size(); i++) { 324d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org const entry& ent = mEntries[i]; 325d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org mValues.add(ent.value, ent.indices[0]); 326d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org } 327d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org 328d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org#if 0 329d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org printf("FINAL SORTED STRING CONFIGS:\n"); 330d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org for (size_t i=0; i<mEntries.size(); i++) { 331d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org const entry& ent = mEntries[i]; 332d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(), 333d3ae77965e94e0efda496f5461cbec4533cb5b16vandebo@chromium.org String8(ent.value).string()); 33437a201231b8f6381938282675eb9abb50ab3b389reed@google.com } 335a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com#endif 336a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com} 33737a201231b8f6381938282675eb9abb50ab3b389reed@google.com 33837a201231b8f6381938282675eb9abb50ab3b389reed@google.comsp<AaptFile> StringPool::createStringBlock() 33937a201231b8f6381938282675eb9abb50ab3b389reed@google.com{ 34037a201231b8f6381938282675eb9abb50ab3b389reed@google.com sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(), 34137a201231b8f6381938282675eb9abb50ab3b389reed@google.com String8()); 34237a201231b8f6381938282675eb9abb50ab3b389reed@google.com status_t err = writeStringBlock(pool); 34359ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com return err == NO_ERROR ? pool : NULL; 34459ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com} 34559ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com 34659ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com#define ENCODE_LENGTH(str, chrsz, strSize) \ 34759ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com{ \ 3480c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com size_t maxMask = 1 << ((chrsz*8)-1); \ 34959ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com size_t maxSize = maxMask-1; \ 35059ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com if (strSize > maxSize) { \ 35159ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com *str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \ 3520c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com } \ 35359ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com *str++ = strSize; \ 35459ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com} 35559ccef695cef28a74ab2ea13d5a6c9017af45402reed@google.com 3560c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.comstatus_t StringPool::writeStringBlock(const sp<AaptFile>& pool) 35737a201231b8f6381938282675eb9abb50ab3b389reed@google.com{ 35837a201231b8f6381938282675eb9abb50ab3b389reed@google.com // Allow appending. Sorry this is a little wacky. 359a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com if (pool->getSize() > 0) { 360 sp<AaptFile> block = createStringBlock(); 361 if (block == NULL) { 362 return UNKNOWN_ERROR; 363 } 364 ssize_t res = pool->writeData(block->getData(), block->getSize()); 365 return (res >= 0) ? (status_t)NO_ERROR : res; 366 } 367 368 // First we need to add all style span names to the string pool. 369 // We do this now (instead of when the span is added) so that these 370 // will appear at the end of the pool, not disrupting the order 371 // our client placed their own strings in it. 372 373 const size_t STYLES = mEntryStyleArray.size(); 374 size_t i; 375 376 for (i=0; i<STYLES; i++) { 377 entry_style& style = mEntryStyleArray.editItemAt(i); 378 const size_t N = style.spans.size(); 379 for (size_t i=0; i<N; i++) { 380 entry_style_span& span = style.spans.editItemAt(i); 381 ssize_t idx = add(span.name, true); 382 if (idx < 0) { 383 fprintf(stderr, "Error adding span for style tag '%s'\n", 384 String8(span.name).string()); 385 return idx; 386 } 387 span.span.name.index = (uint32_t)idx; 388 } 389 } 390 391 const size_t ENTRIES = mEntryArray.size(); 392 393 // Now build the pool of unique strings. 394 395 const size_t STRINGS = mEntries.size(); 396 const size_t preSize = sizeof(ResStringPool_header) 397 + (sizeof(uint32_t)*ENTRIES) 398 + (sizeof(uint32_t)*STYLES); 399 if (pool->editData(preSize) == NULL) { 400 fprintf(stderr, "ERROR: Out of memory for string pool\n"); 401 return NO_MEMORY; 402 } 403 404 const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t); 405 406 size_t strPos = 0; 407 for (i=0; i<STRINGS; i++) { 408 entry& ent = mEntries.editItemAt(i); 409 const size_t strSize = (ent.value.size()); 410 const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ? 411 charSize*2 : charSize; 412 413 String8 encStr; 414 if (mUTF8) { 415 encStr = String8(ent.value); 416 } 417 418 const size_t encSize = mUTF8 ? encStr.size() : 0; 419 const size_t encLenSize = mUTF8 ? 420 (encSize > (size_t)(1<<((charSize*8)-1))-1 ? 421 charSize*2 : charSize) : 0; 422 423 ent.offset = strPos; 424 425 const size_t totalSize = lenSize + encLenSize + 426 ((mUTF8 ? encSize : strSize)+1)*charSize; 427 428 void* dat = (void*)pool->editData(preSize + strPos + totalSize); 429 if (dat == NULL) { 430 fprintf(stderr, "ERROR: Out of memory for string pool\n"); 431 return NO_MEMORY; 432 } 433 dat = (uint8_t*)dat + preSize + strPos; 434 if (mUTF8) { 435 uint8_t* strings = (uint8_t*)dat; 436 437 ENCODE_LENGTH(strings, sizeof(uint8_t), strSize) 438 439 ENCODE_LENGTH(strings, sizeof(uint8_t), encSize) 440 441 strncpy((char*)strings, encStr, encSize+1); 442 } else { 443 uint16_t* strings = (uint16_t*)dat; 444 445 ENCODE_LENGTH(strings, sizeof(uint16_t), strSize) 446 447 strcpy16_htod(strings, ent.value); 448 } 449 450 strPos += totalSize; 451 } 452 453 // Pad ending string position up to a uint32_t boundary. 454 455 if (strPos&0x3) { 456 size_t padPos = ((strPos+3)&~0x3); 457 uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos); 458 if (dat == NULL) { 459 fprintf(stderr, "ERROR: Out of memory padding string pool\n"); 460 return NO_MEMORY; 461 } 462 memset(dat+preSize+strPos, 0, padPos-strPos); 463 strPos = padPos; 464 } 465 466 // Build the pool of style spans. 467 468 size_t styPos = strPos; 469 for (i=0; i<STYLES; i++) { 470 entry_style& ent = mEntryStyleArray.editItemAt(i); 471 const size_t N = ent.spans.size(); 472 const size_t totalSize = (N*sizeof(ResStringPool_span)) 473 + sizeof(ResStringPool_ref); 474 475 ent.offset = styPos-strPos; 476 uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize); 477 if (dat == NULL) { 478 fprintf(stderr, "ERROR: Out of memory for string styles\n"); 479 return NO_MEMORY; 480 } 481 ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos); 482 for (size_t i=0; i<N; i++) { 483 span->name.index = htodl(ent.spans[i].span.name.index); 484 span->firstChar = htodl(ent.spans[i].span.firstChar); 485 span->lastChar = htodl(ent.spans[i].span.lastChar); 486 span++; 487 } 488 span->name.index = htodl(ResStringPool_span::END); 489 490 styPos += totalSize; 491 } 492 493 if (STYLES > 0) { 494 // Add full terminator at the end (when reading we validate that 495 // the end of the pool is fully terminated to simplify error 496 // checking). 497 size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref); 498 uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra); 499 if (dat == NULL) { 500 fprintf(stderr, "ERROR: Out of memory for string styles\n"); 501 return NO_MEMORY; 502 } 503 uint32_t* p = (uint32_t*)(dat+preSize+styPos); 504 while (extra > 0) { 505 *p++ = htodl(ResStringPool_span::END); 506 extra -= sizeof(uint32_t); 507 } 508 styPos += extra; 509 } 510 511 // Write header. 512 513 ResStringPool_header* header = 514 (ResStringPool_header*)pool->padData(sizeof(uint32_t)); 515 if (header == NULL) { 516 fprintf(stderr, "ERROR: Out of memory for string pool\n"); 517 return NO_MEMORY; 518 } 519 memset(header, 0, sizeof(*header)); 520 header->header.type = htods(RES_STRING_POOL_TYPE); 521 header->header.headerSize = htods(sizeof(*header)); 522 header->header.size = htodl(pool->getSize()); 523 header->stringCount = htodl(ENTRIES); 524 header->styleCount = htodl(STYLES); 525 if (mUTF8) { 526 header->flags |= htodl(ResStringPool_header::UTF8_FLAG); 527 } 528 header->stringsStart = htodl(preSize); 529 header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0); 530 531 // Write string index array. 532 533 uint32_t* index = (uint32_t*)(header+1); 534 for (i=0; i<ENTRIES; i++) { 535 entry& ent = mEntries.editItemAt(mEntryArray[i]); 536 *index++ = htodl(ent.offset); 537 NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i, 538 String8(ent.value).string(), 539 mEntryArray[i], ent.offset)); 540 } 541 542 // Write style index array. 543 544 for (i=0; i<STYLES; i++) { 545 *index++ = htodl(mEntryStyleArray[i].offset); 546 } 547 548 return NO_ERROR; 549} 550 551ssize_t StringPool::offsetForString(const String16& val) const 552{ 553 const Vector<size_t>* indices = offsetsForString(val); 554 ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1; 555 NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res, 556 res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8())); 557 return res; 558} 559 560const Vector<size_t>* StringPool::offsetsForString(const String16& val) const 561{ 562 ssize_t pos = mValues.valueFor(val); 563 if (pos < 0) { 564 return NULL; 565 } 566 return &mEntries[mEntryArray[pos]].indices; 567} 568