blob: c2a9c8283a6d26e6c10be320cab0223b6592c80d [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
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 Lesinskice5e56e2016-10-21 17:56:45 -070017#include <iostream>
18#include <string>
19
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "util/Maybe.h"
21#include "util/Util.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080022#include "xml/XmlPullParser.h"
23#include "xml/XmlUtil.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070024
Adam Lesinskid5083f62017-01-16 15:07:21 -080025using android::StringPiece;
26
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080027namespace aapt {
Adam Lesinski467f1712015-11-16 17:35:44 -080028namespace xml {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080029
30constexpr char kXmlNamespaceSep = 1;
31
Adam Lesinskice5e56e2016-10-21 17:56:45 -070032XmlPullParser::XmlPullParser(std::istream& in) : in_(in), empty_(), depth_(0) {
33 parser_ = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
34 XML_SetUserData(parser_, this);
35 XML_SetElementHandler(parser_, StartElementHandler, EndElementHandler);
36 XML_SetNamespaceDeclHandler(parser_, StartNamespaceHandler,
37 EndNamespaceHandler);
38 XML_SetCharacterDataHandler(parser_, CharacterDataHandler);
39 XML_SetCommentHandler(parser_, CommentDataHandler);
40 event_queue_.push(EventData{Event::kStartDocument, 0, depth_++});
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080041}
42
Adam Lesinskice5e56e2016-10-21 17:56:45 -070043XmlPullParser::~XmlPullParser() { XML_ParserFree(parser_); }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080044
Adam Lesinskice5e56e2016-10-21 17:56:45 -070045XmlPullParser::Event XmlPullParser::Next() {
46 const Event currentEvent = event();
47 if (currentEvent == Event::kBadDocument ||
48 currentEvent == Event::kEndDocument) {
49 return currentEvent;
50 }
51
52 event_queue_.pop();
53 while (event_queue_.empty()) {
54 in_.read(buffer_, sizeof(buffer_) / sizeof(*buffer_));
55
56 const bool done = in_.eof();
57 if (in_.bad() && !done) {
58 error_ = strerror(errno);
59 event_queue_.push(EventData{Event::kBadDocument});
60 continue;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080061 }
62
Adam Lesinskice5e56e2016-10-21 17:56:45 -070063 if (XML_Parse(parser_, buffer_, in_.gcount(), done) == XML_STATUS_ERROR) {
64 error_ = XML_ErrorString(XML_GetErrorCode(parser_));
65 event_queue_.push(EventData{Event::kBadDocument});
66 continue;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080067 }
68
Adam Lesinskice5e56e2016-10-21 17:56:45 -070069 if (done) {
70 event_queue_.push(EventData{Event::kEndDocument, 0, 0});
Adam Lesinski24aad162015-04-24 19:19:30 -070071 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070072 }
Adam Lesinski24aad162015-04-24 19:19:30 -070073
Adam Lesinskice5e56e2016-10-21 17:56:45 -070074 Event next_event = event();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080075
Adam Lesinskice5e56e2016-10-21 17:56:45 -070076 // Record namespace prefixes and package names so that we can do our own
77 // handling of references that use namespace aliases.
78 if (next_event == Event::kStartNamespace ||
79 next_event == Event::kEndNamespace) {
80 Maybe<ExtractedPackage> result =
81 ExtractPackageFromNamespace(namespace_uri());
82 if (next_event == Event::kStartNamespace) {
83 if (result) {
84 package_aliases_.emplace_back(
85 PackageDecl{namespace_prefix(), std::move(result.value())});
86 }
87 } else {
88 if (result) {
89 package_aliases_.pop_back();
90 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080091 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 }
93
94 return next_event;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080095}
96
Adam Lesinskice5e56e2016-10-21 17:56:45 -070097XmlPullParser::Event XmlPullParser::event() const {
98 return event_queue_.front().event;
99}
100
101const std::string& XmlPullParser::error() const { return error_; }
102
103const std::string& XmlPullParser::comment() const {
104 return event_queue_.front().data1;
105}
106
107size_t XmlPullParser::line_number() const {
108 return event_queue_.front().line_number;
109}
110
111size_t XmlPullParser::depth() const { return event_queue_.front().depth; }
112
113const std::string& XmlPullParser::text() const {
114 if (event() != Event::kText) {
115 return empty_;
116 }
117 return event_queue_.front().data1;
118}
119
120const std::string& XmlPullParser::namespace_prefix() const {
121 const Event current_event = event();
122 if (current_event != Event::kStartNamespace &&
123 current_event != Event::kEndNamespace) {
124 return empty_;
125 }
126 return event_queue_.front().data1;
127}
128
129const std::string& XmlPullParser::namespace_uri() const {
130 const Event current_event = event();
131 if (current_event != Event::kStartNamespace &&
132 current_event != Event::kEndNamespace) {
133 return empty_;
134 }
135 return event_queue_.front().data2;
136}
137
138Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(
139 const StringPiece& alias, const StringPiece& local_package) const {
140 if (alias.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800141 return ExtractedPackage{local_package.to_string(), false /* private */};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142 }
143
144 const auto end_iter = package_aliases_.rend();
145 for (auto iter = package_aliases_.rbegin(); iter != end_iter; ++iter) {
146 if (alias == iter->prefix) {
147 if (iter->package.package.empty()) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800148 return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149 }
150 return iter->package;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800151 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700152 }
153 return {};
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800154}
155
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156const std::string& XmlPullParser::element_namespace() const {
157 const Event current_event = event();
158 if (current_event != Event::kStartElement &&
159 current_event != Event::kEndElement) {
160 return empty_;
161 }
162 return event_queue_.front().data1;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800163}
164
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700165const std::string& XmlPullParser::element_name() const {
166 const Event current_event = event();
167 if (current_event != Event::kStartElement &&
168 current_event != Event::kEndElement) {
169 return empty_;
170 }
171 return event_queue_.front().data2;
Adam Lesinski24aad162015-04-24 19:19:30 -0700172}
173
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174XmlPullParser::const_iterator XmlPullParser::begin_attributes() const {
175 return event_queue_.front().attributes.begin();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800176}
177
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700178XmlPullParser::const_iterator XmlPullParser::end_attributes() const {
179 return event_queue_.front().attributes.end();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800180}
181
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700182size_t XmlPullParser::attribute_count() const {
183 if (event() != Event::kStartElement) {
184 return 0;
185 }
186 return event_queue_.front().attributes.size();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800187}
188
189/**
190 * Extracts the namespace and name of an expanded element or attribute name.
191 */
Adam Lesinskid5083f62017-01-16 15:07:21 -0800192static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700193 const char* p = name;
194 while (*p != 0 && *p != kXmlNamespaceSep) {
195 p++;
196 }
197
198 if (*p == 0) {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800199 out_ns->clear();
200 out_name->assign(name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700201 } else {
Adam Lesinskid5083f62017-01-16 15:07:21 -0800202 out_ns->assign(name, (p - name));
203 out_name->assign(p + 1);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700204 }
205}
206
207void XMLCALL XmlPullParser::StartNamespaceHandler(void* user_data,
208 const char* prefix,
209 const char* uri) {
210 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
211 std::string namespace_uri = uri != nullptr ? uri : std::string();
212 parser->namespace_uris_.push(namespace_uri);
213 parser->event_queue_.push(
214 EventData{Event::kStartNamespace,
215 XML_GetCurrentLineNumber(parser->parser_), parser->depth_++,
216 prefix != nullptr ? prefix : std::string(), namespace_uri});
217}
218
219void XMLCALL XmlPullParser::StartElementHandler(void* user_data,
220 const char* name,
221 const char** attrs) {
222 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
223
224 EventData data = {Event::kStartElement,
225 XML_GetCurrentLineNumber(parser->parser_),
226 parser->depth_++};
Adam Lesinskid5083f62017-01-16 15:07:21 -0800227 SplitName(name, &data.data1, &data.data2);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700228
229 while (*attrs) {
230 Attribute attribute;
Adam Lesinskid5083f62017-01-16 15:07:21 -0800231 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700232 attribute.value = *attrs++;
233
234 // Insert in sorted order.
235 auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(),
236 attribute);
237 data.attributes.insert(iter, std::move(attribute));
238 }
239
240 // Move the structure into the queue (no copy).
241 parser->event_queue_.push(std::move(data));
242}
243
244void XMLCALL XmlPullParser::CharacterDataHandler(void* user_data, const char* s,
245 int len) {
246 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
247
Adam Lesinskid5083f62017-01-16 15:07:21 -0800248 parser->event_queue_.push(EventData{Event::kText, XML_GetCurrentLineNumber(parser->parser_),
249 parser->depth_, std::string(s, len)});
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700250}
251
252void XMLCALL XmlPullParser::EndElementHandler(void* user_data,
253 const char* name) {
254 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
255
256 EventData data = {Event::kEndElement,
257 XML_GetCurrentLineNumber(parser->parser_),
258 --(parser->depth_)};
Adam Lesinskid5083f62017-01-16 15:07:21 -0800259 SplitName(name, &data.data1, &data.data2);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260
261 // Move the data into the queue (no copy).
262 parser->event_queue_.push(std::move(data));
263}
264
265void XMLCALL XmlPullParser::EndNamespaceHandler(void* user_data,
266 const char* prefix) {
267 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
268
269 parser->event_queue_.push(
270 EventData{Event::kEndNamespace, XML_GetCurrentLineNumber(parser->parser_),
271 --(parser->depth_), prefix != nullptr ? prefix : std::string(),
272 parser->namespace_uris_.top()});
273 parser->namespace_uris_.pop();
274}
275
276void XMLCALL XmlPullParser::CommentDataHandler(void* user_data,
277 const char* comment) {
278 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
279
280 parser->event_queue_.push(EventData{Event::kComment,
281 XML_GetCurrentLineNumber(parser->parser_),
282 parser->depth_, comment});
283}
284
285Maybe<StringPiece> FindAttribute(const XmlPullParser* parser,
286 const StringPiece& name) {
287 auto iter = parser->FindAttribute("", name);
288 if (iter != parser->end_attributes()) {
289 return StringPiece(util::TrimWhitespace(iter->value));
290 }
291 return {};
292}
293
294Maybe<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
295 const StringPiece& name) {
296 auto iter = parser->FindAttribute("", name);
297 if (iter != parser->end_attributes()) {
298 StringPiece trimmed = util::TrimWhitespace(iter->value);
299 if (!trimmed.empty()) {
300 return trimmed;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800301 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700302 }
303 return {};
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800304}
305
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700306} // namespace xml
307} // namespace aapt