blob: 885ab3e33feddc14e8fda5a72e2f8ebca660a923 [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;
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) {
Adam Lesinski48448e82017-04-26 15:13:52 -070068 if (!stack->last_text_node->text.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 Lesinskice5e56e2016-10-21 17:56:45 -070077static void AddToStack(Stack* stack, XML_Parser parser,
78 std::unique_ptr<Node> node) {
79 node->line_number = XML_GetCurrentLineNumber(parser);
80 node->column_number = XML_GetCurrentColumnNumber(parser);
Adam Lesinski75f3a552015-06-03 14:54:23 -070081
Adam Lesinskice5e56e2016-10-21 17:56:45 -070082 Node* this_node = node.get();
83 if (!stack->node_stack.empty()) {
Adam Lesinskie343eb12016-10-27 16:31:58 -070084 stack->node_stack.top()->AppendChild(std::move(node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085 } else {
86 stack->root = std::move(node);
87 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070088
Adam Lesinskice5e56e2016-10-21 17:56:45 -070089 if (!NodeCast<Text>(this_node)) {
90 stack->node_stack.push(this_node);
91 }
Adam Lesinski75f3a552015-06-03 14:54:23 -070092}
93
Adam Lesinskice5e56e2016-10-21 17:56:45 -070094static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix,
95 const char* uri) {
96 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
97 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -080098 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -070099
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
101 if (prefix) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800102 ns->namespace_prefix = prefix;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700103 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700104
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700105 if (uri) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800106 ns->namespace_uri = uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700107 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700108
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700109 AddToStack(stack, parser, std::move(ns));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700110}
111
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700112static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix) {
113 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
114 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800115 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700116
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117 CHECK(!stack->node_stack.empty());
118 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700119}
120
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700121static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
122 return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
123 std::tie(rhs.namespace_uri, rhs.name, rhs.value);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700124}
125
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700126static void XMLCALL StartElementHandler(void* user_data, const char* name,
127 const char** attrs) {
128 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
129 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800130 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700131
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700132 std::unique_ptr<Element> el = util::make_unique<Element>();
133 SplitName(name, &el->namespace_uri, &el->name);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700134
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700135 while (*attrs) {
136 Attribute attribute;
137 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
Adam Lesinski48448e82017-04-26 15:13:52 -0700138 attribute.value = *attrs++;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700139
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 // Insert in sorted order.
Adam Lesinski48448e82017-04-26 15:13:52 -0700141 auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute,
142 less_attribute);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700143 el->attributes.insert(iter, std::move(attribute));
144 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700145
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700146 el->comment = std::move(stack->pending_comment);
147 AddToStack(stack, parser, std::move(el));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700148}
149
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700150static void XMLCALL EndElementHandler(void* user_data, const char* name) {
151 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
152 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800153 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700154
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700155 CHECK(!stack->node_stack.empty());
156 // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
157 stack->node_stack.pop();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700158}
159
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800160static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700161 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
162 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700163
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800164 const StringPiece str(s, len);
165 if (str.empty()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700166 return;
167 }
168
169 // See if we can just append the text to a previous text node.
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800170 if (stack->last_text_node != nullptr) {
Adam Lesinski48448e82017-04-26 15:13:52 -0700171 stack->last_text_node->text.append(str.data(), str.size());
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800172 return;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700173 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700174
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800175 stack->last_text_node = util::make_unique<Text>();
176 stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
177 stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
Adam Lesinski48448e82017-04-26 15:13:52 -0700178 stack->last_text_node->text = str.to_string();
Adam Lesinski75f3a552015-06-03 14:54:23 -0700179}
180
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700181static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
182 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
183 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
Adam Lesinskiac6edc52017-03-02 19:31:28 -0800184 FinishPendingText(stack);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700185
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186 if (!stack->pending_comment.empty()) {
187 stack->pending_comment += '\n';
188 }
189 stack->pending_comment += comment;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700190}
191
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700192std::unique_ptr<XmlResource> Inflate(std::istream* in, IDiagnostics* diag, const Source& source) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700193 Stack stack;
Adam Lesinski803c7c82016-04-06 16:09:43 -0700194
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700195 XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
196 XML_SetUserData(parser, &stack);
197 XML_UseParserAsHandlerArg(parser);
198 XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700199 XML_SetNamespaceDeclHandler(parser, StartNamespaceHandler, EndNamespaceHandler);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700200 XML_SetCharacterDataHandler(parser, CharacterDataHandler);
201 XML_SetCommentHandler(parser, CommentDataHandler);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700202
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700203 char buffer[1024];
204 while (!in->eof()) {
205 in->read(buffer, sizeof(buffer) / sizeof(buffer[0]));
206 if (in->bad() && !in->eof()) {
207 stack.root = {};
208 diag->Error(DiagMessage(source) << strerror(errno));
209 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700210 }
211
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700212 if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213 stack.root = {};
214 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser)))
215 << XML_ErrorString(XML_GetErrorCode(parser)));
216 break;
217 }
218 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700219
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 XML_ParserFree(parser);
221 if (stack.root) {
Adam Lesinskiea134e02017-04-13 12:55:19 -0700222 return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
223 std::move(stack.root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 }
225 return {};
226}
Adam Lesinski75f3a552015-06-03 14:54:23 -0700227
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700228static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 const size_t attr_count = parser->getAttributeCount();
230 if (attr_count > 0) {
231 el->attributes.reserve(attr_count);
232 for (size_t i = 0; i < attr_count; i++) {
233 Attribute attr;
234 size_t len;
235 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
236 if (str16) {
237 attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
238 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700239
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240 str16 = parser->getAttributeName(i, &len);
241 if (str16) {
242 attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
243 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700244
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700245 str16 = parser->getAttributeStringValue(i, &len);
246 if (str16) {
247 attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
248 }
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700249
250 android::Res_value res_value;
251 if (parser->getAttributeValue(i, &res_value) > 0) {
252 attr.compiled_value = ResourceUtils::ParseBinaryResValue(
253 ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
254 }
255
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 Lesinskid0f492d2017-04-03 18:12:45 -0700261std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
262 const Source& source) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700263 // 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 Lesinskid0f492d2017-04-03 18:12:45 -0700268 StringPool string_pool;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700269 std::unique_ptr<Node> root;
270 std::stack<Node*> node_stack;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700271
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700272 ResXMLTree tree;
273 if (tree.setTo(data, data_len) != NO_ERROR) {
274 return {};
275 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700276
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700277 ResXMLParser::event_code_t code;
278 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
279 code != ResXMLParser::END_DOCUMENT) {
280 std::unique_ptr<Node> new_node;
281 switch (code) {
282 case ResXMLParser::START_NAMESPACE: {
283 std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
284 size_t len;
285 const char16_t* str16 = tree.getNamespacePrefix(&len);
286 if (str16) {
287 node->namespace_prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700288 }
289
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700290 str16 = tree.getNamespaceUri(&len);
291 if (str16) {
292 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700293 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700294 new_node = std::move(node);
295 break;
296 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700297
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700298 case ResXMLParser::START_TAG: {
299 std::unique_ptr<Element> node = util::make_unique<Element>();
300 size_t len;
301 const char16_t* str16 = tree.getElementNamespace(&len);
302 if (str16) {
303 node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinskica5638f2015-10-21 14:42:43 -0700304 }
Adam Lesinskica5638f2015-10-21 14:42:43 -0700305
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700306 str16 = tree.getElementName(&len);
307 if (str16) {
308 node->name = util::Utf16ToUtf8(StringPiece16(str16, len));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700309 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700310
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700311 CopyAttributes(node.get(), &tree, &string_pool);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700312
313 new_node = std::move(node);
314 break;
315 }
316
317 case ResXMLParser::TEXT: {
318 std::unique_ptr<Text> node = util::make_unique<Text>();
319 size_t len;
320 const char16_t* str16 = tree.getText(&len);
321 if (str16) {
322 node->text = util::Utf16ToUtf8(StringPiece16(str16, len));
323 }
324 new_node = std::move(node);
325 break;
326 }
327
328 case ResXMLParser::END_NAMESPACE:
329 case ResXMLParser::END_TAG:
330 CHECK(!node_stack.empty());
331 node_stack.pop();
332 break;
333
334 default:
335 LOG(FATAL) << "unhandled XML chunk type";
336 break;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700337 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700338
339 if (new_node) {
340 new_node->line_number = tree.getLineNumber();
341
342 Node* this_node = new_node.get();
343 if (!root) {
344 CHECK(node_stack.empty()) << "node stack should be empty";
345 root = std::move(new_node);
346 } else {
347 CHECK(!node_stack.empty()) << "node stack should not be empty";
Adam Lesinskie343eb12016-10-27 16:31:58 -0700348 node_stack.top()->AppendChild(std::move(new_node));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700349 }
350
351 if (!NodeCast<Text>(this_node)) {
352 node_stack.push(this_node);
353 }
354 }
355 }
Adam Lesinskiea134e02017-04-13 12:55:19 -0700356 return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357}
358
Adam Lesinskic744ae82017-05-17 19:28:38 -0700359std::unique_ptr<Node> Namespace::Clone(const ElementCloneFunc& el_cloner) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700360 auto ns = util::make_unique<Namespace>();
361 ns->comment = comment;
362 ns->line_number = line_number;
363 ns->column_number = column_number;
364 ns->namespace_prefix = namespace_prefix;
365 ns->namespace_uri = namespace_uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700366 ns->children.reserve(children.size());
367 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskic744ae82017-05-17 19:28:38 -0700368 ns->AppendChild(child->Clone(el_cloner));
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 Lesinskic744ae82017-05-17 19:28:38 -0700414const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
415 for (const auto& attr : attributes) {
416 if (ns == attr.namespace_uri && name == attr.name) {
417 return &attr;
418 }
419 }
420 return nullptr;
421}
422
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700423Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
424 return FindChildWithAttribute(ns, name, {}, {}, {});
425}
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700426
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700427Element* Element::FindChildWithAttribute(const StringPiece& ns,
428 const StringPiece& name,
429 const StringPiece& attr_ns,
430 const StringPiece& attr_name,
431 const StringPiece& attr_value) {
432 for (auto& child_node : children) {
433 Node* child = child_node.get();
434 while (NodeCast<Namespace>(child)) {
435 if (child->children.empty()) {
436 break;
437 }
438 child = child->children[0].get();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700439 }
440
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700441 if (Element* el = NodeCast<Element>(child)) {
442 if (ns == el->namespace_uri && name == el->name) {
443 if (attr_ns.empty() && attr_name.empty()) {
444 return el;
445 }
446
447 Attribute* attr = el->FindAttribute(attr_ns, attr_name);
448 if (attr && attr_value == attr->value) {
449 return el;
450 }
451 }
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700452 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700453 }
454 return nullptr;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700455}
456
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700457std::vector<Element*> Element::GetChildElements() {
458 std::vector<Element*> elements;
459 for (auto& child_node : children) {
460 Node* child = child_node.get();
461 while (NodeCast<Namespace>(child)) {
462 if (child->children.empty()) {
463 break;
464 }
465 child = child->children[0].get();
466 }
467
468 if (Element* el = NodeCast<Element>(child)) {
469 elements.push_back(el);
470 }
471 }
472 return elements;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700473}
474
Adam Lesinskic744ae82017-05-17 19:28:38 -0700475std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700476 auto el = util::make_unique<Element>();
477 el->comment = comment;
478 el->line_number = line_number;
479 el->column_number = column_number;
480 el->name = name;
481 el->namespace_uri = namespace_uri;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700482 el->attributes.reserve(attributes.size());
Adam Lesinskic744ae82017-05-17 19:28:38 -0700483 el_cloner(*this, el.get());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700484 el->children.reserve(children.size());
485 for (const std::unique_ptr<xml::Node>& child : children) {
Adam Lesinskic744ae82017-05-17 19:28:38 -0700486 el->AppendChild(child->Clone(el_cloner));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700487 }
488 return std::move(el);
Adam Lesinski467f1712015-11-16 17:35:44 -0800489}
490
Adam Lesinskic744ae82017-05-17 19:28:38 -0700491std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700492 auto t = util::make_unique<Text>();
493 t->comment = comment;
494 t->line_number = line_number;
495 t->column_number = column_number;
496 t->text = text;
497 return std::move(t);
Adam Lesinski467f1712015-11-16 17:35:44 -0800498}
499
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700500void PackageAwareVisitor::Visit(Namespace* ns) {
501 bool added = false;
502 if (Maybe<ExtractedPackage> maybe_package =
503 ExtractPackageFromNamespace(ns->namespace_uri)) {
504 ExtractedPackage& package = maybe_package.value();
505 package_decls_.push_back(
506 PackageDecl{ns->namespace_prefix, std::move(package)});
507 added = true;
508 }
509
510 Visitor::Visit(ns);
511
512 if (added) {
513 package_decls_.pop_back();
514 }
515}
516
517Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
518 const StringPiece& alias, const StringPiece& local_package) const {
519 if (alias.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800520 return ExtractedPackage{local_package.to_string(), false /* private */};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700521 }
522
523 const auto rend = package_decls_.rend();
524 for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
525 if (alias == iter->prefix) {
526 if (iter->package.package.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800527 return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700528 }
529 return iter->package;
530 }
531 }
532 return {};
533}
534
535} // namespace xml
536} // namespace aapt