• 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                 for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) {
238                     Attribute::Symbol symbol;
239                     deserializeItemCommon(pbSymbol, &symbol.symbol);
240                     if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) {
241                         return {};
242                     }
243                     symbol.value = pbSymbol.value();
244                     attr->symbols.push_back(std::move(symbol));
245                 }
246                 value = std::move(attr);
247 
248             } else if (pbCompoundValue.has_style()) {
249                 const pb::Style& pbStyle = pbCompoundValue.style();
250                 std::unique_ptr<Style> style = util::make_unique<Style>();
251                 if (pbStyle.has_parent()) {
252                     style->parent = Reference();
253                     if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) {
254                         return {};
255                     }
256 
257                     if (pbStyle.has_parent_source()) {
258                         Source parentSource;
259                         deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool,
260                                                 &parentSource);
261                         style->parent.value().setSource(std::move(parentSource));
262                     }
263                 }
264 
265                 for (const pb::Style_Entry& pbEntry : pbStyle.entries()) {
266                     Style::Entry entry;
267                     deserializeItemCommon(pbEntry, &entry.key);
268                     if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) {
269                         return {};
270                     }
271 
272                     entry.value = deserializeItemFromPb(pbEntry.item(), config, pool);
273                     if (!entry.value) {
274                         return {};
275                     }
276 
277                     deserializeItemCommon(pbEntry, entry.value.get());
278                     style->entries.push_back(std::move(entry));
279                 }
280                 value = std::move(style);
281 
282             } else if (pbCompoundValue.has_styleable()) {
283                 const pb::Styleable& pbStyleable = pbCompoundValue.styleable();
284                 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
285                 for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) {
286                     Reference attrRef;
287                     deserializeItemCommon(pbEntry, &attrRef);
288                     deserializeReferenceFromPb(pbEntry.attr(), &attrRef);
289                     styleable->entries.push_back(std::move(attrRef));
290                 }
291                 value = std::move(styleable);
292 
293             } else if (pbCompoundValue.has_array()) {
294                 const pb::Array& pbArray = pbCompoundValue.array();
295                 std::unique_ptr<Array> array = util::make_unique<Array>();
296                 for (const pb::Array_Entry& pbEntry : pbArray.entries()) {
297                     std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config,
298                                                                        pool);
299                     if (!item) {
300                         return {};
301                     }
302 
303                     deserializeItemCommon(pbEntry, item.get());
304                     array->items.push_back(std::move(item));
305                 }
306                 value = std::move(array);
307 
308             } else if (pbCompoundValue.has_plural()) {
309                 const pb::Plural& pbPlural = pbCompoundValue.plural();
310                 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
311                 for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) {
312                     size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity());
313                     plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config,
314                                                                       pool);
315                     if (!plural->values[pluralIdx]) {
316                         return {};
317                     }
318 
319                     deserializeItemCommon(pbEntry, plural->values[pluralIdx].get());
320                 }
321                 value = std::move(plural);
322 
323             } else {
324                 mDiag->error(DiagMessage(mSource) << "unknown compound value");
325                 return {};
326             }
327         } else {
328             mDiag->error(DiagMessage(mSource) << "unknown value");
329             return {};
330         }
331 
332         assert(value && "forgot to set value");
333 
334         value->setWeak(isWeak);
335         deserializeItemCommon(pbValue, value.get());
336         return value;
337     }
338 
deserializeReferenceFromPb(const pb::Reference & pbRef,Reference * outRef)339     bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) {
340         outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type());
341         outRef->privateReference = pbRef.private_();
342 
343         if (!pbRef.has_id() && !pbRef.has_symbol_idx()) {
344             return false;
345         }
346 
347         if (pbRef.has_id()) {
348             outRef->id = ResourceId(pbRef.id());
349         }
350 
351         if (pbRef.has_symbol_idx()) {
352             StringPiece16 strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx());
353             ResourceNameRef nameRef;
354             if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) {
355                 mDiag->error(DiagMessage(mSource) << "invalid reference name '"
356                              << strSymbol << "'");
357                 return false;
358             }
359 
360             outRef->name = nameRef.toResourceName();
361         }
362         return true;
363     }
364 
365     template <typename T>
deserializeItemCommon(const T & pbItem,Value * outValue)366     void deserializeItemCommon(const T& pbItem, Value* outValue) {
367         if (pbItem.has_source()) {
368             Source source;
369             deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source);
370             outValue->setSource(std::move(source));
371         }
372 
373         if (pbItem.has_comment()) {
374             outValue->setComment(util::utf8ToUtf16(pbItem.comment()));
375         }
376     }
377 
378 private:
379     const android::ResStringPool* mValuePool;
380     const android::ResStringPool* mSourcePool;
381     const android::ResStringPool* mSymbolPool;
382     const Source mSource;
383     IDiagnostics* mDiag;
384 };
385 
386 } // namespace
387 
deserializeTableFromPb(const pb::ResourceTable & pbTable,const Source & source,IDiagnostics * diag)388 std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable,
389                                                       const Source& source,
390                                                       IDiagnostics* diag) {
391     // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
392     // causes errors when qualifying it with android::
393     using namespace android;
394 
395     std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
396 
397     if (!pbTable.has_string_pool()) {
398         diag->error(DiagMessage(source) << "no string pool found");
399         return {};
400     }
401 
402     ResStringPool valuePool;
403     status_t result = valuePool.setTo(pbTable.string_pool().data().data(),
404                                       pbTable.string_pool().data().size());
405     if (result != NO_ERROR) {
406         diag->error(DiagMessage(source) << "invalid string pool");
407         return {};
408     }
409 
410     ResStringPool sourcePool;
411     if (pbTable.has_source_pool()) {
412         result = sourcePool.setTo(pbTable.source_pool().data().data(),
413                                   pbTable.source_pool().data().size());
414         if (result != NO_ERROR) {
415             diag->error(DiagMessage(source) << "invalid source pool");
416             return {};
417         }
418     }
419 
420     ResStringPool symbolPool;
421     if (pbTable.has_symbol_pool()) {
422         result = symbolPool.setTo(pbTable.symbol_pool().data().data(),
423                                   pbTable.symbol_pool().data().size());
424         if (result != NO_ERROR) {
425             diag->error(DiagMessage(source) << "invalid symbol pool");
426             return {};
427         }
428     }
429 
430     PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag);
431     for (const pb::Package& pbPackage : pbTable.packages()) {
432         if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) {
433             return {};
434         }
435     }
436     return table;
437 }
438 
deserializeCompiledFileFromPb(const pb::CompiledFile & pbFile,const Source & source,IDiagnostics * diag)439 std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile,
440                                                             const Source& source,
441                                                             IDiagnostics* diag) {
442     std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
443 
444     ResourceNameRef nameRef;
445 
446     // Need to create an lvalue here so that nameRef can point to something real.
447     std::u16string utf16Name = util::utf8ToUtf16(pbFile.resource_name());
448     if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
449         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.
459         utf16Name = util::utf8ToUtf16(pbSymbol.resource_name());
460         if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
461             diag->error(DiagMessage(source) << "invalid resource name for exported symbol in "
462                                                "compiled file header: "
463                                             << pbFile.resource_name());
464             return {};
465         }
466         file->exportedSymbols.push_back(
467                 SourcedResourceName{ nameRef.toResourceName(), pbSymbol.line_no() });
468     }
469     return file;
470 }
471 
CompiledFileInputStream(const void * data,size_t size)472 CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) :
473         mIn(static_cast<const uint8_t*>(data), size), mPbFile(),
474         mData(static_cast<const uint8_t*>(data)), mSize(size) {
475 }
476 
CompiledFile()477 const pb::CompiledFile* CompiledFileInputStream::CompiledFile() {
478     if (!mPbFile) {
479         std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
480         uint64_t pbSize = 0u;
481         if (!mIn.ReadLittleEndian64(&pbSize)) {
482             return nullptr;
483         }
484         mIn.PushLimit(static_cast<int>(pbSize));
485         if (!pbFile->ParsePartialFromCodedStream(&mIn)) {
486             return nullptr;
487         }
488 
489         const size_t padding = 4 - (pbSize & 0x03);
490         const size_t offset = sizeof(uint64_t) + pbSize + padding;
491         if (offset > mSize) {
492             return nullptr;
493         }
494 
495         mData += offset;
496         mSize -= offset;
497         mPbFile = std::move(pbFile);
498     }
499     return mPbFile.get();
500 }
501 
data()502 const void* CompiledFileInputStream::data() {
503     if (!mPbFile) {
504         if (!CompiledFile()) {
505             return nullptr;
506         }
507     }
508     return mData;
509 }
510 
size()511 size_t CompiledFileInputStream::size() {
512     if (!mPbFile) {
513         if (!CompiledFile()) {
514             return 0;
515         }
516     }
517     return mSize;
518 }
519 
520 } // namespace aapt
521