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 "XmlDom.h"
18
19 #include <expat.h>
20
21 #include <memory>
22 #include <stack>
23 #include <string>
24 #include <tuple>
25
26 #include "android-base/logging.h"
27
28 #include "ResourceUtils.h"
29 #include "XmlPullParser.h"
30 #include "util/Util.h"
31
32 using ::aapt::io::InputStream;
33 using ::android::StringPiece;
34 using ::android::StringPiece16;
35
36 namespace aapt {
37 namespace xml {
38
39 constexpr char kXmlNamespaceSep = 1;
40
41 struct Stack {
42 std::unique_ptr<xml::Element> root;
43 std::stack<xml::Element*> node_stack;
44 std::unique_ptr<xml::Element> pending_element;
45 std::string pending_comment;
46 std::unique_ptr<xml::Text> last_text_node;
47 };
48
49 // Extracts the namespace and name of an expanded element or attribute name.
SplitName(const char * name,std::string * out_ns,std::string * out_name)50 static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
51 const char* p = name;
52 while (*p != 0 && *p != kXmlNamespaceSep) {
53 p++;
54 }
55
56 if (*p == 0) {
57 out_ns->clear();
58 out_name->assign(name);
59 } else {
60 out_ns->assign(name, (p - name));
61 out_name->assign(p + 1);
62 }
63 }
64
FinishPendingText(Stack * stack)65 static void FinishPendingText(Stack* stack) {
66 if (stack->last_text_node != nullptr) {
67 if (!stack->last_text_node->text.empty()) {
68 CHECK(!stack->node_stack.empty());
69 stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
70 } else {
71 // Drop an empty text node.
72 }
73 stack->last_text_node = nullptr;
74 }
75 }
76
StartNamespaceHandler(void * user_data,const char * prefix,const char * uri)77 static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix, const char* uri) {
78 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
79 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
80 FinishPendingText(stack);
81
82 NamespaceDecl decl;
83 decl.line_number = XML_GetCurrentLineNumber(parser);
84 decl.column_number = XML_GetCurrentColumnNumber(parser);
85 decl.prefix = prefix ? prefix : "";
86 decl.uri = uri ? uri : "";
87
88 if (stack->pending_element == nullptr) {
89 stack->pending_element = util::make_unique<Element>();
90 }
91 stack->pending_element->namespace_decls.push_back(std::move(decl));
92 }
93
EndNamespaceHandler(void * user_data,const char *)94 static void XMLCALL EndNamespaceHandler(void* user_data, const char* /*prefix*/) {
95 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
96 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
97 FinishPendingText(stack);
98 }
99
less_attribute(const Attribute & lhs,const Attribute & rhs)100 static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
101 return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
102 std::tie(rhs.namespace_uri, rhs.name, rhs.value);
103 }
104
StartElementHandler(void * user_data,const char * name,const char ** attrs)105 static void XMLCALL StartElementHandler(void* user_data, const char* name, const char** attrs) {
106 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
107 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
108 FinishPendingText(stack);
109
110 std::unique_ptr<Element> el;
111 if (stack->pending_element != nullptr) {
112 el = std::move(stack->pending_element);
113 } else {
114 el = util::make_unique<Element>();
115 }
116
117 el->line_number = XML_GetCurrentLineNumber(parser);
118 el->column_number = XML_GetCurrentColumnNumber(parser);
119 el->comment = std::move(stack->pending_comment);
120
121 SplitName(name, &el->namespace_uri, &el->name);
122
123 while (*attrs) {
124 Attribute attribute;
125 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
126 attribute.value = *attrs++;
127 el->attributes.push_back(std::move(attribute));
128 }
129
130 // Sort the attributes.
131 std::sort(el->attributes.begin(), el->attributes.end(), less_attribute);
132
133 // Add to the stack.
134 Element* this_el = el.get();
135 if (!stack->node_stack.empty()) {
136 stack->node_stack.top()->AppendChild(std::move(el));
137 } else {
138 stack->root = std::move(el);
139 }
140 stack->node_stack.push(this_el);
141 }
142
EndElementHandler(void * user_data,const char * name)143 static void XMLCALL EndElementHandler(void* user_data, const char* name) {
144 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
145 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
146 FinishPendingText(stack);
147
148 CHECK(!stack->node_stack.empty());
149 // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
150 stack->node_stack.pop();
151 }
152
CharacterDataHandler(void * user_data,const char * s,int len)153 static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
154 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
155 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
156
157 const StringPiece str(s, len);
158 if (str.empty()) {
159 return;
160 }
161
162 // See if we can just append the text to a previous text node.
163 if (stack->last_text_node != nullptr) {
164 stack->last_text_node->text.append(str.data(), str.size());
165 return;
166 }
167
168 stack->last_text_node = util::make_unique<Text>();
169 stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
170 stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
171 stack->last_text_node->text = str.to_string();
172 }
173
CommentDataHandler(void * user_data,const char * comment)174 static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
175 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
176 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
177 FinishPendingText(stack);
178
179 if (!stack->pending_comment.empty()) {
180 stack->pending_comment += '\n';
181 }
182 stack->pending_comment += comment;
183 }
184
Inflate(InputStream * in,IDiagnostics * diag,const Source & source)185 std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
186 Stack stack;
187
188 std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
189 XML_ParserCreateNS(nullptr, kXmlNamespaceSep), XML_ParserFree};
190 XML_SetUserData(parser.get(), &stack);
191 XML_UseParserAsHandlerArg(parser.get());
192 XML_SetElementHandler(parser.get(), StartElementHandler, EndElementHandler);
193 XML_SetNamespaceDeclHandler(parser.get(), StartNamespaceHandler, EndNamespaceHandler);
194 XML_SetCharacterDataHandler(parser.get(), CharacterDataHandler);
195 XML_SetCommentHandler(parser.get(), CommentDataHandler);
196
197 const char* buffer = nullptr;
198 size_t buffer_size = 0;
199 while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
200 if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
201 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
202 << XML_ErrorString(XML_GetErrorCode(parser.get())));
203 return {};
204 }
205 }
206
207 if (in->HadError()) {
208 diag->Error(DiagMessage(source) << in->GetError());
209 return {};
210 } else {
211 // Finish off the parsing.
212 if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
213 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
214 << XML_ErrorString(XML_GetErrorCode(parser.get())));
215 return {};
216 }
217 }
218 return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
219 std::move(stack.root));
220 }
221
CopyAttributes(Element * el,android::ResXMLParser * parser,StringPool * out_pool)222 static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
223 const size_t attr_count = parser->getAttributeCount();
224 if (attr_count > 0) {
225 el->attributes.reserve(attr_count);
226 for (size_t i = 0; i < attr_count; i++) {
227 Attribute attr;
228 size_t len;
229 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
230 if (str16) {
231 attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
232 }
233
234 str16 = parser->getAttributeName(i, &len);
235 if (str16) {
236 attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
237 }
238
239 str16 = parser->getAttributeStringValue(i, &len);
240 if (str16) {
241 attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
242 }
243
244 android::Res_value res_value;
245 if (parser->getAttributeValue(i, &res_value) > 0) {
246 attr.compiled_value = ResourceUtils::ParseBinaryResValue(
247 ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
248 }
249
250 el->attributes.push_back(std::move(attr));
251 }
252 }
253 }
254
Inflate(const void * data,size_t data_len,IDiagnostics * diag,const Source & source)255 std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
256 const Source& source) {
257 // We import the android namespace because on Windows NO_ERROR is a macro, not
258 // an enum, which causes errors when qualifying it with android::
259 using namespace android;
260
261 StringPool string_pool;
262 std::unique_ptr<Element> root;
263 std::stack<Element*> node_stack;
264 std::unique_ptr<Element> pending_element;
265
266 ResXMLTree tree;
267 if (tree.setTo(data, data_len) != NO_ERROR) {
268 return {};
269 }
270
271 ResXMLParser::event_code_t code;
272 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT && code != ResXMLParser::END_DOCUMENT) {
273 std::unique_ptr<Node> new_node;
274 switch (code) {
275 case ResXMLParser::START_NAMESPACE: {
276 NamespaceDecl decl;
277 decl.line_number = tree.getLineNumber();
278
279 size_t len;
280 const char16_t* str16 = tree.getNamespacePrefix(&len);
281 if (str16) {
282 decl.prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
283 }
284
285 str16 = tree.getNamespaceUri(&len);
286 if (str16) {
287 decl.uri = util::Utf16ToUtf8(StringPiece16(str16, len));
288 }
289
290 if (pending_element == nullptr) {
291 pending_element = util::make_unique<Element>();
292 }
293 pending_element->namespace_decls.push_back(std::move(decl));
294 break;
295 }
296
297 case ResXMLParser::START_TAG: {
298 std::unique_ptr<Element> el;
299 if (pending_element != nullptr) {
300 el = std::move(pending_element);
301 } else {
302 el = util::make_unique<Element>();
303 }
304 el->line_number = tree.getLineNumber();
305
306 size_t len;
307 const char16_t* str16 = tree.getElementNamespace(&len);
308 if (str16) {
309 el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
310 }
311
312 str16 = tree.getElementName(&len);
313 if (str16) {
314 el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
315 }
316
317 Element* this_el = el.get();
318 CopyAttributes(el.get(), &tree, &string_pool);
319
320 if (!node_stack.empty()) {
321 node_stack.top()->AppendChild(std::move(el));
322 } else {
323 root = std::move(el);
324 }
325 node_stack.push(this_el);
326 break;
327 }
328
329 case ResXMLParser::TEXT: {
330 std::unique_ptr<Text> text = util::make_unique<Text>();
331 text->line_number = tree.getLineNumber();
332 size_t len;
333 const char16_t* str16 = tree.getText(&len);
334 if (str16) {
335 text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
336 }
337 CHECK(!node_stack.empty());
338 node_stack.top()->AppendChild(std::move(text));
339 break;
340 }
341
342 case ResXMLParser::END_NAMESPACE:
343 break;
344
345 case ResXMLParser::END_TAG:
346 CHECK(!node_stack.empty());
347 node_stack.pop();
348 break;
349
350 default:
351 LOG(FATAL) << "unhandled XML chunk type";
352 break;
353 }
354 }
355 return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
356 }
357
FindRootElement(Node * node)358 Element* FindRootElement(Node* node) {
359 if (node == nullptr) {
360 return nullptr;
361 }
362
363 while (node->parent != nullptr) {
364 node = node->parent;
365 }
366 return NodeCast<Element>(node);
367 }
368
AppendChild(std::unique_ptr<Node> child)369 void Element::AppendChild(std::unique_ptr<Node> child) {
370 child->parent = this;
371 children.push_back(std::move(child));
372 }
373
InsertChild(size_t index,std::unique_ptr<Node> child)374 void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
375 child->parent = this;
376 children.insert(children.begin() + index, std::move(child));
377 }
378
FindAttribute(const StringPiece & ns,const StringPiece & name)379 Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
380 for (auto& attr : attributes) {
381 if (ns == attr.namespace_uri && name == attr.name) {
382 return &attr;
383 }
384 }
385 return nullptr;
386 }
387
FindAttribute(const StringPiece & ns,const StringPiece & name) const388 const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
389 for (const auto& attr : attributes) {
390 if (ns == attr.namespace_uri && name == attr.name) {
391 return &attr;
392 }
393 }
394 return nullptr;
395 }
396
FindChild(const StringPiece & ns,const StringPiece & name)397 Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
398 return FindChildWithAttribute(ns, name, {}, {}, {});
399 }
400
FindChildWithAttribute(const StringPiece & ns,const StringPiece & name,const StringPiece & attr_ns,const StringPiece & attr_name,const StringPiece & attr_value)401 Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
402 const StringPiece& attr_ns, const StringPiece& attr_name,
403 const StringPiece& attr_value) {
404 for (auto& child : children) {
405 if (Element* el = NodeCast<Element>(child.get())) {
406 if (ns == el->namespace_uri && name == el->name) {
407 if (attr_ns.empty() && attr_name.empty()) {
408 return el;
409 }
410
411 Attribute* attr = el->FindAttribute(attr_ns, attr_name);
412 if (attr && attr_value == attr->value) {
413 return el;
414 }
415 }
416 }
417 }
418 return nullptr;
419 }
420
GetChildElements()421 std::vector<Element*> Element::GetChildElements() {
422 std::vector<Element*> elements;
423 for (auto& child_node : children) {
424 if (Element* child = NodeCast<Element>(child_node.get())) {
425 elements.push_back(child);
426 }
427 }
428 return elements;
429 }
430
Clone(const ElementCloneFunc & el_cloner) const431 std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) const {
432 auto el = util::make_unique<Element>();
433 el->namespace_decls = namespace_decls;
434 el->comment = comment;
435 el->line_number = line_number;
436 el->column_number = column_number;
437 el->name = name;
438 el->namespace_uri = namespace_uri;
439 el->attributes.reserve(attributes.size());
440 el_cloner(*this, el.get());
441 el->children.reserve(children.size());
442 for (const std::unique_ptr<xml::Node>& child : children) {
443 el->AppendChild(child->Clone(el_cloner));
444 }
445 return std::move(el);
446 }
447
CloneElement(const ElementCloneFunc & el_cloner) const448 std::unique_ptr<Element> Element::CloneElement(const ElementCloneFunc& el_cloner) const {
449 return std::unique_ptr<Element>(static_cast<Element*>(Clone(el_cloner).release()));
450 }
451
Accept(Visitor * visitor)452 void Element::Accept(Visitor* visitor) {
453 visitor->BeforeVisitElement(this);
454 visitor->Visit(this);
455 visitor->AfterVisitElement(this);
456 }
457
Clone(const ElementCloneFunc &) const458 std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) const {
459 auto t = util::make_unique<Text>();
460 t->comment = comment;
461 t->line_number = line_number;
462 t->column_number = column_number;
463 t->text = text;
464 return std::move(t);
465 }
466
Accept(Visitor * visitor)467 void Text::Accept(Visitor* visitor) {
468 visitor->Visit(this);
469 }
470
BeforeVisitElement(Element * el)471 void PackageAwareVisitor::BeforeVisitElement(Element* el) {
472 std::vector<PackageDecl> decls;
473 for (const NamespaceDecl& decl : el->namespace_decls) {
474 if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
475 decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())});
476 }
477 }
478 package_decls_.push_back(std::move(decls));
479 }
480
AfterVisitElement(Element * el)481 void PackageAwareVisitor::AfterVisitElement(Element* el) {
482 package_decls_.pop_back();
483 }
484
TransformPackageAlias(const StringPiece & alias,const StringPiece & local_package) const485 Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
486 const StringPiece& alias, const StringPiece& local_package) const {
487 if (alias.empty()) {
488 return ExtractedPackage{local_package.to_string(), false /* private */};
489 }
490
491 const auto rend = package_decls_.rend();
492 for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
493 const std::vector<PackageDecl>& decls = *iter;
494 const auto rend2 = decls.rend();
495 for (auto iter2 = decls.rbegin(); iter2 != rend2; ++iter2) {
496 const PackageDecl& decl = *iter2;
497 if (alias == decl.prefix) {
498 if (decl.package.package.empty()) {
499 return ExtractedPackage{local_package.to_string(), decl.package.private_namespace};
500 }
501 return decl.package;
502 }
503 }
504 }
505 return {};
506 }
507
508 } // namespace xml
509 } // namespace aapt
510