blob: 304e571832f4a3e5b0976a40ca47996d6889283f [file] [log] [blame]
Adam Lesinski330edcd2015-05-04 17:40:56 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Debug.h"
18#include "ResourceTable.h"
19#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "util/Util.h"
21#include "ValueVisitor.h"
Adam Lesinski330edcd2015-05-04 17:40:56 -070022
23#include <algorithm>
24#include <iostream>
25#include <map>
26#include <memory>
Adam Lesinskid13fb242015-05-12 20:40:48 -070027#include <queue>
Adam Lesinski330edcd2015-05-04 17:40:56 -070028#include <set>
29#include <vector>
30
31namespace aapt {
32
Adam Lesinski355f2852016-02-13 20:26:45 -080033class PrintVisitor : public ValueVisitor {
34public:
Adam Lesinski1ab598f2015-08-14 14:26:04 -070035 using ValueVisitor::visit;
36
37 void visit(Attribute* attr) override {
Adam Lesinski330edcd2015-05-04 17:40:56 -070038 std::cout << "(attr) type=";
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039 attr->printMask(&std::cout);
Adam Lesinski330edcd2015-05-04 17:40:56 -070040 static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM |
41 android::ResTable_map::TYPE_FLAGS;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070042 if (attr->typeMask & kMask) {
43 for (const auto& symbol : attr->symbols) {
44 std::cout << "\n " << symbol.symbol.name.value().entry;
45 if (symbol.symbol.id) {
46 std::cout << " (" << symbol.symbol.id.value() << ")";
47 }
48 std::cout << " = " << symbol.value;
Adam Lesinski330edcd2015-05-04 17:40:56 -070049 }
50 }
51 }
52
Adam Lesinski1ab598f2015-08-14 14:26:04 -070053 void visit(Style* style) override {
Adam Lesinski330edcd2015-05-04 17:40:56 -070054 std::cout << "(style)";
Adam Lesinski1ab598f2015-08-14 14:26:04 -070055 if (style->parent) {
Adam Lesinski24b8ff02015-12-16 14:01:57 -080056 const Reference& parentRef = style->parent.value();
Adam Lesinski330edcd2015-05-04 17:40:56 -070057 std::cout << " parent=";
Adam Lesinski24b8ff02015-12-16 14:01:57 -080058 if (parentRef.name) {
59 if (parentRef.privateReference) {
60 std::cout << "*";
61 }
62 std::cout << parentRef.name.value() << " ";
Adam Lesinski330edcd2015-05-04 17:40:56 -070063 }
64
Adam Lesinski24b8ff02015-12-16 14:01:57 -080065 if (parentRef.id) {
66 std::cout << parentRef.id.value();
Adam Lesinski330edcd2015-05-04 17:40:56 -070067 }
68 }
69
Adam Lesinski1ab598f2015-08-14 14:26:04 -070070 for (const auto& entry : style->entries) {
Adam Lesinski330edcd2015-05-04 17:40:56 -070071 std::cout << "\n ";
Adam Lesinski1ab598f2015-08-14 14:26:04 -070072 if (entry.key.name) {
Adam Lesinski355f2852016-02-13 20:26:45 -080073 const ResourceName& name = entry.key.name.value();
74 if (!name.package.empty()) {
75 std::cout << name.package << ":";
76 }
77 std::cout << name.entry;
Adam Lesinski330edcd2015-05-04 17:40:56 -070078 }
79
Adam Lesinski1ab598f2015-08-14 14:26:04 -070080 if (entry.key.id) {
81 std::cout << "(" << entry.key.id.value() << ")";
Adam Lesinski330edcd2015-05-04 17:40:56 -070082 }
83
84 std::cout << "=" << *entry.value;
85 }
86 }
87
Adam Lesinski1ab598f2015-08-14 14:26:04 -070088 void visit(Array* array) override {
89 array->print(&std::cout);
Adam Lesinski330edcd2015-05-04 17:40:56 -070090 }
91
Adam Lesinski1ab598f2015-08-14 14:26:04 -070092 void visit(Plural* plural) override {
93 plural->print(&std::cout);
Adam Lesinski330edcd2015-05-04 17:40:56 -070094 }
95
Adam Lesinski1ab598f2015-08-14 14:26:04 -070096 void visit(Styleable* styleable) override {
Adam Lesinski355f2852016-02-13 20:26:45 -080097 std::cout << "(styleable)";
98 for (const auto& attr : styleable->entries) {
99 std::cout << "\n ";
100 if (attr.name) {
101 const ResourceName& name = attr.name.value();
102 if (!name.package.empty()) {
103 std::cout << name.package << ":";
104 }
105 std::cout << name.entry;
106 }
107
108 if (attr.id) {
109 std::cout << "(" << attr.id.value() << ")";
110 }
111 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700112 }
113
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700114 void visitItem(Item* item) override {
115 item->print(&std::cout);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700116 }
117};
118
Adam Lesinski355f2852016-02-13 20:26:45 -0800119void Debug::printTable(ResourceTable* table, const DebugPrintTableOptions& options) {
120 PrintVisitor visitor;
121
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700122 for (auto& package : table->packages) {
123 std::cout << "Package name=" << package->name;
124 if (package->id) {
125 std::cout << " id=" << std::hex << (int) package->id.value() << std::dec;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700126 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700127 std::cout << std::endl;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700128
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700129 for (const auto& type : package->types) {
Adam Lesinski355f2852016-02-13 20:26:45 -0800130 std::cout << "\n type " << type->type;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700131 if (type->id) {
132 std::cout << " id=" << std::hex << (int) type->id.value() << std::dec;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700133 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700134 std::cout << " entryCount=" << type->entries.size() << std::endl;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700135
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700136 std::vector<const ResourceEntry*> sortedEntries;
137 for (const auto& entry : type->entries) {
138 auto iter = std::lower_bound(sortedEntries.begin(), sortedEntries.end(), entry.get(),
139 [](const ResourceEntry* a, const ResourceEntry* b) -> bool {
140 if (a->id && b->id) {
141 return a->id.value() < b->id.value();
142 } else if (a->id) {
143 return true;
144 } else {
145 return false;
146 }
147 });
148 sortedEntries.insert(iter, entry.get());
149 }
150
151 for (const ResourceEntry* entry : sortedEntries) {
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700152 ResourceId id(package->id ? package->id.value() : uint8_t(0),
153 type->id ? type->id.value() : uint8_t(0),
154 entry->id ? entry->id.value() : uint16_t(0));
155 ResourceName name(package->name, type->type, entry->name);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700156
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700157 std::cout << " spec resource " << id << " " << name;
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700158 switch (entry->symbolStatus.state) {
159 case SymbolState::kPublic: std::cout << " PUBLIC"; break;
160 case SymbolState::kPrivate: std::cout << " _PRIVATE_"; break;
161 default: break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700162 }
Adam Lesinski9e10ac72015-10-16 14:37:48 -0700163
Adam Lesinski330edcd2015-05-04 17:40:56 -0700164 std::cout << std::endl;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700165
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700166 for (const auto& value : entry->values) {
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800167 std::cout << " (" << value->config << ") ";
168 value->value->accept(&visitor);
Adam Lesinski355f2852016-02-13 20:26:45 -0800169 if (options.showSources && !value->value->getSource().path.empty()) {
170 std::cout << " src=" << value->value->getSource();
171 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700172 std::cout << std::endl;
173 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700174 }
175 }
176 }
177}
178
179static size_t getNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) {
180 auto iter = std::lower_bound(names.begin(), names.end(), name);
181 assert(iter != names.end() && *iter == name);
182 return std::distance(names.begin(), iter);
183}
184
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700185void Debug::printStyleGraph(ResourceTable* table, const ResourceName& targetStyle) {
Adam Lesinski330edcd2015-05-04 17:40:56 -0700186 std::map<ResourceName, std::set<ResourceName>> graph;
187
Adam Lesinskid13fb242015-05-12 20:40:48 -0700188 std::queue<ResourceName> stylesToVisit;
189 stylesToVisit.push(targetStyle);
190 for (; !stylesToVisit.empty(); stylesToVisit.pop()) {
191 const ResourceName& styleName = stylesToVisit.front();
192 std::set<ResourceName>& parents = graph[styleName];
193 if (!parents.empty()) {
194 // We've already visited this style.
195 continue;
196 }
197
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700198 Maybe<ResourceTable::SearchResult> result = table->findResource(styleName);
199 if (result) {
200 ResourceEntry* entry = result.value().entry;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700201 for (const auto& value : entry->values) {
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800202 if (Style* style = valueCast<Style>(value->value.get())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700203 if (style->parent && style->parent.value().name) {
204 parents.insert(style->parent.value().name.value());
205 stylesToVisit.push(style->parent.value().name.value());
Adam Lesinski330edcd2015-05-04 17:40:56 -0700206 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700207 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700208 }
209 }
210 }
211
Adam Lesinskid13fb242015-05-12 20:40:48 -0700212 std::vector<ResourceName> names;
213 for (const auto& entry : graph) {
214 names.push_back(entry.first);
215 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700216
217 std::cout << "digraph styles {\n";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700218 for (const auto& name : names) {
219 std::cout << " node_" << getNodeIndex(names, name)
Adam Lesinskid13fb242015-05-12 20:40:48 -0700220 << " [label=\"" << name << "\"];\n";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700221 }
222
223 for (const auto& entry : graph) {
Adam Lesinskid13fb242015-05-12 20:40:48 -0700224 const ResourceName& styleName = entry.first;
225 size_t styleNodeIndex = getNodeIndex(names, styleName);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700226
Adam Lesinskid13fb242015-05-12 20:40:48 -0700227 for (const auto& parentName : entry.second) {
228 std::cout << " node_" << styleNodeIndex << " -> "
229 << "node_" << getNodeIndex(names, parentName) << ";\n";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700230 }
231 }
232
233 std::cout << "}" << std::endl;
234}
235
Adam Lesinski52364f72016-01-11 13:10:24 -0800236void Debug::dumpHex(const void* data, size_t len) {
237 const uint8_t* d = (const uint8_t*) data;
238 for (size_t i = 0; i < len; i++) {
239 std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t) d[i] << " ";
240 if (i % 8 == 7) {
241 std::cerr << "\n";
242 }
243 }
244
245 if (len - 1 % 8 != 7) {
246 std::cerr << std::endl;
247 }
248}
249
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700250namespace {
251
252class XmlPrinter : public xml::Visitor {
253public:
254 using xml::Visitor::visit;
255
256 void visit(xml::Element* el) override {
257 std::cerr << mPrefix;
258 std::cerr << "E: ";
259 if (!el->namespaceUri.empty()) {
260 std::cerr << el->namespaceUri << ":";
261 }
262 std::cerr << el->name << " (line=" << el->lineNumber << ")\n";
263
264 for (const xml::Attribute& attr : el->attributes) {
265 std::cerr << mPrefix << " A: ";
266 if (!attr.namespaceUri.empty()) {
267 std::cerr << attr.namespaceUri << ":";
268 }
269 std::cerr << attr.name << "=" << attr.value << "\n";
270 }
271
272 const size_t previousSize = mPrefix.size();
273 mPrefix += " ";
274 xml::Visitor::visit(el);
275 mPrefix.resize(previousSize);
276 }
277
278 void visit(xml::Namespace* ns) override {
279 std::cerr << mPrefix;
280 std::cerr << "N: " << ns->namespacePrefix << "=" << ns->namespaceUri
281 << " (line=" << ns->lineNumber << ")\n";
282
283 const size_t previousSize = mPrefix.size();
284 mPrefix += " ";
285 xml::Visitor::visit(ns);
286 mPrefix.resize(previousSize);
287 }
288
289 void visit(xml::Text* text) override {
290 std::cerr << mPrefix;
291 std::cerr << "T: '" << text->text << "'\n";
292 }
293
294private:
295 std::string mPrefix;
296};
297
298} // namespace
299
300void Debug::dumpXml(xml::XmlResource* doc) {
301 XmlPrinter printer;
302 doc->root->accept(&printer);
303}
Adam Lesinski52364f72016-01-11 13:10:24 -0800304
Adam Lesinski330edcd2015-05-04 17:40:56 -0700305} // namespace aapt