blob: cec3adf49c5d0a0fdd13f2147efba8d074d22cd3 [file] [log] [blame]
Yifan Hong676447a2016-11-15 12:57:23 -08001/*
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// Convert objects from and to strings.
18
19#include "parse_string.h"
20#include <android-base/parseint.h>
21
22namespace android {
23using base::ParseUint;
24
25namespace vintf {
26
27static const std::string kRequired("required");
28static const std::string kOptional("optional");
29static const std::string kConfigPrefix("CONFIG_");
30
31std::vector<std::string> SplitString(const std::string &s, char c) {
32 std::vector<std::string> components;
33
34 size_t startPos = 0;
35 size_t matchPos;
36 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
37 components.push_back(s.substr(startPos, matchPos - startPos));
38 startPos = matchPos + 1;
39 }
40
41 if (startPos <= s.length()) {
42 components.push_back(s.substr(startPos));
43 }
44 return components;
45}
46
47template <typename T>
48std::ostream &operator<<(std::ostream &os, const std::vector<T> objs) {
49 bool first = true;
50 for (const T &v : objs) {
51 if (!first) {
52 os << ",";
53 }
54 os << v;
55 first = false;
56 }
57 return os;
58}
59
60template <typename T>
61bool parse(const std::string &s, std::vector<T> *objs) {
62 std::vector<std::string> v = SplitString(s, ',');
63 objs->resize(v.size());
64 size_t idx = 0;
65 for (const auto &item : v) {
66 T ver;
67 if (!parse(item, &ver)) {
68 return false;
69 }
70 objs->at(idx++) = ver;
71 }
72 return true;
73}
74
75template<typename E, typename Array>
76bool parseEnum(const std::string &s, E *e, const Array &strings) {
77 for (size_t i = 0; i < strings.size(); ++i) {
78 if (s == strings.at(i)) {
79 *e = static_cast<E>(i);
80 return true;
81 }
82 }
83 return false;
84}
85
Yifan Hongc54d32c2017-03-07 19:12:26 -080086#define DEFINE_PARSE_STREAMIN_FOR_ENUM(ENUM) \
87 bool parse(const std::string &s, ENUM *hf) { \
88 return parseEnum(s, hf, g##ENUM##Strings); \
89 } \
90 std::ostream &operator<<(std::ostream &os, ENUM hf) { \
91 return os << g##ENUM##Strings.at(static_cast<size_t>(hf)); \
92 } \
Yifan Hong676447a2016-11-15 12:57:23 -080093
Yifan Hongc54d32c2017-03-07 19:12:26 -080094DEFINE_PARSE_STREAMIN_FOR_ENUM(HalFormat);
Yifan Hongc54d32c2017-03-07 19:12:26 -080095DEFINE_PARSE_STREAMIN_FOR_ENUM(Transport);
96DEFINE_PARSE_STREAMIN_FOR_ENUM(Arch);
97DEFINE_PARSE_STREAMIN_FOR_ENUM(KernelConfigType);
98DEFINE_PARSE_STREAMIN_FOR_ENUM(Tristate);
Yifan Hong3f5489a2017-02-08 11:14:21 -080099
100std::ostream &operator<<(std::ostream &os, const KernelConfigTypedValue &kctv) {
101 switch (kctv.mType) {
102 case KernelConfigType::STRING:
103 return os << kctv.mStringValue;
104 case KernelConfigType::INTEGER:
105 return os << to_string(kctv.mIntegerValue);
106 case KernelConfigType::RANGE:
107 return os << to_string(kctv.mRangeValue.first) << "-"
108 << to_string(kctv.mRangeValue.second);
109 case KernelConfigType::TRISTATE:
110 return os << to_string(kctv.mTristateValue);
111 }
112}
113
114// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
115// because strtoull can accept negative values as well.
116// Notice that according to man strtoul, strtoull can actually accept
117// -2^64 + 1 to 2^64 - 1, with the 65th bit truncated.
118// ParseInt / ParseUint are not used because they do not handle signed hex very well.
119template <typename T>
120bool parseKernelConfigIntHelper(const std::string &s, T *i) {
121 char *end;
122 errno = 0;
123 unsigned long long int ulli = strtoull(s.c_str(), &end, 0 /* base */);
124 // It is implementation defined that what value will be returned by strtoull
125 // in the error case, so we are checking errno directly here.
126 if (errno == 0 && s.c_str() != end && *end == '\0') {
127 *i = static_cast<T>(ulli);
128 return true;
129 }
130 return false;
131}
132
133bool parseKernelConfigInt(const std::string &s, int64_t *i) {
134 return parseKernelConfigIntHelper(s, i);
135}
136
137bool parseKernelConfigInt(const std::string &s, uint64_t *i) {
138 return parseKernelConfigIntHelper(s, i);
139}
140
141bool parseRange(const std::string &s, KernelConfigRangeValue *range) {
142 auto pos = s.find('-');
143 if (pos == std::string::npos) {
144 return false;
145 }
146 return parseKernelConfigInt(s.substr(0, pos), &range->first)
147 && parseKernelConfigInt(s.substr(pos + 1), &range->second);
148}
149
150bool parse(const std::string &s, KernelConfigKey *key) {
151 *key = s;
152 return true;
153}
154
155bool parseKernelConfigValue(const std::string &s, KernelConfigTypedValue *kctv) {
156 switch (kctv->mType) {
157 case KernelConfigType::STRING:
158 kctv->mStringValue = s;
159 return true;
160 case KernelConfigType::INTEGER:
161 return parseKernelConfigInt(s, &kctv->mIntegerValue);
162 case KernelConfigType::RANGE:
163 return parseRange(s, &kctv->mRangeValue);
164 case KernelConfigType::TRISTATE:
165 return parse(s, &kctv->mTristateValue);
166 }
Yifan Hong676447a2016-11-15 12:57:23 -0800167}
168
169bool parse(const std::string &s, Version *ver) {
170 std::vector<std::string> v = SplitString(s, '.');
171 if (v.size() != 2) {
172 return false;
173 }
174 size_t major, minor;
175 if (!ParseUint(v[0], &major)) {
176 return false;
177 }
178 if (!ParseUint(v[1], &minor)) {
179 return false;
180 }
181 *ver = Version(major, minor);
182 return true;
183}
184
185std::ostream &operator<<(std::ostream &os, const Version &ver) {
186 return os << ver.majorVer << "." << ver.minorVer;
187}
188
189bool parse(const std::string &s, VersionRange *vr) {
190 std::vector<std::string> v = SplitString(s, '-');
191 if (v.size() != 1 && v.size() != 2) {
192 return false;
193 }
194 Version minVer;
195 if (!parse(v[0], &minVer)) {
196 return false;
197 }
198 if (v.size() == 1) {
199 *vr = VersionRange(minVer.majorVer, minVer.minorVer);
200 } else {
201 size_t maxMinor;
202 if (!ParseUint(v[1], &maxMinor)) {
203 return false;
204 }
205 *vr = VersionRange(minVer.majorVer, minVer.minorVer, maxMinor);
206 }
207 return true;
208}
209
210std::ostream &operator<<(std::ostream &os, const VersionRange &vr) {
211 if (vr.isSingleVersion()) {
212 return os << vr.minVer();
213 }
214 return os << vr.minVer() << "-" << vr.maxMinor;
215}
216
Yifan Hong3f5489a2017-02-08 11:14:21 -0800217bool parse(const std::string &s, KernelVersion *kernelVersion) {
218 std::vector<std::string> v = SplitString(s, '.');
219 if (v.size() != 3) {
220 return false;
221 }
222 size_t version, major, minor;
223 if (!ParseUint(v[0], &version)) {
224 return false;
225 }
226 if (!ParseUint(v[1], &major)) {
227 return false;
228 }
229 if (!ParseUint(v[2], &minor)) {
230 return false;
231 }
232 *kernelVersion = KernelVersion(version, major, minor);
233 return true;
234}
235
Yifan Hongc54d32c2017-03-07 19:12:26 -0800236std::ostream &operator<<(std::ostream &os, const TransportArch &ta) {
237 return os << to_string(ta.transport) << to_string(ta.arch);
238}
239
240bool parse(const std::string &s, TransportArch *ta) {
241 bool transportSet = false;
242 bool archSet = false;
243 for (size_t i = 0; i < gTransportStrings.size(); ++i) {
244 if (s.find(gTransportStrings.at(i)) != std::string::npos) {
245 ta->transport = static_cast<Transport>(i);
246 transportSet = true;
247 break;
248 }
249 }
250 if (!transportSet) {
251 return false;
252 }
253 for (size_t i = 0; i < gArchStrings.size(); ++i) {
254 if (s.find(gArchStrings.at(i)) != std::string::npos) {
255 ta->arch = static_cast<Arch>(i);
256 archSet = true;
257 break;
258 }
259 }
260 if (!archSet) {
261 return false;
262 }
263 return ta->isValid();
264}
265
Yifan Hong3f5489a2017-02-08 11:14:21 -0800266std::ostream &operator<<(std::ostream &os, const KernelVersion &ver) {
267 return os << ver.version << "." << ver.majorRev << "." << ver.minorRev;
268}
269
Yifan Hong676447a2016-11-15 12:57:23 -0800270bool parse(const std::string &s, ManifestHal *hal) {
271 std::vector<std::string> v = SplitString(s, '/');
Yifan Hong974ad9c2017-04-04 15:37:39 -0700272 if (v.size() != 4) {
Yifan Hong676447a2016-11-15 12:57:23 -0800273 return false;
274 }
275 if (!parse(v[0], &hal->format)) {
276 return false;
277 }
278 hal->name = v[1];
Yifan Hongc54d32c2017-03-07 19:12:26 -0800279 if (!parse(v[2], &hal->transportArch)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800280 return false;
281 }
Yifan Hong974ad9c2017-04-04 15:37:39 -0700282 if (!parse(v[3], &hal->versions)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800283 return false;
284 }
Yifan Hong5a06ef72017-01-24 19:54:24 -0800285 return hal->isValid();
Yifan Hong676447a2016-11-15 12:57:23 -0800286}
287
288std::ostream &operator<<(std::ostream &os, const ManifestHal &hal) {
289 return os << hal.format << "/"
290 << hal.name << "/"
Yifan Hongc54d32c2017-03-07 19:12:26 -0800291 << hal.transportArch << "/"
Yifan Hong676447a2016-11-15 12:57:23 -0800292 << hal.versions;
293}
294
295bool parse(const std::string &s, MatrixHal *req) {
296 std::vector<std::string> v = SplitString(s, '/');
297 if (v.size() != 4) {
298 return false;
299 }
300 if (!parse(v[0], &req->format)) {
301 return false;
302 }
303 req->name = v[1];
304 if (!parse(v[2], &req->versionRanges)) {
305 return false;
306 }
307 if (v[3] != kRequired || v[3] != kOptional) {
308 return false;
309 }
310 req->optional = (v[3] == kOptional);
311 return true;
312}
313
314std::ostream &operator<<(std::ostream &os, const MatrixHal &req) {
315 return os << req.format << "/"
316 << req.name << "/"
317 << req.versionRanges << "/"
318 << (req.optional ? kOptional : kRequired);
319}
320
Yifan Hong558380a2017-02-09 15:37:32 -0800321
322std::ostream &operator<<(std::ostream &os, KernelSepolicyVersion ksv){
323 return os << ksv.value;
324}
325
326bool parse(const std::string &s, KernelSepolicyVersion *ksv){
327 return ParseUint(s, &ksv->value);
328}
329
330std::ostream &operator<<(std::ostream &os, const SepolicyVersion &sv){
331 return os << sv.minVer << "-" << sv.maxVer;
332}
333
334bool parse(const std::string &s, SepolicyVersion *sv){
335 std::vector<std::string> v = SplitString(s, '-');
336 if (v.size() != 2) {
337 return false;
338 }
339 if (!ParseUint(v[0], &sv->minVer)) {
340 return false;
341 }
342 if (!ParseUint(v[1], &sv->maxVer)) {
343 return false;
344 }
345 return true;
346}
347
Yifan Hongd2b7e642017-02-17 10:15:32 -0800348std::string dump(const HalManifest &vm) {
Yifan Hong676447a2016-11-15 12:57:23 -0800349 std::ostringstream oss;
350 bool first = true;
Yifan Hongef6d4d32017-01-23 14:12:28 -0800351 for (const auto &hal : vm.getHals()) {
Yifan Hong676447a2016-11-15 12:57:23 -0800352 if (!first) {
353 oss << ":";
354 }
355 oss << hal;
356 first = false;
357 }
358 return oss.str();
359}
360
Yifan Honga7201e72017-02-17 10:09:59 -0800361std::string dump(const RuntimeInfo &ki) {
Yifan Hongccf967b2017-01-18 11:04:19 -0800362 std::ostringstream oss;
363
364 oss << "kernel = "
365 << ki.osName() << "/"
366 << ki.nodeName() << "/"
367 << ki.osRelease() << "/"
368 << ki.osVersion() << "/"
369 << ki.hardwareId() << ";"
370 << "kernelSepolicyVersion = " << ki.kernelSepolicyVersion() << ";"
Yifan Hongf1af7522017-02-16 18:00:55 -0800371 << "#CONFIG's loaded = " << ki.mKernelConfigs.size() << ";\n";
372 for (const auto &pair : ki.mKernelConfigs) {
Yifan Hongccf967b2017-01-18 11:04:19 -0800373 oss << pair.first << "=" << pair.second << "\n";
374 }
375
376 return oss.str();
377}
378
Yifan Hong676447a2016-11-15 12:57:23 -0800379} // namespace vintf
380} // namespace android