blob: d1c7a18c8c6a9f3f9146f78dee68817a81283f28 [file] [log] [blame]
Andy Hung1ea842e2020-05-18 10:47:31 -07001/*
2 * Copyright (C) 2020 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//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaMetricsService::stringutils"
19#include <utils/Log.h>
20
21#include "StringUtils.h"
22
Andy Hung76adef72022-09-14 17:24:19 -070023#include "AudioTypes.h"
24
Andy Hung1ea842e2020-05-18 10:47:31 -070025namespace android::mediametrics::stringutils {
26
27std::string tokenizer(std::string::const_iterator& it,
28 const std::string::const_iterator& end, const char *reserved)
29{
30 // consume leading white space
31 for (; it != end && std::isspace(*it); ++it);
32 if (it == end) return {};
33
34 auto start = it;
35 // parse until we hit a reserved keyword or space
36 if (strchr(reserved, *it)) return {start, ++it};
37 for (;;) {
38 ++it;
39 if (it == end || std::isspace(*it) || strchr(reserved, *it)) return {start, it};
40 }
41}
42
43std::vector<std::string> split(const std::string& flags, const char *delim)
44{
45 std::vector<std::string> result;
46 for (auto it = flags.begin(); ; ) {
47 auto flag = tokenizer(it, flags.end(), delim);
48 if (flag.empty() || !std::isalnum(flag[0])) return result;
49 result.emplace_back(std::move(flag));
50
51 // look for the delimeter and discard
52 auto token = tokenizer(it, flags.end(), delim);
53 if (token.size() != 1 || strchr(delim, token[0]) == nullptr) return result;
54 }
55}
56
57std::vector<std::pair<std::string, std::string>> getDeviceAddressPairs(const std::string& devices)
58{
59 std::vector<std::pair<std::string, std::string>> result;
60
61 // Currently, the device format is EXACTLY
62 // (device1, addr1)|(device2, addr2)|...
63
64 static constexpr char delim[] = "()|,";
65 for (auto it = devices.begin(); ; ) {
66 auto token = tokenizer(it, devices.end(), delim);
67 if (token != "(") return result;
68
69 auto device = tokenizer(it, devices.end(), delim);
70 if (device.empty() || !std::isalnum(device[0])) return result;
71
72 token = tokenizer(it, devices.end(), delim);
73 if (token != ",") return result;
74
75 // special handling here for empty addresses
76 auto address = tokenizer(it, devices.end(), delim);
77 if (address.empty() || !std::isalnum(device[0])) return result;
78 if (address == ")") { // no address, just the ")"
79 address.clear();
80 } else {
81 token = tokenizer(it, devices.end(), delim);
82 if (token != ")") return result;
83 }
84
85 result.emplace_back(std::move(device), std::move(address));
86
87 token = tokenizer(it, devices.end(), delim);
88 if (token != "|") return result; // this includes end of string detection
89 }
90}
91
92size_t replace(std::string &str, const char *targetChars, const char replaceChar)
93{
94 size_t replaced = 0;
95 for (char &c : str) {
96 if (strchr(targetChars, c) != nullptr) {
97 c = replaceChar;
98 ++replaced;
99 }
100 }
101 return replaced;
102}
103
Andy Hung76adef72022-09-14 17:24:19 -0700104template <types::AudioEnumCategory CATEGORY>
105std::pair<std::string /* external statsd */, std::string /* internal */>
106parseDevicePairs(const std::string& devicePairs) {
107 std::pair<std::string, std::string> result{};
108 const auto devaddrvec = stringutils::getDeviceAddressPairs(devicePairs);
109 for (const auto& [device, addr] : devaddrvec) { // addr ignored for now.
110 if (!result.second.empty()) {
111 result.second.append("|"); // delimit devices with '|'.
112 result.first.append("|");
113 }
114 result.second.append(device);
115 result.first.append(types::lookup<CATEGORY, std::string>(device));
116 }
117 return result;
118}
119
120std::pair<std::string /* external statsd */, std::string /* internal */>
121parseOutputDevicePairs(const std::string& devicePairs) {
122 return parseDevicePairs<types::OUTPUT_DEVICE>(devicePairs);
123}
124
125std::pair<std::string /* external statsd */, std::string /* internal */>
126parseInputDevicePairs(const std::string& devicePairs) {
127 return parseDevicePairs<types::INPUT_DEVICE>(devicePairs);
128}
129
Andy Hung1ea842e2020-05-18 10:47:31 -0700130} // namespace android::mediametrics::stringutils