From 24aad163bc88cb10d2275385e9afc3de7f342d65 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Fri, 24 Apr 2015 19:19:30 -0700 Subject: Add namespace handling in attribute values Previously, you could only reference namespace prefixes in attribute names: @@ -371,6 +373,8 @@ bool compileXml(const AaptOptions& options, const std::shared_ptr XmlFlattener flattener(table, {}); XmlFlattener::Options xmlOptions; + xmlOptions.defaultPackage = table->getPackage(); + if (options.versionStylesAndLayouts) { // We strip attributes that do not belong in this version of the resource. // Non-version qualified resources have an implicit version 1 requirement. @@ -432,7 +436,7 @@ bool compileXml(const AaptOptions& options, const std::shared_ptr return true; } -bool linkXml(const AaptOptions& options, const std::shared_ptr& resolver, +bool linkXml(const AaptOptions& options, const std::shared_ptr& resolver, const LinkItem& item, const void* data, size_t dataLen, ZipFile* outApk) { std::shared_ptr tree = std::make_shared(); if (tree->setTo(data, dataLen, false) != android::NO_ERROR) { @@ -443,7 +447,10 @@ bool linkXml(const AaptOptions& options, const std::shared_ptr& resolv BigBuffer outBuffer(1024); XmlFlattener flattener({}, resolver); - if (!flattener.flatten(item.source, xmlParser, &outBuffer, {})) { + + XmlFlattener::Options xmlOptions; + xmlOptions.defaultPackage = item.originalPackage; + if (!flattener.flatten(item.source, xmlParser, &outBuffer, xmlOptions)) { return false; } @@ -490,8 +497,8 @@ bool copyFile(const AaptOptions& options, const CompileItem& item, ZipFile* outA return true; } -bool compileManifest(const AaptOptions& options, const std::shared_ptr& resolver, - ZipFile* outApk) { +bool compileManifest(const AaptOptions& options, + const std::shared_ptr& resolver, ZipFile* outApk) { if (options.verbose) { Logger::note(options.manifest) << "compiling AndroidManifest.xml." << std::endl; } @@ -506,7 +513,9 @@ bool compileManifest(const AaptOptions& options, const std::shared_ptr std::shared_ptr xmlParser = std::make_shared(in); XmlFlattener flattener({}, resolver); - if (!flattener.flatten(options.manifest, xmlParser, &outBuffer, {})) { + XmlFlattener::Options xmlOptions; + xmlOptions.defaultPackage = options.appInfo.package; + if (!flattener.flatten(options.manifest, xmlParser, &outBuffer, xmlOptions)) { return false; } @@ -640,8 +649,12 @@ static void addApkFilesToLinkQueue(const std::u16string& package, const Source& for (auto& value : entry->values) { visitFunc(*value.value, [&](FileReference& ref) { std::string pathUtf8 = util::utf16ToUtf8(*ref.path); + Source newSource = source; + newSource.path += "/"; + newSource.path += pathUtf8; outLinkQueue->push(LinkItem{ - source, name, value.config, pathUtf8, apk.get() }); + newSource, name, value.config, pathUtf8, apk.get(), + table->getPackage() }); // Now rewrite the file path. if (mangle) { ref.path = table->getValueStringPool().makeRef(util::utf8ToUtf16( @@ -657,9 +670,20 @@ static void addApkFilesToLinkQueue(const std::u16string& package, const Source& static constexpr int kOpenFlags = ZipFile::kOpenCreate | ZipFile::kOpenTruncate | ZipFile::kOpenReadWrite; +struct DeleteMalloc { + void operator()(void* ptr) { + free(ptr); + } +}; + +struct StaticLibraryData { + Source source; + std::unique_ptr apk; +}; + bool link(const AaptOptions& options, const std::shared_ptr& outTable, - const std::shared_ptr& resolver) { - std::map, std::unique_ptr> apkFiles; + const std::shared_ptr& resolver) { + std::map, StaticLibraryData> apkFiles; std::unordered_set linkedPackages; // Populate the linkedPackages with our own. @@ -681,19 +705,18 @@ bool link(const AaptOptions& options, const std::shared_ptr& outT return false; } - void* uncompressedData = zipFile->uncompress(entry); + std::unique_ptr uncompressedData = std::unique_ptr( + zipFile->uncompress(entry)); assert(uncompressedData); - BinaryResourceParser parser(table, resolver, source, uncompressedData, + BinaryResourceParser parser(table, resolver, source, uncompressedData.get(), entry->getUncompressedLen()); if (!parser.parse()) { - free(uncompressedData); return false; } - free(uncompressedData); // Keep track of where this table came from. - apkFiles[table] = std::move(zipFile); + apkFiles[table] = StaticLibraryData{ source, std::move(zipFile) }; // Add the package to the set of linked packages. linkedPackages.insert(table->getPackage()); @@ -704,7 +727,8 @@ bool link(const AaptOptions& options, const std::shared_ptr& outT const std::shared_ptr& inTable = p.first; // Collect all FileReferences and add them to the queue for processing. - addApkFilesToLinkQueue(options.appInfo.package, Source{}, inTable, p.second, &linkQueue); + addApkFilesToLinkQueue(options.appInfo.package, p.second.source, inTable, p.second.apk, + &linkQueue); // Merge the tables. if (!outTable->merge(std::move(*inTable))) { @@ -746,6 +770,7 @@ bool link(const AaptOptions& options, const std::shared_ptr& outT for (; !linkQueue.empty(); linkQueue.pop()) { const LinkItem& item = linkQueue.front(); + assert(!item.originalPackage.empty()); ZipEntry* entry = item.apk->getEntryByName(item.originalPath.data()); if (!entry) { Logger::error(item.source) << "failed to find '" << item.originalPath << "'." @@ -811,6 +836,20 @@ bool link(const AaptOptions& options, const std::shared_ptr& outT } } + outTable->getValueStringPool().prune(); + outTable->getValueStringPool().sort( + [](const StringPool::Entry& a, const StringPool::Entry& b) -> bool { + if (a.context.priority < b.context.priority) { + return true; + } + + if (a.context.priority > b.context.priority) { + return false; + } + return a.value < b.value; + }); + + // Flatten the resource table. TableFlattener::Options flattenerOptions; flattenerOptions.useExtendedChunks = false; @@ -823,7 +862,7 @@ bool link(const AaptOptions& options, const std::shared_ptr& outT } bool compile(const AaptOptions& options, const std::shared_ptr& table, - const std::shared_ptr& resolver) { + const std::shared_ptr& resolver) { std::queue compileQueue; bool error = false; @@ -1073,7 +1112,8 @@ int main(int argc, char** argv) { } // Make the resolver that will cache IDs for us. - std::shared_ptr resolver = std::make_shared(table, libraries); + std::shared_ptr resolver = std::make_shared( + table, libraries); if (options.phase == AaptOptions::Phase::Compile) { if (!compile(options, table, resolver)) { -- cgit v1.2.3-59-g8ed1b