Loading tools/aapt2/Android.mk +3 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ sources := \ flatten/TableFlattener.cpp \ flatten/XmlFlattener.cpp \ link/AutoVersioner.cpp \ link/ManifestFixer.cpp \ link/PrivateAttributeMover.cpp \ link/ReferenceLinker.cpp \ link/TableMerger.cpp \ Loading Loading @@ -67,6 +68,7 @@ testSources := \ flatten/TableFlattener_test.cpp \ flatten/XmlFlattener_test.cpp \ link/AutoVersioner_test.cpp \ link/ManifestFixer_test.cpp \ link/PrivateAttributeMover_test.cpp \ link/ReferenceLinker_test.cpp \ link/TableMerger_test.cpp \ Loading Loading @@ -113,7 +115,7 @@ else endif cFlags := -Wall -Werror -Wno-unused-parameter -UNDEBUG cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions -fno-rtti # ========================================================== # Build the host static library: libaapt2 Loading tools/aapt2/Flags.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "Flags.h" #include "util/StringPiece.h" #include "util/Util.h" #include <iomanip> #include <iostream> Loading Loading @@ -94,7 +95,14 @@ void Flags::usage(const StringPiece& command, std::ostream* out) { if (flag.numArgs > 0) { argLine += " arg"; } *out << " " << std::setw(30) << std::left << argLine << flag.description << "\n"; // Split the description by newlines and write out the argument (which is empty after // the first line) followed by the description line. This will make sure that multiline // descriptions are still right justified and aligned. for (StringPiece line : util::tokenize<char>(flag.description, '\n')) { *out << " " << std::setw(30) << std::left << argLine << line << "\n"; argLine = " "; } } *out << " " << std::setw(30) << std::left << "-h" << "Displays this help menu\n"; out->flush(); Loading tools/aapt2/ManifestValidator.cppdeleted 100644 → 0 +0 −217 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Logger.h" #include "ManifestValidator.h" #include "util/Maybe.h" #include "Source.h" #include "util/Util.h" #include <androidfw/ResourceTypes.h> namespace aapt { ManifestValidator::ManifestValidator(const android::ResTable& table) : mTable(table) { } bool ManifestValidator::validate(const Source& source, android::ResXMLParser* parser) { SourceLogger logger(source); android::ResXMLParser::event_code_t code; while ((code = parser->next()) != android::ResXMLParser::END_DOCUMENT && code != android::ResXMLParser::BAD_DOCUMENT) { if (code != android::ResXMLParser::START_TAG) { continue; } size_t len = 0; const StringPiece16 namespaceUri(parser->getElementNamespace(&len), len); if (!namespaceUri.empty()) { continue; } const StringPiece16 name(parser->getElementName(&len), len); if (name.empty()) { logger.error(parser->getLineNumber()) << "failed to get the element name." << std::endl; return false; } if (name == u"manifest") { if (!validateManifest(source, parser)) { return false; } } } return true; } Maybe<StringPiece16> ManifestValidator::getAttributeValue(android::ResXMLParser* parser, size_t idx) { android::Res_value value; if (parser->getAttributeValue(idx, &value) < 0) { return StringPiece16(); } const android::ResStringPool* pool = &parser->getStrings(); if (value.dataType == android::Res_value::TYPE_REFERENCE) { ssize_t strIdx = mTable.resolveReference(&value, 0x10000000u); if (strIdx < 0) { return {}; } pool = mTable.getTableStringBlock(strIdx); } if (value.dataType != android::Res_value::TYPE_STRING || !pool) { return {}; } return util::getString(*pool, value.data); } Maybe<StringPiece16> ManifestValidator::getAttributeInlineValue(android::ResXMLParser* parser, size_t idx) { android::Res_value value; if (parser->getAttributeValue(idx, &value) < 0) { return StringPiece16(); } if (value.dataType != android::Res_value::TYPE_STRING) { return {}; } return util::getString(parser->getStrings(), value.data); } bool ManifestValidator::validateInlineAttribute(android::ResXMLParser* parser, size_t idx, SourceLogger& logger, const StringPiece16& charSet) { size_t len = 0; StringPiece16 element(parser->getElementName(&len), len); StringPiece16 attributeName(parser->getAttributeName(idx, &len), len); Maybe<StringPiece16> result = getAttributeInlineValue(parser, idx); if (!result) { logger.error(parser->getLineNumber()) << "<" << element << "> must have a '" << attributeName << "' attribute with a string literal value." << std::endl; return false; } return validateAttributeImpl(element, attributeName, result.value(), charSet, parser->getLineNumber(), logger); } bool ManifestValidator::validateAttribute(android::ResXMLParser* parser, size_t idx, SourceLogger& logger, const StringPiece16& charSet) { size_t len = 0; StringPiece16 element(parser->getElementName(&len), len); StringPiece16 attributeName(parser->getAttributeName(idx, &len), len); Maybe<StringPiece16> result = getAttributeValue(parser, idx); if (!result) { logger.error(parser->getLineNumber()) << "<" << element << "> must have a '" << attributeName << "' attribute that points to a string." << std::endl; return false; } return validateAttributeImpl(element, attributeName, result.value(), charSet, parser->getLineNumber(), logger); } bool ManifestValidator::validateAttributeImpl(const StringPiece16& element, const StringPiece16& attributeName, const StringPiece16& attributeValue, const StringPiece16& charSet, size_t lineNumber, SourceLogger& logger) { StringPiece16::const_iterator badIter = util::findNonAlphaNumericAndNotInSet(attributeValue, charSet); if (badIter != attributeValue.end()) { logger.error(lineNumber) << "tag <" << element << "> attribute '" << attributeName << "' has invalid character '" << StringPiece16(badIter, 1) << "'." << std::endl; return false; } if (!attributeValue.empty()) { StringPiece16 trimmed = util::trimWhitespace(attributeValue); if (attributeValue.begin() != trimmed.begin()) { logger.error(lineNumber) << "tag <" << element << "> attribute '" << attributeName << "' can not start with whitespace." << std::endl; return false; } if (attributeValue.end() != trimmed.end()) { logger.error(lineNumber) << "tag <" << element << "> attribute '" << attributeName << "' can not end with whitespace." << std::endl; return false; } } return true; } constexpr const char16_t* kPackageIdentSet = u"._"; bool ManifestValidator::validateManifest(const Source& source, android::ResXMLParser* parser) { bool error = false; SourceLogger logger(source); const StringPiece16 kAndroid = u"android"; const StringPiece16 kPackage = u"package"; const StringPiece16 kSharedUserId = u"sharedUserId"; ssize_t idx; idx = parser->indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()); if (idx < 0) { logger.error(parser->getLineNumber()) << "missing package attribute." << std::endl; error = true; } else { error |= !validateInlineAttribute(parser, idx, logger, kPackageIdentSet); } idx = parser->indexOfAttribute(kAndroid.data(), kAndroid.size(), kSharedUserId.data(), kSharedUserId.size()); if (idx >= 0) { error |= !validateInlineAttribute(parser, idx, logger, kPackageIdentSet); } return !error; } } // namespace aapt tools/aapt2/ResourceUtils.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -74,9 +74,11 @@ bool tryParseReference(const StringPiece16& str, ResourceNameRef* outRef, bool* return false; } if (outRef != nullptr) { outRef->package = package; outRef->type = *parsedType; outRef->entry = entry; } if (outCreate) { *outCreate = create; } Loading @@ -88,6 +90,10 @@ bool tryParseReference(const StringPiece16& str, ResourceNameRef* outRef, bool* return false; } bool isReference(const StringPiece16& str) { return tryParseReference(str, nullptr, nullptr, nullptr); } bool tryParseAttributeReference(const StringPiece16& str, ResourceNameRef* outRef) { StringPiece16 trimmedStr(util::trimWhitespace(str)); if (trimmedStr.empty()) { Loading tools/aapt2/ResourceUtils.h +5 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,11 @@ void extractResourceName(const StringPiece16& str, StringPiece16* outPackage, bool tryParseReference(const StringPiece16& str, ResourceNameRef* outReference, bool* outCreate = nullptr, bool* outPrivate = nullptr); /* * Returns true if the string is in the form of a resource reference (@[+][package:]type/name). */ bool isReference(const StringPiece16& str); /* * Returns true if the string was parsed as an attribute reference (?[package:]type/name), * with `outReference` set to the parsed reference. Loading Loading
tools/aapt2/Android.mk +3 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ sources := \ flatten/TableFlattener.cpp \ flatten/XmlFlattener.cpp \ link/AutoVersioner.cpp \ link/ManifestFixer.cpp \ link/PrivateAttributeMover.cpp \ link/ReferenceLinker.cpp \ link/TableMerger.cpp \ Loading Loading @@ -67,6 +68,7 @@ testSources := \ flatten/TableFlattener_test.cpp \ flatten/XmlFlattener_test.cpp \ link/AutoVersioner_test.cpp \ link/ManifestFixer_test.cpp \ link/PrivateAttributeMover_test.cpp \ link/ReferenceLinker_test.cpp \ link/TableMerger_test.cpp \ Loading Loading @@ -113,7 +115,7 @@ else endif cFlags := -Wall -Werror -Wno-unused-parameter -UNDEBUG cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions -fno-rtti # ========================================================== # Build the host static library: libaapt2 Loading
tools/aapt2/Flags.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "Flags.h" #include "util/StringPiece.h" #include "util/Util.h" #include <iomanip> #include <iostream> Loading Loading @@ -94,7 +95,14 @@ void Flags::usage(const StringPiece& command, std::ostream* out) { if (flag.numArgs > 0) { argLine += " arg"; } *out << " " << std::setw(30) << std::left << argLine << flag.description << "\n"; // Split the description by newlines and write out the argument (which is empty after // the first line) followed by the description line. This will make sure that multiline // descriptions are still right justified and aligned. for (StringPiece line : util::tokenize<char>(flag.description, '\n')) { *out << " " << std::setw(30) << std::left << argLine << line << "\n"; argLine = " "; } } *out << " " << std::setw(30) << std::left << "-h" << "Displays this help menu\n"; out->flush(); Loading
tools/aapt2/ManifestValidator.cppdeleted 100644 → 0 +0 −217 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Logger.h" #include "ManifestValidator.h" #include "util/Maybe.h" #include "Source.h" #include "util/Util.h" #include <androidfw/ResourceTypes.h> namespace aapt { ManifestValidator::ManifestValidator(const android::ResTable& table) : mTable(table) { } bool ManifestValidator::validate(const Source& source, android::ResXMLParser* parser) { SourceLogger logger(source); android::ResXMLParser::event_code_t code; while ((code = parser->next()) != android::ResXMLParser::END_DOCUMENT && code != android::ResXMLParser::BAD_DOCUMENT) { if (code != android::ResXMLParser::START_TAG) { continue; } size_t len = 0; const StringPiece16 namespaceUri(parser->getElementNamespace(&len), len); if (!namespaceUri.empty()) { continue; } const StringPiece16 name(parser->getElementName(&len), len); if (name.empty()) { logger.error(parser->getLineNumber()) << "failed to get the element name." << std::endl; return false; } if (name == u"manifest") { if (!validateManifest(source, parser)) { return false; } } } return true; } Maybe<StringPiece16> ManifestValidator::getAttributeValue(android::ResXMLParser* parser, size_t idx) { android::Res_value value; if (parser->getAttributeValue(idx, &value) < 0) { return StringPiece16(); } const android::ResStringPool* pool = &parser->getStrings(); if (value.dataType == android::Res_value::TYPE_REFERENCE) { ssize_t strIdx = mTable.resolveReference(&value, 0x10000000u); if (strIdx < 0) { return {}; } pool = mTable.getTableStringBlock(strIdx); } if (value.dataType != android::Res_value::TYPE_STRING || !pool) { return {}; } return util::getString(*pool, value.data); } Maybe<StringPiece16> ManifestValidator::getAttributeInlineValue(android::ResXMLParser* parser, size_t idx) { android::Res_value value; if (parser->getAttributeValue(idx, &value) < 0) { return StringPiece16(); } if (value.dataType != android::Res_value::TYPE_STRING) { return {}; } return util::getString(parser->getStrings(), value.data); } bool ManifestValidator::validateInlineAttribute(android::ResXMLParser* parser, size_t idx, SourceLogger& logger, const StringPiece16& charSet) { size_t len = 0; StringPiece16 element(parser->getElementName(&len), len); StringPiece16 attributeName(parser->getAttributeName(idx, &len), len); Maybe<StringPiece16> result = getAttributeInlineValue(parser, idx); if (!result) { logger.error(parser->getLineNumber()) << "<" << element << "> must have a '" << attributeName << "' attribute with a string literal value." << std::endl; return false; } return validateAttributeImpl(element, attributeName, result.value(), charSet, parser->getLineNumber(), logger); } bool ManifestValidator::validateAttribute(android::ResXMLParser* parser, size_t idx, SourceLogger& logger, const StringPiece16& charSet) { size_t len = 0; StringPiece16 element(parser->getElementName(&len), len); StringPiece16 attributeName(parser->getAttributeName(idx, &len), len); Maybe<StringPiece16> result = getAttributeValue(parser, idx); if (!result) { logger.error(parser->getLineNumber()) << "<" << element << "> must have a '" << attributeName << "' attribute that points to a string." << std::endl; return false; } return validateAttributeImpl(element, attributeName, result.value(), charSet, parser->getLineNumber(), logger); } bool ManifestValidator::validateAttributeImpl(const StringPiece16& element, const StringPiece16& attributeName, const StringPiece16& attributeValue, const StringPiece16& charSet, size_t lineNumber, SourceLogger& logger) { StringPiece16::const_iterator badIter = util::findNonAlphaNumericAndNotInSet(attributeValue, charSet); if (badIter != attributeValue.end()) { logger.error(lineNumber) << "tag <" << element << "> attribute '" << attributeName << "' has invalid character '" << StringPiece16(badIter, 1) << "'." << std::endl; return false; } if (!attributeValue.empty()) { StringPiece16 trimmed = util::trimWhitespace(attributeValue); if (attributeValue.begin() != trimmed.begin()) { logger.error(lineNumber) << "tag <" << element << "> attribute '" << attributeName << "' can not start with whitespace." << std::endl; return false; } if (attributeValue.end() != trimmed.end()) { logger.error(lineNumber) << "tag <" << element << "> attribute '" << attributeName << "' can not end with whitespace." << std::endl; return false; } } return true; } constexpr const char16_t* kPackageIdentSet = u"._"; bool ManifestValidator::validateManifest(const Source& source, android::ResXMLParser* parser) { bool error = false; SourceLogger logger(source); const StringPiece16 kAndroid = u"android"; const StringPiece16 kPackage = u"package"; const StringPiece16 kSharedUserId = u"sharedUserId"; ssize_t idx; idx = parser->indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()); if (idx < 0) { logger.error(parser->getLineNumber()) << "missing package attribute." << std::endl; error = true; } else { error |= !validateInlineAttribute(parser, idx, logger, kPackageIdentSet); } idx = parser->indexOfAttribute(kAndroid.data(), kAndroid.size(), kSharedUserId.data(), kSharedUserId.size()); if (idx >= 0) { error |= !validateInlineAttribute(parser, idx, logger, kPackageIdentSet); } return !error; } } // namespace aapt
tools/aapt2/ResourceUtils.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -74,9 +74,11 @@ bool tryParseReference(const StringPiece16& str, ResourceNameRef* outRef, bool* return false; } if (outRef != nullptr) { outRef->package = package; outRef->type = *parsedType; outRef->entry = entry; } if (outCreate) { *outCreate = create; } Loading @@ -88,6 +90,10 @@ bool tryParseReference(const StringPiece16& str, ResourceNameRef* outRef, bool* return false; } bool isReference(const StringPiece16& str) { return tryParseReference(str, nullptr, nullptr, nullptr); } bool tryParseAttributeReference(const StringPiece16& str, ResourceNameRef* outRef) { StringPiece16 trimmedStr(util::trimWhitespace(str)); if (trimmedStr.empty()) { Loading
tools/aapt2/ResourceUtils.h +5 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,11 @@ void extractResourceName(const StringPiece16& str, StringPiece16* outPackage, bool tryParseReference(const StringPiece16& str, ResourceNameRef* outReference, bool* outCreate = nullptr, bool* outPrivate = nullptr); /* * Returns true if the string is in the form of a resource reference (@[+][package:]type/name). */ bool isReference(const StringPiece16& str); /* * Returns true if the string was parsed as an attribute reference (?[package:]type/name), * with `outReference` set to the parsed reference. Loading