1/*
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
17#include "XmlDom.h"
18
19#include <expat.h>
20
21#include <memory>
22#include <stack>
23#include <string>
24#include <tuple>
25
26#include "android-base/logging.h"
27
28#include "ResourceUtils.h"
29#include "XmlPullParser.h"
30#include "util/Util.h"
31
32using ::aapt::io::InputStream;
33using ::android::StringPiece;
34using ::android::StringPiece16;
35
36namespace aapt {
37namespace xml {
38
39constexpr char kXmlNamespaceSep = 1;
40
41struct Stack {
42  std::unique_ptr<xml::Element> root;
43  std::stack<xml::Element*> node_stack;
44  std::unique_ptr<xml::Element> pending_element;
45  std::string pending_comment;
46  std::unique_ptr<xml::Text> last_text_node;
47};
48
49// Extracts the namespace and name of an expanded element or attribute name.
50static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
51  const char* p = name;
52  while (*p != 0 && *p != kXmlNamespaceSep) {
53    p++;
54  }
55
56  if (*p == 0) {
57    out_ns->clear();
58    out_name->assign(name);
59  } else {
60    out_ns->assign(name, (p - name));
61    out_name->assign(p + 1);
62  }
63}
64
65static void FinishPendingText(Stack* stack) {
66  if (stack->last_text_node != nullptr) {
67    if (!stack->last_text_node->text.empty()) {
68      CHECK(!stack->node_stack.empty());
69      stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
70    } else {
71      // Drop an empty text node.
72    }
73    stack->last_text_node = nullptr;
74  }
75}
76
77static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix, const char* uri) {
78  XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
79  Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
80  FinishPendingText(stack);
81
82  NamespaceDecl decl;
83  decl.line_number = XML_GetCurrentLineNumber(parser);
84  decl.column_number = XML_GetCurrentColumnNumber(parser);
85  decl.prefix = prefix ? prefix : "";
86  decl.uri = uri ? uri : "";
87
88  if (stack->pending_element == nullptr) {
89    stack->pending_element = util::make_unique<Element>();
90  }
91  stack->pending_element->namespace_decls.push_back(std::move(decl));
92}
93
94static void XMLCALL EndNamespaceHandler(void* user_data, const char* /*prefix*/) {
95  XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
96  Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
97  FinishPendingText(stack);
98}
99
100static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
101  return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
102         std::tie(rhs.namespace_uri, rhs.name, rhs.value);
103}
104
105static void XMLCALL StartElementHandler(void* user_data, const char* name, const char** attrs) {
106  XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
107  Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
108  FinishPendingText(stack);
109
110  std::unique_ptr<Element> el;
111  if (stack->pending_element != nullptr) {
112    el = std::move(stack->pending_element);
113  } else {
114    el = util::make_unique<Element>();
115  }
116
117  el->line_number = XML_GetCurrentLineNumber(parser);
118  el->column_number = XML_GetCurrentColumnNumber(parser);
119  el->comment = std::move(stack->pending_comment);
120
121  SplitName(name, &el->namespace_uri, &el->name);
122
123  while (*attrs) {
124    Attribute attribute;
125    SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
126    attribute.value = *attrs++;
127    el->attributes.push_back(std::move(attribute));
128  }
129
130  // Sort the attributes.
131  std::sort(el->attributes.begin(), el->attributes.end(), less_attribute);
132
133  // Add to the stack.
134  Element* this_el = el.get();
135  if (!stack->node_stack.empty()) {
136    stack->node_stack.top()->AppendChild(std::move(el));
137  } else {
138    stack->root = std::move(el);
139  }
140  stack->node_stack.push(this_el);
141}
142
143static void XMLCALL EndElementHandler(void* user_data, const char* name) {
144  XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
145  Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
146  FinishPendingText(stack);
147
148  CHECK(!stack->node_stack.empty());
149  // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
150  stack->node_stack.pop();
151}
152
153static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
154  XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
155  Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
156
157  const StringPiece str(s, len);
158  if (str.empty()) {
159    return;
160  }
161
162  // See if we can just append the text to a previous text node.
163  if (stack->last_text_node != nullptr) {
164    stack->last_text_node->text.append(str.data(), str.size());
165    return;
166  }
167
168  stack->last_text_node = util::make_unique<Text>();
169  stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
170  stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
171  stack->last_text_node->text = str.to_string();
172}
173
174static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
175  XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
176  Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
177  FinishPendingText(stack);
178
179  if (!stack->pending_comment.empty()) {
180    stack->pending_comment += '\n';
181  }
182  stack->pending_comment += comment;
183}
184
185std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
186  Stack stack;
187
188  std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
189      XML_ParserCreateNS(nullptr, kXmlNamespaceSep), XML_ParserFree};
190  XML_SetUserData(parser.get(), &stack);
191  XML_UseParserAsHandlerArg(parser.get());
192  XML_SetElementHandler(parser.get(), StartElementHandler, EndElementHandler);
193  XML_SetNamespaceDeclHandler(parser.get(), StartNamespaceHandler, EndNamespaceHandler);
194  XML_SetCharacterDataHandler(parser.get(), CharacterDataHandler);
195  XML_SetCommentHandler(parser.get(), CommentDataHandler);
196
197  const char* buffer = nullptr;
198  size_t buffer_size = 0;
199  while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
200    if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
201      diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
202                  << XML_ErrorString(XML_GetErrorCode(parser.get())));
203      return {};
204    }
205  }
206
207  if (in->HadError()) {
208    diag->Error(DiagMessage(source) << in->GetError());
209    return {};
210  } else {
211    // Finish off the parsing.
212    if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
213      diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
214                  << XML_ErrorString(XML_GetErrorCode(parser.get())));
215      return {};
216    }
217  }
218  return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
219                                        std::move(stack.root));
220}
221
222static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
223  const size_t attr_count = parser->getAttributeCount();
224  if (attr_count > 0) {
225    el->attributes.reserve(attr_count);
226    for (size_t i = 0; i < attr_count; i++) {
227      Attribute attr;
228      size_t len;
229      const char16_t* str16 = parser->getAttributeNamespace(i, &len);
230      if (str16) {
231        attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
232      }
233
234      str16 = parser->getAttributeName(i, &len);
235      if (str16) {
236        attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
237      }
238
239      str16 = parser->getAttributeStringValue(i, &len);
240      if (str16) {
241        attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
242      }
243
244      android::Res_value res_value;
245      if (parser->getAttributeValue(i, &res_value) > 0) {
246        attr.compiled_value = ResourceUtils::ParseBinaryResValue(
247            ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
248      }
249
250      el->attributes.push_back(std::move(attr));
251    }
252  }
253}
254
255std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
256                                     const Source& source) {
257  // We import the android namespace because on Windows NO_ERROR is a macro, not
258  // an enum, which causes errors when qualifying it with android::
259  using namespace android;
260
261  StringPool string_pool;
262  std::unique_ptr<Element> root;
263  std::stack<Element*> node_stack;
264  std::unique_ptr<Element> pending_element;
265
266  ResXMLTree tree;
267  if (tree.setTo(data, data_len) != NO_ERROR) {
268    return {};
269  }
270
271  ResXMLParser::event_code_t code;
272  while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT && code != ResXMLParser::END_DOCUMENT) {
273    std::unique_ptr<Node> new_node;
274    switch (code) {
275      case ResXMLParser::START_NAMESPACE: {
276        NamespaceDecl decl;
277        decl.line_number = tree.getLineNumber();
278
279        size_t len;
280        const char16_t* str16 = tree.getNamespacePrefix(&len);
281        if (str16) {
282          decl.prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
283        }
284
285        str16 = tree.getNamespaceUri(&len);
286        if (str16) {
287          decl.uri = util::Utf16ToUtf8(StringPiece16(str16, len));
288        }
289
290        if (pending_element == nullptr) {
291          pending_element = util::make_unique<Element>();
292        }
293        pending_element->namespace_decls.push_back(std::move(decl));
294        break;
295      }
296
297      case ResXMLParser::START_TAG: {
298        std::unique_ptr<Element> el;
299        if (pending_element != nullptr) {
300          el = std::move(pending_element);
301        } else {
302          el = util::make_unique<Element>();
303        }
304        el->line_number = tree.getLineNumber();
305
306        size_t len;
307        const char16_t* str16 = tree.getElementNamespace(&len);
308        if (str16) {
309          el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
310        }
311
312        str16 = tree.getElementName(&len);
313        if (str16) {
314          el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
315        }
316
317        Element* this_el = el.get();
318        CopyAttributes(el.get(), &tree, &string_pool);
319
320        if (!node_stack.empty()) {
321          node_stack.top()->AppendChild(std::move(el));
322        } else {
323          root = std::move(el);
324        }
325        node_stack.push(this_el);
326        break;
327      }
328
329      case ResXMLParser::TEXT: {
330        std::unique_ptr<Text> text = util::make_unique<Text>();
331        text->line_number = tree.getLineNumber();
332        size_t len;
333        const char16_t* str16 = tree.getText(&len);
334        if (str16) {
335          text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
336        }
337        CHECK(!node_stack.empty());
338        node_stack.top()->AppendChild(std::move(text));
339        break;
340      }
341
342      case ResXMLParser::END_NAMESPACE:
343        break;
344
345      case ResXMLParser::END_TAG:
346        CHECK(!node_stack.empty());
347        node_stack.pop();
348        break;
349
350      default:
351        LOG(FATAL) << "unhandled XML chunk type";
352        break;
353    }
354  }
355  return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
356}
357
358Element* FindRootElement(Node* node) {
359  if (node == nullptr) {
360    return nullptr;
361  }
362
363  while (node->parent != nullptr) {
364    node = node->parent;
365  }
366  return NodeCast<Element>(node);
367}
368
369void Element::AppendChild(std::unique_ptr<Node> child) {
370  child->parent = this;
371  children.push_back(std::move(child));
372}
373
374void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
375  child->parent = this;
376  children.insert(children.begin() + index, std::move(child));
377}
378
379Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
380  for (auto& attr : attributes) {
381    if (ns == attr.namespace_uri && name == attr.name) {
382      return &attr;
383    }
384  }
385  return nullptr;
386}
387
388const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
389  for (const auto& attr : attributes) {
390    if (ns == attr.namespace_uri && name == attr.name) {
391      return &attr;
392    }
393  }
394  return nullptr;
395}
396
397Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
398  return FindChildWithAttribute(ns, name, {}, {}, {});
399}
400
401Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
402                                         const StringPiece& attr_ns, const StringPiece& attr_name,
403                                         const StringPiece& attr_value) {
404  for (auto& child : children) {
405    if (Element* el = NodeCast<Element>(child.get())) {
406      if (ns == el->namespace_uri && name == el->name) {
407        if (attr_ns.empty() && attr_name.empty()) {
408          return el;
409        }
410
411        Attribute* attr = el->FindAttribute(attr_ns, attr_name);
412        if (attr && attr_value == attr->value) {
413          return el;
414        }
415      }
416    }
417  }
418  return nullptr;
419}
420
421std::vector<Element*> Element::GetChildElements() {
422  std::vector<Element*> elements;
423  for (auto& child_node : children) {
424    if (Element* child = NodeCast<Element>(child_node.get())) {
425      elements.push_back(child);
426    }
427  }
428  return elements;
429}
430
431std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) const {
432  auto el = util::make_unique<Element>();
433  el->namespace_decls = namespace_decls;
434  el->comment = comment;
435  el->line_number = line_number;
436  el->column_number = column_number;
437  el->name = name;
438  el->namespace_uri = namespace_uri;
439  el->attributes.reserve(attributes.size());
440  el_cloner(*this, el.get());
441  el->children.reserve(children.size());
442  for (const std::unique_ptr<xml::Node>& child : children) {
443    el->AppendChild(child->Clone(el_cloner));
444  }
445  return std::move(el);
446}
447
448std::unique_ptr<Element> Element::CloneElement(const ElementCloneFunc& el_cloner) const {
449  return std::unique_ptr<Element>(static_cast<Element*>(Clone(el_cloner).release()));
450}
451
452void Element::Accept(Visitor* visitor) {
453  visitor->BeforeVisitElement(this);
454  visitor->Visit(this);
455  visitor->AfterVisitElement(this);
456}
457
458std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) const {
459  auto t = util::make_unique<Text>();
460  t->comment = comment;
461  t->line_number = line_number;
462  t->column_number = column_number;
463  t->text = text;
464  return std::move(t);
465}
466
467void Text::Accept(Visitor* visitor) {
468  visitor->Visit(this);
469}
470
471void PackageAwareVisitor::BeforeVisitElement(Element* el) {
472  std::vector<PackageDecl> decls;
473  for (const NamespaceDecl& decl : el->namespace_decls) {
474    if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
475      decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())});
476    }
477  }
478  package_decls_.push_back(std::move(decls));
479}
480
481void PackageAwareVisitor::AfterVisitElement(Element* el) {
482  package_decls_.pop_back();
483}
484
485Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
486    const StringPiece& alias, const StringPiece& local_package) const {
487  if (alias.empty()) {
488    return ExtractedPackage{local_package.to_string(), false /* private */};
489  }
490
491  const auto rend = package_decls_.rend();
492  for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
493    const std::vector<PackageDecl>& decls = *iter;
494    const auto rend2 = decls.rend();
495    for (auto iter2 = decls.rbegin(); iter2 != rend2; ++iter2) {
496      const PackageDecl& decl = *iter2;
497      if (alias == decl.prefix) {
498        if (decl.package.package.empty()) {
499          return ExtractedPackage{local_package.to_string(), decl.package.private_namespace};
500        }
501        return decl.package;
502      }
503    }
504  }
505  return {};
506}
507
508}  // namespace xml
509}  // namespace aapt
510