Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 581cc1ee authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

Merge "AAPT2: Change xml file parsing to DOM based" into mnc-dev

parents 2b710c29 75f3a55c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ main := Main.cpp
sources := \
	BigBuffer.cpp \
	BinaryResourceParser.cpp \
	BinaryXmlPullParser.cpp \
	BindingXmlPullParser.cpp \
	ConfigDescription.cpp \
	Debug.cpp \
@@ -53,6 +52,7 @@ sources := \
	ScopedXmlPullParser.cpp \
	SourceXmlPullParser.cpp \
	XliffXmlPullParser.cpp \
	XmlDom.cpp \
	XmlFlattener.cpp \
	ZipEntry.cpp \
	ZipFile.cpp
@@ -76,6 +76,7 @@ testSources := \
	StringPool_test.cpp \
	Util_test.cpp \
	XliffXmlPullParser_test.cpp \
	XmlDom_test.cpp \
	XmlFlattener_test.cpp

cIncludes := \
+0 −259
Original line number Diff line number Diff line
/*
 * 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 "BinaryXmlPullParser.h"
#include "Maybe.h"
#include "Util.h"

#include <androidfw/ResourceTypes.h>
#include <memory>
#include <string>
#include <vector>

namespace aapt {

static XmlPullParser::Event codeToEvent(android::ResXMLParser::event_code_t code) {
    switch (code) {
        case android::ResXMLParser::START_DOCUMENT:
            return XmlPullParser::Event::kStartDocument;
        case android::ResXMLParser::END_DOCUMENT:
            return XmlPullParser::Event::kEndDocument;
        case android::ResXMLParser::START_NAMESPACE:
            return XmlPullParser::Event::kStartNamespace;
        case android::ResXMLParser::END_NAMESPACE:
            return XmlPullParser::Event::kEndNamespace;
        case android::ResXMLParser::START_TAG:
            return XmlPullParser::Event::kStartElement;
        case android::ResXMLParser::END_TAG:
            return XmlPullParser::Event::kEndElement;
        case android::ResXMLParser::TEXT:
            return XmlPullParser::Event::kText;
        default:
            break;
    }
    return XmlPullParser::Event::kBadDocument;
}

BinaryXmlPullParser::BinaryXmlPullParser(const std::shared_ptr<android::ResXMLTree>& parser)
    : mParser(parser), mEvent(Event::kStartDocument), mHasComment(false), sEmpty(), sEmpty8(),
      mDepth(0) {
}

XmlPullParser::Event BinaryXmlPullParser::next() {
    mStr1.clear();
    mStr2.clear();
    mAttributes.clear();

    android::ResXMLParser::event_code_t code;
    if (mHasComment) {
        mHasComment = false;
        code = mParser->getEventType();
    } else {
        code = mParser->next();
        if (code != android::ResXMLParser::BAD_DOCUMENT) {
            size_t len;
            const char16_t* comment = mParser->getComment(&len);
            if (comment) {
                mHasComment = true;
                mStr1.assign(comment, len);
                return XmlPullParser::Event::kComment;
            }
        }
    }

    size_t len;
    const char16_t* data;
    mEvent = codeToEvent(code);
    switch (mEvent) {
        case Event::kStartNamespace:
        case Event::kEndNamespace: {
            data = mParser->getNamespacePrefix(&len);
            if (data) {
                mStr1.assign(data, len);
            } else {
                mStr1.clear();
            }
            data = mParser->getNamespaceUri(&len);
            if (data) {
                mStr2.assign(data, len);
            } else {
                mStr2.clear();
            }

            Maybe<std::u16string> result = util::extractPackageFromNamespace(mStr2);
            if (result) {
                if (mEvent == Event::kStartNamespace) {
                    mPackageAliases.emplace_back(mStr1, result.value());
                } else {
                    assert(mPackageAliases.back().second == result.value());
                    mPackageAliases.pop_back();
                }
            }
            break;
        }

        case Event::kStartElement:
            copyAttributes();
            // fallthrough

        case Event::kEndElement:
            data = mParser->getElementNamespace(&len);
            if (data) {
                mStr1.assign(data, len);
            } else {
                mStr1.clear();
            }
            data = mParser->getElementName(&len);
            if (data) {
                mStr2.assign(data, len);
            } else {
                mStr2.clear();
            }
            break;

        case Event::kText:
            data = mParser->getText(&len);
            if (data) {
                mStr1.assign(data, len);
            } else {
                mStr1.clear();
            }
            break;

        default:
            break;
    }
    return mEvent;
}

XmlPullParser::Event BinaryXmlPullParser::getEvent() const {
    if (mHasComment) {
        return XmlPullParser::Event::kComment;
    }
    return mEvent;
}

const std::string& BinaryXmlPullParser::getLastError() const {
    return sEmpty8;
}

const std::u16string& BinaryXmlPullParser::getComment() const {
    if (mHasComment) {
        return mStr1;
    }
    return sEmpty;
}

size_t BinaryXmlPullParser::getLineNumber() const {
    return mParser->getLineNumber();
}

size_t BinaryXmlPullParser::getDepth() const {
    return mDepth;
}

const std::u16string& BinaryXmlPullParser::getText() const {
    if (!mHasComment && mEvent == XmlPullParser::Event::kText) {
        return mStr1;
    }
    return sEmpty;
}

const std::u16string& BinaryXmlPullParser::getNamespacePrefix() const {
    if (!mHasComment && (mEvent == XmlPullParser::Event::kStartNamespace ||
            mEvent == XmlPullParser::Event::kEndNamespace)) {
        return mStr1;
    }
    return sEmpty;
}

const std::u16string& BinaryXmlPullParser::getNamespaceUri() const {
    if (!mHasComment && (mEvent == XmlPullParser::Event::kStartNamespace ||
            mEvent == XmlPullParser::Event::kEndNamespace)) {
        return mStr2;
    }
    return sEmpty;
}

bool BinaryXmlPullParser::applyPackageAlias(std::u16string* package,
                                            const std::u16string& defaultPackage) const {
    const auto endIter = mPackageAliases.rend();
    for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) {
        if (iter->first == *package) {
            if (iter->second.empty()) {
                *package = defaultPackage;
            } else {
                *package = iter->second;
            }
            return true;
        }
    }
    return false;
}

const std::u16string& BinaryXmlPullParser::getElementNamespace() const {
    if (!mHasComment && (mEvent == XmlPullParser::Event::kStartElement ||
            mEvent == XmlPullParser::Event::kEndElement)) {
        return mStr1;
    }
    return sEmpty;
}

const std::u16string& BinaryXmlPullParser::getElementName() const {
    if (!mHasComment && (mEvent == XmlPullParser::Event::kStartElement ||
            mEvent == XmlPullParser::Event::kEndElement)) {
        return mStr2;
    }
    return sEmpty;
}

size_t BinaryXmlPullParser::getAttributeCount() const {
    return mAttributes.size();
}

XmlPullParser::const_iterator BinaryXmlPullParser::beginAttributes() const {
    return mAttributes.begin();
}

XmlPullParser::const_iterator BinaryXmlPullParser::endAttributes() const {
    return mAttributes.end();
}

void BinaryXmlPullParser::copyAttributes() {
    const size_t attrCount = mParser->getAttributeCount();
    if (attrCount > 0) {
        mAttributes.reserve(attrCount);
        for (size_t i = 0; i < attrCount; i++) {
            XmlPullParser::Attribute attr;
            size_t len;
            const char16_t* str = mParser->getAttributeNamespace(i, &len);
            if (str) {
                attr.namespaceUri.assign(str, len);
            }
            str = mParser->getAttributeName(i, &len);
            if (str) {
                attr.name.assign(str, len);
            }
            str = mParser->getAttributeStringValue(i, &len);
            if (str) {
                attr.value.assign(str, len);
            }
            mAttributes.push_back(std::move(attr));
        }
    }
}

} // namespace aapt

tools/aapt2/BinaryXmlPullParser.h

deleted100644 → 0
+0 −76
Original line number Diff line number Diff line
/*
 * 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.
 */

