blob: 595fa6f29facabdca4c05b566dbc5dec6bef9f5e [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"
Adam Lesinski59e04c62016-02-04 15:59:23 -080022
23#include <androidfw/ResourceTypes.h>
24
25namespace aapt {
26
27namespace {
28
29class ReferenceIdToNameVisitor : public ValueVisitor {
30public:
31 using ValueVisitor::visit;
32
Chih-Hung Hsiehd53e3be2016-05-03 10:02:51 -070033 explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) :
Adam Lesinski59e04c62016-02-04 15:59:23 -080034 mMapping(mapping) {
35 assert(mMapping);
36 }
37
38 void visit(Reference* reference) override {
39 if (!reference->id || !reference->id.value().isValid()) {
40 return;
41 }
42
43 ResourceId id = reference->id.value();
44 auto cacheIter = mMapping->find(id);
45 if (cacheIter != mMapping->end()) {
46 reference->name = cacheIter->second.toResourceName();
47 }
48 }
49
50private:
51 const std::map<ResourceId, ResourceNameRef>* mMapping;
52};
53
54class PackagePbDeserializer {
55public:
56 PackagePbDeserializer(const android::ResStringPool* valuePool,
57 const android::ResStringPool* sourcePool,
58 const android::ResStringPool* symbolPool,
59 const Source& source, IDiagnostics* diag) :
60 mValuePool(valuePool), mSourcePool(sourcePool), mSymbolPool(symbolPool),
61 mSource(source), mDiag(diag) {
62 }
63
64public:
65 bool deserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) {
66 Maybe<uint8_t> id;
67 if (pbPackage.has_package_id()) {
68 id = static_cast<uint8_t>(pbPackage.package_id());
69 }
70
71 std::map<ResourceId, ResourceNameRef> idIndex;
72
Adam Lesinskid0f116b2016-07-08 15:00:32 -070073 ResourceTablePackage* pkg = table->createPackage(pbPackage.package_name(), id);
Adam Lesinski59e04c62016-02-04 15:59:23 -080074 for (const pb::Type& pbType : pbPackage.types()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -070075 const ResourceType* resType = parseResourceType(pbType.name());
Adam Lesinski59e04c62016-02-04 15:59:23 -080076 if (!resType) {
77 mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() << "'");
78 return {};
79 }
80
81 ResourceTableType* type = pkg->findOrCreateType(*resType);
82
83 for (const pb::Entry& pbEntry : pbType.entries()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -070084 ResourceEntry* entry = type->findOrCreateEntry(pbEntry.name());
Adam Lesinski59e04c62016-02-04 15:59:23 -080085
86 // Deserialize the symbol status (public/private with source and comments).
87 if (pbEntry.has_symbol_status()) {
88 const pb::SymbolStatus& pbStatus = pbEntry.symbol_status();
89 if (pbStatus.has_source()) {
90 deserializeSourceFromPb(pbStatus.source(), *mSourcePool,
91 &entry->symbolStatus.source);
92 }
93
94 if (pbStatus.has_comment()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -070095 entry->symbolStatus.comment = pbStatus.comment();
Adam Lesinski59e04c62016-02-04 15:59:23 -080096 }
97
98 SymbolState visibility = deserializeVisibilityFromPb(pbStatus.visibility());
99 entry->symbolStatus.state = visibility;
100
101 if (visibility == SymbolState::kPublic) {
102 // This is a public symbol, we must encode the ID now if there is one.
103 if (pbEntry.has_id()) {
104 entry->id = static_cast<uint16_t>(pbEntry.id());
105 }
106
107 if (type->symbolStatus.state != SymbolState::kPublic) {
108 // If the type has not been made public, do so now.
109 type->symbolStatus.state = SymbolState::kPublic;
110 if (pbType.has_id()) {
111 type->id = static_cast<uint8_t>(pbType.id());
112 }
113 }
114 } else if (visibility == SymbolState::kPrivate) {
115 if (type->symbolStatus.state == SymbolState::kUndefined) {
116 type->symbolStatus.state = SymbolState::kPrivate;
117 }
118 }
119 }
120
121 ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id());
122 if (resId.isValid()) {
123 idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name);
124 }
125
126 for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) {
127 const pb::ConfigDescription& pbConfig = pbConfigValue.config();
128
129 ConfigDescription config;
130 if (!deserializeConfigDescriptionFromPb(pbConfig, &config)) {
131 mDiag->error(DiagMessage(mSource) << "invalid configuration");
132 return {};
133 }
134
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800135 ResourceConfigValue* configValue = entry->findOrCreateValue(config,
136 pbConfig.product());
137 if (configValue->value) {
Adam Lesinski59e04c62016-02-04 15:59:23 -0800138 // Duplicate config.
139 mDiag->error(DiagMessage(mSource) << "duplicate configuration");
140 return {};
141 }
142
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800143 configValue->value = deserializeValueFromPb(pbConfigValue.value(),
144 config, &table->stringPool);
145 if (!configValue->value) {
Adam Lesinski59e04c62016-02-04 15:59:23 -0800146 return {};
147 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800148 }
149 }
150 }
151
152 ReferenceIdToNameVisitor visitor(&idIndex);
153 visitAllValuesInPackage(pkg, &visitor);
154 return true;
155 }
156
157private:
158 std::unique_ptr<Item> deserializeItemFromPb(const pb::Item& pbItem,
159 const ConfigDescription& config,
160 StringPool* pool) {
161 if (pbItem.has_ref()) {
162 const pb::Reference& pbRef = pbItem.ref();
163 std::unique_ptr<Reference> ref = util::make_unique<Reference>();
164 if (!deserializeReferenceFromPb(pbRef, ref.get())) {
165 return {};
166 }
167 return std::move(ref);
168
169 } else if (pbItem.has_prim()) {
170 const pb::Primitive& pbPrim = pbItem.prim();
171 android::Res_value prim = {};
172 prim.dataType = static_cast<uint8_t>(pbPrim.type());
173 prim.data = pbPrim.data();
174 return util::make_unique<BinaryPrimitive>(prim);
175
176 } else if (pbItem.has_id()) {
177 return util::make_unique<Id>();
178
179 } else if (pbItem.has_str()) {
180 const uint32_t idx = pbItem.str().idx();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700181 const std::string str = util::getString(*mValuePool, idx);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800182
183 const android::ResStringPool_span* spans = mValuePool->styleAt(idx);
184 if (spans && spans->name.index != android::ResStringPool_span::END) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700185 StyleString styleStr = { str };
Adam Lesinski59e04c62016-02-04 15:59:23 -0800186 while (spans->name.index != android::ResStringPool_span::END) {
187 styleStr.spans.push_back(Span{
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700188 util::getString(*mValuePool, spans->name.index),
Adam Lesinski59e04c62016-02-04 15:59:23 -0800189 spans->firstChar,
190 spans->lastChar
191 });
192 spans++;
193 }
194 return util::make_unique<StyledString>(
195 pool->makeRef(styleStr, StringPool::Context{ 1, config }));
196 }
197 return util::make_unique<String>(
198 pool->makeRef(str, StringPool::Context{ 1, config }));
199
200 } else if (pbItem.has_raw_str()) {
201 const uint32_t idx = pbItem.raw_str().idx();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700202 const std::string str = util::getString(*mValuePool, idx);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800203 return util::make_unique<RawString>(
204 pool->makeRef(str, StringPool::Context{ 1, config }));
205
206 } else if (pbItem.has_file()) {
207 const uint32_t idx = pbItem.file().path_idx();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700208 const std::string str = util::getString(*mValuePool, idx);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800209 return util::make_unique<FileReference>(
210 pool->makeRef(str, StringPool::Context{ 0, config }));
211
212 } else {
213 mDiag->error(DiagMessage(mSource) << "unknown item");
214 }
215 return {};
216 }
217
218 std::unique_ptr<Value> deserializeValueFromPb(const pb::Value& pbValue,
219 const ConfigDescription& config,
220 StringPool* pool) {
221 const bool isWeak = pbValue.has_weak() ? pbValue.weak() : false;
222
223 std::unique_ptr<Value> value;
224 if (pbValue.has_item()) {
225 value = deserializeItemFromPb(pbValue.item(), config, pool);
226 if (!value) {
227 return {};
228 }
229
230 } else if (pbValue.has_compound_value()) {
Chih-Hung Hsieh9b8528f2016-08-10 14:15:30 -0700231 const pb::CompoundValue& pbCompoundValue = pbValue.compound_value();
Adam Lesinski59e04c62016-02-04 15:59:23 -0800232 if (pbCompoundValue.has_attr()) {
233 const pb::Attribute& pbAttr = pbCompoundValue.attr();
234 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak);
235 attr->typeMask = pbAttr.format_flags();
Adam Lesinski458b8772016-04-25 14:20:21 -0700236 attr->minInt = pbAttr.min_int();
237 attr->maxInt = pbAttr.max_int();
Adam Lesinski59e04c62016-02-04 15:59:23 -0800238 for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) {
239 Attribute::Symbol symbol;
240 deserializeItemCommon(pbSymbol, &symbol.symbol);
241 if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) {
242 return {};
243 }
244 symbol.value = pbSymbol.value();
245 attr->symbols.push_back(std::move(symbol));
246 }
247 value = std::move(attr);
248
249 } else if (pbCompoundValue.has_style()) {
250 const pb::Style& pbStyle = pbCompoundValue.style();
251 std::unique_ptr<Style> style = util::make_unique<Style>();
252 if (pbStyle.has_parent()) {
253 style->parent = Reference();
254 if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) {
255 return {};
256 }
257
258 if (pbStyle.has_parent_source()) {
259 Source parentSource;
260 deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool,
261 &parentSource);
262 style->parent.value().setSource(std::move(parentSource));
263 }
264 }
265
266 for (const pb::Style_Entry& pbEntry : pbStyle.entries()) {
267 Style::Entry entry;
268 deserializeItemCommon(pbEntry, &entry.key);
269 if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) {
270 return {};
271 }
272
273 entry.value = deserializeItemFromPb(pbEntry.item(), config, pool);
274 if (!entry.value) {
275 return {};
276 }
277
278 deserializeItemCommon(pbEntry, entry.value.get());
279 style->entries.push_back(std::move(entry));
280 }
281 value = std::move(style);
282
283 } else if (pbCompoundValue.has_styleable()) {
284 const pb::Styleable& pbStyleable = pbCompoundValue.styleable();
285 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
286 for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) {
287 Reference attrRef;
288 deserializeItemCommon(pbEntry, &attrRef);
289 deserializeReferenceFromPb(pbEntry.attr(), &attrRef);
290 styleable->entries.push_back(std::move(attrRef));
291 }
292 value = std::move(styleable);
293
294 } else if (pbCompoundValue.has_array()) {
295 const pb::Array& pbArray = pbCompoundValue.array();
296 std::unique_ptr<Array> array = util::make_unique<Array>();
297 for (const pb::Array_Entry& pbEntry : pbArray.entries()) {
298 std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config,
299 pool);
300 if (!item) {
301 return {};
302 }
303
304 deserializeItemCommon(pbEntry, item.get());
305 array->items.push_back(std::move(item));
306 }
307 value = std::move(array);
308
309 } else if (pbCompoundValue.has_plural()) {
310 const pb::Plural& pbPlural = pbCompoundValue.plural();
311 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
312 for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) {
313 size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity());
314 plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config,
315 pool);
316 if (!plural->values[pluralIdx]) {
317 return {};
318 }
319
320 deserializeItemCommon(pbEntry, plural->values[pluralIdx].get());
321 }
322 value = std::move(plural);
323
324 } else {
325 mDiag->error(DiagMessage(mSource) << "unknown compound value");
326 return {};
327 }
328 } else {
329 mDiag->error(DiagMessage(mSource) << "unknown value");
330 return {};
331 }
332
333 assert(value && "forgot to set value");
334
335 value->setWeak(isWeak);
336 deserializeItemCommon(pbValue, value.get());
337 return value;
338 }
339
340 bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) {
341 outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type());
342 outRef->privateReference = pbRef.private_();
343
344 if (!pbRef.has_id() && !pbRef.has_symbol_idx()) {
345 return false;
346 }
347
348 if (pbRef.has_id()) {
349 outRef->id = ResourceId(pbRef.id());
350 }
351
352 if (pbRef.has_symbol_idx()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700353 const std::string strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx());
Adam Lesinski59e04c62016-02-04 15:59:23 -0800354 ResourceNameRef nameRef;
355 if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) {
356 mDiag->error(DiagMessage(mSource) << "invalid reference name '"
357 << strSymbol << "'");
358 return false;
359 }
360
361 outRef->name = nameRef.toResourceName();
362 }
363 return true;
364 }
365
366 template <typename T>
367 void deserializeItemCommon(const T& pbItem, Value* outValue) {
368 if (pbItem.has_source()) {
369 Source source;
370 deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source);
371 outValue->setSource(std::move(source));
372 }
373
374 if (pbItem.has_comment()) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700375 outValue->setComment(pbItem.comment());
Adam Lesinski59e04c62016-02-04 15:59:23 -0800376 }
377 }
378
379private:
380 const android::ResStringPool* mValuePool;
381 const android::ResStringPool* mSourcePool;
382 const android::ResStringPool* mSymbolPool;
383 const Source mSource;
384 IDiagnostics* mDiag;
385};
386
387} // namespace
388
389std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable,
390 const Source& source,
391 IDiagnostics* diag) {
Adam Lesinski803c7c82016-04-06 16:09:43 -0700392 // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
393 // causes errors when qualifying it with android::
394 using namespace android;
395
Adam Lesinski59e04c62016-02-04 15:59:23 -0800396 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
397
398 if (!pbTable.has_string_pool()) {
399 diag->error(DiagMessage(source) << "no string pool found");
400 return {};
401 }
402
Adam Lesinski803c7c82016-04-06 16:09:43 -0700403 ResStringPool valuePool;
404 status_t result = valuePool.setTo(pbTable.string_pool().data().data(),
405 pbTable.string_pool().data().size());
406 if (result != NO_ERROR) {
Adam Lesinski59e04c62016-02-04 15:59:23 -0800407 diag->error(DiagMessage(source) << "invalid string pool");
408 return {};
409 }
410
Adam Lesinski803c7c82016-04-06 16:09:43 -0700411 ResStringPool sourcePool;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800412 if (pbTable.has_source_pool()) {
413 result = sourcePool.setTo(pbTable.source_pool().data().data(),
414 pbTable.source_pool().data().size());
Adam Lesinski803c7c82016-04-06 16:09:43 -0700415 if (result != NO_ERROR) {
Adam Lesinski59e04c62016-02-04 15:59:23 -0800416 diag->error(DiagMessage(source) << "invalid source pool");
417 return {};
418 }
419 }
420
Adam Lesinski803c7c82016-04-06 16:09:43 -0700421 ResStringPool symbolPool;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800422 if (pbTable.has_symbol_pool()) {
423 result = symbolPool.setTo(pbTable.symbol_pool().data().data(),
424 pbTable.symbol_pool().data().size());
Adam Lesinski803c7c82016-04-06 16:09:43 -0700425 if (result != NO_ERROR) {
Adam Lesinski59e04c62016-02-04 15:59:23 -0800426 diag->error(DiagMessage(source) << "invalid symbol pool");
427 return {};
428 }
429 }
430
431 PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag);
432 for (const pb::Package& pbPackage : pbTable.packages()) {
433 if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) {
434 return {};
435 }
436 }
437 return table;
438}
439
440std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile,
441 const Source& source,
442 IDiagnostics* diag) {
443 std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
444
445 ResourceNameRef nameRef;
446
447 // Need to create an lvalue here so that nameRef can point to something real.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700448 if (!ResourceUtils::parseResourceName(pbFile.resource_name(), &nameRef)) {
Adam Lesinski59e04c62016-02-04 15:59:23 -0800449 diag->error(DiagMessage(source) << "invalid resource name in compiled file header: "
450 << pbFile.resource_name());
451 return {};
452 }
453 file->name = nameRef.toResourceName();
454 file->source.path = pbFile.source_path();
455 deserializeConfigDescriptionFromPb(pbFile.config(), &file->config);
456
457 for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) {
458 // Need to create an lvalue here so that nameRef can point to something real.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700459 if (!ResourceUtils::parseResourceName(pbSymbol.resource_name(), &nameRef)) {
Adam Lesinski59e04c62016-02-04 15:59:23 -0800460 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
Adam Lesinski59e04c62016-02-04 15:59:23 -0800471} // namespace aapt