blob: a167a6aec802232592af25f9ac9a936936a95f99 [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 Lesinski1ab598f2015-08-14 14:26:04 -070018#include "util/BigBuffer.h"
19#include "util/StringPiece.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "util/Util.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080021
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080022#include <androidfw/ResourceTypes.h>
Adam Lesinskicacb28f2016-10-19 12:18:14 -070023#include <algorithm>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024#include <memory>
25#include <string>
26
27namespace aapt {
28
Adam Lesinskicacb28f2016-10-19 12:18:14 -070029StringPool::Ref::Ref() : mEntry(nullptr) {}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080030
31StringPool::Ref::Ref(const StringPool::Ref& rhs) : mEntry(rhs.mEntry) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070032 if (mEntry != nullptr) {
33 mEntry->ref++;
34 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080035}
36
37StringPool::Ref::Ref(StringPool::Entry* entry) : mEntry(entry) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070038 if (mEntry != nullptr) {
39 mEntry->ref++;
40 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080041}
42
43StringPool::Ref::~Ref() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070044 if (mEntry != nullptr) {
45 mEntry->ref--;
46 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080047}
48
49StringPool::Ref& StringPool::Ref::operator=(const StringPool::Ref& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070050 if (rhs.mEntry != nullptr) {
51 rhs.mEntry->ref++;
52 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080053
Adam Lesinskicacb28f2016-10-19 12:18:14 -070054 if (mEntry != nullptr) {
55 mEntry->ref--;
56 }
57 mEntry = rhs.mEntry;
58 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080059}
60
Adam Lesinskid0f116b2016-07-08 15:00:32 -070061const std::string* StringPool::Ref::operator->() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 return &mEntry->value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080063}
64
Adam Lesinskicacb28f2016-10-19 12:18:14 -070065const std::string& StringPool::Ref::operator*() const { return mEntry->value; }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080066
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067size_t StringPool::Ref::getIndex() const { return mEntry->index; }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080068
69const StringPool::Context& StringPool::Ref::getContext() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070070 return mEntry->context;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080071}
72
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073StringPool::StyleRef::StyleRef() : mEntry(nullptr) {}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080074
Adam Lesinskicacb28f2016-10-19 12:18:14 -070075StringPool::StyleRef::StyleRef(const StringPool::StyleRef& rhs)
76 : mEntry(rhs.mEntry) {
77 if (mEntry != nullptr) {
78 mEntry->ref++;
79 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080080}
81
82StringPool::StyleRef::StyleRef(StringPool::StyleEntry* entry) : mEntry(entry) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070083 if (mEntry != nullptr) {
84 mEntry->ref++;
85 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080086}
87
88StringPool::StyleRef::~StyleRef() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070089 if (mEntry != nullptr) {
90 mEntry->ref--;
91 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080092}
93
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094StringPool::StyleRef& StringPool::StyleRef::operator=(
95 const StringPool::StyleRef& rhs) {
96 if (rhs.mEntry != nullptr) {
97 rhs.mEntry->ref++;
98 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080099
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700100 if (mEntry != nullptr) {
101 mEntry->ref--;
102 }
103 mEntry = rhs.mEntry;
104 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800105}
106
107const StringPool::StyleEntry* StringPool::StyleRef::operator->() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108 return mEntry;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800109}
110
111const StringPool::StyleEntry& StringPool::StyleRef::operator*() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700112 return *mEntry;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800113}
114
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700115size_t StringPool::StyleRef::getIndex() const { return mEntry->str.getIndex(); }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800116
117const StringPool::Context& StringPool::StyleRef::getContext() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700118 return mEntry->str.getContext();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800119}
120
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700121StringPool::Ref StringPool::makeRef(const StringPiece& str) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700122 return makeRefImpl(str, Context{}, true);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800123}
124
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700125StringPool::Ref StringPool::makeRef(const StringPiece& str,
126 const Context& context) {
127 return makeRefImpl(str, context, true);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800128}
129
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700130StringPool::Ref StringPool::makeRefImpl(const StringPiece& str,
131 const Context& context, bool unique) {
132 if (unique) {
133 auto iter = mIndexedStrings.find(str);
134 if (iter != std::end(mIndexedStrings)) {
135 return Ref(iter->second);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800136 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700137 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800138
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700139 Entry* entry = new Entry();
140 entry->value = str.toString();
141 entry->context = context;
142 entry->index = mStrings.size();
143 entry->ref = 0;
144 mStrings.emplace_back(entry);
145 mIndexedStrings.insert(std::make_pair(StringPiece(entry->value), entry));
146 return Ref(entry);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800147}
148
149StringPool::StyleRef StringPool::makeRef(const StyleString& str) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 return makeRef(str, Context{});
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800151}
152
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700153StringPool::StyleRef StringPool::makeRef(const StyleString& str,
154 const Context& context) {
155 Entry* entry = new Entry();
156 entry->value = str.str;
157 entry->context = context;
158 entry->index = mStrings.size();
159 entry->ref = 0;
160 mStrings.emplace_back(entry);
161 mIndexedStrings.insert(std::make_pair(StringPiece(entry->value), entry));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800162
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700163 StyleEntry* styleEntry = new StyleEntry();
164 styleEntry->str = Ref(entry);
165 for (const aapt::Span& span : str.spans) {
166 styleEntry->spans.emplace_back(
167 Span{makeRef(span.name), span.firstChar, span.lastChar});
168 }
169 styleEntry->ref = 0;
170 mStyles.emplace_back(styleEntry);
171 return StyleRef(styleEntry);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800172}
173
Adam Lesinski769de982015-04-10 19:43:55 -0700174StringPool::StyleRef StringPool::makeRef(const StyleRef& ref) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700175 Entry* entry = new Entry();
176 entry->value = *ref.mEntry->str;
177 entry->context = ref.mEntry->str.mEntry->context;
178 entry->index = mStrings.size();
179 entry->ref = 0;
180 mStrings.emplace_back(entry);
181 mIndexedStrings.insert(std::make_pair(StringPiece(entry->value), entry));
Adam Lesinski769de982015-04-10 19:43:55 -0700182
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 StyleEntry* styleEntry = new StyleEntry();
184 styleEntry->str = Ref(entry);
185 for (const Span& span : ref.mEntry->spans) {
186 styleEntry->spans.emplace_back(
187 Span{makeRef(*span.name), span.firstChar, span.lastChar});
188 }
189 styleEntry->ref = 0;
190 mStyles.emplace_back(styleEntry);
191 return StyleRef(styleEntry);
Adam Lesinski769de982015-04-10 19:43:55 -0700192}
193
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800194void StringPool::merge(StringPool&& pool) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 mIndexedStrings.insert(pool.mIndexedStrings.begin(),
196 pool.mIndexedStrings.end());
197 pool.mIndexedStrings.clear();
198 std::move(pool.mStrings.begin(), pool.mStrings.end(),
199 std::back_inserter(mStrings));
200 pool.mStrings.clear();
201 std::move(pool.mStyles.begin(), pool.mStyles.end(),
202 std::back_inserter(mStyles));
203 pool.mStyles.clear();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800204
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700205 // Assign the indices.
206 const size_t len = mStrings.size();
207 for (size_t index = 0; index < len; index++) {
208 mStrings[index]->index = index;
209 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800210}
211
212void StringPool::hintWillAdd(size_t stringCount, size_t styleCount) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700213 mStrings.reserve(mStrings.size() + stringCount);
214 mStyles.reserve(mStyles.size() + styleCount);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800215}
216
217void StringPool::prune() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700218 const auto iterEnd = std::end(mIndexedStrings);
219 auto indexIter = std::begin(mIndexedStrings);
220 while (indexIter != iterEnd) {
221 if (indexIter->second->ref <= 0) {
222 indexIter = mIndexedStrings.erase(indexIter);
223 } else {
224 ++indexIter;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800225 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700226 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800227
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700228 auto endIter2 =
229 std::remove_if(std::begin(mStrings), std::end(mStrings),
230 [](const std::unique_ptr<Entry>& entry) -> bool {
231 return entry->ref <= 0;
232 });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800233
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700234 auto endIter3 =
235 std::remove_if(std::begin(mStyles), std::end(mStyles),
236 [](const std::unique_ptr<StyleEntry>& entry) -> bool {
237 return entry->ref <= 0;
238 });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800239
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700240 // Remove the entries at the end or else we'll be accessing
241 // a deleted string from the StyleEntry.
242 mStrings.erase(endIter2, std::end(mStrings));
243 mStyles.erase(endIter3, std::end(mStyles));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700244
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700245 // Reassign the indices.
246 const size_t len = mStrings.size();
247 for (size_t index = 0; index < len; index++) {
248 mStrings[index]->index = index;
249 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800250}
251
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700252void StringPool::sort(
253 const std::function<bool(const Entry&, const Entry&)>& cmp) {
254 std::sort(
255 std::begin(mStrings), std::end(mStrings),
256 [&cmp](const std::unique_ptr<Entry>& a,
257 const std::unique_ptr<Entry>& b) -> bool { return cmp(*a, *b); });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800258
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700259 // Assign the indices.
260 const size_t len = mStrings.size();
261 for (size_t index = 0; index < len; index++) {
262 mStrings[index]->index = index;
263 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800264
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700265 // Reorder the styles.
266 std::sort(std::begin(mStyles), std::end(mStyles),
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800267 [](const std::unique_ptr<StyleEntry>& lhs,
268 const std::unique_ptr<StyleEntry>& rhs) -> bool {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 return lhs->str.getIndex() < rhs->str.getIndex();
270 });
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800271}
272
Adam Lesinski24aad162015-04-24 19:19:30 -0700273template <typename T>
274static T* encodeLength(T* data, size_t length) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 static_assert(std::is_integral<T>::value, "wat.");
Adam Lesinski24aad162015-04-24 19:19:30 -0700276
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700277 constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1);
278 constexpr size_t kMaxSize = kMask - 1;
279 if (length > kMaxSize) {
280 *data++ = kMask | (kMaxSize & (length >> (sizeof(T) * 8)));
281 }
282 *data++ = length;
283 return data;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800284}
285
Adam Lesinski24aad162015-04-24 19:19:30 -0700286template <typename T>
287static size_t encodedLengthUnits(size_t length) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700288 static_assert(std::is_integral<T>::value, "wat.");
Adam Lesinski24aad162015-04-24 19:19:30 -0700289
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700290 constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1);
291 constexpr size_t kMaxSize = kMask - 1;
292 return length > kMaxSize ? 2 : 1;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800293}
294
Adam Lesinski24aad162015-04-24 19:19:30 -0700295bool StringPool::flatten(BigBuffer* out, const StringPool& pool, bool utf8) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700296 const size_t startIndex = out->size();
297 android::ResStringPool_header* header =
298 out->nextBlock<android::ResStringPool_header>();
299 header->header.type = android::RES_STRING_POOL_TYPE;
300 header->header.headerSize = sizeof(*header);
301 header->stringCount = pool.size();
302 if (utf8) {
303 header->flags |= android::ResStringPool_header::UTF8_FLAG;
304 }
305
306 uint32_t* indices =
307 pool.size() != 0 ? out->nextBlock<uint32_t>(pool.size()) : nullptr;
308
309 uint32_t* styleIndices = nullptr;
310 if (!pool.mStyles.empty()) {
311 header->styleCount = pool.mStyles.back()->str.getIndex() + 1;
312 styleIndices = out->nextBlock<uint32_t>(header->styleCount);
313 }
314
315 const size_t beforeStringsIndex = out->size();
316 header->stringsStart = beforeStringsIndex - startIndex;
317
318 for (const auto& entry : pool) {
319 *indices = out->size() - beforeStringsIndex;
320 indices++;
321
Adam Lesinski24aad162015-04-24 19:19:30 -0700322 if (utf8) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700323 const std::string& encoded = entry->value;
324 const ssize_t utf16Length = utf8_to_utf16_length(
325 reinterpret_cast<const uint8_t*>(entry->value.data()),
326 entry->value.size());
327 assert(utf16Length >= 0);
328
329 const size_t totalSize = encodedLengthUnits<char>(utf16Length) +
330 encodedLengthUnits<char>(encoded.length()) +
331 encoded.size() + 1;
332
333 char* data = out->nextBlock<char>(totalSize);
334
335 // First encode the UTF16 string length.
336 data = encodeLength(data, utf16Length);
337
338 // Now encode the size of the real UTF8 string.
339 data = encodeLength(data, encoded.length());
340 strncpy(data, encoded.data(), encoded.size());
341
342 } else {
343 const std::u16string encoded = util::utf8ToUtf16(entry->value);
344 const ssize_t utf16Length = encoded.size();
345
346 // Total number of 16-bit words to write.
347 const size_t totalSize =
348 encodedLengthUnits<char16_t>(utf16Length) + encoded.size() + 1;
349
350 char16_t* data = out->nextBlock<char16_t>(totalSize);
351
352 // Encode the actual UTF16 string length.
353 data = encodeLength(data, utf16Length);
354 const size_t byteLength = encoded.size() * sizeof(char16_t);
355
356 // NOTE: For some reason, strncpy16(data, entry->value.data(),
357 // entry->value.size())
358 // truncates the string.
359 memcpy(data, encoded.data(), byteLength);
360
361 // The null-terminating character is already here due to the block of data
362 // being set
363 // to 0s on allocation.
364 }
365 }
366
367 out->align4();
368
369 if (!pool.mStyles.empty()) {
370 const size_t beforeStylesIndex = out->size();
371 header->stylesStart = beforeStylesIndex - startIndex;
372
373 size_t currentIndex = 0;
374 for (const auto& entry : pool.mStyles) {
375 while (entry->str.getIndex() > currentIndex) {
376 styleIndices[currentIndex++] = out->size() - beforeStylesIndex;
377
378 uint32_t* spanOffset = out->nextBlock<uint32_t>();
379 *spanOffset = android::ResStringPool_span::END;
380 }
381 styleIndices[currentIndex++] = out->size() - beforeStylesIndex;
382
383 android::ResStringPool_span* span =
384 out->nextBlock<android::ResStringPool_span>(entry->spans.size());
385 for (const auto& s : entry->spans) {
386 span->name.index = s.name.getIndex();
387 span->firstChar = s.firstChar;
388 span->lastChar = s.lastChar;
389 span++;
390 }
391
392 uint32_t* spanEnd = out->nextBlock<uint32_t>();
393 *spanEnd = android::ResStringPool_span::END;
Adam Lesinski24aad162015-04-24 19:19:30 -0700394 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800395
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700396 // The error checking code in the platform looks for an entire
397 // ResStringPool_span structure worth of 0xFFFFFFFF at the end
398 // of the style block, so fill in the remaining 2 32bit words
399 // with 0xFFFFFFFF.
400 const size_t paddingLength = sizeof(android::ResStringPool_span) -
401 sizeof(android::ResStringPool_span::name);
402 uint8_t* padding = out->nextBlock<uint8_t>(paddingLength);
403 memset(padding, 0xff, paddingLength);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800404 out->align4();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700405 }
406 header->header.size = out->size() - startIndex;
407 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800408}
409
Adam Lesinski24aad162015-04-24 19:19:30 -0700410bool StringPool::flattenUtf8(BigBuffer* out, const StringPool& pool) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700411 return flatten(out, pool, true);
Adam Lesinski24aad162015-04-24 19:19:30 -0700412}
413
414bool StringPool::flattenUtf16(BigBuffer* out, const StringPool& pool) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700415 return flatten(out, pool, false);
Adam Lesinski24aad162015-04-24 19:19:30 -0700416}
417
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700418} // namespace aapt