16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License. 66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at 76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software 116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and 146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License. 156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski#include "StringPool.h" 181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/BigBuffer.h" 191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/StringPiece.h" 201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h" 216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <algorithm> 236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/ResourceTypes.h> 246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <memory> 256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <string> 266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref::Ref() : mEntry(nullptr) { 306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref::Ref(const StringPool::Ref& rhs) : mEntry(rhs.mEntry) { 336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref++; 356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref::Ref(StringPool::Entry* entry) : mEntry(entry) { 396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref++; 416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref::~Ref() { 456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref--; 476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref& StringPool::Ref::operator=(const StringPool::Ref& rhs) { 516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (rhs.mEntry != nullptr) { 526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski rhs.mEntry->ref++; 536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref--; 576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry = rhs.mEntry; 596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return *this; 606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiconst std::u16string* StringPool::Ref::operator->() const { 636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return &mEntry->value; 646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiconst std::u16string& StringPool::Ref::operator*() const { 676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return mEntry->value; 686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskisize_t StringPool::Ref::getIndex() const { 716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return mEntry->index; 726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiconst StringPool::Context& StringPool::Ref::getContext() const { 756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return mEntry->context; 766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::StyleRef::StyleRef() : mEntry(nullptr) { 796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::StyleRef::StyleRef(const StringPool::StyleRef& rhs) : mEntry(rhs.mEntry) { 826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref++; 846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::StyleRef::StyleRef(StringPool::StyleEntry* entry) : mEntry(entry) { 886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref++; 906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::StyleRef::~StyleRef() { 946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref--; 966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::StyleRef& StringPool::StyleRef::operator=(const StringPool::StyleRef& rhs) { 1006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (rhs.mEntry != nullptr) { 1016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski rhs.mEntry->ref++; 1026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mEntry != nullptr) { 1056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry->ref--; 1066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mEntry = rhs.mEntry; 1086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return *this; 1096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiconst StringPool::StyleEntry* StringPool::StyleRef::operator->() const { 1126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return mEntry; 1136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiconst StringPool::StyleEntry& StringPool::StyleRef::operator*() const { 1166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return *mEntry; 1176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskisize_t StringPool::StyleRef::getIndex() const { 1206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return mEntry->str.getIndex(); 1216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiconst StringPool::Context& StringPool::StyleRef::getContext() const { 1246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return mEntry->str.getContext(); 1256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref StringPool::makeRef(const StringPiece16& str) { 1286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return makeRefImpl(str, Context{}, true); 1296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref StringPool::makeRef(const StringPiece16& str, const Context& context) { 1326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return makeRefImpl(str, context, true); 1336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::Ref StringPool::makeRefImpl(const StringPiece16& str, const Context& context, 1366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski bool unique) { 1376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (unique) { 1386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski auto iter = mIndexedStrings.find(str); 1396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (iter != std::end(mIndexedStrings)) { 1406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return Ref(iter->second); 1416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski Entry* entry = new Entry(); 1456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->value = str.toString(); 1466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->context = context; 1476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->index = mStrings.size(); 1486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->ref = 0; 1496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStrings.emplace_back(entry); 1506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry)); 1516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return Ref(entry); 1526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::StyleRef StringPool::makeRef(const StyleString& str) { 1556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return makeRef(str, Context{}); 1566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPool::StyleRef StringPool::makeRef(const StyleString& str, const Context& context) { 1596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski Entry* entry = new Entry(); 1606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->value = str.str; 1616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->context = context; 1626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->index = mStrings.size(); 1636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->ref = 0; 1646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStrings.emplace_back(entry); 1656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry)); 1666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski StyleEntry* styleEntry = new StyleEntry(); 1686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski styleEntry->str = Ref(entry); 1696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (const aapt::Span& span : str.spans) { 1706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski styleEntry->spans.emplace_back(Span{makeRef(span.name), 1716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski span.firstChar, span.lastChar}); 1726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski styleEntry->ref = 0; 1746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStyles.emplace_back(styleEntry); 1756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return StyleRef(styleEntry); 1766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 178769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiStringPool::StyleRef StringPool::makeRef(const StyleRef& ref) { 179769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski Entry* entry = new Entry(); 180769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski entry->value = *ref.mEntry->str; 181769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski entry->context = ref.mEntry->str.mEntry->context; 182769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski entry->index = mStrings.size(); 183769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski entry->ref = 0; 184769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski mStrings.emplace_back(entry); 185769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry)); 186769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 187769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski StyleEntry* styleEntry = new StyleEntry(); 188769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski styleEntry->str = Ref(entry); 189769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski for (const Span& span : ref.mEntry->spans) { 190769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski styleEntry->spans.emplace_back(Span{ makeRef(*span.name), span.firstChar, span.lastChar }); 191769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski } 192769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski styleEntry->ref = 0; 193769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski mStyles.emplace_back(styleEntry); 194769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski return StyleRef(styleEntry); 195769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 196769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 1976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskivoid StringPool::merge(StringPool&& pool) { 1986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mIndexedStrings.insert(pool.mIndexedStrings.begin(), pool.mIndexedStrings.end()); 1996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski pool.mIndexedStrings.clear(); 2006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::move(pool.mStrings.begin(), pool.mStrings.end(), std::back_inserter(mStrings)); 2016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski pool.mStrings.clear(); 2026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::move(pool.mStyles.begin(), pool.mStyles.end(), std::back_inserter(mStyles)); 2036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski pool.mStyles.clear(); 2046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Assign the indices. 2066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const size_t len = mStrings.size(); 2076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (size_t index = 0; index < len; index++) { 2086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStrings[index]->index = index; 2096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskivoid StringPool::hintWillAdd(size_t stringCount, size_t styleCount) { 2136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStrings.reserve(mStrings.size() + stringCount); 2146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStyles.reserve(mStyles.size() + styleCount); 2156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskivoid StringPool::prune() { 2186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const auto iterEnd = std::end(mIndexedStrings); 2196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski auto indexIter = std::begin(mIndexedStrings); 2206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski while (indexIter != iterEnd) { 2216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (indexIter->second->ref <= 0) { 2221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski indexIter = mIndexedStrings.erase(indexIter); 2236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else { 2246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ++indexIter; 2256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski auto endIter2 = std::remove_if(std::begin(mStrings), std::end(mStrings), 2296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski [](const std::unique_ptr<Entry>& entry) -> bool { 2306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return entry->ref <= 0; 2316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ); 2336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski auto endIter3 = std::remove_if(std::begin(mStyles), std::end(mStyles), 2356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski [](const std::unique_ptr<StyleEntry>& entry) -> bool { 2366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return entry->ref <= 0; 2376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ); 2396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Remove the entries at the end or else we'll be accessing 2416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // a deleted string from the StyleEntry. 2426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStrings.erase(endIter2, std::end(mStrings)); 2436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStyles.erase(endIter3, std::end(mStyles)); 2441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 2451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Reassign the indices. 2461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t len = mStrings.size(); 2471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski for (size_t index = 0; index < len; index++) { 2481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mStrings[index]->index = index; 2491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 2506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskivoid StringPool::sort(const std::function<bool(const Entry&, const Entry&)>& cmp) { 2536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::sort(std::begin(mStrings), std::end(mStrings), 2546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski [&cmp](const std::unique_ptr<Entry>& a, const std::unique_ptr<Entry>& b) -> bool { 2556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return cmp(*a, *b); 2566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ); 2586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Assign the indices. 2606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const size_t len = mStrings.size(); 2616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (size_t index = 0; index < len; index++) { 2626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStrings[index]->index = index; 2636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Reorder the styles. 2666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::sort(std::begin(mStyles), std::end(mStyles), 2676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski [](const std::unique_ptr<StyleEntry>& lhs, 2686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const std::unique_ptr<StyleEntry>& rhs) -> bool { 2696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return lhs->str.getIndex() < rhs->str.getIndex(); 2706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ); 2726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 27424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskitemplate <typename T> 27524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskistatic T* encodeLength(T* data, size_t length) { 27624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski static_assert(std::is_integral<T>::value, "wat."); 27724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 27824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1); 27924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski constexpr size_t kMaxSize = kMask - 1; 28024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski if (length > kMaxSize) { 28124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski *data++ = kMask | (kMaxSize & (length >> (sizeof(T) * 8))); 2826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 28324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski *data++ = length; 2846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return data; 2856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 28724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskitemplate <typename T> 28824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskistatic size_t encodedLengthUnits(size_t length) { 28924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski static_assert(std::is_integral<T>::value, "wat."); 29024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 29124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1); 29224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski constexpr size_t kMaxSize = kMask - 1; 29324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski return length > kMaxSize ? 2 : 1; 2946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 29624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 29724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskibool StringPool::flatten(BigBuffer* out, const StringPool& pool, bool utf8) { 2986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const size_t startIndex = out->size(); 2996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski android::ResStringPool_header* header = out->nextBlock<android::ResStringPool_header>(); 3006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski header->header.type = android::RES_STRING_POOL_TYPE; 3016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski header->header.headerSize = sizeof(*header); 3026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski header->stringCount = pool.size(); 30324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski if (utf8) { 30424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski header->flags |= android::ResStringPool_header::UTF8_FLAG; 30524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski } 3066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 307769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski uint32_t* indices = pool.size() != 0 ? out->nextBlock<uint32_t>(pool.size()) : nullptr; 3086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski uint32_t* styleIndices = nullptr; 3106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!pool.mStyles.empty()) { 3116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski header->styleCount = pool.mStyles.back()->str.getIndex() + 1; 3126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski styleIndices = out->nextBlock<uint32_t>(header->styleCount); 3136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const size_t beforeStringsIndex = out->size(); 3166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski header->stringsStart = beforeStringsIndex - startIndex; 3176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (const auto& entry : pool) { 3196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *indices = out->size() - beforeStringsIndex; 3206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski indices++; 3216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 32224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski if (utf8) { 32324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string encoded = util::utf16ToUtf8(entry->value); 32424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 32524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski const size_t totalSize = encodedLengthUnits<char>(entry->value.size()) 32624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski + encodedLengthUnits<char>(encoded.length()) 32724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski + encoded.size() + 1; 3286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 32924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski char* data = out->nextBlock<char>(totalSize); 3306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 33124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski // First encode the actual UTF16 string length. 33224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski data = encodeLength(data, entry->value.size()); 3336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 33424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski // Now encode the size of the converted UTF8 string. 33524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski data = encodeLength(data, encoded.length()); 33624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski strncpy(data, encoded.data(), encoded.size()); 33724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski } else { 33824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski const size_t totalSize = encodedLengthUnits<char16_t>(entry->value.size()) 33924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski + entry->value.size() + 1; 3406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 34124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski char16_t* data = out->nextBlock<char16_t>(totalSize); 3426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 34324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski // Encode the actual UTF16 string length. 34424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski data = encodeLength(data, entry->value.size()); 34552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski const size_t byteLength = entry->value.size() * sizeof(char16_t); 34652364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 34752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski // NOTE: For some reason, strncpy16(data, entry->value.data(), entry->value.size()) 34852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski // truncates the string. 34952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski memcpy(data, entry->value.data(), byteLength); 35052364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 35152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski // The null-terminating character is already here due to the block of data being set 35252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski // to 0s on allocation. 35324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski } 3546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski out->align4(); 3576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!pool.mStyles.empty()) { 3596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const size_t beforeStylesIndex = out->size(); 3606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski header->stylesStart = beforeStylesIndex - startIndex; 3616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski size_t currentIndex = 0; 3636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (const auto& entry : pool.mStyles) { 3646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski while (entry->str.getIndex() > currentIndex) { 3656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski styleIndices[currentIndex++] = out->size() - beforeStylesIndex; 3666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski uint32_t* spanOffset = out->nextBlock<uint32_t>(); 3686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *spanOffset = android::ResStringPool_span::END; 3696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski styleIndices[currentIndex++] = out->size() - beforeStylesIndex; 3716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski android::ResStringPool_span* span = 3736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski out->nextBlock<android::ResStringPool_span>(entry->spans.size()); 3746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (const auto& s : entry->spans) { 3756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski span->name.index = s.name.getIndex(); 3766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski span->firstChar = s.firstChar; 3776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski span->lastChar = s.lastChar; 3786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski span++; 3796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski uint32_t* spanEnd = out->nextBlock<uint32_t>(); 3826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *spanEnd = android::ResStringPool_span::END; 3836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // The error checking code in the platform looks for an entire 3866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // ResStringPool_span structure worth of 0xFFFFFFFF at the end 3876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // of the style block, so fill in the remaining 2 32bit words 3886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // with 0xFFFFFFFF. 3896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const size_t paddingLength = sizeof(android::ResStringPool_span) 3906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski - sizeof(android::ResStringPool_span::name); 3916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski uint8_t* padding = out->nextBlock<uint8_t>(paddingLength); 3926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski memset(padding, 0xff, paddingLength); 3936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski out->align4(); 3946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski header->header.size = out->size() - startIndex; 3966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return true; 3976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 39924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskibool StringPool::flattenUtf8(BigBuffer* out, const StringPool& pool) { 40024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski return flatten(out, pool, true); 40124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 40224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 40324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskibool StringPool::flattenUtf16(BigBuffer* out, const StringPool& pool) { 40424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski return flatten(out, pool, false); 40524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 40624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 4076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt 408