#ifndef AAPT_BINARY_XML_PULL_PARSER_H
#define AAPT_BINARY_XML_PULL_PARSER_H

#include "XmlPullParser.h"

#include <androidfw/ResourceTypes.h>
#include <memory>
#include <string>
#include <vector>

namespace aapt {

/**
 * Wraps a ResTable into the canonical XmlPullParser interface.
 */
class BinaryXmlPullParser : public XmlPullParser {
public:
    BinaryXmlPullParser(const std::shared_ptr<android::ResXMLTree>& parser);
    BinaryXmlPullParser(const BinaryXmlPullParser& rhs) = delete;

    Event getEvent() const override;
    const std::string& getLastError() const override;
    Event next() override;

    const std::u16string& getComment() const override;
    size_t getLineNumber() const override;
    size_t getDepth() const override;

    const std::u16string& getText() const override;

    const std::u16string& getNamespacePrefix() const override;
    const std::u16string& getNamespaceUri() const override;
    bool applyPackageAlias(std::u16string* package, const std::u16string& defaultpackage)
            const override;

    const std::u16string& getElementNamespace() const override;
    const std::u16string& getElementName() const override;

    const_iterator beginAttributes() const override;
    const_iterator endAttributes() const override;
    size_t getAttributeCount() const override;

private:
    void copyAttributes();

