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