blob: e59fa86788cd0a9fd102bc73011e7fd5b64c3482 [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 Lesinski6f6ceb72014-11-14 14:48:12 -080025namespace aapt {
Adam Lesinski467f1712015-11-16 17:35:44 -080026namespace xml {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080027
28constexpr char kXmlNamespaceSep = 1;
29
Adam Lesinskice5e56e2016-10-21 17:56:45 -070030XmlPullParser::XmlPullParser(std::istream& in) : in_(in), empty_(), depth_(0) {
31 parser_ = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
32 XML_SetUserData(parser_, this);
33 XML_SetElementHandler(parser_, StartElementHandler, EndElementHandler);
34 XML_SetNamespaceDeclHandler(parser_, StartNamespaceHandler,
35 EndNamespaceHandler);
36 XML_SetCharacterDataHandler(parser_, CharacterDataHandler);
37 XML_SetCommentHandler(parser_, CommentDataHandler);
38 event_queue_.push(EventData{Event::kStartDocument, 0, depth_++});
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080039}
40
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041XmlPullParser::~XmlPullParser() { XML_ParserFree(parser_); }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080042
Adam Lesinskice5e56e2016-10-21 17:56:45 -070043XmlPullParser::Event XmlPullParser::Next() {
44 const Event currentEvent = event();
45 if (currentEvent == Event::kBadDocument ||
46 currentEvent == Event::kEndDocument) {
47 return currentEvent;
48 }
49
50 event_queue_.pop();
51 while (event_queue_.empty()) {
52 in_.read(buffer_, sizeof(buffer_) / sizeof(*buffer_));
53
54 const bool done = in_.eof();
55 if (in_.bad() && !done) {
56 error_ = strerror(errno);
57 event_queue_.push(EventData{Event::kBadDocument});
58 continue;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080059 }
60
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 if (XML_Parse(parser_, buffer_, in_.gcount(), done) == XML_STATUS_ERROR) {
62 error_ = XML_ErrorString(XML_GetErrorCode(parser_));
63 event_queue_.push(EventData{Event::kBadDocument});
64 continue;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080065 }
66
Adam Lesinskice5e56e2016-10-21 17:56:45 -070067 if (done) {
68 event_queue_.push(EventData{Event::kEndDocument, 0, 0});
Adam Lesinski24aad162015-04-24 19:19:30 -070069 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070070 }
Adam Lesinski24aad162015-04-24 19:19:30 -070071
Adam Lesinskice5e56e2016-10-21 17:56:45 -070072 Event next_event = event();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080073
Adam Lesinskice5e56e2016-10-21 17:56:45 -070074 // Record namespace prefixes and package names so that we can do our own
75 // handling of references that use namespace aliases.
76 if (next_event == Event::kStartNamespace ||
77 next_event == Event::kEndNamespace) {
78 Maybe<ExtractedPackage> result =
79 ExtractPackageFromNamespace(namespace_uri());
80 if (next_event == Event::kStartNamespace) {
81 if (result) {
82 package_aliases_.emplace_back(
83 PackageDecl{namespace_prefix(), std::move(result.value())});
84 }
85 } else {
86 if (result) {
87 package_aliases_.pop_back();
88 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080089 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090 }
91
92 return next_event;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080093}
94
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095XmlPullParser::Event XmlPullParser::event() const {
96 return event_queue_.front().event;
97}
98
99const std::string& XmlPullParser::error() const { return error_; }
100
101const std::string& XmlPullParser::comment() const {
102 return event_queue_.front().data1;
103}
104
105size_t XmlPullParser::line_number() const {
106 return event_queue_.front().line_number;
107}
108
109size_t XmlPullParser::depth() const { return event_queue_.front().depth; }
110
111const std::string& XmlPullParser::text() const {
112 if (event() != Event::kText) {
113 return empty_;
114 }
115 return event_queue_.front().data1;
116}
117
118const std::string& XmlPullParser::namespace_prefix() const {
119 const Event current_event = event();
120 if (current_event != Event::kStartNamespace &&
121 current_event != Event::kEndNamespace) {
122 return empty_;
123 }
124 return event_queue_.front().data1;
125}
126
127const std::string& XmlPullParser::namespace_uri() const {
128 const Event current_event = event();
129 if (current_event != Event::kStartNamespace &&
130 current_event != Event::kEndNamespace) {
131 return empty_;
132 }
133 return event_queue_.front().data2;
134}
135
136Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(
137 const StringPiece& alias, const StringPiece& local_package) const {
138 if (alias.empty()) {
139 return ExtractedPackage{local_package.ToString(), false /* private */};
140 }
141
142 const auto end_iter = package_aliases_.rend();
143 for (auto iter = package_aliases_.rbegin(); iter != end_iter; ++iter) {
144 if (alias == iter->prefix) {
145 if (iter->package.package.empty()) {
146 return ExtractedPackage{local_package.ToString(),
147 iter->package.private_namespace};
148 }
149 return iter->package;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800150 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700151 }
152 return {};
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800153}
154
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700155const std::string& XmlPullParser::element_namespace() const {
156 const Event current_event = event();
157 if (current_event != Event::kStartElement &&
158 current_event != Event::kEndElement) {
159 return empty_;
160 }
161 return event_queue_.front().data1;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800162}
163
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700164const std::string& XmlPullParser::element_name() const {
165 const Event current_event = event();
166 if (current_event != Event::kStartElement &&
167 current_event != Event::kEndElement) {
168 return empty_;
169 }
170 return event_queue_.front().data2;
Adam Lesinski24aad162015-04-24 19:19:30 -0700171}
172
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700173XmlPullParser::const_iterator XmlPullParser::begin_attributes() const {
174 return event_queue_.front().attributes.begin();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800175}
176
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177XmlPullParser::const_iterator XmlPullParser::end_attributes() const {
178 return event_queue_.front().attributes.end();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800179}
180
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700181size_t XmlPullParser::attribute_count() const {
182 if (event() != Event::kStartElement) {
183 return 0;
184 }
185 return event_queue_.front().attributes.size();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800186}
187
188/**
189 * Extracts the namespace and name of an expanded element or attribute name.
190 */
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700191static void SplitName(const char* name, std::string& out_ns,
192 std::string& out_name) {
193 const char* p = name;
194 while (*p != 0 && *p != kXmlNamespaceSep) {
195 p++;
196 }
197
198 if (*p == 0) {
199 out_ns = std::string();
200 out_name = name;
201 } else {
202 out_ns = StringPiece(name, (p - name)).ToString();
203 out_name = p + 1;
204 }
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_++};
227 SplitName(name, data.data1, data.data2);
228
229 while (*attrs) {
230 Attribute attribute;
231 SplitName(*attrs++, attribute.namespace_uri, attribute.name);
232 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
248 parser->event_queue_.push(
249 EventData{Event::kText, XML_GetCurrentLineNumber(parser->parser_),
250 parser->depth_, StringPiece(s, len).ToString()});
251}
252
253void XMLCALL XmlPullParser::EndElementHandler(void* user_data,
254 const char* name) {
255 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
256
257 EventData data = {Event::kEndElement,
258 XML_GetCurrentLineNumber(parser->parser_),
259 --(parser->depth_)};
260 SplitName(name, data.data1, data.data2);
261
262 // Move the data into the queue (no copy).
263 parser->event_queue_.push(std::move(data));
264}
265
266void XMLCALL XmlPullParser::EndNamespaceHandler(void* user_data,
267 const char* prefix) {
268 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
269
270 parser->event_queue_.push(
271 EventData{Event::kEndNamespace, XML_GetCurrentLineNumber(parser->parser_),
272 --(parser->depth_), prefix != nullptr ? prefix : std::string(),
273 parser->namespace_uris_.top()});
274 parser->namespace_uris_.pop();
275}
276
277void XMLCALL XmlPullParser::CommentDataHandler(void* user_data,
278 const char* comment) {
279 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
280
281 parser->event_queue_.push(EventData{Event::kComment,
282 XML_GetCurrentLineNumber(parser->parser_),
283 parser->depth_, comment});
284}
285
286Maybe<StringPiece> FindAttribute(const XmlPullParser* parser,
287 const StringPiece& name) {
288 auto iter = parser->FindAttribute("", name);
289 if (iter != parser->end_attributes()) {
290 return StringPiece(util::TrimWhitespace(iter->value));
291 }
292 return {};
293}
294
295Maybe<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
296 const StringPiece& name) {
297 auto iter = parser->FindAttribute("", name);
298 if (iter != parser->end_attributes()) {
299 StringPiece trimmed = util::TrimWhitespace(iter->value);
300 if (!trimmed.empty()) {
301 return trimmed;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800302 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700303 }
304 return {};
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800305}
306
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700307} // namespace xml
308} // namespace aapt