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
27namespace aapt {
28
29namespace {
30
31class ReferenceIdToNameVisitor : public ValueVisitor {
32 public:
33  using ValueVisitor::Visit;
34
35  explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
36      : mapping_(mapping) {
37    CHECK(mapping_ != nullptr);
38  }
39
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
56class PackagePbDeserializer {
57 public:
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:
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:
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
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
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>
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
390std::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
443std::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