1// 2// Copyright (C) 2017 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 <property_info_serializer/property_info_serializer.h> 18 19#include <android-base/strings.h> 20 21#include "space_tokenizer.h" 22 23using android::base::Join; 24using android::base::Split; 25using android::base::StartsWith; 26using android::base::Trim; 27 28namespace android { 29namespace properties { 30 31namespace { 32 33bool IsTypeValid(const std::vector<std::string>& type_strings) { 34 if (type_strings.empty()) { 35 return false; 36 } 37 38 // There must be at least one string following 'enum' 39 if (type_strings[0] == "enum") { 40 return type_strings.size() > 1; 41 } 42 43 // There should not be any string following any other types. 44 if (type_strings.size() != 1) { 45 return false; 46 } 47 48 // Check that the type matches one of remaining valid types. 49 static const char* const no_parameter_types[] = {"string", "bool", "int", 50 "uint", "double", "size"}; 51 for (const auto& type : no_parameter_types) { 52 if (type_strings[0] == type) { 53 return true; 54 } 55 } 56 return false; 57} 58 59bool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) { 60 auto tokenizer = SpaceTokenizer(line); 61 62 auto property = tokenizer.GetNext(); 63 if (property.empty()) { 64 *error = "Did not find a property entry in '" + line + "'"; 65 return false; 66 } 67 68 auto context = tokenizer.GetNext(); 69 if (context.empty()) { 70 *error = "Did not find a context entry in '" + line + "'"; 71 return false; 72 } 73 74 // It is not an error to not find exact_match or a type, as older files will not contain them. 75 auto exact_match = tokenizer.GetNext(); 76 // We reformat type to be space deliminated regardless of the input whitespace for easier storage 77 // and subsequent parsing. 78 auto type_strings = std::vector<std::string>{}; 79 auto type = tokenizer.GetNext(); 80 while (!type.empty()) { 81 type_strings.emplace_back(type); 82 type = tokenizer.GetNext(); 83 } 84 85 if (!type_strings.empty() && !IsTypeValid(type_strings)) { 86 *error = "Type '" + Join(type_strings, " ") + "' is not valid"; 87 return false; 88 } 89 90 *out = {property, context, Join(type_strings, " "), exact_match == "exact"}; 91 return true; 92} 93 94} // namespace 95 96void ParsePropertyInfoFile(const std::string& file_contents, 97 std::vector<PropertyInfoEntry>* property_infos, 98 std::vector<std::string>* errors) { 99 // Do not clear property_infos to allow this function to be called on multiple files, with 100 // their results concatenated. 101 errors->clear(); 102 103 for (const auto& line : Split(file_contents, "\n")) { 104 auto trimmed_line = Trim(line); 105 if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) { 106 continue; 107 } 108 109 auto property_info_entry = PropertyInfoEntry{}; 110 auto parse_error = std::string{}; 111 if (!ParsePropertyInfoLine(trimmed_line, &property_info_entry, &parse_error)) { 112 errors->emplace_back(parse_error); 113 continue; 114 } 115 116 property_infos->emplace_back(property_info_entry); 117 } 118} 119 120} // namespace properties 121} // namespace android 122