1 /*
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 #include "util/Maybe.h"
18 #include "util/Util.h"
19 #include "xml/XmlPullParser.h"
20 #include "xml/XmlUtil.h"
21 
22 #include <iostream>
23 #include <string>
24 
25 namespace aapt {
26 namespace xml {
27 
28 constexpr char kXmlNamespaceSep = 1;
29 
XmlPullParser(std::istream & in)30 XmlPullParser::XmlPullParser(std::istream& in) : mIn(in), mEmpty(), mDepth(0) {
31     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 
~XmlPullParser()40 XmlPullParser::~XmlPullParser() {
41     XML_ParserFree(mParser);
42 }
43 
next()44 XmlPullParser::Event XmlPullParser::next() {
45     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 
72     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) {
77         Maybe<ExtractedPackage> result = extractPackageFromNamespace(getNamespaceUri());
78         if (event == Event::kStartNamespace) {
79             if (result) {
80                 mPackageAliases.emplace_back(
81                         PackageDecl{ getNamespacePrefix(), std::move(result.value()) });
82             }
83         } else {
84             if (result) {
85                 mPackageAliases.pop_back();
86             }
87         }
88     }
89 
90     return event;
91 }
92 
getEvent() const93 XmlPullParser::Event XmlPullParser::getEvent() const {
94     return mEventQueue.front().event;
95 }
96 
getLastError() const97 const std::string& XmlPullParser::getLastError() const {
98     return mLastError;
99 }
100 
getComment() const101 const std::u16string& XmlPullParser::getComment() const {
102     return mEventQueue.front().data1;
103 }
104 
getLineNumber() const105 size_t XmlPullParser::getLineNumber() const {
106     return mEventQueue.front().lineNumber;
107 }
108 
getDepth() const109 size_t XmlPullParser::getDepth() const {
110     return mEventQueue.front().depth;
111 }
112 
getText() const113 const std::u16string& XmlPullParser::getText() const {
114     if (getEvent() != Event::kText) {
115         return mEmpty;
116     }
117     return mEventQueue.front().data1;
118 }
119 
getNamespacePrefix() const120 const std::u16string& XmlPullParser::getNamespacePrefix() const {
121     const Event currentEvent = getEvent();
122     if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
123         return mEmpty;
124     }
125     return mEventQueue.front().data1;
126 }
127 
getNamespaceUri() const128 const std::u16string& XmlPullParser::getNamespaceUri() const {
129     const Event currentEvent = getEvent();
130     if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
131         return mEmpty;
132     }
133     return mEventQueue.front().data2;
134 }
135 
transformPackageAlias(const StringPiece16 & alias,const StringPiece16 & localPackage) const136 Maybe<ExtractedPackage> XmlPullParser::transformPackageAlias(
137         const StringPiece16& alias, const StringPiece16& localPackage) const {
138     if (alias.empty()) {
139         return ExtractedPackage{ localPackage.toString(), false /* private */ };
140     }
141 
142     const auto endIter = mPackageAliases.rend();
143     for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) {
144         if (alias == iter->prefix) {
145             if (iter->package.package.empty()) {
146                 return ExtractedPackage{ localPackage.toString(),
147                                          iter->package.privateNamespace };
148             }
149             return iter->package;
150         }
151     }
152     return {};
153 }
154 
getElementNamespace() const155 const std::u16string& XmlPullParser::getElementNamespace() const {
156     const Event currentEvent = getEvent();
157     if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
158         return mEmpty;
159     }
160     return mEventQueue.front().data1;
161 }
162 
getElementName() const163 const std::u16string& XmlPullParser::getElementName() const {
164     const Event currentEvent = getEvent();
165     if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
166         return mEmpty;
167     }
168     return mEventQueue.front().data2;
169 }
170 
beginAttributes() const171 XmlPullParser::const_iterator XmlPullParser::beginAttributes() const {
172     return mEventQueue.front().attributes.begin();
173 }
174 
endAttributes() const175 XmlPullParser::const_iterator XmlPullParser::endAttributes() const {
176     return mEventQueue.front().attributes.end();
177 }
178 
getAttributeCount() const179 size_t XmlPullParser::getAttributeCount() const {
180     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  */
splitName(const char * name,std::u16string & outNs,std::u16string & outName)189 static 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 
startNamespaceHandler(void * userData,const char * prefix,const char * uri)204 void XMLCALL XmlPullParser::startNamespaceHandler(void* userData, const char* prefix,
205         const char* uri) {
206     XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
207     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 
startElementHandler(void * userData,const char * name,const char ** attrs)218 void XMLCALL XmlPullParser::startElementHandler(void* userData, const char* name,
219         const char** attrs) {
220     XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
221 
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 
characterDataHandler(void * userData,const char * s,int len)241 void XMLCALL XmlPullParser::characterDataHandler(void* userData, const char* s, int len) {
242     XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
243 
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 
endElementHandler(void * userData,const char * name)252 void XMLCALL XmlPullParser::endElementHandler(void* userData, const char* name) {
253     XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
254 
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 
endNamespaceHandler(void * userData,const char * prefix)264 void XMLCALL XmlPullParser::endNamespaceHandler(void* userData, const char* prefix) {
265     XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
266 
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 
commentDataHandler(void * userData,const char * comment)277 void XMLCALL XmlPullParser::commentDataHandler(void* userData, const char* comment) {
278     XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData);
279 
280     parser->mEventQueue.push(EventData{
281             Event::kComment,
282             XML_GetCurrentLineNumber(parser->mParser),
283             parser->mDepth,
284             util::utf8ToUtf16(comment)
285     });
286 }
287 
findAttribute(const XmlPullParser * parser,const StringPiece16 & name)288 Maybe<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 
findNonEmptyAttribute(const XmlPullParser * parser,const StringPiece16 & name)296 Maybe<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
308 } // namespace aapt
309