1927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry//
2927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// Copyright (C) 2017 The Android Open Source Project
3927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry//
4927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// Licensed under the Apache License, Version 2.0 (the "License");
5927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// you may not use this file except in compliance with the License.
6927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// You may obtain a copy of the License at
7927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry//
8927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry//      http://www.apache.org/licenses/LICENSE-2.0
9927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry//
10927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// Unless required by applicable law or agreed to in writing, software
11927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// distributed under the License is distributed on an "AS IS" BASIS,
12927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// See the License for the specific language governing permissions and
14927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry// limitations under the License.
15927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry//
16927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
17919458c350563e578e2d55852fbae187756c130aTom Cherry#include <property_info_serializer/property_info_serializer.h>
18919458c350563e578e2d55852fbae187756c130aTom Cherry
19919458c350563e578e2d55852fbae187756c130aTom Cherry#include <android-base/strings.h>
20919458c350563e578e2d55852fbae187756c130aTom Cherry
21919458c350563e578e2d55852fbae187756c130aTom Cherry#include "space_tokenizer.h"
22919458c350563e578e2d55852fbae187756c130aTom Cherry
23927c5d5fdc46eb60c28e569a922659733d927adaTom Cherryusing android::base::Join;
24919458c350563e578e2d55852fbae187756c130aTom Cherryusing android::base::Split;
25919458c350563e578e2d55852fbae187756c130aTom Cherryusing android::base::StartsWith;
26919458c350563e578e2d55852fbae187756c130aTom Cherryusing android::base::Trim;
27919458c350563e578e2d55852fbae187756c130aTom Cherry
28919458c350563e578e2d55852fbae187756c130aTom Cherrynamespace android {
29919458c350563e578e2d55852fbae187756c130aTom Cherrynamespace properties {
30919458c350563e578e2d55852fbae187756c130aTom Cherry
31927c5d5fdc46eb60c28e569a922659733d927adaTom Cherrynamespace {
32927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
33927c5d5fdc46eb60c28e569a922659733d927adaTom Cherrybool IsTypeValid(const std::vector<std::string>& type_strings) {
34927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  if (type_strings.empty()) {
35927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    return false;
36927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  }
37927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
38927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  // There must be at least one string following 'enum'
39927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  if (type_strings[0] == "enum") {
40927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    return type_strings.size() > 1;
41927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  }
42927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
43927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  // There should not be any string following any other types.
44927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  if (type_strings.size() != 1) {
45927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    return false;
46927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  }
47927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
48927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  // Check that the type matches one of remaining valid types.
49927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  static const char* const no_parameter_types[] = {"string", "bool",   "int",
50927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry                                                   "uint",   "double", "size"};
51927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  for (const auto& type : no_parameter_types) {
52927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    if (type_strings[0] == type) {
53927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry      return true;
54927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    }
55927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  }
56927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  return false;
57927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry}
58927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
59919458c350563e578e2d55852fbae187756c130aTom Cherrybool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) {
60919458c350563e578e2d55852fbae187756c130aTom Cherry  auto tokenizer = SpaceTokenizer(line);
61919458c350563e578e2d55852fbae187756c130aTom Cherry
62919458c350563e578e2d55852fbae187756c130aTom Cherry  auto property = tokenizer.GetNext();
63919458c350563e578e2d55852fbae187756c130aTom Cherry  if (property.empty()) {
64919458c350563e578e2d55852fbae187756c130aTom Cherry    *error = "Did not find a property entry in '" + line + "'";
65919458c350563e578e2d55852fbae187756c130aTom Cherry    return false;
66919458c350563e578e2d55852fbae187756c130aTom Cherry  }
67919458c350563e578e2d55852fbae187756c130aTom Cherry
68919458c350563e578e2d55852fbae187756c130aTom Cherry  auto context = tokenizer.GetNext();
69919458c350563e578e2d55852fbae187756c130aTom Cherry  if (context.empty()) {
70919458c350563e578e2d55852fbae187756c130aTom Cherry    *error = "Did not find a context entry in '" + line + "'";
71919458c350563e578e2d55852fbae187756c130aTom Cherry    return false;
72919458c350563e578e2d55852fbae187756c130aTom Cherry  }
73919458c350563e578e2d55852fbae187756c130aTom Cherry
74927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  // It is not an error to not find exact_match or a type, as older files will not contain them.
75919458c350563e578e2d55852fbae187756c130aTom Cherry  auto exact_match = tokenizer.GetNext();
76927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  // We reformat type to be space deliminated regardless of the input whitespace for easier storage
77927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  // and subsequent parsing.
78927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  auto type_strings = std::vector<std::string>{};
79927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  auto type = tokenizer.GetNext();
80927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  while (!type.empty()) {
81927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    type_strings.emplace_back(type);
82927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    type = tokenizer.GetNext();
83927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  }
84919458c350563e578e2d55852fbae187756c130aTom Cherry
85927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  if (!type_strings.empty() && !IsTypeValid(type_strings)) {
86927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    *error = "Type '" + Join(type_strings, " ") + "' is not valid";
87927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry    return false;
88927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  }
89927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
90927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry  *out = {property, context, Join(type_strings, " "), exact_match == "exact"};
91919458c350563e578e2d55852fbae187756c130aTom Cherry  return true;
92919458c350563e578e2d55852fbae187756c130aTom Cherry}
93919458c350563e578e2d55852fbae187756c130aTom Cherry
94927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry}  // namespace
95927c5d5fdc46eb60c28e569a922659733d927adaTom Cherry
96919458c350563e578e2d55852fbae187756c130aTom Cherryvoid ParsePropertyInfoFile(const std::string& file_contents,
97919458c350563e578e2d55852fbae187756c130aTom Cherry                           std::vector<PropertyInfoEntry>* property_infos,
98919458c350563e578e2d55852fbae187756c130aTom Cherry                           std::vector<std::string>* errors) {
99919458c350563e578e2d55852fbae187756c130aTom Cherry  // Do not clear property_infos to allow this function to be called on multiple files, with
100919458c350563e578e2d55852fbae187756c130aTom Cherry  // their results concatenated.
101919458c350563e578e2d55852fbae187756c130aTom Cherry  errors->clear();
102919458c350563e578e2d55852fbae187756c130aTom Cherry
103919458c350563e578e2d55852fbae187756c130aTom Cherry  for (const auto& line : Split(file_contents, "\n")) {
104919458c350563e578e2d55852fbae187756c130aTom Cherry    auto trimmed_line = Trim(line);
105919458c350563e578e2d55852fbae187756c130aTom Cherry    if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) {
106919458c350563e578e2d55852fbae187756c130aTom Cherry      continue;
107919458c350563e578e2d55852fbae187756c130aTom Cherry    }
108919458c350563e578e2d55852fbae187756c130aTom Cherry
109919458c350563e578e2d55852fbae187756c130aTom Cherry    auto property_info_entry = PropertyInfoEntry{};
110919458c350563e578e2d55852fbae187756c130aTom Cherry    auto parse_error = std::string{};
111919458c350563e578e2d55852fbae187756c130aTom Cherry    if (!ParsePropertyInfoLine(trimmed_line, &property_info_entry, &parse_error)) {
112919458c350563e578e2d55852fbae187756c130aTom Cherry      errors->emplace_back(parse_error);
113919458c350563e578e2d55852fbae187756c130aTom Cherry      continue;
114919458c350563e578e2d55852fbae187756c130aTom Cherry    }
115919458c350563e578e2d55852fbae187756c130aTom Cherry
116919458c350563e578e2d55852fbae187756c130aTom Cherry    property_infos->emplace_back(property_info_entry);
117919458c350563e578e2d55852fbae187756c130aTom Cherry  }
118919458c350563e578e2d55852fbae187756c130aTom Cherry}
119919458c350563e578e2d55852fbae187756c130aTom Cherry
120919458c350563e578e2d55852fbae187756c130aTom Cherry}  // namespace properties
121919458c350563e578e2d55852fbae187756c130aTom Cherry}  // namespace android
122