    std::shared_ptr<android::ResXMLTree> mParser;
    std::u16string mStr1;
    std::u16string mStr2;
    std::vector<Attribute> mAttributes;
    Event mEvent;
    bool mHasComment;
    const std::u16string sEmpty;
    const std::string sEmpty8;
    size_t mDepth;
    std::vector<std::pair<std::u16string, std::u16string>> mPackageAliases;
};

} // namespace aapt

#endif // AAPT_BINARY_XML_PULL_PARSER_H
+65 −63
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
#include "AppInfo.h"
#include "BigBuffer.h"
#include "BinaryResourceParser.h"
#include "BinaryXmlPullParser.h"
#include "BindingXmlPullParser.h"
#include "Debug.h"
#include "Files.h"
@@ -128,7 +127,7 @@ void versionStylesForCompat(const std::shared_ptr<ResourceTable>& table) {
                    auto iter = style.entries.begin();
                    while (iter != style.entries.end()) {
                        if (iter->key.name.package == u"android") {
                            size_t sdkLevel = findAttributeSdkLevel(iter->key.name.entry);
                            size_t sdkLevel = findAttributeSdkLevel(iter->key.name);
                            if (sdkLevel > 1 && sdkLevel > configValue.config.sdkVersion) {
                                // Record that we are about to strip this.
                                stripped.emplace_back(std::move(*iter));
@@ -300,6 +299,42 @@ struct AaptOptions {
    ResourceName dumpStyleTarget;
};

struct IdCollector : public xml::Visitor {
    IdCollector(const Source& source, const std::shared_ptr<ResourceTable>& table) :
            mSource(source), mTable(table) {
    }

    virtual void visit(xml::Text* node) override {}

    virtual void visit(xml::Namespace* node) override {
        for (const auto& child : node->children) {
            child->accept(this);
        }
    }

    virtual void visit(xml::Element* node) override {
        for (const xml::Attribute& attr : node->attributes) {
            bool create = false;
            bool priv = false;
            ResourceNameRef nameRef;
            if (ResourceParser::tryParseReference(attr.value, &nameRef, &create, &priv)) {
                if (create) {
                    mTable->addResource(nameRef, {}, mSource.line(node->lineNumber),
                                        util::make_unique<Id>());
                }
            }
        }

        for (const auto& child : node->children) {
            child->accept(this);
        }
    }

private:
    Source mSource;
    std::shared_ptr<ResourceTable> mTable;
};

bool compileXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& table,
                const CompileItem& item, ZipFile* outApk) {
    std::ifstream in(item.source.path, std::ifstream::binary);
@@ -308,20 +343,19 @@ bool compileXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>
        return false;
    }

    BigBuffer outBuffer(1024);

    // No resolver, since we are not compiling attributes here.
    XmlFlattener flattener(table, {});

    XmlFlattener::Options xmlOptions;
    xmlOptions.defaultPackage = table->getPackage();
    xmlOptions.keepRawValues = true;
    SourceLogger logger(item.source);
    std::unique_ptr<xml::Node> root = xml::inflate(&in, &logger);
    if (!root) {
        return false;
    }

    std::shared_ptr<XmlPullParser> parser = std::make_shared<SourceXmlPullParser>(in);
    // Collect any resource ID's declared here.
    IdCollector idCollector(item.source, table);
    root->accept(&idCollector);

    Maybe<size_t> minStrippedSdk = flattener.flatten(item.source, parser, &outBuffer,
                                                     xmlOptions);
    if (!minStrippedSdk) {
    BigBuffer outBuffer(1024);
    if (!xml::flatten(root.get(), options.appInfo.package, &outBuffer)) {
        logger.error() << "failed to encode XML." << std::endl;
        return false;
    }

@@ -369,19 +403,13 @@ bool shouldGenerateVersionedResource(const std::shared_ptr<const ResourceTable>&
bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& table,
             const std::shared_ptr<IResolver>& resolver, const LinkItem& item,
             const void* data, size_t dataLen, ZipFile* outApk, std::queue<LinkItem>* outQueue) {
    std::shared_ptr<android::ResXMLTree> tree = std::make_shared<android::ResXMLTree>();
    if (tree->setTo(data, dataLen, false) != android::NO_ERROR) {
    SourceLogger logger(item.source);
    std::unique_ptr<xml::Node> root = xml::inflate(data, dataLen, &logger);
    if (!root) {
        return false;
    }

    std::shared_ptr<XmlPullParser> parser = std::make_shared<BinaryXmlPullParser>(tree);

    BigBuffer outBuffer(1024);
    XmlFlattener flattener({}, resolver);

    XmlFlattener::Options xmlOptions;
    xmlOptions.defaultPackage = item.originalPackage;

    xml::FlattenOptions xmlOptions;
    if (options.packageType == AaptOptions::PackageType::StaticLibrary) {
        xmlOptions.keepRawValues = true;
    }
@@ -392,16 +420,12 @@ bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& t
        xmlOptions.maxSdkAttribute = item.config.sdkVersion ? item.config.sdkVersion : 1;
    }

    std::shared_ptr<BindingXmlPullParser> binding;
    if (item.name.type == ResourceType::kLayout) {
        // Layouts may have defined bindings, so we need to make sure they get processed.
        binding = std::make_shared<BindingXmlPullParser>(parser);
        parser = binding;
    }

    Maybe<size_t> minStrippedSdk = flattener.flatten(item.source, parser, &outBuffer,
                                                     xmlOptions);
    BigBuffer outBuffer(1024);
    Maybe<size_t> minStrippedSdk = xml::flattenAndLink(item.source, root.get(),
                                                       item.originalPackage, resolver,
                                                       xmlOptions, &outBuffer);
    if (!minStrippedSdk) {
        logger.error() << "failed to encode XML." << std::endl;
        return false;
    }

@@ -431,30 +455,6 @@ bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& t
                                      << buildFileReference(item) << "' to apk." << std::endl;
        return false;
    }

    if (binding && !options.bindingOutput.path.empty()) {
        // We generated a binding xml file, write it out.
        Source bindingOutput = options.bindingOutput;
        appendPath(&bindingOutput.path, buildFileReference(item));

        if (!mkdirs(bindingOutput.path)) {
            Logger::error(bindingOutput) << strerror(errno) << std::endl;
            return false;
        }

        appendPath(&bindingOutput.path, "bind.xml");

        std::ofstream bout(bindingOutput.path);
        if (!bout) {
            Logger::error(bindingOutput) << strerror(errno) << std::endl;
            return false;
        }

        if (!binding->writeToFile(bout)) {
            Logger::error(bindingOutput) << strerror(errno) << std::endl;
            return false;
        }
    }
    return true;
}

@@ -504,13 +504,15 @@ bool compileManifest(const AaptOptions& options, const std::shared_ptr<IResolver
        return false;
    }

    BigBuffer outBuffer(1024);
    std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(in);
    XmlFlattener flattener({}, resolver);
    SourceLogger logger(options.manifest);
    std::unique_ptr<xml::Node> root = xml::inflate(&in, &logger);
    if (!root) {
        return false;
    }

    XmlFlattener::Options xmlOptions;
    xmlOptions.defaultPackage = options.appInfo.package;
    if (!flattener.flatten(options.manifest, xmlParser, &outBuffer, xmlOptions)) {
    BigBuffer outBuffer(1024);
    if (!xml::flattenAndLink(options.manifest, root.get(), options.appInfo.package, resolver, {},
                &outBuffer)) {
        return false;
    }

+47 −3
Original line number Diff line number Diff line
@@ -14,11 +14,51 @@
 * limitations under the License.
 */

#include "SdkConstants.h"

#include <algorithm>
#include <string>
#include <unordered_map>
#include <vector>

namespace aapt {

static const std::vector<std::pair<uint16_t, size_t>> sAttrIdMap = {
    { 0x021c, 1 },
    { 0x021d, 2 },
    { 0x0269, SDK_CUPCAKE },
    { 0x028d, SDK_DONUT },
    { 0x02ad, SDK_ECLAIR },
    { 0x02b3, SDK_ECLAIR_0_1 },
    { 0x02b5, SDK_ECLAIR_MR1 },
    { 0x02bd, SDK_FROYO },
    { 0x02cb, SDK_GINGERBREAD },
    { 0x0361, SDK_HONEYCOMB },
    { 0x0366, SDK_HONEYCOMB_MR1 },
    { 0x03a6, SDK_HONEYCOMB_MR2 },
    { 0x03ae, SDK_JELLY_BEAN },
    { 0x03cc, SDK_JELLY_BEAN_MR1 },
    { 0x03da, SDK_JELLY_BEAN_MR2 },
    { 0x03f1, SDK_KITKAT },
    { 0x03f6, SDK_KITKAT_WATCH },
    { 0x04ce, SDK_LOLLIPOP },
};

static bool lessEntryId(const std::pair<uint16_t, size_t>& p, uint16_t entryId) {
    return p.first < entryId;
}

size_t findAttributeSdkLevel(ResourceId id) {
    if (id.packageId() != 0x01 && id.typeId() != 0x01) {
        return 0;
    }
    auto iter = std::lower_bound(sAttrIdMap.begin(), sAttrIdMap.end(), id.entryId(), lessEntryId);
    if (iter == sAttrIdMap.end()) {
        return SDK_LOLLIPOP_MR1;
    }
    return iter->second;
}

static const std::unordered_map<std::u16string, size_t> sAttrMap = {
    { u"marqueeRepeatLimit", 2 },
    { u"windowNoDisplay", 3 },
@@ -682,12 +722,16 @@ static const std::unordered_map<std::u16string, size_t> sAttrMap = {
    { u"colorEdgeEffect", 21 }
};

size_t findAttributeSdkLevel(const std::u16string& name) {
    auto iter = sAttrMap.find(name);
size_t findAttributeSdkLevel(const ResourceName& name) {
    if (name.package != u"android" && name.type != ResourceType::kAttr) {
        return 0;
    }

    auto iter = sAttrMap.find(name.entry);
    if (iter != sAttrMap.end()) {
        return iter->second;
    }
    return 0;
    return SDK_LOLLIPOP_MR1;
}

} // namespace aapt
Loading