libfilezilla
string.hpp
Go to the documentation of this file.
1 #ifndef LIBFILEZILLA_STRING_HEADER
2 #define LIBFILEZILLA_STRING_HEADER
3 
4 #include "libfilezilla.hpp"
5 
6 #include <string>
7 #include <vector>
8 
16 namespace fz {
17 
30 #ifdef FZ_WINDOWS
31 typedef std::wstring native_string;
32 #endif
33 #if defined(FZ_UNIX) || defined(FZ_MAC)
34 typedef std::string native_string;
35 #endif
36 
41 native_string FZ_PUBLIC_SYMBOL to_native(std::string const& in);
42 
47 native_string FZ_PUBLIC_SYMBOL to_native(std::wstring const& in);
48 
55 int FZ_PUBLIC_SYMBOL stricmp(std::string const& a, std::string const& b);
56 int FZ_PUBLIC_SYMBOL stricmp(std::wstring const& a, std::wstring const& b);
57 
75 template<typename Char>
76 Char tolower_ascii(Char c) {
77  if (c >= 'A' && c <= 'Z') {
78  return c + ('a' - 'A');
79  }
80  return c;
81 }
82 
83 template<>
84 std::wstring::value_type FZ_PUBLIC_SYMBOL tolower_ascii(std::wstring::value_type c);
85 
87 template<typename Char>
88 Char toupper_ascii(Char c) {
89  if (c >= 'a' && c <= 'z') {
90  return c + ('A' - 'a');
91  }
92  return c;
93 }
94 
95 template<>
96 std::wstring::value_type FZ_PUBLIC_SYMBOL toupper_ascii(std::wstring::value_type c);
97 
100  // Note: For UTF-8 strings it works on individual octets!
101 template<typename String>
102 String str_tolower_ascii(String const& s)
103 {
104  String ret = s;
105  for (auto& c : ret) {
106  c = tolower_ascii(c);
107  }
108  return ret;
109 }
110 
111 template<typename String>
112 String str_toupper_ascii(String const& s)
113 {
114  String ret = s;
115  for (auto& c : ret) {
116  c = toupper_ascii(c);
117  }
118  return ret;
119 }
120 
127 std::wstring FZ_PUBLIC_SYMBOL to_wstring(std::string const& in);
128 
130 inline std::wstring FZ_PUBLIC_SYMBOL to_wstring(std::wstring const& in) { return in; }
131 
133 template<typename Arg>
134 inline typename std::enable_if<std::is_arithmetic<std::decay_t<Arg>>::value, std::wstring>::type to_wstring(Arg && arg)
135 {
136  return std::to_wstring(std::forward<Arg>(arg));
137 }
138 
139 
144 std::wstring FZ_PUBLIC_SYMBOL to_wstring_from_utf8(std::string const& in);
145 
152 std::string FZ_PUBLIC_SYMBOL to_string(std::wstring const& in);
153 
155 inline std::string FZ_PUBLIC_SYMBOL to_string(std::string const& in) { return in; }
156 
158 template<typename Arg>
159 inline typename std::enable_if<std::is_arithmetic<std::decay_t<Arg>>::value, std::string>::type to_string(Arg && arg)
160 {
161  return std::to_string(std::forward<Arg>(arg));
162 }
163 
164 
166 template<typename Char>
167 size_t strlen(Char const* str) {
168  return std::char_traits<Char>::length(str);
169 }
170 
171 
178 std::string FZ_PUBLIC_SYMBOL to_utf8(std::string const& in);
179 
186 std::string FZ_PUBLIC_SYMBOL to_utf8(std::wstring const& in);
187 
188 
195 template<typename Char>
196 int hex_char_to_int(Char c)
197 {
198  if (c >= 'a' && c <= 'z') {
199  return c - 'a' + 10;
200  }
201  if (c >= 'A' && c <= 'Z') {
202  return c - 'A' + 10;
203  }
204  else if (c >= '0' && c <= '9') {
205  return c - '0';
206  }
207  return -1;
208 }
209 
210 template<typename String>
211 std::vector<uint8_t> hex_decode(String const& in)
212 {
213  std::vector<uint8_t> ret;
214  if (!(in.size() % 2)) {
215  ret.reserve(in.size() / 2);
216  for (size_t i = 0; i < in.size(); i += 2) {
217  int high = hex_char_to_int(in[i]);
218  int low = hex_char_to_int(in[i + 1]);
219  if (high == -1 || low == -1) {
220  return std::vector<uint8_t>();
221  }
222  ret.push_back(static_cast<uint8_t>((high << 4) + low));
223  }
224  }
225 
226  return ret;
227 }
228 
235 template<typename Char = char, bool Lowercase = true>
236 Char int_to_hex_char(int d)
237 {
238  if (d > 9) {
239  return (Lowercase ? 'a' : 'A') + d - 10;
240  }
241  else {
242  return '0' + d;
243  }
244 }
245 
246 template<typename String, typename InString, bool Lowercase = true>
247 String hex_encode(InString const& data)
248 {
249  static_assert(sizeof(typename InString::value_type) == 1, "Input must be a container of 8 bit values");
250  String ret;
251  ret.reserve(data.size() * 2);
252  for (auto const& c : data) {
253  ret.push_back(int_to_hex_char<typename String::value_type, Lowercase>(static_cast<unsigned char>(c) >> 4));
254  ret.push_back(int_to_hex_char<typename String::value_type, Lowercase>(static_cast<unsigned char>(c) & 0xf));
255  }
256 
257  return ret;
258 }
259 
261 template<typename String, typename Arg>
262 inline auto toString(Arg&& arg) -> typename std::enable_if<std::is_same<String, std::string>::value, decltype(to_string(std::forward<Arg>(arg)))>::type
263 {
264  return to_string(std::forward<Arg>(arg));
265 }
266 
267 template<typename String, typename Arg>
268 inline auto toString(Arg&& arg) -> typename std::enable_if<std::is_same<String, std::wstring>::value, decltype(to_wstring(std::forward<Arg>(arg)))>::type
269 {
270  return to_wstring(std::forward<Arg>(arg));
271 }
272 
273 #if !defined(fzT) || defined(DOXYGEN)
274 #ifdef FZ_WINDOWS
275 
279 #define fzT(x) L ## x
280 #else
281 
285 #define fzT(x) x
286 #endif
287 #endif
288 
290 template<typename Char>
291 Char const* choose_string(char const* c, wchar_t const* w);
292 
293 template<> inline char const* choose_string(char const* c, wchar_t const*) { return c; }
294 template<> inline wchar_t const* choose_string(char const*, wchar_t const* w) { return w; }
295 
296 #if !defined(fzS) || defined(DOXYGEN)
297 
308 #define fzS(Char, s) fz::choose_string<Char>(s, L ## s)
309 #endif
310 
312 std::string FZ_PUBLIC_SYMBOL replaced_substrings(std::string const& in, std::string const& find, std::string const& replacement);
313 std::wstring FZ_PUBLIC_SYMBOL replaced_substrings(std::wstring const& in, std::wstring const& find, std::wstring const& replacement);
314 
316 void FZ_PUBLIC_SYMBOL replace_substrings(std::string& in, std::string const& find, std::string const& replacement);
317 void FZ_PUBLIC_SYMBOL replace_substrings(std::wstring& in, std::wstring const& find, std::wstring const& replacement);
318 
320 template<typename String, typename Delim, typename Container = std::vector<String>>
321 Container strtok(String const& s, Delim const& delims)
322 {
323  Container ret;
324 
325  typename String::size_type start{}, pos{};
326  do {
327  pos = s.find_first_of(delims, start);
328 
329  // Not found, we're at ends;
330  if (pos == String::npos) {
331  if (start + 1 < s.size()) {
332  ret.emplace_back(s.substr(start));
333  }
334  }
335  else if (pos > start + 1) {
336  // Non-empty substring
337  ret.emplace_back(s.substr(start, pos - start));
338  }
339  start = pos + 1;
340  } while (pos != String::npos);
341 
342  return ret;
343 }
344 
345 
347 std::string FZ_PUBLIC_SYMBOL base64_encode(std::string const& in);
348 
350 std::string FZ_PUBLIC_SYMBOL base64_decode(std::string const& in);
351 
352 // Converts string to integral type T. If string is not convertible, T() is returned.
353 template<typename T, typename String>
354 T to_integral(String const& s, T const errorval = T())
355 {
356  T ret{};
357 
358  auto it = s.cbegin();
359  if (it != s.cend() && (*it == '-' || *it == '+')) {
360  ++it;
361  }
362 
363  if (it == s.cend()) {
364  return errorval;
365  }
366 
367  for (; it != s.cend(); ++it) {
368  auto const& c = *it;
369  if (c < '0' || c > '9') {
370  return errorval;
371  }
372  ret *= 10;
373  ret += c - '0';
374  }
375 
376  if (!s.empty() && s.front() == '-') {
377  return ret *= static_cast<T>(-1);
378  }
379  else {
380  return ret;
381  }
382 }
383 
385 template<typename String>
386 bool str_is_ascii(String const& s) {
387  for (auto const& c : s) {
388  if (static_cast<std::make_unsigned_t<typename String::value_type>>(c) > 127) {
389  return false;
390  }
391  }
392 
393  return true;
394 }
395 
397 template<typename String>
398 String trimmed(String const& s) {
399  size_t const first = s.find_first_not_of(fzS(typename String::value_type, " \r\n\t"));
400  if (first == String::npos) {
401  return String();
402  }
403  else {
404  // Cannot be npos
405  size_t const last = s.find_last_not_of(fzS(typename String::value_type, " \r\n\t"));
406 
407  return s.substr(first, last - first + 1);
408  }
409 }
410 
411 
413 template<typename String>
414 void trim(String & s) {
415  s = trimmed(s);
416 }
417 
418 }
419 
420 #endif
std::wstring to_wstring_from_utf8(std::string const &in)
Converts from std::string in UTF-8 into std::wstring.
Char toupper_ascii(Char c)
Converts ASCII lowercase characters to uppercase as if C-locale is used.
Definition: string.hpp:88
Char int_to_hex_char(int d)
Converts an integer to the corresponding lowercase hex digit.
Definition: string.hpp:236
int hex_char_to_int(Char c)
Converts a hex digit to decimal int.
Definition: string.hpp:196
std::enable_if< std::is_arithmetic< std::decay_t< Arg > >::value, std::wstring >::type to_wstring(Arg &&arg)
Converts from arithmetic type to std::wstring.
Definition: string.hpp:134
std::enable_if< std::is_arithmetic< std::decay_t< Arg > >::value, std::string >::type to_string(Arg &&arg)
Converts from arithmetic type to std::string.
Definition: string.hpp:159
#define fzS(Char, s)
Macro to get const pointer to a string of the corresponding type.
Definition: string.hpp:308
int stricmp(std::string const &a, std::string const &b)
Locale-sensitive stricmp.
Char tolower_ascii(Char c)
Converts ASCII uppercase characters to lowercase as if C-locale is used.
Definition: string.hpp:76
std::string replaced_substrings(std::string const &in, std::string const &find, std::string const &replacement)
Returns in with all occurrences of find in the input string replaced with replacement.
std::string to_utf8(std::string const &in)
Converts from std::string in native encoding into std::string in UTF-8.
void replace_substrings(std::string &in, std::string const &find, std::string const &replacement)
Modifies in, replacing all occurrences of find with replacement.
size_t strlen(Char const *str)
Returns length of 0-terminated character sequence. Works with both narrow and wide-characters.
Definition: string.hpp:167
bool str_is_ascii(String const &s)
Returns true iff the string only has characters in the 7-bit ASCII range.
Definition: string.hpp:386
Container strtok(String const &s, Delim const &delims)
Tokenizes string. Returns all non-empty substrings.
Definition: string.hpp:321
std::string base64_encode(std::string const &in)
Encodes raw input string to base64.
std::wstring native_string
A string in the system&#39;s native character type and encoding. Note: This typedef changes depending on...
Definition: string.hpp:31
void trim(String &s)
Remove all leading and trailing whitespace from string.
Definition: string.hpp:414
std::string to_string(std::wstring const &in)
Converts from std::wstring into std::string in system encoding.
The namespace used by libfilezilla.
Definition: apply.hpp:16
String trimmed(String const &s)
Return passed string with all leading and trailing whitespace removed.
Definition: string.hpp:398
Char const * choose_string(char const *c, wchar_t const *w)
Returns the function argument of the type matching the template argument.
Definition: string.hpp:293
String str_tolower_ascii(String const &s)
tr_tolower_ascii does for strings what tolower_ascii does for individual characters ...
Definition: string.hpp:102
Sets some global macros and further includes string.hpp.
native_string to_native(std::string const &in)
Converts std::string to native_string.
std::string base64_decode(std::string const &in)
Decodes base64, ignores whitespace. Returns empty string on invalid input.
auto toString(Arg &&arg) -> typename std::enable_if< std::is_same< String, std::string >::value, decltype(to_string(std::forward< Arg >(arg)))>::type
Calls either fz::to_string or fz::to_wstring depending on the passed template argument.
Definition: string.hpp:262
std::wstring to_wstring(std::string const &in)
Converts from std::string in system encoding into std::wstring.