/src/mozilla-central/ipc/chromium/src/base/string_util.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
4 | | // Use of this source code is governed by a BSD-style license that can be |
5 | | // found in the LICENSE file. |
6 | | |
7 | | #include "base/string_util.h" |
8 | | |
9 | | #include "build/build_config.h" |
10 | | |
11 | | #include <ctype.h> |
12 | | #include <errno.h> |
13 | | #include <math.h> |
14 | | #include <stdarg.h> |
15 | | #include <stdio.h> |
16 | | #include <stdlib.h> |
17 | | #include <string.h> |
18 | | #include <time.h> |
19 | | #include <wchar.h> |
20 | | #include <wctype.h> |
21 | | |
22 | | #include <algorithm> |
23 | | #include <vector> |
24 | | |
25 | | #include "base/basictypes.h" |
26 | | #include "base/logging.h" |
27 | | #include "base/singleton.h" |
28 | | |
29 | | namespace { |
30 | | |
31 | | // Hack to convert any char-like type to its unsigned counterpart. |
32 | | // For example, it will convert char, signed char and unsigned char to unsigned |
33 | | // char. |
34 | | template<typename T> |
35 | | struct ToUnsigned { |
36 | | typedef T Unsigned; |
37 | | }; |
38 | | |
39 | | template<> |
40 | | struct ToUnsigned<char> { |
41 | | typedef unsigned char Unsigned; |
42 | | }; |
43 | | template<> |
44 | | struct ToUnsigned<signed char> { |
45 | | typedef unsigned char Unsigned; |
46 | | }; |
47 | | template<> |
48 | | struct ToUnsigned<wchar_t> { |
49 | | #if defined(WCHAR_T_IS_UTF16) |
50 | | typedef unsigned short Unsigned; |
51 | | #elif defined(WCHAR_T_IS_UTF32) |
52 | | typedef uint32_t Unsigned; |
53 | | #endif |
54 | | }; |
55 | | template<> |
56 | | struct ToUnsigned<short> { |
57 | | typedef unsigned short Unsigned; |
58 | | }; |
59 | | |
60 | | // Generalized string-to-number conversion. |
61 | | // |
62 | | // StringToNumberTraits should provide: |
63 | | // - a typedef for string_type, the STL string type used as input. |
64 | | // - a typedef for value_type, the target numeric type. |
65 | | // - a static function, convert_func, which dispatches to an appropriate |
66 | | // strtol-like function and returns type value_type. |
67 | | // - a static function, valid_func, which validates |input| and returns a bool |
68 | | // indicating whether it is in proper form. This is used to check for |
69 | | // conditions that convert_func tolerates but should result in |
70 | | // StringToNumber returning false. For strtol-like funtions, valid_func |
71 | | // should check for leading whitespace. |
72 | | template<typename StringToNumberTraits> |
73 | | bool StringToNumber(const typename StringToNumberTraits::string_type& input, |
74 | 0 | typename StringToNumberTraits::value_type* output) { |
75 | 0 | typedef StringToNumberTraits traits; |
76 | 0 |
|
77 | 0 | errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows. |
78 | 0 | typename traits::string_type::value_type* endptr = NULL; |
79 | 0 | typename traits::value_type value = traits::convert_func(input.c_str(), |
80 | 0 | &endptr); |
81 | 0 | *output = value; |
82 | 0 |
|
83 | 0 | // Cases to return false: |
84 | 0 | // - If errno is ERANGE, there was an overflow or underflow. |
85 | 0 | // - If the input string is empty, there was nothing to parse. |
86 | 0 | // - If endptr does not point to the end of the string, there are either |
87 | 0 | // characters remaining in the string after a parsed number, or the string |
88 | 0 | // does not begin with a parseable number. endptr is compared to the |
89 | 0 | // expected end given the string's stated length to correctly catch cases |
90 | 0 | // where the string contains embedded NUL characters. |
91 | 0 | // - valid_func determines that the input is not in preferred form. |
92 | 0 | return errno == 0 && |
93 | 0 | !input.empty() && |
94 | 0 | input.c_str() + input.length() == endptr && |
95 | 0 | traits::valid_func(input); |
96 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:bool (anonymous namespace)::StringToNumber<(anonymous namespace)::StringToLongTraits>((anonymous namespace)::StringToLongTraits::string_type const&, (anonymous namespace)::StringToLongTraits::value_type*) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:bool (anonymous namespace)::StringToNumber<(anonymous namespace)::String16ToLongTraits>((anonymous namespace)::String16ToLongTraits::string_type const&, (anonymous namespace)::String16ToLongTraits::value_type*) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:bool (anonymous namespace)::StringToNumber<(anonymous namespace)::StringToInt64Traits>((anonymous namespace)::StringToInt64Traits::string_type const&, (anonymous namespace)::StringToInt64Traits::value_type*) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:bool (anonymous namespace)::StringToNumber<(anonymous namespace)::String16ToInt64Traits>((anonymous namespace)::String16ToInt64Traits::string_type const&, (anonymous namespace)::String16ToInt64Traits::value_type*) |
97 | | |
98 | | class StringToLongTraits { |
99 | | public: |
100 | | typedef std::string string_type; |
101 | | typedef long value_type; |
102 | | static const int kBase = 10; |
103 | | static inline value_type convert_func(const string_type::value_type* str, |
104 | 0 | string_type::value_type** endptr) { |
105 | 0 | return strtol(str, endptr, kBase); |
106 | 0 | } |
107 | 0 | static inline bool valid_func(const string_type& str) { |
108 | 0 | return !str.empty() && !isspace(str[0]); |
109 | 0 | } |
110 | | }; |
111 | | |
112 | | class String16ToLongTraits { |
113 | | public: |
114 | | typedef string16 string_type; |
115 | | typedef long value_type; |
116 | | static const int kBase = 10; |
117 | | static inline value_type convert_func(const string_type::value_type* str, |
118 | 0 | string_type::value_type** endptr) { |
119 | | #if defined(WCHAR_T_IS_UTF16) |
120 | | return wcstol(str, endptr, kBase); |
121 | | #elif defined(WCHAR_T_IS_UTF32) |
122 | | std::string ascii_string = UTF16ToASCII(string16(str)); |
123 | 0 | char* ascii_end = NULL; |
124 | 0 | value_type ret = strtol(ascii_string.c_str(), &ascii_end, kBase); |
125 | 0 | if (ascii_string.c_str() + ascii_string.length() == ascii_end) { |
126 | 0 | *endptr = |
127 | 0 | const_cast<string_type::value_type*>(str) + ascii_string.length(); |
128 | 0 | } |
129 | 0 | return ret; |
130 | 0 | #endif |
131 | 0 | } |
132 | 0 | static inline bool valid_func(const string_type& str) { |
133 | 0 | return !str.empty() && !iswspace(str[0]); |
134 | 0 | } |
135 | | }; |
136 | | |
137 | | class StringToInt64Traits { |
138 | | public: |
139 | | typedef std::string string_type; |
140 | | typedef int64_t value_type; |
141 | | static const int kBase = 10; |
142 | | static inline value_type convert_func(const string_type::value_type* str, |
143 | 0 | string_type::value_type** endptr) { |
144 | | #ifdef OS_WIN |
145 | | return _strtoi64(str, endptr, kBase); |
146 | | #else // assume OS_POSIX |
147 | | return strtoll(str, endptr, kBase); |
148 | 0 | #endif |
149 | 0 | } |
150 | 0 | static inline bool valid_func(const string_type& str) { |
151 | 0 | return !str.empty() && !isspace(str[0]); |
152 | 0 | } |
153 | | }; |
154 | | |
155 | | class String16ToInt64Traits { |
156 | | public: |
157 | | typedef string16 string_type; |
158 | | typedef int64_t value_type; |
159 | | static const int kBase = 10; |
160 | | static inline value_type convert_func(const string_type::value_type* str, |
161 | 0 | string_type::value_type** endptr) { |
162 | | #ifdef OS_WIN |
163 | | return _wcstoi64(str, endptr, kBase); |
164 | | #else // assume OS_POSIX |
165 | | std::string ascii_string = UTF16ToASCII(string16(str)); |
166 | 0 | char* ascii_end = NULL; |
167 | 0 | value_type ret = strtoll(ascii_string.c_str(), &ascii_end, kBase); |
168 | 0 | if (ascii_string.c_str() + ascii_string.length() == ascii_end) { |
169 | 0 | *endptr = |
170 | 0 | const_cast<string_type::value_type*>(str) + ascii_string.length(); |
171 | 0 | } |
172 | 0 | return ret; |
173 | 0 | #endif |
174 | 0 | } |
175 | 0 | static inline bool valid_func(const string_type& str) { |
176 | 0 | return !str.empty() && !iswspace(str[0]); |
177 | 0 | } |
178 | | }; |
179 | | |
180 | | } // namespace |
181 | | |
182 | | |
183 | | namespace base { |
184 | | |
185 | 0 | bool IsWprintfFormatPortable(const wchar_t* format) { |
186 | 0 | for (const wchar_t* position = format; *position != '\0'; ++position) { |
187 | 0 |
|
188 | 0 | if (*position == '%') { |
189 | 0 | bool in_specification = true; |
190 | 0 | bool modifier_l = false; |
191 | 0 | while (in_specification) { |
192 | 0 | // Eat up characters until reaching a known specifier. |
193 | 0 | if (*++position == '\0') { |
194 | 0 | // The format string ended in the middle of a specification. Call |
195 | 0 | // it portable because no unportable specifications were found. The |
196 | 0 | // string is equally broken on all platforms. |
197 | 0 | return true; |
198 | 0 | } |
199 | 0 | |
200 | 0 | if (*position == 'l') { |
201 | 0 | // 'l' is the only thing that can save the 's' and 'c' specifiers. |
202 | 0 | modifier_l = true; |
203 | 0 | } else if (((*position == 's' || *position == 'c') && !modifier_l) || |
204 | 0 | *position == 'S' || *position == 'C' || *position == 'F' || |
205 | 0 | *position == 'D' || *position == 'O' || *position == 'U') { |
206 | 0 | // Not portable. |
207 | 0 | return false; |
208 | 0 | } |
209 | 0 | |
210 | 0 | if (wcschr(L"diouxXeEfgGaAcspn%", *position)) { |
211 | 0 | // Portable, keep scanning the rest of the format string. |
212 | 0 | in_specification = false; |
213 | 0 | } |
214 | 0 | } |
215 | 0 | } |
216 | 0 |
|
217 | 0 | } |
218 | 0 |
|
219 | 0 | return true; |
220 | 0 | } |
221 | | |
222 | | |
223 | | } // namespace base |
224 | | |
225 | | static const wchar_t kWhitespaceWide[] = { |
226 | | 0x0009, // <control-0009> to <control-000D> |
227 | | 0x000A, |
228 | | 0x000B, |
229 | | 0x000C, |
230 | | 0x000D, |
231 | | 0x0020, // Space |
232 | | 0x0085, // <control-0085> |
233 | | 0x00A0, // No-Break Space |
234 | | 0x1680, // Ogham Space Mark |
235 | | 0x180E, // Mongolian Vowel Separator |
236 | | 0x2000, // En Quad to Hair Space |
237 | | 0x2001, |
238 | | 0x2002, |
239 | | 0x2003, |
240 | | 0x2004, |
241 | | 0x2005, |
242 | | 0x2006, |
243 | | 0x2007, |
244 | | 0x2008, |
245 | | 0x2009, |
246 | | 0x200A, |
247 | | 0x200C, // Zero Width Non-Joiner |
248 | | 0x2028, // Line Separator |
249 | | 0x2029, // Paragraph Separator |
250 | | 0x202F, // Narrow No-Break Space |
251 | | 0x205F, // Medium Mathematical Space |
252 | | 0x3000, // Ideographic Space |
253 | | 0 |
254 | | }; |
255 | | static const char kWhitespaceASCII[] = { |
256 | | 0x09, // <control-0009> to <control-000D> |
257 | | 0x0A, |
258 | | 0x0B, |
259 | | 0x0C, |
260 | | 0x0D, |
261 | | 0x20, // Space |
262 | | 0 |
263 | | }; |
264 | | |
265 | | template<typename STR> |
266 | | TrimPositions TrimStringT(const STR& input, |
267 | | const typename STR::value_type trim_chars[], |
268 | | TrimPositions positions, |
269 | 0 | STR* output) { |
270 | 0 | // Find the edges of leading/trailing whitespace as desired. |
271 | 0 | const typename STR::size_type last_char = input.length() - 1; |
272 | 0 | const typename STR::size_type first_good_char = (positions & TRIM_LEADING) ? |
273 | 0 | input.find_first_not_of(trim_chars) : 0; |
274 | 0 | const typename STR::size_type last_good_char = (positions & TRIM_TRAILING) ? |
275 | 0 | input.find_last_not_of(trim_chars) : last_char; |
276 | 0 |
|
277 | 0 | // When the string was all whitespace, report that we stripped off whitespace |
278 | 0 | // from whichever position the caller was interested in. For empty input, we |
279 | 0 | // stripped no whitespace, but we still need to clear |output|. |
280 | 0 | if (input.empty() || |
281 | 0 | (first_good_char == STR::npos) || (last_good_char == STR::npos)) { |
282 | 0 | bool input_was_empty = input.empty(); // in case output == &input |
283 | 0 | output->clear(); |
284 | 0 | return input_was_empty ? TRIM_NONE : positions; |
285 | 0 | } |
286 | 0 |
|
287 | 0 | // Trim the whitespace. |
288 | 0 | *output = |
289 | 0 | input.substr(first_good_char, last_good_char - first_good_char + 1); |
290 | 0 |
|
291 | 0 | // Return where we trimmed from. |
292 | 0 | return static_cast<TrimPositions>( |
293 | 0 | ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) | |
294 | 0 | ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING)); |
295 | 0 | } Unexecuted instantiation: TrimPositions TrimStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > >(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >::value_type const*, TrimPositions, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >*) Unexecuted instantiation: TrimPositions TrimStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::value_type const*, TrimPositions, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) |
296 | | |
297 | | TrimPositions TrimWhitespace(const std::wstring& input, |
298 | | TrimPositions positions, |
299 | 0 | std::wstring* output) { |
300 | 0 | return TrimStringT(input, kWhitespaceWide, positions, output); |
301 | 0 | } |
302 | | |
303 | | TrimPositions TrimWhitespaceASCII(const std::string& input, |
304 | | TrimPositions positions, |
305 | 0 | std::string* output) { |
306 | 0 | return TrimStringT(input, kWhitespaceASCII, positions, output); |
307 | 0 | } |
308 | | |
309 | | // This function is only for backward-compatibility. |
310 | | // To be removed when all callers are updated. |
311 | | TrimPositions TrimWhitespace(const std::string& input, |
312 | | TrimPositions positions, |
313 | 0 | std::string* output) { |
314 | 0 | return TrimWhitespaceASCII(input, positions, output); |
315 | 0 | } |
316 | | |
317 | 0 | std::string WideToASCII(const std::wstring& wide) { |
318 | 0 | DCHECK(IsStringASCII(wide)); |
319 | 0 | return std::string(wide.begin(), wide.end()); |
320 | 0 | } |
321 | | |
322 | 0 | std::wstring ASCIIToWide(const std::string& ascii) { |
323 | 0 | DCHECK(IsStringASCII(ascii)); |
324 | 0 | return std::wstring(ascii.begin(), ascii.end()); |
325 | 0 | } |
326 | | |
327 | 0 | std::string UTF16ToASCII(const string16& utf16) { |
328 | 0 | DCHECK(IsStringASCII(utf16)); |
329 | 0 | return std::string(utf16.begin(), utf16.end()); |
330 | 0 | } |
331 | | |
332 | 0 | string16 ASCIIToUTF16(const std::string& ascii) { |
333 | 0 | DCHECK(IsStringASCII(ascii)); |
334 | 0 | return string16(ascii.begin(), ascii.end()); |
335 | 0 | } |
336 | | |
337 | | template<class STR> |
338 | 0 | static bool DoIsStringASCII(const STR& str) { |
339 | 0 | for (size_t i = 0; i < str.length(); i++) { |
340 | 0 | typename ToUnsigned<typename STR::value_type>::Unsigned c = str[i]; |
341 | 0 | if (c > 0x7F) |
342 | 0 | return false; |
343 | 0 | } |
344 | 0 | return true; |
345 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:bool DoIsStringASCII<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > >(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:bool DoIsStringASCII<std::__1::basic_string<unsigned short, base::string16_char_traits, std::__1::allocator<unsigned short> > >(std::__1::basic_string<unsigned short, base::string16_char_traits, std::__1::allocator<unsigned short> > const&) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:bool DoIsStringASCII<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) |
346 | | |
347 | 0 | bool IsStringASCII(const std::wstring& str) { |
348 | 0 | return DoIsStringASCII(str); |
349 | 0 | } |
350 | | |
351 | | #if !defined(WCHAR_T_IS_UTF16) |
352 | 0 | bool IsStringASCII(const string16& str) { |
353 | 0 | return DoIsStringASCII(str); |
354 | 0 | } |
355 | | #endif |
356 | | |
357 | 0 | bool IsStringASCII(const std::string& str) { |
358 | 0 | return DoIsStringASCII(str); |
359 | 0 | } |
360 | | |
361 | | // Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter |
362 | | // is the size of the buffer. These return the number of characters in the |
363 | | // formatted string excluding the NUL terminator. If the buffer is not |
364 | | // large enough to accommodate the formatted string without truncation, they |
365 | | // return the number of characters that would be in the fully-formatted string |
366 | | // (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms). |
367 | | inline int vsnprintfT(char* buffer, |
368 | | size_t buf_size, |
369 | | const char* format, |
370 | 0 | va_list argptr) { |
371 | 0 | return base::vsnprintf(buffer, buf_size, format, argptr); |
372 | 0 | } |
373 | | |
374 | | inline int vsnprintfT(wchar_t* buffer, |
375 | | size_t buf_size, |
376 | | const wchar_t* format, |
377 | 0 | va_list argptr) { |
378 | 0 | return base::vswprintf(buffer, buf_size, format, argptr); |
379 | 0 | } |
380 | | |
381 | | // Templatized backend for StringPrintF/StringAppendF. This does not finalize |
382 | | // the va_list, the caller is expected to do that. |
383 | | template <class StringType> |
384 | | static void StringAppendVT(StringType* dst, |
385 | | const typename StringType::value_type* format, |
386 | 0 | va_list ap) { |
387 | 0 | // First try with a small fixed size buffer. |
388 | 0 | // This buffer size should be kept in sync with StringUtilTest.GrowBoundary |
389 | 0 | // and StringUtilTest.StringPrintfBounds. |
390 | 0 | typename StringType::value_type stack_buf[1024]; |
391 | 0 |
|
392 | 0 | va_list backup_ap; |
393 | 0 | base_va_copy(backup_ap, ap); |
394 | 0 |
|
395 | 0 | #if !defined(OS_WIN) |
396 | 0 | errno = 0; |
397 | 0 | #endif |
398 | 0 | int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, backup_ap); |
399 | 0 | va_end(backup_ap); |
400 | 0 |
|
401 | 0 | if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) { |
402 | 0 | // It fit. |
403 | 0 | dst->append(stack_buf, result); |
404 | 0 | return; |
405 | 0 | } |
406 | 0 | |
407 | 0 | // Repeatedly increase buffer size until it fits. |
408 | 0 | int mem_length = arraysize(stack_buf); |
409 | 0 | while (true) { |
410 | 0 | if (result < 0) { |
411 | 0 | #if !defined(OS_WIN) |
412 | 0 | // On Windows, vsnprintfT always returns the number of characters in a |
413 | 0 | // fully-formatted string, so if we reach this point, something else is |
414 | 0 | // wrong and no amount of buffer-doubling is going to fix it. |
415 | 0 | if (errno != 0 && errno != EOVERFLOW) |
416 | 0 | #endif |
417 | 0 | { |
418 | 0 | // If an error other than overflow occurred, it's never going to work. |
419 | 0 | DLOG(WARNING) << "Unable to printf the requested string due to error."; |
420 | 0 | return; |
421 | 0 | } |
422 | 0 | // Try doubling the buffer size. |
423 | 0 | mem_length *= 2; |
424 | 0 | } else { |
425 | 0 | // We need exactly "result + 1" characters. |
426 | 0 | mem_length = result + 1; |
427 | 0 | } |
428 | 0 |
|
429 | 0 | if (mem_length > 32 * 1024 * 1024) { |
430 | 0 | // That should be plenty, don't try anything larger. This protects |
431 | 0 | // against huge allocations when using vsnprintfT implementations that |
432 | 0 | // return -1 for reasons other than overflow without setting errno. |
433 | 0 | DLOG(WARNING) << "Unable to printf the requested string due to size."; |
434 | 0 | return; |
435 | 0 | } |
436 | 0 |
|
437 | 0 | std::vector<typename StringType::value_type> mem_buf(mem_length); |
438 | 0 |
|
439 | 0 | // Restore the va_list before we use it again. |
440 | 0 | base_va_copy(backup_ap, ap); |
441 | 0 |
|
442 | 0 | result = vsnprintfT(&mem_buf[0], mem_length, format, ap); |
443 | 0 | va_end(backup_ap); |
444 | 0 |
|
445 | 0 | if ((result >= 0) && (result < mem_length)) { |
446 | 0 | // It fit. |
447 | 0 | dst->append(&mem_buf[0], result); |
448 | 0 | return; |
449 | 0 | } |
450 | 0 | } |
451 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:void StringAppendVT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::value_type const*, __va_list_tag*) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:void StringAppendVT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > >(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >*, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >::value_type const*, __va_list_tag*) |
452 | | |
453 | | namespace { |
454 | | |
455 | | template <typename STR, typename INT, typename UINT, bool NEG> |
456 | | struct IntToStringT { |
457 | | |
458 | | // This is to avoid a compiler warning about unary minus on unsigned type. |
459 | | // For example, say you had the following code: |
460 | | // template <typename INT> |
461 | | // INT abs(INT value) { return value < 0 ? -value : value; } |
462 | | // Even though if INT is unsigned, it's impossible for value < 0, so the |
463 | | // unary minus will never be taken, the compiler will still generate a |
464 | | // warning. We do a little specialization dance... |
465 | | template <typename INT2, typename UINT2, bool NEG2> |
466 | | struct ToUnsignedT { }; |
467 | | |
468 | | template <typename INT2, typename UINT2> |
469 | | struct ToUnsignedT<INT2, UINT2, false> { |
470 | 0 | static UINT2 ToUnsigned(INT2 value) { |
471 | 0 | return static_cast<UINT2>(value); |
472 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int, unsigned int, false>::ToUnsignedT<unsigned int, unsigned int, false>::ToUnsigned(unsigned int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, unsigned int, unsigned int, false>::ToUnsignedT<unsigned int, unsigned int, false>::ToUnsigned(unsigned int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned long, unsigned long, false>::ToUnsignedT<unsigned long, unsigned long, false>::ToUnsigned(unsigned long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, unsigned long, unsigned long, false>::ToUnsignedT<unsigned long, unsigned long, false>::ToUnsigned(unsigned long) |
473 | | }; |
474 | | |
475 | | template <typename INT2, typename UINT2> |
476 | | struct ToUnsignedT<INT2, UINT2, true> { |
477 | 0 | static UINT2 ToUnsigned(INT2 value) { |
478 | 0 | return static_cast<UINT2>(value < 0 ? -value : value); |
479 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, unsigned int, true>::ToUnsignedT<int, unsigned int, true>::ToUnsigned(int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, int, unsigned int, true>::ToUnsignedT<int, unsigned int, true>::ToUnsigned(int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, long, unsigned long, true>::ToUnsignedT<long, unsigned long, true>::ToUnsigned(long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, long, unsigned long, true>::ToUnsignedT<long, unsigned long, true>::ToUnsigned(long) |
480 | | }; |
481 | | |
482 | | // This set of templates is very similar to the above templates, but |
483 | | // for testing whether an integer is negative. |
484 | | template <typename INT2, bool NEG2> |
485 | | struct TestNegT {}; |
486 | | template <typename INT2> |
487 | | struct TestNegT<INT2, false> { |
488 | 0 | static bool TestNeg(INT2 value) { |
489 | 0 | // value is unsigned, and can never be negative. |
490 | 0 | return false; |
491 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int, unsigned int, false>::TestNegT<unsigned int, false>::TestNeg(unsigned int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, unsigned int, unsigned int, false>::TestNegT<unsigned int, false>::TestNeg(unsigned int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned long, unsigned long, false>::TestNegT<unsigned long, false>::TestNeg(unsigned long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, unsigned long, unsigned long, false>::TestNegT<unsigned long, false>::TestNeg(unsigned long) |
492 | | }; |
493 | | template <typename INT2> |
494 | | struct TestNegT<INT2, true> { |
495 | 0 | static bool TestNeg(INT2 value) { |
496 | 0 | return value < 0; |
497 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, unsigned int, true>::TestNegT<int, true>::TestNeg(int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, int, unsigned int, true>::TestNegT<int, true>::TestNeg(int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, long, unsigned long, true>::TestNegT<long, true>::TestNeg(long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, long, unsigned long, true>::TestNegT<long, true>::TestNeg(long) |
498 | | }; |
499 | | |
500 | 0 | static STR IntToString(INT value) { |
501 | 0 | // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. |
502 | 0 | // So round up to allocate 3 output characters per byte, plus 1 for '-'. |
503 | 0 | const int kOutputBufSize = 3 * sizeof(INT) + 1; |
504 | 0 |
|
505 | 0 | // Allocate the whole string right away, we will right back to front, and |
506 | 0 | // then return the substr of what we ended up using. |
507 | 0 | STR outbuf(kOutputBufSize, 0); |
508 | 0 |
|
509 | 0 | bool is_neg = TestNegT<INT, NEG>::TestNeg(value); |
510 | 0 | // Even though is_neg will never be true when INT is parameterized as |
511 | 0 | // unsigned, even the presence of the unary operation causes a warning. |
512 | 0 | UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value); |
513 | 0 |
|
514 | 0 | for (typename STR::iterator it = outbuf.end();;) { |
515 | 0 | --it; |
516 | 0 | DCHECK(it != outbuf.begin()); |
517 | 0 | *it = static_cast<typename STR::value_type>((res % 10) + '0'); |
518 | 0 | res /= 10; |
519 | 0 |
|
520 | 0 | // We're done.. |
521 | 0 | if (res == 0) { |
522 | 0 | if (is_neg) { |
523 | 0 | --it; |
524 | 0 | DCHECK(it != outbuf.begin()); |
525 | 0 | *it = static_cast<typename STR::value_type>('-'); |
526 | 0 | } |
527 | 0 | return STR(it, outbuf.end()); |
528 | 0 | } |
529 | 0 | } |
530 | 0 | NOTREACHED(); |
531 | 0 | return STR(); |
532 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, unsigned int, true>::IntToString(int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, int, unsigned int, true>::IntToString(int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int, unsigned int, false>::IntToString(unsigned int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, unsigned int, unsigned int, false>::IntToString(unsigned int) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, long, unsigned long, true>::IntToString(long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, long, unsigned long, true>::IntToString(long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned long, unsigned long, false>::IntToString(unsigned long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:(anonymous namespace)::IntToStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, unsigned long, unsigned long, false>::IntToString(unsigned long) |
533 | | }; |
534 | | |
535 | | } |
536 | | |
537 | 0 | std::string IntToString(int value) { |
538 | 0 | return IntToStringT<std::string, int, unsigned int, true>:: |
539 | 0 | IntToString(value); |
540 | 0 | } |
541 | 0 | std::wstring IntToWString(int value) { |
542 | 0 | return IntToStringT<std::wstring, int, unsigned int, true>:: |
543 | 0 | IntToString(value); |
544 | 0 | } |
545 | 0 | std::string UintToString(unsigned int value) { |
546 | 0 | return IntToStringT<std::string, unsigned int, unsigned int, false>:: |
547 | 0 | IntToString(value); |
548 | 0 | } |
549 | 0 | std::wstring UintToWString(unsigned int value) { |
550 | 0 | return IntToStringT<std::wstring, unsigned int, unsigned int, false>:: |
551 | 0 | IntToString(value); |
552 | 0 | } |
553 | 0 | std::string Int64ToString(int64_t value) { |
554 | 0 | return IntToStringT<std::string, int64_t, uint64_t, true>:: |
555 | 0 | IntToString(value); |
556 | 0 | } |
557 | 0 | std::wstring Int64ToWString(int64_t value) { |
558 | 0 | return IntToStringT<std::wstring, int64_t, uint64_t, true>:: |
559 | 0 | IntToString(value); |
560 | 0 | } |
561 | 0 | std::string Uint64ToString(uint64_t value) { |
562 | 0 | return IntToStringT<std::string, uint64_t, uint64_t, false>:: |
563 | 0 | IntToString(value); |
564 | 0 | } |
565 | 0 | std::wstring Uint64ToWString(uint64_t value) { |
566 | 0 | return IntToStringT<std::wstring, uint64_t, uint64_t, false>:: |
567 | 0 | IntToString(value); |
568 | 0 | } |
569 | | |
570 | | // Lower-level routine that takes a va_list and appends to a specified |
571 | | // string. All other routines are just convenience wrappers around it. |
572 | 0 | static void StringAppendV(std::string* dst, const char* format, va_list ap) { |
573 | 0 | StringAppendVT(dst, format, ap); |
574 | 0 | } |
575 | | |
576 | 0 | static void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) { |
577 | 0 | StringAppendVT(dst, format, ap); |
578 | 0 | } |
579 | | |
580 | 0 | std::string StringPrintf(const char* format, ...) { |
581 | 0 | va_list ap; |
582 | 0 | va_start(ap, format); |
583 | 0 | std::string result; |
584 | 0 | StringAppendV(&result, format, ap); |
585 | 0 | va_end(ap); |
586 | 0 | return result; |
587 | 0 | } |
588 | | |
589 | 0 | std::wstring StringPrintf(const wchar_t* format, ...) { |
590 | 0 | va_list ap; |
591 | 0 | va_start(ap, format); |
592 | 0 | std::wstring result; |
593 | 0 | StringAppendV(&result, format, ap); |
594 | 0 | va_end(ap); |
595 | 0 | return result; |
596 | 0 | } |
597 | | |
598 | 0 | const std::string& SStringPrintf(std::string* dst, const char* format, ...) { |
599 | 0 | va_list ap; |
600 | 0 | va_start(ap, format); |
601 | 0 | dst->clear(); |
602 | 0 | StringAppendV(dst, format, ap); |
603 | 0 | va_end(ap); |
604 | 0 | return *dst; |
605 | 0 | } |
606 | | |
607 | | const std::wstring& SStringPrintf(std::wstring* dst, |
608 | 0 | const wchar_t* format, ...) { |
609 | 0 | va_list ap; |
610 | 0 | va_start(ap, format); |
611 | 0 | dst->clear(); |
612 | 0 | StringAppendV(dst, format, ap); |
613 | 0 | va_end(ap); |
614 | 0 | return *dst; |
615 | 0 | } |
616 | | |
617 | 0 | void StringAppendF(std::string* dst, const char* format, ...) { |
618 | 0 | va_list ap; |
619 | 0 | va_start(ap, format); |
620 | 0 | StringAppendV(dst, format, ap); |
621 | 0 | va_end(ap); |
622 | 0 | } |
623 | | |
624 | 0 | void StringAppendF(std::wstring* dst, const wchar_t* format, ...) { |
625 | 0 | va_list ap; |
626 | 0 | va_start(ap, format); |
627 | 0 | StringAppendV(dst, format, ap); |
628 | 0 | va_end(ap); |
629 | 0 | } |
630 | | |
631 | | template<typename STR> |
632 | | static void SplitStringT(const STR& str, |
633 | | const typename STR::value_type s, |
634 | | bool trim_whitespace, |
635 | 0 | std::vector<STR>* r) { |
636 | 0 | size_t last = 0; |
637 | 0 | size_t i; |
638 | 0 | size_t c = str.size(); |
639 | 0 | for (i = 0; i <= c; ++i) { |
640 | 0 | if (i == c || str[i] == s) { |
641 | 0 | size_t len = i - last; |
642 | 0 | STR tmp = str.substr(last, len); |
643 | 0 | if (trim_whitespace) { |
644 | 0 | STR t_tmp; |
645 | 0 | TrimWhitespace(tmp, TRIM_ALL, &t_tmp); |
646 | 0 | r->push_back(t_tmp); |
647 | 0 | } else { |
648 | 0 | r->push_back(tmp); |
649 | 0 | } |
650 | 0 | last = i + 1; |
651 | 0 | } |
652 | 0 | } |
653 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:void SplitStringT<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > >(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >::value_type, bool, std::__1::vector<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, std::__1::allocator<std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > > >*) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:void SplitStringT<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::value_type, bool, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*) |
654 | | |
655 | | void SplitString(const std::wstring& str, |
656 | | wchar_t s, |
657 | 0 | std::vector<std::wstring>* r) { |
658 | 0 | SplitStringT(str, s, true, r); |
659 | 0 | } |
660 | | |
661 | | void SplitString(const std::string& str, |
662 | | char s, |
663 | 0 | std::vector<std::string>* r) { |
664 | 0 | SplitStringT(str, s, true, r); |
665 | 0 | } |
666 | | |
667 | | // For the various *ToInt conversions, there are no *ToIntTraits classes to use |
668 | | // because there's no such thing as strtoi. Use *ToLongTraits through a cast |
669 | | // instead, requiring that long and int are compatible and equal-width. They |
670 | | // are on our target platforms. |
671 | | |
672 | | // XXX Sigh. |
673 | | |
674 | | #if !defined(ARCH_CPU_64_BITS) |
675 | | bool StringToInt(const std::string& input, int* output) { |
676 | | COMPILE_ASSERT(sizeof(int) == sizeof(long), cannot_strtol_to_int); |
677 | | return StringToNumber<StringToLongTraits>(input, |
678 | | reinterpret_cast<long*>(output)); |
679 | | } |
680 | | |
681 | | bool StringToInt(const string16& input, int* output) { |
682 | | COMPILE_ASSERT(sizeof(int) == sizeof(long), cannot_wcstol_to_int); |
683 | | return StringToNumber<String16ToLongTraits>(input, |
684 | | reinterpret_cast<long*>(output)); |
685 | | } |
686 | | |
687 | | #else |
688 | 0 | bool StringToInt(const std::string& input, int* output) { |
689 | 0 | long tmp; |
690 | 0 | bool ok = StringToNumber<StringToLongTraits>(input, &tmp); |
691 | 0 | if (!ok || tmp > kint32max) { |
692 | 0 | return false; |
693 | 0 | } |
694 | 0 | *output = static_cast<int>(tmp); |
695 | 0 | return true; |
696 | 0 | } |
697 | | |
698 | 0 | bool StringToInt(const string16& input, int* output) { |
699 | 0 | long tmp; |
700 | 0 | bool ok = StringToNumber<String16ToLongTraits>(input, &tmp); |
701 | 0 | if (!ok || tmp > kint32max) { |
702 | 0 | return false; |
703 | 0 | } |
704 | 0 | *output = static_cast<int>(tmp); |
705 | 0 | return true; |
706 | 0 | } |
707 | | #endif // !defined(ARCH_CPU_64_BITS) |
708 | | |
709 | 0 | bool StringToInt64(const std::string& input, int64_t* output) { |
710 | 0 | return StringToNumber<StringToInt64Traits>(input, output); |
711 | 0 | } |
712 | | |
713 | 0 | bool StringToInt64(const string16& input, int64_t* output) { |
714 | 0 | return StringToNumber<String16ToInt64Traits>(input, output); |
715 | 0 | } |
716 | | |
717 | 0 | int StringToInt(const std::string& value) { |
718 | 0 | int result; |
719 | 0 | StringToInt(value, &result); |
720 | 0 | return result; |
721 | 0 | } |
722 | | |
723 | 0 | int StringToInt(const string16& value) { |
724 | 0 | int result; |
725 | 0 | StringToInt(value, &result); |
726 | 0 | return result; |
727 | 0 | } |
728 | | |
729 | 0 | int64_t StringToInt64(const std::string& value) { |
730 | 0 | int64_t result; |
731 | 0 | StringToInt64(value, &result); |
732 | 0 | return result; |
733 | 0 | } |
734 | | |
735 | 0 | int64_t StringToInt64(const string16& value) { |
736 | 0 | int64_t result; |
737 | 0 | StringToInt64(value, &result); |
738 | 0 | return result; |
739 | 0 | } |
740 | | |
741 | | // The following code is compatible with the OpenBSD lcpy interface. See: |
742 | | // http://www.gratisoft.us/todd/papers/strlcpy.html |
743 | | // ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c |
744 | | |
745 | | namespace { |
746 | | |
747 | | template <typename CHAR> |
748 | 0 | size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) { |
749 | 0 | for (size_t i = 0; i < dst_size; ++i) { |
750 | 0 | if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL. |
751 | 0 | return i; |
752 | 0 | } |
753 | 0 |
|
754 | 0 | // We were left off at dst_size. We over copied 1 byte. Null terminate. |
755 | 0 | if (dst_size != 0) |
756 | 0 | dst[dst_size - 1] = 0; |
757 | 0 |
|
758 | 0 | // Count the rest of the |src|, and return it's length in characters. |
759 | 0 | while (src[dst_size]) ++dst_size; |
760 | 0 | return dst_size; |
761 | 0 | } Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:unsigned long (anonymous namespace)::lcpyT<char>(char*, char const*, unsigned long) Unexecuted instantiation: Unified_cpp_ipc_chromium1.cpp:unsigned long (anonymous namespace)::lcpyT<wchar_t>(wchar_t*, wchar_t const*, unsigned long) |
762 | | |
763 | | } // namespace |
764 | | |
765 | 0 | size_t base::strlcpy(char* dst, const char* src, size_t dst_size) { |
766 | 0 | return lcpyT<char>(dst, src, dst_size); |
767 | 0 | } |
768 | 0 | size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) { |
769 | 0 | return lcpyT<wchar_t>(dst, src, dst_size); |
770 | 0 | } |