blob: 476a215b7da801021900beb7d9a0fa01b5a498c7 [file] [log] [blame]
Adam Lesinski769de982015-04-10 19:43:55 -07001/*
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 "BinaryXmlPullParser.h"
Adam Lesinski24aad162015-04-24 19:19:30 -070018#include "Maybe.h"
19#include "Util.h"
Adam Lesinski769de982015-04-10 19:43:55 -070020
21#include <androidfw/ResourceTypes.h>
22#include <memory>
23#include <string>
24#include <vector>
25
26namespace aapt {
27
28static XmlPullParser::Event codeToEvent(android::ResXMLParser::event_code_t code) {
29 switch (code) {
30 case android::ResXMLParser::START_DOCUMENT:
31 return XmlPullParser::Event::kStartDocument;
32 case android::ResXMLParser::END_DOCUMENT:
33 return XmlPullParser::Event::kEndDocument;
34 case android::ResXMLParser::START_NAMESPACE:
35 return XmlPullParser::Event::kStartNamespace;
36 case android::ResXMLParser::END_NAMESPACE:
37 return XmlPullParser::Event::kEndNamespace;
38 case android::ResXMLParser::START_TAG:
39 return XmlPullParser::Event::kStartElement;
40 case android::ResXMLParser::END_TAG:
41 return XmlPullParser::Event::kEndElement;
42 case android::ResXMLParser::TEXT:
43 return XmlPullParser::Event::kText;
44 default:
45 break;
46 }
47 return XmlPullParser::Event::kBadDocument;
48}
49
50BinaryXmlPullParser::BinaryXmlPullParser(const std::shared_ptr<android::ResXMLTree>& parser)
51 : mParser(parser), mEvent(Event::kStartDocument), mHasComment(false), sEmpty(), sEmpty8(),
52 mDepth(0) {
53}
54
55XmlPullParser::Event BinaryXmlPullParser::next() {
56 mStr1.clear();
57 mStr2.clear();
58 mAttributes.clear();
59
60 android::ResXMLParser::event_code_t code;
61 if (mHasComment) {
62 mHasComment = false;
63 code = mParser->getEventType();
64 } else {
65 code = mParser->next();
66 if (code != android::ResXMLParser::BAD_DOCUMENT) {
67 size_t len;
68 const char16_t* comment = mParser->getComment(&len);
69 if (comment) {
70 mHasComment = true;
71 mStr1.assign(comment, len);
72 return XmlPullParser::Event::kComment;
73 }
74 }
75 }
76
77 size_t len;
78 const char16_t* data;
79 mEvent = codeToEvent(code);
80 switch (mEvent) {
81 case Event::kStartNamespace:
Adam Lesinski24aad162015-04-24 19:19:30 -070082 case Event::kEndNamespace: {
Adam Lesinski769de982015-04-10 19:43:55 -070083 data = mParser->getNamespacePrefix(&len);
Adam Lesinski24aad162015-04-24 19:19:30 -070084 if (data) {
85 mStr1.assign(data, len);
86 } else {
87 mStr1.clear();
88 }
Adam Lesinski769de982015-04-10 19:43:55 -070089 data = mParser->getNamespaceUri(&len);
Adam Lesinski24aad162015-04-24 19:19:30 -070090 if (data) {
91 mStr2.assign(data, len);
92 } else {
93 mStr2.clear();
94 }
95
96 Maybe<std::u16string> result = util::extractPackageFromNamespace(mStr2);
97 if (result) {
98 if (mEvent == Event::kStartNamespace) {
99 mPackageAliases.emplace_back(mStr1, result.value());
100 } else {
101 assert(mPackageAliases.back().second == result.value());
102 mPackageAliases.pop_back();
103 }
104 }
Adam Lesinski769de982015-04-10 19:43:55 -0700105 break;
Adam Lesinski24aad162015-04-24 19:19:30 -0700106 }
Adam Lesinski769de982015-04-10 19:43:55 -0700107
108 case Event::kStartElement:
109 copyAttributes();
110 // fallthrough
111
112 case Event::kEndElement:
113 data = mParser->getElementNamespace(&len);
Adam Lesinski24aad162015-04-24 19:19:30 -0700114 if (data) {
115 mStr1.assign(data, len);
116 } else {
117 mStr1.clear();
118 }
Adam Lesinski769de982015-04-10 19:43:55 -0700119 data = mParser->getElementName(&len);
Adam Lesinski24aad162015-04-24 19:19:30 -0700120 if (data) {
121 mStr2.assign(data, len);
122 } else {
123 mStr2.clear();
124 }
Adam Lesinski769de982015-04-10 19:43:55 -0700125 break;
126
127 case Event::kText:
128 data = mParser->getText(&len);
Adam Lesinski24aad162015-04-24 19:19:30 -0700129 if (data) {
130 mStr1.assign(data, len);
131 } else {
132 mStr1.clear();
133 }
Adam Lesinski769de982015-04-10 19:43:55 -0700134 break;
135
136 default:
137 break;
138 }
139 return mEvent;
140}
141
142XmlPullParser::Event BinaryXmlPullParser::getEvent() const {
143 if (mHasComment) {
144 return XmlPullParser::Event::kComment;
145 }
146 return mEvent;
147}
148
149const std::string& BinaryXmlPullParser::getLastError() const {
150 return sEmpty8;
151}
152
153const std::u16string& BinaryXmlPullParser::getComment() const {
154 if (mHasComment) {
155 return mStr1;
156 }
157 return sEmpty;
158}
159
160size_t BinaryXmlPullParser::getLineNumber() const {
161 return mParser->getLineNumber();
162}
163
164size_t BinaryXmlPullParser::getDepth() const {
165 return mDepth;
166}
167
168const std::u16string& BinaryXmlPullParser::getText() const {
169 if (!mHasComment && mEvent == XmlPullParser::Event::kText) {
170 return mStr1;
171 }
172 return sEmpty;
173}
174
175const std::u16string& BinaryXmlPullParser::getNamespacePrefix() const {
176 if (!mHasComment && (mEvent == XmlPullParser::Event::kStartNamespace ||
177 mEvent == XmlPullParser::Event::kEndNamespace)) {
178 return mStr1;
179 }
180 return sEmpty;
181}
182
183const std::u16string& BinaryXmlPullParser::getNamespaceUri() const {
184 if (!mHasComment && (mEvent == XmlPullParser::Event::kStartNamespace ||
185 mEvent == XmlPullParser::Event::kEndNamespace)) {
186 return mStr2;
187 }
188 return sEmpty;
189}
190
Adam Lesinski24aad162015-04-24 19:19:30 -0700191bool BinaryXmlPullParser::applyPackageAlias(std::u16string* package,
192 const std::u16string& defaultPackage) const {
193 const auto endIter = mPackageAliases.rend();
194 for (auto iter = mPackageAliases.rbegin(); iter != endIter; ++iter) {
195 if (iter->first == *package) {
196 if (iter->second.empty()) {
197 *package = defaultPackage;
198 } else {
199 *package = iter->second;
200 }
201 return true;
202 }
203 }
204 return false;
205}
206
Adam Lesinski769de982015-04-10 19:43:55 -0700207const std::u16string& BinaryXmlPullParser::getElementNamespace() const {
208 if (!mHasComment && (mEvent == XmlPullParser::Event::kStartElement ||
209 mEvent == XmlPullParser::Event::kEndElement)) {
210 return mStr1;
211 }
212 return sEmpty;
213}
214
215const std::u16string& BinaryXmlPullParser::getElementName() const {
216 if (!mHasComment && (mEvent == XmlPullParser::Event::kStartElement ||
217 mEvent == XmlPullParser::Event::kEndElement)) {
218 return mStr2;
219 }
220 return sEmpty;
221}
222
223size_t BinaryXmlPullParser::getAttributeCount() const {
224 return mAttributes.size();
225}
226
227XmlPullParser::const_iterator BinaryXmlPullParser::beginAttributes() const {
228 return mAttributes.begin();
229}
230
231XmlPullParser::const_iterator BinaryXmlPullParser::endAttributes() const {
232 return mAttributes.end();
233}
234
235void BinaryXmlPullParser::copyAttributes() {
236 const size_t attrCount = mParser->getAttributeCount();
237 if (attrCount > 0) {
238 mAttributes.reserve(attrCount);
239 for (size_t i = 0; i < attrCount; i++) {
240 XmlPullParser::Attribute attr;
241 size_t len;
242 const char16_t* str = mParser->getAttributeNamespace(i, &len);
Adam Lesinski24aad162015-04-24 19:19:30 -0700243 if (str) {
244 attr.namespaceUri.assign(str, len);
245 }
Adam Lesinski769de982015-04-10 19:43:55 -0700246 str = mParser->getAttributeName(i, &len);
Adam Lesinski24aad162015-04-24 19:19:30 -0700247 if (str) {
248 attr.name.assign(str, len);
249 }
Adam Lesinski769de982015-04-10 19:43:55 -0700250 str = mParser->getAttributeStringValue(i, &len);
Adam Lesinski24aad162015-04-24 19:19:30 -0700251 if (str) {
252 attr.value.assign(str, len);
253 }
Adam Lesinski769de982015-04-10 19:43:55 -0700254 mAttributes.push_back(std::move(attr));
255 }
256 }
257}
258
259} // namespace aapt