blob: fddb6b8c5d87805e41794facb2a3e955eba7a092 [file] [log] [blame]
Adam Lesinski75f3a552015-06-03 14:54:23 -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
Adam Lesinski75f3a552015-06-03 14:54:23 -070017#include "XmlDom.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018
19#include <expat.h>
Adam Lesinski75f3a552015-06-03 14:54:23 -070020
Adam Lesinski75f3a552015-06-03 14:54:23 -070021#include <memory>
22#include <stack>
23#include <string>
24#include <tuple>
25
Adam Lesinskice5e56e2016-10-21 17:56:45 -070026#include "android-base/logging.h"
27
Adam Lesinskid0f492d2017-04-03 18:12:45 -070028#include "ResourceUtils.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070029#include "XmlPullParser.h"
30#include "util/Util.h"
31
Adam Lesinskiefeb7af2017-08-02 14:57:43 -070032using ::aapt::io::InputStream;
33using ::android::StringPiece;
34using ::android::StringPiece16;
Adam Lesinskid5083f62017-01-16 15:07:21 -080035
Adam Lesinski75f3a552015-06-03 14:54:23 -070036namespace aapt {
37namespace xml {
38
39constexpr char kXmlNamespaceSep = 1;
40
41struct Stack {
Adam Lesinski6b372992017-08-09 10:54:23 -070042 std::unique_ptr<xml::Element> root;
43 std::stack<xml::Element*> node_stack;
44 std::unique_ptr<xml::Element> pending_element;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070045 std::string pending_comment;
Adam Lesinskiac6edc52017-03-02 19:31:28 -080046 std::unique_ptr<xml::Text> last_text_node;
Adam Lesinski75f3a552015-06-03 14:54:23 -070047};
48
Adam Lesinski6b372992017-08-09 10:54:23 -070049// Extracts the namespace and name of an expanded element or attribute name.
50static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070051 const char* p = name;
52 while (*p != 0 && *p != kXmlNamespaceSep) {
53 p++;
54 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070055
Adam Lesinskice5e56e2016-10-21 17:56:45 -070056 if (*p == 0) {
57 out_ns->clear();
Adam Lesinskid5083f62017-01-16 15:07:21 -080058 out_name->assign(name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -070059 } else {
Adam Lesinskid5083f62017-01-16 15:07:21 -080060 out_ns->assign(name, (p - name));
61 out_name->assign(p + 1);
Adam Lesinskice5e56e2016-10-21 17:56:45 -070062 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070063}
64
Adam Lesinskiac6edc52017-03-02 19:31:28 -080065static void FinishPendingText(Stack* stack) {
66 if (stack->last_text_node != nullptr) {
Adam Lesinski48448e82017-04-26 15:13:52 -070067 if (!stack->last_text_node->text.empty()) {
Adam Lesinski6b372992017-08-09 10:54:23 -070068 CHECK(!stack->node_stack.empty());
Adam Lesinskiac6edc52017-03-02 19:31:28 -080069 stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
70 } else {
71 // Drop an empty text node.
Adam Lesinskiac6edc52017-03-02 19:31:28 -080072 }
Adam Lesinski48448e82017-04-26 15:13:52 -070073 stack->last_text_node = nullptr;
Adam Lesinskiac6edc52017-03-02 19:31:28 -080074 }
75}
76
Adam Lesinski6b372992017-08-09 10:54:23 -070077static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix, const char* uri) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
79 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -080080 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -070081
Adam Lesinski6b372992017-08-09 10:54:23 -070082 NamespaceDecl decl;
83 decl.line_number = XML_GetCurrentLineNumber(parser);
84 decl.column_number = XML_GetCurrentColumnNumber(parser);
85 decl.prefix = prefix ? prefix : "";
86 decl.uri = uri ? uri : "";
Adam Lesinski75f3a552015-06-03 14:54:23 -070087
Adam Lesinski6b372992017-08-09 10:54:23 -070088 if (stack->pending_element == nullptr) {
89 stack->pending_element = util::make_unique<Element>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 }
Adam Lesinski6b372992017-08-09 10:54:23 -070091 stack->pending_element->namespace_decls.push_back(std::move(decl));
Adam Lesinski75f3a552015-06-03 14:54:23 -070092}
93
Adam Lesinski6b372992017-08-09 10:54:23 -070094static void XMLCALL EndNamespaceHandler(void* user_data, const char* /*prefix*/) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
96 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -080097 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -070098}
99
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
101 return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
102 std::tie(rhs.namespace_uri, rhs.name, rhs.value);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700103}
104
Adam Lesinski6b372992017-08-09 10:54:23 -0700105static void XMLCALL StartElementHandler(void* user_data, const char* name, const char** attrs) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700106 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
107 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800108 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700109
Adam Lesinski6b372992017-08-09 10:54:23 -0700110 std::unique_ptr<Element> el;
111 if (stack->pending_element != nullptr) {
112 el = std::move(stack->pending_element);
113 } else {
114 el = util::make_unique<Element>();
115 }
116
117 el->line_number = XML_GetCurrentLineNumber(parser);
118 el->column_number = XML_GetCurrentColumnNumber(parser);
119 el->comment = std::move(stack->pending_comment);
120
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700121 SplitName(name, &el->namespace_uri, &el->name);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700122
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700123 while (*attrs) {
124 Attribute attribute;
125 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
Adam Lesinski48448e82017-04-26 15:13:52 -0700126 attribute.value = *attrs++;
Adam Lesinski6b372992017-08-09 10:54:23 -0700127 el->attributes.push_back(std::move(attribute));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700129
Adam Lesinski6b372992017-08-09 10:54:23 -0700130 // Sort the attributes.
131 std::sort(el->attributes.begin(), el->attributes.end(), less_attribute);
132
133 // Add to the stack.
134 Element* this_el = el.get();
135 if (!stack->node_stack.empty()) {
136 stack->node_stack.top()->AppendChild(std::move(el));
137 } else {
138 stack->root = std::move(el);
139 }
140 stack->node_stack.push(this_el);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700141}
142
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700143static void XMLCALL EndElementHandler(void* user_data, const char* name) {
144 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
145 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800146 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700147
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700148 CHECK(!stack->node_stack.empty());
149 // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
150 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700151}
152
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800153static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
155 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700156
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800157 const StringPiece str(s, len);
158 if (str.empty()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159 return;
160 }
161
162 // See if we can just append the text to a previous text node.
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800163 if (stack->last_text_node != nullptr) {
Adam Lesinski48448e82017-04-26 15:13:52 -0700164 stack->last_text_node->text.append(str.data(), str.size());
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800165 return;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700166 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700167
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800168 stack->last_text_node = util::make_unique<Text>();
169 stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
170 stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
Adam Lesinski48448e82017-04-26 15:13:52 -0700171 stack->last_text_node->text = str.to_string();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700172}
173
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
175 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
176 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800177 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700178
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 if (!stack->pending_comment.empty()) {
180 stack->pending_comment += '\n';
181 }
182 stack->pending_comment += comment;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700183}
184
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700185std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186 Stack stack;
Adam Lesinski803c7c82016-04-06 16:09:43 -0700187
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700188 std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
189 XML_ParserCreateNS(nullptr, kXmlNamespaceSep), XML_ParserFree};
190 XML_SetUserData(parser.get(), &stack);
191 XML_UseParserAsHandlerArg(parser.get());
192 XML_SetElementHandler(parser.get(), StartElementHandler, EndElementHandler);
193 XML_SetNamespaceDeclHandler(parser.get(), StartNamespaceHandler, EndNamespaceHandler);
194 XML_SetCharacterDataHandler(parser.get(), CharacterDataHandler);
195 XML_SetCommentHandler(parser.get(), CommentDataHandler);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700196
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700197 const char* buffer = nullptr;
198 size_t buffer_size = 0;
199 while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
200 if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
201 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
202 << XML_ErrorString(XML_GetErrorCode(parser.get())));
203 return {};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700204 }
205 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700206
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700207 if (in->HadError()) {
208 diag->Error(DiagMessage(source) << in->GetError());
209 return {};
210 } else {
211 // Finish off the parsing.
212 if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
213 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
214 << XML_ErrorString(XML_GetErrorCode(parser.get())));
215 return {};
216 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217 }
Adam Lesinski00451162017-10-03 07:44:08 -0700218 return util::make_unique<XmlResource>(ResourceFile{{}, {}, ResourceFile::Type::kUnknown, source},
219 StringPool{}, std::move(stack.root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700221
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700222static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700223 const size_t attr_count = parser->getAttributeCount();
224 if (attr_count > 0) {
225 el->attributes.reserve(attr_count);
226 for (size_t i = 0; i < attr_count; i++) {
227 Attribute attr;
228 size_t len;
229 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
230 if (str16) {
231 attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
232 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700233
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700234 str16 = parser->getAttributeName(i, &len);
235 if (str16) {
236 attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
237 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700238
Shane Farmer4b8ca8b2017-09-08 12:17:05 -0700239 uint32_t res_id = parser->getAttributeNameResID(i);
240 if (res_id > 0) {
241 attr.compiled_attribute = AaptAttribute(::aapt::Attribute(), {res_id});
242 }
243
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700244 str16 = parser->getAttributeStringValue(i, &len);
245 if (str16) {
246 attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
Shane Farmer4b8ca8b2017-09-08 12:17:05 -0700247 } else {
248 android::Res_value res_value;
249 if (parser->getAttributeValue(i, &res_value) > 0) {
250 attr.compiled_value = ResourceUtils::ParseBinaryResValue(
251 ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
252 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700253 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700254
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700255
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700256 el->attributes.push_back(std::move(attr));
257 }
258 }
259}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700260
Adam Lesinski8780eb62017-10-31 17:44:39 -0700261std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string* out_error) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700262 // We import the android namespace because on Windows NO_ERROR is a macro, not
Adam Lesinski6b372992017-08-09 10:54:23 -0700263 // an enum, which causes errors when qualifying it with android::
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700264 using namespace android;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700265
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700266 StringPool string_pool;
Adam Lesinski6b372992017-08-09 10:54:23 -0700267 std::unique_ptr<Element> root;
268 std::stack<Element*> node_stack;
269 std::unique_ptr<Element> pending_element;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700270
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 ResXMLTree tree;
Adam Lesinski8780eb62017-10-31 17:44:39 -0700272 if (tree.setTo(data, len) != NO_ERROR) {
273 if (out_error != nullptr) {
274 *out_error = "failed to initialize ResXMLTree";
275 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700276 return {};
277 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700278
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700279 ResXMLParser::event_code_t code;
Adam Lesinski6b372992017-08-09 10:54:23 -0700280 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT && code != ResXMLParser::END_DOCUMENT) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700281 std::unique_ptr<Node> new_node;
282 switch (code) {
283 case ResXMLParser::START_NAMESPACE: {
Adam Lesinski6b372992017-08-09 10:54:23 -0700284 NamespaceDecl decl;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700285 decl.line_number = tree.getLineNumber();
286
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700287 size_t len;
288 const char16_t* str16 = tree.getNamespacePrefix(&len);
289 if (str16) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700290 decl.prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700291 }
292
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700293 str16 = tree.getNamespaceUri(&len);
294 if (str16) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700295 decl.uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700296 }
Adam Lesinski6b372992017-08-09 10:54:23 -0700297
298 if (pending_element == nullptr) {
299 pending_element = util::make_unique<Element>();
300 }
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700301 pending_element->namespace_decls.push_back(std::move(decl));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700302 break;
303 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700304
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700305 case ResXMLParser::START_TAG: {
Adam Lesinski6b372992017-08-09 10:54:23 -0700306 std::unique_ptr<Element> el;
307 if (pending_element != nullptr) {
308 el = std::move(pending_element);
309 } else {
310 el = util::make_unique<Element>();
Adam Lesinski6b372992017-08-09 10:54:23 -0700311 }
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700312 el->line_number = tree.getLineNumber();
Adam Lesinski6b372992017-08-09 10:54:23 -0700313
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700314 size_t len;
315 const char16_t* str16 = tree.getElementNamespace(&len);
316 if (str16) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700317 el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinskica5638f2015-10-21 14:42:43 -0700318 }
Adam Lesinskica5638f2015-10-21 14:42:43 -0700319
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700320 str16 = tree.getElementName(&len);
321 if (str16) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700322 el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700323 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700324
Adam Lesinski6b372992017-08-09 10:54:23 -0700325 Element* this_el = el.get();
326 CopyAttributes(el.get(), &tree, &string_pool);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700327
Adam Lesinski6b372992017-08-09 10:54:23 -0700328 if (!node_stack.empty()) {
329 node_stack.top()->AppendChild(std::move(el));
330 } else {
331 root = std::move(el);
332 }
333 node_stack.push(this_el);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700334 break;
335 }
336
337 case ResXMLParser::TEXT: {
Adam Lesinski6b372992017-08-09 10:54:23 -0700338 std::unique_ptr<Text> text = util::make_unique<Text>();
339 text->line_number = tree.getLineNumber();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700340 size_t len;
341 const char16_t* str16 = tree.getText(&len);
342 if (str16) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700343 text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700344 }
Adam Lesinski6b372992017-08-09 10:54:23 -0700345 CHECK(!node_stack.empty());
346 node_stack.top()->AppendChild(std::move(text));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700347 break;
348 }
349
350 case ResXMLParser::END_NAMESPACE:
Adam Lesinski6b372992017-08-09 10:54:23 -0700351 break;
352
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700353 case ResXMLParser::END_TAG:
354 CHECK(!node_stack.empty());
355 node_stack.pop();
356 break;
357
358 default:
359 LOG(FATAL) << "unhandled XML chunk type";
360 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700361 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700362 }
Adam Lesinskiea134e02017-04-13 12:55:19 -0700363 return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700364}
365
Adam Lesinski8780eb62017-10-31 17:44:39 -0700366std::unique_ptr<XmlResource> XmlResource::Clone() const {
367 std::unique_ptr<XmlResource> cloned = util::make_unique<XmlResource>(file);
368 if (root != nullptr) {
369 cloned->root = root->CloneElement([&](const xml::Element& src, xml::Element* dst) {
370 dst->attributes.reserve(src.attributes.size());
371 for (const xml::Attribute& attr : src.attributes) {
372 xml::Attribute cloned_attr;
373 cloned_attr.name = attr.name;
374 cloned_attr.namespace_uri = attr.namespace_uri;
375 cloned_attr.value = attr.value;
376 cloned_attr.compiled_attribute = attr.compiled_attribute;
377 if (attr.compiled_value != nullptr) {
378 cloned_attr.compiled_value.reset(attr.compiled_value->Clone(&cloned->string_pool));
379 }
380 dst->attributes.push_back(std::move(cloned_attr));
381 }
382 });
383 }
384 return cloned;
385}
386
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700387Element* FindRootElement(Node* node) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700388 if (node == nullptr) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700389 return nullptr;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700390 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700391
Adam Lesinski6b372992017-08-09 10:54:23 -0700392 while (node->parent != nullptr) {
393 node = node->parent;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700394 }
Adam Lesinski6b372992017-08-09 10:54:23 -0700395 return NodeCast<Element>(node);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700396}
397
Adam Lesinski6b372992017-08-09 10:54:23 -0700398void Element::AppendChild(std::unique_ptr<Node> child) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700399 child->parent = this;
400 children.push_back(std::move(child));
401}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700402
Adam Lesinski6b372992017-08-09 10:54:23 -0700403void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
Adam Lesinskie343eb12016-10-27 16:31:58 -0700404 child->parent = this;
405 children.insert(children.begin() + index, std::move(child));
406}
407
Adam Lesinski6b372992017-08-09 10:54:23 -0700408Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700409 return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700410}
411
Adam Lesinskic744ae82017-05-17 19:28:38 -0700412const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
413 for (const auto& attr : attributes) {
414 if (ns == attr.namespace_uri && name == attr.name) {
415 return &attr;
416 }
417 }
418 return nullptr;
419}
420
Adam Lesinskic6284372017-12-04 13:46:23 -0800421Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
422 Attribute* attr = FindAttribute(ns, name);
423 if (attr == nullptr) {
424 attributes.push_back(Attribute{ns.to_string(), name.to_string()});
425 attr = &attributes.back();
426 }
427 return attr;
428}
429
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700430Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
431 return FindChildWithAttribute(ns, name, {}, {}, {});
432}
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700433
Adam Lesinski8780eb62017-10-31 17:44:39 -0700434const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
435 return FindChildWithAttribute(ns, name, {}, {}, {});
436}
437
Adam Lesinski6b372992017-08-09 10:54:23 -0700438Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
439 const StringPiece& attr_ns, const StringPiece& attr_name,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700440 const StringPiece& attr_value) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700441 return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
442 ns, name, attr_ns, attr_name, attr_value));
443}
444
445const Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
446 const StringPiece& attr_ns,
447 const StringPiece& attr_name,
448 const StringPiece& attr_value) const {
449 for (const auto& child : children) {
450 if (const Element* el = NodeCast<Element>(child.get())) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700451 if (ns == el->namespace_uri && name == el->name) {
452 if (attr_ns.empty() && attr_name.empty()) {
453 return el;
454 }
455
Adam Lesinski8780eb62017-10-31 17:44:39 -0700456 const Attribute* attr = el->FindAttribute(attr_ns, attr_name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700457 if (attr && attr_value == attr->value) {
458 return el;
459 }
460 }
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700461 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700462 }
463 return nullptr;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700464}
465
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700466std::vector<Element*> Element::GetChildElements() {
467 std::vector<Element*> elements;
468 for (auto& child_node : children) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700469 if (Element* child = NodeCast<Element>(child_node.get())) {
470 elements.push_back(child);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700471 }
472 }
473 return elements;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700474}
475
Adam Lesinski6b372992017-08-09 10:54:23 -0700476std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700477 auto el = util::make_unique<Element>();
Adam Lesinski6b372992017-08-09 10:54:23 -0700478 el->namespace_decls = namespace_decls;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700479 el->comment = comment;
480 el->line_number = line_number;
481 el->column_number = column_number;
482 el->name = name;
483 el->namespace_uri = namespace_uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700484 el->attributes.reserve(attributes.size());
Adam Lesinskic744ae82017-05-17 19:28:38 -0700485 el_cloner(*this, el.get());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700486 el->children.reserve(children.size());
487 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskic744ae82017-05-17 19:28:38 -0700488 el->AppendChild(child->Clone(el_cloner));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700489 }
490 return std::move(el);
Adam Lesinski467f1712015-11-16 17:35:44 -0800491}
492
Adam Lesinski6b372992017-08-09 10:54:23 -0700493std::unique_ptr<Element> Element::CloneElement(const ElementCloneFunc& el_cloner) const {
494 return std::unique_ptr<Element>(static_cast<Element*>(Clone(el_cloner).release()));
495}
496
497void Element::Accept(Visitor* visitor) {
498 visitor->BeforeVisitElement(this);
499 visitor->Visit(this);
500 visitor->AfterVisitElement(this);
501}
502
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700503void Element::Accept(ConstVisitor* visitor) const {
504 visitor->BeforeVisitElement(this);
505 visitor->Visit(this);
506 visitor->AfterVisitElement(this);
507}
508
Adam Lesinski6b372992017-08-09 10:54:23 -0700509std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700510 auto t = util::make_unique<Text>();
511 t->comment = comment;
512 t->line_number = line_number;
513 t->column_number = column_number;
514 t->text = text;
515 return std::move(t);
Adam Lesinski467f1712015-11-16 17:35:44 -0800516}
517
Adam Lesinski6b372992017-08-09 10:54:23 -0700518void Text::Accept(Visitor* visitor) {
519 visitor->Visit(this);
520}
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700521
Adam Lesinskid3ffa8442017-09-28 13:34:35 -0700522void Text::Accept(ConstVisitor* visitor) const {
523 visitor->Visit(this);
524}
525
Adam Lesinski6b372992017-08-09 10:54:23 -0700526void PackageAwareVisitor::BeforeVisitElement(Element* el) {
527 std::vector<PackageDecl> decls;
528 for (const NamespaceDecl& decl : el->namespace_decls) {
529 if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
530 decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())});
531 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700532 }
Adam Lesinski6b372992017-08-09 10:54:23 -0700533 package_decls_.push_back(std::move(decls));
534}
535
536void PackageAwareVisitor::AfterVisitElement(Element* el) {
537 package_decls_.pop_back();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700538}
539
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700540Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(const StringPiece& alias) const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700541 if (alias.empty()) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700542 return ExtractedPackage{{}, false /*private*/};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700543 }
544
545 const auto rend = package_decls_.rend();
546 for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700547 const std::vector<PackageDecl>& decls = *iter;
548 const auto rend2 = decls.rend();
549 for (auto iter2 = decls.rbegin(); iter2 != rend2; ++iter2) {
550 const PackageDecl& decl = *iter2;
551 if (alias == decl.prefix) {
552 if (decl.package.package.empty()) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700553 return ExtractedPackage{{}, decl.package.private_namespace};
Adam Lesinski6b372992017-08-09 10:54:23 -0700554 }
555 return decl.package;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700556 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700557 }
558 }
559 return {};
560}
561
562} // namespace xml
563} // namespace aapt