From 0faba5fdfab0f2af85aaed468e7d0933680e276e Mon Sep 17 00:00:00 2001 From: Izabela Orlowska Date: Fri, 1 Jun 2018 12:06:31 +0100 Subject: [PATCH] AAPT2: allow regexes for extensions to not compress Change-Id: I09d2ad1d1466643ca7628c6480224e16b9002ee5 Fixes: 67575899 Test: added + manual --- tools/aapt2/cmd/Link.cpp | 29 ++++++++++++++++++++++++++++- tools/aapt2/cmd/Link.h | 9 +++++++++ tools/aapt2/cmd/Util.cpp | 7 +++++++ tools/aapt2/cmd/Util.h | 5 +++++ tools/aapt2/cmd/Util_test.cpp | 8 ++++++++ tools/aapt2/util/Files.cpp | 19 +++++++++++++++++++ tools/aapt2/util/Files.h | 5 +++++ 7 files changed, 81 insertions(+), 1 deletion(-) diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 8463046a80eb1..0befb6ff7c9d4 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -268,6 +268,7 @@ struct ResourceFileFlattenerOptions { bool update_proguard_spec = false; OutputFormat output_format = OutputFormat::kApk; std::unordered_set extensions_to_not_compress; + Maybe regex_to_not_compress; }; // A sampling of public framework resource IDs. @@ -377,11 +378,18 @@ ResourceFileFlattener::ResourceFileFlattener(const ResourceFileFlattenerOptions& } } +// TODO(rtmitchell): turn this function into a variable that points to a method that retrieves the +// compression flag uint32_t ResourceFileFlattener::GetCompressionFlags(const StringPiece& str) { if (options_.do_not_compress_anything) { return 0; } + if (options_.regex_to_not_compress + && std::regex_search(str.to_string(), options_.regex_to_not_compress.value())) { + return 0; + } + for (const std::string& extension : options_.extensions_to_not_compress) { if (util::EndsWith(str, extension)) { return 0; @@ -1530,7 +1538,11 @@ class Linker { for (auto& entry : merged_assets) { uint32_t compression_flags = ArchiveEntry::kCompress; std::string extension = file::GetExtension(entry.first).to_string(); - if (options_.extensions_to_not_compress.count(extension) > 0) { + + if (options_.do_not_compress_anything + || options_.extensions_to_not_compress.count(extension) > 0 + || (options_.regex_to_not_compress + && std::regex_search(extension, options_.regex_to_not_compress.value()))) { compression_flags = 0u; } @@ -1558,6 +1570,7 @@ class Linker { file_flattener_options.keep_raw_values = keep_raw_values; file_flattener_options.do_not_compress_anything = options_.do_not_compress_anything; file_flattener_options.extensions_to_not_compress = options_.extensions_to_not_compress; + file_flattener_options.regex_to_not_compress = options_.regex_to_not_compress; file_flattener_options.no_auto_version = options_.no_auto_version; file_flattener_options.no_version_vectors = options_.no_version_vectors; file_flattener_options.no_version_transitions = options_.no_version_transitions; @@ -2165,6 +2178,20 @@ int LinkCommand::Action(const std::vector& args) { } } + if (no_compress_regex) { + std::string regex = no_compress_regex.value(); + if (util::StartsWith(regex, "@")) { + const std::string path = regex.substr(1, regex.size() -1); + std::string error; + if (!file::AppendSetArgsFromFile(path, &options_.extensions_to_not_compress, &error)) { + context.GetDiagnostics()->Error(DiagMessage(path) << error); + return 1; + } + } else { + options_.regex_to_not_compress = GetRegularExpression(no_compress_regex.value()); + } + } + // Populate some default no-compress extensions that are already compressed. options_.extensions_to_not_compress.insert( {".jpg", ".jpeg", ".png", ".gif", ".wav", ".mp2", ".mp3", ".ogg", diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 590a6bb19e30c..1fc149ab41afc 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -17,6 +17,8 @@ #ifndef AAPT2_LINK_H #define AAPT2_LINK_H +#include + #include "Command.h" #include "Diagnostics.h" #include "Resource.h" @@ -63,6 +65,7 @@ struct LinkOptions { bool no_xml_namespaces = false; bool do_not_compress_anything = false; std::unordered_set extensions_to_not_compress; + Maybe regex_to_not_compress; // Static lib options. bool no_static_lib_packages = false; @@ -250,6 +253,11 @@ class LinkCommand : public Command { &options_.do_not_compress_anything); AddOptionalSwitch("--keep-raw-values", "Preserve raw attribute values in xml files.", &options_.keep_raw_values); + AddOptionalFlag("--no-compress-regex", + "Do not compress extensions matching the regular expression. Remember to\n" + " use the '$' symbol for end of line. Uses a non case-sensitive\n" + " ECMAScript regular expression grammar.", + &no_compress_regex); AddOptionalSwitch("--warn-manifest-validation", "Treat manifest validation errors as warnings.", &options_.manifest_fixer_options.warn_validation); @@ -283,6 +291,7 @@ class LinkCommand : public Command { std::vector configs_; Maybe preferred_density_; Maybe product_list_; + Maybe no_compress_regex; bool legacy_x_flag_ = false; bool require_localization_ = false; bool verbose_ = false; diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp index 792120e449aec..e2c65ba74271d 100644 --- a/tools/aapt2/cmd/Util.cpp +++ b/tools/aapt2/cmd/Util.cpp @@ -435,4 +435,11 @@ void SetLongVersionCode(xml::Element* manifest, uint64_t version) { } } +std::regex GetRegularExpression(const std::string &input) { + // Standard ECMAScript grammar plus case insensitive. + std::regex case_insensitive( + input, std::regex_constants::icase | std::regex_constants::ECMAScript); + return case_insensitive; +} + } // namespace aapt diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h index cf1443e30e1f1..2a7c62eef6784 100644 --- a/tools/aapt2/cmd/Util.h +++ b/tools/aapt2/cmd/Util.h @@ -17,6 +17,8 @@ #ifndef AAPT_SPLIT_UTIL_H #define AAPT_SPLIT_UTIL_H +#include + #include "androidfw/StringPiece.h" #include "AppInfo.h" @@ -72,6 +74,9 @@ std::string MakePackageSafeName(const std::string &name); // versionCodeMajor if the version code requires more than 32 bits. void SetLongVersionCode(xml::Element* manifest, uint64_t version_code); +// Returns a case insensitive regular expression based on the input. +std::regex GetRegularExpression(const std::string &input); + } // namespace aapt #endif /* AAPT_SPLIT_UTIL_H */ diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp index f92f1e3c4c7e1..7e492610b658a 100644 --- a/tools/aapt2/cmd/Util_test.cpp +++ b/tools/aapt2/cmd/Util_test.cpp @@ -383,4 +383,12 @@ TEST (UtilTest, AdjustSplitConstraintsForMinSdk) { EXPECT_NE(*adjusted_contraints[1].configs.begin(), ConfigDescription::DefaultConfig()); } +TEST(UtilTest, RegularExperssions) { + std::string valid(".bc$"); + std::regex expression = GetRegularExpression(valid); + EXPECT_TRUE(std::regex_search("file.abc", expression)); + EXPECT_TRUE(std::regex_search("file.123bc", expression)); + EXPECT_FALSE(std::regex_search("abc.zip", expression)); +} + } // namespace aapt diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index 7b268bb283f4b..604b2575daa17 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -251,6 +251,25 @@ bool AppendArgsFromFile(const StringPiece& path, std::vector* out_a return true; } +bool AppendSetArgsFromFile(const StringPiece& path, std::unordered_set* out_argset, + std::string* out_error) { + std::string contents; + if(!ReadFileToString(path.to_string(), &contents, true /*follow_symlinks*/)) { + if (out_error) { + *out_error = "failed to read argument-list file"; + } + return false; + } + + for (StringPiece line : util::Tokenize(contents, ' ')) { + line = util::TrimWhitespace(line); + if (!line.empty()) { + out_argset->insert(line.to_string()); + } + } + return true; +} + bool FileFilter::SetPattern(const StringPiece& pattern) { pattern_tokens_ = util::SplitAndLowercase(pattern, ':'); return true; diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h index 58395526b193a..481a4cdb6ad09 100644 --- a/tools/aapt2/util/Files.h +++ b/tools/aapt2/util/Files.h @@ -19,6 +19,7 @@ #include #include +#include #include #include "android-base/macros.h" @@ -86,6 +87,10 @@ Maybe MmapPath(const std::string& path, std::string* out_error bool AppendArgsFromFile(const android::StringPiece& path, std::vector* out_arglist, std::string* out_error); +// Reads the file at path and appends each line to the outargset set. +bool AppendSetArgsFromFile(const android::StringPiece& path, + std::unordered_set* out_argset, std::string* out_error); + // Filter that determines which resource files/directories are // processed by AAPT. Takes a pattern string supplied by the user. // Pattern format is specified in the FileFilter::SetPattern() method.