blob: d6df7150214bfb52c8daecd5b7ac5b1a629b3ef3 [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 Lesinskice5e56e2016-10-21 17:56:45 -070042 std::unique_ptr<xml::Node> root;
43 std::stack<xml::Node*> node_stack;
44 std::string pending_comment;
Adam Lesinskiac6edc52017-03-02 19:31:28 -080045 std::unique_ptr<xml::Text> last_text_node;
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) {
Adam Lesinski48448e82017-04-26 15:13:52 -070069 if (!stack->last_text_node->text.empty()) {
Adam Lesinskiac6edc52017-03-02 19:31:28 -080070 stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
71 } else {
72 // Drop an empty text node.
Adam Lesinskiac6edc52017-03-02 19:31:28 -080073 }
Adam Lesinski48448e82017-04-26 15:13:52 -070074 stack->last_text_node = nullptr;
Adam Lesinskiac6edc52017-03-02 19:31:28 -080075 }
76}
77
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078static void AddToStack(Stack* stack, XML_Parser parser,
79 std::unique_ptr<Node> node) {
80 node->line_number = XML_GetCurrentLineNumber(parser);
81 node->column_number = XML_GetCurrentColumnNumber(parser);
Adam Lesinski75f3a552015-06-03 14:54:23 -070082
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083 Node* this_node = node.get();
84 if (!stack->node_stack.empty()) {
Adam Lesinskie343eb12016-10-27 16:31:58 -070085 stack->node_stack.top()->AppendChild(std::move(node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -070086 } else {
87 stack->root = std::move(node);
88 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070089
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 if (!NodeCast<Text>(this_node)) {
91 stack->node_stack.push(this_node);
92 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070093}
94
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix,
96 const char* uri) {
97 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
98 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -080099 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700100
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700101 std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
102 if (prefix) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800103 ns->namespace_prefix = prefix;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700104 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700105
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700106 if (uri) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800107 ns->namespace_uri = uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700108 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700109
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 AddToStack(stack, parser, std::move(ns));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700111}
112
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700113static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix) {
114 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
115 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800116 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700117
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700118 CHECK(!stack->node_stack.empty());
119 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700120}
121
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
123 return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
124 std::tie(rhs.namespace_uri, rhs.name, rhs.value);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700125}
126
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700127static void XMLCALL StartElementHandler(void* user_data, const char* name,
128 const char** attrs) {
129 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
130 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800131 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700132
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700133 std::unique_ptr<Element> el = util::make_unique<Element>();
134 SplitName(name, &el->namespace_uri, &el->name);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700135
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700136 while (*attrs) {
137 Attribute attribute;
138 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
Adam Lesinski48448e82017-04-26 15:13:52 -0700139 attribute.value = *attrs++;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700140
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700141 // Insert in sorted order.
Adam Lesinski48448e82017-04-26 15:13:52 -0700142 auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute,
143 less_attribute);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700144 el->attributes.insert(iter, std::move(attribute));
145 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700146
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700147 el->comment = std::move(stack->pending_comment);
148 AddToStack(stack, parser, std::move(el));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700149}
150
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700151static void XMLCALL EndElementHandler(void* user_data, const char* name) {
152 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
153 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800154 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700155
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 CHECK(!stack->node_stack.empty());
157 // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
158 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700159}
160
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800161static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700162 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
163 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700164
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800165 const StringPiece str(s, len);
166 if (str.empty()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700167 return;
168 }
169
170 // See if we can just append the text to a previous text node.
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800171 if (stack->last_text_node != nullptr) {
Adam Lesinski48448e82017-04-26 15:13:52 -0700172 stack->last_text_node->text.append(str.data(), str.size());
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800173 return;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700175
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800176 stack->last_text_node = util::make_unique<Text>();
177 stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
178 stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
Adam Lesinski48448e82017-04-26 15:13:52 -0700179 stack->last_text_node->text = str.to_string();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700180}
181
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700182static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
183 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
184 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800185 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700186
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187 if (!stack->pending_comment.empty()) {
188 stack->pending_comment += '\n';
189 }
190 stack->pending_comment += comment;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700191}
192
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700193std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700194 Stack stack;
Adam Lesinski803c7c82016-04-06 16:09:43 -0700195
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700196 std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
197 XML_ParserCreateNS(nullptr, kXmlNamespaceSep), XML_ParserFree};
198 XML_SetUserData(parser.get(), &stack);
199 XML_UseParserAsHandlerArg(parser.get());
200 XML_SetElementHandler(parser.get(), StartElementHandler, EndElementHandler);
201 XML_SetNamespaceDeclHandler(parser.get(), StartNamespaceHandler, EndNamespaceHandler);
202 XML_SetCharacterDataHandler(parser.get(), CharacterDataHandler);
203 XML_SetCommentHandler(parser.get(), CommentDataHandler);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700204
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700205 const char* buffer = nullptr;
206 size_t buffer_size = 0;
207 while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
208 if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
209 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
210 << XML_ErrorString(XML_GetErrorCode(parser.get())));
211 return {};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700212 }
213 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700214
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700215 if (in->HadError()) {
216 diag->Error(DiagMessage(source) << in->GetError());
217 return {};
218 } else {
219 // Finish off the parsing.
220 if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
221 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
222 << XML_ErrorString(XML_GetErrorCode(parser.get())));
223 return {};
224 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700225 }
Adam Lesinskiefeb7af2017-08-02 14:57:43 -0700226 return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
227 std::move(stack.root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700228}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700229
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700230static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 const size_t attr_count = parser->getAttributeCount();
232 if (attr_count > 0) {
233 el->attributes.reserve(attr_count);
234 for (size_t i = 0; i < attr_count; i++) {
235 Attribute attr;
236 size_t len;
237 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
238 if (str16) {
239 attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
240 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700241
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242 str16 = parser->getAttributeName(i, &len);
243 if (str16) {
244 attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
245 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700246
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 str16 = parser->getAttributeStringValue(i, &len);
248 if (str16) {
249 attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
250 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700251
252 android::Res_value res_value;
253 if (parser->getAttributeValue(i, &res_value) > 0) {
254 attr.compiled_value = ResourceUtils::ParseBinaryResValue(
255 ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
256 }
257
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258 el->attributes.push_back(std::move(attr));
259 }
260 }
261}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700262
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700263std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
264 const Source& source) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700265 // We import the android namespace because on Windows NO_ERROR is a macro, not
266 // an enum, which
267 // causes errors when qualifying it with android::
268 using namespace android;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700269
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700270 StringPool string_pool;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 std::unique_ptr<Node> root;
272 std::stack<Node*> node_stack;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700273
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700274 ResXMLTree tree;
275 if (tree.setTo(data, data_len) != NO_ERROR) {
276 return {};
277 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700278
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700279 ResXMLParser::event_code_t code;
280 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
281 code != ResXMLParser::END_DOCUMENT) {
282 std::unique_ptr<Node> new_node;
283 switch (code) {
284 case ResXMLParser::START_NAMESPACE: {
285 std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
286 size_t len;
287 const char16_t* str16 = tree.getNamespacePrefix(&len);
288 if (str16) {
289 node->namespace_prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700290 }
291
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700292 str16 = tree.getNamespaceUri(&len);
293 if (str16) {
294 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700295 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700296 new_node = std::move(node);
297 break;
298 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700299
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700300 case ResXMLParser::START_TAG: {
301 std::unique_ptr<Element> node = util::make_unique<Element>();
302 size_t len;
303 const char16_t* str16 = tree.getElementNamespace(&len);
304 if (str16) {
305 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinskica5638f2015-10-21 14:42:43 -0700306 }
Adam Lesinskica5638f2015-10-21 14:42:43 -0700307
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700308 str16 = tree.getElementName(&len);
309 if (str16) {
310 node->name = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700311 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700312
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700313 CopyAttributes(node.get(), &tree, &string_pool);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700314
315 new_node = std::move(node);
316 break;
317 }
318
319 case ResXMLParser::TEXT: {
320 std::unique_ptr<Text> node = util::make_unique<Text>();
321 size_t len;
322 const char16_t* str16 = tree.getText(&len);
323 if (str16) {
324 node->text = util::Utf16ToUtf8(StringPiece16(str16, len));
325 }
326 new_node = std::move(node);
327 break;
328 }
329
330 case ResXMLParser::END_NAMESPACE:
331 case ResXMLParser::END_TAG:
332 CHECK(!node_stack.empty());
333 node_stack.pop();
334 break;
335
336 default:
337 LOG(FATAL) << "unhandled XML chunk type";
338 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700339 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700340
341 if (new_node) {
342 new_node->line_number = tree.getLineNumber();
343
344 Node* this_node = new_node.get();
345 if (!root) {
346 CHECK(node_stack.empty()) << "node stack should be empty";
347 root = std::move(new_node);
348 } else {
349 CHECK(!node_stack.empty()) << "node stack should not be empty";
Adam Lesinskie343eb12016-10-27 16:31:58 -0700350 node_stack.top()->AppendChild(std::move(new_node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700351 }
352
353 if (!NodeCast<Text>(this_node)) {
354 node_stack.push(this_node);
355 }
356 }
357 }
Adam Lesinskiea134e02017-04-13 12:55:19 -0700358 return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700359}
360
Adam Lesinskic744ae82017-05-17 19:28:38 -0700361std::unique_ptr<Node> Namespace::Clone(const ElementCloneFunc& el_cloner) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700362 auto ns = util::make_unique<Namespace>();
363 ns->comment = comment;
364 ns->line_number = line_number;
365 ns->column_number = column_number;
366 ns->namespace_prefix = namespace_prefix;
367 ns->namespace_uri = namespace_uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700368 ns->children.reserve(children.size());
369 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskic744ae82017-05-17 19:28:38 -0700370 ns->AppendChild(child->Clone(el_cloner));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700371 }
372 return std::move(ns);
373}
374
375Element* FindRootElement(XmlResource* doc) {
376 return FindRootElement(doc->root.get());
377}
378
379Element* FindRootElement(Node* node) {
380 if (!node) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700381 return nullptr;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700382 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700383
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700384 Element* el = nullptr;
385 while ((el = NodeCast<Element>(node)) == nullptr) {
386 if (node->children.empty()) {
387 return nullptr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700388 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700389 // We are looking for the first element, and namespaces can only have one
390 // child.
391 node = node->children.front().get();
392 }
393 return el;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700394}
395
Adam Lesinskie343eb12016-10-27 16:31:58 -0700396void Node::AppendChild(std::unique_ptr<Node> child) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700397 child->parent = this;
398 children.push_back(std::move(child));
399}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700400
Adam Lesinskie343eb12016-10-27 16:31:58 -0700401void Node::InsertChild(size_t index, std::unique_ptr<Node> child) {
402 child->parent = this;
403 children.insert(children.begin() + index, std::move(child));
404}
405
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700406Attribute* Element::FindAttribute(const StringPiece& ns,
407 const StringPiece& name) {
408 for (auto& attr : attributes) {
409 if (ns == attr.namespace_uri && name == attr.name) {
410 return &attr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700411 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700412 }
413 return nullptr;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700414}
415
Adam Lesinskic744ae82017-05-17 19:28:38 -0700416const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
417 for (const auto& attr : attributes) {
418 if (ns == attr.namespace_uri && name == attr.name) {
419 return &attr;
420 }
421 }
422 return nullptr;
423}
424
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700425Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
426 return FindChildWithAttribute(ns, name, {}, {}, {});
427}
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700428
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700429Element* Element::FindChildWithAttribute(const StringPiece& ns,
430 const StringPiece& name,
431 const StringPiece& attr_ns,
432 const StringPiece& attr_name,
433 const StringPiece& attr_value) {
434 for (auto& child_node : children) {
435 Node* child = child_node.get();
436 while (NodeCast<Namespace>(child)) {
437 if (child->children.empty()) {
438 break;
439 }
440 child = child->children[0].get();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700441 }
442
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700443 if (Element* el = NodeCast<Element>(child)) {
444 if (ns == el->namespace_uri && name == el->name) {
445 if (attr_ns.empty() && attr_name.empty()) {
446 return el;
447 }
448
449 Attribute* attr = el->FindAttribute(attr_ns, attr_name);
450 if (attr && attr_value == attr->value) {
451 return el;
452 }
453 }
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700454 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700455 }
456 return nullptr;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700457}
458
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700459std::vector<Element*> Element::GetChildElements() {
460 std::vector<Element*> elements;
461 for (auto& child_node : children) {
462 Node* child = child_node.get();
463 while (NodeCast<Namespace>(child)) {
464 if (child->children.empty()) {
465 break;
466 }
467 child = child->children[0].get();
468 }
469
470 if (Element* el = NodeCast<Element>(child)) {
471 elements.push_back(el);
472 }
473 }
474 return elements;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700475}
476
Adam Lesinskic744ae82017-05-17 19:28:38 -0700477std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700478 auto el = util::make_unique<Element>();
479 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 Lesinskic744ae82017-05-17 19:28:38 -0700493std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700494 auto t = util::make_unique<Text>();
495 t->comment = comment;
496 t->line_number = line_number;
497 t->column_number = column_number;
498 t->text = text;
499 return std::move(t);
Adam Lesinski467f1712015-11-16 17:35:44 -0800500}
501
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700502void PackageAwareVisitor::Visit(Namespace* ns) {
503 bool added = false;
504 if (Maybe<ExtractedPackage> maybe_package =
505 ExtractPackageFromNamespace(ns->namespace_uri)) {
506 ExtractedPackage& package = maybe_package.value();
507 package_decls_.push_back(
508 PackageDecl{ns->namespace_prefix, std::move(package)});
509 added = true;
510 }
511
512 Visitor::Visit(ns);
513
514 if (added) {
515 package_decls_.pop_back();
516 }
517}
518
519Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
520 const StringPiece& alias, const StringPiece& local_package) const {
521 if (alias.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800522 return ExtractedPackage{local_package.to_string(), false /* private */};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700523 }
524
525 const auto rend = package_decls_.rend();
526 for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
527 if (alias == iter->prefix) {
528 if (iter->package.package.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800529 return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700530 }
531 return iter->package;
532 }
533 }
534 return {};
535}
536
537} // namespace xml
538} // namespace aapt