tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

string_util.cc (23266B)


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