blob: f6ecc319bebd202bb35bb4262dfb65db5f6b5fd3 [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);
95DEFINE_PARSE_STREAMIN_FOR_ENUM(ImplLevel);
96DEFINE_PARSE_STREAMIN_FOR_ENUM(Transport);
97DEFINE_PARSE_STREAMIN_FOR_ENUM(Arch);
98DEFINE_PARSE_STREAMIN_FOR_ENUM(KernelConfigType);
99DEFINE_PARSE_STREAMIN_FOR_ENUM(Tristate);
Yifan Hong3f5489a2017-02-08 11:14:21 -0800100
101std::ostream &operator<<(std::ostream &os, const KernelConfigTypedValue &kctv) {
102 switch (kctv.mType) {
103 case KernelConfigType::STRING:
104 return os << kctv.mStringValue;
105 case KernelConfigType::INTEGER:
106 return os << to_string(kctv.mIntegerValue);
107 case KernelConfigType::RANGE:
108 return os << to_string(kctv.mRangeValue.first) << "-"
109 << to_string(kctv.mRangeValue.second);
110 case KernelConfigType::TRISTATE:
111 return os << to_string(kctv.mTristateValue);
112 }
113}
114
115// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
116// because strtoull can accept negative values as well.
117// Notice that according to man strtoul, strtoull can actually accept
118// -2^64 + 1 to 2^64 - 1, with the 65th bit truncated.
119// ParseInt / ParseUint are not used because they do not handle signed hex very well.
120template <typename T>
121bool parseKernelConfigIntHelper(const std::string &s, T *i) {
122 char *end;
123 errno = 0;
124 unsigned long long int ulli = strtoull(s.c_str(), &end, 0 /* base */);
125 // It is implementation defined that what value will be returned by strtoull
126 // in the error case, so we are checking errno directly here.
127 if (errno == 0 && s.c_str() != end && *end == '\0') {
128 *i = static_cast<T>(ulli);
129 return true;
130 }
131 return false;
132}
133
134bool parseKernelConfigInt(const std::string &s, int64_t *i) {
135 return parseKernelConfigIntHelper(s, i);
136}
137
138bool parseKernelConfigInt(const std::string &s, uint64_t *i) {
139 return parseKernelConfigIntHelper(s, i);
140}
141
142bool parseRange(const std::string &s, KernelConfigRangeValue *range) {
143 auto pos = s.find('-');
144 if (pos == std::string::npos) {
145 return false;
146 }
147 return parseKernelConfigInt(s.substr(0, pos), &range->first)
148 && parseKernelConfigInt(s.substr(pos + 1), &range->second);
149}
150
151bool parse(const std::string &s, KernelConfigKey *key) {
152 *key = s;
153 return true;
154}
155
156bool parseKernelConfigValue(const std::string &s, KernelConfigTypedValue *kctv) {
157 switch (kctv->mType) {
158 case KernelConfigType::STRING:
159 kctv->mStringValue = s;
160 return true;
161 case KernelConfigType::INTEGER:
162 return parseKernelConfigInt(s, &kctv->mIntegerValue);
163 case KernelConfigType::RANGE:
164 return parseRange(s, &kctv->mRangeValue);
165 case KernelConfigType::TRISTATE:
166 return parse(s, &kctv->mTristateValue);
167 }
Yifan Hong676447a2016-11-15 12:57:23 -0800168}
169
170bool parse(const std::string &s, Version *ver) {
171 std::vector<std::string> v = SplitString(s, '.');
172 if (v.size() != 2) {
173 return false;
174 }
175 size_t major, minor;
176 if (!ParseUint(v[0], &major)) {
177 return false;
178 }
179 if (!ParseUint(v[1], &minor)) {
180 return false;
181 }
182 *ver = Version(major, minor);
183 return true;
184}
185
186std::ostream &operator<<(std::ostream &os, const Version &ver) {
187 return os << ver.majorVer << "." << ver.minorVer;
188}
189
190bool parse(const std::string &s, VersionRange *vr) {
191 std::vector<std::string> v = SplitString(s, '-');
192 if (v.size() != 1 && v.size() != 2) {
193 return false;
194 }
195 Version minVer;
196 if (!parse(v[0], &minVer)) {
197 return false;
198 }
199 if (v.size() == 1) {
200 *vr = VersionRange(minVer.majorVer, minVer.minorVer);
201 } else {
202 size_t maxMinor;
203 if (!ParseUint(v[1], &maxMinor)) {
204 return false;
205 }
206 *vr = VersionRange(minVer.majorVer, minVer.minorVer, maxMinor);
207 }
208 return true;
209}
210
211std::ostream &operator<<(std::ostream &os, const VersionRange &vr) {
212 if (vr.isSingleVersion()) {
213 return os << vr.minVer();
214 }
215 return os << vr.minVer() << "-" << vr.maxMinor;
216}
217
Yifan Hong3f5489a2017-02-08 11:14:21 -0800218bool parse(const std::string &s, KernelVersion *kernelVersion) {
219 std::vector<std::string> v = SplitString(s, '.');
220 if (v.size() != 3) {
221 return false;
222 }
223 size_t version, major, minor;
224 if (!ParseUint(v[0], &version)) {
225 return false;
226 }
227 if (!ParseUint(v[1], &major)) {
228 return false;
229 }
230 if (!ParseUint(v[2], &minor)) {
231 return false;
232 }
233 *kernelVersion = KernelVersion(version, major, minor);
234 return true;
235}
236
Yifan Hongc54d32c2017-03-07 19:12:26 -0800237std::ostream &operator<<(std::ostream &os, const TransportArch &ta) {
238 return os << to_string(ta.transport) << to_string(ta.arch);
239}
240
241bool parse(const std::string &s, TransportArch *ta) {
242 bool transportSet = false;
243 bool archSet = false;
244 for (size_t i = 0; i < gTransportStrings.size(); ++i) {
245 if (s.find(gTransportStrings.at(i)) != std::string::npos) {
246 ta->transport = static_cast<Transport>(i);
247 transportSet = true;
248 break;
249 }
250 }
251 if (!transportSet) {
252 return false;
253 }
254 for (size_t i = 0; i < gArchStrings.size(); ++i) {
255 if (s.find(gArchStrings.at(i)) != std::string::npos) {
256 ta->arch = static_cast<Arch>(i);
257 archSet = true;
258 break;
259 }
260 }
261 if (!archSet) {
262 return false;
263 }
264 return ta->isValid();
265}
266
Yifan Hong3f5489a2017-02-08 11:14:21 -0800267std::ostream &operator<<(std::ostream &os, const KernelVersion &ver) {
268 return os << ver.version << "." << ver.majorRev << "." << ver.minorRev;
269}
270
Yifan Hong676447a2016-11-15 12:57:23 -0800271bool parse(const std::string &s, ManifestHal *hal) {
272 std::vector<std::string> v = SplitString(s, '/');
273 if (v.size() != 5) {
274 return false;
275 }
276 if (!parse(v[0], &hal->format)) {
277 return false;
278 }
279 hal->name = v[1];
Yifan Hongc54d32c2017-03-07 19:12:26 -0800280 if (!parse(v[2], &hal->transportArch)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800281 return false;
282 }
283 if (!parse(v[3], &hal->impl.implLevel)) {
284 return false;
285 }
286 hal->impl.impl = v[4];
287 if (!parse(v[5], &hal->versions)) {
288 return false;
289 }
Yifan Hong5a06ef72017-01-24 19:54:24 -0800290 return hal->isValid();
Yifan Hong676447a2016-11-15 12:57:23 -0800291}
292
293std::ostream &operator<<(std::ostream &os, const ManifestHal &hal) {
294 return os << hal.format << "/"
295 << hal.name << "/"
Yifan Hongc54d32c2017-03-07 19:12:26 -0800296 << hal.transportArch << "/"
Yifan Hong676447a2016-11-15 12:57:23 -0800297 << hal.impl.implLevel << "/"
298 << hal.impl.impl << "/"
299 << hal.versions;
300}
301
302bool parse(const std::string &s, MatrixHal *req) {
303 std::vector<std::string> v = SplitString(s, '/');
304 if (v.size() != 4) {
305 return false;
306 }
307 if (!parse(v[0], &req->format)) {
308 return false;
309 }
310 req->name = v[1];
311 if (!parse(v[2], &req->versionRanges)) {
312 return false;
313 }
314 if (v[3] != kRequired || v[3] != kOptional) {
315 return false;
316 }
317 req->optional = (v[3] == kOptional);
318 return true;
319}
320
321std::ostream &operator<<(std::ostream &os, const MatrixHal &req) {
322 return os << req.format << "/"
323 << req.name << "/"
324 << req.versionRanges << "/"
325 << (req.optional ? kOptional : kRequired);
326}
327
Yifan Hong558380a2017-02-09 15:37:32 -0800328
329std::ostream &operator<<(std::ostream &os, KernelSepolicyVersion ksv){
330 return os << ksv.value;
331}
332
333bool parse(const std::string &s, KernelSepolicyVersion *ksv){
334 return ParseUint(s, &ksv->value);
335}
336
337std::ostream &operator<<(std::ostream &os, const SepolicyVersion &sv){
338 return os << sv.minVer << "-" << sv.maxVer;
339}
340
341bool parse(const std::string &s, SepolicyVersion *sv){
342 std::vector<std::string> v = SplitString(s, '-');
343 if (v.size() != 2) {
344 return false;
345 }
346 if (!ParseUint(v[0], &sv->minVer)) {
347 return false;
348 }
349 if (!ParseUint(v[1], &sv->maxVer)) {
350 return false;
351 }
352 return true;
353}
354
Yifan Hongd2b7e642017-02-17 10:15:32 -0800355std::string dump(const HalManifest &vm) {
Yifan Hong676447a2016-11-15 12:57:23 -0800356 std::ostringstream oss;
357 bool first = true;
Yifan Hongef6d4d32017-01-23 14:12:28 -0800358 for (const auto &hal : vm.getHals()) {
Yifan Hong676447a2016-11-15 12:57:23 -0800359 if (!first) {
360 oss << ":";
361 }
362 oss << hal;
363 first = false;
364 }
365 return oss.str();
366}
367
Yifan Honga7201e72017-02-17 10:09:59 -0800368std::string dump(const RuntimeInfo &ki) {
Yifan Hongccf967b2017-01-18 11:04:19 -0800369 std::ostringstream oss;
370
371 oss << "kernel = "
372 << ki.osName() << "/"
373 << ki.nodeName() << "/"
374 << ki.osRelease() << "/"
375 << ki.osVersion() << "/"
376 << ki.hardwareId() << ";"
377 << "kernelSepolicyVersion = " << ki.kernelSepolicyVersion() << ";"
Yifan Hongf1af7522017-02-16 18:00:55 -0800378 << "#CONFIG's loaded = " << ki.mKernelConfigs.size() << ";\n";
379 for (const auto &pair : ki.mKernelConfigs) {
Yifan Hongccf967b2017-01-18 11:04:19 -0800380 oss << pair.first << "=" << pair.second << "\n";
381 }
382
383 return oss.str();
384}
385
Yifan Hong676447a2016-11-15 12:57:23 -0800386} // namespace vintf
387} // namespace android