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( 145 const StringPiece& alias, const StringPiece& local_package) const { 146 if (alias.empty()) { 147 return ExtractedPackage{local_package.to_string(), 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{local_package.to_string(), 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 Maybe<StringPiece> FindAttribute(const XmlPullParser* parser, 292 const StringPiece& name) { 293 auto iter = parser->FindAttribute("", name); 294 if (iter != parser->end_attributes()) { 295 return StringPiece(util::TrimWhitespace(iter->value)); 296 } 297 return {}; 298 } 299 300 Maybe<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, 301 const StringPiece& name) { 302 auto iter = parser->FindAttribute("", name); 303 if (iter != parser->end_attributes()) { 304 StringPiece trimmed = util::TrimWhitespace(iter->value); 305 if (!trimmed.empty()) { 306 return trimmed; 307 } 308 } 309 return {}; 310 } 311 312 } // namespace xml 313 } // namespace aapt 314