blob: 60551901fe8df2bc1537a6df57924d8d31b7a29b [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 Lesinskid5083f62017-01-16 15:07:21 -080032using android::StringPiece;
33using android::StringPiece16;
34
Adam Lesinski75f3a552015-06-03 14:54:23 -070035namespace aapt {
36namespace xml {
37
38constexpr char kXmlNamespaceSep = 1;
39
40struct Stack {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041 std::unique_ptr<xml::Node> root;
42 std::stack<xml::Node*> node_stack;
43 std::string pending_comment;
Adam Lesinskiac6edc52017-03-02 19:31:28 -080044 std::unique_ptr<xml::Text> last_text_node;
45 util::StringBuilder pending_text;
Adam Lesinski75f3a552015-06-03 14:54:23 -070046};
47
48/**
49 * Extracts the namespace and name of an expanded element or attribute name.
50 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -070051static void SplitName(const char* name, std::string* out_ns,
52 std::string* out_name) {
53 const char* p = name;
54 while (*p != 0 && *p != kXmlNamespaceSep) {
55 p++;
56 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070057
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 if (*p == 0) {
59 out_ns->clear();
Adam Lesinskid5083f62017-01-16 15:07:21 -080060 out_name->assign(name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 } else {
Adam Lesinskid5083f62017-01-16 15:07:21 -080062 out_ns->assign(name, (p - name));
63 out_name->assign(p + 1);
Adam Lesinskice5e56e2016-10-21 17:56:45 -070064 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070065}
66
Adam Lesinskiac6edc52017-03-02 19:31:28 -080067static void FinishPendingText(Stack* stack) {
68 if (stack->last_text_node != nullptr) {
69 if (!stack->pending_text.IsEmpty()) {
70 stack->last_text_node->text = stack->pending_text.ToString();
71 stack->pending_text = {};
72 stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
73 } else {
74 // Drop an empty text node.
75 stack->last_text_node = nullptr;
76 }
77 }
78}
79
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080static void AddToStack(Stack* stack, XML_Parser parser,
81 std::unique_ptr<Node> node) {
82 node->line_number = XML_GetCurrentLineNumber(parser);
83 node->column_number = XML_GetCurrentColumnNumber(parser);
Adam Lesinski75f3a552015-06-03 14:54:23 -070084
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085 Node* this_node = node.get();
86 if (!stack->node_stack.empty()) {
Adam Lesinskie343eb12016-10-27 16:31:58 -070087 stack->node_stack.top()->AppendChild(std::move(node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -070088 } else {
89 stack->root = std::move(node);
90 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070091
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 if (!NodeCast<Text>(this_node)) {
93 stack->node_stack.push(this_node);
94 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070095}
96
Adam Lesinskice5e56e2016-10-21 17:56:45 -070097static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix,
98 const char* uri) {
99 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
100 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800101 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700102
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700103 std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
104 if (prefix) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800105 ns->namespace_prefix = prefix;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700106 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700107
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700108 if (uri) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800109 ns->namespace_uri = uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700111
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700112 AddToStack(stack, parser, std::move(ns));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700113}
114
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700115static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix) {
116 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
117 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800118 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700119
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700120 CHECK(!stack->node_stack.empty());
121 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700122}
123
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700124static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
125 return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
126 std::tie(rhs.namespace_uri, rhs.name, rhs.value);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700127}
128
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129static void XMLCALL StartElementHandler(void* user_data, const char* name,
130 const char** attrs) {
131 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
132 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800133 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700134
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700135 std::unique_ptr<Element> el = util::make_unique<Element>();
136 SplitName(name, &el->namespace_uri, &el->name);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700137
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700138 while (*attrs) {
139 Attribute attribute;
140 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800141 util::StringBuilder builder;
142 builder.Append(*attrs++);
143 attribute.value = builder.ToString();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700144
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700145 // Insert in sorted order.
146 auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(),
147 attribute, less_attribute);
148 el->attributes.insert(iter, std::move(attribute));
149 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700150
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700151 el->comment = std::move(stack->pending_comment);
152 AddToStack(stack, parser, std::move(el));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700153}
154
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700155static void XMLCALL EndElementHandler(void* user_data, const char* name) {
156 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
157 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800158 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700159
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700160 CHECK(!stack->node_stack.empty());
161 // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
162 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700163}
164
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800165static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700166 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
167 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700168
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800169 const StringPiece str(s, len);
170 if (str.empty()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700171 return;
172 }
173
174 // See if we can just append the text to a previous text node.
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800175 if (stack->last_text_node != nullptr) {
176 stack->pending_text.Append(str);
177 return;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700178 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700179
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800180 stack->last_text_node = util::make_unique<Text>();
181 stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
182 stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
183 stack->pending_text.Append(str);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700184}
185
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
187 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
188 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800189 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700190
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700191 if (!stack->pending_comment.empty()) {
192 stack->pending_comment += '\n';
193 }
194 stack->pending_comment += comment;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700195}
196
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700197std::unique_ptr<XmlResource> Inflate(std::istream* in, IDiagnostics* diag, const Source& source) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700198 Stack stack;
Adam Lesinski803c7c82016-04-06 16:09:43 -0700199
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700200 XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
201 XML_SetUserData(parser, &stack);
202 XML_UseParserAsHandlerArg(parser);
203 XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700204 XML_SetNamespaceDeclHandler(parser, StartNamespaceHandler, EndNamespaceHandler);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700205 XML_SetCharacterDataHandler(parser, CharacterDataHandler);
206 XML_SetCommentHandler(parser, CommentDataHandler);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700207
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700208 char buffer[1024];
209 while (!in->eof()) {
210 in->read(buffer, sizeof(buffer) / sizeof(buffer[0]));
211 if (in->bad() && !in->eof()) {
212 stack.root = {};
213 diag->Error(DiagMessage(source) << strerror(errno));
214 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700215 }
216
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700217 if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 stack.root = {};
219 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser)))
220 << XML_ErrorString(XML_GetErrorCode(parser)));
221 break;
222 }
223 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700224
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700225 XML_ParserFree(parser);
226 if (stack.root) {
Adam Lesinskiea134e02017-04-13 12:55:19 -0700227 return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
228 std::move(stack.root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 }
230 return {};
231}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700232
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700233static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700234 const size_t attr_count = parser->getAttributeCount();
235 if (attr_count > 0) {
236 el->attributes.reserve(attr_count);
237 for (size_t i = 0; i < attr_count; i++) {
238 Attribute attr;
239 size_t len;
240 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
241 if (str16) {
242 attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
243 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700244
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700245 str16 = parser->getAttributeName(i, &len);
246 if (str16) {
247 attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
248 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700249
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700250 str16 = parser->getAttributeStringValue(i, &len);
251 if (str16) {
252 attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
253 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700254
255 android::Res_value res_value;
256 if (parser->getAttributeValue(i, &res_value) > 0) {
257 attr.compiled_value = ResourceUtils::ParseBinaryResValue(
258 ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
259 }
260
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700261 el->attributes.push_back(std::move(attr));
262 }
263 }
264}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700265
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700266std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
267 const Source& source) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700268 // We import the android namespace because on Windows NO_ERROR is a macro, not
269 // an enum, which
270 // causes errors when qualifying it with android::
271 using namespace android;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700272
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700273 StringPool string_pool;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700274 std::unique_ptr<Node> root;
275 std::stack<Node*> node_stack;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700276
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700277 ResXMLTree tree;
278 if (tree.setTo(data, data_len) != NO_ERROR) {
279 return {};
280 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700281
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700282 ResXMLParser::event_code_t code;
283 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
284 code != ResXMLParser::END_DOCUMENT) {
285 std::unique_ptr<Node> new_node;
286 switch (code) {
287 case ResXMLParser::START_NAMESPACE: {
288 std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
289 size_t len;
290 const char16_t* str16 = tree.getNamespacePrefix(&len);
291 if (str16) {
292 node->namespace_prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700293 }
294
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700295 str16 = tree.getNamespaceUri(&len);
296 if (str16) {
297 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700298 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700299 new_node = std::move(node);
300 break;
301 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700302
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700303 case ResXMLParser::START_TAG: {
304 std::unique_ptr<Element> node = util::make_unique<Element>();
305 size_t len;
306 const char16_t* str16 = tree.getElementNamespace(&len);
307 if (str16) {
308 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinskica5638f2015-10-21 14:42:43 -0700309 }
Adam Lesinskica5638f2015-10-21 14:42:43 -0700310
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700311 str16 = tree.getElementName(&len);
312 if (str16) {
313 node->name = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700314 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700315
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700316 CopyAttributes(node.get(), &tree, &string_pool);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700317
318 new_node = std::move(node);
319 break;
320 }
321
322 case ResXMLParser::TEXT: {
323 std::unique_ptr<Text> node = util::make_unique<Text>();
324 size_t len;
325 const char16_t* str16 = tree.getText(&len);
326 if (str16) {
327 node->text = util::Utf16ToUtf8(StringPiece16(str16, len));
328 }
329 new_node = std::move(node);
330 break;
331 }
332
333 case ResXMLParser::END_NAMESPACE:
334 case ResXMLParser::END_TAG:
335 CHECK(!node_stack.empty());
336 node_stack.pop();
337 break;
338
339 default:
340 LOG(FATAL) << "unhandled XML chunk type";
341 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700342 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700343
344 if (new_node) {
345 new_node->line_number = tree.getLineNumber();
346
347 Node* this_node = new_node.get();
348 if (!root) {
349 CHECK(node_stack.empty()) << "node stack should be empty";
350 root = std::move(new_node);
351 } else {
352 CHECK(!node_stack.empty()) << "node stack should not be empty";
Adam Lesinskie343eb12016-10-27 16:31:58 -0700353 node_stack.top()->AppendChild(std::move(new_node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700354 }
355
356 if (!NodeCast<Text>(this_node)) {
357 node_stack.push(this_node);
358 }
359 }
360 }
Adam Lesinskiea134e02017-04-13 12:55:19 -0700361 return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700362}
363
364std::unique_ptr<Node> Namespace::Clone() {
365 auto ns = util::make_unique<Namespace>();
366 ns->comment = comment;
367 ns->line_number = line_number;
368 ns->column_number = column_number;
369 ns->namespace_prefix = namespace_prefix;
370 ns->namespace_uri = namespace_uri;
371
372 ns->children.reserve(children.size());
373 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskie343eb12016-10-27 16:31:58 -0700374 ns->AppendChild(child->Clone());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700375 }
376 return std::move(ns);
377}
378
379Element* FindRootElement(XmlResource* doc) {
380 return FindRootElement(doc->root.get());
381}
382
383Element* FindRootElement(Node* node) {
384 if (!node) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700385 return nullptr;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700386 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700387
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700388 Element* el = nullptr;
389 while ((el = NodeCast<Element>(node)) == nullptr) {
390 if (node->children.empty()) {
391 return nullptr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700392 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700393 // We are looking for the first element, and namespaces can only have one
394 // child.
395 node = node->children.front().get();
396 }
397 return el;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700398}
399
Adam Lesinskie343eb12016-10-27 16:31:58 -0700400void Node::AppendChild(std::unique_ptr<Node> child) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700401 child->parent = this;
402 children.push_back(std::move(child));
403}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700404
Adam Lesinskie343eb12016-10-27 16:31:58 -0700405void Node::InsertChild(size_t index, std::unique_ptr<Node> child) {
406 child->parent = this;
407 children.insert(children.begin() + index, std::move(child));
408}
409
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700410Attribute* Element::FindAttribute(const StringPiece& ns,
411 const StringPiece& name) {
412 for (auto& attr : attributes) {
413 if (ns == attr.namespace_uri && name == attr.name) {
414 return &attr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700415 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700416 }
417 return nullptr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700418}
419
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700420Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
421 return FindChildWithAttribute(ns, name, {}, {}, {});
422}
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700423
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700424Element* Element::FindChildWithAttribute(const StringPiece& ns,
425 const StringPiece& name,
426 const StringPiece& attr_ns,
427 const StringPiece& attr_name,
428 const StringPiece& attr_value) {
429 for (auto& child_node : children) {
430 Node* child = child_node.get();
431 while (NodeCast<Namespace>(child)) {
432 if (child->children.empty()) {
433 break;
434 }
435 child = child->children[0].get();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700436 }
437
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700438 if (Element* el = NodeCast<Element>(child)) {
439 if (ns == el->namespace_uri && name == el->name) {
440 if (attr_ns.empty() && attr_name.empty()) {
441 return el;
442 }
443
444 Attribute* attr = el->FindAttribute(attr_ns, attr_name);
445 if (attr && attr_value == attr->value) {
446 return el;
447 }
448 }
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700449 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700450 }
451 return nullptr;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700452}
453
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700454std::vector<Element*> Element::GetChildElements() {
455 std::vector<Element*> elements;
456 for (auto& child_node : children) {
457 Node* child = child_node.get();
458 while (NodeCast<Namespace>(child)) {
459 if (child->children.empty()) {
460 break;
461 }
462 child = child->children[0].get();
463 }
464
465 if (Element* el = NodeCast<Element>(child)) {
466 elements.push_back(el);
467 }
468 }
469 return elements;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700470}
471
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700472std::unique_ptr<Node> Element::Clone() {
473 auto el = util::make_unique<Element>();
474 el->comment = comment;
475 el->line_number = line_number;
476 el->column_number = column_number;
477 el->name = name;
478 el->namespace_uri = namespace_uri;
Adam Lesinski467f1712015-11-16 17:35:44 -0800479
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700480 el->attributes.reserve(attributes.size());
481 for (xml::Attribute& attr : attributes) {
482 // Don't copy compiled values or attributes.
483 el->attributes.push_back(
484 xml::Attribute{attr.namespace_uri, attr.name, attr.value});
485 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800486
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700487 el->children.reserve(children.size());
488 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskie343eb12016-10-27 16:31:58 -0700489 el->AppendChild(child->Clone());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700490 }
491 return std::move(el);
Adam Lesinski467f1712015-11-16 17:35:44 -0800492}
493
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700494std::unique_ptr<Node> Text::Clone() {
495 auto t = util::make_unique<Text>();
496 t->comment = comment;
497 t->line_number = line_number;
498 t->column_number = column_number;
499 t->text = text;
500 return std::move(t);
Adam Lesinski467f1712015-11-16 17:35:44 -0800501}
502
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700503void PackageAwareVisitor::Visit(Namespace* ns) {
504 bool added = false;
505 if (Maybe<ExtractedPackage> maybe_package =
506 ExtractPackageFromNamespace(ns->namespace_uri)) {
507 ExtractedPackage& package = maybe_package.value();
508 package_decls_.push_back(
509 PackageDecl{ns->namespace_prefix, std::move(package)});
510 added = true;
511 }
512
513 Visitor::Visit(ns);
514
515 if (added) {
516 package_decls_.pop_back();
517 }
518}
519
520Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
521 const StringPiece& alias, const StringPiece& local_package) const {
522 if (alias.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800523 return ExtractedPackage{local_package.to_string(), false /* private */};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700524 }
525
526 const auto rend = package_decls_.rend();
527 for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
528 if (alias == iter->prefix) {
529 if (iter->package.package.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800530 return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700531 }
532 return iter->package;
533 }
534 }
535 return {};
536}
537
538} // namespace xml
539} // namespace aapt