1 /* 2 * Copyright (C) 2019 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 #ifndef IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_ 18 #define IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_ 19 20 #include <memory> 21 #include <string> 22 23 #include "ResourceUtils.h" 24 #include "Result.h" 25 #include "android-base/macros.h" 26 #include "androidfw/ResourceTypes.h" 27 #include "utils/String16.h" 28 29 namespace android::idmap2 { 30 31 struct XmlParser { 32 using Event = ResXMLParser::event_code_t; 33 class iterator; 34 35 class Node { 36 public: 37 Event event() const; 38 std::string name() const; 39 40 Result<Res_value> GetAttributeValue(const std::string& name) const; 41 Result<Res_value> GetAttributeValue(ResourceId attr, const std::string& label) const; 42 43 Result<std::string> GetAttributeStringValue(const std::string& name) const; 44 Result<std::string> GetAttributeStringValue(ResourceId attr, const std::string& label) const; 45 46 bool operator==(const Node& rhs) const; 47 bool operator!=(const Node& rhs) const; 48 49 private: 50 explicit Node(const ResXMLTree& tree); 51 Node(const ResXMLTree& tree, const ResXMLParser::ResXMLPosition& pos); 52 53 // Retrieves/Sets the position of the position of the xml parser in the xml tree. 54 ResXMLParser::ResXMLPosition get_position() const; 55 void set_position(const ResXMLParser::ResXMLPosition& pos); 56 57 // If `inner_child` is true, seek advances the parser to the first inner child of the current 58 // node. Otherwise, seek advances the parser to the following node. Returns false if there is 59 // no node to seek to. 60 bool Seek(bool inner_child); 61 62 ResXMLParser parser_; 63 friend iterator; 64 }; 65 66 class iterator { 67 public: iteratorXmlParser68 iterator(const iterator& other) : iterator(other.tree_, other.iter_) { 69 } 70 71 inline iterator& operator=(const iterator& rhs) { 72 iter_.set_position(rhs.iter_.get_position()); 73 return *this; 74 } 75 76 inline bool operator==(const iterator& rhs) const { 77 return iter_ == rhs.iter_; 78 } 79 80 inline bool operator!=(const iterator& rhs) const { 81 return !(*this == rhs); 82 } 83 84 inline iterator operator++() { 85 // Seek to the following xml node. 86 iter_.Seek(false /* inner_child */); 87 return *this; 88 } 89 beginXmlParser90 iterator begin() const { 91 iterator child_it(*this); 92 // Seek to the first inner child of the current node. 93 child_it.iter_.Seek(true /* inner_child */); 94 return child_it; 95 } 96 endXmlParser97 iterator end() const { 98 iterator child_it = begin(); 99 while (child_it.iter_.Seek(false /* inner_child */)) { 100 // Continue iterating until the end tag is found. 101 } 102 103 return child_it; 104 } 105 106 inline const Node operator*() { 107 return Node(tree_, iter_.get_position()); 108 } 109 110 inline const Node* operator->() { 111 return &iter_; 112 } 113 114 private: iteratorXmlParser115 explicit iterator(const ResXMLTree& tree) : tree_(tree), iter_(Node(tree)) { 116 } iteratorXmlParser117 iterator(const ResXMLTree& tree, const Node& node) 118 : tree_(tree), iter_(Node(tree, node.get_position())) { 119 } 120 121 const ResXMLTree& tree_; 122 Node iter_; 123 friend XmlParser; 124 }; 125 126 // Creates a new xml parser beginning at the first tag. 127 static Result<XmlParser> Create(const void* data, size_t size, bool copy_data = false); 128 tree_iteratorXmlParser129 inline iterator tree_iterator() const { 130 return iterator(*tree_); 131 } 132 get_stringsXmlParser133 inline const ResStringPool& get_strings() const { 134 return tree_->getStrings(); 135 } 136 137 private: 138 explicit XmlParser(std::unique_ptr<ResXMLTree> tree); 139 mutable std::unique_ptr<ResXMLTree> tree_; 140 }; 141 142 } // namespace android::idmap2 143 144 #endif // IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_ 145