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 "compile/XmlIdCollector.h" 18 19 #include <algorithm> 20 #include <vector> 21 22 #include "ResourceUtils.h" 23 #include "ResourceValues.h" 24 #include "text/Unicode.h" 25 #include "trace/TraceBuffer.h" 26 #include "xml/XmlDom.h" 27 28 namespace aapt { 29 30 namespace { 31 32 static bool cmp_name(const SourcedResourceName& a, const ResourceNameRef& b) { 33 return a.name < b; 34 } 35 36 struct IdCollector : public xml::Visitor { 37 public: 38 using xml::Visitor::Visit; 39 40 explicit IdCollector(std::vector<SourcedResourceName>* out_symbols, 41 SourcePathDiagnostics* source_diag) : out_symbols_(out_symbols), 42 source_diag_(source_diag) {} 43 44 void Visit(xml::Element* element) override { 45 for (xml::Attribute& attr : element->attributes) { 46 ResourceNameRef name; 47 bool create = false; 48 if (ResourceUtils::ParseReference(attr.value, &name, &create, nullptr)) { 49 if (create && name.type == ResourceType::kId) { 50 if (!text::IsValidResourceEntryName(name.entry)) { 51 source_diag_->Error(DiagMessage(element->line_number) 52 << "id '" << name << "' has an invalid entry name"); 53 } else { 54 auto iter = std::lower_bound(out_symbols_->begin(), 55 out_symbols_->end(), name, cmp_name); 56 if (iter == out_symbols_->end() || iter->name != name) { 57 out_symbols_->insert(iter, SourcedResourceName{name.ToResourceName(), 58 element->line_number}); 59 } 60 } 61 } 62 } 63 } 64 65 xml::Visitor::Visit(element); 66 } 67 68 private: 69 std::vector<SourcedResourceName>* out_symbols_; 70 SourcePathDiagnostics* source_diag_; 71 }; 72 73 } // namespace 74 75 bool XmlIdCollector::Consume(IAaptContext* context, xml::XmlResource* xmlRes) { 76 TRACE_CALL(); 77 xmlRes->file.exported_symbols.clear(); 78 SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics()); 79 IdCollector collector(&xmlRes->file.exported_symbols, &source_diag); 80 xmlRes->root->Accept(&collector); 81 return !source_diag.HadError(); 82 } 83 84 } // namespace aapt 85