blob: 323ec05b5f2cad55ad8c8ace9e6586ab93af45f4 [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 Lesinski1ab598f2015-08-14 14:26:04 -070017#include "util/Maybe.h"
18#include "util/Util.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080019#include "xml/XmlPullParser.h"
20#include "xml/XmlUtil.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070021
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080022#include <iostream>
23#include <string>
24
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 Lesinski1ab598f2015-08-14 14:26:04 -070030XmlPullParser::XmlPullParser(std::istream& in) : mIn(in), mEmpty(), mDepth(0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080031 mParser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
32 XML_SetUserData(mParser, this);
33 XML_SetElementHandler(mParser, startElementHandler, endElementHandler);
34 XML_SetNamespaceDeclHandler(mParser, startNamespaceHandler, endNamespaceHandler);
35 XML_SetCharacterDataHandler(mParser, characterDataHandler);
36 XML_SetCommentHandler(mParser, commentDataHandler);
37 mEventQueue.push(EventData{ Event::kStartDocument, 0, mDepth++ });
38}
39
Adam Lesinski1ab598f2015-08-14 14:26:04 -070040XmlPullParser::~XmlPullParser() {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080041 XML_ParserFree(mParser);
42}
43
Adam Lesinski1ab598f2015-08-14 14:26:04 -070044XmlPullParser::Event XmlPullParser::next() {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080045 const Event currentEvent = getEvent();
46 if (currentEvent == Event::kBadDocument || currentEvent == Event::kEndDocument) {
47 return currentEvent;
48 }
49
50 mEventQueue.pop();
51 while (mEventQueue.empty()) {
52 mIn.read(mBuffer, sizeof(mBuffer) / sizeof(*mBuffer));
53
54 const bool done = mIn.eof();
55 if (mIn.bad() && !done) {
56 mLastError = strerror(errno);
57 mEventQueue.push(EventData{ Event::kBadDocument });
58 continue;
59 }
60
61 if (XML_Parse(mParser, mBuffer, mIn.gcount(), done) == XML_STATUS_ERROR) {
62 mLastError = XML_ErrorString(XML_GetErrorCode(mParser));
63 mEventQueue.push(EventData{ Event::kBadDocument });
64 continue;
65 }
66
67 if (done) {
68 mEventQueue.push(EventData{ Event::kEndDocument, 0, 0 });
69 }
70 }
71
Adam Lesinski24aad162015-04-24 19:19:30 -070072 Event event = getEvent();
73
74 // Record namespace prefixes and package names so that we can do our own
75 // handling of references that use namespace aliases.
76 if (event == Event::kStartNamespace || event == Event::kEndNamespace) {
Adam Lesinski467f1712015-11-16 17:35:44 -080077 Maybe<ExtractedPackage> result = extractPackageFromNamespace(getNamespaceUri());
Adam Lesinski24aad162015-04-24 19:19:30 -070078 if (event == Event::kStartNamespace) {
79 if (result) {
Adam Lesinski467f1712015-11-16 17:35:44 -080080 mPackageAliases.emplace_back(
81 PackageDecl{ getNamespacePrefix(), std::move(result.value()) });
Adam Lesinski24aad162015-04-24 19:19:30 -070082 }
83 } else {
84 if (result) {
Adam Lesinski24aad162015-04-24 19:19:30 -070085 mPackageAliases.pop_back();
86 }
87 }
88 }
89
90 return event;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080091}
92
Adam Lesinski1ab598f2015-08-14 14:26:04 -070093XmlPullParser::Event XmlPullParser::getEvent() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080094 return mEventQueue.front().event;
95}
96
Adam Lesinski1ab598f2015-08-14 14:26:04 -070097const std::string& XmlPullParser::getLastError() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080098 return mLastError;
99}
100
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700101const std::u16string& XmlPullParser::getComment() const {
Adam Lesinskie78fd612015-10-22 12:48:43 -0700102 return mEventQueue.front().data1;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800103}
104
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700105size_t XmlPullParser::getLineNumber() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800106 return mEventQueue.front().lineNumber;
107}
108
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700109size_t XmlPullParser::getDepth() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800110 return mEventQueue.front().depth;
111}
112
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700113const std::u16string& XmlPullParser::getText() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800114 if (getEvent() != Event::kText) {
115 return mEmpty;
116 }
117 return mEventQueue.front().data1;
118}
119
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700120const std::u16string& XmlPullParser::getNamespacePrefix() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800121 const Event currentEvent = getEvent();
122 if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
123 return mEmpty;
124 }
125 return mEventQueue.front().data1;
126}
127
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700128const std::u16string& XmlPullParser::getNamespaceUri() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800129 const Event currentEvent = getEvent();
130 if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
131 return mEmpty;
132 }
133 return mEventQueue.front().data2;
134}
135
Adam Lesinski467f1712015-11-16 17:35:44 -0800136Maybe<ExtractedPackage> XmlPullParser::transformPackageAlias(
137 const StringPiece16& alias, const StringPiece16& localPackage) const {
138 if (alias.empty()) {
139 return ExtractedPackage{ localPackage.toString(), false /* private */ };
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700140 }
141
Adam Lesinski24aad162015-04-24 19:19:30 -0700142 const auto endIter = mPackageAliases.rend();
143 for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) {
Adam Lesinski467f1712015-11-16 17:35:44 -0800144 if (alias == iter->prefix) {
145 if (iter->package.package.empty()) {
146 return ExtractedPackage{ localPackage.toString(),
147 iter->package.privateNamespace };
Adam Lesinski24aad162015-04-24 19:19:30 -0700148 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800149 return iter->package;
Adam Lesinski24aad162015-04-24 19:19:30 -0700150 }
151 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700152 return {};
Adam Lesinski24aad162015-04-24 19:19:30 -0700153}
154
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700155const std::u16string& XmlPullParser::getElementNamespace() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800156 const Event currentEvent = getEvent();
157 if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
158 return mEmpty;
159 }
160 return mEventQueue.front().data1;
161}
162
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700163const std::u16string& XmlPullParser::getElementName() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800164 const Event currentEvent = getEvent();
165 if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
166 return mEmpty;
167 }
168 return mEventQueue.front().data2;
169}
170
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700171XmlPullParser::const_iterator XmlPullParser::beginAttributes() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800172 return mEventQueue.front().attributes.begin();
173}
174
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700175XmlPullParser::const_iterator XmlPullParser::endAttributes() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800176 return mEventQueue.front().attributes.end();
177}
178
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700179size_t XmlPullParser::getAttributeCount() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800180 if (getEvent() != Event::kStartElement) {
181 return 0;
182 }
183 return mEventQueue.front().attributes.size();
184}
185
186/**
187 * Extracts the namespace and name of an expanded element or attribute name.
188 */
189static void splitName(const char* name, std::u16string& outNs, std::u16string& outName) {
190 const char* p = name;
191 while (*p != 0 && *p != kXmlNamespaceSep) {
192 p++;
193 }
194
195 if (*p == 0) {
196 outNs = std::u16string();
197 outName = util::utf8ToUtf16(name);
198 } else {
199 outNs = util::utf8ToUtf16(StringPiece(name, (p - name)));
200 outName = util::utf8ToUtf16(p + 1);
201 }
202}
203
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700204void XMLCALL XmlPullParser::startNamespaceHandler(void* userData, const char* prefix,
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800205 const char* uri) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700206 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800207 std::u16string namespaceUri = uri != nullptr ? util::utf8ToUtf16(uri) : std::u16string();
208 parser->mNamespaceUris.push(namespaceUri);
209 parser->mEventQueue.push(EventData{
210 Event::kStartNamespace,
211 XML_GetCurrentLineNumber(parser->mParser),
212 parser->mDepth++,
213 prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
214 namespaceUri
215 });
216}
217
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700218void XMLCALL XmlPullParser::startElementHandler(void* userData, const char* name,
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800219 const char** attrs) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700220 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800221
222 EventData data = {
223 Event::kStartElement, XML_GetCurrentLineNumber(parser->mParser), parser->mDepth++
224 };
225 splitName(name, data.data1, data.data2);
226
227 while (*attrs) {
228 Attribute attribute;
229 splitName(*attrs++, attribute.namespaceUri, attribute.name);
230 attribute.value = util::utf8ToUtf16(*attrs++);
231
232 // Insert in sorted order.
233 auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(), attribute);
234 data.attributes.insert(iter, std::move(attribute));
235 }
236
237 // Move the structure into the queue (no copy).
238 parser->mEventQueue.push(std::move(data));
239}
240
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700241void XMLCALL XmlPullParser::characterDataHandler(void* userData, const char* s, int len) {
242 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800243
244 parser->mEventQueue.push(EventData{
245 Event::kText,
246 XML_GetCurrentLineNumber(parser->mParser),
247 parser->mDepth,
248 util::utf8ToUtf16(StringPiece(s, len))
249 });
250}
251
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700252void XMLCALL XmlPullParser::endElementHandler(void* userData, const char* name) {
253 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800254
255 EventData data = {
256 Event::kEndElement, XML_GetCurrentLineNumber(parser->mParser), --(parser->mDepth)
257 };
258 splitName(name, data.data1, data.data2);
259
260 // Move the data into the queue (no copy).
261 parser->mEventQueue.push(std::move(data));
262}
263
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700264void XMLCALL XmlPullParser::endNamespaceHandler(void* userData, const char* prefix) {
265 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800266
267 parser->mEventQueue.push(EventData{
268 Event::kEndNamespace,
269 XML_GetCurrentLineNumber(parser->mParser),
270 --(parser->mDepth),
271 prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
272 parser->mNamespaceUris.top()
273 });
274 parser->mNamespaceUris.pop();
275}
276
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700277void XMLCALL XmlPullParser::commentDataHandler(void* userData, const char* comment) {
278 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800279
280 parser->mEventQueue.push(EventData{
281 Event::kComment,
282 XML_GetCurrentLineNumber(parser->mParser),
283 parser->mDepth,
284 util::utf8ToUtf16(comment)
285 });
286}
287
Adam Lesinski467f1712015-11-16 17:35:44 -0800288Maybe<StringPiece16> findAttribute(const XmlPullParser* parser, const StringPiece16& name) {
289 auto iter = parser->findAttribute(u"", name);
290 if (iter != parser->endAttributes()) {
291 return StringPiece16(util::trimWhitespace(iter->value));
292 }
293 return {};
294}
295
296Maybe<StringPiece16> findNonEmptyAttribute(const XmlPullParser* parser, const StringPiece16& name) {
297 auto iter = parser->findAttribute(u"", name);
298 if (iter != parser->endAttributes()) {
299 StringPiece16 trimmed = util::trimWhitespace(iter->value);
300 if (!trimmed.empty()) {
301 return trimmed;
302 }
303 }
304 return {};
305}
306
307} // namespace xml
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800308} // namespace aapt