• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
23 #include "AudioTypes.h"
24 
25 namespace android::mediametrics::stringutils {
26 
tokenizer(std::string::const_iterator & it,const std::string::const_iterator & end,const char * reserved)27 std::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 
split(const std::string & flags,const char * delim)43 std::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 
getDeviceAddressPairs(const std::string & devices)57 std::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 
replace(std::string & str,const char * targetChars,const char replaceChar)92 size_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 
104 template <types::AudioEnumCategory CATEGORY>
105 std::pair<std::string /* external statsd */, std::string /* internal */>
parseDevicePairs(const std::string & devicePairs)106 parseDevicePairs(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 
120 std::pair<std::string /* external statsd */, std::string /* internal */>
parseOutputDevicePairs(const std::string & devicePairs)121 parseOutputDevicePairs(const std::string& devicePairs) {
122     return parseDevicePairs<types::OUTPUT_DEVICE>(devicePairs);
123 }
124 
125 std::pair<std::string /* external statsd */, std::string /* internal */>
parseInputDevicePairs(const std::string & devicePairs)126 parseInputDevicePairs(const std::string& devicePairs) {
127     return parseDevicePairs<types::INPUT_DEVICE>(devicePairs);
128 }
129 
130 } // namespace android::mediametrics::stringutils
131