1330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski/*
2330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * Copyright (C) 2015 The Android Open Source Project
3330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski *
4330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * you may not use this file except in compliance with the License.
6330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * You may obtain a copy of the License at
7330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski *
8330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski *
10330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * See the License for the specific language governing permissions and
14330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski * limitations under the License.
15330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski */
16330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
17330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include "Debug.h"
18330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include "ResourceTable.h"
19330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include "ResourceValues.h"
20330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include "Util.h"
21330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
22330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include <algorithm>
23330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include <iostream>
24330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include <map>
25330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include <memory>
26d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski#include <queue>
27330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include <set>
28330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski#include <vector>
29330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
30330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskinamespace aapt {
31330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
32330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskistruct PrintVisitor : ConstValueVisitor {
33330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    void visit(const Attribute& attr, ValueVisitorArgs&) override {
34330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        std::cout << "(attr) type=";
35330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        attr.printMask(std::cout);
36330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM |
37330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            android::ResTable_map::TYPE_FLAGS;
38330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        if (attr.typeMask & kMask) {
39330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            for (const auto& symbol : attr.symbols) {
40330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << "\n        "
41330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                          << symbol.symbol.name.entry << " (" << symbol.symbol.id << ") = "
42330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                          << symbol.value;
43330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
44330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
45330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
46330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
47330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    void visit(const Style& style, ValueVisitorArgs&) override {
48330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        std::cout << "(style)";
49330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        if (style.parent.name.isValid() || style.parent.id.isValid()) {
50330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            std::cout << " parent=";
51330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            if (style.parent.name.isValid()) {
52330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << style.parent.name << " ";
53330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
54330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
55330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            if (style.parent.id.isValid()) {
56330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << style.parent.id;
57330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
58330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
59330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
60330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        for (const auto& entry : style.entries) {
61330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            std::cout << "\n        ";
62330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            if (entry.key.name.isValid()) {
63330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << entry.key.name.package << ":" << entry.key.name.entry;
64330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
65330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
66330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            if (entry.key.id.isValid()) {
67330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << "(" << entry.key.id << ")";
68330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
69330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
70330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            std::cout << "=" << *entry.value;
71330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
72330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
73330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
74330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    void visit(const Array& array, ValueVisitorArgs&) override {
75330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        array.print(std::cout);
76330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
77330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
78330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    void visit(const Plural& plural, ValueVisitorArgs&) override {
79330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        plural.print(std::cout);
80330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
81330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
82330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    void visit(const Styleable& styleable, ValueVisitorArgs&) override {
83330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        styleable.print(std::cout);
84330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
85330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
86330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    void visitItem(const Item& item, ValueVisitorArgs& args) override {
87330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        item.print(std::cout);
88330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
89330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski};
90330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
91330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskivoid Debug::printTable(const std::shared_ptr<ResourceTable>& table) {
92330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    std::cout << "Package name=" << table->getPackage();
93330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    if (table->getPackageId() != ResourceTable::kUnsetPackageId) {
94330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        std::cout << " id=" << std::hex << table->getPackageId() << std::dec;
95330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
96330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    std::cout << std::endl;
97330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
98330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    for (const auto& type : *table) {
99330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        std::cout << "  type " << type->type;
100330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        if (type->typeId != ResourceTableType::kUnsetTypeId) {
101330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            std::cout << " id=" << std::hex << type->typeId << std::dec;
102330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
103330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        std::cout << " entryCount=" << type->entries.size() << std::endl;
104330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
105330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        std::vector<const ResourceEntry*> sortedEntries;
106330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        for (const auto& entry : type->entries) {
107330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            auto iter = std::lower_bound(sortedEntries.begin(), sortedEntries.end(), entry.get(),
108330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    [](const ResourceEntry* a, const ResourceEntry* b) -> bool {
109330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                        return a->entryId < b->entryId;
110330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    });
111330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            sortedEntries.insert(iter, entry.get());
112330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
113330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
114330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        for (const ResourceEntry* entry : sortedEntries) {
115330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            ResourceId id = { table->getPackageId(), type->typeId, entry->entryId };
116330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            ResourceName name = { table->getPackage(), type->type, entry->name };
117330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            std::cout << "    spec resource " << id << " " << name;
118330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            if (entry->publicStatus.isPublic) {
119330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << " PUBLIC";
120330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
121330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            std::cout << std::endl;
122330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
123330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            PrintVisitor visitor;
124330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            for (const auto& value : entry->values) {
125330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << "      (" << value.config << ") ";
126330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                value.value->accept(visitor, {});
127330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                std::cout << std::endl;
128330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
129330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
130330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
131330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
132330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
133330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinskistatic size_t getNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) {
134330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    auto iter = std::lower_bound(names.begin(), names.end(), name);
135330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    assert(iter != names.end() && *iter == name);
136330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    return std::distance(names.begin(), iter);
137330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
138330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
139d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinskivoid Debug::printStyleGraph(const std::shared_ptr<ResourceTable>& table,
140d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski                            const ResourceName& targetStyle) {
141330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    std::map<ResourceName, std::set<ResourceName>> graph;
142330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
143d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski    std::queue<ResourceName> stylesToVisit;
144d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski    stylesToVisit.push(targetStyle);
145d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski    for (; !stylesToVisit.empty(); stylesToVisit.pop()) {
146d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        const ResourceName& styleName = stylesToVisit.front();
147d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        std::set<ResourceName>& parents = graph[styleName];
148d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        if (!parents.empty()) {
149d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski            // We've already visited this style.
150d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski            continue;
151d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        }
152d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski
153d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        const ResourceTableType* type;
154d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        const ResourceEntry* entry;
155d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        std::tie(type, entry) = table->findResource(styleName);
156d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        if (entry) {
157330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            for (const auto& value : entry->values) {
158330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                visitFunc<Style>(*value.value, [&](const Style& style) {
159330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    if (style.parent.name.isValid()) {
160d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski                        parents.insert(style.parent.name);
161d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski                        stylesToVisit.push(style.parent.name);
162330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                    }
163330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski                });
164330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski            }
165330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
166330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
167330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
168d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski    std::vector<ResourceName> names;
169d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski    for (const auto& entry : graph) {
170d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        names.push_back(entry.first);
171d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski    }
172330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
173330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    std::cout << "digraph styles {\n";
174330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    for (const auto& name : names) {
175330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        std::cout << "  node_" << getNodeIndex(names, name)
176d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski                  << " [label=\"" << name << "\"];\n";
177330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
178330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
179330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    for (const auto& entry : graph) {
180d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        const ResourceName& styleName = entry.first;
181d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        size_t styleNodeIndex = getNodeIndex(names, styleName);
182330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
183d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski        for (const auto& parentName : entry.second) {
184d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski            std::cout << "  node_" << styleNodeIndex << " -> "
185d13fb249865703901b77f48c5fed1864f06e1c63Adam Lesinski                      << "node_" << getNodeIndex(names, parentName) << ";\n";
186330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski        }
187330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    }
188330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
189330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski    std::cout << "}" << std::endl;
190330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski}
191330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski
192330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski} // namespace aapt
193