Merge "AAPT2: Better debugging output"
This commit is contained in:
committed by
Android (Google) Code Review
commit
2dd3953ae0
@@ -113,6 +113,7 @@ cc_library_host_static {
|
||||
"optimize/VersionCollapser.cpp",
|
||||
"process/SymbolTable.cpp",
|
||||
"split/TableSplitter.cpp",
|
||||
"text/Printer.cpp",
|
||||
"text/Unicode.cpp",
|
||||
"text/Utf8Iterator.cpp",
|
||||
"util/BigBuffer.cpp",
|
||||
|
||||
@@ -882,6 +882,11 @@ std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const {
|
||||
return std::string(locale);
|
||||
}
|
||||
|
||||
std::string ConfigDescription::to_string() const {
|
||||
const android::String8 str = toString();
|
||||
return std::string(str.string(), str.size());
|
||||
}
|
||||
|
||||
bool ConfigDescription::Dominates(const ConfigDescription& o) const {
|
||||
if (*this == o) {
|
||||
return true;
|
||||
|
||||
@@ -64,6 +64,8 @@ struct ConfigDescription : public android::ResTable_config {
|
||||
// Returns the BCP-47 language tag of this configuration's locale.
|
||||
std::string GetBcp47LanguageTag(bool canonicalize = false) const;
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
/**
|
||||
* A configuration X dominates another configuration Y, if X has at least the
|
||||
* precedence of Y and X is strictly more general than Y: for any type defined
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "Debug.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
@@ -25,120 +24,244 @@
|
||||
#include <vector>
|
||||
|
||||
#include "android-base/logging.h"
|
||||
#include "android-base/stringprintf.h"
|
||||
|
||||
#include "ResourceTable.h"
|
||||
#include "ResourceValues.h"
|
||||
#include "ValueVisitor.h"
|
||||
#include "text/Printer.h"
|
||||
#include "util/Util.h"
|
||||
|
||||
using ::aapt::text::Printer;
|
||||
using ::android::StringPiece;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
namespace aapt {
|
||||
|
||||
namespace {
|
||||
|
||||
class PrintVisitor : public ConstValueVisitor {
|
||||
class ValueHeadlinePrinter : public ConstValueVisitor {
|
||||
public:
|
||||
using ConstValueVisitor::Visit;
|
||||
|
||||
explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
|
||||
: package_(package), printer_(printer) {
|
||||
}
|
||||
|
||||
void Visit(const Attribute* attr) override {
|
||||
std::cout << "(attr) type=";
|
||||
attr->PrintMask(&std::cout);
|
||||
static constexpr uint32_t kMask =
|
||||
android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
|
||||
printer_->Print("(attr) type=");
|
||||
printer_->Print(attr->MaskString());
|
||||
if (!attr->symbols.empty()) {
|
||||
printer_->Print(StringPrintf(" size=%zd", attr->symbols.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void Visit(const Style* style) override {
|
||||
printer_->Print(StringPrintf("(style) size=%zd", style->entries.size()));
|
||||
if (style->parent) {
|
||||
printer_->Print(" parent=");
|
||||
|
||||
const Reference& parent_ref = style->parent.value();
|
||||
if (parent_ref.name) {
|
||||
if (parent_ref.private_reference) {
|
||||
printer_->Print("*");
|
||||
}
|
||||
|
||||
const ResourceName& parent_name = parent_ref.name.value();
|
||||
if (package_ != parent_name.package) {
|
||||
printer_->Print(parent_name.package);
|
||||
printer_->Print(":");
|
||||
}
|
||||
printer_->Print(to_string(parent_name.type));
|
||||
printer_->Print("/");
|
||||
printer_->Print(parent_name.entry);
|
||||
if (parent_ref.id) {
|
||||
printer_->Print(" (");
|
||||
printer_->Print(parent_ref.id.value().to_string());
|
||||
printer_->Print(")");
|
||||
}
|
||||
} else if (parent_ref.id) {
|
||||
printer_->Print(parent_ref.id.value().to_string());
|
||||
} else {
|
||||
printer_->Print("???");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Visit(const Array* array) override {
|
||||
printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
|
||||
}
|
||||
|
||||
void Visit(const Plural* plural) override {
|
||||
size_t count = std::count_if(plural->values.begin(), plural->values.end(),
|
||||
[](const std::unique_ptr<Item>& v) { return v != nullptr; });
|
||||
printer_->Print(StringPrintf("(plurals) size=%zd", count));
|
||||
}
|
||||
|
||||
void Visit(const Styleable* styleable) override {
|
||||
printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
|
||||
}
|
||||
|
||||
void VisitItem(const Item* item) override {
|
||||
// Pretty much guaranteed to be one line.
|
||||
if (const Reference* ref = ValueCast<Reference>(item)) {
|
||||
// Special case Reference so that we can print local resources without a package name.
|
||||
ref->PrettyPrint(package_, printer_);
|
||||
} else {
|
||||
item->PrettyPrint(printer_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string package_;
|
||||
Printer* printer_;
|
||||
};
|
||||
|
||||
class ValueBodyPrinter : public ConstValueVisitor {
|
||||
public:
|
||||
using ConstValueVisitor::Visit;
|
||||
|
||||
explicit ValueBodyPrinter(const std::string& package, Printer* printer)
|
||||
: package_(package), printer_(printer) {
|
||||
}
|
||||
|
||||
void Visit(const Attribute* attr) override {
|
||||
constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
|
||||
if (attr->type_mask & kMask) {
|
||||
for (const auto& symbol : attr->symbols) {
|
||||
std::cout << "\n " << symbol.symbol.name.value().entry;
|
||||
printer_->Print(symbol.symbol.name.value().entry);
|
||||
if (symbol.symbol.id) {
|
||||
std::cout << " (" << symbol.symbol.id.value() << ")";
|
||||
printer_->Print("(");
|
||||
printer_->Print(symbol.symbol.id.value().to_string());
|
||||
printer_->Print(")");
|
||||
}
|
||||
std::cout << " = " << symbol.value;
|
||||
printer_->Println(StringPrintf("=0x%08x", symbol.value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Visit(const Style* style) override {
|
||||
std::cout << "(style)";
|
||||
if (style->parent) {
|
||||
const Reference& parent_ref = style->parent.value();
|
||||
std::cout << " parent=";
|
||||
if (parent_ref.name) {
|
||||
if (parent_ref.private_reference) {
|
||||
std::cout << "*";
|
||||
}
|
||||
std::cout << parent_ref.name.value() << " ";
|
||||
}
|
||||
|
||||
if (parent_ref.id) {
|
||||
std::cout << parent_ref.id.value();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& entry : style->entries) {
|
||||
std::cout << "\n ";
|
||||
if (entry.key.name) {
|
||||
const ResourceName& name = entry.key.name.value();
|
||||
if (!name.package.empty()) {
|
||||
std::cout << name.package << ":";
|
||||
if (!name.package.empty() && name.package != package_) {
|
||||
printer_->Print(name.package);
|
||||
printer_->Print(":");
|
||||
}
|
||||
std::cout << name.entry;
|
||||
printer_->Print(name.entry);
|
||||
|
||||
if (entry.key.id) {
|
||||
printer_->Print("(");
|
||||
printer_->Print(entry.key.id.value().to_string());
|
||||
printer_->Print(")");
|
||||
}
|
||||
} else if (entry.key.id) {
|
||||
printer_->Print(entry.key.id.value().to_string());
|
||||
} else {
|
||||
printer_->Print("???");
|
||||
}
|
||||
|
||||
if (entry.key.id) {
|
||||
std::cout << "(" << entry.key.id.value() << ")";
|
||||
}
|
||||
|
||||
std::cout << "=" << *entry.value;
|
||||
printer_->Print("=");
|
||||
PrintItem(*entry.value);
|
||||
printer_->Println();
|
||||
}
|
||||
}
|
||||
|
||||
void Visit(const Array* array) override {
|
||||
array->Print(&std::cout);
|
||||
const size_t count = array->elements.size();
|
||||
printer_->Print("[");
|
||||
if (count > 0) {
|
||||
for (size_t i = 0u; i < count; i++) {
|
||||
if (i != 0u && i % 4u == 0u) {
|
||||
printer_->Println();
|
||||
printer_->Print(" ");
|
||||
}
|
||||
PrintItem(*array->elements[i]);
|
||||
if (i != count - 1) {
|
||||
printer_->Print(", ");
|
||||
}
|
||||
}
|
||||
printer_->Println("]");
|
||||
}
|
||||
}
|
||||
|
||||
void Visit(const Plural* plural) override {
|
||||
plural->Print(&std::cout);
|
||||
constexpr std::array<const char*, Plural::Count> kPluralNames = {
|
||||
{"zero", "one", "two", "few", "many", "other"}};
|
||||
|
||||
for (size_t i = 0; i < Plural::Count; i++) {
|
||||
if (plural->values[i] != nullptr) {
|
||||
printer_->Print(StringPrintf("%s=", kPluralNames[i]));
|
||||
PrintItem(*plural->values[i]);
|
||||
printer_->Println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Visit(const Styleable* styleable) override {
|
||||
std::cout << "(styleable)";
|
||||
for (const auto& attr : styleable->entries) {
|
||||
std::cout << "\n ";
|
||||
if (attr.name) {
|
||||
const ResourceName& name = attr.name.value();
|
||||
if (!name.package.empty()) {
|
||||
std::cout << name.package << ":";
|
||||
if (!name.package.empty() && name.package != package_) {
|
||||
printer_->Print(name.package);
|
||||
printer_->Print(":");
|
||||
}
|
||||
printer_->Print(name.entry);
|
||||
|
||||
if (attr.id) {
|
||||
printer_->Print("(");
|
||||
printer_->Print(attr.id.value().to_string());
|
||||
printer_->Print(")");
|
||||
}
|
||||
std::cout << name.entry;
|
||||
}
|
||||
|
||||
if (attr.id) {
|
||||
std::cout << "(" << attr.id.value() << ")";
|
||||
printer_->Print(attr.id.value().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VisitItem(const Item* item) override {
|
||||
item->Print(&std::cout);
|
||||
// Intentionally left empty, we already printed the Items.
|
||||
}
|
||||
|
||||
private:
|
||||
void PrintItem(const Item& item) {
|
||||
if (const Reference* ref = ValueCast<Reference>(&item)) {
|
||||
// Special case Reference so that we can print local resources without a package name.
|
||||
ref->PrettyPrint(package_, printer_);
|
||||
} else {
|
||||
item.PrettyPrint(printer_);
|
||||
}
|
||||
}
|
||||
|
||||
std::string package_;
|
||||
Printer* printer_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options) {
|
||||
PrintVisitor visitor;
|
||||
|
||||
void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
|
||||
Printer* printer) {
|
||||
for (const auto& package : table.packages) {
|
||||
std::cout << "Package name=" << package->name;
|
||||
if (package->id) {
|
||||
std::cout << " id=" << std::hex << (int)package->id.value() << std::dec;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
ValueHeadlinePrinter headline_printer(package->name, printer);
|
||||
ValueBodyPrinter body_printer(package->name, printer);
|
||||
|
||||
printer->Print("Package name=");
|
||||
printer->Print(package->name);
|
||||
if (package->id) {
|
||||
printer->Print(StringPrintf(" id=%02x", package->id.value()));
|
||||
}
|
||||
printer->Println();
|
||||
|
||||
printer->Indent();
|
||||
for (const auto& type : package->types) {
|
||||
std::cout << "\n type " << type->type;
|
||||
printer->Print("type ");
|
||||
printer->Print(to_string(type->type));
|
||||
if (type->id) {
|
||||
std::cout << " id=" << std::hex << (int)type->id.value() << std::dec;
|
||||
printer->Print(StringPrintf(" id=%02x", type->id.value()));
|
||||
}
|
||||
std::cout << " entryCount=" << type->entries.size() << std::endl;
|
||||
printer->Println(StringPrintf(" entryCount=%zd", type->entries.size()));
|
||||
|
||||
std::vector<const ResourceEntry*> sorted_entries;
|
||||
for (const auto& entry : type->entries) {
|
||||
@@ -156,35 +279,54 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
|
||||
sorted_entries.insert(iter, entry.get());
|
||||
}
|
||||
|
||||
printer->Indent();
|
||||
for (const ResourceEntry* entry : sorted_entries) {
|
||||
const ResourceId id(package->id.value_or_default(0), type->id.value_or_default(0),
|
||||
entry->id.value_or_default(0));
|
||||
const ResourceName name(package->name, type->type, entry->name);
|
||||
|
||||
std::cout << " spec resource " << id << " " << name;
|
||||
printer->Print("resource ");
|
||||
printer->Print(id.to_string());
|
||||
printer->Print(" ");
|
||||
|
||||
// Write the name without the package (this is obvious and too verbose).
|
||||
printer->Print(to_string(type->type));
|
||||
printer->Print("/");
|
||||
printer->Print(entry->name);
|
||||
|
||||
switch (entry->symbol_status.state) {
|
||||
case SymbolState::kPublic:
|
||||
std::cout << " PUBLIC";
|
||||
printer->Print(" PUBLIC");
|
||||
break;
|
||||
case SymbolState::kPrivate:
|
||||
std::cout << " _PRIVATE_";
|
||||
printer->Print(" _PRIVATE_");
|
||||
break;
|
||||
default:
|
||||
case SymbolState::kUndefined:
|
||||
// Print nothing.
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
printer->Println();
|
||||
|
||||
printer->Indent();
|
||||
for (const auto& value : entry->values) {
|
||||
std::cout << " (" << value->config << ") ";
|
||||
value->value->Accept(&visitor);
|
||||
printer->Print("(");
|
||||
printer->Print(value->config.to_string());
|
||||
printer->Print(") ");
|
||||
value->value->Accept(&headline_printer);
|
||||
if (options.show_sources && !value->value->GetSource().path.empty()) {
|
||||
std::cout << " src=" << value->value->GetSource();
|
||||
printer->Print(" src=");
|
||||
printer->Print(value->value->GetSource().to_string());
|
||||
}
|
||||
std::cout << std::endl;
|
||||
printer->Println();
|
||||
printer->Indent();
|
||||
value->value->Accept(&body_printer);
|
||||
printer->Undent();
|
||||
}
|
||||
printer->Undent();
|
||||
}
|
||||
printer->Undent();
|
||||
}
|
||||
printer->Undent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "text/Printer.h"
|
||||
#include "xml/XmlDom.h"
|
||||
|
||||
namespace aapt {
|
||||
@@ -31,9 +32,9 @@ struct DebugPrintTableOptions {
|
||||
};
|
||||
|
||||
struct Debug {
|
||||
static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options = {});
|
||||
static void PrintStyleGraph(ResourceTable* table,
|
||||
const ResourceName& target_style);
|
||||
static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
|
||||
text::Printer* printer);
|
||||
static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
|
||||
static void DumpHex(const void* data, size_t len);
|
||||
static void DumpXml(const xml::XmlResource& doc);
|
||||
};
|
||||
|
||||
@@ -17,13 +17,34 @@
|
||||
#include "Resource.h"
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using android::StringPiece;
|
||||
#include "android-base/stringprintf.h"
|
||||
|
||||
using ::android::StringPiece;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
namespace aapt {
|
||||
|
||||
StringPiece ToString(ResourceType type) {
|
||||
std::string ResourceId::to_string() const {
|
||||
return StringPrintf("0x%08x", id);
|
||||
}
|
||||
|
||||
std::string ResourceName::to_string() const {
|
||||
return ResourceNameRef(*this).to_string();
|
||||
}
|
||||
|
||||
std::string ResourceNameRef::to_string() const {
|
||||
std::ostringstream str_stream;
|
||||
if (!package.empty()) {
|
||||
str_stream << package << ":";
|
||||
}
|
||||
str_stream << type << "/" << entry;
|
||||
return str_stream.str();
|
||||
}
|
||||
|
||||
StringPiece to_string(ResourceType type) {
|
||||
switch (type) {
|
||||
case ResourceType::kAnim:
|
||||
return "anim";
|
||||
|
||||
@@ -69,11 +69,10 @@ enum class ResourceType {
|
||||
kXml,
|
||||
};
|
||||
|
||||
android::StringPiece ToString(ResourceType type);
|
||||
android::StringPiece to_string(ResourceType type);
|
||||
|
||||
/**
|
||||
* Returns a pointer to a valid ResourceType, or nullptr if
|
||||
* the string was invalid.
|
||||
* Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
|
||||
*/
|
||||
const ResourceType* ParseResourceType(const android::StringPiece& str);
|
||||
|
||||
@@ -92,7 +91,7 @@ struct ResourceName {
|
||||
int compare(const ResourceName& other) const;
|
||||
|
||||
bool is_valid() const;
|
||||
std::string ToString() const;
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -115,8 +114,10 @@ struct ResourceNameRef {
|
||||
ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
|
||||
ResourceNameRef& operator=(const ResourceName& rhs);
|
||||
|
||||
ResourceName ToResourceName() const;
|
||||
bool is_valid() const;
|
||||
|
||||
ResourceName ToResourceName() const;
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
constexpr const uint8_t kAppPackageId = 0x7fu;
|
||||
@@ -149,6 +150,8 @@ struct ResourceId {
|
||||
uint8_t package_id() const;
|
||||
uint8_t type_id() const;
|
||||
uint16_t entry_id() const;
|
||||
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
struct SourcedResourceName {
|
||||
@@ -229,7 +232,9 @@ inline bool ResourceId::is_valid() const {
|
||||
return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
|
||||
}
|
||||
|
||||
inline bool ResourceId::is_valid_dynamic() const { return (id & 0x00ff0000u) != 0; }
|
||||
inline bool ResourceId::is_valid_dynamic() const {
|
||||
return (id & 0x00ff0000u) != 0;
|
||||
}
|
||||
|
||||
inline uint8_t ResourceId::package_id() const {
|
||||
return static_cast<uint8_t>(id >> 24);
|
||||
@@ -259,24 +264,16 @@ inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
|
||||
return lhs.id != rhs.id;
|
||||
}
|
||||
|
||||
inline ::std::ostream& operator<<(::std::ostream& out,
|
||||
const ResourceId& res_id) {
|
||||
std::ios_base::fmtflags old_flags = out.flags();
|
||||
char old_fill = out.fill();
|
||||
out << "0x" << std::internal << std::setfill('0') << std::setw(8) << std::hex
|
||||
<< res_id.id;
|
||||
out.flags(old_flags);
|
||||
out.fill(old_fill);
|
||||
return out;
|
||||
inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id) {
|
||||
return out << res_id.to_string();
|
||||
}
|
||||
|
||||
//
|
||||
// ResourceType implementation.
|
||||
//
|
||||
|
||||
inline ::std::ostream& operator<<(::std::ostream& out,
|
||||
const ResourceType& val) {
|
||||
return out << ToString(val);
|
||||
inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
|
||||
return out << to_string(val);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -315,18 +312,8 @@ inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
|
||||
std::tie(rhs.package, rhs.type, rhs.entry);
|
||||
}
|
||||
|
||||
inline ::std::ostream& operator<<(::std::ostream& out,
|
||||
const ResourceName& name) {
|
||||
if (!name.package.empty()) {
|
||||
out << name.package << ":";
|
||||
}
|
||||
return out << name.type << "/" << name.entry;
|
||||
}
|
||||
|
||||
inline std::string ResourceName::ToString() const {
|
||||
std::stringstream stream;
|
||||
stream << *this;
|
||||
return stream.str();
|
||||
inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
|
||||
return out << name.to_string();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -370,12 +357,8 @@ inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
|
||||
std::tie(rhs.package, rhs.type, rhs.entry);
|
||||
}
|
||||
|
||||
inline ::std::ostream& operator<<(::std::ostream& out,
|
||||
const ResourceNameRef& name) {
|
||||
if (!name.package.empty()) {
|
||||
out << name.package << ":";
|
||||
}
|
||||
return out << name.type << "/" << name.entry;
|
||||
inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
|
||||
return out << name.to_string();
|
||||
}
|
||||
|
||||
inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
|
||||
@@ -386,8 +369,7 @@ inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
|
||||
return ResourceNameRef(lhs) != rhs;
|
||||
}
|
||||
|
||||
inline bool operator==(const SourcedResourceName& lhs,
|
||||
const SourcedResourceName& rhs) {
|
||||
inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
|
||||
return lhs.name == rhs.name && lhs.line == rhs.line;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 @@ void Reference::Print(std::ostream* out) const {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ bool Id::Flatten(android::Res_value* out) const {
|
||||
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 @@ void String::Print(std::ostream* out) const {
|
||||
*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 @@ void StyledString::Print(std::ostream* out) const {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void FileReference::Print(std::ostream* out) const {
|
||||
*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 @@ bool BinaryPrimitive::Equals(const Value* value) const {
|
||||
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 @@ BinaryPrimitive* BinaryPrimitive::Clone(StringPool* /*new_pool*/) const {
|
||||
}
|
||||
|
||||
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 @@ Attribute* Attribute::Clone(StringPool* /*new_pool*/) const {
|
||||
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, ", ") << "]";
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Resource.h"
|
||||
#include "StringPool.h"
|
||||
#include "io/File.h"
|
||||
#include "text/Printer.h"
|
||||
#include "util/Maybe.h"
|
||||
|
||||
namespace aapt {
|
||||
@@ -106,6 +107,10 @@ class Value {
|
||||
// Human readable printout of this value.
|
||||
virtual void Print(std::ostream* out) const = 0;
|
||||
|
||||
// Human readable printout of this value that may omit some information for the sake
|
||||
// of brevity and readability. Default implementation just calls Print().
|
||||
virtual void PrettyPrint(text::Printer* printer) const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const Value& value);
|
||||
|
||||
protected:
|
||||
@@ -162,6 +167,10 @@ struct Reference : public BaseItem<Reference> {
|
||||
bool Flatten(android::Res_value* out_value) const override;
|
||||
Reference* Clone(StringPool* new_pool) const override;
|
||||
void Print(std::ostream* out) const override;
|
||||
void PrettyPrint(text::Printer* printer) const override;
|
||||
|
||||
// Prints the reference without a package name if the package name matches the one given.
|
||||
void PrettyPrint(const android::StringPiece& package, text::Printer* printer) const;
|
||||
};
|
||||
|
||||
bool operator<(const Reference&, const Reference&);
|
||||
@@ -224,6 +233,7 @@ struct String : public BaseItem<String> {
|
||||
bool Flatten(android::Res_value* out_value) const override;
|
||||
String* Clone(StringPool* new_pool) const override;
|
||||
void Print(std::ostream* out) const override;
|
||||
void PrettyPrint(text::Printer* printer) const override;
|
||||
};
|
||||
|
||||
struct StyledString : public BaseItem<StyledString> {
|
||||
@@ -274,6 +284,7 @@ struct BinaryPrimitive : public BaseItem<BinaryPrimitive> {
|
||||
bool Flatten(android::Res_value* out_value) const override;
|
||||
BinaryPrimitive* Clone(StringPool* new_pool) const override;
|
||||
void Print(std::ostream* out) const override;
|
||||
void PrettyPrint(text::Printer* printer) const override;
|
||||
};
|
||||
|
||||
struct Attribute : public BaseValue<Attribute> {
|
||||
@@ -294,7 +305,7 @@ struct Attribute : public BaseValue<Attribute> {
|
||||
|
||||
bool Equals(const Value* value) const override;
|
||||
Attribute* Clone(StringPool* new_pool) const override;
|
||||
void PrintMask(std::ostream* out) const;
|
||||
std::string MaskString() const;
|
||||
void Print(std::ostream* out) const override;
|
||||
bool Matches(const Item& item, DiagMessage* out_msg = nullptr) const;
|
||||
};
|
||||
|
||||
@@ -20,16 +20,14 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "android-base/stringprintf.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "util/Maybe.h"
|
||||
|
||||
namespace aapt {
|
||||
|
||||
/**
|
||||
* Represents a file on disk. Used for logging and
|
||||
* showing errors.
|
||||
*/
|
||||
// Represents a file on disk. Used for logging and showing errors.
|
||||
struct Source {
|
||||
std::string path;
|
||||
Maybe<size_t> line;
|
||||
@@ -42,7 +40,16 @@ struct Source {
|
||||
inline Source(const android::StringPiece& path, size_t line)
|
||||
: path(path.to_string()), line(line) {}
|
||||
|
||||
inline Source WithLine(size_t line) const { return Source(path, line); }
|
||||
inline Source WithLine(size_t line) const {
|
||||
return Source(path, line);
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
if (line) {
|
||||
return ::android::base::StringPrintf("%s:%zd", path.c_str(), line.value());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
@@ -50,11 +57,7 @@ struct Source {
|
||||
//
|
||||
|
||||
inline ::std::ostream& operator<<(::std::ostream& out, const Source& source) {
|
||||
out << source.path;
|
||||
if (source.line) {
|
||||
out << ":" << source.line.value();
|
||||
}
|
||||
return out;
|
||||
return out << source.to_string();
|
||||
}
|
||||
|
||||
inline bool operator==(const Source& lhs, const Source& rhs) {
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cinttypes>
|
||||
#include <vector>
|
||||
|
||||
#include "android-base/stringprintf.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "Debug.h"
|
||||
@@ -27,9 +29,12 @@
|
||||
#include "io/FileStream.h"
|
||||
#include "io/ZipArchive.h"
|
||||
#include "process/IResourceTableConsumer.h"
|
||||
#include "text/Printer.h"
|
||||
#include "util/Files.h"
|
||||
|
||||
using ::aapt::text::Printer;
|
||||
using ::android::StringPiece;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
namespace aapt {
|
||||
|
||||
@@ -48,16 +53,28 @@ static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
|
||||
}
|
||||
|
||||
static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
|
||||
size_t len) {
|
||||
std::cout << "Resource: " << file.name << "\n"
|
||||
<< "Config: " << file.config << "\n"
|
||||
<< "Source: " << file.source << "\n"
|
||||
<< "Type: " << ResourceFileTypeToString(file.type) << "\n"
|
||||
<< "DataOff: " << offset << "\n"
|
||||
<< "DataLen: " << len << "\n";
|
||||
size_t len, Printer* printer) {
|
||||
printer->Print("Resource: ");
|
||||
printer->Println(file.name.to_string());
|
||||
|
||||
printer->Print("Config: ");
|
||||
printer->Println(file.config.to_string());
|
||||
|
||||
printer->Print("Source: ");
|
||||
printer->Println(file.source.to_string());
|
||||
|
||||
printer->Print("Type: ");
|
||||
printer->Println(ResourceFileTypeToString(file.type));
|
||||
|
||||
printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len));
|
||||
}
|
||||
|
||||
static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
|
||||
// Use a smaller buffer so that there is less latency for dumping to stdout.
|
||||
constexpr size_t kStdOutBufferSize = 1024u;
|
||||
io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
|
||||
Printer printer(&fout);
|
||||
|
||||
DebugPrintTableOptions print_options;
|
||||
print_options.show_sources = true;
|
||||
|
||||
@@ -83,6 +100,8 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
|
||||
<< "failed to parse table: " << err);
|
||||
return false;
|
||||
}
|
||||
|
||||
printer.Println("Proto APK");
|
||||
} else if (io::IFile* file = zip->FindFile("resources.arsc")) {
|
||||
std::unique_ptr<io::IData> data = file->OpenAsData();
|
||||
if (!data) {
|
||||
@@ -95,9 +114,11 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
|
||||
if (!parser.Parse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printer.Println("Binary APK");
|
||||
}
|
||||
|
||||
Debug::PrintTable(table, print_options);
|
||||
Debug::PrintTable(table, print_options, &printer);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -118,9 +139,12 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printer.Println("AAPT2 Container (APC)");
|
||||
ContainerReaderEntry* entry;
|
||||
while ((entry = reader.Next()) != nullptr) {
|
||||
if (entry->Type() == ContainerEntryType::kResTable) {
|
||||
printer.Println("kResTable");
|
||||
|
||||
pb::ResourceTable pb_table;
|
||||
if (!entry->GetResTable(&pb_table)) {
|
||||
context->GetDiagnostics()->Error(DiagMessage(file_path)
|
||||
@@ -136,8 +160,11 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug::PrintTable(table, print_options);
|
||||
printer.Indent();
|
||||
Debug::PrintTable(table, print_options, &printer);
|
||||
printer.Undent();
|
||||
} else if (entry->Type() == ContainerEntryType::kResFile) {
|
||||
printer.Println("kResFile");
|
||||
pb::internal::CompiledFile pb_compiled_file;
|
||||
off64_t offset;
|
||||
size_t length;
|
||||
@@ -155,7 +182,9 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DumpCompiledFile(file, Source(file_path), offset, length);
|
||||
printer.Indent();
|
||||
DumpCompiledFile(file, Source(file_path), offset, length, &printer);
|
||||
printer.Undent();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -164,7 +164,7 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc
|
||||
|
||||
// Add the inline attribute to the parent.
|
||||
parent_el->attributes.push_back(xml::Attribute{decl.attr_namespace_uri, decl.attr_name,
|
||||
"@" + new_doc->file.name.ToString()});
|
||||
"@" + new_doc->file.name.to_string()});
|
||||
|
||||
// Delete the subtree.
|
||||
for (auto iter = parent_el->children.begin(); iter != parent_el->children.end(); ++iter) {
|
||||
|
||||
@@ -424,7 +424,7 @@ std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(const ResourceNameRef
|
||||
// We can ignore the value here.
|
||||
return util::make_unique<Id>();
|
||||
default:
|
||||
diag_->Error(DiagMessage() << "illegal map type '" << ToString(name.type) << "' ("
|
||||
diag_->Error(DiagMessage() << "illegal map type '" << to_string(name.type) << "' ("
|
||||
<< (int)name.type << ")");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ class PackageFlattener {
|
||||
expected_type_id++;
|
||||
}
|
||||
expected_type_id++;
|
||||
type_pool_.MakeRef(ToString(type->type));
|
||||
type_pool_.MakeRef(to_string(type->type));
|
||||
|
||||
std::vector<ResourceEntry*> sorted_entries = CollectAndSortEntries(type);
|
||||
if (sorted_entries.empty()) {
|
||||
|
||||
@@ -284,7 +284,7 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
|
||||
if (type->id) {
|
||||
pb_type->mutable_type_id()->set_id(type->id.value());
|
||||
}
|
||||
pb_type->set_name(ToString(type->type).to_string());
|
||||
pb_type->set_name(to_string(type->type).to_string());
|
||||
|
||||
for (const std::unique_ptr<ResourceEntry>& entry : type->entries) {
|
||||
pb::Entry* pb_entry = pb_type->add_entry();
|
||||
@@ -328,7 +328,7 @@ static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref)
|
||||
pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
|
||||
|
||||
if (ref.name) {
|
||||
pb_ref->set_name(ref.name.value().ToString());
|
||||
pb_ref->set_name(ref.name.value().to_string());
|
||||
}
|
||||
|
||||
pb_ref->set_private_(ref.private_reference);
|
||||
@@ -523,14 +523,14 @@ void SerializeItemToPb(const Item& item, pb::Item* out_item) {
|
||||
}
|
||||
|
||||
void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
|
||||
out_file->set_resource_name(file.name.ToString());
|
||||
out_file->set_resource_name(file.name.to_string());
|
||||
out_file->set_source_path(file.source.path);
|
||||
out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
|
||||
SerializeConfig(file.config, out_file->mutable_config());
|
||||
|
||||
for (const SourcedResourceName& exported : file.exported_symbols) {
|
||||
pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
|
||||
pb_symbol->set_resource_name(exported.name.ToString());
|
||||
pb_symbol->set_resource_name(exported.name.to_string());
|
||||
pb_symbol->mutable_source()->set_line_number(exported.line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "android-base/utf8.h"
|
||||
|
||||
using ::android::base::SystemErrorCodeToString;
|
||||
using ::android::base::unique_fd;
|
||||
|
||||
namespace aapt {
|
||||
namespace io {
|
||||
@@ -100,7 +101,13 @@ std::string FileInputStream::GetError() const {
|
||||
}
|
||||
|
||||
FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
|
||||
: FileOutputStream(::android::base::utf8::open(path.c_str(), mode), buffer_capacity) {
|
||||
: FileOutputStream(unique_fd(::android::base::utf8::open(path.c_str(), mode)),
|
||||
buffer_capacity) {
|
||||
}
|
||||
|
||||
FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
|
||||
: FileOutputStream(fd.get(), buffer_capacity) {
|
||||
owned_fd_ = std::move(fd);
|
||||
}
|
||||
|
||||
FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
|
||||
@@ -118,7 +125,7 @@ FileOutputStream::~FileOutputStream() {
|
||||
}
|
||||
|
||||
bool FileOutputStream::Next(void** data, size_t* size) {
|
||||
if (fd_ == -1 || HadError()) {
|
||||
if (HadError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -159,7 +166,8 @@ bool FileOutputStream::FlushImpl() {
|
||||
ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
|
||||
if (n < 0) {
|
||||
error_ = SystemErrorCodeToString(errno);
|
||||
fd_.reset();
|
||||
owned_fd_.reset();
|
||||
fd_ = -1;
|
||||
buffer_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,12 +29,15 @@
|
||||
namespace aapt {
|
||||
namespace io {
|
||||
|
||||
constexpr size_t kDefaultBufferCapacity = 4096u;
|
||||
|
||||
class FileInputStream : public InputStream {
|
||||
public:
|
||||
explicit FileInputStream(const std::string& path, size_t buffer_capacity = 4096);
|
||||
explicit FileInputStream(const std::string& path,
|
||||
size_t buffer_capacity = kDefaultBufferCapacity);
|
||||
|
||||
// Takes ownership of `fd`.
|
||||
explicit FileInputStream(int fd, size_t buffer_capacity = 4096);
|
||||
// Take ownership of `fd`.
|
||||
explicit FileInputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
|
||||
|
||||
bool Next(const void** data, size_t* size) override;
|
||||
|
||||
@@ -61,10 +64,14 @@ class FileInputStream : public InputStream {
|
||||
class FileOutputStream : public OutputStream {
|
||||
public:
|
||||
explicit FileOutputStream(const std::string& path, int mode = O_RDWR | O_CREAT | O_BINARY,
|
||||
size_t buffer_capacity = 4096);
|
||||
size_t buffer_capacity = kDefaultBufferCapacity);
|
||||
|
||||
// Does not take ownership of `fd`.
|
||||
explicit FileOutputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
|
||||
|
||||
// Takes ownership of `fd`.
|
||||
explicit FileOutputStream(int fd, size_t buffer_capacity = 4096);
|
||||
explicit FileOutputStream(android::base::unique_fd fd,
|
||||
size_t buffer_capacity = kDefaultBufferCapacity);
|
||||
|
||||
~FileOutputStream();
|
||||
|
||||
@@ -86,7 +93,8 @@ class FileOutputStream : public OutputStream {
|
||||
|
||||
bool FlushImpl();
|
||||
|
||||
android::base::unique_fd fd_;
|
||||
android::base::unique_fd owned_fd_;
|
||||
int fd_;
|
||||
std::string error_;
|
||||
std::unique_ptr<uint8_t[]> buffer_;
|
||||
size_t buffer_capacity_;
|
||||
|
||||
@@ -87,10 +87,8 @@ TEST(FileOutputStreamTest, NextAndBackup) {
|
||||
const std::string input = "this is a cool string";
|
||||
|
||||
TemporaryFile file;
|
||||
int fd = file.release();
|
||||
|
||||
// FileOutputStream takes ownership.
|
||||
FileOutputStream out(fd, 10u);
|
||||
FileOutputStream out(file.fd, 10u);
|
||||
ASSERT_FALSE(out.HadError());
|
||||
EXPECT_THAT(out.ByteCount(), Eq(0u));
|
||||
|
||||
@@ -118,10 +116,10 @@ TEST(FileOutputStreamTest, NextAndBackup) {
|
||||
|
||||
ASSERT_TRUE(out.Flush());
|
||||
|
||||
lseek64(fd, 0, SEEK_SET);
|
||||
lseek64(file.fd, 0, SEEK_SET);
|
||||
|
||||
std::string actual;
|
||||
ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
|
||||
ASSERT_TRUE(android::base::ReadFdToString(file.fd, &actual));
|
||||
EXPECT_THAT(actual, StrEq(input));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
|
||||
|
||||
using ::android::StringPiece;
|
||||
using ::google::protobuf::io::ZeroCopyOutputStream;
|
||||
|
||||
namespace aapt {
|
||||
@@ -93,6 +94,25 @@ bool Copy(OutputStream* out, InputStream* in) {
|
||||
return !in->HadError();
|
||||
}
|
||||
|
||||
bool Copy(OutputStream* out, const StringPiece& in) {
|
||||
const char* in_buffer = in.data();
|
||||
size_t in_len = in.size();
|
||||
while (in_len != 0) {
|
||||
void* out_buffer;
|
||||
size_t out_len;
|
||||
if (!out->Next(&out_buffer, &out_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t bytes_to_copy = in_len < out_len ? in_len : out_len;
|
||||
memcpy(out_buffer, in_buffer, bytes_to_copy);
|
||||
out->BackUp(out_len - bytes_to_copy);
|
||||
in_buffer += bytes_to_copy;
|
||||
in_len -= bytes_to_copy;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Copy(ZeroCopyOutputStream* out, InputStream* in) {
|
||||
OutputStreamAdaptor adaptor(out);
|
||||
return Copy(&adaptor, in);
|
||||
|
||||
@@ -42,6 +42,7 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::MessageLite*
|
||||
// Copies the data from in to out. Returns false if there was an error.
|
||||
// If there was an error, check the individual streams' HadError/GetError methods.
|
||||
bool Copy(OutputStream* out, InputStream* in);
|
||||
bool Copy(OutputStream* out, const ::android::StringPiece& in);
|
||||
bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in);
|
||||
|
||||
class OutputStreamAdaptor : public io::OutputStream {
|
||||
|
||||
@@ -461,7 +461,7 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso
|
||||
}
|
||||
|
||||
if (out_rewrite_method != nullptr) {
|
||||
const StringPiece& type_str = ToString(name.type);
|
||||
const StringPiece& type_str = to_string(name.type);
|
||||
out_rewrite_method->AppendStatement(StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | (p << 24);",
|
||||
type_str.data(), field_name.data(),
|
||||
type_str.data(), field_name.data()));
|
||||
@@ -584,7 +584,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
|
||||
(options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
|
||||
|
||||
std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
|
||||
ToString(type->type), ClassQualifier::kStatic, force_creation_if_empty);
|
||||
to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
|
||||
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
|
||||
rewrite_method.get(), out_r_txt)) {
|
||||
return false;
|
||||
|
||||
@@ -289,7 +289,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
|
||||
const android::ResTable& table = assets_.getResources(false);
|
||||
|
||||
const std::u16string package16 = util::Utf8ToUtf16(name.package);
|
||||
const std::u16string type16 = util::Utf8ToUtf16(ToString(name.type));
|
||||
const std::u16string type16 = util::Utf8ToUtf16(to_string(name.type));
|
||||
const std::u16string entry16 = util::Utf8ToUtf16(name.entry);
|
||||
|
||||
uint32_t type_spec_flags = 0;
|
||||
|
||||
92
tools/aapt2/text/Printer.cpp
Normal file
92
tools/aapt2/text/Printer.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "text/Printer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "io/Util.h"
|
||||
|
||||
using ::aapt::io::OutputStream;
|
||||
using ::android::StringPiece;
|
||||
|
||||
namespace aapt {
|
||||
namespace text {
|
||||
|
||||
void Printer::Println(const StringPiece& str) {
|
||||
Print(str);
|
||||
Print("\n");
|
||||
}
|
||||
|
||||
void Printer::Println() {
|
||||
Print("\n");
|
||||
}
|
||||
|
||||
void Printer::Print(const StringPiece& str) {
|
||||
if (error_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto remaining_str_begin = str.begin();
|
||||
const auto remaining_str_end = str.end();
|
||||
while (remaining_str_end != remaining_str_begin) {
|
||||
// Find the next new-line.
|
||||
const auto new_line_iter = std::find(remaining_str_begin, remaining_str_end, '\n');
|
||||
|
||||
// We will copy the string up until the next new-line (or end of string).
|
||||
const StringPiece str_to_copy = str.substr(remaining_str_begin, new_line_iter);
|
||||
if (!str_to_copy.empty()) {
|
||||
if (needs_indent_) {
|
||||
for (int i = 0; i < indent_level_; i++) {
|
||||
if (!io::Copy(out_, " ")) {
|
||||
error_ = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
needs_indent_ = false;
|
||||
}
|
||||
|
||||
if (!io::Copy(out_, str_to_copy)) {
|
||||
error_ = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a new-line.
|
||||
if (new_line_iter != remaining_str_end) {
|
||||
if (!io::Copy(out_, "\n")) {
|
||||
error_ = true;
|
||||
return;
|
||||
}
|
||||
needs_indent_ = true;
|
||||
// Ok to increment iterator here because we know that the '\n' character is one byte.
|
||||
remaining_str_begin = new_line_iter + 1;
|
||||
} else {
|
||||
remaining_str_begin = new_line_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Printer::Indent() {
|
||||
++indent_level_;
|
||||
}
|
||||
|
||||
void Printer::Undent() {
|
||||
--indent_level_;
|
||||
}
|
||||
|
||||
} // namespace text
|
||||
} // namespace aapt
|
||||
53
tools/aapt2/text/Printer.h
Normal file
53
tools/aapt2/text/Printer.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef AAPT_TEXT_PRINTER_H
|
||||
#define AAPT_TEXT_PRINTER_H
|
||||
|
||||
#include "android-base/macros.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "io/Io.h"
|
||||
|
||||
namespace aapt {
|
||||
namespace text {
|
||||
|
||||
// An indenting Printer that helps write formatted text to the OutputStream.
|
||||
class Printer {
|
||||
public:
|
||||
explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
|
||||
}
|
||||
|
||||
void Print(const ::android::StringPiece& str);
|
||||
void Println(const ::android::StringPiece& str);
|
||||
void Println();
|
||||
|
||||
void Indent();
|
||||
void Undent();
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(Printer);
|
||||
|
||||
::aapt::io::OutputStream* out_;
|
||||
int indent_level_ = 0;
|
||||
bool needs_indent_ = false;
|
||||
bool error_ = false;
|
||||
};
|
||||
|
||||
} // namespace text
|
||||
} // namespace aapt
|
||||
|
||||
#endif // AAPT_TEXT_PRINTER_H
|
||||
67
tools/aapt2/text/Printer_test.cpp
Normal file
67
tools/aapt2/text/Printer_test.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "text/Printer.h"
|
||||
|
||||
#include "io/StringStream.h"
|
||||
#include "test/Test.h"
|
||||
|
||||
using ::aapt::io::StringOutputStream;
|
||||
using ::android::StringPiece;
|
||||
using ::testing::StrEq;
|
||||
|
||||
namespace aapt {
|
||||
namespace text {
|
||||
|
||||
TEST(PrinterTest, PrintsToStreamWithIndents) {
|
||||
std::string result;
|
||||
StringOutputStream out(&result);
|
||||
Printer printer(&out);
|
||||
|
||||
printer.Print("Hello");
|
||||
out.Flush();
|
||||
EXPECT_THAT(result, StrEq("Hello"));
|
||||
|
||||
printer.Println();
|
||||
out.Flush();
|
||||
EXPECT_THAT(result, StrEq("Hello\n"));
|
||||
|
||||
// This shouldn't print anything yet.
|
||||
printer.Indent();
|
||||
out.Flush();
|
||||
EXPECT_THAT(result, StrEq("Hello\n"));
|
||||
|
||||
// Now we should see the indent.
|
||||
printer.Print("world!");
|
||||
out.Flush();
|
||||
EXPECT_THAT(result, StrEq("Hello\n world!"));
|
||||
|
||||
printer.Println(" What a\nlovely day.");
|
||||
out.Flush();
|
||||
EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\n"));
|
||||
|
||||
// This shouldn't print anything yet.
|
||||
printer.Undent();
|
||||
out.Flush();
|
||||
EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\n"));
|
||||
|
||||
printer.Println("Isn't it?");
|
||||
out.Flush();
|
||||
EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\nIsn't it?\n"));
|
||||
}
|
||||
|
||||
} // namespace text
|
||||
} // namespace aapt
|
||||
Reference in New Issue
Block a user