blob: 1310aa6774bb62f53f94bd0c84eaac28a7ab2582 [file] [log] [blame]
Adam Lesinski59e04c62016-02-04 15:59:23 -08001/*
2 * Copyright (C) 2016 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
17#include "ResourceTable.h"
18#include "ResourceUtils.h"
19#include "ValueVisitor.h"
20#include "proto/ProtoHelpers.h"
21#include "proto/ProtoSerialize.h"
22#include "util/Comparators.h"
23
24#include <androidfw/ResourceTypes.h>
25
26namespace aapt {
27
28namespace {
29
30class ReferenceIdToNameVisitor : public ValueVisitor {
31public:
32 using ValueVisitor::visit;
33
34 ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) :
35 mMapping(mapping) {
36 assert(mMapping);
37 }
38
39 void visit(Reference* reference) override {
40 if (!reference->id || !reference->id.value().isValid()) {
41 return;
42 }
43
44 ResourceId id = reference->id.value();
45 auto cacheIter = mMapping->find(id);
46 if (cacheIter != mMapping->end()) {
47 reference->name = cacheIter->second.toResourceName();
48 }
49 }
50
51private:
52 const std::map<ResourceId, ResourceNameRef>* mMapping;
53};
54
55class PackagePbDeserializer {
56public:
57 PackagePbDeserializer(const android::ResStringPool* valuePool,
58 const android::ResStringPool* sourcePool,
59 const android::ResStringPool* symbolPool,
60 const Source& source, IDiagnostics* diag) :
61 mValuePool(valuePool), mSourcePool(sourcePool), mSymbolPool(symbolPool),
62 mSource(source), mDiag(diag) {
63 }
64
65public:
66 bool deserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) {
67 Maybe<uint8_t> id;
68 if (pbPackage.has_package_id()) {
69 id = static_cast<uint8_t>(pbPackage.package_id());
70 }
71
72 std::map<ResourceId, ResourceNameRef> idIndex;
73
74 ResourceTablePackage* pkg = table->createPackage(
75 util::utf8ToUtf16(pbPackage.package_name()), id);
76 for (const pb::Type& pbType : pbPackage.types()) {
77 const ResourceType* resType = parseResourceType(util::utf8ToUtf16(pbType.name()));
78 if (!resType) {
79 mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() << "'");
80 return {};
81 }
82
83 ResourceTableType* type = pkg->findOrCreateType(*resType);
84
85 for (const pb::Entry& pbEntry : pbType.entries()) {
86 ResourceEntry* entry = type->findOrCreateEntry(util::utf8ToUtf16(pbEntry.name()));
87
88 // Deserialize the symbol status (public/private with source and comments).
89 if (pbEntry.has_symbol_status()) {
90 const pb::SymbolStatus& pbStatus = pbEntry.symbol_status();
91 if (pbStatus.has_source()) {
92 deserializeSourceFromPb(pbStatus.source(), *mSourcePool,
93 &entry->symbolStatus.source);
94 }
95
96 if (pbStatus.has_comment()) {
97 entry->symbolStatus.comment = util::utf8ToUtf16(pbStatus.comment());
98 }
99
100 SymbolState visibility = deserializeVisibilityFromPb(pbStatus.visibility());
101 entry->symbolStatus.state = visibility;
102
103 if (visibility == SymbolState::kPublic) {
104 // This is a public symbol, we must encode the ID now if there is one.
105 if (pbEntry.has_id()) {
106 entry->id = static_cast<uint16_t>(pbEntry.id());
107 }
108
109 if (type->symbolStatus.state != SymbolState::kPublic) {
110 // If the type has not been made public, do so now.
111 type->symbolStatus.state = SymbolState::kPublic;
112 if (pbType.has_id()) {
113 type->id = static_cast<uint8_t>(pbType.id());
114 }
115 }
116 } else if (visibility == SymbolState::kPrivate) {
117 if (type->symbolStatus.state == SymbolState::kUndefined) {
118 type->symbolStatus.state = SymbolState::kPrivate;
119 }
120 }
121 }
122
123 ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id());
124 if (resId.isValid()) {
125 idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name);
126 }
127
128 for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) {
129 const pb::ConfigDescription& pbConfig = pbConfigValue.config();
130
131 ConfigDescription config;
132 if (!deserializeConfigDescriptionFromPb(pbConfig, &config)) {
133 mDiag->error(DiagMessage(mSource) << "invalid configuration");
134 return {};
135 }
136
137 auto iter = std::lower_bound(entry->values.begin(), entry->values.end(),
138 config, cmp::lessThanConfig);
139 if (iter != entry->values.end() && iter->config == config) {
140 // Duplicate config.
141 mDiag->error(DiagMessage(mSource) << "duplicate configuration");
142 return {};
143 }
144
145 std::unique_ptr<Value> value = deserializeValueFromPb(pbConfigValue.value(),
146 config,
147 &table->stringPool);
148 if (!value) {
149 return {};
150 }
151 entry->values.insert(iter, ResourceConfigValue{ config, std::move(value) });
152 }
153 }
154 }
155
156 ReferenceIdToNameVisitor visitor(&idIndex);
157 visitAllValuesInPackage(pkg, &visitor);
158 return true;
159 }
160
161private:
162 std::unique_ptr<Item> deserializeItemFromPb(const pb::Item& pbItem,
163 const ConfigDescription& config,
164 StringPool* pool) {
165 if (pbItem.has_ref()) {
166 const pb::Reference& pbRef = pbItem.ref();
167 std::unique_ptr<Reference> ref = util::make_unique<Reference>();
168 if (!deserializeReferenceFromPb(pbRef, ref.get())) {
169 return {};
170 }
171 return std::move(ref);
172
173 } else if (pbItem.has_prim()) {
174 const pb::Primitive& pbPrim = pbItem.prim();
175 android::Res_value prim = {};
176 prim.dataType = static_cast<uint8_t>(pbPrim.type());
177 prim.data = pbPrim.data();
178 return util::make_unique<BinaryPrimitive>(prim);
179
180 } else if (pbItem.has_id()) {
181 return util::make_unique<Id>();
182
183 } else if (pbItem.has_str()) {
184 const uint32_t idx = pbItem.str().idx();
185 StringPiece16 str = util::getString(*mValuePool, idx);
186
187 const android::ResStringPool_span* spans = mValuePool->styleAt(idx);
188 if (spans && spans->name.index != android::ResStringPool_span::END) {
189 StyleString styleStr = { str.toString() };
190 while (spans->name.index != android::ResStringPool_span::END) {
191 styleStr.spans.push_back(Span{
192 util::getString(*mValuePool, spans->name.index).toString(),
193 spans->firstChar,
194 spans->lastChar
195 });
196 spans++;
197 }
198 return util::make_unique<StyledString>(
199 pool->makeRef(styleStr, StringPool::Context{ 1, config }));
200 }
201 return util::make_unique<String>(
202 pool->makeRef(str, StringPool::Context{ 1, config }));
203
204 } else if (pbItem.has_raw_str()) {
205 const uint32_t idx = pbItem.raw_str().idx();
206 StringPiece16 str = util::getString(*mValuePool, idx);
207 return util::make_unique<RawString>(
208 pool->makeRef(str, StringPool::Context{ 1, config }));
209
210 } else if (pbItem.has_file()) {
211 const uint32_t idx = pbItem.file().path_idx();
212 StringPiece16 str = util::getString(*mValuePool, idx);
213 return util::make_unique<FileReference>(
214 pool->makeRef(str, StringPool::Context{ 0, config }));
215
216 } else {
217 mDiag->error(DiagMessage(mSource) << "unknown item");
218 }
219 return {};
220 }
221
222 std::unique_ptr<Value> deserializeValueFromPb(const pb::Value& pbValue,
223 const ConfigDescription& config,
224 StringPool* pool) {
225 const bool isWeak = pbValue.has_weak() ? pbValue.weak() : false;
226
227 std::unique_ptr<Value> value;
228 if (pbValue.has_item()) {
229 value = deserializeItemFromPb(pbValue.item(), config, pool);
230 if (!value) {
231 return {};
232 }
233
234 } else if (pbValue.has_compound_value()) {
235 const pb::CompoundValue pbCompoundValue = pbValue.compound_value();
236 if (pbCompoundValue.has_attr()) {
237 const pb::Attribute& pbAttr = pbCompoundValue.attr();
238 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak);
239 attr->typeMask = pbAttr.format_flags();
240 for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) {
241 Attribute::Symbol symbol;
242 deserializeItemCommon(pbSymbol, &symbol.symbol);
243 if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) {
244 return {};
245 }
246 symbol.value = pbSymbol.value();
247 attr->symbols.push_back(std::move(symbol));
248 }
249 value = std::move(attr);
250
251 } else if (pbCompoundValue.has_style()) {
252 const pb::Style& pbStyle = pbCompoundValue.style();
253 std::unique_ptr<Style> style = util::make_unique<Style>();
254 if (pbStyle.has_parent()) {
255 style->parent = Reference();
256 if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) {
257 return {};
258 }
259
260 if (pbStyle.has_parent_source()) {
261 Source parentSource;
262 deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool,
263 &parentSource);
264 style->parent.value().setSource(std::move(parentSource));
265 }
266 }
267
268 for (const pb::Style_Entry& pbEntry : pbStyle.entries()) {
269 Style::Entry entry;
270 deserializeItemCommon(pbEntry, &entry.key);
271 if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) {
272 return {};
273 }
274
275 entry.value = deserializeItemFromPb(pbEntry.item(), config, pool);
276 if (!entry.value) {
277 return {};
278 }
279
280 deserializeItemCommon(pbEntry, entry.value.get());
281 style->entries.push_back(std::move(entry));
282 }
283 value = std::move(style);
284
285 } else if (pbCompoundValue.has_styleable()) {
286 const pb::Styleable& pbStyleable = pbCompoundValue.styleable();
287 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
288 for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) {
289 Reference attrRef;
290 deserializeItemCommon(pbEntry, &attrRef);
291 deserializeReferenceFromPb(pbEntry.attr(), &attrRef);
292 styleable->entries.push_back(std::move(attrRef));
293 }
294 value = std::move(styleable);
295
296 } else if (pbCompoundValue.has_array()) {
297 const pb::Array& pbArray = pbCompoundValue.array();
298 std::unique_ptr<Array> array = util::make_unique<Array>();
299 for (const pb::Array_Entry& pbEntry : pbArray.entries()) {
300 std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config,
301 pool);
302 if (!item) {
303 return {};
304 }
305
306 deserializeItemCommon(pbEntry, item.get());
307 array->items.push_back(std::move(item));
308 }
309 value = std::move(array);
310
311 } else if (pbCompoundValue.has_plural()) {
312 const pb::Plural& pbPlural = pbCompoundValue.plural();
313 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
314 for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) {
315 size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity());
316 plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config,
317 pool);
318 if (!plural->values[pluralIdx]) {
319 return {};
320 }
321
322 deserializeItemCommon(pbEntry, plural->values[pluralIdx].get());
323 }
324 value = std::move(plural);
325
326 } else {
327 mDiag->error(DiagMessage(mSource) << "unknown compound value");
328 return {};
329 }
330 } else {
331 mDiag->error(DiagMessage(mSource) << "unknown value");
332 return {};
333 }
334
335 assert(value && "forgot to set value");
336
337 value->setWeak(isWeak);
338 deserializeItemCommon(pbValue, value.get());
339 return value;
340 }
341
342 bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) {
343 outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type());
344 outRef->privateReference = pbRef.private_();
345
346 if (!pbRef.has_id() && !pbRef.has_symbol_idx()) {
347 return false;
348 }
349
350 if (pbRef.has_id()) {
351 outRef->id = ResourceId(pbRef.id());
352 }
353
354 if (pbRef.has_symbol_idx()) {
355 StringPiece16 strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx());
356 ResourceNameRef nameRef;
357 if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) {
358 mDiag->error(DiagMessage(mSource) << "invalid reference name '"
359 << strSymbol << "'");
360 return false;
361 }
362
363 outRef->name = nameRef.toResourceName();
364 }
365 return true;
366 }
367
368 template <typename T>
369 void deserializeItemCommon(const T& pbItem, Value* outValue) {
370 if (pbItem.has_source()) {
371 Source source;
372 deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source);
373 outValue->setSource(std::move(source));
374 }
375
376 if (pbItem.has_comment()) {
377 outValue->setComment(util::utf8ToUtf16(pbItem.comment()));
378 }
379 }
380
381private:
382 const android::ResStringPool* mValuePool;
383 const android::ResStringPool* mSourcePool;
384 const android::ResStringPool* mSymbolPool;
385 const Source mSource;
386 IDiagnostics* mDiag;
387};
388
389} // namespace
390
391std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable,
392 const Source& source,
393 IDiagnostics* diag) {
394 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
395
396 if (!pbTable.has_string_pool()) {
397 diag->error(DiagMessage(source) << "no string pool found");
398 return {};
399 }
400
401 android::ResStringPool valuePool;
402 android::status_t result = valuePool.setTo(pbTable.string_pool().data().data(),
403 pbTable.string_pool().data().size());
404 if (result != android::NO_ERROR) {
405 diag->error(DiagMessage(source) << "invalid string pool");
406 return {};
407 }
408
409 android::ResStringPool sourcePool;
410 if (pbTable.has_source_pool()) {
411 result = sourcePool.setTo(pbTable.source_pool().data().data(),
412 pbTable.source_pool().data().size());
413 if (result != android::NO_ERROR) {
414 diag->error(DiagMessage(source) << "invalid source pool");
415 return {};
416 }
417 }
418
419 android::ResStringPool symbolPool;
420 if (pbTable.has_symbol_pool()) {
421 result = symbolPool.setTo(pbTable.symbol_pool().data().data(),
422 pbTable.symbol_pool().data().size());
423 if (result != android::NO_ERROR) {
424 diag->error(DiagMessage(source) << "invalid symbol pool");
425 return {};
426 }
427 }
428
429 PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag);
430 for (const pb::Package& pbPackage : pbTable.packages()) {
431 if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) {
432 return {};
433 }
434 }
435 return table;
436}
437
438std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile,
439 const Source& source,
440 IDiagnostics* diag) {
441 std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
442
443 ResourceNameRef nameRef;
444
445 // Need to create an lvalue here so that nameRef can point to something real.
446 std::u16string utf16Name = util::utf8ToUtf16(pbFile.resource_name());
447 if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
448 diag->error(DiagMessage(source) << "invalid resource name in compiled file header: "
449 << pbFile.resource_name());
450 return {};
451 }
452 file->name = nameRef.toResourceName();
453 file->source.path = pbFile.source_path();
454 deserializeConfigDescriptionFromPb(pbFile.config(), &file->config);
455
456 for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) {
457 // Need to create an lvalue here so that nameRef can point to something real.
458 utf16Name = util::utf8ToUtf16(pbSymbol.resource_name());
459 if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
460 diag->error(DiagMessage(source) << "invalid resource name for exported symbol in "
461 "compiled file header: "
462 << pbFile.resource_name());
463 return {};
464 }
465 file->exportedSymbols.push_back(
466 SourcedResourceName{ nameRef.toResourceName(), pbSymbol.line_no() });
467 }
468 return file;
469}
470
471CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) :
472 mIn(static_cast<const uint8_t*>(data), size), mPbFile(),
473 mData(static_cast<const uint8_t*>(data)), mSize(size) {
474}
475
476const pb::CompiledFile* CompiledFileInputStream::CompiledFile() {
477 if (!mPbFile) {
478 std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
479 uint64_t pbSize = 0u;
480 if (!mIn.ReadLittleEndian64(&pbSize)) {
481 return nullptr;
482 }
483 mIn.PushLimit(static_cast<int>(pbSize));
484 if (!pbFile->ParsePartialFromCodedStream(&mIn)) {
485 return nullptr;
486 }
487
488 const size_t padding = 4 - (pbSize & 0x03);
489 mData += sizeof(uint64_t) + pbSize + padding;
490 mSize -= sizeof(uint64_t) + pbSize + padding;
491 mPbFile = std::move(pbFile);
492 }
493 return mPbFile.get();
494}
495
496const void* CompiledFileInputStream::data() {
497 if (!mPbFile) {
498 if (!CompiledFile()) {
499 return nullptr;
500 }
501 }
502 return mData;
503}
504
505size_t CompiledFileInputStream::size() {
506 if (!mPbFile) {
507 if (!CompiledFile()) {
508 return 0;
509 }
510 }
511 return mSize;
512}
513
514} // namespace aapt