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 event_queue_.push(EventData{Event::kStartDocument, 0, depth_++}); 42 } 43 44 XmlPullParser::~XmlPullParser() { 45 XML_ParserFree(parser_); 46 } 47 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 Maybe<ExtractedPackage> result = 87 ExtractPackageFromNamespace(namespace_uri()); 88 if (next_event == Event::kStartNamespace) { 89 if (result) { 90 package_aliases_.emplace_back( 91 PackageDecl{namespace_prefix(), std::move(result.value())}); 92 } 93 } else { 94 if (result) { 95 package_aliases_.pop_back(); 96 } 97 } 98 } 99 100 return next_event; 101 } 102 103 XmlPullParser::Event XmlPullParser::event() const { 104 return event_queue_.front().event; 105 } 106 107 const std::string& XmlPullParser::error() const { return error_; } 108 109 const std::string& XmlPullParser::comment() const { 110 return event_queue_.front().data1; 111 } 112 113 size_t XmlPullParser::line_number() const { 114 return event_queue_.front().line_number; 115 } 116 117 size_t XmlPullParser::depth() const { return event_queue_.front().depth; } 118 119 const std::string& XmlPullParser::text() const { 120 if (event() != Event::kText) { 121 return empty_; 122 } 123 return event_queue_.front().data1; 124 } 125 126 const std::string& XmlPullParser::namespace_prefix() const { 127 const Event current_event = event(); 128 if (current_event != Event::kStartNamespace && 129 current_event != Event::kEndNamespace) { 130 return empty_; 131 } 132 return event_queue_.front().data1; 133 } 134 135 const std::string& XmlPullParser::namespace_uri() const { 136 const Event current_event = event(); 137 if (current_event != Event::kStartNamespace && 138 current_event != Event::kEndNamespace) { 139 return empty_; 140 } 141 return event_queue_.front().data2; 142 } 143 144 Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(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 161 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 170 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 179 XmlPullParser::const_iterator XmlPullParser::begin_attributes() const { 180 return event_queue_.front().attributes.begin(); 181 } 182 183 XmlPullParser::const_iterator XmlPullParser::end_attributes() const { 184 return event_queue_.front().attributes.end(); 185 } 186 187 size_t XmlPullParser::attribute_count() const { 188 if (event() != Event::kStartElement) { 189 return 0; 190 } 191 return event_queue_.front().attributes.size(); 192 } 193 194 /** 195 * Extracts the namespace and name of an expanded element or attribute name. 196 */ 197 static void SplitName(const char* name, std::string* out_ns, std::string* out_name) { 198 const char* p = name; 199 while (*p != 0 && *p != kXmlNamespaceSep) { 200 p++; 201 } 202 203 if (*p == 0) { 204 out_ns->clear(); 205 out_name->assign(name); 206 } else { 207 out_ns->assign(name, (p - name)); 208 out_name->assign(p + 1); 209 } 210 } 211 212 void XMLCALL XmlPullParser::StartNamespaceHandler(void* user_data, 213 const char* prefix, 214 const char* uri) { 215 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data); 216 std::string namespace_uri = uri != nullptr ? uri : std::string(); 217 parser->namespace_uris_.push(namespace_uri); 218 parser->event_queue_.push( 219 EventData{Event::kStartNamespace, 220 XML_GetCurrentLineNumber(parser->parser_), parser->depth_++, 221 prefix != nullptr ? prefix : std::string(), namespace_uri}); 222 } 223 224 void XMLCALL XmlPullParser::StartElementHandler(void* user_data, 225 const char* name, 226 const char** attrs) { 227 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data); 228 229 EventData data = {Event::kStartElement, 230 XML_GetCurrentLineNumber(parser->parser_), 231 parser->depth_++}; 232 SplitName(name, &data.data1, &data.data2); 233 234 while (*attrs) { 235 Attribute attribute; 236 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name); 237 attribute.value = *attrs++; 238 239 // Insert in sorted order. 240 auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(), 241 attribute); 242 data.attributes.insert(iter, std::move(attribute)); 243 } 244 245 // Move the structure into the queue (no copy). 246 parser->event_queue_.push(std::move(data)); 247 } 248 249 void XMLCALL XmlPullParser::CharacterDataHandler(void* user_data, const char* s, 250 int len) { 251 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data); 252 253 parser->event_queue_.push(EventData{Event::kText, XML_GetCurrentLineNumber(parser->parser_), 254 parser->depth_, std::string(s, len)}); 255 } 256 257 void XMLCALL XmlPullParser::EndElementHandler(void* user_data, 258 const char* name) { 259 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data); 260 261 EventData data = {Event::kEndElement, 262 XML_GetCurrentLineNumber(parser->parser_), 263 --(parser->depth_)}; 264 SplitName(name, &data.data1, &data.data2); 265 266 // Move the data into the queue (no copy). 267 parser->event_queue_.push(std::move(data)); 268 } 269 270 void XMLCALL XmlPullParser::EndNamespaceHandler(void* user_data, 271 const char* prefix) { 272 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data); 273 274 parser->event_queue_.push( 275 EventData{Event::kEndNamespace, XML_GetCurrentLineNumber(parser->parser_), 276 --(parser->depth_), prefix != nullptr ? prefix : std::string(), 277 parser->namespace_uris_.top()}); 278 parser->namespace_uris_.pop(); 279 } 280 281 void XMLCALL XmlPullParser::CommentDataHandler(void* user_data, 282 const char* comment) { 283 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data); 284 285 parser->event_queue_.push(EventData{Event::kComment, 286 XML_GetCurrentLineNumber(parser->parser_), 287 parser->depth_, comment}); 288 } 289 290 Maybe<StringPiece> FindAttribute(const XmlPullParser* parser, 291 const StringPiece& name) { 292 auto iter = parser->FindAttribute("", name); 293 if (iter != parser->end_attributes()) { 294 return StringPiece(util::TrimWhitespace(iter->value)); 295 } 296 return {}; 297 } 298 299 Maybe<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, 300 const StringPiece& name) { 301 auto iter = parser->FindAttribute("", name); 302 if (iter != parser->end_attributes()) { 303 StringPiece trimmed = util::TrimWhitespace(iter->value); 304 if (!trimmed.empty()) { 305 return trimmed; 306 } 307 } 308 return {}; 309 } 310 311 } // namespace xml 312 } // namespace aapt 313