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 "util/Maybe.h" 18 #include "util/Util.h" 19 #include "xml/XmlPullParser.h" 20 #include "xml/XmlUtil.h" 21 22 #include <iostream> 23 #include <string> 24 25 namespace aapt { 26 namespace xml { 27 28 constexpr char kXmlNamespaceSep = 1; 29 30 XmlPullParser::XmlPullParser(std::istream& in) : mIn(in), mEmpty(), mDepth(0) { 31 mParser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep); 32 XML_SetUserData(mParser, this); 33 XML_SetElementHandler(mParser, startElementHandler, endElementHandler); 34 XML_SetNamespaceDeclHandler(mParser, startNamespaceHandler, endNamespaceHandler); 35 XML_SetCharacterDataHandler(mParser, characterDataHandler); 36 XML_SetCommentHandler(mParser, commentDataHandler); 37 mEventQueue.push(EventData{ Event::kStartDocument, 0, mDepth++ }); 38 } 39 40 XmlPullParser::~XmlPullParser() { 41 XML_ParserFree(mParser); 42 } 43 44 XmlPullParser::Event XmlPullParser::next() { 45 const Event currentEvent = getEvent(); 46 if (currentEvent == Event::kBadDocument || currentEvent == Event::kEndDocument) { 47 return currentEvent; 48 } 49 50 mEventQueue.pop(); 51 while (mEventQueue.empty()) { 52 mIn.read(mBuffer, sizeof(mBuffer) / sizeof(*mBuffer)); 53 54 const bool done = mIn.eof(); 55 if (mIn.bad() && !done) { 56 mLastError = strerror(errno); 57 mEventQueue.push(EventData{ Event::kBadDocument }); 58 continue; 59 } 60 61 if (XML_Parse(mParser, mBuffer, mIn.gcount(), done) == XML_STATUS_ERROR) { 62 mLastError = XML_ErrorString(XML_GetErrorCode(mParser)); 63 mEventQueue.push(EventData{ Event::kBadDocument }); 64 continue; 65 } 66 67 if (done) { 68 mEventQueue.push(EventData{ Event::kEndDocument, 0, 0 }); 69 } 70 } 71 72 Event event = getEvent(); 73 74 // Record namespace prefixes and package names so that we can do our own 75 // handling of references that use namespace aliases. 76 if (event == Event::kStartNamespace || event == Event::kEndNamespace) { 77 Maybe<ExtractedPackage> result = extractPackageFromNamespace(getNamespaceUri()); 78 if (event == Event::kStartNamespace) { 79 if (result) { 80 mPackageAliases.emplace_back( 81 PackageDecl{ getNamespacePrefix(), std::move(result.value()) }); 82 } 83 } else { 84 if (result) { 85 mPackageAliases.pop_back(); 86 } 87 } 88 } 89 90 return event; 91 } 92 93 XmlPullParser::Event XmlPullParser::getEvent() const { 94 return mEventQueue.front().event; 95 } 96 97 const std::string& XmlPullParser::getLastError() const { 98 return mLastError; 99 } 100 101 const std::u16string& XmlPullParser::getComment() const { 102 return mEventQueue.front().data1; 103 } 104 105 size_t XmlPullParser::getLineNumber() const { 106 return mEventQueue.front().lineNumber; 107 } 108 109 size_t XmlPullParser::getDepth() const { 110 return mEventQueue.front().depth; 111 } 112 113 const std::u16string& XmlPullParser::getText() const { 114 if (getEvent() != Event::kText) { 115 return mEmpty; 116 } 117 return mEventQueue.front().data1; 118 } 119 120 const std::u16string& XmlPullParser::getNamespacePrefix() const { 121 const Event currentEvent = getEvent(); 122 if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) { 123 return mEmpty; 124 } 125 return mEventQueue.front().data1; 126 } 127 128 const std::u16string& XmlPullParser::getNamespaceUri() const { 129 const Event currentEvent = getEvent(); 130 if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) { 131 return mEmpty; 132 } 133 return mEventQueue.front().data2; 134 } 135 136 Maybe<ExtractedPackage> XmlPullParser::transformPackageAlias( 137 const StringPiece16& alias, const StringPiece16& localPackage) const { 138 if (alias.empty()) { 139 return ExtractedPackage{ localPackage.toString(), false /* private */ }; 140 } 141 142 const auto endIter = mPackageAliases.rend(); 143 for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) { 144 if (alias == iter->prefix) { 145 if (iter->package.package.empty()) { 146 return ExtractedPackage{ localPackage.toString(), 147 iter->package.privateNamespace }; 148 } 149 return iter->package; 150 } 151 } 152 return {}; 153 } 154 155 const std::u16string& XmlPullParser::getElementNamespace() const { 156 const Event currentEvent = getEvent(); 157 if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) { 158 return mEmpty; 159 } 160 return mEventQueue.front().data1; 161 } 162 163 const std::u16string& XmlPullParser::getElementName() const { 164 const Event currentEvent = getEvent(); 165 if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) { 166 return mEmpty; 167 } 168 return mEventQueue.front().data2; 169 } 170 171 XmlPullParser::const_iterator XmlPullParser::beginAttributes() const { 172 return mEventQueue.front().attributes.begin(); 173 } 174 175 XmlPullParser::const_iterator XmlPullParser::endAttributes() const { 176 return mEventQueue.front().attributes.end(); 177 } 178 179 size_t XmlPullParser::getAttributeCount() const { 180 if (getEvent() != Event::kStartElement) { 181 return 0; 182 } 183 return mEventQueue.front().attributes.size(); 184 } 185 186 /** 187 * Extracts the namespace and name of an expanded element or attribute name. 188 */ 189 static void splitName(const char* name, std::u16string& outNs, std::u16string& outName) { 190 const char* p = name; 191 while (*p != 0 && *p != kXmlNamespaceSep) { 192 p++; 193 } 194 195 if (*p == 0) { 196 outNs = std::u16string(); 197 outName = util::utf8ToUtf16(name); 198 } else { 199 outNs = util::utf8ToUtf16(StringPiece(name, (p - name))); 200 outName = util::utf8ToUtf16(p + 1); 201 } 202 } 203 204 void XMLCALL XmlPullParser::startNamespaceHandler(void* userData, const char* prefix, 205 const char* uri) { 206 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); 207 std::u16string namespaceUri = uri != nullptr ? util::utf8ToUtf16(uri) : std::u16string(); 208 parser->mNamespaceUris.push(namespaceUri); 209 parser->mEventQueue.push(EventData{ 210 Event::kStartNamespace, 211 XML_GetCurrentLineNumber(parser->mParser), 212 parser->mDepth++, 213 prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(), 214 namespaceUri 215 }); 216 } 217 218 void XMLCALL XmlPullParser::startElementHandler(void* userData, const char* name, 219 const char** attrs) { 220 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); 221 222 EventData data = { 223 Event::kStartElement, XML_GetCurrentLineNumber(parser->mParser), parser->mDepth++ 224 }; 225 splitName(name, data.data1, data.data2); 226 227 while (*attrs) { 228 Attribute attribute; 229 splitName(*attrs++, attribute.namespaceUri, attribute.name); 230 attribute.value = util::utf8ToUtf16(*attrs++); 231 232 // Insert in sorted order. 233 auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(), attribute); 234 data.attributes.insert(iter, std::move(attribute)); 235 } 236 237 // Move the structure into the queue (no copy). 238 parser->mEventQueue.push(std::move(data)); 239 } 240 241 void XMLCALL XmlPullParser::characterDataHandler(void* userData, const char* s, int len) { 242 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); 243 244 parser->mEventQueue.push(EventData{ 245 Event::kText, 246 XML_GetCurrentLineNumber(parser->mParser), 247 parser->mDepth, 248 util::utf8ToUtf16(StringPiece(s, len)) 249 }); 250 } 251 252 void XMLCALL XmlPullParser::endElementHandler(void* userData, const char* name) { 253 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); 254 255 EventData data = { 256 Event::kEndElement, XML_GetCurrentLineNumber(parser->mParser), --(parser->mDepth) 257 }; 258 splitName(name, data.data1, data.data2); 259 260 // Move the data into the queue (no copy). 261 parser->mEventQueue.push(std::move(data)); 262 } 263 264 void XMLCALL XmlPullParser::endNamespaceHandler(void* userData, const char* prefix) { 265 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); 266 267 parser->mEventQueue.push(EventData{ 268 Event::kEndNamespace, 269 XML_GetCurrentLineNumber(parser->mParser), 270 --(parser->mDepth), 271 prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(), 272 parser->mNamespaceUris.top() 273 }); 274 parser->mNamespaceUris.pop(); 275 } 276 277 void XMLCALL XmlPullParser::commentDataHandler(void* userData, const char* comment) { 278 XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); 279 280 parser->mEventQueue.push(EventData{ 281 Event::kComment, 282 XML_GetCurrentLineNumber(parser->mParser), 283 parser->mDepth, 284 util::utf8ToUtf16(comment) 285 }); 286 } 287 288 Maybe<StringPiece16> findAttribute(const XmlPullParser* parser, const StringPiece16& name) { 289 auto iter = parser->findAttribute(u"", name); 290 if (iter != parser->endAttributes()) { 291 return StringPiece16(util::trimWhitespace(iter->value)); 292 } 293 return {}; 294 } 295 296 Maybe<StringPiece16> findNonEmptyAttribute(const XmlPullParser* parser, const StringPiece16& name) { 297 auto iter = parser->findAttribute(u"", name); 298 if (iter != parser->endAttributes()) { 299 StringPiece16 trimmed = util::trimWhitespace(iter->value); 300 if (!trimmed.empty()) { 301 return trimmed; 302 } 303 } 304 return {}; 305 } 306 307 } // namespace xml 308 } // namespace aapt 309