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