blob: 367a673ab44838e1639fc0c551ae201819df92ea [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 04:47:3111#ifndef RTC_BASE_STRINGUTILS_H_
12#define RTC_BASE_STRINGUTILS_H_
henrike@webrtc.orgf0488722014-05-13 18:00:2613
Henrik Kjellanderec78f1c2017-06-29 05:52:5014#include <ctype.h>
15#include <stdarg.h>
16#include <stdio.h>
17#include <string.h>
henrike@webrtc.orgf0488722014-05-13 18:00:2618
Henrik Kjellanderec78f1c2017-06-29 05:52:5019#if defined(WEBRTC_WIN)
20#include <malloc.h>
21#include <wchar.h>
Patrik Höglunda8005cf2017-12-13 15:05:4222#include <windows.h>
Henrik Kjellanderec78f1c2017-06-29 05:52:5023#define alloca _alloca
Henrik Kjellanderc0362762017-06-29 06:03:0424#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:2625
Henrik Kjellanderec78f1c2017-06-29 05:52:5026#if defined(WEBRTC_POSIX)
27#ifdef BSD
28#include <stdlib.h>
29#else // BSD
30#include <alloca.h>
31#endif // !BSD
32#endif // WEBRTC_POSIX
33
34#include <string>
35
36///////////////////////////////////////////////////////////////////////////////
37// Generic string/memory utilities
38///////////////////////////////////////////////////////////////////////////////
39
Yves Gerey665174f2018-06-19 13:03:0540#define STACK_ARRAY(TYPE, LEN) \
41 static_cast<TYPE*>(::alloca((LEN) * sizeof(TYPE)))
Henrik Kjellanderec78f1c2017-06-29 05:52:5042
43namespace rtc {
44
Henrik Kjellanderec78f1c2017-06-29 05:52:5045// Determines whether the simple wildcard pattern matches target.
46// Alpha characters in pattern match case-insensitively.
47// Asterisks in pattern match 0 or more characters.
48// Ex: string_match("www.TEST.GOOGLE.COM", "www.*.com") -> true
49bool string_match(const char* target, const char* pattern);
50
51} // namespace rtc
52
53///////////////////////////////////////////////////////////////////////////////
Niels Möllere98c3de2017-12-15 13:10:0954// Rename a few common string functions so they are consistent across platforms.
Henrik Kjellanderec78f1c2017-06-29 05:52:5055// tolowercase is like tolower, but not compatible with end-of-file value
56//
57// It's not clear if we will ever use wchar_t strings on unix. In theory,
58// all strings should be Utf8 all the time, except when interfacing with Win32
59// APIs that require Utf16.
60///////////////////////////////////////////////////////////////////////////////
Henrik Kjellanderec78f1c2017-06-29 05:52:5061inline char tolowercase(char c) {
62 return static_cast<char>(tolower(c));
63}
64
65#if defined(WEBRTC_WIN)
66
Henrik Kjellanderec78f1c2017-06-29 05:52:5067inline wchar_t tolowercase(wchar_t c) {
68 return static_cast<wchar_t>(towlower(c));
69}
70
Henrik Kjellanderc0362762017-06-29 06:03:0471#endif // WEBRTC_WIN
Henrik Kjellanderec78f1c2017-06-29 05:52:5072
73#if defined(WEBRTC_POSIX)
74
75inline int _stricmp(const char* s1, const char* s2) {
76 return strcasecmp(s1, s2);
77}
78inline int _strnicmp(const char* s1, const char* s2, size_t n) {
79 return strncasecmp(s1, s2, n);
80}
81
Jonas Olsson74395342018-04-03 10:22:0782#endif // WEBRTC_POSIX
Henrik Kjellanderec78f1c2017-06-29 05:52:5083
84///////////////////////////////////////////////////////////////////////////////
85// Traits simplifies porting string functions to be CTYPE-agnostic
86///////////////////////////////////////////////////////////////////////////////
87
88namespace rtc {
89
90const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
91
Yves Gerey665174f2018-06-19 13:03:0592template <class CTYPE>
Henrik Kjellanderec78f1c2017-06-29 05:52:5093struct Traits {
94 // STL string type
Jonas Olsson74395342018-04-03 10:22:0795 // typedef XXX string;
Henrik Kjellanderec78f1c2017-06-29 05:52:5096 // Null-terminated string
Jonas Olsson74395342018-04-03 10:22:0797 // inline static const CTYPE* empty_str();
Henrik Kjellanderec78f1c2017-06-29 05:52:5098};
99
100///////////////////////////////////////////////////////////////////////////////
101// String utilities which work with char or wchar_t
102///////////////////////////////////////////////////////////////////////////////
103
104template <class CTYPE>
105inline const CTYPE* nonnull(const CTYPE* str, const CTYPE* def_str = nullptr) {
106 return str ? str : (def_str ? def_str : Traits<CTYPE>::empty_str());
107}
108
Yves Gerey665174f2018-06-19 13:03:05109template <class CTYPE>
Henrik Kjellanderec78f1c2017-06-29 05:52:50110const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) {
Yves Gerey665174f2018-06-19 13:03:05111 for (size_t i = 0; str[i]; ++i) {
112 for (size_t j = 0; chs[j]; ++j) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50113 if (str[i] == chs[j]) {
114 return str + i;
115 }
116 }
117 }
118 return 0;
119}
120
Yves Gerey665174f2018-06-19 13:03:05121template <class CTYPE>
Henrik Kjellanderec78f1c2017-06-29 05:52:50122const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) {
Yves Gerey665174f2018-06-19 13:03:05123 for (size_t i = 0; i < slen && str[i]; ++i) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50124 if (str[i] == ch) {
125 return str + i;
126 }
127 }
128 return 0;
129}
130
Yves Gerey665174f2018-06-19 13:03:05131template <class CTYPE>
Henrik Kjellanderec78f1c2017-06-29 05:52:50132size_t strlenn(const CTYPE* buffer, size_t buflen) {
133 size_t bufpos = 0;
134 while (buffer[bufpos] && (bufpos < buflen)) {
135 ++bufpos;
136 }
137 return bufpos;
138}
139
140// Safe versions of strncpy, strncat, snprintf and vsnprintf that always
141// null-terminate.
142
Yves Gerey665174f2018-06-19 13:03:05143template <class CTYPE>
144size_t strcpyn(CTYPE* buffer,
145 size_t buflen,
146 const CTYPE* source,
147 size_t srclen = SIZE_UNKNOWN) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50148 if (buflen <= 0)
149 return 0;
150
151 if (srclen == SIZE_UNKNOWN) {
152 srclen = strlenn(source, buflen - 1);
153 } else if (srclen >= buflen) {
154 srclen = buflen - 1;
155 }
156 memcpy(buffer, source, srclen * sizeof(CTYPE));
157 buffer[srclen] = 0;
158 return srclen;
159}
160
Yves Gerey665174f2018-06-19 13:03:05161template <class CTYPE>
162size_t strcatn(CTYPE* buffer,
163 size_t buflen,
164 const CTYPE* source,
165 size_t srclen = SIZE_UNKNOWN) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50166 if (buflen <= 0)
167 return 0;
168
169 size_t bufpos = strlenn(buffer, buflen - 1);
170 return bufpos + strcpyn(buffer + bufpos, buflen - bufpos, source, srclen);
171}
172
173// Some compilers (clang specifically) require vsprintfn be defined before
174// sprintfn.
Yves Gerey665174f2018-06-19 13:03:05175template <class CTYPE>
176size_t vsprintfn(CTYPE* buffer,
177 size_t buflen,
178 const CTYPE* format,
Henrik Kjellanderec78f1c2017-06-29 05:52:50179 va_list args) {
180 int len = vsnprintf(buffer, buflen, format, args);
181 if ((len < 0) || (static_cast<size_t>(len) >= buflen)) {
182 len = static_cast<int>(buflen - 1);
183 buffer[len] = 0;
184 }
185 return len;
186}
187
Yves Gerey665174f2018-06-19 13:03:05188template <class CTYPE>
Henrik Kjellanderec78f1c2017-06-29 05:52:50189size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...);
Yves Gerey665174f2018-06-19 13:03:05190template <class CTYPE>
Henrik Kjellanderec78f1c2017-06-29 05:52:50191size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) {
192 va_list args;
193 va_start(args, format);
194 size_t len = vsprintfn(buffer, buflen, format, args);
195 va_end(args);
196 return len;
197}
198
199///////////////////////////////////////////////////////////////////////////////
200// Allow safe comparing and copying ascii (not UTF-8) with both wide and
201// non-wide character strings.
202///////////////////////////////////////////////////////////////////////////////
203
204inline int asccmp(const char* s1, const char* s2) {
205 return strcmp(s1, s2);
206}
207inline int ascicmp(const char* s1, const char* s2) {
208 return _stricmp(s1, s2);
209}
210inline int ascncmp(const char* s1, const char* s2, size_t n) {
211 return strncmp(s1, s2, n);
212}
213inline int ascnicmp(const char* s1, const char* s2, size_t n) {
214 return _strnicmp(s1, s2, n);
215}
Yves Gerey665174f2018-06-19 13:03:05216inline size_t asccpyn(char* buffer,
217 size_t buflen,
218 const char* source,
219 size_t srclen = SIZE_UNKNOWN) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50220 return strcpyn(buffer, buflen, source, srclen);
221}
222
223#if defined(WEBRTC_WIN)
224
Yves Gerey665174f2018-06-19 13:03:05225typedef wchar_t (*CharacterTransformation)(wchar_t);
226inline wchar_t identity(wchar_t c) {
227 return c;
228}
229int ascii_string_compare(const wchar_t* s1,
230 const char* s2,
231 size_t n,
Henrik Kjellanderec78f1c2017-06-29 05:52:50232 CharacterTransformation transformation);
233
234inline int asccmp(const wchar_t* s1, const char* s2) {
235 return ascii_string_compare(s1, s2, static_cast<size_t>(-1), identity);
236}
237inline int ascicmp(const wchar_t* s1, const char* s2) {
238 return ascii_string_compare(s1, s2, static_cast<size_t>(-1), tolowercase);
239}
240inline int ascncmp(const wchar_t* s1, const char* s2, size_t n) {
241 return ascii_string_compare(s1, s2, n, identity);
242}
243inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) {
244 return ascii_string_compare(s1, s2, n, tolowercase);
245}
Yves Gerey665174f2018-06-19 13:03:05246size_t asccpyn(wchar_t* buffer,
247 size_t buflen,
248 const char* source,
249 size_t srclen = SIZE_UNKNOWN);
Henrik Kjellanderec78f1c2017-06-29 05:52:50250
Henrik Kjellanderc0362762017-06-29 06:03:04251#endif // WEBRTC_WIN
Henrik Kjellanderec78f1c2017-06-29 05:52:50252
253///////////////////////////////////////////////////////////////////////////////
254// Traits<char> specializations
255///////////////////////////////////////////////////////////////////////////////
256
Yves Gerey665174f2018-06-19 13:03:05257template <>
Henrik Kjellanderec78f1c2017-06-29 05:52:50258struct Traits<char> {
259 typedef std::string string;
260 inline static const char* empty_str() { return ""; }
261};
262
263///////////////////////////////////////////////////////////////////////////////
264// Traits<wchar_t> specializations (Windows only, currently)
265///////////////////////////////////////////////////////////////////////////////
266
267#if defined(WEBRTC_WIN)
268
Yves Gerey665174f2018-06-19 13:03:05269template <>
Henrik Kjellanderec78f1c2017-06-29 05:52:50270struct Traits<wchar_t> {
271 typedef std::wstring string;
272 inline static const wchar_t* empty_str() { return L""; }
273};
274
Henrik Kjellanderc0362762017-06-29 06:03:04275#endif // WEBRTC_WIN
Henrik Kjellanderec78f1c2017-06-29 05:52:50276
Patrik Höglunda8005cf2017-12-13 15:05:42277///////////////////////////////////////////////////////////////////////////////
278// UTF helpers (Windows only)
279///////////////////////////////////////////////////////////////////////////////
280
281#if defined(WEBRTC_WIN)
282
283inline std::wstring ToUtf16(const char* utf8, size_t len) {
284 int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len),
285 nullptr, 0);
286 wchar_t* ws = STACK_ARRAY(wchar_t, len16);
287 ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len), ws, len16);
288 return std::wstring(ws, len16);
289}
290
291inline std::wstring ToUtf16(const std::string& str) {
292 return ToUtf16(str.data(), str.length());
293}
294
295inline std::string ToUtf8(const wchar_t* wide, size_t len) {
296 int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len),
297 nullptr, 0, nullptr, nullptr);
298 char* ns = STACK_ARRAY(char, len8);
299 ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len), ns, len8,
300 nullptr, nullptr);
301 return std::string(ns, len8);
302}
303
304inline std::string ToUtf8(const wchar_t* wide) {
305 return ToUtf8(wide, wcslen(wide));
306}
307
308inline std::string ToUtf8(const std::wstring& wstr) {
309 return ToUtf8(wstr.data(), wstr.length());
310}
311
312#endif // WEBRTC_WIN
313
Henrik Kjellanderec78f1c2017-06-29 05:52:50314// Replaces all occurrences of "search" with "replace".
Yves Gerey665174f2018-06-19 13:03:05315void replace_substrs(const char* search,
Henrik Kjellanderec78f1c2017-06-29 05:52:50316 size_t search_len,
Yves Gerey665174f2018-06-19 13:03:05317 const char* replace,
Henrik Kjellanderec78f1c2017-06-29 05:52:50318 size_t replace_len,
Yves Gerey665174f2018-06-19 13:03:05319 std::string* s);
Henrik Kjellanderec78f1c2017-06-29 05:52:50320
321// True iff s1 starts with s2.
Yves Gerey665174f2018-06-19 13:03:05322bool starts_with(const char* s1, const char* s2);
Henrik Kjellanderec78f1c2017-06-29 05:52:50323
324// True iff s1 ends with s2.
Yves Gerey665174f2018-06-19 13:03:05325bool ends_with(const char* s1, const char* s2);
Henrik Kjellanderec78f1c2017-06-29 05:52:50326
327// Remove leading and trailing whitespaces.
328std::string string_trim(const std::string& s);
329
Jonas Olssonabbe8412018-04-03 11:40:05330// TODO(jonasolsson): replace with absl::Hex when that becomes available.
Jonas Olsson74395342018-04-03 10:22:07331std::string ToHex(const int i);
Jonas Olssond8c50782018-09-07 09:21:28332
333std::string LeftPad(char padding, unsigned length, std::string s);
334
Henrik Kjellanderec78f1c2017-06-29 05:52:50335} // namespace rtc
336
Jonas Olsson74395342018-04-03 10:22:07337#endif // RTC_BASE_STRINGUTILS_H_