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 "proto/ProtoSerialize.h"
18 
19 #include "android-base/logging.h"
20 #include "androidfw/ResourceTypes.h"
21 
22 #include "ResourceTable.h"
23 #include "ResourceUtils.h"
24 #include "ValueVisitor.h"
25 #include "proto/ProtoHelpers.h"
26 
27 namespace aapt {
28 
29 namespace {
30 
31 class ReferenceIdToNameVisitor : public ValueVisitor {
32  public:
33   using ValueVisitor::Visit;
34 
ReferenceIdToNameVisitor(const std::map<ResourceId,ResourceNameRef> * mapping)35   explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
36       : mapping_(mapping) {
37     CHECK(mapping_ != nullptr);
38   }
39 
Visit(Reference * reference)40   void Visit(Reference* reference) override {
41     if (!reference->id || !reference->id.value().is_valid()) {
42       return;
43     }
44 
45     ResourceId id = reference->id.value();
46     auto cache_iter = mapping_->find(id);
47     if (cache_iter != mapping_->end()) {
48       reference->name = cache_iter->second.ToResourceName();
49     }
50   }
51 
52  private:
53   const std::map<ResourceId, ResourceNameRef>* mapping_;
54 };
55 
56 class PackagePbDeserializer {
57  public:
PackagePbDeserializer(const android::ResStringPool * valuePool,const android::ResStringPool * sourcePool,const android::ResStringPool * symbolPool,const Source & source,IDiagnostics * diag)58   PackagePbDeserializer(const android::ResStringPool* valuePool,
59                         const android::ResStringPool* sourcePool,
60                         const android::ResStringPool* symbolPool,
61                         const Source& source, IDiagnostics* diag)
62       : value_pool_(valuePool),
63         source_pool_(sourcePool),
64         symbol_pool_(symbolPool),
65         source_(source),
66         diag_(diag) {}
67 
68  public:
DeserializeFromPb(const pb::Package & pbPackage,ResourceTable * table)69   bool DeserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) {
70     Maybe<uint8_t> id;
71     if (pbPackage.has_package_id()) {
72       id = static_cast<uint8_t>(pbPackage.package_id());
73     }
74 
75     std::map<ResourceId, ResourceNameRef> idIndex;
76 
77     ResourceTablePackage* pkg = table->CreatePackage(pbPackage.package_name(), id);
78     for (const pb::Type& pbType : pbPackage.types()) {
79       const ResourceType* resType = ParseResourceType(pbType.name());
80       if (!resType) {
81         diag_->Error(DiagMessage(source_) << "unknown type '" << pbType.name() << "'");
82         return {};
83       }
84 
85       ResourceTableType* type = pkg->FindOrCreateType(*resType);
86 
87       for (const pb::Entry& pbEntry : pbType.entries()) {
88         ResourceEntry* entry = type->FindOrCreateEntry(pbEntry.name());
89 
90         // Deserialize the symbol status (public/private with source and
91         // comments).
92         if (pbEntry.has_symbol_status()) {
93           const pb::SymbolStatus& pbStatus = pbEntry.symbol_status();
94           if (pbStatus.has_source()) {
95             DeserializeSourceFromPb(pbStatus.source(), *source_pool_, &entry->symbol_status.source);
96           }
97 
98           if (pbStatus.has_comment()) {
99             entry->symbol_status.comment = pbStatus.comment();
100           }
101 
102           entry->symbol_status.allow_new = pbStatus.allow_new();
103 
104           SymbolState visibility = DeserializeVisibilityFromPb(pbStatus.visibility());
105           entry->symbol_status.state = visibility;
106 
107           if (visibility == SymbolState::kPublic) {
108             // This is a public symbol, we must encode the ID now if there is one.
109             if (pbEntry.has_id()) {
110               entry->id = static_cast<uint16_t>(pbEntry.id());
111             }
112 
113             if (type->symbol_status.state != SymbolState::kPublic) {
114               // If the type has not been made public, do so now.
115               type->symbol_status.state = SymbolState::kPublic;
116               if (pbType.has_id()) {
117                 type->id = static_cast<uint8_t>(pbType.id());
118               }
119             }
120           } else if (visibility == SymbolState::kPrivate) {
121             if (type->symbol_status.state == SymbolState::kUndefined) {
122               type->symbol_status.state = SymbolState::kPrivate;
123             }
124           }
125         }
126 
127         ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id());
128         if (resId.is_valid()) {
129           idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name);
130         }
131 
132         for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) {
133           const pb::ConfigDescription& pbConfig = pbConfigValue.config();
134 
135           ConfigDescription config;
136           if (!DeserializeConfigDescriptionFromPb(pbConfig, &config)) {
137             diag_->Error(DiagMessage(source_) << "invalid configuration");
138             return {};
139           }
140 
141           ResourceConfigValue* configValue = entry->FindOrCreateValue(config, pbConfig.product());
142           if (configValue->value) {
143             // Duplicate config.
144             diag_->Error(DiagMessage(source_) << "duplicate configuration");
145             return {};
146           }
147 
148           configValue->value =
149               DeserializeValueFromPb(pbConfigValue.value(), config, &table->string_pool);
150           if (!configValue->value) {
151             return {};
152           }
153         }
154       }
155     }
156 
157     ReferenceIdToNameVisitor visitor(&idIndex);
158     VisitAllValuesInPackage(pkg, &visitor);
159     return true;
160   }
161 
162  private:
DeserializeItemFromPb(const pb::Item & pb_item,const ConfigDescription & config,StringPool * pool)163   std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
164                                               const ConfigDescription& config,
165                                               StringPool* pool) {
166     if (pb_item.has_ref()) {
167       const pb::Reference& pb_ref = pb_item.ref();
168       std::unique_ptr<Reference> ref = util::make_unique<Reference>();
169       if (!DeserializeReferenceFromPb(pb_ref, ref.get())) {
170         return {};
171       }
172       return std::move(ref);
173 
174     } else if (pb_item.has_prim()) {
175       const pb::Primitive& pb_prim = pb_item.prim();
176       android::Res_value prim = {};
177       prim.dataType = static_cast<uint8_t>(pb_prim.type());
178       prim.data = pb_prim.data();
179       return util::make_unique<BinaryPrimitive>(prim);
180 
181     } else if (pb_item.has_id()) {
182       return util::make_unique<Id>();
183 
184     } else if (pb_item.has_str()) {
185       const uint32_t idx = pb_item.str().idx();
186       const std::string str = util::GetString(*value_pool_, idx);
187 
188       const android::ResStringPool_span* spans = value_pool_->styleAt(idx);
189       if (spans && spans->name.index != android::ResStringPool_span::END) {
190         StyleString style_str = {str};
191         while (spans->name.index != android::ResStringPool_span::END) {
192           style_str.spans.push_back(
193               Span{util::GetString(*value_pool_, spans->name.index),
194                    spans->firstChar, spans->lastChar});
195           spans++;
196         }
197         return util::make_unique<StyledString>(pool->MakeRef(
198             style_str,
199             StringPool::Context(StringPool::Context::kStylePriority, config)));
200       }
201       return util::make_unique<String>(
202           pool->MakeRef(str, StringPool::Context(config)));
203 
204     } else if (pb_item.has_raw_str()) {
205       const uint32_t idx = pb_item.raw_str().idx();
206       const std::string str = util::GetString(*value_pool_, idx);
207       return util::make_unique<RawString>(
208           pool->MakeRef(str, StringPool::Context(config)));
209 
210     } else if (pb_item.has_file()) {
211       const uint32_t idx = pb_item.file().path_idx();
212       const std::string str = util::GetString(*value_pool_, idx);
213       return util::make_unique<FileReference>(pool->MakeRef(
214           str,
215           StringPool::Context(StringPool::Context::kHighPriority, config)));
216 
217     } else {
218       diag_->Error(DiagMessage(source_) << "unknown item");
219     }
220     return {};
221   }
222 
DeserializeValueFromPb(const pb::Value & pb_value,const ConfigDescription & config,StringPool * pool)223   std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
224                                                 const ConfigDescription& config,
225                                                 StringPool* pool) {
226     const bool is_weak = pb_value.has_weak() ? pb_value.weak() : false;
227 
228     std::unique_ptr<Value> value;
229     if (pb_value.has_item()) {
230       value = DeserializeItemFromPb(pb_value.item(), config, pool);
231       if (!value) {
232         return {};
233       }
234 
235     } else if (pb_value.has_compound_value()) {
236       const pb::CompoundValue& pb_compound_value = pb_value.compound_value();
237       if (pb_compound_value.has_attr()) {
238         const pb::Attribute& pb_attr = pb_compound_value.attr();
239         std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
240         attr->type_mask = pb_attr.format_flags();
241         attr->min_int = pb_attr.min_int();
242         attr->max_int = pb_attr.max_int();
243         for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbols()) {
244           Attribute::Symbol symbol;
245           DeserializeItemCommon(pb_symbol, &symbol.symbol);
246           if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol)) {
247             return {};
248           }
249           symbol.value = pb_symbol.value();
250           attr->symbols.push_back(std::move(symbol));
251         }
252         value = std::move(attr);
253 
254       } else if (pb_compound_value.has_style()) {
255         const pb::Style& pb_style = pb_compound_value.style();
256         std::unique_ptr<Style> style = util::make_unique<Style>();
257         if (pb_style.has_parent()) {
258           style->parent = Reference();
259           if (!DeserializeReferenceFromPb(pb_style.parent(),
260                                           &style->parent.value())) {
261             return {};
262           }
263 
264           if (pb_style.has_parent_source()) {
265             Source parent_source;
266             DeserializeSourceFromPb(pb_style.parent_source(), *source_pool_,
267                                     &parent_source);
268             style->parent.value().SetSource(std::move(parent_source));
269           }
270         }
271 
272         for (const pb::Style_Entry& pb_entry : pb_style.entries()) {
273           Style::Entry entry;
274           DeserializeItemCommon(pb_entry, &entry.key);
275           if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key)) {
276             return {};
277           }
278 
279           entry.value = DeserializeItemFromPb(pb_entry.item(), config, pool);
280           if (!entry.value) {
281             return {};
282           }
283 
284           DeserializeItemCommon(pb_entry, entry.value.get());
285           style->entries.push_back(std::move(entry));
286         }
287         value = std::move(style);
288 
289       } else if (pb_compound_value.has_styleable()) {
290         const pb::Styleable& pb_styleable = pb_compound_value.styleable();
291         std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
292         for (const pb::Styleable_Entry& pb_entry : pb_styleable.entries()) {
293           Reference attr_ref;
294           DeserializeItemCommon(pb_entry, &attr_ref);
295           DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref);
296           styleable->entries.push_back(std::move(attr_ref));
297         }
298         value = std::move(styleable);
299 
300       } else if (pb_compound_value.has_array()) {
301         const pb::Array& pb_array = pb_compound_value.array();
302         std::unique_ptr<Array> array = util::make_unique<Array>();
303         for (const pb::Array_Entry& pb_entry : pb_array.entries()) {
304           std::unique_ptr<Item> item =
305               DeserializeItemFromPb(pb_entry.item(), config, pool);
306           if (!item) {
307             return {};
308           }
309 
310           DeserializeItemCommon(pb_entry, item.get());
311           array->items.push_back(std::move(item));
312         }
313         value = std::move(array);
314 
315       } else if (pb_compound_value.has_plural()) {
316         const pb::Plural& pb_plural = pb_compound_value.plural();
317         std::unique_ptr<Plural> plural = util::make_unique<Plural>();
318         for (const pb::Plural_Entry& pb_entry : pb_plural.entries()) {
319           size_t pluralIdx = DeserializePluralEnumFromPb(pb_entry.arity());
320           plural->values[pluralIdx] =
321               DeserializeItemFromPb(pb_entry.item(), config, pool);
322           if (!plural->values[pluralIdx]) {
323             return {};
324           }
325 
326           DeserializeItemCommon(pb_entry, plural->values[pluralIdx].get());
327         }
328         value = std::move(plural);
329 
330       } else {
331         diag_->Error(DiagMessage(source_) << "unknown compound value");
332         return {};
333       }
334     } else {
335       diag_->Error(DiagMessage(source_) << "unknown value");
336       return {};
337     }
338 
339     CHECK(value) << "forgot to set value";
340 
341     value->SetWeak(is_weak);
342     DeserializeItemCommon(pb_value, value.get());
343     return value;
344   }
345 
DeserializeReferenceFromPb(const pb::Reference & pb_ref,Reference * out_ref)346   bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref) {
347     out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type());
348     out_ref->private_reference = pb_ref.private_();
349 
350     if (pb_ref.has_id()) {
351       out_ref->id = ResourceId(pb_ref.id());
352     }
353 
354     if (pb_ref.has_symbol_idx()) {
355       const std::string str_symbol = util::GetString(*symbol_pool_, pb_ref.symbol_idx());
356       ResourceNameRef name_ref;
357       if (!ResourceUtils::ParseResourceName(str_symbol, &name_ref, nullptr)) {
358         diag_->Error(DiagMessage(source_) << "invalid reference name '" << str_symbol << "'");
359         return false;
360       }
361 
362       out_ref->name = name_ref.ToResourceName();
363     }
364     return true;
365   }
366 
367   template <typename T>
DeserializeItemCommon(const T & pb_item,Value * out_value)368   void DeserializeItemCommon(const T& pb_item, Value* out_value) {
369     if (pb_item.has_source()) {
370       Source source;
371       DeserializeSourceFromPb(pb_item.source(), *source_pool_, &source);
372       out_value->SetSource(std::move(source));
373     }
374 
375     if (pb_item.has_comment()) {
376       out_value->SetComment(pb_item.comment());
377     }
378   }
379 
380  private:
381   const android::ResStringPool* value_pool_;
382   const android::ResStringPool* source_pool_;
383   const android::ResStringPool* symbol_pool_;
384   const Source source_;
385   IDiagnostics* diag_;
386 };
387 
388 }  // namespace
389 
DeserializeTableFromPb(const pb::ResourceTable & pb_table,const Source & source,IDiagnostics * diag)390 std::unique_ptr<ResourceTable> DeserializeTableFromPb(
391     const pb::ResourceTable& pb_table, const Source& source,
392     IDiagnostics* diag) {
393   // We import the android namespace because on Windows NO_ERROR is a macro, not
394   // an enum, which
395   // causes errors when qualifying it with android::
396   using namespace android;
397 
398   std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
399 
400   if (!pb_table.has_string_pool()) {
401     diag->Error(DiagMessage(source) << "no string pool found");
402     return {};
403   }
404 
405   ResStringPool value_pool;
406   status_t result = value_pool.setTo(pb_table.string_pool().data().data(),
407                                      pb_table.string_pool().data().size());
408   if (result != NO_ERROR) {
409     diag->Error(DiagMessage(source) << "invalid string pool");
410     return {};
411   }
412 
413   ResStringPool source_pool;
414   if (pb_table.has_source_pool()) {
415     result = source_pool.setTo(pb_table.source_pool().data().data(),
416                                pb_table.source_pool().data().size());
417     if (result != NO_ERROR) {
418       diag->Error(DiagMessage(source) << "invalid source pool");
419       return {};
420     }
421   }
422 
423   ResStringPool symbol_pool;
424   if (pb_table.has_symbol_pool()) {
425     result = symbol_pool.setTo(pb_table.symbol_pool().data().data(),
426                                pb_table.symbol_pool().data().size());
427     if (result != NO_ERROR) {
428       diag->Error(DiagMessage(source) << "invalid symbol pool");
429       return {};
430     }
431   }
432 
433   PackagePbDeserializer package_pb_deserializer(&value_pool, &source_pool,
434                                                 &symbol_pool, source, diag);
435   for (const pb::Package& pb_package : pb_table.packages()) {
436     if (!package_pb_deserializer.DeserializeFromPb(pb_package, table.get())) {
437       return {};
438     }
439   }
440   return table;
441 }
442 
DeserializeCompiledFileFromPb(const pb::CompiledFile & pb_file,const Source & source,IDiagnostics * diag)443 std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb(
444     const pb::CompiledFile& pb_file, const Source& source, IDiagnostics* diag) {
445   std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
446 
447   ResourceNameRef name_ref;
448 
449   // Need to create an lvalue here so that nameRef can point to something real.
450   if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) {
451     diag->Error(DiagMessage(source)
452                 << "invalid resource name in compiled file header: "
453                 << pb_file.resource_name());
454     return {};
455   }
456   file->name = name_ref.ToResourceName();
457   file->source.path = pb_file.source_path();
458   DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config);
459 
460   for (const pb::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbols()) {
461     // Need to create an lvalue here so that nameRef can point to something
462     // real.
463     if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(),
464                                           &name_ref)) {
465       diag->Error(DiagMessage(source)
466                   << "invalid resource name for exported symbol in "
467                      "compiled file header: "
468                   << pb_file.resource_name());
469       return {};
470     }
471     file->exported_symbols.push_back(
472         SourcedResourceName{name_ref.ToResourceName(), pb_symbol.line_no()});
473   }
474   return file;
475 }
476 
477 }  // namespace aapt
478