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 #include "idmap2/XmlParser.h"
18 
19 #include <iostream>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 
25 namespace android::idmap2 {
26 
27 template <typename T>
get_tree_position(const T & tree)28 ResXMLParser::ResXMLPosition get_tree_position(const T& tree) {
29   ResXMLParser::ResXMLPosition pos{};
30   tree.getPosition(&pos);
31   return pos;
32 }
33 
Node(const ResXMLTree & tree)34 XmlParser::Node::Node(const ResXMLTree& tree) : Node(tree, get_tree_position(tree)) {
35 }
Node(const ResXMLTree & tree,const ResXMLParser::ResXMLPosition & pos)36 XmlParser::Node::Node(const ResXMLTree& tree, const ResXMLParser::ResXMLPosition& pos)
37     : parser_(tree) {
38   set_position(pos);
39 }
40 
operator ==(const XmlParser::Node & rhs) const41 bool XmlParser::Node::operator==(const XmlParser::Node& rhs) const {
42   ResXMLParser::ResXMLPosition pos = get_position();
43   ResXMLParser::ResXMLPosition rhs_pos = rhs.get_position();
44   return pos.curExt == rhs_pos.curExt && pos.curNode == rhs_pos.curNode &&
45          pos.eventCode == rhs_pos.eventCode;
46 }
47 
operator !=(const XmlParser::Node & rhs) const48 bool XmlParser::Node::operator!=(const XmlParser::Node& rhs) const {
49   return !(*this == rhs);
50 }
51 
get_position() const52 ResXMLParser::ResXMLPosition XmlParser::Node::get_position() const {
53   return get_tree_position(parser_);
54 }
55 
set_position(const ResXMLParser::ResXMLPosition & pos)56 void XmlParser::Node::set_position(const ResXMLParser::ResXMLPosition& pos) {
57   parser_.setPosition(pos);
58 }
59 
Seek(bool inner_child)60 bool XmlParser::Node::Seek(bool inner_child) {
61   if (parser_.getEventType() == XmlParser::Event::END_TAG) {
62     return false;
63   }
64 
65   ssize_t depth = 0;
66   XmlParser::Event code;
67   while ((code = parser_.next()) != XmlParser::Event::BAD_DOCUMENT &&
68          code != XmlParser::Event::END_DOCUMENT) {
69     if (code == XmlParser::Event::START_TAG) {
70       if (++depth == (inner_child ? 1 : 0)) {
71         return true;
72       }
73     } else if (code == XmlParser::Event::END_TAG) {
74       if (--depth == (inner_child ? -1 : -2)) {
75         return false;
76       }
77     }
78   }
79 
80   return false;
81 }
82 
event() const83 XmlParser::Event XmlParser::Node::event() const {
84   return parser_.getEventType();
85 }
86 
name() const87 std::string XmlParser::Node::name() const {
88   size_t len;
89   const String16 key16(parser_.getElementName(&len));
90   return String8(key16).c_str();
91 }
92 
GetAttributeStringValue(const std::string & name) const93 Result<std::string> XmlParser::Node::GetAttributeStringValue(const std::string& name) const {
94   auto value = GetAttributeValue(name);
95   if (!value) {
96     return value.GetError();
97   }
98 
99   switch ((*value).dataType) {
100     case Res_value::TYPE_STRING: {
101       size_t len;
102       const String16 value16(parser_.getStrings().stringAt((*value).data, &len));
103       return std::string(String8(value16).c_str());
104     }
105     case Res_value::TYPE_INT_DEC:
106     case Res_value::TYPE_INT_HEX:
107     case Res_value::TYPE_INT_BOOLEAN: {
108       return std::to_string((*value).data);
109     }
110     default:
111       return Error(R"(Failed to convert attribute "%s" value to a string)", name.c_str());
112   }
113 }
114 
GetAttributeValue(const std::string & name) const115 Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
116   size_t len;
117   for (size_t i = 0; i < parser_.getAttributeCount(); i++) {
118     const String16 key16(parser_.getAttributeName(i, &len));
119     std::string key = String8(key16).c_str();
120     if (key != name) {
121       continue;
122     }
123 
124     Res_value res_value{};
125     if (parser_.getAttributeValue(i, &res_value) == BAD_TYPE) {
126       return Error(R"(Bad value for attribute "%s")", name.c_str());
127     }
128 
129     return res_value;
130   }
131 
132   return Error(R"(Failed to find attribute "%s")", name.c_str());
133 }
134 
Create(const void * data,size_t size,bool copy_data)135 Result<std::unique_ptr<const XmlParser>> XmlParser::Create(const void* data, size_t size,
136                                                            bool copy_data) {
137   auto parser = std::unique_ptr<const XmlParser>(new XmlParser());
138   if (parser->tree_.setTo(data, size, copy_data) != NO_ERROR) {
139     return Error("Malformed xml block");
140   }
141 
142   // Find the beginning of the first tag.
143   XmlParser::Event event;
144   while ((event = parser->tree_.next()) != XmlParser::Event::BAD_DOCUMENT &&
145          event != XmlParser::Event::END_DOCUMENT && event != XmlParser::Event::START_TAG) {
146   }
147 
148   if (event == XmlParser::Event::END_DOCUMENT) {
149     return Error("Root tag was not be found");
150   }
151 
152   if (event == XmlParser::Event::BAD_DOCUMENT) {
153     return Error("Bad xml document");
154   }
155 
156   return parser;
157 }
158 
~XmlParser()159 XmlParser::~XmlParser() {
160   tree_.uninit();
161 }
162 
163 }  // namespace android::idmap2
164