AAPT2: Improve diff command
Change-Id: Ia1e2f8482c7192ef50126b61bed7975297332767
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index c10b134..4a86579 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -21,6 +21,7 @@
#include "io/File.h"
#include "util/Util.h"
+#include <algorithm>
#include <androidfw/ResourceTypes.h>
#include <limits>
@@ -302,18 +303,42 @@
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 @@
(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 @@
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 @@
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 @@
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 @@
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);
diff --git a/tools/aapt2/diff/Diff.cpp b/tools/aapt2/diff/Diff.cpp
index 67333a2..1ff6ef6 100644
--- a/tools/aapt2/diff/Diff.cpp
+++ b/tools/aapt2/diff/Diff.cpp
@@ -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 @@
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 @@
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;
diff --git a/tools/aapt2/dump/Dump.cpp b/tools/aapt2/dump/Dump.cpp
index dba2d28..8f0dd3a 100644
--- a/tools/aapt2/dump/Dump.cpp
+++ b/tools/aapt2/dump/Dump.cpp
@@ -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 @@
<< "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 @@
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;
}
}
- 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;
+ }
+ }
+ }
}
- 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);
}
}
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 5cd1c8b..d2eccbc 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -61,7 +61,6 @@
auto cacheIter = mMapping->find(id);
if (cacheIter != mMapping->end()) {
reference->name = cacheIter->second;
- reference->id = {};
}
}
};
diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h
index 595db96..a31bc89 100644
--- a/tools/aapt2/util/Maybe.h
+++ b/tools/aapt2/util/Maybe.h
@@ -88,6 +88,8 @@
*/
const T& value() const;
+ T valueOrDefault(const T& def) const;
+
private:
template <typename U>
friend class Maybe;
@@ -263,6 +265,14 @@
}
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 @@
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