Merge "AAPT2: Improve diff command"
This commit is contained in:
committed by
Android (Google) Code Review
commit
2726f482f1
@@ -21,6 +21,7 @@
|
||||
#include "io/File.h"
|
||||
#include "util/Util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include <limits>
|
||||
|
||||
@@ -302,18 +303,42 @@ Attribute::Attribute(bool w, uint32_t t) :
|
||||
mWeak = w;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* addPointer(T& val) {
|
||||
return &val;
|
||||
}
|
||||
|
||||
bool Attribute::equals(const Value* value) const {
|
||||
const Attribute* other = valueCast<Attribute>(value);
|
||||
if (!other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->typeMask == other->typeMask && this->minInt == other->minInt &&
|
||||
this->maxInt == other->maxInt &&
|
||||
std::equal(this->symbols.begin(), this->symbols.end(),
|
||||
other->symbols.begin(),
|
||||
[](const Symbol& a, const Symbol& b) -> bool {
|
||||
return a.symbol.equals(&b.symbol) && a.value == b.value;
|
||||
if (symbols.size() != other->symbols.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeMask != other->typeMask || minInt != other->minInt || maxInt != other->maxInt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const Symbol*> sortedA;
|
||||
std::transform(symbols.begin(), symbols.end(),
|
||||
std::back_inserter(sortedA), addPointer<const Symbol>);
|
||||
std::sort(sortedA.begin(), sortedA.end(), [](const Symbol* a, const Symbol* b) -> bool {
|
||||
return a->symbol.name < b->symbol.name;
|
||||
});
|
||||
|
||||
std::vector<const Symbol*> sortedB;
|
||||
std::transform(other->symbols.begin(), other->symbols.end(),
|
||||
std::back_inserter(sortedB), addPointer<const Symbol>);
|
||||
std::sort(sortedB.begin(), sortedB.end(), [](const Symbol* a, const Symbol* b) -> bool {
|
||||
return a->symbol.name < b->symbol.name;
|
||||
});
|
||||
|
||||
return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
|
||||
[](const Symbol* a, const Symbol* b) -> bool {
|
||||
return a->symbol.equals(&b->symbol) && a->value == b->value;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -526,9 +551,28 @@ bool Style::equals(const Value* value) const {
|
||||
(parent && other->parent && !parent.value().equals(&other->parent.value()))) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(entries.begin(), entries.end(), other->entries.begin(),
|
||||
[](const Entry& a, const Entry& b) -> bool {
|
||||
return a.key.equals(&b.key) && a.value->equals(b.value.get());
|
||||
|
||||
if (entries.size() != other->entries.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const Entry*> sortedA;
|
||||
std::transform(entries.begin(), entries.end(),
|
||||
std::back_inserter(sortedA), addPointer<const Entry>);
|
||||
std::sort(sortedA.begin(), sortedA.end(), [](const Entry* a, const Entry* b) -> bool {
|
||||
return a->key.name < b->key.name;
|
||||
});
|
||||
|
||||
std::vector<const Entry*> sortedB;
|
||||
std::transform(other->entries.begin(), other->entries.end(),
|
||||
std::back_inserter(sortedB), addPointer<const Entry>);
|
||||
std::sort(sortedB.begin(), sortedB.end(), [](const Entry* a, const Entry* b) -> bool {
|
||||
return a->key.name < b->key.name;
|
||||
});
|
||||
|
||||
return std::equal(sortedA.begin(), sortedA.end(), sortedB.begin(),
|
||||
[](const Entry* a, const Entry* b) -> bool {
|
||||
return a->key.equals(&b->key) && a->value->equals(b->value.get());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -563,6 +607,8 @@ void Style::print(std::ostream* out) const {
|
||||
static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
|
||||
if (value.key.name) {
|
||||
out << value.key.name.value();
|
||||
} else if (value.key.id) {
|
||||
out << value.key.id.value();
|
||||
} else {
|
||||
out << "???";
|
||||
}
|
||||
@@ -577,6 +623,10 @@ bool Array::equals(const Value* value) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (items.size() != other->items.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::equal(items.begin(), items.end(), other->items.begin(),
|
||||
[](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
|
||||
return a->equals(b.get());
|
||||
@@ -605,6 +655,10 @@ bool Plural::equals(const Value* value) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (values.size() != other->values.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::equal(values.begin(), values.end(), other->values.begin(),
|
||||
[](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
|
||||
if (bool(a) != bool(b)) {
|
||||
@@ -659,6 +713,11 @@ bool Styleable::equals(const Value* value) const {
|
||||
if (!other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entries.size() != other->entries.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::equal(entries.begin(), entries.end(), other->entries.begin(),
|
||||
[](const Reference& a, const Reference& b) -> bool {
|
||||
return a.equals(&b);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "Flags.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "ValueVisitor.h"
|
||||
#include "io/ZipArchive.h"
|
||||
#include "process/IResourceTableConsumer.h"
|
||||
#include "process/SymbolTable.h"
|
||||
@@ -385,6 +386,24 @@ static bool emitResourceTableDiff(IAaptContext* context, LoadedApk* apkA, Loaded
|
||||
return diff;
|
||||
}
|
||||
|
||||
class ZeroingReferenceVisitor : public ValueVisitor {
|
||||
public:
|
||||
using ValueVisitor::visit;
|
||||
|
||||
void visit(Reference* ref) override {
|
||||
if (ref->name && ref->id) {
|
||||
if (ref->id.value().packageId() == 0x7f) {
|
||||
ref->id = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void zeroOutAppReferences(ResourceTable* table) {
|
||||
ZeroingReferenceVisitor visitor;
|
||||
visitAllValuesInTable(table, &visitor);
|
||||
}
|
||||
|
||||
int diff(const std::vector<StringPiece>& args) {
|
||||
DiffContext context;
|
||||
|
||||
@@ -405,6 +424,10 @@ int diff(const std::vector<StringPiece>& args) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Zero out Application IDs in references.
|
||||
zeroOutAppReferences(apkA->getResourceTable());
|
||||
zeroOutAppReferences(apkB->getResourceTable());
|
||||
|
||||
if (emitResourceTableDiff(&context, apkA.get(), apkB.get())) {
|
||||
// We emitted a diff, so return 1 (failure).
|
||||
return 1;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "io/ZipArchive.h"
|
||||
#include "process/IResourceTableConsumer.h"
|
||||
#include "proto/ProtoSerialize.h"
|
||||
#include "unflatten/BinaryResourceParser.h"
|
||||
#include "util/Files.h"
|
||||
#include "util/StringPiece.h"
|
||||
|
||||
@@ -44,18 +45,9 @@ void dumpCompiledFile(const pb::CompiledFile& pbFile, const void* data, size_t l
|
||||
<< "Source: " << file->source << "\n";
|
||||
}
|
||||
|
||||
void dumpCompiledTable(const pb::ResourceTable& pbTable, const Source& source,
|
||||
IAaptContext* context) {
|
||||
std::unique_ptr<ResourceTable> table = deserializeTableFromPb(pbTable, source,
|
||||
context->getDiagnostics());
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::printTable(table.get());
|
||||
}
|
||||
|
||||
void tryDumpFile(IAaptContext* context, const std::string& filePath) {
|
||||
std::unique_ptr<ResourceTable> table;
|
||||
|
||||
std::string err;
|
||||
std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err);
|
||||
if (zip) {
|
||||
@@ -75,37 +67,62 @@ void tryDumpFile(IAaptContext* context, const std::string& filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<ResourceTable> table = deserializeTableFromPb(
|
||||
table = deserializeTableFromPb(
|
||||
pbTable, Source(filePath), context->getDiagnostics());
|
||||
if (table) {
|
||||
DebugPrintTableOptions debugPrintTableOptions;
|
||||
debugPrintTableOptions.showSources = true;
|
||||
Debug::printTable(table.get(), debugPrintTableOptions);
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!table) {
|
||||
file = zip->findFile("resources.arsc");
|
||||
if (file) {
|
||||
std::unique_ptr<io::IData> data = file->openAsData();
|
||||
if (!data) {
|
||||
context->getDiagnostics()->error(DiagMessage(filePath)
|
||||
<< "failed to open resources.arsc");
|
||||
return;
|
||||
}
|
||||
|
||||
table = util::make_unique<ResourceTable>();
|
||||
BinaryResourceParser parser(context, table.get(), Source(filePath),
|
||||
data->data(), data->size());
|
||||
if (!parser.parse()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<android::FileMap> file = file::mmapPath(filePath, &err);
|
||||
if (!file) {
|
||||
context->getDiagnostics()->error(DiagMessage(filePath) << err);
|
||||
return;
|
||||
if (!table) {
|
||||
Maybe<android::FileMap> file = file::mmapPath(filePath, &err);
|
||||
if (!file) {
|
||||
context->getDiagnostics()->error(DiagMessage(filePath) << err);
|
||||
return;
|
||||
}
|
||||
|
||||
android::FileMap* fileMap = &file.value();
|
||||
|
||||
// Try as a compiled table.
|
||||
pb::ResourceTable pbTable;
|
||||
if (pbTable.ParseFromArray(fileMap->getDataPtr(), fileMap->getDataLength())) {
|
||||
table = deserializeTableFromPb(pbTable, Source(filePath), context->getDiagnostics());
|
||||
}
|
||||
|
||||
if (!table) {
|
||||
// Try as a compiled file.
|
||||
CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength());
|
||||
if (const pb::CompiledFile* pbFile = input.CompiledFile()) {
|
||||
dumpCompiledFile(*pbFile, input.data(), input.size(), Source(filePath), context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android::FileMap* fileMap = &file.value();
|
||||
|
||||
// Try as a compiled table.
|
||||
pb::ResourceTable pbTable;
|
||||
if (pbTable.ParseFromArray(fileMap->getDataPtr(), fileMap->getDataLength())) {
|
||||
dumpCompiledTable(pbTable, Source(filePath), context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try as a compiled file.
|
||||
CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength());
|
||||
if (const pb::CompiledFile* pbFile = input.CompiledFile()) {
|
||||
dumpCompiledFile(*pbFile, input.data(), input.size(), Source(filePath), context);
|
||||
return;
|
||||
if (table) {
|
||||
DebugPrintTableOptions debugPrintTableOptions;
|
||||
debugPrintTableOptions.showSources = true;
|
||||
Debug::printTable(table.get(), debugPrintTableOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ public:
|
||||
auto cacheIter = mMapping->find(id);
|
||||
if (cacheIter != mMapping->end()) {
|
||||
reference->name = cacheIter->second;
|
||||
reference->id = {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,6 +88,8 @@ public:
|
||||
*/
|
||||
const T& value() const;
|
||||
|
||||
T valueOrDefault(const T& def) const;
|
||||
|
||||
private:
|
||||
template <typename U>
|
||||
friend class Maybe;
|
||||
@@ -262,6 +264,14 @@ const T& Maybe<T>::value() const {
|
||||
return reinterpret_cast<const T&>(mStorage);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Maybe<T>::valueOrDefault(const T& def) const {
|
||||
if (mNothing) {
|
||||
return def;
|
||||
}
|
||||
return reinterpret_cast<const T&>(mStorage);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Maybe<T>::destroy() {
|
||||
reinterpret_cast<T&>(mStorage).~T();
|
||||
@@ -306,6 +316,19 @@ typename std::enable_if<
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
typename std::enable_if<
|
||||
has_lt_op<T, U>::value,
|
||||
bool
|
||||
>::type operator<(const Maybe<T>& a, const Maybe<U>& b) {
|
||||
if (a && b) {
|
||||
return a.value() < b.value();
|
||||
} else if (!a && !b) {
|
||||
return false;
|
||||
}
|
||||
return !a;
|
||||
}
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
#endif // AAPT_MAYBE_H
|
||||
|
||||
Reference in New Issue
Block a user