Properly mangle file names
Change-Id: I49c0f82e8c06f056198eb64b8369d83403b74321
This commit is contained in:
@@ -603,6 +603,13 @@ std::unique_ptr<Item> BinaryResourceParser::parseValue(const ResourceNameRef& na
|
||||
mTable->getValueStringPool().makeRef(
|
||||
styleStr, StringPool::Context{1, config}));
|
||||
} else {
|
||||
if (name.type != ResourceType::kString &&
|
||||
util::stringStartsWith<char16_t>(str, u"res/")) {
|
||||
// This must be a FileReference.
|
||||
return util::make_unique<FileReference>(mTable->getValueStringPool().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>(
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Linker.h"
|
||||
#include "ManifestParser.h"
|
||||
#include "ManifestValidator.h"
|
||||
#include "NameMangler.h"
|
||||
#include "Png.h"
|
||||
#include "ResourceParser.h"
|
||||
#include "ResourceTable.h"
|
||||
@@ -266,22 +267,50 @@ struct CompileItem {
|
||||
|
||||
struct LinkItem {
|
||||
Source source;
|
||||
std::string apkPath;
|
||||
ResourceName name;
|
||||
ConfigDescription config;
|
||||
std::string originalPath;
|
||||
ZipFile* apk;
|
||||
};
|
||||
|
||||
std::string buildFileReference(const CompileItem& item) {
|
||||
std::stringstream path;
|
||||
path << "res/" << item.name.type;
|
||||
if (item.config != ConfigDescription{}) {
|
||||
path << "-" << item.config;
|
||||
template <typename TChar>
|
||||
static BasicStringPiece<TChar> getExtension(const BasicStringPiece<TChar>& str) {
|
||||
auto iter = std::find(str.begin(), str.end(), static_cast<TChar>('.'));
|
||||
if (iter == str.end()) {
|
||||
return BasicStringPiece<TChar>();
|
||||
}
|
||||
size_t offset = (iter - str.begin()) + 1;
|
||||
return str.substr(offset, str.size() - offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string buildFileReference(const ResourceNameRef& name, const ConfigDescription& config,
|
||||
const StringPiece& extension) {
|
||||
std::stringstream path;
|
||||
path << "res/" << name.type;
|
||||
if (config != ConfigDescription{}) {
|
||||
path << "-" << config;
|
||||
}
|
||||
path << "/" << util::utf16ToUtf8(name.entry);
|
||||
if (!extension.empty()) {
|
||||
path << "." << extension;
|
||||
}
|
||||
path << "/" << util::utf16ToUtf8(item.name.entry) + "." + item.extension;
|
||||
return path.str();
|
||||
}
|
||||
|
||||
std::string buildFileReference(const CompileItem& item) {
|
||||
return buildFileReference(item.name, item.config, item.extension);
|
||||
}
|
||||
|
||||
std::string buildFileReference(const LinkItem& item) {
|
||||
return buildFileReference(item.name, item.config, getExtension<char>(item.originalPath));
|
||||
}
|
||||
|
||||
bool addFileReference(const std::shared_ptr<ResourceTable>& table, const CompileItem& item) {
|
||||
StringPool& pool = table->getValueStringPool();
|
||||
StringPool::Ref ref = pool.makeRef(util::utf8ToUtf16(buildFileReference(item)));
|
||||
StringPool::Ref ref = pool.makeRef(util::utf8ToUtf16(buildFileReference(item)),
|
||||
StringPool::Context{ 0, item.config });
|
||||
return table->addResource(item.name, item.config, item.source.line(0),
|
||||
util::make_unique<FileReference>(ref));
|
||||
}
|
||||
@@ -418,8 +447,8 @@ bool linkXml(const AaptOptions& options, const std::shared_ptr<Resolver>& resolv
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outApk->add(outBuffer, item.apkPath.data(), ZipEntry::kCompressDeflated, nullptr) !=
|
||||
android::NO_ERROR) {
|
||||
if (outApk->add(outBuffer, buildFileReference(item).data(), ZipEntry::kCompressDeflated,
|
||||
nullptr) != android::NO_ERROR) {
|
||||
Logger::error(options.output) << "failed to write linked file '" << item.source
|
||||
<< "' to apk." << std::endl;
|
||||
return false;
|
||||
@@ -502,109 +531,6 @@ bool compileManifest(const AaptOptions& options, const std::shared_ptr<Resolver>
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadAppInfo(const Source& source, AppInfo* outInfo) {
|
||||
std::ifstream ifs(source.path, std::ifstream::in | std::ifstream::binary);
|
||||
if (!ifs) {
|
||||
Logger::error(source) << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ManifestParser parser;
|
||||
std::shared_ptr<XmlPullParser> pullParser = std::make_shared<SourceXmlPullParser>(ifs);
|
||||
return parser.parse(source, pullParser, outInfo);
|
||||
}
|
||||
|
||||
static void printCommandsAndDie() {
|
||||
std::cerr << "The following commands are supported:" << std::endl << std::endl;
|
||||
std::cerr << "compile compiles a subset of resources" << std::endl;
|
||||
std::cerr << "link links together compiled resources and libraries" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "run aapt2 with one of the commands and the -h flag for extra details."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static AaptOptions prepareArgs(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "no command specified." << std::endl << std::endl;
|
||||
printCommandsAndDie();
|
||||
}
|
||||
|
||||
const StringPiece command(argv[1]);
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
AaptOptions options;
|
||||
|
||||
if (command == "--version" || command == "version") {
|
||||
std::cout << kAaptVersionStr << std::endl;
|
||||
exit(0);
|
||||
} else if (command == "link") {
|
||||
options.phase = AaptOptions::Phase::Link;
|
||||
} else if (command == "compile") {
|
||||
options.phase = AaptOptions::Phase::Compile;
|
||||
} else {
|
||||
std::cerr << "invalid command '" << command << "'." << std::endl << std::endl;
|
||||
printCommandsAndDie();
|
||||
}
|
||||
|
||||
if (options.phase == AaptOptions::Phase::Compile) {
|
||||
flag::requiredFlag("--package", "Android package name",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.appInfo.package = util::utf8ToUtf16(arg);
|
||||
});
|
||||
flag::optionalFlag("--binding", "Output directory for binding XML files",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.bindingOutput = Source{ arg.toString() };
|
||||
});
|
||||
flag::optionalSwitch("--no-version", "Disables automatic style and layout versioning",
|
||||
false, &options.versionStylesAndLayouts);
|
||||
|
||||
} else if (options.phase == AaptOptions::Phase::Link) {
|
||||
flag::requiredFlag("--manifest", "AndroidManifest.xml of your app",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.manifest = Source{ arg.toString() };
|
||||
});
|
||||
|
||||
flag::optionalFlag("-I", "add an Android APK to link against",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.libraries.push_back(Source{ arg.toString() });
|
||||
});
|
||||
|
||||
flag::optionalFlag("--java", "directory in which to generate R.java",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.generateJavaClass = Source{ arg.toString() };
|
||||
});
|
||||
}
|
||||
|
||||
// Common flags for all steps.
|
||||
flag::requiredFlag("-o", "Output path", [&options](const StringPiece& arg) {
|
||||
options.output = Source{ arg.toString() };
|
||||
});
|
||||
|
||||
bool help = false;
|
||||
flag::optionalSwitch("-v", "enables verbose logging", true, &options.verbose);
|
||||
flag::optionalSwitch("-h", "displays this help menu", true, &help);
|
||||
|
||||
// Build the command string for output (eg. "aapt2 compile").
|
||||
std::string fullCommand = "aapt2";
|
||||
fullCommand += " ";
|
||||
fullCommand += command.toString();
|
||||
|
||||
// Actually read the command line flags.
|
||||
flag::parse(argc, argv, fullCommand);
|
||||
|
||||
if (help) {
|
||||
flag::usageAndDie(fullCommand);
|
||||
}
|
||||
|
||||
// Copy all the remaining arguments.
|
||||
for (const std::string& arg : flag::getArgs()) {
|
||||
options.input.push_back(Source{ arg });
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
static bool compileValues(const std::shared_ptr<ResourceTable>& table, const Source& source,
|
||||
const ConfigDescription& config) {
|
||||
std::ifstream in(source.path, std::ifstream::binary);
|
||||
@@ -630,6 +556,7 @@ struct ResourcePathData {
|
||||
* [--/res/]type[-config]/name
|
||||
*/
|
||||
static Maybe<ResourcePathData> extractResourcePathData(const Source& source) {
|
||||
// TODO(adamlesinski): Use Windows path separator on windows.
|
||||
std::vector<std::string> parts = util::splitAndLowercase(source.path, '/');
|
||||
if (parts.size() < 2) {
|
||||
Logger::error(source) << "bad resource path." << std::endl;
|
||||
@@ -695,6 +622,38 @@ bool writeResourceTable(const AaptOptions& options, const std::shared_ptr<Resour
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For each FileReference in the table, adds a LinkItem to the link queue for processing.
|
||||
*/
|
||||
static void addApkFilesToLinkQueue(const std::u16string& package, const Source& source,
|
||||
const std::shared_ptr<ResourceTable>& table,
|
||||
const std::unique_ptr<ZipFile>& apk,
|
||||
std::queue<LinkItem>* outLinkQueue) {
|
||||
bool mangle = package != table->getPackage();
|
||||
for (auto& type : *table) {
|
||||
for (auto& entry : type->entries) {
|
||||
ResourceName name = { package, type->type, entry->name };
|
||||
if (mangle) {
|
||||
NameMangler::mangle(table->getPackage(), &name.entry);
|
||||
}
|
||||
|
||||
for (auto& value : entry->values) {
|
||||
visitFunc<FileReference>(*value.value, [&](FileReference& ref) {
|
||||
std::string pathUtf8 = util::utf16ToUtf8(*ref.path);
|
||||
outLinkQueue->push(LinkItem{
|
||||
source, name, value.config, pathUtf8, apk.get() });
|
||||
// Now rewrite the file path.
|
||||
if (mangle) {
|
||||
ref.path = table->getValueStringPool().makeRef(util::utf8ToUtf16(
|
||||
buildFileReference(name, value.config,
|
||||
getExtension<char>(pathUtf8))));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr int kOpenFlags = ZipFile::kOpenCreate | ZipFile::kOpenTruncate |
|
||||
ZipFile::kOpenReadWrite;
|
||||
|
||||
@@ -740,9 +699,14 @@ bool link(const AaptOptions& options, const std::shared_ptr<ResourceTable>& outT
|
||||
linkedPackages.insert(table->getPackage());
|
||||
}
|
||||
|
||||
std::queue<LinkItem> linkQueue;
|
||||
for (auto& p : apkFiles) {
|
||||
const std::shared_ptr<ResourceTable>& inTable = p.first;
|
||||
|
||||
// Collect all FileReferences and add them to the queue for processing.
|
||||
addApkFilesToLinkQueue(options.appInfo.package, Source{}, inTable, p.second, &linkQueue);
|
||||
|
||||
// Merge the tables.
|
||||
if (!outTable->merge(std::move(*inTable))) {
|
||||
return false;
|
||||
}
|
||||
@@ -779,39 +743,32 @@ bool link(const AaptOptions& options, const std::shared_ptr<ResourceTable>& outT
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& p : apkFiles) {
|
||||
std::unique_ptr<ZipFile>& zipFile = p.second;
|
||||
for (; !linkQueue.empty(); linkQueue.pop()) {
|
||||
const LinkItem& item = linkQueue.front();
|
||||
|
||||
// TODO(adamlesinski): Get list of files to read when processing config filter.
|
||||
ZipEntry* entry = item.apk->getEntryByName(item.originalPath.data());
|
||||
if (!entry) {
|
||||
Logger::error(item.source) << "failed to find '" << item.originalPath << "'."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int numEntries = zipFile->getNumEntries();
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
ZipEntry* entry = zipFile->getEntryByIndex(i);
|
||||
assert(entry);
|
||||
if (util::stringEndsWith<char>(item.originalPath, ".xml")) {
|
||||
void* uncompressedData = item.apk->uncompress(entry);
|
||||
assert(uncompressedData);
|
||||
|
||||
StringPiece filename = entry->getFileName();
|
||||
if (!util::stringStartsWith<char>(filename, "res/")) {
|
||||
continue;
|
||||
if (!linkXml(options, resolver, item, uncompressedData, entry->getUncompressedLen(),
|
||||
&outApk)) {
|
||||
Logger::error(options.output) << "failed to link '" << item.originalPath << "'."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (util::stringEndsWith<char>(filename, ".xml")) {
|
||||
void* uncompressedData = zipFile->uncompress(entry);
|
||||
assert(uncompressedData);
|
||||
|
||||
LinkItem item = { Source{ filename.toString() }, filename.toString() };
|
||||
|
||||
if (!linkXml(options, resolver, item, uncompressedData,
|
||||
entry->getUncompressedLen(), &outApk)) {
|
||||
Logger::error(options.output) << "failed to link '" << filename << "'."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (outApk.add(zipFile.get(), entry, 0, nullptr) != android::NO_ERROR) {
|
||||
Logger::error(options.output) << "failed to copy '" << filename << "'."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (outApk.add(item.apk, entry, buildFileReference(item).data(), 0, nullptr) !=
|
||||
android::NO_ERROR) {
|
||||
Logger::error(options.output) << "failed to copy '" << item.originalPath << "'."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -957,6 +914,109 @@ bool compile(const AaptOptions& options, const std::shared_ptr<ResourceTable>& t
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadAppInfo(const Source& source, AppInfo* outInfo) {
|
||||
std::ifstream ifs(source.path, std::ifstream::in | std::ifstream::binary);
|
||||
if (!ifs) {
|
||||
Logger::error(source) << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ManifestParser parser;
|
||||
std::shared_ptr<XmlPullParser> pullParser = std::make_shared<SourceXmlPullParser>(ifs);
|
||||
return parser.parse(source, pullParser, outInfo);
|
||||
}
|
||||
|
||||
static void printCommandsAndDie() {
|
||||
std::cerr << "The following commands are supported:" << std::endl << std::endl;
|
||||
std::cerr << "compile compiles a subset of resources" << std::endl;
|
||||
std::cerr << "link links together compiled resources and libraries" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "run aapt2 with one of the commands and the -h flag for extra details."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static AaptOptions prepareArgs(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "no command specified." << std::endl << std::endl;
|
||||
printCommandsAndDie();
|
||||
}
|
||||
|
||||
const StringPiece command(argv[1]);
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
AaptOptions options;
|
||||
|
||||
if (command == "--version" || command == "version") {
|
||||
std::cout << kAaptVersionStr << std::endl;
|
||||
exit(0);
|
||||
} else if (command == "link") {
|
||||
options.phase = AaptOptions::Phase::Link;
|
||||
} else if (command == "compile") {
|
||||
options.phase = AaptOptions::Phase::Compile;
|
||||
} else {
|
||||
std::cerr << "invalid command '" << command << "'." << std::endl << std::endl;
|
||||
printCommandsAndDie();
|
||||
}
|
||||
|
||||
if (options.phase == AaptOptions::Phase::Compile) {
|
||||
flag::requiredFlag("--package", "Android package name",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.appInfo.package = util::utf8ToUtf16(arg);
|
||||
});
|
||||
flag::optionalFlag("--binding", "Output directory for binding XML files",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.bindingOutput = Source{ arg.toString() };
|
||||
});
|
||||
flag::optionalSwitch("--no-version", "Disables automatic style and layout versioning",
|
||||
false, &options.versionStylesAndLayouts);
|
||||
|
||||
} else if (options.phase == AaptOptions::Phase::Link) {
|
||||
flag::requiredFlag("--manifest", "AndroidManifest.xml of your app",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.manifest = Source{ arg.toString() };
|
||||
});
|
||||
|
||||
flag::optionalFlag("-I", "add an Android APK to link against",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.libraries.push_back(Source{ arg.toString() });
|
||||
});
|
||||
|
||||
flag::optionalFlag("--java", "directory in which to generate R.java",
|
||||
[&options](const StringPiece& arg) {
|
||||
options.generateJavaClass = Source{ arg.toString() };
|
||||
});
|
||||
}
|
||||
|
||||
// Common flags for all steps.
|
||||
flag::requiredFlag("-o", "Output path", [&options](const StringPiece& arg) {
|
||||
options.output = Source{ arg.toString() };
|
||||
});
|
||||
|
||||
bool help = false;
|
||||
flag::optionalSwitch("-v", "enables verbose logging", true, &options.verbose);
|
||||
flag::optionalSwitch("-h", "displays this help menu", true, &help);
|
||||
|
||||
// Build the command string for output (eg. "aapt2 compile").
|
||||
std::string fullCommand = "aapt2";
|
||||
fullCommand += " ";
|
||||
fullCommand += command.toString();
|
||||
|
||||
// Actually read the command line flags.
|
||||
flag::parse(argc, argv, fullCommand);
|
||||
|
||||
if (help) {
|
||||
flag::usageAndDie(fullCommand);
|
||||
}
|
||||
|
||||
// Copy all the remaining arguments.
|
||||
for (const std::string& arg : flag::getArgs()) {
|
||||
options.input.push_back(Source{ arg });
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Logger::setLog(std::make_shared<Log>(std::cerr, std::cerr));
|
||||
AaptOptions options = prepareArgs(argc, argv);
|
||||
|
||||
@@ -43,8 +43,7 @@ struct FlatEntry {
|
||||
*/
|
||||
class MapFlattener : public ConstValueVisitor {
|
||||
public:
|
||||
MapFlattener(BigBuffer* out, const FlatEntry& flatEntry,
|
||||
std::vector<std::pair<ResourceNameRef, uint32_t>>& symbols) :
|
||||
MapFlattener(BigBuffer* out, const FlatEntry& flatEntry, SymbolEntryVector* symbols) :
|
||||
mOut(out), mSymbols(symbols) {
|
||||
mMap = mOut->nextBlock<android::ResTable_map_entry>();
|
||||
mMap->key.index = flatEntry.entryKey;
|
||||
@@ -65,7 +64,7 @@ public:
|
||||
|
||||
void flattenParent(const Reference& ref) {
|
||||
if (!ref.id.isValid()) {
|
||||
mSymbols.push_back({
|
||||
mSymbols->push_back({
|
||||
ResourceNameRef(ref.name),
|
||||
(mOut->size() - mMap->size) + sizeof(*mMap) - sizeof(android::ResTable_entry)
|
||||
});
|
||||
@@ -80,7 +79,7 @@ public:
|
||||
|
||||
// Write the key.
|
||||
if (!Res_INTERNALID(key.id.id) && !key.id.isValid()) {
|
||||
mSymbols.push_back(std::make_pair(ResourceNameRef(key.name),
|
||||
mSymbols->push_back(std::make_pair(ResourceNameRef(key.name),
|
||||
mOut->size() - sizeof(*outMapEntry)));
|
||||
}
|
||||
outMapEntry->name.ident = key.id.id;
|
||||
@@ -90,7 +89,7 @@ public:
|
||||
|
||||
if (outMapEntry->value.data == 0x0) {
|
||||
visitFunc<Reference>(value, [&](const Reference& reference) {
|
||||
mSymbols.push_back(std::make_pair(ResourceNameRef(reference.name),
|
||||
mSymbols->push_back(std::make_pair(ResourceNameRef(reference.name),
|
||||
mOut->size() - sizeof(outMapEntry->value.data)));
|
||||
});
|
||||
}
|
||||
@@ -188,16 +187,47 @@ public:
|
||||
|
||||
private:
|
||||
BigBuffer* mOut;
|
||||
std::vector<std::pair<ResourceNameRef, uint32_t>>& mSymbols;
|
||||
SymbolEntryVector* mSymbols;
|
||||
android::ResTable_map_entry* mMap;
|
||||
};
|
||||
|
||||
/**
|
||||
* Flattens a value, with special handling for References.
|
||||
*/
|
||||
struct ValueFlattener : ConstValueVisitor {
|
||||
ValueFlattener(BigBuffer* out, SymbolEntryVector* symbols) :
|
||||
result(false), mOut(out), mOutValue(nullptr), mSymbols(symbols) {
|
||||
mOutValue = mOut->nextBlock<android::Res_value>();
|
||||
}
|
||||
|
||||
virtual void visit(const Reference& ref, ValueVisitorArgs& a) override {
|
||||
visitItem(ref, a);
|
||||
if (mOutValue->data == 0x0) {
|
||||
mSymbols->push_back({
|
||||
ResourceNameRef(ref.name),
|
||||
mOut->size() - sizeof(mOutValue->data)});
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visitItem(const Item& item, ValueVisitorArgs&) override {
|
||||
result = item.flatten(*mOutValue);
|
||||
mOutValue->size = sizeof(*mOutValue);
|
||||
}
|
||||
|
||||
bool result;
|
||||
|
||||
private:
|
||||
BigBuffer* mOut;
|
||||
android::Res_value* mOutValue;
|
||||
SymbolEntryVector* mSymbols;
|
||||
};
|
||||
|
||||
TableFlattener::TableFlattener(Options options)
|
||||
: mOptions(options) {
|
||||
}
|
||||
|
||||
bool TableFlattener::flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
|
||||
std::vector<std::pair<ResourceNameRef, uint32_t>>& symbolEntries) {
|
||||
SymbolEntryVector* symbols) {
|
||||
if (flatEntry.value.isItem()) {
|
||||
android::ResTable_entry* entry = out->nextBlock<android::ResTable_entry>();
|
||||
|
||||
@@ -218,30 +248,16 @@ bool TableFlattener::flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
|
||||
ResTable_entry_source* sourceBlock = out->nextBlock<ResTable_entry_source>();
|
||||
sourceBlock->pathIndex = flatEntry.sourcePathKey;
|
||||
sourceBlock->line = flatEntry.sourceLine;
|
||||
|
||||
entry->size += sizeof(*sourceBlock);
|
||||
}
|
||||
|
||||
android::Res_value* outValue = out->nextBlock<android::Res_value>();
|
||||
|
||||
const Item& item = static_cast<const Item&>(flatEntry.value);
|
||||
if (!item.flatten(*outValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outValue->data == 0x0) {
|
||||
visitFunc<Reference>(item, [&](const Reference& reference) {
|
||||
symbolEntries.push_back({
|
||||
ResourceNameRef(reference.name),
|
||||
out->size() - sizeof(outValue->data)
|
||||
});
|
||||
});
|
||||
}
|
||||
outValue->size = sizeof(*outValue);
|
||||
return true;
|
||||
const Item* item = static_cast<const Item*>(&flatEntry.value);
|
||||
ValueFlattener flattener(out, symbols);
|
||||
item->accept(flattener, {});
|
||||
return flattener.result;
|
||||
}
|
||||
|
||||
MapFlattener flattener(out, flatEntry, symbolEntries);
|
||||
MapFlattener flattener(out, flatEntry, symbols);
|
||||
flatEntry.value.accept(flattener, {});
|
||||
return true;
|
||||
}
|
||||
@@ -263,7 +279,7 @@ bool TableFlattener::flatten(BigBuffer* out, const ResourceTable& table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::pair<ResourceNameRef, uint32_t>> symbolEntries;
|
||||
SymbolEntryVector symbolEntries;
|
||||
|
||||
StringPool typePool;
|
||||
StringPool keyPool;
|
||||
@@ -401,7 +417,7 @@ bool TableFlattener::flatten(BigBuffer* out, const ResourceTable& table) {
|
||||
for (const FlatEntry& flatEntry : entry.second) {
|
||||
assert(flatEntry.entry.entryId < type->entries.size());
|
||||
indices[flatEntry.entry.entryId] = typeBlock.size() - entryStart;
|
||||
if (!flattenValue(&typeBlock, flatEntry, symbolEntries)) {
|
||||
if (!flattenValue(&typeBlock, flatEntry, &symbolEntries)) {
|
||||
Logger::error()
|
||||
<< "failed to flatten resource '"
|
||||
<< ResourceNameRef {
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
namespace aapt {
|
||||
|
||||
using SymbolEntryVector = std::vector<std::pair<ResourceNameRef, uint32_t>>;
|
||||
|
||||
struct FlatEntry;
|
||||
|
||||
/**
|
||||
@@ -49,8 +51,7 @@ struct TableFlattener {
|
||||
bool flatten(BigBuffer* out, const ResourceTable& table);
|
||||
|
||||
private:
|
||||
bool flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
|
||||
std::vector<std::pair<ResourceNameRef, uint32_t>>& symbolEntries);
|
||||
bool flattenValue(BigBuffer* out, const FlatEntry& flatEntry, SymbolEntryVector* symbols);
|
||||
|
||||
Options mOptions;
|
||||
};
|
||||
|
||||
@@ -144,9 +144,15 @@ void ZipEntry::initNew(const char* fileName, const char* comment)
|
||||
* Initializes the CDE and the LFH.
|
||||
*/
|
||||
status_t ZipEntry::initFromExternal(const ZipFile* /* pZipFile */,
|
||||
const ZipEntry* pEntry)
|
||||
const ZipEntry* pEntry, const char* storageName)
|
||||
{
|
||||
mCDE = pEntry->mCDE;
|
||||
if (storageName && *storageName != 0) {
|
||||
mCDE.mFileNameLength = strlen(storageName);
|
||||
mCDE.mFileName = new unsigned char[mCDE.mFileNameLength + 1];
|
||||
strcpy((char*) mCDE.mFileName, storageName);
|
||||
}
|
||||
|
||||
// Check whether we got all the memory needed.
|
||||
if ((mCDE.mFileNameLength > 0 && mCDE.mFileName == NULL) ||
|
||||
(mCDE.mFileCommentLength > 0 && mCDE.mFileComment == NULL) ||
|
||||
|
||||
@@ -171,9 +171,10 @@ protected:
|
||||
|
||||
/*
|
||||
* Initialize the structure with the contents of a ZipEntry from
|
||||
* another file.
|
||||
* another file. If fileName is non-NULL, override the name with fileName.
|
||||
*/
|
||||
status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
|
||||
status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry,
|
||||
const char* fileName);
|
||||
|
||||
/*
|
||||
* Add some pad bytes to the LFH. We do this by adding or resizing
|
||||
|
||||
@@ -546,7 +546,7 @@ bail:
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
|
||||
int padding, ZipEntry** ppEntry)
|
||||
const char* storageName, int padding, ZipEntry** ppEntry)
|
||||
{
|
||||
ZipEntry* pEntry = NULL;
|
||||
status_t result;
|
||||
@@ -570,9 +570,10 @@ status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
|
||||
if (result != NO_ERROR)
|
||||
result = pEntry->initFromExternal(pSourceZip, pSourceEntry, storageName);
|
||||
if (result != NO_ERROR) {
|
||||
goto bail;
|
||||
}
|
||||
if (padding != 0) {
|
||||
result = pEntry->addPadding(padding);
|
||||
if (result != NO_ERROR)
|
||||
|
||||
@@ -123,14 +123,16 @@ public:
|
||||
int compressionMethod, ZipEntry** ppEntry);
|
||||
|
||||
/*
|
||||
* Add an entry by copying it from another zip file. If "padding" is
|
||||
* Add an entry by copying it from another zip file. If storageName is
|
||||
* non-NULL, the entry will be inserted with the name storageName, otherwise
|
||||
* it will have the same name as the source entry. If "padding" is
|
||||
* nonzero, the specified number of bytes will be added to the "extra"
|
||||
* field in the header.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
|
||||
int padding, ZipEntry** ppEntry);
|
||||
const char* storageName, int padding, ZipEntry** ppEntry);
|
||||
|
||||
/*
|
||||
* Mark an entry as having been removed. It is not actually deleted
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
# Environment dependent variables
|
||||
##
|
||||
|
||||
SHELL := /bin/bash
|
||||
AAPT := aapt2
|
||||
ZIP := zip -n .arsc:.png:AndroidManifest.xml
|
||||
ZIPALIGN := zipalign 4
|
||||
ZIPALIGN := zipalign -f 4
|
||||
FRAMEWORK := ../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
|
||||
|
||||
##
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
##
|
||||
|
||||
AAPT := aapt2
|
||||
ZIPALIGN := zipalign 4
|
||||
ZIPALIGN := zipalign -f 4
|
||||
FRAMEWORK := ../../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
|
||||
|
||||
##
|
||||
|
||||
4
tools/aapt2/data/lib/res/layout/main.xml
Normal file
4
tools/aapt2/data/lib/res/layout/main.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
1
tools/aapt2/data/lib/res/raw/hello.txt
Normal file
1
tools/aapt2/data/lib/res/raw/hello.txt
Normal file
@@ -0,0 +1 @@
|
||||
Oh howdy there
|
||||
Reference in New Issue
Block a user