blob: 9a46bcb9fc5ced504ee27aecf03cd30fe6b4cff0 [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
17#ifndef AAPT_XML_DOM_H
18#define AAPT_XML_DOM_H
19
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "Diagnostics.h"
21#include "Resource.h"
22#include "ResourceValues.h"
23#include "util/StringPiece.h"
24#include "util/Util.h"
25
26#include "process/IResourceTableConsumer.h"
Adam Lesinski75f3a552015-06-03 14:54:23 -070027
28#include <istream>
Elliott Hughes51348d22015-07-21 11:39:21 -070029#include <expat.h>
Adam Lesinski75f3a552015-06-03 14:54:23 -070030#include <memory>
31#include <string>
32#include <vector>
33
34namespace aapt {
35namespace xml {
36
Adam Lesinski2ae4a872015-11-02 16:10:55 -080037constexpr const char16_t* kSchemaAndroid = u"http://schemas.android.com/apk/res/android";
38
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039struct RawVisitor;
Adam Lesinski75f3a552015-06-03 14:54:23 -070040
41/**
42 * The type of node. Can be used to downcast to the concrete XML node
43 * class.
44 */
45enum class NodeType {
46 kNamespace,
47 kElement,
48 kText,
49};
50
51/**
52 * Base class for all XML nodes.
53 */
54struct Node {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070055 Node* parent = nullptr;
56 size_t lineNumber = 0;
57 size_t columnNumber = 0;
Adam Lesinski75f3a552015-06-03 14:54:23 -070058 std::u16string comment;
59 std::vector<std::unique_ptr<Node>> children;
60
Adam Lesinski75f3a552015-06-03 14:54:23 -070061 void addChild(std::unique_ptr<Node> child);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070062 virtual void accept(RawVisitor* visitor) = 0;
Adam Lesinski75f3a552015-06-03 14:54:23 -070063 virtual ~Node() {}
64};
65
66/**
67 * Base class that implements the visitor methods for a
68 * subclass of Node.
69 */
70template <typename Derived>
71struct BaseNode : public Node {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070072 virtual void accept(RawVisitor* visitor) override;
Adam Lesinski75f3a552015-06-03 14:54:23 -070073};
74
75/**
76 * A Namespace XML node. Can only have one child.
77 */
78struct Namespace : public BaseNode<Namespace> {
79 std::u16string namespacePrefix;
80 std::u16string namespaceUri;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070081};
Adam Lesinski75f3a552015-06-03 14:54:23 -070082
Adam Lesinski1ab598f2015-08-14 14:26:04 -070083struct AaptAttribute {
84 ResourceId id;
85 aapt::Attribute attribute;
Adam Lesinski75f3a552015-06-03 14:54:23 -070086};
87
88/**
89 * An XML attribute.
90 */
91struct Attribute {
92 std::u16string namespaceUri;
93 std::u16string name;
94 std::u16string value;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070095
96 Maybe<AaptAttribute> compiledAttribute;
97 std::unique_ptr<Item> compiledValue;
Adam Lesinski75f3a552015-06-03 14:54:23 -070098};
99
100/**
101 * An Element XML node.
102 */
103struct Element : public BaseNode<Element> {
104 std::u16string namespaceUri;
105 std::u16string name;
106 std::vector<Attribute> attributes;
107
Adam Lesinski75f3a552015-06-03 14:54:23 -0700108 Attribute* findAttribute(const StringPiece16& ns, const StringPiece16& name);
109 xml::Element* findChild(const StringPiece16& ns, const StringPiece16& name);
110 xml::Element* findChildWithAttribute(const StringPiece16& ns, const StringPiece16& name,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700111 const StringPiece16& attrNs,
112 const StringPiece16& attrName,
113 const StringPiece16& attrValue);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700114 std::vector<xml::Element*> getChildElements();
115};
116
117/**
118 * A Text (CDATA) XML node. Can not have any children.
119 */
120struct Text : public BaseNode<Text> {
121 std::u16string text;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700122};
123
124/**
125 * Inflates an XML DOM from a text stream, logging errors to the logger.
126 * Returns the root node on success, or nullptr on failure.
127 */
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700128std::unique_ptr<XmlResource> inflate(std::istream* in, IDiagnostics* diag, const Source& source);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700129
130/**
131 * Inflates an XML DOM from a binary ResXMLTree, logging errors to the logger.
132 * Returns the root node on success, or nullptr on failure.
133 */
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700134std::unique_ptr<XmlResource> inflate(const void* data, size_t dataLen, IDiagnostics* diag,
135 const Source& source);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700136
Adam Lesinskica5638f2015-10-21 14:42:43 -0700137Element* findRootElement(Node* node);
138
Adam Lesinski75f3a552015-06-03 14:54:23 -0700139/**
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700140 * A visitor interface for the different XML Node subtypes. This will not traverse into
141 * children. Use Visitor for that.
Adam Lesinski75f3a552015-06-03 14:54:23 -0700142 */
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700143struct RawVisitor {
144 virtual ~RawVisitor() = default;
145
146 virtual void visit(Namespace* node) {}
147 virtual void visit(Element* node) {}
148 virtual void visit(Text* text) {}
149};
150
151/**
152 * Visitor whose default implementation visits the children nodes of any node.
153 */
154struct Visitor : public RawVisitor {
155 using RawVisitor::visit;
156
157 void visit(Namespace* node) override {
158 visitChildren(node);
159 }
160
161 void visit(Element* node) override {
162 visitChildren(node);
163 }
164
165 void visit(Text* text) override {
166 visitChildren(text);
167 }
168
169 void visitChildren(Node* node) {
170 for (auto& child : node->children) {
171 child->accept(this);
172 }
173 }
174};
175
176/**
177 * An XML DOM visitor that will record the package name for a namespace prefix.
178 */
179class PackageAwareVisitor : public Visitor, public IPackageDeclStack {
180private:
181 struct PackageDecl {
182 std::u16string prefix;
183 std::u16string package;
184 };
185
186 std::vector<PackageDecl> mPackageDecls;
187
188public:
189 using Visitor::visit;
190
191 void visit(Namespace* ns) override {
192 bool added = false;
193 {
194 Maybe<std::u16string> package = util::extractPackageFromNamespace(ns->namespaceUri);
195 if (package) {
196 mPackageDecls.push_back(PackageDecl{ ns->namespacePrefix, package.value() });
197 added = true;
198 }
199 }
200
201 Visitor::visit(ns);
202
203 if (added) {
204 mPackageDecls.pop_back();
205 }
206 }
207
208 Maybe<ResourceName> transformPackage(const ResourceName& name,
209 const StringPiece16& localPackage) const override {
210 if (name.package.empty()) {
211 return ResourceName{ localPackage.toString(), name.type, name.entry };
212 }
213
214 const auto rend = mPackageDecls.rend();
215 for (auto iter = mPackageDecls.rbegin(); iter != rend; ++iter) {
216 if (name.package == iter->prefix) {
217 if (iter->package.empty()) {
218 return ResourceName{ localPackage.toString(), name.type, name.entry };
219 } else {
220 return ResourceName{ iter->package, name.type, name.entry };
221 }
222 }
223 }
224 return {};
225 }
Adam Lesinski75f3a552015-06-03 14:54:23 -0700226};
227
228// Implementations
229
230template <typename Derived>
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700231void BaseNode<Derived>::accept(RawVisitor* visitor) {
232 visitor->visit(static_cast<Derived*>(this));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700233}
234
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700235template <typename T>
236struct NodeCastImpl : public RawVisitor {
237 using RawVisitor::visit;
238
239 T* value = nullptr;
240
241 void visit(T* v) override {
242 value = v;
243 }
244};
245
246template <typename T>
247T* nodeCast(Node* node) {
248 NodeCastImpl<T> visitor;
249 node->accept(&visitor);
250 return visitor.value;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700251}
252
253} // namespace xml
254} // namespace aapt
255
256#endif // AAPT_XML_DOM_H