Home | History | Annotate | Download | only in aapt2
      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 #ifndef AAPT_XML_PULL_PARSER_H
     18 #define AAPT_XML_PULL_PARSER_H
     19 
     20 #include <algorithm>
     21 #include <ostream>
     22 #include <string>
     23 #include <vector>
     24 
     25 #include "StringPiece.h"
     26 
     27 namespace aapt {
     28 
     29 class XmlPullParser {
     30 public:
     31     enum class Event {
     32         kBadDocument,
     33         kStartDocument,
     34         kEndDocument,
     35 
     36         kStartNamespace,
     37         kEndNamespace,
     38         kStartElement,
     39         kEndElement,
     40         kText,
     41         kComment,
     42     };
     43 
     44     static void skipCurrentElement(XmlPullParser* parser);
     45     static bool isGoodEvent(Event event);
     46 
     47     virtual ~XmlPullParser() {}
     48 
     49     /**
     50      * Returns the current event that is being processed.
     51      */
     52     virtual Event getEvent() const = 0;
     53 
     54     virtual const std::string& getLastError() const = 0;
     55 
     56     /**
     57      * Note, unlike XmlPullParser, the first call to next() will return
     58      * StartElement of the first element.
     59      */
     60     virtual Event next() = 0;
     61 
     62     //
     63     // These are available for all nodes.
     64     //
     65 
     66     virtual const std::u16string& getComment() const = 0;
     67     virtual size_t getLineNumber() const = 0;
     68     virtual size_t getDepth() const = 0;
     69 
     70     /**
     71      * Returns the character data for a Text event.
     72      */
     73     virtual const std::u16string& getText() const = 0;
     74 
     75     //
     76     // Namespace prefix and URI are available for StartNamespace and EndNamespace.
     77     //
     78 
     79     virtual const std::u16string& getNamespacePrefix() const = 0;
     80     virtual const std::u16string& getNamespaceUri() const = 0;
     81 
     82     /*
     83      * Uses the current stack of namespaces to resolve the package. Eg:
     84      * xmlns:app = "http://schemas.android.com/apk/res/com.android.app"
     85      * ...
     86      * android:text="@app:string/message"
     87      *
     88      * In this case, 'app' will be converted to 'com.android.app'.
     89      *
     90      * If xmlns:app="http://schemas.android.com/apk/res-auto", then
     91      * 'package' will be set to 'defaultPackage'.
     92      */
     93     virtual bool applyPackageAlias(std::u16string* package,
     94                                    const std::u16string& defaultPackage) const = 0;
     95 
     96     //
     97     // These are available for StartElement and EndElement.
     98     //
     99 
    100     virtual const std::u16string& getElementNamespace() const = 0;
    101     virtual const std::u16string& getElementName() const = 0;
    102 
    103     //
    104     // Remaining methods are for retrieving information about attributes
    105     // associated with a StartElement.
    106     //
    107     // Attributes must be in sorted order (according to the less than operator
    108     // of struct Attribute).
    109     //
    110 
    111     struct Attribute {
    112         std::u16string namespaceUri;
    113         std::u16string name;
    114         std::u16string value;
    115 
    116         int compare(const Attribute& rhs) const;
    117         bool operator<(const Attribute& rhs) const;
    118         bool operator==(const Attribute& rhs) const;
    119         bool operator!=(const Attribute& rhs) const;
    120     };
    121 
    122     using const_iterator = std::vector<Attribute>::const_iterator;
    123 
    124     virtual const_iterator beginAttributes() const = 0;
    125     virtual const_iterator endAttributes() const = 0;
    126     virtual size_t getAttributeCount() const = 0;
    127     const_iterator findAttribute(StringPiece16 namespaceUri, StringPiece16 name) const;
    128 };
    129 
    130 //
    131 // Implementation
    132 //
    133 
    134 inline ::std::ostream& operator<<(::std::ostream& out, XmlPullParser::Event event) {
    135     switch (event) {
    136         case XmlPullParser::Event::kBadDocument: return out << "BadDocument";
    137         case XmlPullParser::Event::kStartDocument: return out << "StartDocument";
    138         case XmlPullParser::Event::kEndDocument: return out << "EndDocument";
    139         case XmlPullParser::Event::kStartNamespace: return out << "StartNamespace";
    140         case XmlPullParser::Event::kEndNamespace: return out << "EndNamespace";
    141         case XmlPullParser::Event::kStartElement: return out << "StartElement";
    142         case XmlPullParser::Event::kEndElement: return out << "EndElement";
    143         case XmlPullParser::Event::kText: return out << "Text";
    144         case XmlPullParser::Event::kComment: return out << "Comment";
    145     }
    146     return out;
    147 }
    148 
    149 inline void XmlPullParser::skipCurrentElement(XmlPullParser* parser) {
    150     int depth = 1;
    151     while (depth > 0) {
    152         switch (parser->next()) {
    153             case Event::kEndDocument:
    154             case Event::kBadDocument:
    155                 return;
    156             case Event::kStartElement:
    157                 depth++;
    158                 break;
    159             case Event::kEndElement:
    160                 depth--;
    161                 break;
    162             default:
    163                 break;
    164         }
    165     }
    166 }
    167 
    168 inline bool XmlPullParser::isGoodEvent(XmlPullParser::Event event) {
    169     return event != Event::kBadDocument && event != Event::kEndDocument;
    170 }
    171 
    172 inline int XmlPullParser::Attribute::compare(const Attribute& rhs) const {
    173     int cmp = namespaceUri.compare(rhs.namespaceUri);
    174     if (cmp != 0) return cmp;
    175     return name.compare(rhs.name);
    176 }
    177 
    178 inline bool XmlPullParser::Attribute::operator<(const Attribute& rhs) const {
    179     return compare(rhs) < 0;
    180 }
    181 
    182 inline bool XmlPullParser::Attribute::operator==(const Attribute& rhs) const {
    183     return compare(rhs) == 0;
    184 }
    185 
    186 inline bool XmlPullParser::Attribute::operator!=(const Attribute& rhs) const {
    187     return compare(rhs) != 0;
    188 }
    189 
    190 inline XmlPullParser::const_iterator XmlPullParser::findAttribute(StringPiece16 namespaceUri,
    191                                                                   StringPiece16 name) const {
    192     const auto endIter = endAttributes();
    193     const auto iter = std::lower_bound(beginAttributes(), endIter,
    194             std::pair<StringPiece16, StringPiece16>(namespaceUri, name),
    195             [](const Attribute& attr, const std::pair<StringPiece16, StringPiece16>& rhs) -> bool {
    196                 int cmp = attr.namespaceUri.compare(0, attr.namespaceUri.size(),
    197                         rhs.first.data(), rhs.first.size());
    198                 if (cmp < 0) return true;
    199                 if (cmp > 0) return false;
    200                 cmp = attr.name.compare(0, attr.name.size(), rhs.second.data(), rhs.second.size());
    201                 if (cmp < 0) return true;
    202                 return false;
    203             }
    204     );
    205 
    206     if (iter != endIter && namespaceUri == iter->namespaceUri && name == iter->name) {
    207         return iter;
    208     }
    209     return endIter;
    210 }
    211 
    212 } // namespace aapt
    213 
    214 #endif // AAPT_XML_PULL_PARSER_H
    215