blob: cff935c10aaef15862bb6c1d81ea2295c07a40cc [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"
19#include "XmlPullParser.h"
20
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080021#include <iostream>
22#include <string>
23
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024namespace aapt {
25
26constexpr char kXmlNamespaceSep = 1;
27
Adam Lesinski1ab598f2015-08-14 14:26:04 -070028XmlPullParser::XmlPullParser(std::istream& in) : mIn(in), mEmpty(), mDepth(0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080029 mParser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
30 XML_SetUserData(mParser, this);
31 XML_SetElementHandler(mParser, startElementHandler, endElementHandler);
32 XML_SetNamespaceDeclHandler(mParser, startNamespaceHandler, endNamespaceHandler);
33 XML_SetCharacterDataHandler(mParser, characterDataHandler);
34 XML_SetCommentHandler(mParser, commentDataHandler);
35 mEventQueue.push(EventData{ Event::kStartDocument, 0, mDepth++ });
36}
37
Adam Lesinski1ab598f2015-08-14 14:26:04 -070038XmlPullParser::~XmlPullParser() {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080039 XML_ParserFree(mParser);
40}
41
Adam Lesinski1ab598f2015-08-14 14:26:04 -070042XmlPullParser::Event XmlPullParser::next() {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080043 const Event currentEvent = getEvent();
44 if (currentEvent == Event::kBadDocument || currentEvent == Event::kEndDocument) {
45 return currentEvent;
46 }
47
48 mEventQueue.pop();
49 while (mEventQueue.empty()) {
50 mIn.read(mBuffer, sizeof(mBuffer) / sizeof(*mBuffer));
51
52 const bool done = mIn.eof();
53 if (mIn.bad() && !done) {
54 mLastError = strerror(errno);
55 mEventQueue.push(EventData{ Event::kBadDocument });
56 continue;
57 }
58
59 if (XML_Parse(mParser, mBuffer, mIn.gcount(), done) == XML_STATUS_ERROR) {
60 mLastError = XML_ErrorString(XML_GetErrorCode(mParser));
61 mEventQueue.push(EventData{ Event::kBadDocument });
62 continue;
63 }
64
65 if (done) {
66 mEventQueue.push(EventData{ Event::kEndDocument, 0, 0 });
67 }
68 }
69
Adam Lesinski24aad162015-04-24 19:19:30 -070070 Event event = getEvent();
71
72 // Record namespace prefixes and package names so that we can do our own
73 // handling of references that use namespace aliases.
74 if (event == Event::kStartNamespace || event == Event::kEndNamespace) {
75 Maybe<std::u16string> result = util::extractPackageFromNamespace(getNamespaceUri());
76 if (event == Event::kStartNamespace) {
77 if (result) {
78 mPackageAliases.emplace_back(getNamespacePrefix(), result.value());
79 }
80 } else {
81 if (result) {
82 assert(mPackageAliases.back().second == result.value());
83 mPackageAliases.pop_back();
84 }
85 }
86 }
87
88 return event;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080089}
90
Adam Lesinski1ab598f2015-08-14 14:26:04 -070091XmlPullParser::Event XmlPullParser::getEvent() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080092 return mEventQueue.front().event;
93}
94
Adam Lesinski1ab598f2015-08-14 14:26:04 -070095const std::string& XmlPullParser::getLastError() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080096 return mLastError;
97}
98
Adam Lesinski1ab598f2015-08-14 14:26:04 -070099const std::u16string& XmlPullParser::getComment() const {
Adam Lesinskie78fd612015-10-22 12:48:43 -0700100 return mEventQueue.front().data1;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800101}
102
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700103size_t XmlPullParser::getLineNumber() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800104 return mEventQueue.front().lineNumber;
105}
106
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700107size_t XmlPullParser::getDepth() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800108 return mEventQueue.front().depth;
109}
110
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700111const std::u16string& XmlPullParser::getText() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800112 if (getEvent() != Event::kText) {
113 return mEmpty;
114 }
115 return mEventQueue.front().data1;
116}
117
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700118const std::u16string& XmlPullParser::getNamespacePrefix() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800119 const Event currentEvent = getEvent();
120 if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
121 return mEmpty;
122 }
123 return mEventQueue.front().data1;
124}
125
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700126const std::u16string& XmlPullParser::getNamespaceUri() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800127 const Event currentEvent = getEvent();
128 if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
129 return mEmpty;
130 }
131 return mEventQueue.front().data2;
132}
133
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700134Maybe<ResourceName> XmlPullParser::transformPackage(
135 const ResourceName& name, const StringPiece16& localPackage) const {
136 if (name.package.empty()) {
137 return ResourceName{ localPackage.toString(), name.type, name.entry };
138 }
139
Adam Lesinski24aad162015-04-24 19:19:30 -0700140 const auto endIter = mPackageAliases.rend();
141 for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700142 if (name.package == iter->first) {
Adam Lesinski24aad162015-04-24 19:19:30 -0700143 if (iter->second.empty()) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700144 return ResourceName{ localPackage.toString(), name.type, name.entry };
Adam Lesinski24aad162015-04-24 19:19:30 -0700145 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700146 return ResourceName{ iter->second, name.type, name.entry };
Adam Lesinski24aad162015-04-24 19:19:30 -0700147 }
Adam Lesinski24aad162015-04-24 19:19:30 -0700148 }
149 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700150 return {};
Adam Lesinski24aad162015-04-24 19:19:30 -0700151}
152
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700153const std::u16string& XmlPullParser::getElementNamespace() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800154 const Event currentEvent = getEvent();
155 if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
156 return mEmpty;
157 }
158 return mEventQueue.front().data1;
159}
160
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700161const std::u16string& XmlPullParser::getElementName() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800162 const Event currentEvent = getEvent();
163 if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
164 return mEmpty;
165 }
166 return mEventQueue.front().data2;
167}
168
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700169XmlPullParser::const_iterator XmlPullParser::beginAttributes() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800170 return mEventQueue.front().attributes.begin();
171}
172
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700173XmlPullParser::const_iterator XmlPullParser::endAttributes() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800174 return mEventQueue.front().attributes.end();
175}
176
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700177size_t XmlPullParser::getAttributeCount() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800178 if (getEvent() != Event::kStartElement) {
179 return 0;
180 }
181 return mEventQueue.front().attributes.size();
182}
183
184/**
185 * Extracts the namespace and name of an expanded element or attribute name.
186 */
187static void splitName(const char* name, std::u16string& outNs, std::u16string& outName) {
188 const char* p = name;
189 while (*p != 0 && *p != kXmlNamespaceSep) {
190 p++;
191 }
192
193 if (*p == 0) {
194 outNs = std::u16string();
195 outName = util::utf8ToUtf16(name);
196 } else {
197 outNs = util::utf8ToUtf16(StringPiece(name, (p - name)));
198 outName = util::utf8ToUtf16(p + 1);
199 }
200}
201
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700202void XMLCALL XmlPullParser::startNamespaceHandler(void* userData, const char* prefix,
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800203 const char* uri) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700204 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800205 std::u16string namespaceUri = uri != nullptr ? util::utf8ToUtf16(uri) : std::u16string();
206 parser->mNamespaceUris.push(namespaceUri);
207 parser->mEventQueue.push(EventData{
208 Event::kStartNamespace,
209 XML_GetCurrentLineNumber(parser->mParser),
210 parser->mDepth++,
211 prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
212 namespaceUri
213 });
214}
215
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700216void XMLCALL XmlPullParser::startElementHandler(void* userData, const char* name,
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800217 const char** attrs) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700218 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800219
220 EventData data = {
221 Event::kStartElement, XML_GetCurrentLineNumber(parser->mParser), parser->mDepth++
222 };
223 splitName(name, data.data1, data.data2);
224
225 while (*attrs) {
226 Attribute attribute;
227 splitName(*attrs++, attribute.namespaceUri, attribute.name);
228 attribute.value = util::utf8ToUtf16(*attrs++);
229
230 // Insert in sorted order.
231 auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(), attribute);
232 data.attributes.insert(iter, std::move(attribute));
233 }
234
235 // Move the structure into the queue (no copy).
236 parser->mEventQueue.push(std::move(data));
237}
238
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700239void XMLCALL XmlPullParser::characterDataHandler(void* userData, const char* s, int len) {
240 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800241
242 parser->mEventQueue.push(EventData{
243 Event::kText,
244 XML_GetCurrentLineNumber(parser->mParser),
245 parser->mDepth,
246 util::utf8ToUtf16(StringPiece(s, len))
247 });
248}
249
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700250void XMLCALL XmlPullParser::endElementHandler(void* userData, const char* name) {
251 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800252
253 EventData data = {
254 Event::kEndElement, XML_GetCurrentLineNumber(parser->mParser), --(parser->mDepth)
255 };
256 splitName(name, data.data1, data.data2);
257
258 // Move the data into the queue (no copy).
259 parser->mEventQueue.push(std::move(data));
260}
261
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700262void XMLCALL XmlPullParser::endNamespaceHandler(void* userData, const char* prefix) {
263 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800264
265 parser->mEventQueue.push(EventData{
266 Event::kEndNamespace,
267 XML_GetCurrentLineNumber(parser->mParser),
268 --(parser->mDepth),
269 prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
270 parser->mNamespaceUris.top()
271 });
272 parser->mNamespaceUris.pop();
273}
274
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700275void XMLCALL XmlPullParser::commentDataHandler(void* userData, const char* comment) {
276 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800277
278 parser->mEventQueue.push(EventData{
279 Event::kComment,
280 XML_GetCurrentLineNumber(parser->mParser),
281 parser->mDepth,
282 util::utf8ToUtf16(comment)
283 });
284}
285
286} // namespace aapt