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