Home | History | Annotate | Download | only in aapt2
      1 /*
      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"
     20 #include "util/Util.h"
     21 #include "ValueVisitor.h"
     22 
     23 #include <algorithm>
     24 #include <iostream>
     25 #include <map>
     26 #include <memory>
     27 #include <queue>
     28 #include <set>
     29 #include <vector>
     30 
     31 namespace aapt {
     32 
     33 class PrintVisitor : public ValueVisitor {
     34 public:
     35     using ValueVisitor::visit;
     36 
     37     void visit(Attribute* attr) override {
     38         std::cout << "(attr) type=";
     39         attr->printMask(&std::cout);
     40         static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM |
     41             android::ResTable_map::TYPE_FLAGS;
     42         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;
     49             }
     50         }
     51     }
     52 
     53     void visit(Style* style) override {
     54         std::cout << "(style)";
     55         if (style->parent) {
     56             const Reference& parentRef = style->parent.value();
     57             std::cout << " parent=";
     58             if (parentRef.name) {
     59                 if (parentRef.privateReference) {
     60                     std::cout << "*";
     61                 }
     62                 std::cout << parentRef.name.value() << " ";
     63             }
     64 
     65             if (parentRef.id) {
     66                 std::cout << parentRef.id.value();
     67             }
     68         }
     69 
     70         for (const auto& entry : style->entries) {
     71             std::cout << "\n        ";
     72             if (entry.key.name) {
     73                 const ResourceName& name = entry.key.name.value();
     74                 if (!name.package.empty()) {
     75                     std::cout << name.package << ":";
     76                 }
     77                 std::cout << name.entry;
     78             }
     79 
     80             if (entry.key.id) {
     81                 std::cout << "(" << entry.key.id.value() << ")";
     82             }
     83 
     84             std::cout << "=" << *entry.value;
     85         }
     86     }
     87 
     88     void visit(Array* array) override {
     89         array->print(&std::cout);
     90     }
     91 
     92     void visit(Plural* plural) override {
     93         plural->print(&std::cout);
     94     }
     95 
     96     void visit(Styleable* styleable) override {
     97         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         }
    112     }
    113 
    114     void visitItem(Item* item) override {
    115         item->print(&std::cout);
    116     }
    117 };
    118 
    119 void Debug::printTable(ResourceTable* table, const DebugPrintTableOptions& options) {
    120     PrintVisitor visitor;
    121 
    122     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;
    126         }
    127         std::cout << std::endl;
    128 
    129         for (const auto& type : package->types) {
    130             std::cout << "\n  type " << type->type;
    131             if (type->id) {
    132                 std::cout << " id=" << std::hex << (int) type->id.value() << std::dec;
    133             }
    134             std::cout << " entryCount=" << type->entries.size() << std::endl;
    135 
    136             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) {
    152                 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);
    156 
    157                 std::cout << "    spec resource " << id << " " << name;
    158                 switch (entry->symbolStatus.state) {
    159                 case SymbolState::kPublic: std::cout << " PUBLIC"; break;
    160                 case SymbolState::kPrivate: std::cout << " _PRIVATE_"; break;
    161                 default: break;
    162                 }
    163 
    164                 std::cout << std::endl;
    165 
    166                 for (const auto& value : entry->values) {
    167                     std::cout << "      (" << value->config << ") ";
    168                     value->value->accept(&visitor);
    169                     if (options.showSources && !value->value->getSource().path.empty()) {
    170                         std::cout << " src=" << value->value->getSource();
    171                     }
    172                     std::cout << std::endl;
    173                 }
    174             }
    175         }
    176     }
    177 }
    178 
    179 static 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 
    185 void Debug::printStyleGraph(ResourceTable* table, const ResourceName& targetStyle) {
    186     std::map<ResourceName, std::set<ResourceName>> graph;
    187 
    188     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 
    198         Maybe<ResourceTable::SearchResult> result = table->findResource(styleName);
    199         if (result) {
    200             ResourceEntry* entry = result.value().entry;
    201             for (const auto& value : entry->values) {
    202                 if (Style* style = valueCast<Style>(value->value.get())) {
    203                     if (style->parent && style->parent.value().name) {
    204                         parents.insert(style->parent.value().name.value());
    205                         stylesToVisit.push(style->parent.value().name.value());
    206                     }
    207                 }
    208             }
    209         }
    210     }
    211 
    212     std::vector<ResourceName> names;
    213     for (const auto& entry : graph) {
    214         names.push_back(entry.first);
    215     }
    216 
    217     std::cout << "digraph styles {\n";
    218     for (const auto& name : names) {
    219         std::cout << "  node_" << getNodeIndex(names, name)
    220                   << " [label=\"" << name << "\"];\n";
    221     }
    222 
    223     for (const auto& entry : graph) {
    224         const ResourceName& styleName = entry.first;
    225         size_t styleNodeIndex = getNodeIndex(names, styleName);
    226 
    227         for (const auto& parentName : entry.second) {
    228             std::cout << "  node_" << styleNodeIndex << " -> "
    229                       << "node_" << getNodeIndex(names, parentName) << ";\n";
    230         }
    231     }
    232 
    233     std::cout << "}" << std::endl;
    234 }
    235 
    236 void 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 
    250 
    251 } // namespace aapt
    252