blob: d968d73c44eeea4b3fd792b0fcbb2eb4e69b18dd [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinski52364f72016-01-11 13:10:24 -080017#include "StringPool.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080018
Adam Lesinskicacb28f2016-10-19 12:18:14 -070019#include <algorithm>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080020#include <memory>
21#include <string>
22
Adam Lesinskice5e56e2016-10-21 17:56:45 -070023#include "android-base/logging.h"
24#include "androidfw/ResourceTypes.h"
Adam Lesinskid5083f62017-01-16 15:07:21 -080025#include "androidfw/StringPiece.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070026
27#include "util/BigBuffer.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070028#include "util/Util.h"
29
Adam Lesinskid5083f62017-01-16 15:07:21 -080030using android::StringPiece;
31
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080032namespace aapt {
33
Adam Lesinskice5e56e2016-10-21 17:56:45 -070034StringPool::Ref::Ref() : entry_(nullptr) {}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080035
Adam Lesinskice5e56e2016-10-21 17:56:45 -070036StringPool::Ref::Ref(const StringPool::Ref& rhs) : entry_(rhs.entry_) {
37 if (entry_ != nullptr) {
38 entry_->ref_++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070039 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080040}
41
Adam Lesinskice5e56e2016-10-21 17:56:45 -070042StringPool::Ref::Ref(StringPool::Entry* entry) : entry_(entry) {
43 if (entry_ != nullptr) {
44 entry_->ref_++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070045 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080046}
47
48StringPool::Ref::~Ref() {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070049 if (entry_ != nullptr) {
50 entry_->ref_--;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080052}
53
54StringPool::Ref& StringPool::Ref::operator=(const StringPool::Ref& rhs) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070055 if (rhs.entry_ != nullptr) {
56 rhs.entry_->ref_++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070057 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080058
Adam Lesinskice5e56e2016-10-21 17:56:45 -070059 if (entry_ != nullptr) {
60 entry_->ref_--;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070061 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070062 entry_ = rhs.entry_;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070063 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080064}
65
Adam Lesinskid0f116b2016-07-08 15:00:32 -070066const std::string* StringPool::Ref::operator->() const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070067 return &entry_->value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080068}
69
Adam Lesinskice5e56e2016-10-21 17:56:45 -070070const std::string& StringPool::Ref::operator*() const { return entry_->value; }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080071
Adam Lesinskice5e56e2016-10-21 17:56:45 -070072size_t StringPool::Ref::index() const { return entry_->index; }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080073
Adam Lesinskice5e56e2016-10-21 17:56:45 -070074const StringPool::Context& StringPool::Ref::GetContext() const {
75 return entry_->context;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080076}
77
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078StringPool::StyleRef::StyleRef() : entry_(nullptr) {}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080079
Adam Lesinskicacb28f2016-10-19 12:18:14 -070080StringPool::StyleRef::StyleRef(const StringPool::StyleRef& rhs)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070081 : entry_(rhs.entry_) {
82 if (entry_ != nullptr) {
83 entry_->ref_++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070084 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080085}
86
Adam Lesinskice5e56e2016-10-21 17:56:45 -070087StringPool::StyleRef::StyleRef(StringPool::StyleEntry* entry) : entry_(entry) {
88 if (entry_ != nullptr) {
89 entry_->ref_++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070090 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080091}
92
93StringPool::StyleRef::~StyleRef() {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070094 if (entry_ != nullptr) {
95 entry_->ref_--;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070096 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080097}
98
Adam Lesinskicacb28f2016-10-19 12:18:14 -070099StringPool::StyleRef& StringPool::StyleRef::operator=(
100 const StringPool::StyleRef& rhs) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700101 if (rhs.entry_ != nullptr) {
102 rhs.entry_->ref_++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700103 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800104
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700105 if (entry_ != nullptr) {
106 entry_->ref_--;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700107 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700108 entry_ = rhs.entry_;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700109 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800110}
111
112const StringPool::StyleEntry* StringPool::StyleRef::operator->() const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700113 return entry_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800114}
115
116const StringPool::StyleEntry& StringPool::StyleRef::operator*() const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117 return *entry_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800118}
119
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700120size_t StringPool::StyleRef::index() const { return entry_->str.index(); }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800121
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122const StringPool::Context& StringPool::StyleRef::GetContext() const {
123 return entry_->str.GetContext();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800124}
125
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700126StringPool::Ref StringPool::MakeRef(const StringPiece& str) {
127 return MakeRefImpl(str, Context{}, true);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800128}
129
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700130StringPool::Ref StringPool::MakeRef(const StringPiece& str,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700131 const Context& context) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700132 return MakeRefImpl(str, context, true);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800133}
134
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700135StringPool::Ref StringPool::MakeRefImpl(const StringPiece& str,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700136 const Context& context, bool unique) {
137 if (unique) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700138 auto iter = indexed_strings_.find(str);
139 if (iter != std::end(indexed_strings_)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700140 return Ref(iter->second);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800141 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700142 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800143
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700144 Entry* entry = new Entry();
Adam Lesinskid5083f62017-01-16 15:07:21 -0800145 entry->value = str.to_string();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700146 entry->context = context;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700147 entry->index = strings_.size();
148 entry->ref_ = 0;
149 strings_.emplace_back(entry);
150 indexed_strings_.insert(std::make_pair(StringPiece(entry->value), entry));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700151 return Ref(entry);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800152}
153
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154StringPool::StyleRef StringPool::MakeRef(const StyleString& str) {
155 return MakeRef(str, Context{});
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800156}
157
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700158StringPool::StyleRef StringPool::MakeRef(const StyleString& str,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700159 const Context& context) {
160 Entry* entry = new Entry();
161 entry->value = str.str;
162 entry->context = context;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700163 entry->index = strings_.size();
164 entry->ref_ = 0;
165 strings_.emplace_back(entry);
166 indexed_strings_.insert(std::make_pair(StringPiece(entry->value), entry));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800167
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700168 StyleEntry* style_entry = new StyleEntry();
169 style_entry->str = Ref(entry);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700170 for (const aapt::Span& span : str.spans) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700171 style_entry->spans.emplace_back(
172 Span{MakeRef(span.name), span.first_char, span.last_char});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700173 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 style_entry->ref_ = 0;
175 styles_.emplace_back(style_entry);
176 return StyleRef(style_entry);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800177}
178
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179StringPool::StyleRef StringPool::MakeRef(const StyleRef& ref) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700180 Entry* entry = new Entry();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700181 entry->value = *ref.entry_->str;
182 entry->context = ref.entry_->str.entry_->context;
183 entry->index = strings_.size();
184 entry->ref_ = 0;
185 strings_.emplace_back(entry);
186 indexed_strings_.insert(std::make_pair(StringPiece(entry->value), entry));
Adam Lesinski769de982015-04-10 19:43:55 -0700187
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700188 StyleEntry* style_entry = new StyleEntry();
189 style_entry->str = Ref(entry);
190 for (const Span& span : ref.entry_->spans) {
191 style_entry->spans.emplace_back(
192 Span{MakeRef(*span.name), span.first_char, span.last_char});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700193 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700194 style_entry->ref_ = 0;
195 styles_.emplace_back(style_entry);
196 return StyleRef(style_entry);
Adam Lesinski769de982015-04-10 19:43:55 -0700197}
198
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700199void StringPool::Merge(StringPool&& pool) {
200 indexed_strings_.insert(pool.indexed_strings_.begin(),
201 pool.indexed_strings_.end());
202 pool.indexed_strings_.clear();
203 std::move(pool.strings_.begin(), pool.strings_.end(),
204 std::back_inserter(strings_));
205 pool.strings_.clear();
206 std::move(pool.styles_.begin(), pool.styles_.end(),
207 std::back_inserter(styles_));
208 pool.styles_.clear();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800209
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 // Assign the indices.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700211 const size_t len = strings_.size();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700212 for (size_t index = 0; index < len; index++) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213 strings_[index]->index = index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700214 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800215}
216
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217void StringPool::HintWillAdd(size_t stringCount, size_t styleCount) {
218 strings_.reserve(strings_.size() + stringCount);
219 styles_.reserve(styles_.size() + styleCount);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800220}
221
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700222void StringPool::Prune() {
223 const auto iter_end = indexed_strings_.end();
224 auto index_iter = indexed_strings_.begin();
225 while (index_iter != iter_end) {
226 if (index_iter->second->ref_ <= 0) {
227 index_iter = indexed_strings_.erase(index_iter);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700228 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 ++index_iter;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800230 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700231 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800232
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700233 auto end_iter2 =
234 std::remove_if(strings_.begin(), strings_.end(),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700235 [](const std::unique_ptr<Entry>& entry) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 return entry->ref_ <= 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700237 });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800238
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700239 auto end_iter3 =
240 std::remove_if(styles_.begin(), styles_.end(),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700241 [](const std::unique_ptr<StyleEntry>& entry) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242 return entry->ref_ <= 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700243 });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800244
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700245 // Remove the entries at the end or else we'll be accessing
246 // a deleted string from the StyleEntry.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 strings_.erase(end_iter2, strings_.end());
248 styles_.erase(end_iter3, styles_.end());
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700249
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700250 // Reassign the indices.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700251 const size_t len = strings_.size();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700252 for (size_t index = 0; index < len; index++) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700253 strings_[index]->index = index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700254 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800255}
256
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700257void StringPool::Sort(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700258 const std::function<bool(const Entry&, const Entry&)>& cmp) {
259 std::sort(
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260 strings_.begin(), strings_.end(),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700261 [&cmp](const std::unique_ptr<Entry>& a,
262 const std::unique_ptr<Entry>& b) -> bool { return cmp(*a, *b); });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800263
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700264 // Assign the indices.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700265 const size_t len = strings_.size();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700266 for (size_t index = 0; index < len; index++) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700267 strings_[index]->index = index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700268 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800269
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700270 // Reorder the styles.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 std::sort(styles_.begin(), styles_.end(),
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800272 [](const std::unique_ptr<StyleEntry>& lhs,
273 const std::unique_ptr<StyleEntry>& rhs) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700274 return lhs->str.index() < rhs->str.index();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800276}
277
Adam Lesinski24aad162015-04-24 19:19:30 -0700278template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700279static T* EncodeLength(T* data, size_t length) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700280 static_assert(std::is_integral<T>::value, "wat.");
Adam Lesinski24aad162015-04-24 19:19:30 -0700281
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282 constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1);
283 constexpr size_t kMaxSize = kMask - 1;
284 if (length > kMaxSize) {
285 *data++ = kMask | (kMaxSize & (length >> (sizeof(T) * 8)));
286 }
287 *data++ = length;
288 return data;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800289}
290
Adam Lesinski24aad162015-04-24 19:19:30 -0700291template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700292static size_t EncodedLengthUnits(size_t length) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700293 static_assert(std::is_integral<T>::value, "wat.");
Adam Lesinski24aad162015-04-24 19:19:30 -0700294
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700295 constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1);
296 constexpr size_t kMaxSize = kMask - 1;
297 return length > kMaxSize ? 2 : 1;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800298}
299
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700300bool StringPool::Flatten(BigBuffer* out, const StringPool& pool, bool utf8) {
301 const size_t start_index = out->size();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700302 android::ResStringPool_header* header =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700303 out->NextBlock<android::ResStringPool_header>();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700304 header->header.type = android::RES_STRING_POOL_TYPE;
305 header->header.headerSize = sizeof(*header);
306 header->stringCount = pool.size();
307 if (utf8) {
308 header->flags |= android::ResStringPool_header::UTF8_FLAG;
309 }
310
311 uint32_t* indices =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700312 pool.size() != 0 ? out->NextBlock<uint32_t>(pool.size()) : nullptr;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700313
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700314 uint32_t* style_indices = nullptr;
315 if (!pool.styles_.empty()) {
316 header->styleCount = pool.styles_.back()->str.index() + 1;
317 style_indices = out->NextBlock<uint32_t>(header->styleCount);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700318 }
319
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700320 const size_t before_strings_index = out->size();
321 header->stringsStart = before_strings_index - start_index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700322
323 for (const auto& entry : pool) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700324 *indices = out->size() - before_strings_index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700325 indices++;
326
Adam Lesinski24aad162015-04-24 19:19:30 -0700327 if (utf8) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700328 const std::string& encoded = entry->value;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700329 const ssize_t utf16_length = utf8_to_utf16_length(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700330 reinterpret_cast<const uint8_t*>(entry->value.data()),
331 entry->value.size());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700332 CHECK(utf16_length >= 0);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700333
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700334 const size_t total_size = EncodedLengthUnits<char>(utf16_length) +
335 EncodedLengthUnits<char>(encoded.length()) +
336 encoded.size() + 1;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700337
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700338 char* data = out->NextBlock<char>(total_size);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700339
340 // First encode the UTF16 string length.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700341 data = EncodeLength(data, utf16_length);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700342
343 // Now encode the size of the real UTF8 string.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700344 data = EncodeLength(data, encoded.length());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700345 strncpy(data, encoded.data(), encoded.size());
346
347 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700348 const std::u16string encoded = util::Utf8ToUtf16(entry->value);
349 const ssize_t utf16_length = encoded.size();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700350
351 // Total number of 16-bit words to write.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700352 const size_t total_size =
353 EncodedLengthUnits<char16_t>(utf16_length) + encoded.size() + 1;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700354
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700355 char16_t* data = out->NextBlock<char16_t>(total_size);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700356
357 // Encode the actual UTF16 string length.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700358 data = EncodeLength(data, utf16_length);
359 const size_t byte_length = encoded.size() * sizeof(char16_t);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700360
361 // NOTE: For some reason, strncpy16(data, entry->value.data(),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700362 // entry->value.size()) truncates the string.
363 memcpy(data, encoded.data(), byte_length);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700364
365 // The null-terminating character is already here due to the block of data
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700366 // being set to 0s on allocation.
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700367 }
368 }
369
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700370 out->Align4();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700371
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700372 if (!pool.styles_.empty()) {
373 const size_t before_styles_index = out->size();
374 header->stylesStart = before_styles_index - start_index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700375
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700376 size_t current_index = 0;
377 for (const auto& entry : pool.styles_) {
378 while (entry->str.index() > current_index) {
379 style_indices[current_index++] = out->size() - before_styles_index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700380
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700381 uint32_t* span_offset = out->NextBlock<uint32_t>();
382 *span_offset = android::ResStringPool_span::END;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700383 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700384 style_indices[current_index++] = out->size() - before_styles_index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700385
386 android::ResStringPool_span* span =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700387 out->NextBlock<android::ResStringPool_span>(entry->spans.size());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700388 for (const auto& s : entry->spans) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700389 span->name.index = s.name.index();
390 span->firstChar = s.first_char;
391 span->lastChar = s.last_char;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700392 span++;
393 }
394
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700395 uint32_t* spanEnd = out->NextBlock<uint32_t>();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700396 *spanEnd = android::ResStringPool_span::END;
Adam Lesinski24aad162015-04-24 19:19:30 -0700397 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800398
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700399 // The error checking code in the platform looks for an entire
400 // ResStringPool_span structure worth of 0xFFFFFFFF at the end
401 // of the style block, so fill in the remaining 2 32bit words
402 // with 0xFFFFFFFF.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700403 const size_t padding_length = sizeof(android::ResStringPool_span) -
404 sizeof(android::ResStringPool_span::name);
405 uint8_t* padding = out->NextBlock<uint8_t>(padding_length);
406 memset(padding, 0xff, padding_length);
407 out->Align4();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700408 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700409 header->header.size = out->size() - start_index;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700410 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800411}
412
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700413bool StringPool::FlattenUtf8(BigBuffer* out, const StringPool& pool) {
414 return Flatten(out, pool, true);
Adam Lesinski24aad162015-04-24 19:19:30 -0700415}
416
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700417bool StringPool::FlattenUtf16(BigBuffer* out, const StringPool& pool) {
418 return Flatten(out, pool, false);
Adam Lesinski24aad162015-04-24 19:19:30 -0700419}
420
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700421} // namespace aapt