blob: d9ea1bcf37665bc903d802a20bc0745eaefa5630 [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
28#include "XmlPullParser.h"
29#include "util/Util.h"
30
Adam Lesinskid5083f62017-01-16 15:07:21 -080031using android::StringPiece;
32using android::StringPiece16;
33
Adam Lesinski75f3a552015-06-03 14:54:23 -070034namespace aapt {
35namespace xml {
36
37constexpr char kXmlNamespaceSep = 1;
38
39struct Stack {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070040 std::unique_ptr<xml::Node> root;
41 std::stack<xml::Node*> node_stack;
42 std::string pending_comment;
Adam Lesinskiac6edc52017-03-02 19:31:28 -080043 std::unique_ptr<xml::Text> last_text_node;
44 util::StringBuilder pending_text;
Adam Lesinski75f3a552015-06-03 14:54:23 -070045};
46
47/**
48 * Extracts the namespace and name of an expanded element or attribute name.
49 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -070050static void SplitName(const char* name, std::string* out_ns,
51 std::string* out_name) {
52 const char* p = name;
53 while (*p != 0 && *p != kXmlNamespaceSep) {
54 p++;
55 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070056
Adam Lesinskice5e56e2016-10-21 17:56:45 -070057 if (*p == 0) {
58 out_ns->clear();
Adam Lesinskid5083f62017-01-16 15:07:21 -080059 out_name->assign(name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -070060 } else {
Adam Lesinskid5083f62017-01-16 15:07:21 -080061 out_ns->assign(name, (p - name));
62 out_name->assign(p + 1);
Adam Lesinskice5e56e2016-10-21 17:56:45 -070063 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070064}
65
Adam Lesinskiac6edc52017-03-02 19:31:28 -080066static void FinishPendingText(Stack* stack) {
67 if (stack->last_text_node != nullptr) {
68 if (!stack->pending_text.IsEmpty()) {
69 stack->last_text_node->text = stack->pending_text.ToString();
70 stack->pending_text = {};
71 stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
72 } else {
73 // Drop an empty text node.
74 stack->last_text_node = nullptr;
75 }
76 }
77}
78
Adam Lesinskice5e56e2016-10-21 17:56:45 -070079static void AddToStack(Stack* stack, XML_Parser parser,
80 std::unique_ptr<Node> node) {
81 node->line_number = XML_GetCurrentLineNumber(parser);
82 node->column_number = XML_GetCurrentColumnNumber(parser);
Adam Lesinski75f3a552015-06-03 14:54:23 -070083
Adam Lesinskice5e56e2016-10-21 17:56:45 -070084 Node* this_node = node.get();
85 if (!stack->node_stack.empty()) {
Adam Lesinskie343eb12016-10-27 16:31:58 -070086 stack->node_stack.top()->AppendChild(std::move(node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -070087 } else {
88 stack->root = std::move(node);
89 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070090
Adam Lesinskice5e56e2016-10-21 17:56:45 -070091 if (!NodeCast<Text>(this_node)) {
92 stack->node_stack.push(this_node);
93 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070094}
95
Adam Lesinskice5e56e2016-10-21 17:56:45 -070096static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix,
97 const char* uri) {
98 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
99 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800100 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700101
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700102 std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
103 if (prefix) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800104 ns->namespace_prefix = prefix;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700105 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700106
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107 if (uri) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800108 ns->namespace_uri = uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700109 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700110
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700111 AddToStack(stack, parser, std::move(ns));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700112}
113
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700114static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix) {
115 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
116 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800117 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700118
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700119 CHECK(!stack->node_stack.empty());
120 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700121}
122
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700123static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
124 return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
125 std::tie(rhs.namespace_uri, rhs.name, rhs.value);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700126}
127
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128static void XMLCALL StartElementHandler(void* user_data, const char* name,
129 const char** attrs) {
130 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
131 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800132 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700133
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700134 std::unique_ptr<Element> el = util::make_unique<Element>();
135 SplitName(name, &el->namespace_uri, &el->name);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700136
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700137 while (*attrs) {
138 Attribute attribute;
139 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800140 util::StringBuilder builder;
141 builder.Append(*attrs++);
142 attribute.value = builder.ToString();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700143
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700144 // Insert in sorted order.
145 auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(),
146 attribute, less_attribute);
147 el->attributes.insert(iter, std::move(attribute));
148 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700149
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700150 el->comment = std::move(stack->pending_comment);
151 AddToStack(stack, parser, std::move(el));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700152}
153
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154static void XMLCALL EndElementHandler(void* user_data, const char* name) {
155 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
156 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800157 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700158
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159 CHECK(!stack->node_stack.empty());
160 // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
161 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700162}
163
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800164static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700165 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
166 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700167
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800168 const StringPiece str(s, len);
169 if (str.empty()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700170 return;
171 }
172
173 // See if we can just append the text to a previous text node.
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800174 if (stack->last_text_node != nullptr) {
175 stack->pending_text.Append(str);
176 return;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700178
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800179 stack->last_text_node = util::make_unique<Text>();
180 stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
181 stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
182 stack->pending_text.Append(str);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700183}
184
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700185static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
186 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
187 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800188 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700189
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700190 if (!stack->pending_comment.empty()) {
191 stack->pending_comment += '\n';
192 }
193 stack->pending_comment += comment;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700194}
195
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700196std::unique_ptr<XmlResource> Inflate(std::istream* in, IDiagnostics* diag,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700197 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);
204 XML_SetNamespaceDeclHandler(parser, StartNamespaceHandler,
205 EndNamespaceHandler);
206 XML_SetCharacterDataHandler(parser, CharacterDataHandler);
207 XML_SetCommentHandler(parser, CommentDataHandler);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700208
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700209 char buffer[1024];
210 while (!in->eof()) {
211 in->read(buffer, sizeof(buffer) / sizeof(buffer[0]));
212 if (in->bad() && !in->eof()) {
213 stack.root = {};
214 diag->Error(DiagMessage(source) << strerror(errno));
215 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700216 }
217
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 if (XML_Parse(parser, buffer, in->gcount(), in->eof()) ==
219 XML_STATUS_ERROR) {
220 stack.root = {};
221 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser)))
222 << XML_ErrorString(XML_GetErrorCode(parser)));
223 break;
224 }
225 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700226
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700227 XML_ParserFree(parser);
228 if (stack.root) {
229 return util::make_unique<XmlResource>(ResourceFile{{}, {}, source},
230 std::move(stack.root));
231 }
232 return {};
233}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700234
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235static void CopyAttributes(Element* el, android::ResXMLParser* parser) {
236 const size_t attr_count = parser->getAttributeCount();
237 if (attr_count > 0) {
238 el->attributes.reserve(attr_count);
239 for (size_t i = 0; i < attr_count; i++) {
240 Attribute attr;
241 size_t len;
242 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
243 if (str16) {
244 attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
245 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700246
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 str16 = parser->getAttributeName(i, &len);
248 if (str16) {
249 attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
250 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700251
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700252 str16 = parser->getAttributeStringValue(i, &len);
253 if (str16) {
254 attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
255 }
256 el->attributes.push_back(std::move(attr));
257 }
258 }
259}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700260
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700261std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len,
262 IDiagnostics* diag, const Source& source) {
263 // We import the android namespace because on Windows NO_ERROR is a macro, not
264 // an enum, which
265 // causes errors when qualifying it with android::
266 using namespace android;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700267
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700268 std::unique_ptr<Node> root;
269 std::stack<Node*> node_stack;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700270
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 ResXMLTree tree;
272 if (tree.setTo(data, data_len) != NO_ERROR) {
273 return {};
274 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700275
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700276 ResXMLParser::event_code_t code;
277 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
278 code != ResXMLParser::END_DOCUMENT) {
279 std::unique_ptr<Node> new_node;
280 switch (code) {
281 case ResXMLParser::START_NAMESPACE: {
282 std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
283 size_t len;
284 const char16_t* str16 = tree.getNamespacePrefix(&len);
285 if (str16) {
286 node->namespace_prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700287 }
288
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700289 str16 = tree.getNamespaceUri(&len);
290 if (str16) {
291 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700292 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700293 new_node = std::move(node);
294 break;
295 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700296
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700297 case ResXMLParser::START_TAG: {
298 std::unique_ptr<Element> node = util::make_unique<Element>();
299 size_t len;
300 const char16_t* str16 = tree.getElementNamespace(&len);
301 if (str16) {
302 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinskica5638f2015-10-21 14:42:43 -0700303 }
Adam Lesinskica5638f2015-10-21 14:42:43 -0700304
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700305 str16 = tree.getElementName(&len);
306 if (str16) {
307 node->name = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700308 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700309
310 CopyAttributes(node.get(), &tree);
311
312 new_node = std::move(node);
313 break;
314 }
315
316 case ResXMLParser::TEXT: {
317 std::unique_ptr<Text> node = util::make_unique<Text>();
318 size_t len;
319 const char16_t* str16 = tree.getText(&len);
320 if (str16) {
321 node->text = util::Utf16ToUtf8(StringPiece16(str16, len));
322 }
323 new_node = std::move(node);
324 break;
325 }
326
327 case ResXMLParser::END_NAMESPACE:
328 case ResXMLParser::END_TAG:
329 CHECK(!node_stack.empty());
330 node_stack.pop();
331 break;
332
333 default:
334 LOG(FATAL) << "unhandled XML chunk type";
335 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700336 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700337
338 if (new_node) {
339 new_node->line_number = tree.getLineNumber();
340
341 Node* this_node = new_node.get();
342 if (!root) {
343 CHECK(node_stack.empty()) << "node stack should be empty";
344 root = std::move(new_node);
345 } else {
346 CHECK(!node_stack.empty()) << "node stack should not be empty";
Adam Lesinskie343eb12016-10-27 16:31:58 -0700347 node_stack.top()->AppendChild(std::move(new_node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700348 }
349
350 if (!NodeCast<Text>(this_node)) {
351 node_stack.push(this_node);
352 }
353 }
354 }
355 return util::make_unique<XmlResource>(ResourceFile{}, std::move(root));
356}
357
358std::unique_ptr<Node> Namespace::Clone() {
359 auto ns = util::make_unique<Namespace>();
360 ns->comment = comment;
361 ns->line_number = line_number;
362 ns->column_number = column_number;
363 ns->namespace_prefix = namespace_prefix;
364 ns->namespace_uri = namespace_uri;
365
366 ns->children.reserve(children.size());
367 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskie343eb12016-10-27 16:31:58 -0700368 ns->AppendChild(child->Clone());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700369 }
370 return std::move(ns);
371}
372
373Element* FindRootElement(XmlResource* doc) {
374 return FindRootElement(doc->root.get());
375}
376
377Element* FindRootElement(Node* node) {
378 if (!node) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700379 return nullptr;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700380 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700381
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700382 Element* el = nullptr;
383 while ((el = NodeCast<Element>(node)) == nullptr) {
384 if (node->children.empty()) {
385 return nullptr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700386 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700387 // We are looking for the first element, and namespaces can only have one
388 // child.
389 node = node->children.front().get();
390 }
391 return el;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700392}
393
Adam Lesinskie343eb12016-10-27 16:31:58 -0700394void Node::AppendChild(std::unique_ptr<Node> child) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700395 child->parent = this;
396 children.push_back(std::move(child));
397}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700398
Adam Lesinskie343eb12016-10-27 16:31:58 -0700399void Node::InsertChild(size_t index, std::unique_ptr<Node> child) {
400 child->parent = this;
401 children.insert(children.begin() + index, std::move(child));
402}
403
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700404Attribute* Element::FindAttribute(const StringPiece& ns,
405 const StringPiece& name) {
406 for (auto& attr : attributes) {
407 if (ns == attr.namespace_uri && name == attr.name) {
408 return &attr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700409 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700410 }
411 return nullptr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700412}
413
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700414Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
415 return FindChildWithAttribute(ns, name, {}, {}, {});
416}
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700417
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700418Element* Element::FindChildWithAttribute(const StringPiece& ns,
419 const StringPiece& name,
420 const StringPiece& attr_ns,
421 const StringPiece& attr_name,
422 const StringPiece& attr_value) {
423 for (auto& child_node : children) {
424 Node* child = child_node.get();
425 while (NodeCast<Namespace>(child)) {
426 if (child->children.empty()) {
427 break;
428 }
429 child = child->children[0].get();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700430 }
431
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700432 if (Element* el = NodeCast<Element>(child)) {
433 if (ns == el->namespace_uri && name == el->name) {
434 if (attr_ns.empty() && attr_name.empty()) {
435 return el;
436 }
437
438 Attribute* attr = el->FindAttribute(attr_ns, attr_name);
439 if (attr && attr_value == attr->value) {
440 return el;
441 }
442 }
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700443 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700444 }
445 return nullptr;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700446}
447
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700448std::vector<Element*> Element::GetChildElements() {
449 std::vector<Element*> elements;
450 for (auto& child_node : children) {
451 Node* child = child_node.get();
452 while (NodeCast<Namespace>(child)) {
453 if (child->children.empty()) {
454 break;
455 }
456 child = child->children[0].get();
457 }
458
459 if (Element* el = NodeCast<Element>(child)) {
460 elements.push_back(el);
461 }
462 }
463 return elements;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700464}
465
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700466std::unique_ptr<Node> Element::Clone() {
467 auto el = util::make_unique<Element>();
468 el->comment = comment;
469 el->line_number = line_number;
470 el->column_number = column_number;
471 el->name = name;
472 el->namespace_uri = namespace_uri;
Adam Lesinski467f1712015-11-16 17:35:44 -0800473
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700474 el->attributes.reserve(attributes.size());
475 for (xml::Attribute& attr : attributes) {
476 // Don't copy compiled values or attributes.
477 el->attributes.push_back(
478 xml::Attribute{attr.namespace_uri, attr.name, attr.value});
479 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800480
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700481 el->children.reserve(children.size());
482 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskie343eb12016-10-27 16:31:58 -0700483 el->AppendChild(child->Clone());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700484 }
485 return std::move(el);
Adam Lesinski467f1712015-11-16 17:35:44 -0800486}
487
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700488std::unique_ptr<Node> Text::Clone() {
489 auto t = util::make_unique<Text>();
490 t->comment = comment;
491 t->line_number = line_number;
492 t->column_number = column_number;
493 t->text = text;
494 return std::move(t);
Adam Lesinski467f1712015-11-16 17:35:44 -0800495}
496
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700497void PackageAwareVisitor::Visit(Namespace* ns) {
498 bool added = false;
499 if (Maybe<ExtractedPackage> maybe_package =
500 ExtractPackageFromNamespace(ns->namespace_uri)) {
501 ExtractedPackage& package = maybe_package.value();
502 package_decls_.push_back(
503 PackageDecl{ns->namespace_prefix, std::move(package)});
504 added = true;
505 }
506
507 Visitor::Visit(ns);
508
509 if (added) {
510 package_decls_.pop_back();
511 }
512}
513
514Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
515 const StringPiece& alias, const StringPiece& local_package) const {
516 if (alias.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800517 return ExtractedPackage{local_package.to_string(), false /* private */};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700518 }
519
520 const auto rend = package_decls_.rend();
521 for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
522 if (alias == iter->prefix) {
523 if (iter->package.package.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800524 return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700525 }
526 return iter->package;
527 }
528 }
529 return {};
530}
531
532} // namespace xml
533} // namespace aapt