• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <iostream>
18 #include <string>
19 
20 #include "util/Maybe.h"
21 #include "util/Util.h"
22 #include "xml/XmlPullParser.h"
23 #include "xml/XmlUtil.h"
24 
25 using android::StringPiece;
26 
27 namespace aapt {
28 namespace xml {
29 
30 constexpr char kXmlNamespaceSep = 1;
31 
XmlPullParser(std::istream & in)32 XmlPullParser::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_++});
41 }
42 
~XmlPullParser()43 XmlPullParser::~XmlPullParser() { XML_ParserFree(parser_); }
44 
Next()45 XmlPullParser::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;
61     }
62 
63     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;
67     }
68 
69     if (done) {
70       event_queue_.push(EventData{Event::kEndDocument, 0, 0});
71     }
72   }
73 
74   Event next_event = event();
75 
76   // 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       }
91     }
92   }
93 
94   return next_event;
95 }
96 
event() const97 XmlPullParser::Event XmlPullParser::event() const {
98   return event_queue_.front().event;
99 }
100 
error() const101 const std::string& XmlPullParser::error() const { return error_; }
102 
comment() const103 const std::string& XmlPullParser::comment() const {
104   return event_queue_.front().data1;
105 }
106 
line_number() const107 size_t XmlPullParser::line_number() const {
108   return event_queue_.front().line_number;
109 }
110 
depth() const111 size_t XmlPullParser::depth() const { return event_queue_.front().depth; }
112 
text() const113 const std::string& XmlPullParser::text() const {
114   if (event() != Event::kText) {
115     return empty_;
116   }
117   return event_queue_.front().data1;
118 }
119 
namespace_prefix() const120 const 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 
namespace_uri() const129 const 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 
TransformPackageAlias(const StringPiece & alias,const StringPiece & local_package) const138 Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(
139     const StringPiece& alias, const StringPiece& local_package) const {
140   if (alias.empty()) {
141     return ExtractedPackage{local_package.to_string(), false /* private */};
142   }
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()) {
148         return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
149       }
150       return iter->package;
151     }
152   }
153   return {};
154 }
155 
element_namespace() const156 const 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;
163 }
164 
element_name() const165 const 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;
172 }
173 
begin_attributes() const174 XmlPullParser::const_iterator XmlPullParser::begin_attributes() const {
175   return event_queue_.front().attributes.begin();
176 }
177 
end_attributes() const178 XmlPullParser::const_iterator XmlPullParser::end_attributes() const {
179   return event_queue_.front().attributes.end();
180 }
181 
attribute_count() const182 size_t XmlPullParser::attribute_count() const {
183   if (event() != Event::kStartElement) {
184     return 0;
185   }
186   return event_queue_.front().attributes.size();
187 }
188 
189 /**
190  * Extracts the namespace and name of an expanded element or attribute name.
191  */
SplitName(const char * name,std::string * out_ns,std::string * out_name)192 static void SplitName(const char* name, std::string* out_ns, 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->clear();
200     out_name->assign(name);
201   } else {
202     out_ns->assign(name, (p - name));
203     out_name->assign(p + 1);
204   }
205 }
206 
StartNamespaceHandler(void * user_data,const char * prefix,const char * uri)207 void 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 
StartElementHandler(void * user_data,const char * name,const char ** attrs)219 void 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 
CharacterDataHandler(void * user_data,const char * s,int len)244 void 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(EventData{Event::kText, XML_GetCurrentLineNumber(parser->parser_),
249                                       parser->depth_, std::string(s, len)});
250 }
251 
EndElementHandler(void * user_data,const char * name)252 void 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_)};
259   SplitName(name, &data.data1, &data.data2);
260 
261   // Move the data into the queue (no copy).
262   parser->event_queue_.push(std::move(data));
263 }
264 
EndNamespaceHandler(void * user_data,const char * prefix)265 void 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 
CommentDataHandler(void * user_data,const char * comment)276 void 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 
FindAttribute(const XmlPullParser * parser,const StringPiece & name)285 Maybe<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 
FindNonEmptyAttribute(const XmlPullParser * parser,const StringPiece & name)294 Maybe<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;
301     }
302   }
303   return {};
304 }
305 
306 }  // namespace xml
307 }  // namespace aapt
308