• 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/Util.h"
21 #include "xml/XmlPullParser.h"
22 #include "xml/XmlUtil.h"
23 
24 using ::aapt::io::InputStream;
25 using ::android::StringPiece;
26 
27 namespace aapt {
28 namespace xml {
29 
30 constexpr char kXmlNamespaceSep = 1;
31 
XmlPullParser(InputStream * in)32 XmlPullParser::XmlPullParser(InputStream* 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   XML_SetCdataSectionHandler(parser_, StartCdataSectionHandler, EndCdataSectionHandler);
41   event_queue_.push(EventData{Event::kStartDocument, 0, depth_++});
42 }
43 
~XmlPullParser()44 XmlPullParser::~XmlPullParser() {
45   XML_ParserFree(parser_);
46 }
47 
Next()48 XmlPullParser::Event XmlPullParser::Next() {
49   const Event currentEvent = event();
50   if (currentEvent == Event::kBadDocument || currentEvent == Event::kEndDocument) {
51     return currentEvent;
52   }
53 
54   event_queue_.pop();
55   while (event_queue_.empty()) {
56     const char* buffer = nullptr;
57     size_t buffer_size = 0;
58     bool done = false;
59     if (!in_->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
60       if (in_->HadError()) {
61         error_ = in_->GetError();
62         event_queue_.push(EventData{Event::kBadDocument});
63         break;
64       }
65 
66       done = true;
67     }
68 
69     if (XML_Parse(parser_, buffer, buffer_size, done) == XML_STATUS_ERROR) {
70       error_ = XML_ErrorString(XML_GetErrorCode(parser_));
71       event_queue_.push(EventData{Event::kBadDocument});
72       break;
73     }
74 
75     if (done) {
76       event_queue_.push(EventData{Event::kEndDocument, 0, 0});
77     }
78   }
79 
80   Event next_event = event();
81 
82   // Record namespace prefixes and package names so that we can do our own
83   // handling of references that use namespace aliases.
84   if (next_event == Event::kStartNamespace ||
85       next_event == Event::kEndNamespace) {
86     std::optional<ExtractedPackage> result = ExtractPackageFromNamespace(namespace_uri());
87     if (next_event == Event::kStartNamespace) {
88       if (result) {
89         package_aliases_.emplace_back(
90             PackageDecl{namespace_prefix(), std::move(result.value())});
91       }
92     } else {
93       if (result) {
94         package_aliases_.pop_back();
95       }
96     }
97   }
98 
99   return next_event;
100 }
101 
event() const102 XmlPullParser::Event XmlPullParser::event() const {
103   return event_queue_.front().event;
104 }
105 
error() const106 const std::string& XmlPullParser::error() const { return error_; }
107 
comment() const108 const std::string& XmlPullParser::comment() const {
109   return event_queue_.front().data1;
110 }
111 
line_number() const112 size_t XmlPullParser::line_number() const {
113   return event_queue_.front().line_number;
114 }
115 
depth() const116 size_t XmlPullParser::depth() const { return event_queue_.front().depth; }
117 
text() const118 const std::string& XmlPullParser::text() const {
119   if (event() != Event::kText) {
120     return empty_;
121   }
122   return event_queue_.front().data1;
123 }
124 
namespace_prefix() const125 const std::string& XmlPullParser::namespace_prefix() const {
126   const Event current_event = event();
127   if (current_event != Event::kStartNamespace &&
128       current_event != Event::kEndNamespace) {
129     return empty_;
130   }
131   return event_queue_.front().data1;
132 }
133 
namespace_uri() const134 const std::string& XmlPullParser::namespace_uri() const {
135   const Event current_event = event();
136   if (current_event != Event::kStartNamespace &&
137       current_event != Event::kEndNamespace) {
138     return empty_;
139   }
140   return event_queue_.front().data2;
141 }
142 
TransformPackageAlias(const StringPiece & alias) const143 std::optional<ExtractedPackage> XmlPullParser::TransformPackageAlias(
144     const StringPiece& alias) const {
145   if (alias.empty()) {
146     return ExtractedPackage{{}, false /*private*/};
147   }
148 
149   const auto end_iter = package_aliases_.rend();
150   for (auto iter = package_aliases_.rbegin(); iter != end_iter; ++iter) {
151     if (alias == iter->prefix) {
152       if (iter->package.package.empty()) {
153         return ExtractedPackage{{}, iter->package.private_namespace};
154       }
155       return iter->package;
156     }
157   }
158   return {};
159 }
160 
element_namespace() const161 const std::string& XmlPullParser::element_namespace() const {
162   const Event current_event = event();
163   if (current_event != Event::kStartElement &&
164       current_event != Event::kEndElement) {
165     return empty_;
166   }
167   return event_queue_.front().data1;
168 }
169 
element_name() const170 const std::string& XmlPullParser::element_name() const {
171   const Event current_event = event();
172   if (current_event != Event::kStartElement &&
173       current_event != Event::kEndElement) {
174     return empty_;
175   }
176   return event_queue_.front().data2;
177 }
178 
package_decls() const179 const std::vector<XmlPullParser::PackageDecl>& XmlPullParser::package_decls() const {
180   return package_aliases_;
181 }
182 
begin_attributes() const183 XmlPullParser::const_iterator XmlPullParser::begin_attributes() const {
184   return event_queue_.front().attributes.begin();
185 }
186 
end_attributes() const187 XmlPullParser::const_iterator XmlPullParser::end_attributes() const {
188   return event_queue_.front().attributes.end();
189 }
190 
attribute_count() const191 size_t XmlPullParser::attribute_count() const {
192   if (event() != Event::kStartElement) {
193     return 0;
194   }
195   return event_queue_.front().attributes.size();
196 }
197 
198 /**
199  * Extracts the namespace and name of an expanded element or attribute name.
200  */
SplitName(const char * name,std::string * out_ns,std::string * out_name)201 static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
202   const char* p = name;
203   while (*p != 0 && *p != kXmlNamespaceSep) {
204     p++;
205   }
206 
207   if (*p == 0) {
208     out_ns->clear();
209     out_name->assign(name);
210   } else {
211     out_ns->assign(name, (p - name));
212     out_name->assign(p + 1);
213   }
214 }
215 
StartNamespaceHandler(void * user_data,const char * prefix,const char * uri)216 void XMLCALL XmlPullParser::StartNamespaceHandler(void* user_data,
217                                                   const char* prefix,
218                                                   const char* uri) {
219   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
220   std::string namespace_uri = uri != nullptr ? uri : std::string();
221   parser->namespace_uris_.push(namespace_uri);
222   parser->event_queue_.push(
223       EventData{Event::kStartNamespace,
224                 XML_GetCurrentLineNumber(parser->parser_), parser->depth_++,
225                 prefix != nullptr ? prefix : std::string(), namespace_uri});
226 }
227 
StartElementHandler(void * user_data,const char * name,const char ** attrs)228 void XMLCALL XmlPullParser::StartElementHandler(void* user_data,
229                                                 const char* name,
230                                                 const char** attrs) {
231   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
232 
233   EventData data = {Event::kStartElement,
234                     XML_GetCurrentLineNumber(parser->parser_),
235                     parser->depth_++};
236   SplitName(name, &data.data1, &data.data2);
237 
238   while (*attrs) {
239     Attribute attribute;
240     SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
241     attribute.value = *attrs++;
242 
243     // Insert in sorted order.
244     auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(),
245                                  attribute);
246     data.attributes.insert(iter, std::move(attribute));
247   }
248 
249   // Move the structure into the queue (no copy).
250   parser->event_queue_.push(std::move(data));
251 }
252 
CharacterDataHandler(void * user_data,const char * s,int len)253 void XMLCALL XmlPullParser::CharacterDataHandler(void* user_data, const char* s,
254                                                  int len) {
255   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
256 
257   parser->event_queue_.push(EventData{Event::kText, XML_GetCurrentLineNumber(parser->parser_),
258                                       parser->depth_, std::string(s, len)});
259 }
260 
EndElementHandler(void * user_data,const char * name)261 void XMLCALL XmlPullParser::EndElementHandler(void* user_data,
262                                               const char* name) {
263   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
264 
265   EventData data = {Event::kEndElement,
266                     XML_GetCurrentLineNumber(parser->parser_),
267                     --(parser->depth_)};
268   SplitName(name, &data.data1, &data.data2);
269 
270   // Move the data into the queue (no copy).
271   parser->event_queue_.push(std::move(data));
272 }
273 
EndNamespaceHandler(void * user_data,const char * prefix)274 void XMLCALL XmlPullParser::EndNamespaceHandler(void* user_data,
275                                                 const char* prefix) {
276   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
277 
278   parser->event_queue_.push(
279       EventData{Event::kEndNamespace, XML_GetCurrentLineNumber(parser->parser_),
280                 --(parser->depth_), prefix != nullptr ? prefix : std::string(),
281                 parser->namespace_uris_.top()});
282   parser->namespace_uris_.pop();
283 }
284 
CommentDataHandler(void * user_data,const char * comment)285 void XMLCALL XmlPullParser::CommentDataHandler(void* user_data,
286                                                const char* comment) {
287   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
288 
289   parser->event_queue_.push(EventData{Event::kComment,
290                                       XML_GetCurrentLineNumber(parser->parser_),
291                                       parser->depth_, comment});
292 }
293 
StartCdataSectionHandler(void * user_data)294 void XMLCALL XmlPullParser::StartCdataSectionHandler(void* user_data) {
295   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
296 
297   parser->event_queue_.push(EventData{Event::kCdataStart,
298                                       XML_GetCurrentLineNumber(parser->parser_),
299                                       parser->depth_ });
300 }
301 
EndCdataSectionHandler(void * user_data)302 void XMLCALL XmlPullParser::EndCdataSectionHandler(void* user_data) {
303   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
304 
305   parser->event_queue_.push(EventData{Event::kCdataEnd,
306                                       XML_GetCurrentLineNumber(parser->parser_),
307                                       parser->depth_ });
308 }
309 
FindAttribute(const XmlPullParser * parser,const StringPiece & name)310 std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, const StringPiece& name) {
311   auto iter = parser->FindAttribute("", name);
312   if (iter != parser->end_attributes()) {
313     return StringPiece(util::TrimWhitespace(iter->value));
314   }
315   return {};
316 }
317 
FindNonEmptyAttribute(const XmlPullParser * parser,const StringPiece & name)318 std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
319                                                  const StringPiece& name) {
320   auto iter = parser->FindAttribute("", name);
321   if (iter != parser->end_attributes()) {
322     StringPiece trimmed = util::TrimWhitespace(iter->value);
323     if (!trimmed.empty()) {
324       return trimmed;
325     }
326   }
327   return {};
328 }
329 
330 }  // namespace xml
331 }  // namespace aapt
332