AAPT2: Better debugging output
Test: make aapt2_tests
Change-Id: I7778b773201381538dc1f2e376abee4eb33e44c0
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 082fd86..b38d259 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -17,9 +17,12 @@
#include "ResourceValues.h"
#include <algorithm>
+#include <cinttypes>
#include <limits>
#include <set>
+#include <sstream>
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "Resource.h"
@@ -27,8 +30,18 @@
#include "ValueVisitor.h"
#include "util/Util.h"
+using ::aapt::text::Printer;
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
+
namespace aapt {
+void Value::PrettyPrint(Printer* printer) const {
+ std::ostringstream str_stream;
+ Print(&str_stream);
+ printer->Print(str_stream.str());
+}
+
std::ostream& operator<<(std::ostream& out, const Value& value) {
value.Print(&out);
return out;
@@ -155,6 +168,49 @@
}
}
+static void PrettyPrintReferenceImpl(const Reference& ref, bool print_package, Printer* printer) {
+ switch (ref.reference_type) {
+ case Reference::Type::kResource:
+ printer->Print("@");
+ break;
+
+ case Reference::Type::kAttribute:
+ printer->Print("?");
+ break;
+ }
+
+ if (!ref.name && !ref.id) {
+ printer->Print("null");
+ return;
+ }
+
+ if (ref.private_reference) {
+ printer->Print("*");
+ }
+
+ if (ref.name) {
+ const ResourceName& name = ref.name.value();
+ if (print_package) {
+ printer->Print(name.to_string());
+ } else {
+ printer->Print(to_string(name.type));
+ printer->Print("/");
+ printer->Print(name.entry);
+ }
+ } else if (ref.id && ref.id.value().is_valid_dynamic()) {
+ printer->Print(ref.id.value().to_string());
+ }
+}
+
+void Reference::PrettyPrint(Printer* printer) const {
+ PrettyPrintReferenceImpl(*this, true /*print_package*/, printer);
+}
+
+void Reference::PrettyPrint(const StringPiece& package, Printer* printer) const {
+ const bool print_package = name ? package != name.value().package : true;
+ PrettyPrintReferenceImpl(*this, print_package, printer);
+}
+
bool Id::Equals(const Value* value) const {
return ValueCast<Id>(value) != nullptr;
}
@@ -165,11 +221,16 @@
return true;
}
-Id* Id::Clone(StringPool* /*new_pool*/) const { return new Id(*this); }
+Id* Id::Clone(StringPool* /*new_pool*/) const {
+ return new Id(*this);
+}
-void Id::Print(std::ostream* out) const { *out << "(id)"; }
+void Id::Print(std::ostream* out) const {
+ *out << "(id)";
+}
-String::String(const StringPool::Ref& ref) : value(ref) {}
+String::String(const StringPool::Ref& ref) : value(ref) {
+}
bool String::Equals(const Value* value) const {
const String* other = ValueCast<String>(value);
@@ -218,7 +279,14 @@
*out << "(string) \"" << *value << "\"";
}
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {}
+void String::PrettyPrint(Printer* printer) const {
+ printer->Print("\"");
+ printer->Print(*value);
+ printer->Print("\"");
+}
+
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+}
bool StyledString::Equals(const Value* value) const {
const StyledString* other = ValueCast<StyledString>(value);
@@ -269,7 +337,8 @@
}
}
-FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {}
+FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
+}
bool FileReference::Equals(const Value* value) const {
const FileReference* other = ValueCast<FileReference>(value);
@@ -302,7 +371,8 @@
*out << "(file) " << *path;
}
-BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {}
+BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
+}
BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
value.dataType = dataType;
@@ -318,7 +388,7 @@
this->value.data == other->value.data;
}
-bool BinaryPrimitive::Flatten(android::Res_value* out_value) const {
+bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const {
out_value->dataType = value.dataType;
out_value->data = util::HostToDevice32(value.data);
return true;
@@ -329,32 +399,110 @@
}
void BinaryPrimitive::Print(std::ostream* out) const {
+ *out << StringPrintf("(primitive) type=0x%02x data=0x%08x", value.dataType, value.data);
+}
+
+static std::string ComplexToString(uint32_t complex_value, bool fraction) {
+ using ::android::Res_value;
+
+ constexpr std::array<int, 4> kRadixShifts = {{23, 16, 8, 0}};
+
+ // Determine the radix that was used.
+ const uint32_t radix =
+ (complex_value >> Res_value::COMPLEX_RADIX_SHIFT) & Res_value::COMPLEX_RADIX_MASK;
+ const uint64_t mantissa = uint64_t{(complex_value >> Res_value::COMPLEX_MANTISSA_SHIFT) &
+ Res_value::COMPLEX_MANTISSA_MASK}
+ << kRadixShifts[radix];
+ const float value = mantissa * (1.0f / (1 << 23));
+
+ std::string str = StringPrintf("%f", value);
+
+ const int unit_type =
+ (complex_value >> Res_value::COMPLEX_UNIT_SHIFT) & Res_value::COMPLEX_UNIT_MASK;
+ if (fraction) {
+ switch (unit_type) {
+ case Res_value::COMPLEX_UNIT_FRACTION:
+ str += "%";
+ break;
+ case Res_value::COMPLEX_UNIT_FRACTION_PARENT:
+ str += "%p";
+ break;
+ default:
+ str += "???";
+ break;
+ }
+ } else {
+ switch (unit_type) {
+ case Res_value::COMPLEX_UNIT_PX:
+ str += "px";
+ break;
+ case Res_value::COMPLEX_UNIT_DIP:
+ str += "dp";
+ break;
+ case Res_value::COMPLEX_UNIT_SP:
+ str += "sp";
+ break;
+ case Res_value::COMPLEX_UNIT_PT:
+ str += "pt";
+ break;
+ case Res_value::COMPLEX_UNIT_IN:
+ str += "in";
+ break;
+ case Res_value::COMPLEX_UNIT_MM:
+ str += "mm";
+ break;
+ default:
+ str += "???";
+ break;
+ }
+ }
+ return str;
+}
+
+void BinaryPrimitive::PrettyPrint(Printer* printer) const {
+ using ::android::Res_value;
switch (value.dataType) {
- case android::Res_value::TYPE_NULL:
- if (value.data == android::Res_value::DATA_NULL_EMPTY) {
- *out << "(empty)";
+ case Res_value::TYPE_NULL:
+ if (value.data == Res_value::DATA_NULL_EMPTY) {
+ printer->Print("@empty");
} else {
- *out << "(null)";
+ printer->Print("@null");
}
break;
- case android::Res_value::TYPE_INT_DEC:
- *out << "(integer) " << static_cast<int32_t>(value.data);
+
+ case Res_value::TYPE_INT_DEC:
+ printer->Print(StringPrintf("%" PRIi32, static_cast<int32_t>(value.data)));
break;
- case android::Res_value::TYPE_INT_HEX:
- *out << "(integer) 0x" << std::hex << value.data << std::dec;
+
+ case Res_value::TYPE_INT_HEX:
+ printer->Print(StringPrintf("0x%08x", value.data));
break;
- case android::Res_value::TYPE_INT_BOOLEAN:
- *out << "(boolean) " << (value.data != 0 ? "true" : "false");
+
+ case Res_value::TYPE_INT_BOOLEAN:
+ printer->Print(value.data != 0 ? "true" : "false");
break;
- case android::Res_value::TYPE_INT_COLOR_ARGB8:
- case android::Res_value::TYPE_INT_COLOR_RGB8:
- case android::Res_value::TYPE_INT_COLOR_ARGB4:
- case android::Res_value::TYPE_INT_COLOR_RGB4:
- *out << "(color) #" << std::hex << value.data << std::dec;
+
+ case Res_value::TYPE_INT_COLOR_ARGB8:
+ case Res_value::TYPE_INT_COLOR_RGB8:
+ case Res_value::TYPE_INT_COLOR_ARGB4:
+ case Res_value::TYPE_INT_COLOR_RGB4:
+ printer->Print(StringPrintf("#%08x", value.data));
break;
+
+ case Res_value::TYPE_FLOAT:
+ printer->Print(StringPrintf("%g", *reinterpret_cast<const float*>(&value.data)));
+ break;
+
+ case Res_value::TYPE_DIMENSION:
+ printer->Print(ComplexToString(value.data, false /*fraction*/));
+ break;
+
+ case Res_value::TYPE_FRACTION:
+ printer->Print(ComplexToString(value.data, true /*fraction*/));
+ break;
+
default:
- *out << "(unknown 0x" << std::hex << (int)value.dataType << ") 0x"
- << std::hex << value.data << std::dec;
+ printer->Print(StringPrintf("(unknown 0x%02x) 0x%08x", value.dataType, value.data));
break;
}
}
@@ -424,107 +572,107 @@
return new Attribute(*this);
}
-void Attribute::PrintMask(std::ostream* out) const {
+std::string Attribute::MaskString() const {
if (type_mask == android::ResTable_map::TYPE_ANY) {
- *out << "any";
- return;
+ return "any";
}
+ std::ostringstream out;
bool set = false;
if ((type_mask & android::ResTable_map::TYPE_REFERENCE) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "reference";
+ out << "reference";
}
if ((type_mask & android::ResTable_map::TYPE_STRING) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "string";
+ out << "string";
}
if ((type_mask & android::ResTable_map::TYPE_INTEGER) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "integer";
+ out << "integer";
}
if ((type_mask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "boolean";
+ out << "boolean";
}
if ((type_mask & android::ResTable_map::TYPE_COLOR) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "color";
+ out << "color";
}
if ((type_mask & android::ResTable_map::TYPE_FLOAT) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "float";
+ out << "float";
}
if ((type_mask & android::ResTable_map::TYPE_DIMENSION) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "dimension";
+ out << "dimension";
}
if ((type_mask & android::ResTable_map::TYPE_FRACTION) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "fraction";
+ out << "fraction";
}
if ((type_mask & android::ResTable_map::TYPE_ENUM) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "enum";
+ out << "enum";
}
if ((type_mask & android::ResTable_map::TYPE_FLAGS) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "flags";
+ out << "flags";
}
+ return out.str();
}
void Attribute::Print(std::ostream* out) const {
- *out << "(attr) ";
- PrintMask(out);
+ *out << "(attr) " << MaskString();
if (!symbols.empty()) {
*out << " [" << util::Joiner(symbols, ", ") << "]";