diff options
| -rw-r--r-- | tools/aapt2/ResourceParser.cpp | 7 | ||||
| -rw-r--r-- | tools/aapt2/StringPool.h | 17 | ||||
| -rw-r--r-- | tools/aapt2/flatten/XmlFlattener.cpp | 4 | ||||
| -rw-r--r-- | tools/aapt2/proto/TableProtoDeserializer.cpp | 791 | ||||
| -rw-r--r-- | tools/aapt2/unflatten/BinaryResourceParser.cpp | 978 |
5 files changed, 923 insertions, 874 deletions
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 51aed135a39e..7d50e1d38816 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -533,7 +533,8 @@ std::unique_ptr<Item> ResourceParser::parseXml(xml::XmlPullParser* parser, if (!styleString.spans.empty()) { // This can only be a StyledString. return util::make_unique<StyledString>(mTable->stringPool.makeRef( - styleString, StringPool::Context{1, mConfig})); + styleString, + StringPool::Context(StringPool::Context::kStylePriority, mConfig))); } auto onCreateReference = [&](const ResourceName& name) { @@ -559,13 +560,13 @@ std::unique_ptr<Item> ResourceParser::parseXml(xml::XmlPullParser* parser, if (typeMask & android::ResTable_map::TYPE_STRING) { // Use the trimmed, escaped string. return util::make_unique<String>(mTable->stringPool.makeRef( - styleString.str, StringPool::Context{1, mConfig})); + styleString.str, StringPool::Context(mConfig))); } if (allowRawValue) { // We can't parse this so return a RawString if we are allowed. return util::make_unique<RawString>( - mTable->stringPool.makeRef(rawValue, StringPool::Context{1, mConfig})); + mTable->stringPool.makeRef(rawValue, StringPool::Context(mConfig))); } return {}; } diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h index 05c26e7e4ea1..6e0d646cae12 100644 --- a/tools/aapt2/StringPool.h +++ b/tools/aapt2/StringPool.h @@ -42,9 +42,22 @@ struct StyleString { class StringPool { public: - struct Context { - uint32_t priority; + class Context { + public: + enum : uint32_t { + kStylePriority = 0u, + kHighPriority = 1u, + kNormalPriority = 0x7fffffffu, + kLowPriority = 0xffffffffu, + }; + uint32_t priority = kNormalPriority; ConfigDescription config; + + Context() = default; + Context(uint32_t p, const ConfigDescription& c) : priority(p), config(c) {} + explicit Context(uint32_t p) : priority(p) {} + explicit Context(const ConfigDescription& c) + : priority(kNormalPriority), config(c) {} }; class Entry; diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/flatten/XmlFlattener.cpp index c296dde0ca1e..b1536d5f21d2 100644 --- a/tools/aapt2/flatten/XmlFlattener.cpp +++ b/tools/aapt2/flatten/XmlFlattener.cpp @@ -63,7 +63,7 @@ struct XmlFlattenerVisitor : public xml::Visitor { dest->index = util::deviceToHost32(-1); } else { mStringRefs.push_back(StringFlattenDest{ - mPool.makeRef(str, StringPool::Context{priority}), dest}); + mPool.makeRef(str, StringPool::Context(priority)), dest}); } } @@ -256,7 +256,7 @@ struct XmlFlattenerVisitor : public xml::Visitor { StringPool::Ref nameRef = mPackagePools[aaptAttr.id.value().packageId()].makeRef( - xmlAttr->name, StringPool::Context{aaptAttr.id.value().id}); + xmlAttr->name, StringPool::Context(aaptAttr.id.value().id)); // Add it to the list of strings to flatten. addString(nameRef, &flatAttr->name); diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp index 595fa6f29fac..0dfb01c181c6 100644 --- a/tools/aapt2/proto/TableProtoDeserializer.cpp +++ b/tools/aapt2/proto/TableProtoDeserializer.cpp @@ -27,445 +27,460 @@ namespace aapt { namespace { class ReferenceIdToNameVisitor : public ValueVisitor { -public: - using ValueVisitor::visit; - - explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) : - mMapping(mapping) { - assert(mMapping); + public: + using ValueVisitor::visit; + + explicit ReferenceIdToNameVisitor( + const std::map<ResourceId, ResourceNameRef>* mapping) + : mMapping(mapping) { + assert(mMapping); + } + + void visit(Reference* reference) override { + if (!reference->id || !reference->id.value().isValid()) { + return; } - void visit(Reference* reference) override { - if (!reference->id || !reference->id.value().isValid()) { - return; - } - - ResourceId id = reference->id.value(); - auto cacheIter = mMapping->find(id); - if (cacheIter != mMapping->end()) { - reference->name = cacheIter->second.toResourceName(); - } + ResourceId id = reference->id.value(); + auto cacheIter = mMapping->find(id); + if (cacheIter != mMapping->end()) { + reference->name = cacheIter->second.toResourceName(); } + } -private: - const std::map<ResourceId, ResourceNameRef>* mMapping; + private: + const std::map<ResourceId, ResourceNameRef>* mMapping; }; class PackagePbDeserializer { -public: - PackagePbDeserializer(const android::ResStringPool* valuePool, - const android::ResStringPool* sourcePool, - const android::ResStringPool* symbolPool, - const Source& source, IDiagnostics* diag) : - mValuePool(valuePool), mSourcePool(sourcePool), mSymbolPool(symbolPool), - mSource(source), mDiag(diag) { + public: + PackagePbDeserializer(const android::ResStringPool* valuePool, + const android::ResStringPool* sourcePool, + const android::ResStringPool* symbolPool, + const Source& source, IDiagnostics* diag) + : mValuePool(valuePool), + mSourcePool(sourcePool), + mSymbolPool(symbolPool), + mSource(source), + mDiag(diag) {} + + public: + bool deserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) { + Maybe<uint8_t> id; + if (pbPackage.has_package_id()) { + id = static_cast<uint8_t>(pbPackage.package_id()); } -public: - bool deserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) { - Maybe<uint8_t> id; - if (pbPackage.has_package_id()) { - id = static_cast<uint8_t>(pbPackage.package_id()); - } - - std::map<ResourceId, ResourceNameRef> idIndex; + std::map<ResourceId, ResourceNameRef> idIndex; - ResourceTablePackage* pkg = table->createPackage(pbPackage.package_name(), id); - for (const pb::Type& pbType : pbPackage.types()) { - const ResourceType* resType = parseResourceType(pbType.name()); - if (!resType) { - mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() << "'"); - return {}; + ResourceTablePackage* pkg = + table->createPackage(pbPackage.package_name(), id); + for (const pb::Type& pbType : pbPackage.types()) { + const ResourceType* resType = parseResourceType(pbType.name()); + if (!resType) { + mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() + << "'"); + return {}; + } + + ResourceTableType* type = pkg->findOrCreateType(*resType); + + for (const pb::Entry& pbEntry : pbType.entries()) { + ResourceEntry* entry = type->findOrCreateEntry(pbEntry.name()); + + // Deserialize the symbol status (public/private with source and + // comments). + if (pbEntry.has_symbol_status()) { + const pb::SymbolStatus& pbStatus = pbEntry.symbol_status(); + if (pbStatus.has_source()) { + deserializeSourceFromPb(pbStatus.source(), *mSourcePool, + &entry->symbolStatus.source); + } + + if (pbStatus.has_comment()) { + entry->symbolStatus.comment = pbStatus.comment(); + } + + SymbolState visibility = + deserializeVisibilityFromPb(pbStatus.visibility()); + entry->symbolStatus.state = visibility; + + if (visibility == SymbolState::kPublic) { + // This is a public symbol, we must encode the ID now if there is + // one. + if (pbEntry.has_id()) { + entry->id = static_cast<uint16_t>(pbEntry.id()); } - ResourceTableType* type = pkg->findOrCreateType(*resType); - - for (const pb::Entry& pbEntry : pbType.entries()) { - ResourceEntry* entry = type->findOrCreateEntry(pbEntry.name()); - - // Deserialize the symbol status (public/private with source and comments). - if (pbEntry.has_symbol_status()) { - const pb::SymbolStatus& pbStatus = pbEntry.symbol_status(); - if (pbStatus.has_source()) { - deserializeSourceFromPb(pbStatus.source(), *mSourcePool, - &entry->symbolStatus.source); - } - - if (pbStatus.has_comment()) { - entry->symbolStatus.comment = pbStatus.comment(); - } - - SymbolState visibility = deserializeVisibilityFromPb(pbStatus.visibility()); - entry->symbolStatus.state = visibility; - - if (visibility == SymbolState::kPublic) { - // This is a public symbol, we must encode the ID now if there is one. - if (pbEntry.has_id()) { - entry->id = static_cast<uint16_t>(pbEntry.id()); - } - - if (type->symbolStatus.state != SymbolState::kPublic) { - // If the type has not been made public, do so now. - type->symbolStatus.state = SymbolState::kPublic; - if (pbType.has_id()) { - type->id = static_cast<uint8_t>(pbType.id()); - } - } - } else if (visibility == SymbolState::kPrivate) { - if (type->symbolStatus.state == SymbolState::kUndefined) { - type->symbolStatus.state = SymbolState::kPrivate; - } - } - } - - ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id()); - if (resId.isValid()) { - idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name); - } - - for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) { - const pb::ConfigDescription& pbConfig = pbConfigValue.config(); - - ConfigDescription config; - if (!deserializeConfigDescriptionFromPb(pbConfig, &config)) { - mDiag->error(DiagMessage(mSource) << "invalid configuration"); - return {}; - } - - ResourceConfigValue* configValue = entry->findOrCreateValue(config, - pbConfig.product()); - if (configValue->value) { - // Duplicate config. - mDiag->error(DiagMessage(mSource) << "duplicate configuration"); - return {}; - } - - configValue->value = deserializeValueFromPb(pbConfigValue.value(), - config, &table->stringPool); - if (!configValue->value) { - return {}; - } - } + if (type->symbolStatus.state != SymbolState::kPublic) { + // If the type has not been made public, do so now. + type->symbolStatus.state = SymbolState::kPublic; + if (pbType.has_id()) { + type->id = static_cast<uint8_t>(pbType.id()); + } + } + } else if (visibility == SymbolState::kPrivate) { + if (type->symbolStatus.state == SymbolState::kUndefined) { + type->symbolStatus.state = SymbolState::kPrivate; } + } } - ReferenceIdToNameVisitor visitor(&idIndex); - visitAllValuesInPackage(pkg, &visitor); - return true; - } - -private: - std::unique_ptr<Item> deserializeItemFromPb(const pb::Item& pbItem, - const ConfigDescription& config, - StringPool* pool) { - if (pbItem.has_ref()) { - const pb::Reference& pbRef = pbItem.ref(); - std::unique_ptr<Reference> ref = util::make_unique<Reference>(); - if (!deserializeReferenceFromPb(pbRef, ref.get())) { - return {}; - } - return std::move(ref); - - } else if (pbItem.has_prim()) { - const pb::Primitive& pbPrim = pbItem.prim(); - android::Res_value prim = {}; - prim.dataType = static_cast<uint8_t>(pbPrim.type()); - prim.data = pbPrim.data(); - return util::make_unique<BinaryPrimitive>(prim); - - } else if (pbItem.has_id()) { - return util::make_unique<Id>(); - - } else if (pbItem.has_str()) { - const uint32_t idx = pbItem.str().idx(); - const std::string str = util::getString(*mValuePool, idx); - - const android::ResStringPool_span* spans = mValuePool->styleAt(idx); - if (spans && spans->name.index != android::ResStringPool_span::END) { - StyleString styleStr = { str }; - while (spans->name.index != android::ResStringPool_span::END) { - styleStr.spans.push_back(Span{ - util::getString(*mValuePool, spans->name.index), - spans->firstChar, - spans->lastChar - }); - spans++; - } - return util::make_unique<StyledString>( - pool->makeRef(styleStr, StringPool::Context{ 1, config })); - } - return util::make_unique<String>( - pool->makeRef(str, StringPool::Context{ 1, config })); - - } else if (pbItem.has_raw_str()) { - const uint32_t idx = pbItem.raw_str().idx(); - const std::string str = util::getString(*mValuePool, idx); - return util::make_unique<RawString>( - pool->makeRef(str, StringPool::Context{ 1, config })); - - } else if (pbItem.has_file()) { - const uint32_t idx = pbItem.file().path_idx(); - const std::string str = util::getString(*mValuePool, idx); - return util::make_unique<FileReference>( - pool->makeRef(str, StringPool::Context{ 0, config })); - - } else { - mDiag->error(DiagMessage(mSource) << "unknown item"); + ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id()); + if (resId.isValid()) { + idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name); } - return {}; - } - std::unique_ptr<Value> deserializeValueFromPb(const pb::Value& pbValue, - const ConfigDescription& config, - StringPool* pool) { - const bool isWeak = pbValue.has_weak() ? pbValue.weak() : false; + for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) { + const pb::ConfigDescription& pbConfig = pbConfigValue.config(); - std::unique_ptr<Value> value; - if (pbValue.has_item()) { - value = deserializeItemFromPb(pbValue.item(), config, pool); - if (!value) { - return {}; - } + ConfigDescription config; + if (!deserializeConfigDescriptionFromPb(pbConfig, &config)) { + mDiag->error(DiagMessage(mSource) << "invalid configuration"); + return {}; + } - } else if (pbValue.has_compound_value()) { - const pb::CompoundValue& pbCompoundValue = pbValue.compound_value(); - if (pbCompoundValue.has_attr()) { - const pb::Attribute& pbAttr = pbCompoundValue.attr(); - std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak); - attr->typeMask = pbAttr.format_flags(); - attr->minInt = pbAttr.min_int(); - attr->maxInt = pbAttr.max_int(); - for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) { - Attribute::Symbol symbol; - deserializeItemCommon(pbSymbol, &symbol.symbol); - if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) { - return {}; - } - symbol.value = pbSymbol.value(); - attr->symbols.push_back(std::move(symbol)); - } - value = std::move(attr); - - } else if (pbCompoundValue.has_style()) { - const pb::Style& pbStyle = pbCompoundValue.style(); - std::unique_ptr<Style> style = util::make_unique<Style>(); - if (pbStyle.has_parent()) { - style->parent = Reference(); - if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) { - return {}; - } - - if (pbStyle.has_parent_source()) { - Source parentSource; - deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool, - &parentSource); - style->parent.value().setSource(std::move(parentSource)); - } - } - - for (const pb::Style_Entry& pbEntry : pbStyle.entries()) { - Style::Entry entry; - deserializeItemCommon(pbEntry, &entry.key); - if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) { - return {}; - } - - entry.value = deserializeItemFromPb(pbEntry.item(), config, pool); - if (!entry.value) { - return {}; - } - - deserializeItemCommon(pbEntry, entry.value.get()); - style->entries.push_back(std::move(entry)); - } - value = std::move(style); - - } else if (pbCompoundValue.has_styleable()) { - const pb::Styleable& pbStyleable = pbCompoundValue.styleable(); - std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); - for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) { - Reference attrRef; - deserializeItemCommon(pbEntry, &attrRef); - deserializeReferenceFromPb(pbEntry.attr(), &attrRef); - styleable->entries.push_back(std::move(attrRef)); - } - value = std::move(styleable); - - } else if (pbCompoundValue.has_array()) { - const pb::Array& pbArray = pbCompoundValue.array(); - std::unique_ptr<Array> array = util::make_unique<Array>(); - for (const pb::Array_Entry& pbEntry : pbArray.entries()) { - std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config, - pool); - if (!item) { - return {}; - } - - deserializeItemCommon(pbEntry, item.get()); - array->items.push_back(std::move(item)); - } - value = std::move(array); - - } else if (pbCompoundValue.has_plural()) { - const pb::Plural& pbPlural = pbCompoundValue.plural(); - std::unique_ptr<Plural> plural = util::make_unique<Plural>(); - for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) { - size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity()); - plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config, - pool); - if (!plural->values[pluralIdx]) { - return {}; - } - - deserializeItemCommon(pbEntry, plural->values[pluralIdx].get()); - } - value = std::move(plural); - - } else { - mDiag->error(DiagMessage(mSource) << "unknown compound value"); - return {}; - } - } else { - mDiag->error(DiagMessage(mSource) << "unknown value"); + ResourceConfigValue* configValue = + entry->findOrCreateValue(config, pbConfig.product()); + if (configValue->value) { + // Duplicate config. + mDiag->error(DiagMessage(mSource) << "duplicate configuration"); return {}; - } + } - assert(value && "forgot to set value"); + configValue->value = deserializeValueFromPb( + pbConfigValue.value(), config, &table->stringPool); + if (!configValue->value) { + return {}; + } + } + } + } - value->setWeak(isWeak); - deserializeItemCommon(pbValue, value.get()); - return value; + ReferenceIdToNameVisitor visitor(&idIndex); + visitAllValuesInPackage(pkg, &visitor); + return true; + } + + private: + std::unique_ptr<Item> deserializeItemFromPb(const pb::Item& pbItem, + const ConfigDescription& config, + StringPool* pool) { + if (pbItem.has_ref()) { + const pb::Reference& pbRef = pbItem.ref(); + std::unique_ptr<Reference> ref = util::make_unique<Reference>(); + if (!deserializeReferenceFromPb(pbRef, ref.get())) { + return {}; + } + return std::move(ref); + + } else if (pbItem.has_prim()) { + const pb::Primitive& pbPrim = pbItem.prim(); + android::Res_value prim = {}; + prim.dataType = static_cast<uint8_t>(pbPrim.type()); + prim.data = pbPrim.data(); + return util::make_unique<BinaryPrimitive>(prim); + + } else if (pbItem.has_id()) { + return util::make_unique<Id>(); + + } else if (pbItem.has_str()) { + const uint32_t idx = pbItem.str().idx(); + const std::string str = util::getString(*mValuePool, idx); + + const android::ResStringPool_span* spans = mValuePool->styleAt(idx); + if (spans && spans->name.index != android::ResStringPool_span::END) { + StyleString styleStr = {str}; + while (spans->name.index != android::ResStringPool_span::END) { + styleStr.spans.push_back( + Span{util::getString(*mValuePool, spans->name.index), + spans->firstChar, spans->lastChar}); + spans++; + } + return util::make_unique<StyledString>(pool->makeRef( + styleStr, + StringPool::Context(StringPool::Context::kStylePriority, config))); + } + return util::make_unique<String>( + pool->makeRef(str, StringPool::Context(config))); + + } else if (pbItem.has_raw_str()) { + const uint32_t idx = pbItem.raw_str().idx(); + const std::string str = util::getString(*mValuePool, idx); + return util::make_unique<RawString>( + pool->makeRef(str, StringPool::Context(config))); + + } else if (pbItem.has_file()) { + const uint32_t idx = pbItem.file().path_idx(); + const std::string str = util::getString(*mValuePool, idx); + return util::make_unique<FileReference>(pool->makeRef( + str, + StringPool::Context(StringPool::Context::kHighPriority, config))); + + } else { + mDiag->error(DiagMessage(mSource) << "unknown item"); } + return {}; + } - bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) { - outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type()); - outRef->privateReference = pbRef.private_(); + std::unique_ptr<Value> deserializeValueFromPb(const pb::Value& pbValue, + const ConfigDescription& config, + StringPool* pool) { + const bool isWeak = pbValue.has_weak() ? pbValue.weak() : false; - if (!pbRef.has_id() && !pbRef.has_symbol_idx()) { - return false; + std::unique_ptr<Value> value; + if (pbValue.has_item()) { + value = deserializeItemFromPb(pbValue.item(), config, pool); + if (!value) { + return {}; + } + + } else if (pbValue.has_compound_value()) { + const pb::CompoundValue& pbCompoundValue = pbValue.compound_value(); + if (pbCompoundValue.has_attr()) { + const pb::Attribute& pbAttr = pbCompoundValue.attr(); + std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak); + attr->typeMask = pbAttr.format_flags(); + attr->minInt = pbAttr.min_int(); + attr->maxInt = pbAttr.max_int(); + for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) { + Attribute::Symbol symbol; + deserializeItemCommon(pbSymbol, &symbol.symbol); + if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) { + return {}; + } + symbol.value = pbSymbol.value(); + attr->symbols.push_back(std::move(symbol)); } - - if (pbRef.has_id()) { - outRef->id = ResourceId(pbRef.id()); + value = std::move(attr); + + } else if (pbCompoundValue.has_style()) { + const pb::Style& pbStyle = pbCompoundValue.style(); + std::unique_ptr<Style> style = util::make_unique<Style>(); + if (pbStyle.has_parent()) { + style->parent = Reference(); + if (!deserializeReferenceFromPb(pbStyle.parent(), + &style->parent.value())) { + return {}; + } + + if (pbStyle.has_parent_source()) { + Source parentSource; + deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool, + &parentSource); + style->parent.value().setSource(std::move(parentSource)); + } } - if (pbRef.has_symbol_idx()) { - const std::string strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx()); - ResourceNameRef nameRef; - if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) { - mDiag->error(DiagMessage(mSource) << "invalid reference name '" - << strSymbol << "'"); - return false; - } + for (const pb::Style_Entry& pbEntry : pbStyle.entries()) { + Style::Entry entry; + deserializeItemCommon(pbEntry, &entry.key); + if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) { + return {}; + } + + entry.value = deserializeItemFromPb(pbEntry.item(), config, pool); + if (!entry.value) { + return {}; + } - outRef->name = nameRef.toResourceName(); + deserializeItemCommon(pbEntry, entry.value.get()); + style->entries.push_back(std::move(entry)); } - return true; - } + value = std::move(style); + + } else if (pbCompoundValue.has_styleable()) { + const pb::Styleable& pbStyleable = pbCompoundValue.styleable(); + std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); + for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) { + Reference attrRef; + deserializeItemCommon(pbEntry, &attrRef); + deserializeReferenceFromPb(pbEntry.attr(), &attrRef); + styleable->entries.push_back(std::move(attrRef)); + } + value = std::move(styleable); + + } else if (pbCompoundValue.has_array()) { + const pb::Array& pbArray = pbCompoundValue.array(); + std::unique_ptr<Array> array = util::make_unique<Array>(); + for (const pb::Array_Entry& pbEntry : pbArray.entries()) { + std::unique_ptr<Item> item = + deserializeItemFromPb(pbEntry.item(), config, pool); + if (!item) { + return {}; + } - template <typename T> - void deserializeItemCommon(const T& pbItem, Value* outValue) { - if (pbItem.has_source()) { - Source source; - deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source); - outValue->setSource(std::move(source)); + deserializeItemCommon(pbEntry, item.get()); + array->items.push_back(std::move(item)); } + value = std::move(array); + + } else if (pbCompoundValue.has_plural()) { + const pb::Plural& pbPlural = pbCompoundValue.plural(); + std::unique_ptr<Plural> plural = util::make_unique<Plural>(); + for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) { + size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity()); + plural->values[pluralIdx] = + deserializeItemFromPb(pbEntry.item(), config, pool); + if (!plural->values[pluralIdx]) { + return {}; + } - if (pbItem.has_comment()) { - outValue->setComment(pbItem.comment()); + deserializeItemCommon(pbEntry, plural->values[pluralIdx].get()); } - } + value = std::move(plural); -private: - const android::ResStringPool* mValuePool; - const android::ResStringPool* mSourcePool; - const android::ResStringPool* mSymbolPool; - const Source mSource; - IDiagnostics* mDiag; -}; + } else { + mDiag->error(DiagMessage(mSource) << "unknown compound value"); + return {}; + } + } else { + mDiag->error(DiagMessage(mSource) << "unknown value"); + return {}; + } -} // namespace + assert(value && "forgot to set value"); -std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable, - const Source& source, - IDiagnostics* diag) { - // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which - // causes errors when qualifying it with android:: - using namespace android; + value->setWeak(isWeak); + deserializeItemCommon(pbValue, value.get()); + return value; + } - std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); + bool deserializeReferenceFromPb(const pb::Reference& pbRef, + Reference* outRef) { + outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type()); + outRef->privateReference = pbRef.private_(); - if (!pbTable.has_string_pool()) { - diag->error(DiagMessage(source) << "no string pool found"); - return {}; + if (!pbRef.has_id() && !pbRef.has_symbol_idx()) { + return false; } - ResStringPool valuePool; - status_t result = valuePool.setTo(pbTable.string_pool().data().data(), - pbTable.string_pool().data().size()); - if (result != NO_ERROR) { - diag->error(DiagMessage(source) << "invalid string pool"); - return {}; + if (pbRef.has_id()) { + outRef->id = ResourceId(pbRef.id()); } - ResStringPool sourcePool; - if (pbTable.has_source_pool()) { - result = sourcePool.setTo(pbTable.source_pool().data().data(), - pbTable.source_pool().data().size()); - if (result != NO_ERROR) { - diag->error(DiagMessage(source) << "invalid source pool"); - return {}; - } + if (pbRef.has_symbol_idx()) { + const std::string strSymbol = + util::getString(*mSymbolPool, pbRef.symbol_idx()); + ResourceNameRef nameRef; + if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) { + mDiag->error(DiagMessage(mSource) << "invalid reference name '" + << strSymbol << "'"); + return false; + } + + outRef->name = nameRef.toResourceName(); } - - ResStringPool symbolPool; - if (pbTable.has_symbol_pool()) { - result = symbolPool.setTo(pbTable.symbol_pool().data().data(), - pbTable.symbol_pool().data().size()); - if (result != NO_ERROR) { - diag->error(DiagMessage(source) << "invalid symbol pool"); - return {}; - } + return true; + } + + template <typename T> + void deserializeItemCommon(const T& pbItem, Value* outValue) { + if (pbItem.has_source()) { + Source source; + deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source); + outValue->setSource(std::move(source)); } - PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag); - for (const pb::Package& pbPackage : pbTable.packages()) { - if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) { - return {}; - } + if (pbItem.has_comment()) { + outValue->setComment(pbItem.comment()); } - return table; -} + } + + private: + const android::ResStringPool* mValuePool; + const android::ResStringPool* mSourcePool; + const android::ResStringPool* mSymbolPool; + const Source mSource; + IDiagnostics* mDiag; +}; -std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile, - const Source& source, - IDiagnostics* diag) { - std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>(); +} // namespace + +std::unique_ptr<ResourceTable> deserializeTableFromPb( + const pb::ResourceTable& pbTable, const Source& source, + IDiagnostics* diag) { + // We import the android namespace because on Windows NO_ERROR is a macro, not + // an enum, which + // causes errors when qualifying it with android:: + using namespace android; + + std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); + + if (!pbTable.has_string_pool()) { + diag->error(DiagMessage(source) << "no string pool found"); + return {}; + } + + ResStringPool valuePool; + status_t result = valuePool.setTo(pbTable.string_pool().data().data(), + pbTable.string_pool().data().size()); + if (result != NO_ERROR) { + diag->error(DiagMessage(source) << "invalid string pool"); + return {}; + } + + ResStringPool sourcePool; + if (pbTable.has_source_pool()) { + result = sourcePool.setTo(pbTable.source_pool().data().data(), + pbTable.source_pool().data().size()); + if (result != NO_ERROR) { + diag->error(DiagMessage(source) << "invalid source pool"); + return {}; + } + } - ResourceNameRef nameRef; + ResStringPool symbolPool; + if (pbTable.has_symbol_pool()) { + result = symbolPool.setTo(pbTable.symbol_pool().data().data(), + pbTable.symbol_pool().data().size()); + if (result != NO_ERROR) { + diag->error(DiagMessage(source) << "invalid symbol pool"); + return {}; + } + } - // Need to create an lvalue here so that nameRef can point to something real. - if (!ResourceUtils::parseResourceName(pbFile.resource_name(), &nameRef)) { - diag->error(DiagMessage(source) << "invalid resource name in compiled file header: " - << pbFile.resource_name()); - return {}; + PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, + &symbolPool, source, diag); + for (const pb::Package& pbPackage : pbTable.packages()) { + if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) { + return {}; } - file->name = nameRef.toResourceName(); - file->source.path = pbFile.source_path(); - deserializeConfigDescriptionFromPb(pbFile.config(), &file->config); - - for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) { - // Need to create an lvalue here so that nameRef can point to something real. - if (!ResourceUtils::parseResourceName(pbSymbol.resource_name(), &nameRef)) { - diag->error(DiagMessage(source) << "invalid resource name for exported symbol in " - "compiled file header: " - << pbFile.resource_name()); - return {}; - } - file->exportedSymbols.push_back( - SourcedResourceName{ nameRef.toResourceName(), pbSymbol.line_no() }); + } + return table; +} + +std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb( + const pb::CompiledFile& pbFile, const Source& source, IDiagnostics* diag) { + std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>(); + + ResourceNameRef nameRef; + + // Need to create an lvalue here so that nameRef can point to something real. + if (!ResourceUtils::parseResourceName(pbFile.resource_name(), &nameRef)) { + diag->error(DiagMessage(source) + << "invalid resource name in compiled file header: " + << pbFile.resource_name()); + return {}; + } + file->name = nameRef.toResourceName(); + file->source.path = pbFile.source_path(); + deserializeConfigDescriptionFromPb(pbFile.config(), &file->config); + + for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) { + // Need to create an lvalue here so that nameRef can point to something + // real. + if (!ResourceUtils::parseResourceName(pbSymbol.resource_name(), &nameRef)) { + diag->error(DiagMessage(source) + << "invalid resource name for exported symbol in " + "compiled file header: " + << pbFile.resource_name()); + return {}; } - return file; + file->exportedSymbols.push_back( + SourcedResourceName{nameRef.toResourceName(), pbSymbol.line_no()}); + } + return file; } -} // namespace aapt +} // namespace aapt diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp index 4fd77c83a891..546b6078ddb0 100644 --- a/tools/aapt2/unflatten/BinaryResourceParser.cpp +++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp @@ -14,18 +14,18 @@ * limitations under the License. */ +#include "unflatten/BinaryResourceParser.h" #include "ResourceTable.h" #include "ResourceUtils.h" #include "ResourceValues.h" #include "Source.h" #include "ValueVisitor.h" -#include "unflatten/BinaryResourceParser.h" #include "unflatten/ResChunkPullParser.h" #include "util/Util.h" +#include <android-base/macros.h> #include <androidfw/ResourceTypes.h> #include <androidfw/TypeWrappers.h> -#include <android-base/macros.h> #include <algorithm> #include <map> #include <string> @@ -41,533 +41,553 @@ namespace { * given a mapping from resource ID to resource name. */ class ReferenceIdToNameVisitor : public ValueVisitor { -private: - const std::map<ResourceId, ResourceName>* mMapping; + private: + const std::map<ResourceId, ResourceName>* mMapping; -public: - using ValueVisitor::visit; + public: + using ValueVisitor::visit; - explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceName>* mapping) : - mMapping(mapping) { - assert(mMapping); - } + explicit ReferenceIdToNameVisitor( + const std::map<ResourceId, ResourceName>* mapping) + : mMapping(mapping) { + assert(mMapping); + } - void visit(Reference* reference) override { - if (!reference->id || !reference->id.value().isValid()) { - return; - } + void visit(Reference* reference) override { + if (!reference->id || !reference->id.value().isValid()) { + return; + } - ResourceId id = reference->id.value(); - auto cacheIter = mMapping->find(id); - if (cacheIter != mMapping->end()) { - reference->name = cacheIter->second; - } + ResourceId id = reference->id.value(); + auto cacheIter = mMapping->find(id); + if (cacheIter != mMapping->end()) { + reference->name = cacheIter->second; } + } }; -} // namespace +} // namespace -BinaryResourceParser::BinaryResourceParser(IAaptContext* context, ResourceTable* table, - const Source& source, const void* data, size_t len) : - mContext(context), mTable(table), mSource(source), mData(data), mDataLen(len) { -} +BinaryResourceParser::BinaryResourceParser(IAaptContext* context, + ResourceTable* table, + const Source& source, + const void* data, size_t len) + : mContext(context), + mTable(table), + mSource(source), + mData(data), + mDataLen(len) {} bool BinaryResourceParser::parse() { - ResChunkPullParser parser(mData, mDataLen); - - bool error = false; - while(ResChunkPullParser::isGoodEvent(parser.next())) { - if (parser.getChunk()->type != android::RES_TABLE_TYPE) { - mContext->getDiagnostics()->warn(DiagMessage(mSource) - << "unknown chunk of type '" - << (int) parser.getChunk()->type << "'"); - continue; - } + ResChunkPullParser parser(mData, mDataLen); - if (!parseTable(parser.getChunk())) { - error = true; - } + bool error = false; + while (ResChunkPullParser::isGoodEvent(parser.next())) { + if (parser.getChunk()->type != android::RES_TABLE_TYPE) { + mContext->getDiagnostics()->warn(DiagMessage(mSource) + << "unknown chunk of type '" + << (int)parser.getChunk()->type << "'"); + continue; } - if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt resource table: " - << parser.getLastError()); - return false; + if (!parseTable(parser.getChunk())) { + error = true; } - return !error; + } + + if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt resource table: " + << parser.getLastError()); + return false; + } + return !error; } /** - * Parses the resource table, which contains all the packages, types, and entries. + * Parses the resource table, which contains all the packages, types, and + * entries. */ bool BinaryResourceParser::parseTable(const ResChunk_header* chunk) { - const ResTable_header* tableHeader = convertTo<ResTable_header>(chunk); - if (!tableHeader) { - mContext->getDiagnostics()->error(DiagMessage(mSource) << "corrupt ResTable_header chunk"); - return false; - } + const ResTable_header* tableHeader = convertTo<ResTable_header>(chunk); + if (!tableHeader) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt ResTable_header chunk"); + return false; + } + + ResChunkPullParser parser(getChunkData(&tableHeader->header), + getChunkDataLen(&tableHeader->header)); + while (ResChunkPullParser::isGoodEvent(parser.next())) { + switch (util::deviceToHost16(parser.getChunk()->type)) { + case android::RES_STRING_POOL_TYPE: + if (mValuePool.getError() == NO_INIT) { + status_t err = mValuePool.setTo( + parser.getChunk(), util::deviceToHost32(parser.getChunk()->size)); + if (err != NO_ERROR) { + mContext->getDiagnostics()->error( + DiagMessage(mSource) << "corrupt string pool in ResTable: " + << mValuePool.getError()); + return false; + } - ResChunkPullParser parser(getChunkData(&tableHeader->header), - getChunkDataLen(&tableHeader->header)); - while (ResChunkPullParser::isGoodEvent(parser.next())) { - switch (util::deviceToHost16(parser.getChunk()->type)) { - case android::RES_STRING_POOL_TYPE: - if (mValuePool.getError() == NO_INIT) { - status_t err = mValuePool.setTo(parser.getChunk(), - util::deviceToHost32(parser.getChunk()->size)); - if (err != NO_ERROR) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt string pool in ResTable: " - << mValuePool.getError()); - return false; - } - - // Reserve some space for the strings we are going to add. - mTable->stringPool.hintWillAdd(mValuePool.size(), mValuePool.styleCount()); - } else { - mContext->getDiagnostics()->warn(DiagMessage(mSource) - << "unexpected string pool in ResTable"); - } - break; - - case android::RES_TABLE_PACKAGE_TYPE: - if (!parsePackage(parser.getChunk())) { - return false; - } - break; - - default: - mContext->getDiagnostics() - ->warn(DiagMessage(mSource) - << "unexpected chunk type " - << (int) util::deviceToHost16(parser.getChunk()->type)); - break; + // Reserve some space for the strings we are going to add. + mTable->stringPool.hintWillAdd(mValuePool.size(), + mValuePool.styleCount()); + } else { + mContext->getDiagnostics()->warn( + DiagMessage(mSource) << "unexpected string pool in ResTable"); } - } + break; - if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt resource table: " << parser.getLastError()); - return false; - } - return true; + case android::RES_TABLE_PACKAGE_TYPE: + if (!parsePackage(parser.getChunk())) { + return false; + } + break; + + default: + mContext->getDiagnostics()->warn( + DiagMessage(mSource) + << "unexpected chunk type " + << (int)util::deviceToHost16(parser.getChunk()->type)); + break; + } + } + + if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt resource table: " + << parser.getLastError()); + return false; + } + return true; } - bool BinaryResourceParser::parsePackage(const ResChunk_header* chunk) { - const ResTable_package* packageHeader = convertTo<ResTable_package>(chunk); - if (!packageHeader) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt ResTable_package chunk"); - return false; - } - - uint32_t packageId = util::deviceToHost32(packageHeader->id); - if (packageId > std::numeric_limits<uint8_t>::max()) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "package ID is too big (" << packageId << ")"); - return false; - } - - // Extract the package name. - size_t len = strnlen16((const char16_t*) packageHeader->name, arraysize(packageHeader->name)); - std::u16string packageName; - packageName.resize(len); - for (size_t i = 0; i < len; i++) { - packageName[i] = util::deviceToHost16(packageHeader->name[i]); - } - - ResourceTablePackage* package = mTable->createPackage(util::utf16ToUtf8(packageName), - static_cast<uint8_t>(packageId)); - if (!package) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "incompatible package '" << packageName - << "' with ID " << packageId); - return false; - } - - // There can be multiple packages in a table, so - // clear the type and key pool in case they were set from a previous package. - mTypePool.uninit(); - mKeyPool.uninit(); - - ResChunkPullParser parser(getChunkData(&packageHeader->header), - getChunkDataLen(&packageHeader->header)); - while (ResChunkPullParser::isGoodEvent(parser.next())) { - switch (util::deviceToHost16(parser.getChunk()->type)) { - case android::RES_STRING_POOL_TYPE: - if (mTypePool.getError() == NO_INIT) { - status_t err = mTypePool.setTo(parser.getChunk(), - util::deviceToHost32(parser.getChunk()->size)); - if (err != NO_ERROR) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt type string pool in " - << "ResTable_package: " - << mTypePool.getError()); - return false; - } - } else if (mKeyPool.getError() == NO_INIT) { - status_t err = mKeyPool.setTo(parser.getChunk(), - util::deviceToHost32(parser.getChunk()->size)); - if (err != NO_ERROR) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt key string pool in " - << "ResTable_package: " - << mKeyPool.getError()); - return false; - } - } else { - mContext->getDiagnostics()->warn(DiagMessage(mSource) << "unexpected string pool"); - } - break; - - case android::RES_TABLE_TYPE_SPEC_TYPE: - if (!parseTypeSpec(parser.getChunk())) { - return false; - } - break; - - case android::RES_TABLE_TYPE_TYPE: - if (!parseType(package, parser.getChunk())) { - return false; - } - break; - - default: - mContext->getDiagnostics() - ->warn(DiagMessage(mSource) - << "unexpected chunk type " - << (int) util::deviceToHost16(parser.getChunk()->type)); - break; + const ResTable_package* packageHeader = convertTo<ResTable_package>(chunk); + if (!packageHeader) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt ResTable_package chunk"); + return false; + } + + uint32_t packageId = util::deviceToHost32(packageHeader->id); + if (packageId > std::numeric_limits<uint8_t>::max()) { + mContext->getDiagnostics()->error( + DiagMessage(mSource) << "package ID is too big (" << packageId << ")"); + return false; + } + + // Extract the package name. + size_t len = strnlen16((const char16_t*)packageHeader->name, + arraysize(packageHeader->name)); + std::u16string packageName; + packageName.resize(len); + for (size_t i = 0; i < len; i++) { + packageName[i] = util::deviceToHost16(packageHeader->name[i]); + } + + ResourceTablePackage* package = mTable->createPackage( + util::utf16ToUtf8(packageName), static_cast<uint8_t>(packageId)); + if (!package) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "incompatible package '" << packageName + << "' with ID " << packageId); + return false; + } + + // There can be multiple packages in a table, so + // clear the type and key pool in case they were set from a previous package. + mTypePool.uninit(); + mKeyPool.uninit(); + + ResChunkPullParser parser(getChunkData(&packageHeader->header), + getChunkDataLen(&packageHeader->header)); + while (ResChunkPullParser::isGoodEvent(parser.next())) { + switch (util::deviceToHost16(parser.getChunk()->type)) { + case android::RES_STRING_POOL_TYPE: + if (mTypePool.getError() == NO_INIT) { + status_t err = mTypePool.setTo( + parser.getChunk(), util::deviceToHost32(parser.getChunk()->size)); + if (err != NO_ERROR) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt type string pool in " + << "ResTable_package: " + << mTypePool.getError()); + return false; + } + } else if (mKeyPool.getError() == NO_INIT) { + status_t err = mKeyPool.setTo( + parser.getChunk(), util::deviceToHost32(parser.getChunk()->size)); + if (err != NO_ERROR) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt key string pool in " + << "ResTable_package: " + << mKeyPool.getError()); + return false; + } + } else { + mContext->getDiagnostics()->warn(DiagMessage(mSource) + << "unexpected string pool"); } - } + break; - if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt ResTable_package: " - << parser.getLastError()); - return false; - } + case android::RES_TABLE_TYPE_SPEC_TYPE: + if (!parseTypeSpec(parser.getChunk())) { + return false; + } + break; - // Now go through the table and change local resource ID references to - // symbolic references. - ReferenceIdToNameVisitor visitor(&mIdIndex); - visitAllValuesInTable(mTable, &visitor); - return true; + case android::RES_TABLE_TYPE_TYPE: + if (!parseType(package, parser.getChunk())) { + return false; + } + break; + + default: + mContext->getDiagnostics()->warn( + DiagMessage(mSource) + << "unexpected chunk type " + << (int)util::deviceToHost16(parser.getChunk()->type)); + break; + } + } + + if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt ResTable_package: " + << parser.getLastError()); + return false; + } + + // Now go through the table and change local resource ID references to + // symbolic references. + ReferenceIdToNameVisitor visitor(&mIdIndex); + visitAllValuesInTable(mTable, &visitor); + return true; } bool BinaryResourceParser::parseTypeSpec(const ResChunk_header* chunk) { - if (mTypePool.getError() != NO_ERROR) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "missing type string pool"); - return false; - } - - const ResTable_typeSpec* typeSpec = convertTo<ResTable_typeSpec>(chunk); - if (!typeSpec) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt ResTable_typeSpec chunk"); - return false; - } - - if (typeSpec->id == 0) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "ResTable_typeSpec has invalid id: " << typeSpec->id); - return false; - } - return true; + if (mTypePool.getError() != NO_ERROR) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "missing type string pool"); + return false; + } + + const ResTable_typeSpec* typeSpec = convertTo<ResTable_typeSpec>(chunk); + if (!typeSpec) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt ResTable_typeSpec chunk"); + return false; + } + + if (typeSpec->id == 0) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "ResTable_typeSpec has invalid id: " + << typeSpec->id); + return false; + } + return true; } bool BinaryResourceParser::parseType(const ResourceTablePackage* package, const ResChunk_header* chunk) { - if (mTypePool.getError() != NO_ERROR) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "missing type string pool"); + if (mTypePool.getError() != NO_ERROR) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "missing type string pool"); + return false; + } + + if (mKeyPool.getError() != NO_ERROR) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "missing key string pool"); + return false; + } + + const ResTable_type* type = convertTo<ResTable_type>(chunk); + if (!type) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "corrupt ResTable_type chunk"); + return false; + } + + if (type->id == 0) { + mContext->getDiagnostics()->error(DiagMessage(mSource) + << "ResTable_type has invalid id: " + << (int)type->id); + return false; + } + + ConfigDescription config; + config.copyFromDtoH(type->config); + + const std::string typeStr = util::getString(mTypePool, type->id - 1); + + const ResourceType* parsedType = parseResourceType(typeStr); + if (!parsedType) { + mContext->getDiagnostics()->error( + DiagMessage(mSource) << "invalid type name '" << typeStr + << "' for type with ID " << (int)type->id); + return false; + } + + TypeVariant tv(type); + for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) { + const ResTable_entry* entry = *it; + if (!entry) { + continue; + } + + const ResourceName name( + package->name, *parsedType, + util::getString(mKeyPool, util::deviceToHost32(entry->key.index))); + + const ResourceId resId(package->id.value(), type->id, + static_cast<uint16_t>(it.index())); + + std::unique_ptr<Value> resourceValue; + if (entry->flags & ResTable_entry::FLAG_COMPLEX) { + const ResTable_map_entry* mapEntry = + static_cast<const ResTable_map_entry*>(entry); + + // TODO(adamlesinski): Check that the entry count is valid. + resourceValue = parseMapEntry(name, config, mapEntry); + } else { + const Res_value* value = + (const Res_value*)((const uint8_t*)entry + + util::deviceToHost32(entry->size)); + resourceValue = parseValue(name, config, value, entry->flags); + } + + if (!resourceValue) { + mContext->getDiagnostics()->error( + DiagMessage(mSource) << "failed to parse value for resource " << name + << " (" << resId << ") with configuration '" + << config << "'"); + return false; + } + + if (!mTable->addResourceAllowMangled(name, config, {}, + std::move(resourceValue), + mContext->getDiagnostics())) { + return false; + } + + if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) { + Symbol symbol; + symbol.state = SymbolState::kPublic; + symbol.source = mSource.withLine(0); + if (!mTable->setSymbolStateAllowMangled(name, resId, symbol, + mContext->getDiagnostics())) { return false; + } } - if (mKeyPool.getError() != NO_ERROR) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "missing key string pool"); - return false; - } - - const ResTable_type* type = convertTo<ResTable_type>(chunk); - if (!type) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "corrupt ResTable_type chunk"); - return false; - } - - if (type->id == 0) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "ResTable_type has invalid id: " << (int) type->id); - return false; + // Add this resource name->id mapping to the index so + // that we can resolve all ID references to name references. + auto cacheIter = mIdIndex.find(resId); + if (cacheIter == mIdIndex.end()) { + mIdIndex.insert({resId, name}); } - - ConfigDescription config; - config.copyFromDtoH(type->config); - - const std::string typeStr = util::getString(mTypePool, type->id - 1); - - const ResourceType* parsedType = parseResourceType(typeStr); - if (!parsedType) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "invalid type name '" << typeStr - << "' for type with ID " << (int) type->id); - return false; - } - - TypeVariant tv(type); - for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) { - const ResTable_entry* entry = *it; - if (!entry) { - continue; - } - - const ResourceName name(package->name, *parsedType, - util::getString(mKeyPool, - util::deviceToHost32(entry->key.index))); - - const ResourceId resId(package->id.value(), type->id, static_cast<uint16_t>(it.index())); - - std::unique_ptr<Value> resourceValue; - if (entry->flags & ResTable_entry::FLAG_COMPLEX) { - const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry); - - // TODO(adamlesinski): Check that the entry count is valid. - resourceValue = parseMapEntry(name, config, mapEntry); - } else { - const Res_value* value = (const Res_value*)( - (const uint8_t*) entry + util::deviceToHost32(entry->size)); - resourceValue = parseValue(name, config, value, entry->flags); - } - - if (!resourceValue) { - mContext->getDiagnostics()->error(DiagMessage(mSource) - << "failed to parse value for resource " << name - << " (" << resId << ") with configuration '" - << config << "'"); - return false; - } - - if (!mTable->addResourceAllowMangled(name, config, {}, std::move(resourceValue), - mContext->getDiagnostics())) { - return false; - } - - if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) { - Symbol symbol; - symbol.state = SymbolState::kPublic; - symbol.source = mSource.withLine(0); - if (!mTable->setSymbolStateAllowMangled(name, resId, symbol, - mContext->getDiagnostics())) { - return false; - } - } - - // Add this resource name->id mapping to the index so - // that we can resolve all ID references to name references. - auto cacheIter = mIdIndex.find(resId); - if (cacheIter == mIdIndex.end()) { - mIdIndex.insert({ resId, name }); - } - } - return true; + } + return true; } -std::unique_ptr<Item> BinaryResourceParser::parseValue(const ResourceNameRef& name, - const ConfigDescription& config, - const Res_value* value, - uint16_t flags) { - if (name.type == ResourceType::kId) { - return util::make_unique<Id>(); - } - - const uint32_t data = util::deviceToHost32(value->data); - - if (value->dataType == Res_value::TYPE_STRING) { - const std::string str = util::getString(mValuePool, data); - - const ResStringPool_span* spans = mValuePool.styleAt(data); - - // Check if the string has a valid style associated with it. - if (spans != nullptr && spans->name.index != ResStringPool_span::END) { - StyleString styleStr = { str }; - while (spans->name.index != ResStringPool_span::END) { - styleStr.spans.push_back(Span{ - util::getString(mValuePool, spans->name.index), - spans->firstChar, - spans->lastChar - }); - spans++; - } - return util::make_unique<StyledString>(mTable->stringPool.makeRef( - styleStr, StringPool::Context{1, config})); - } else { - if (name.type != ResourceType::kString && - util::stringStartsWith(str, "res/")) { - // This must be a FileReference. - return util::make_unique<FileReference>(mTable->stringPool.makeRef( - str, StringPool::Context{ 0, config })); - } - - // There are no styles associated with this string, so treat it as - // a simple string. - return util::make_unique<String>(mTable->stringPool.makeRef( - str, StringPool::Context{1, config})); - } - } - - if (value->dataType == Res_value::TYPE_REFERENCE || - value->dataType == Res_value::TYPE_ATTRIBUTE) { - const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE) ? - Reference::Type::kResource : Reference::Type::kAttribute; - - if (data == 0) { - // A reference of 0, must be the magic @null reference. - Res_value nullType = {}; - nullType.dataType = Res_value::TYPE_REFERENCE; - return util::make_unique<BinaryPrimitive>(nullType); - } - - // This is a normal reference. - return util::make_unique<Reference>(data, type); - } - - // Treat this as a raw binary primitive. - return util::make_unique<BinaryPrimitive>(*value); +std::unique_ptr<Item> BinaryResourceParser::parseValue( + const ResourceNameRef& name, const ConfigDescription& config, + const Res_value* value, uint16_t flags) { + if (name.type == ResourceType::kId) { + return util::make_unique<Id>(); + } + + const uint32_t data = util::deviceToHost32(value->data); + + if (value->dataType == Res_value::TYPE_STRING) { + const std::string str = util::getString(mValuePool, data); + + const ResStringPool_span* spans = mValuePool.styleAt(data); + + // Check if the string has a valid style associated with it. + if (spans != nullptr && spans->name.index != ResStringPool_span::END) { + StyleString styleStr = {str}; + while (spans->name.index != ResStringPool_span::END) { + styleStr.spans.push_back( + Span{util::getString(mValuePool, spans->name.index), + spans->firstChar, spans->lastChar}); + spans++; + } + return util::make_unique<StyledString>(mTable->stringPool.makeRef( + styleStr, + StringPool::Context(StringPool::Context::kStylePriority, config))); + } else { + if (name.type != ResourceType::kString && + util::stringStartsWith(str, "res/")) { + // This must be a FileReference. + return util::make_unique<FileReference>(mTable->stringPool.makeRef( + str, + StringPool::Context(StringPool::Context::kHighPriority, config))); + } + + // There are no styles associated with this string, so treat it as + // a simple string. + return util::make_unique<String>( + mTable->stringPool.makeRef(str, StringPool::Context(config))); + } + } + + if (value->dataType == Res_value::TYPE_REFERENCE || + value->dataType == Res_value::TYPE_ATTRIBUTE) { + const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE) + ? Reference::Type::kResource + : Reference::Type::kAttribute; + + if (data == 0) { + // A reference of 0, must be the magic @null reference. + Res_value nullType = {}; + nullType.dataType = Res_value::TYPE_REFERENCE; + return util::make_unique<BinaryPrimitive>(nullType); + } + + // This is a normal reference. + return util::make_unique<Reference>(data, type); + } + + // Treat this as a raw binary primitive. + return util::make_unique<BinaryPrimitive>(*value); } -std::unique_ptr<Value> BinaryResourceParser::parseMapEntry(const ResourceNameRef& name, - const ConfigDescription& config, - const ResTable_map_entry* map) { - switch (name.type) { - case ResourceType::kStyle: - return parseStyle(name, config, map); - case ResourceType::kAttrPrivate: - // fallthrough - case ResourceType::kAttr: - return parseAttr(name, config, map); - case ResourceType::kArray: - return parseArray(name, config, map); - case ResourceType::kPlurals: - return parsePlural(name, config, map); - default: - assert(false && "unknown map type"); - break; - } - return {}; +std::unique_ptr<Value> BinaryResourceParser::parseMapEntry( + const ResourceNameRef& name, const ConfigDescription& config, + const ResTable_map_entry* map) { + switch (name.type) { + case ResourceType::kStyle: + return parseStyle(name, config, map); + case ResourceType::kAttrPrivate: + // fallthrough + case ResourceType::kAttr: + return parseAttr(name, config, map); + case ResourceType::kArray: + return parseArray(name, config, map); + case ResourceType::kPlurals: + return parsePlural(name, config, map); + default: + assert(false && "unknown map type"); + break; + } + return {}; } -std::unique_ptr<Style> BinaryResourceParser::parseStyle(const ResourceNameRef& name, - const ConfigDescription& config, - const ResTable_map_entry* map) { - std::unique_ptr<Style> style = util::make_unique<Style>(); - if (util::deviceToHost32(map->parent.ident) != 0) { - // The parent is a regular reference to a resource. - style->parent = Reference(util::deviceToHost32(map->parent.ident)); - } - - for (const ResTable_map& mapEntry : map) { - if (Res_INTERNALID(util::deviceToHost32(mapEntry.name.ident))) { - continue; - } - - Style::Entry styleEntry; - styleEntry.key = Reference(util::deviceToHost32(mapEntry.name.ident)); - styleEntry.value = parseValue(name, config, &mapEntry.value, 0); - if (!styleEntry.value) { - return {}; - } - style->entries.push_back(std::move(styleEntry)); - } - return style; +std::unique_ptr<Style> BinaryResourceParser::parseStyle( + const ResourceNameRef& name, const ConfigDescription& config, + const ResTable_map_entry* map) { + std::unique_ptr<Style> style = util::make_unique<Style>(); + if (util::deviceToHost32(map->parent.ident) != 0) { + // The parent is a regular reference to a resource. + style->parent = Reference(util::deviceToHost32(map->parent.ident)); + } + + for (const ResTable_map& mapEntry : map) { + if (Res_INTERNALID(util::deviceToHost32(mapEntry.name.ident))) { + continue; + } + + Style::Entry styleEntry; + styleEntry.key = Reference(util::deviceToHost32(mapEntry.name.ident)); + styleEntry.value = parseValue(name, config, &mapEntry.value, 0); + if (!styleEntry.value) { + return {}; + } + style->entries.push_back(std::move(styleEntry)); + } + return style; } -std::unique_ptr<Attribute> BinaryResourceParser::parseAttr(const ResourceNameRef& name, - const ConfigDescription& config, - const ResTable_map_entry* map) { - const bool isWeak = (util::deviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0; - std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak); - - // First we must discover what type of attribute this is. Find the type mask. - auto typeMaskIter = std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool { - return util::deviceToHost32(entry.name.ident) == ResTable_map::ATTR_TYPE; - }); - - if (typeMaskIter != end(map)) { - attr->typeMask = util::deviceToHost32(typeMaskIter->value.data); - } - - for (const ResTable_map& mapEntry : map) { - if (Res_INTERNALID(util::deviceToHost32(mapEntry.name.ident))) { - switch (util::deviceToHost32(mapEntry.name.ident)) { - case ResTable_map::ATTR_MIN: - attr->minInt = static_cast<int32_t>(mapEntry.value.data); - break; - case ResTable_map::ATTR_MAX: - attr->maxInt = static_cast<int32_t>(mapEntry.value.data); - break; - } - continue; - } - - if (attr->typeMask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) { - Attribute::Symbol symbol; - symbol.value = util::deviceToHost32(mapEntry.value.data); - symbol.symbol = Reference(util::deviceToHost32(mapEntry.name.ident)); - attr->symbols.push_back(std::move(symbol)); - } - } - - // TODO(adamlesinski): Find i80n, attributes. - return attr; +std::unique_ptr<Attribute> BinaryResourceParser::parseAttr( + const ResourceNameRef& name, const ConfigDescription& config, + const ResTable_map_entry* map) { + const bool isWeak = + (util::deviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0; + std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak); + + // First we must discover what type of attribute this is. Find the type mask. + auto typeMaskIter = + std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool { + return util::deviceToHost32(entry.name.ident) == + ResTable_map::ATTR_TYPE; + }); + + if (typeMaskIter != end(map)) { + attr->typeMask = util::deviceToHost32(typeMaskIter->value.data); + } + + for (const ResTable_map& mapEntry : map) { + if (Res_INTERNALID(util::deviceToHost32(mapEntry.name.ident))) { + switch (util::deviceToHost32(mapEntry.name.ident)) { + case ResTable_map::ATTR_MIN: + attr->minInt = static_cast<int32_t>(mapEntry.value.data); + break; + case ResTable_map::ATTR_MAX: + attr->maxInt = static_cast<int32_t>(mapEntry.value.data); + break; + } + continue; + } + + if (attr->typeMask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) { + Attribute::Symbol symbol; + symbol.value = util::deviceToHost32(mapEntry.value.data); + symbol.symbol = Reference(util::deviceToHost32(mapEntry.name.ident)); + attr->symbols.push_back(std::move(symbol)); + } + } + + // TODO(adamlesinski): Find i80n, attributes. + return attr; } -std::unique_ptr<Array> BinaryResourceParser::parseArray(const ResourceNameRef& name, - const ConfigDescription& config, - const ResTable_map_entry* map) { - std::unique_ptr<Array> array = util::make_unique<Array>(); - for (const ResTable_map& mapEntry : map) { - array->items.push_back(parseValue(name, config, &mapEntry.value, 0)); - } - return array; +std::unique_ptr<Array> BinaryResourceParser::parseArray( + const ResourceNameRef& name, const ConfigDescription& config, + const ResTable_map_entry* map) { + std::unique_ptr<Array> array = util::make_unique<Array>(); + for (const ResTable_map& mapEntry : map) { + array->items.push_back(parseValue(name, config, &mapEntry.value, 0)); + } + return array; } -std::unique_ptr<Plural> BinaryResourceParser::parsePlural(const ResourceNameRef& name, - const ConfigDescription& config, - const ResTable_map_entry* map) { - std::unique_ptr<Plural> plural = util::make_unique<Plural>(); - for (const ResTable_map& mapEntry : map) { - std::unique_ptr<Item> item = parseValue(name, config, &mapEntry.value, 0); - if (!item) { - return {}; - } - - switch (util::deviceToHost32(mapEntry.name.ident)) { - case ResTable_map::ATTR_ZERO: - plural->values[Plural::Zero] = std::move(item); - break; - case ResTable_map::ATTR_ONE: - plural->values[Plural::One] = std::move(item); - break; - case ResTable_map::ATTR_TWO: - plural->values[Plural::Two] = std::move(item); - break; - case ResTable_map::ATTR_FEW: - plural->values[Plural::Few] = std::move(item); - break; - case ResTable_map::ATTR_MANY: - plural->values[Plural::Many] = std::move(item); - break; - case ResTable_map::ATTR_OTHER: - plural->values[Plural::Other] = std::move(item); - break; - } - } - return plural; +std::unique_ptr<Plural> BinaryResourceParser::parsePlural( + const ResourceNameRef& name, const ConfigDescription& config, + const ResTable_map_entry* map) { + std::unique_ptr<Plural> plural = util::make_unique<Plural>(); + for (const ResTable_map& mapEntry : map) { + std::unique_ptr<Item> item = parseValue(name, config, &mapEntry.value, 0); + if (!item) { + return {}; + } + + switch (util::deviceToHost32(mapEntry.name.ident)) { + case ResTable_map::ATTR_ZERO: + plural->values[Plural::Zero] = std::move(item); + break; + case ResTable_map::ATTR_ONE: + plural->values[Plural::One] = std::move(item); + break; + case ResTable_map::ATTR_TWO: + plural->values[Plural::Two] = std::move(item); + break; + case ResTable_map::ATTR_FEW: + plural->values[Plural::Few] = std::move(item); + break; + case ResTable_map::ATTR_MANY: + plural->values[Plural::Many] = std::move(item); + break; + case ResTable_map::ATTR_OTHER: + plural->values[Plural::Other] = std::move(item); + break; + } + } + return plural; } -} // namespace aapt +} // namespace aapt |