diff options
author | Adam Lesinski <adamlesinski@google.com> | 2015-11-16 17:35:44 -0800 |
---|---|---|
committer | Adam Lesinski <adamlesinski@google.com> | 2015-11-19 14:46:53 -0800 |
commit | 467f171315f9c2037fcd3eb5edcfabc40671bf7b (patch) | |
tree | 3b14762e3d9e42a660479d0d5722883b391f835b /tools/aapt2/xml/XmlPullParser.cpp | |
parent | abf83cbe4f63cd76043aab89cd0e08525560fea2 (diff) |
AAPT2: Fail compiling when private symbols are referenced
Also moved some XML specific stuff into its own directory,
and refactored ReferenceLinker a bit.
Change-Id: I912247a82023c1bbf72dc191fbdaf62858cbec0c
Diffstat (limited to 'tools/aapt2/xml/XmlPullParser.cpp')
-rw-r--r-- | tools/aapt2/xml/XmlPullParser.cpp | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp new file mode 100644 index 000000000000..323ec05b5f2c --- /dev/null +++ b/tools/aapt2/xml/XmlPullParser.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/Maybe.h" +#include "util/Util.h" +#include "xml/XmlPullParser.h" +#include "xml/XmlUtil.h" + +#include <iostream> +#include <string> + +namespace aapt { +namespace xml { + +constexpr char kXmlNamespaceSep = 1; + +XmlPullParser::XmlPullParser(std::istream& in) : mIn(in), mEmpty(), mDepth(0) { + mParser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep); + XML_SetUserData(mParser, this); + XML_SetElementHandler(mParser, startElementHandler, endElementHandler); + XML_SetNamespaceDeclHandler(mParser, startNamespaceHandler, endNamespaceHandler); + XML_SetCharacterDataHandler(mParser, characterDataHandler); + XML_SetCommentHandler(mParser, commentDataHandler); + mEventQueue.push(EventData{ Event::kStartDocument, 0, mDepth++ }); +} + +XmlPullParser::~XmlPullParser() { + XML_ParserFree(mParser); +} + +XmlPullParser::Event XmlPullParser::next() { + const Event currentEvent = getEvent(); + if (currentEvent == Event::kBadDocument || currentEvent == Event::kEndDocument) { + return currentEvent; + } + + mEventQueue.pop(); + while (mEventQueue.empty()) { + mIn.read(mBuffer, sizeof(mBuffer) / sizeof(*mBuffer)); + + const bool done = mIn.eof(); + if (mIn.bad() && !done) { + mLastError = strerror(errno); + mEventQueue.push(EventData{ Event::kBadDocument }); + continue; + } + + if (XML_Parse(mParser, mBuffer, mIn.gcount(), done) == XML_STATUS_ERROR) { + mLastError = XML_ErrorString(XML_GetErrorCode(mParser)); + mEventQueue.push(EventData{ Event::kBadDocument }); + continue; + } + + if (done) { + mEventQueue.push(EventData{ Event::kEndDocument, 0, 0 }); + } + } + + Event event = getEvent(); + + // Record namespace prefixes and package names so that we can do our own + // handling of references that use namespace aliases. + if (event == Event::kStartNamespace || event == Event::kEndNamespace) { + Maybe<ExtractedPackage> result = extractPackageFromNamespace(getNamespaceUri()); + if (event == Event::kStartNamespace) { + if (result) { + mPackageAliases.emplace_back( + PackageDecl{ getNamespacePrefix(), std::move(result.value()) }); + } + } else { + if (result) { + mPackageAliases.pop_back(); + } + } + } + + return event; +} + +XmlPullParser::Event XmlPullParser::getEvent() const { + return mEventQueue.front().event; +} + +const std::string& XmlPullParser::getLastError() const { + return mLastError; +} + +const std::u16string& XmlPullParser::getComment() const { + return mEventQueue.front().data1; +} + +size_t XmlPullParser::getLineNumber() const { + return mEventQueue.front().lineNumber; +} + +size_t XmlPullParser::getDepth() const { + return mEventQueue.front().depth; +} + +const std::u16string& XmlPullParser::getText() const { + if (getEvent() != Event::kText) { + return mEmpty; + } + return mEventQueue.front().data1; +} + +const std::u16string& XmlPullParser::getNamespacePrefix() const { + const Event currentEvent = getEvent(); + if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) { + return mEmpty; + } + return mEventQueue.front().data1; +} + +const std::u16string& XmlPullParser::getNamespaceUri() const { + const Event currentEvent = getEvent(); + if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) { + return mEmpty; + } + return mEventQueue.front().data2; +} + +Maybe<ExtractedPackage> XmlPullParser::transformPackageAlias( + const StringPiece16& alias, const StringPiece16& localPackage) const { + if (alias.empty()) { + return ExtractedPackage{ localPackage.toString(), false /* private */ }; + } + + const auto endIter = mPackageAliases.rend(); + for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) { + if (alias == iter->prefix) { + if (iter->package.package.empty()) { + return ExtractedPackage{ localPackage.toString(), + iter->package.privateNamespace }; + } + return iter->package; + } + } + return {}; +} + +const std::u16string& XmlPullParser::getElementNamespace() const { + const Event currentEvent = getEvent(); + if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) { + return mEmpty; + } + return mEventQueue.front().data1; +} + +const std::u16string& XmlPullParser::getElementName() const { + const Event currentEvent = getEvent(); + if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) { + return mEmpty; + } + return mEventQueue.front().data2; +} + +XmlPullParser::const_iterator XmlPullParser::beginAttributes() const { + return mEventQueue.front().attributes.begin(); +} + +XmlPullParser::const_iterator XmlPullParser::endAttributes() const { + return mEventQueue.front().attributes.end(); +} + +size_t XmlPullParser::getAttributeCount() const { + if (getEvent() != Event::kStartElement) { + return 0; + } + return mEventQueue.front().attributes.size(); +} + +/** + * Extracts the namespace and name of an expanded element or attribute name. + */ +static void splitName(const char* name, std::u16string& outNs, std::u16string& outName) { + const char* p = name; + while (*p != 0 && *p != kXmlNamespaceSep) { + p++; + } + + if (*p == 0) { + outNs = std::u16string(); + outName = util::utf8ToUtf16(name); + } else { + outNs = util::utf8ToUtf16(StringPiece(name, (p - name))); + outName = util::utf8ToUtf16(p + 1); + } +} + +void XMLCALL XmlPullParser::startNamespaceHandler(void* userData, const char* prefix, + const char* uri) { + XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); + std::u16string namespaceUri = uri != nullptr ? util::utf8ToUtf16(uri) : std::u16string(); + parser->mNamespaceUris.push(namespaceUri); + parser->mEventQueue.push(EventData{ + Event::kStartNamespace, + XML_GetCurrentLineNumber(parser->mParser), + parser->mDepth++, + prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(), + namespaceUri + }); +} + +void XMLCALL XmlPullParser::startElementHandler(void* userData, const char* name, + const char** attrs) { + XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); + + EventData data = { + Event::kStartElement, XML_GetCurrentLineNumber(parser->mParser), parser->mDepth++ + }; + splitName(name, data.data1, data.data2); + + while (*attrs) { + Attribute attribute; + splitName(*attrs++, attribute.namespaceUri, attribute.name); + attribute.value = util::utf8ToUtf16(*attrs++); + + // Insert in sorted order. + auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(), attribute); + data.attributes.insert(iter, std::move(attribute)); + } + + // Move the structure into the queue (no copy). + parser->mEventQueue.push(std::move(data)); +} + +void XMLCALL XmlPullParser::characterDataHandler(void* userData, const char* s, int len) { + XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); + + parser->mEventQueue.push(EventData{ + Event::kText, + XML_GetCurrentLineNumber(parser->mParser), + parser->mDepth, + util::utf8ToUtf16(StringPiece(s, len)) + }); +} + +void XMLCALL XmlPullParser::endElementHandler(void* userData, const char* name) { + XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); + + EventData data = { + Event::kEndElement, XML_GetCurrentLineNumber(parser->mParser), --(parser->mDepth) + }; + splitName(name, data.data1, data.data2); + + // Move the data into the queue (no copy). + parser->mEventQueue.push(std::move(data)); +} + +void XMLCALL XmlPullParser::endNamespaceHandler(void* userData, const char* prefix) { + XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); + + parser->mEventQueue.push(EventData{ + Event::kEndNamespace, + XML_GetCurrentLineNumber(parser->mParser), + --(parser->mDepth), + prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(), + parser->mNamespaceUris.top() + }); + parser->mNamespaceUris.pop(); +} + +void XMLCALL XmlPullParser::commentDataHandler(void* userData, const char* comment) { + XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(userData); + + parser->mEventQueue.push(EventData{ + Event::kComment, + XML_GetCurrentLineNumber(parser->mParser), + parser->mDepth, + util::utf8ToUtf16(comment) + }); +} + +Maybe<StringPiece16> findAttribute(const XmlPullParser* parser, const StringPiece16& name) { + auto iter = parser->findAttribute(u"", name); + if (iter != parser->endAttributes()) { + return StringPiece16(util::trimWhitespace(iter->value)); + } + return {}; +} + +Maybe<StringPiece16> findNonEmptyAttribute(const XmlPullParser* parser, const StringPiece16& name) { + auto iter = parser->findAttribute(u"", name); + if (iter != parser->endAttributes()) { + StringPiece16 trimmed = util::trimWhitespace(iter->value); + if (!trimmed.empty()) { + return trimmed; + } + } + return {}; +} + +} // namespace xml +} // namespace aapt |