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 "java/ManifestClassGenerator.h" 18 19#include <algorithm> 20 21#include "Source.h" 22#include "java/AnnotationProcessor.h" 23#include "java/ClassDefinition.h" 24#include "util/Maybe.h" 25#include "xml/XmlDom.h" 26 27using android::StringPiece; 28 29namespace aapt { 30 31static Maybe<StringPiece> ExtractJavaIdentifier(IDiagnostics* diag, 32 const Source& source, 33 const StringPiece& value) { 34 const StringPiece sep = "."; 35 auto iter = std::find_end(value.begin(), value.end(), sep.begin(), sep.end()); 36 37 StringPiece result; 38 if (iter != value.end()) { 39 result.assign(iter + sep.size(), value.end() - (iter + sep.size())); 40 } else { 41 result = value; 42 } 43 44 if (result.empty()) { 45 diag->Error(DiagMessage(source) << "empty symbol"); 46 return {}; 47 } 48 49 iter = util::FindNonAlphaNumericAndNotInSet(result, "_"); 50 if (iter != result.end()) { 51 diag->Error(DiagMessage(source) << "invalid character '" 52 << StringPiece(iter, 1) << "' in '" 53 << result << "'"); 54 return {}; 55 } 56 57 if (*result.begin() >= '0' && *result.begin() <= '9') { 58 diag->Error(DiagMessage(source) << "symbol can not start with a digit"); 59 return {}; 60 } 61 62 return result; 63} 64 65static bool WriteSymbol(const Source& source, IDiagnostics* diag, 66 xml::Element* el, ClassDefinition* class_def) { 67 xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name"); 68 if (!attr) { 69 diag->Error(DiagMessage(source) << "<" << el->name 70 << "> must define 'android:name'"); 71 return false; 72 } 73 74 Maybe<StringPiece> result = ExtractJavaIdentifier( 75 diag, source.WithLine(el->line_number), attr->value); 76 if (!result) { 77 return false; 78 } 79 80 std::unique_ptr<StringMember> string_member = 81 util::make_unique<StringMember>(result.value(), attr->value); 82 string_member->GetCommentBuilder()->AppendComment(el->comment); 83 84 class_def->AddMember(std::move(string_member)); 85 return true; 86} 87 88std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, 89 xml::XmlResource* res) { 90 xml::Element* el = xml::FindRootElement(res->root.get()); 91 if (!el) { 92 diag->Error(DiagMessage(res->file.source) << "no root tag defined"); 93 return {}; 94 } 95 96 if (el->name != "manifest" && !el->namespace_uri.empty()) { 97 diag->Error(DiagMessage(res->file.source) 98 << "no <manifest> root tag defined"); 99 return {}; 100 } 101 102 std::unique_ptr<ClassDefinition> permission_class = 103 util::make_unique<ClassDefinition>("permission", ClassQualifier::kStatic, false); 104 std::unique_ptr<ClassDefinition> permission_group_class = 105 util::make_unique<ClassDefinition>("permission_group", ClassQualifier::kStatic, false); 106 107 bool error = false; 108 std::vector<xml::Element*> children = el->GetChildElements(); 109 for (xml::Element* child_el : children) { 110 if (child_el->namespace_uri.empty()) { 111 if (child_el->name == "permission") { 112 error |= !WriteSymbol(res->file.source, diag, child_el, 113 permission_class.get()); 114 } else if (child_el->name == "permission-group") { 115 error |= !WriteSymbol(res->file.source, diag, child_el, 116 permission_group_class.get()); 117 } 118 } 119 } 120 121 if (error) { 122 return {}; 123 } 124 125 std::unique_ptr<ClassDefinition> manifest_class = 126 util::make_unique<ClassDefinition>("Manifest", ClassQualifier::kNone, false); 127 manifest_class->AddMember(std::move(permission_class)); 128 manifest_class->AddMember(std::move(permission_group_class)); 129 return manifest_class; 130} 131 132} // namespace aapt 133