Line data Source code
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 0 : bool StringToNumber(const typename StringToNumberTraits::string_type& input,
74 : typename StringToNumberTraits::value_type* output) {
75 : typedef StringToNumberTraits traits;
76 :
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 :
83 : // Cases to return false:
84 : // - If errno is ERANGE, there was an overflow or underflow.
85 : // - If the input string is empty, there was nothing to parse.
86 : // - If endptr does not point to the end of the string, there are either
87 : // characters remaining in the string after a parsed number, or the string
88 : // does not begin with a parseable number. endptr is compared to the
89 : // expected end given the string's stated length to correctly catch cases
90 : // where the string contains embedded NUL characters.
91 : // - 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 : }
97 :
98 : class StringToLongTraits {
99 : public:
100 : typedef std::string string_type;
101 : typedef long value_type;
102 : static const int kBase = 10;
103 0 : static inline value_type convert_func(const string_type::value_type* str,
104 : string_type::value_type** endptr) {
105 0 : return strtol(str, endptr, kBase);
106 : }
107 0 : static inline bool valid_func(const string_type& str) {
108 0 : return !str.empty() && !isspace(str[0]);
109 : }
110 : };
111 :
112 : class String16ToLongTraits {
113 : public:
114 : typedef string16 string_type;
115 : typedef long value_type;
116 : static const int kBase = 10;
117 0 : static inline value_type convert_func(const string_type::value_type* str,
118 : 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 0 : 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 : }
129 0 : return ret;
130 : #endif
131 : }
132 0 : static inline bool valid_func(const string_type& str) {
133 0 : return !str.empty() && !iswspace(str[0]);
134 : }
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 0 : static inline value_type convert_func(const string_type::value_type* str,
143 : string_type::value_type** endptr) {
144 : #ifdef OS_WIN
145 : return _strtoi64(str, endptr, kBase);
146 : #else // assume OS_POSIX
147 0 : return strtoll(str, endptr, kBase);
148 : #endif
149 : }
150 0 : static inline bool valid_func(const string_type& str) {
151 0 : return !str.empty() && !isspace(str[0]);
152 : }
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 0 : static inline value_type convert_func(const string_type::value_type* str,
161 : string_type::value_type** endptr) {
162 : #ifdef OS_WIN
163 : return _wcstoi64(str, endptr, kBase);
164 : #else // assume OS_POSIX
165 0 : 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 : }
172 0 : return ret;
173 : #endif
174 : }
175 0 : static inline bool valid_func(const string_type& str) {
176 0 : return !str.empty() && !iswspace(str[0]);
177 : }
178 : };
179 :
180 : } // namespace
181 :
182 :
183 : namespace base {
184 :
185 15 : bool IsWprintfFormatPortable(const wchar_t* format) {
186 90 : for (const wchar_t* position = format; *position != '\0'; ++position) {
187 :
188 75 : if (*position == '%') {
189 45 : bool in_specification = true;
190 45 : bool modifier_l = false;
191 135 : while (in_specification) {
192 : // Eat up characters until reaching a known specifier.
193 45 : if (*++position == '\0') {
194 : // The format string ended in the middle of a specification. Call
195 : // it portable because no unportable specifications were found. The
196 : // string is equally broken on all platforms.
197 0 : return true;
198 : }
199 :
200 45 : if (*position == 'l') {
201 : // 'l' is the only thing that can save the 's' and 'c' specifiers.
202 0 : modifier_l = true;
203 90 : } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
204 135 : *position == 'S' || *position == 'C' || *position == 'F' ||
205 90 : *position == 'D' || *position == 'O' || *position == 'U') {
206 : // Not portable.
207 0 : return false;
208 : }
209 :
210 45 : if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
211 : // Portable, keep scanning the rest of the format string.
212 45 : in_specification = false;
213 : }
214 : }
215 : }
216 :
217 : }
218 :
219 15 : return true;
220 : }
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 0 : TrimPositions TrimStringT(const STR& input,
267 : const typename STR::value_type trim_chars[],
268 : TrimPositions positions,
269 : STR* output) {
270 : // 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 :
277 : // When the string was all whitespace, report that we stripped off whitespace
278 : // from whichever position the caller was interested in. For empty input, we
279 : // 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 : }
286 :
287 : // Trim the whitespace.
288 0 : *output =
289 0 : input.substr(first_good_char, last_good_char - first_good_char + 1);
290 :
291 : // Return where we trimmed from.
292 : 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 : }
296 :
297 0 : TrimPositions TrimWhitespace(const std::wstring& input,
298 : TrimPositions positions,
299 : std::wstring* output) {
300 0 : return TrimStringT(input, kWhitespaceWide, positions, output);
301 : }
302 :
303 0 : TrimPositions TrimWhitespaceASCII(const std::string& input,
304 : TrimPositions positions,
305 : std::string* output) {
306 0 : return TrimStringT(input, kWhitespaceASCII, positions, output);
307 : }
308 :
309 : // This function is only for backward-compatibility.
310 : // To be removed when all callers are updated.
311 0 : TrimPositions TrimWhitespace(const std::string& input,
312 : TrimPositions positions,
313 : std::string* output) {
314 0 : return TrimWhitespaceASCII(input, positions, output);
315 : }
316 :
317 19 : std::string WideToASCII(const std::wstring& wide) {
318 19 : DCHECK(IsStringASCII(wide));
319 19 : return std::string(wide.begin(), wide.end());
320 : }
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 : }
326 :
327 0 : std::string UTF16ToASCII(const string16& utf16) {
328 0 : DCHECK(IsStringASCII(utf16));
329 0 : return std::string(utf16.begin(), utf16.end());
330 : }
331 :
332 0 : string16 ASCIIToUTF16(const std::string& ascii) {
333 0 : DCHECK(IsStringASCII(ascii));
334 0 : return string16(ascii.begin(), ascii.end());
335 : }
336 :
337 : template<class STR>
338 19 : static bool DoIsStringASCII(const STR& str) {
339 297 : for (size_t i = 0; i < str.length(); i++) {
340 278 : typename ToUnsigned<typename STR::value_type>::Unsigned c = str[i];
341 278 : if (c > 0x7F)
342 0 : return false;
343 : }
344 19 : return true;
345 : }
346 :
347 19 : bool IsStringASCII(const std::wstring& str) {
348 19 : return DoIsStringASCII(str);
349 : }
350 :
351 : #if !defined(WCHAR_T_IS_UTF16)
352 0 : bool IsStringASCII(const string16& str) {
353 0 : return DoIsStringASCII(str);
354 : }
355 : #endif
356 :
357 0 : bool IsStringASCII(const std::string& str) {
358 0 : return DoIsStringASCII(str);
359 : }
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 0 : inline int vsnprintfT(char* buffer,
368 : size_t buf_size,
369 : const char* format,
370 : va_list argptr) {
371 0 : return base::vsnprintf(buffer, buf_size, format, argptr);
372 : }
373 :
374 15 : inline int vsnprintfT(wchar_t* buffer,
375 : size_t buf_size,
376 : const wchar_t* format,
377 : va_list argptr) {
378 15 : return base::vswprintf(buffer, buf_size, format, argptr);
379 : }
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 15 : static void StringAppendVT(StringType* dst,
385 : const typename StringType::value_type* format,
386 : va_list ap) {
387 : // First try with a small fixed size buffer.
388 : // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
389 : // and StringUtilTest.StringPrintfBounds.
390 : typename StringType::value_type stack_buf[1024];
391 :
392 : va_list backup_ap;
393 15 : base_va_copy(backup_ap, ap);
394 :
395 : #if !defined(OS_WIN)
396 15 : errno = 0;
397 : #endif
398 15 : int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, backup_ap);
399 15 : va_end(backup_ap);
400 :
401 15 : if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
402 : // It fit.
403 15 : dst->append(stack_buf, result);
404 15 : return;
405 : }
406 :
407 : // 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 : #if !defined(OS_WIN)
412 : // On Windows, vsnprintfT always returns the number of characters in a
413 : // fully-formatted string, so if we reach this point, something else is
414 : // wrong and no amount of buffer-doubling is going to fix it.
415 0 : if (errno != 0 && errno != EOVERFLOW)
416 : #endif
417 : {
418 : // 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 : }
422 : // Try doubling the buffer size.
423 0 : mem_length *= 2;
424 : } else {
425 : // We need exactly "result + 1" characters.
426 0 : mem_length = result + 1;
427 : }
428 :
429 0 : if (mem_length > 32 * 1024 * 1024) {
430 : // That should be plenty, don't try anything larger. This protects
431 : // against huge allocations when using vsnprintfT implementations that
432 : // 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 : }
436 :
437 0 : std::vector<typename StringType::value_type> mem_buf(mem_length);
438 :
439 : // Restore the va_list before we use it again.
440 0 : base_va_copy(backup_ap, ap);
441 :
442 0 : result = vsnprintfT(&mem_buf[0], mem_length, format, ap);
443 0 : va_end(backup_ap);
444 :
445 0 : if ((result >= 0) && (result < mem_length)) {
446 : // It fit.
447 0 : dst->append(&mem_buf[0], result);
448 0 : return;
449 : }
450 : }
451 : }
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 : }
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 : }
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 : // value is unsigned, and can never be negative.
490 0 : return false;
491 : }
492 : };
493 : template <typename INT2>
494 : struct TestNegT<INT2, true> {
495 0 : static bool TestNeg(INT2 value) {
496 0 : return value < 0;
497 : }
498 : };
499 :
500 0 : static STR IntToString(INT value) {
501 : // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
502 : // So round up to allocate 3 output characters per byte, plus 1 for '-'.
503 0 : const int kOutputBufSize = 3 * sizeof(INT) + 1;
504 :
505 : // Allocate the whole string right away, we will right back to front, and
506 : // then return the substr of what we ended up using.
507 0 : STR outbuf(kOutputBufSize, 0);
508 :
509 0 : bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
510 : // Even though is_neg will never be true when INT is parameterized as
511 : // unsigned, even the presence of the unary operation causes a warning.
512 0 : UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
513 :
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 :
520 : // 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 : }
527 0 : return STR(it, outbuf.end());
528 : }
529 : }
530 : NOTREACHED();
531 : return STR();
532 : }
533 : };
534 :
535 : }
536 :
537 0 : std::string IntToString(int value) {
538 : return IntToStringT<std::string, int, unsigned int, true>::
539 0 : IntToString(value);
540 : }
541 0 : std::wstring IntToWString(int value) {
542 : return IntToStringT<std::wstring, int, unsigned int, true>::
543 0 : IntToString(value);
544 : }
545 0 : std::string UintToString(unsigned int value) {
546 : return IntToStringT<std::string, unsigned int, unsigned int, false>::
547 0 : IntToString(value);
548 : }
549 0 : std::wstring UintToWString(unsigned int value) {
550 : return IntToStringT<std::wstring, unsigned int, unsigned int, false>::
551 0 : IntToString(value);
552 : }
553 0 : std::string Int64ToString(int64_t value) {
554 : return IntToStringT<std::string, int64_t, uint64_t, true>::
555 0 : IntToString(value);
556 : }
557 0 : std::wstring Int64ToWString(int64_t value) {
558 : return IntToStringT<std::wstring, int64_t, uint64_t, true>::
559 0 : IntToString(value);
560 : }
561 0 : std::string Uint64ToString(uint64_t value) {
562 : return IntToStringT<std::string, uint64_t, uint64_t, false>::
563 0 : IntToString(value);
564 : }
565 0 : std::wstring Uint64ToWString(uint64_t value) {
566 : return IntToStringT<std::wstring, uint64_t, uint64_t, false>::
567 0 : IntToString(value);
568 : }
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 15 : static void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
577 15 : StringAppendVT(dst, format, ap);
578 15 : }
579 :
580 0 : std::string StringPrintf(const char* format, ...) {
581 : 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 : }
588 :
589 15 : std::wstring StringPrintf(const wchar_t* format, ...) {
590 : va_list ap;
591 15 : va_start(ap, format);
592 15 : std::wstring result;
593 15 : StringAppendV(&result, format, ap);
594 15 : va_end(ap);
595 15 : return result;
596 : }
597 :
598 0 : const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
599 : 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 : }
606 :
607 0 : const std::wstring& SStringPrintf(std::wstring* dst,
608 : const wchar_t* format, ...) {
609 : 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 : }
616 :
617 0 : void StringAppendF(std::string* dst, const char* format, ...) {
618 : 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 : 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 0 : static void SplitStringT(const STR& str,
633 : const typename STR::value_type s,
634 : bool trim_whitespace,
635 : std::vector<STR>* r) {
636 0 : size_t last = 0;
637 : 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 : } else {
648 0 : r->push_back(tmp);
649 : }
650 0 : last = i + 1;
651 : }
652 : }
653 0 : }
654 :
655 0 : void SplitString(const std::wstring& str,
656 : wchar_t s,
657 : std::vector<std::wstring>* r) {
658 0 : SplitStringT(str, s, true, r);
659 0 : }
660 :
661 0 : void SplitString(const std::string& str,
662 : char s,
663 : 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 : long tmp;
690 0 : bool ok = StringToNumber<StringToLongTraits>(input, &tmp);
691 0 : if (!ok || tmp > kint32max) {
692 0 : return false;
693 : }
694 0 : *output = static_cast<int>(tmp);
695 0 : return true;
696 : }
697 :
698 0 : bool StringToInt(const string16& input, int* output) {
699 : long tmp;
700 0 : bool ok = StringToNumber<String16ToLongTraits>(input, &tmp);
701 0 : if (!ok || tmp > kint32max) {
702 0 : return false;
703 : }
704 0 : *output = static_cast<int>(tmp);
705 0 : return true;
706 : }
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 : }
712 :
713 0 : bool StringToInt64(const string16& input, int64_t* output) {
714 0 : return StringToNumber<String16ToInt64Traits>(input, output);
715 : }
716 :
717 0 : int StringToInt(const std::string& value) {
718 : int result;
719 0 : StringToInt(value, &result);
720 0 : return result;
721 : }
722 :
723 0 : int StringToInt(const string16& value) {
724 : int result;
725 0 : StringToInt(value, &result);
726 0 : return result;
727 : }
728 :
729 0 : int64_t StringToInt64(const std::string& value) {
730 : int64_t result;
731 0 : StringToInt64(value, &result);
732 0 : return result;
733 : }
734 :
735 0 : int64_t StringToInt64(const string16& value) {
736 : int64_t result;
737 0 : StringToInt64(value, &result);
738 0 : return result;
739 : }
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 : }
753 :
754 : // 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 :
758 : // 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 : }
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 : }
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 : }
|