1 /***
2 This file is part of snapcast
3 Copyright (C) 2014-2020 Johannes Pohl
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 ***/
18
19 #ifndef STRING_UTILS_H
20 #define STRING_UTILS_H
21
22 #include <algorithm>
23 #include <map>
24 #include <sstream>
25 #include <stdio.h>
26 #include <string>
27 #include <vector>
28 #ifdef WINDOWS
29 #include <cctype>
30 #endif
31
32 namespace utils
33 {
34 namespace string
35 {
36
37 // trim from start
ltrim(std::string & s)38 static inline std::string& ltrim(std::string& s)
39 {
40 s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); }));
41 return s;
42 }
43
44 // trim from end
rtrim(std::string & s)45 static inline std::string& rtrim(std::string& s)
46 {
47 s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end());
48 return s;
49 }
50
51 // trim from both ends
trim(std::string & s)52 static inline std::string& trim(std::string& s)
53 {
54 return ltrim(rtrim(s));
55 }
56
57 // trim from start
ltrim_copy(const std::string & s)58 static inline std::string ltrim_copy(const std::string& s)
59 {
60 std::string str(s);
61 return ltrim(str);
62 }
63
64 // trim from end
rtrim_copy(const std::string & s)65 static inline std::string rtrim_copy(const std::string& s)
66 {
67 std::string str(s);
68 return rtrim(str);
69 }
70
71 // trim from both ends
trim_copy(const std::string & s)72 static inline std::string trim_copy(const std::string& s)
73 {
74 std::string str(s);
75 return trim(str);
76 }
77
78 // decode %xx to char
uriDecode(const std::string & src)79 static std::string uriDecode(const std::string& src)
80 {
81 std::string ret;
82 char ch;
83 for (size_t i = 0; i < src.length(); i++)
84 {
85 if (int(src[i]) == 37)
86 {
87 unsigned int ii;
88 sscanf(src.substr(i + 1, 2).c_str(), "%x", &ii);
89 ch = static_cast<char>(ii);
90 ret += ch;
91 i += 2;
92 }
93 else
94 {
95 ret += src[i];
96 }
97 }
98 return (ret);
99 }
100
101
split_left(const std::string & s,char delim,std::string & left,std::string & right)102 static void split_left(const std::string& s, char delim, std::string& left, std::string& right)
103 {
104 auto pos = s.find(delim);
105 if (pos != std::string::npos)
106 {
107 left = s.substr(0, pos);
108 right = s.substr(pos + 1);
109 }
110 else
111 {
112 left = s;
113 right = "";
114 }
115 }
116
117
split_left(const std::string & s,char delim,std::string & right)118 static std::string split_left(const std::string& s, char delim, std::string& right)
119 {
120 std::string left;
121 split_left(s, delim, left, right);
122 return left;
123 }
124
125
126
split(const std::string & s,char delim,std::vector<std::string> & elems)127 static std::vector<std::string>& split(const std::string& s, char delim, std::vector<std::string>& elems)
128 {
129 std::stringstream ss(s);
130 std::string item;
131 while (std::getline(ss, item, delim))
132 {
133 elems.push_back(item);
134 }
135 return elems;
136 }
137
138
split(const std::string & s,char delim)139 static std::vector<std::string> split(const std::string& s, char delim)
140 {
141 std::vector<std::string> elems;
142 split(s, delim, elems);
143 return elems;
144 }
145
146 template <typename T>
split_pairs_to_container(const std::string & s,char pair_delim,char key_value_delim)147 static std::map<std::string, T> split_pairs_to_container(const std::string& s, char pair_delim, char key_value_delim)
148 {
149 std::map<std::string, T> result;
150 auto keyValueList = split(s, pair_delim);
151 for (auto& kv : keyValueList)
152 {
153 auto pos = kv.find(key_value_delim);
154 if (pos != std::string::npos)
155 {
156 std::string key = trim_copy(kv.substr(0, pos));
157 std::string value = trim_copy(kv.substr(pos + 1));
158 result[key].push_back(std::move(value));
159 }
160 }
161 return result;
162 }
163
164
split_pairs(const std::string & s,char pair_delim,char key_value_delim)165 static std::map<std::string, std::string> split_pairs(const std::string& s, char pair_delim, char key_value_delim)
166 {
167 std::map<std::string, std::string> result;
168 auto pairs = split_pairs_to_container<std::vector<std::string>>(s, pair_delim, key_value_delim);
169 for (auto& pair : pairs)
170 result[pair.first] = *pair.second.begin();
171 return result;
172 }
173
174
175 } // namespace string
176 } // namespace utils
177
178 #endif
179