summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-30 19:28:44 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-30 19:28:44 +0000
commit528c56de01bbbd38788ed6cf8d2eea4c56cbe19e (patch)
treeac4f7a001affd772c4ab89701d3d46109b5f9e19 /base
parent5c86ada8d84f6e67d17b027d347052ef451241c4 (diff)
downloadchromium_src-528c56de01bbbd38788ed6cf8d2eea4c56cbe19e.zip
chromium_src-528c56de01bbbd38788ed6cf8d2eea4c56cbe19e.tar.gz
chromium_src-528c56de01bbbd38788ed6cf8d2eea4c56cbe19e.tar.bz2
Move the number conversions from string_util to a new file.
Use the base namespace in the new file. Update callers. I removed all wstring variants and also the string->number ones that ignore the return value. That encourages people to write code and forget about error handling. TEST=included unit tests BUG=none Review URL: http://codereview.chromium.org/3056029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54355 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp1
-rw-r--r--base/base.gypi2
-rw-r--r--base/file_util_win.cc5
-rw-r--r--base/json/json_reader.cc5
-rw-r--r--base/json/json_writer.cc1
-rw-r--r--base/process_util_linux.cc88
-rw-r--r--base/simple_thread.cc2
-rw-r--r--base/simple_thread_unittest.cc11
-rw-r--r--base/string_number_conversions.cc400
-rw-r--r--base/string_number_conversions.h92
-rw-r--r--base/string_number_conversions_unittest.cc339
-rw-r--r--base/string_util_unittest.cc367
-rw-r--r--base/version.cc12
13 files changed, 911 insertions, 414 deletions
diff --git a/base/base.gyp b/base/base.gyp
index d53bd13..77f8de1 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -130,6 +130,7 @@
'singleton_unittest.cc',
'stack_container_unittest.cc',
'stats_table_unittest.cc',
+ 'string_number_conversions_unittest.cc',
'string_piece_unittest.cc',
'string_split_unittest.cc',
'string_tokenizer_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index cad0256..a5fdfc6 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -216,6 +216,8 @@
'stats_table.cc',
'stats_table.h',
'stl_util-inl.h',
+ 'string_number_conversions.cc',
+ 'string_number_conversions.h',
'string_piece.cc',
'string_piece.h',
'string_split.cc',
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 2181516..33491ed 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -17,6 +17,7 @@
#include "base/pe_image.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_handle.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/win_util.h"
@@ -562,9 +563,9 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
// the one exists, keep trying another path name until we reach some limit.
path_to_create = base_dir;
- std::wstring new_dir_name;
+ string16 new_dir_name;
new_dir_name.assign(prefix);
- new_dir_name.append(IntToWString(rand() % kint16max));
+ new_dir_name.append(base::IntToString16(rand() % kint16max));
path_to_create = path_to_create.Append(new_dir_name);
if (::CreateDirectory(path_to_create.value().c_str(), NULL))
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index cf9ce02..1255ac5 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -7,6 +7,7 @@
#include "base/float_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
@@ -401,11 +402,11 @@ Value* JSONReader::DecodeNumber(const Token& token) {
const std::wstring num_string(token.begin, token.length);
int num_int;
- if (StringToInt(WideToUTF16Hack(num_string), &num_int))
+ if (StringToInt(WideToUTF8(num_string), &num_int))
return Value::CreateIntegerValue(num_int);
double num_double;
- if (StringToDouble(WideToUTF16Hack(num_string), &num_double) &&
+ if (StringToDouble(WideToUTF8(num_string), &num_double) &&
base::IsFinite(num_double))
return Value::CreateRealValue(num_double);
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index ffdad76..fa43953 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -7,6 +7,7 @@
#include "base/json/string_escape.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "base/utf_string_conversions.h"
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index d3d029e..8b8a0c7 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -17,6 +17,7 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/sys_info.h"
@@ -32,7 +33,7 @@ enum ParsingState {
// spaces.
void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
FilePath stat_file("/proc");
- stat_file = stat_file.Append(IntToString(pid));
+ stat_file = stat_file.Append(base::IntToString(pid));
stat_file = stat_file.Append("stat");
std::string mem_stats;
if (!file_util::ReadFileToString(stat_file, &mem_stats))
@@ -46,7 +47,7 @@ namespace base {
ProcessId GetParentProcessId(ProcessHandle process) {
FilePath stat_file("/proc");
- stat_file = stat_file.Append(IntToString(process));
+ stat_file = stat_file.Append(base::IntToString(process));
stat_file = stat_file.Append("status");
std::string status;
if (!file_util::ReadFileToString(stat_file, &status))
@@ -64,7 +65,8 @@ ProcessId GetParentProcessId(ProcessHandle process) {
case KEY_VALUE:
DCHECK(!last_key_name.empty());
if (last_key_name == "PPid") {
- pid_t ppid = StringToInt(tokenizer.token());
+ int ppid;
+ base::StringToInt(tokenizer.token(), &ppid);
return ppid;
}
state = KEY_NAME;
@@ -77,7 +79,7 @@ ProcessId GetParentProcessId(ProcessHandle process) {
FilePath GetProcessExecutablePath(ProcessHandle process) {
FilePath stat_file("/proc");
- stat_file = stat_file.Append(IntToString(process));
+ stat_file = stat_file.Append(base::IntToString(process));
stat_file = stat_file.Append("exe");
char exename[2048];
ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename));
@@ -205,8 +207,11 @@ size_t ProcessMetrics::GetPagefileUsage() const {
std::vector<std::string> proc_stats;
GetProcStats(process_, &proc_stats);
const size_t kVmSize = 22;
- if (proc_stats.size() > kVmSize)
- return static_cast<size_t>(StringToInt(proc_stats[kVmSize]));
+ if (proc_stats.size() > kVmSize) {
+ int vm_size;
+ base::StringToInt(proc_stats[kVmSize], &vm_size);
+ return static_cast<size_t>(vm_size);
+ }
return 0;
}
@@ -215,8 +220,11 @@ size_t ProcessMetrics::GetPeakPagefileUsage() const {
std::vector<std::string> proc_stats;
GetProcStats(process_, &proc_stats);
const size_t kVmPeak = 21;
- if (proc_stats.size() > kVmPeak)
- return static_cast<size_t>(StringToInt(proc_stats[kVmPeak]));
+ if (proc_stats.size() > kVmPeak) {
+ int vm_peak;
+ if (base::StringToInt(proc_stats[kVmPeak], &vm_peak))
+ return vm_peak;
+ }
return 0;
}
@@ -226,8 +234,9 @@ size_t ProcessMetrics::GetWorkingSetSize() const {
GetProcStats(process_, &proc_stats);
const size_t kVmRss = 23;
if (proc_stats.size() > kVmRss) {
- size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmRss]));
- return num_pages * getpagesize();
+ int num_pages;
+ if (base::StringToInt(proc_stats[kVmRss], &num_pages))
+ return static_cast<size_t>(num_pages) * getpagesize();
}
return 0;
}
@@ -238,8 +247,9 @@ size_t ProcessMetrics::GetPeakWorkingSetSize() const {
GetProcStats(process_, &proc_stats);
const size_t kVmHwm = 23;
if (proc_stats.size() > kVmHwm) {
- size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmHwm]));
- return num_pages * getpagesize();
+ int num_pages;
+ base::StringToInt(proc_stats[kVmHwm], &num_pages);
+ return static_cast<size_t>(num_pages) * getpagesize();
}
return 0;
}
@@ -265,7 +275,7 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
// See http://www.pixelbeat.org/scripts/ps_mem.py
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
FilePath stat_file =
- FilePath("/proc").Append(IntToString(process_)).Append("smaps");
+ FilePath("/proc").Append(base::IntToString(process_)).Append("smaps");
std::string smaps;
int private_kb = 0;
int pss_kb = 0;
@@ -288,10 +298,14 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
return false;
}
if (last_key_name.starts_with(private_prefix)) {
- private_kb += StringToInt(tokenizer.token());
+ int cur;
+ base::StringToInt(tokenizer.token(), &cur);
+ private_kb += cur;
} else if (last_key_name.starts_with(pss_prefix)) {
have_pss = true;
- pss_kb += StringToInt(tokenizer.token());
+ int cur;
+ base::StringToInt(tokenizer.token(), &cur);
+ pss_kb += cur;
}
state = KEY_NAME;
break;
@@ -305,7 +319,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
return false;
stat_file =
- FilePath("/proc").Append(IntToString(process_)).Append("statm");
+ FilePath("/proc").Append(base::IntToString(process_)).Append("statm");
std::string statm;
if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0)
return false;
@@ -314,8 +328,11 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
SplitString(statm, ' ', &statm_vec);
if (statm_vec.size() != 7)
return false; // Not the format we expect.
- private_kb = StringToInt(statm_vec[1]) - StringToInt(statm_vec[2]);
- private_kb *= page_size_kb;
+
+ int statm1, statm2;
+ base::StringToInt(statm_vec[1], &statm1);
+ base::StringToInt(statm_vec[2], &statm2);
+ private_kb = (statm1 - statm2) * page_size_kb;
}
ws_usage->priv = private_kb;
// Sharable is not calculated, as it does not provide interesting data.
@@ -332,7 +349,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
std::string proc_io_contents;
FilePath io_file("/proc");
- io_file = io_file.Append(IntToString(process_));
+ io_file = io_file.Append(base::IntToString(process_));
io_file = io_file.Append("io");
if (!file_util::ReadFileToString(io_file, &proc_io_contents))
return false;
@@ -352,13 +369,17 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
case KEY_VALUE:
DCHECK(!last_key_name.empty());
if (last_key_name == "syscr") {
- (*io_counters).ReadOperationCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount));
} else if (last_key_name == "syscw") {
- (*io_counters).WriteOperationCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount));
} else if (last_key_name == "rchar") {
- (*io_counters).ReadTransferCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount));
} else if (last_key_name == "wchar") {
- (*io_counters).WriteTransferCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount));
}
state = KEY_NAME;
break;
@@ -384,7 +405,10 @@ int ParseProcStatCPU(const std::string& input) {
if (fields.size() < 13)
return -1; // Output not in the format we expect.
- return StringToInt(fields[11]) + StringToInt(fields[12]);
+ int fields11, fields12;
+ base::StringToInt(fields[11], &fields11);
+ base::StringToInt(fields[12], &fields12);
+ return fields11 + fields12;
}
// Get the total CPU of a single process. Return value is number of jiffies
@@ -498,13 +522,13 @@ size_t GetSystemCommitCharge() {
DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:");
DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:");
- size_t result_in_kb;
- result_in_kb = StringToInt(meminfo_fields[kMemTotalIndex]);
- result_in_kb -= StringToInt(meminfo_fields[kMemFreeIndex]);
- result_in_kb -= StringToInt(meminfo_fields[kMemBuffersIndex]);
- result_in_kb -= StringToInt(meminfo_fields[kMemCacheIndex]);
+ int mem_total, mem_free, mem_buffers, mem_cache;
+ base::StringToInt(meminfo_fields[kMemTotalIndex], &mem_total);
+ base::StringToInt(meminfo_fields[kMemFreeIndex], &mem_free);
+ base::StringToInt(meminfo_fields[kMemBuffersIndex], &mem_buffers);
+ base::StringToInt(meminfo_fields[kMemCacheIndex], &mem_cache);
- return result_in_kb;
+ return mem_total - mem_free - mem_buffers - mem_cache;
}
namespace {
@@ -613,13 +637,13 @@ bool AdjustOOMScore(ProcessId process, int score) {
return false;
FilePath oom_adj("/proc");
- oom_adj = oom_adj.Append(Int64ToString(process));
+ oom_adj = oom_adj.Append(base::Int64ToString(process));
oom_adj = oom_adj.AppendASCII("oom_adj");
if (!file_util::PathExists(oom_adj))
return false;
- std::string score_str = IntToString(score);
+ std::string score_str = base::IntToString(score);
return (static_cast<int>(score_str.length()) ==
file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length()));
}
diff --git a/base/simple_thread.cc b/base/simple_thread.cc
index 6d531a2..a72542d 100644
--- a/base/simple_thread.cc
+++ b/base/simple_thread.cc
@@ -7,7 +7,7 @@
#include "base/waitable_event.h"
#include "base/logging.h"
#include "base/platform_thread.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
namespace base {
diff --git a/base/simple_thread_unittest.cc b/base/simple_thread_unittest.cc
index 8bb267d..df0f5c6 100644
--- a/base/simple_thread_unittest.cc
+++ b/base/simple_thread_unittest.cc
@@ -1,10 +1,11 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/atomic_sequence_num.h"
#include "base/lock.h"
#include "base/simple_thread.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -121,8 +122,8 @@ TEST(SimpleThreadTest, NamedWithOptions) {
thread.Start();
EXPECT_EQ(thread.name_prefix(), "event_waiter");
- EXPECT_EQ(thread.name(), std::string("event_waiter/") +
- IntToString(thread.tid()));
+ EXPECT_EQ(thread.name(),
+ std::string("event_waiter/") + base::IntToString(thread.tid()));
event.Wait();
EXPECT_TRUE(event.IsSignaled());
@@ -130,8 +131,8 @@ TEST(SimpleThreadTest, NamedWithOptions) {
// We keep the name and tid, even after the thread is gone.
EXPECT_EQ(thread.name_prefix(), "event_waiter");
- EXPECT_EQ(thread.name(), std::string("event_waiter/") +
- IntToString(thread.tid()));
+ EXPECT_EQ(thread.name(),
+ std::string("event_waiter/") + base::IntToString(thread.tid()));
}
TEST(SimpleThreadTest, ThreadPool) {
diff --git a/base/string_number_conversions.cc b/base/string_number_conversions.cc
new file mode 100644
index 0000000..d340151
--- /dev/null
+++ b/base/string_number_conversions.cc
@@ -0,0 +1,400 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string_number_conversions.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "base/third_party/dmg_fp/dmg_fp.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT, typename UINT, bool NEG>
+struct IntToStringT {
+ // This is to avoid a compiler warning about unary minus on unsigned type.
+ // For example, say you had the following code:
+ // template <typename INT>
+ // INT abs(INT value) { return value < 0 ? -value : value; }
+ // Even though if INT is unsigned, it's impossible for value < 0, so the
+ // unary minus will never be taken, the compiler will still generate a
+ // warning. We do a little specialization dance...
+ template <typename INT2, typename UINT2, bool NEG2>
+ struct ToUnsignedT {};
+
+ template <typename INT2, typename UINT2>
+ struct ToUnsignedT<INT2, UINT2, false> {
+ static UINT2 ToUnsigned(INT2 value) {
+ return static_cast<UINT2>(value);
+ }
+ };
+
+ template <typename INT2, typename UINT2>
+ struct ToUnsignedT<INT2, UINT2, true> {
+ static UINT2 ToUnsigned(INT2 value) {
+ return static_cast<UINT2>(value < 0 ? -value : value);
+ }
+ };
+
+ // This set of templates is very similar to the above templates, but
+ // for testing whether an integer is negative.
+ template <typename INT2, bool NEG2>
+ struct TestNegT {};
+ template <typename INT2>
+ struct TestNegT<INT2, false> {
+ static bool TestNeg(INT2 value) {
+ // value is unsigned, and can never be negative.
+ return false;
+ }
+ };
+ template <typename INT2>
+ struct TestNegT<INT2, true> {
+ static bool TestNeg(INT2 value) {
+ return value < 0;
+ }
+ };
+
+ static STR IntToString(INT value) {
+ // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
+ // So round up to allocate 3 output characters per byte, plus 1 for '-'.
+ const int kOutputBufSize = 3 * sizeof(INT) + 1;
+
+ // Allocate the whole string right away, we will right back to front, and
+ // then return the substr of what we ended up using.
+ STR outbuf(kOutputBufSize, 0);
+
+ bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
+ // Even though is_neg will never be true when INT is parameterized as
+ // unsigned, even the presence of the unary operation causes a warning.
+ UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
+
+ for (typename STR::iterator it = outbuf.end();;) {
+ --it;
+ DCHECK(it != outbuf.begin());
+ *it = static_cast<typename STR::value_type>((res % 10) + '0');
+ res /= 10;
+
+ // We're done..
+ if (res == 0) {
+ if (is_neg) {
+ --it;
+ DCHECK(it != outbuf.begin());
+ *it = static_cast<typename STR::value_type>('-');
+ }
+ return STR(it, outbuf.end());
+ }
+ }
+ NOTREACHED();
+ return STR();
+ }
+};
+
+// Generalized string-to-number conversion.
+//
+// StringToNumberTraits should provide:
+// - a typedef for string_type, the STL string type used as input.
+// - a typedef for value_type, the target numeric type.
+// - a static function, convert_func, which dispatches to an appropriate
+// strtol-like function and returns type value_type.
+// - a static function, valid_func, which validates |input| and returns a bool
+// indicating whether it is in proper form. This is used to check for
+// conditions that convert_func tolerates but should result in
+// StringToNumber returning false. For strtol-like funtions, valid_func
+// should check for leading whitespace.
+template<typename StringToNumberTraits>
+bool StringToNumber(const typename StringToNumberTraits::string_type& input,
+ typename StringToNumberTraits::value_type* output) {
+ typedef StringToNumberTraits traits;
+
+ errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows.
+ typename traits::string_type::value_type* endptr = NULL;
+ typename traits::value_type value = traits::convert_func(input.c_str(),
+ &endptr);
+ *output = value;
+
+ // Cases to return false:
+ // - If errno is ERANGE, there was an overflow or underflow.
+ // - If the input string is empty, there was nothing to parse.
+ // - If endptr does not point to the end of the string, there are either
+ // characters remaining in the string after a parsed number, or the string
+ // does not begin with a parseable number. endptr is compared to the
+ // expected end given the string's stated length to correctly catch cases
+ // where the string contains embedded NUL characters.
+ // - valid_func determines that the input is not in preferred form.
+ return errno == 0 &&
+ !input.empty() &&
+ input.c_str() + input.length() == endptr &&
+ traits::valid_func(input);
+}
+
+static int strtoi(const char *nptr, char **endptr, int base) {
+ long res = strtol(nptr, endptr, base);
+#if __LP64__
+ // Long is 64-bits, we have to handle under/overflow ourselves.
+ if (res > kint32max) {
+ res = kint32max;
+ errno = ERANGE;
+ } else if (res < kint32min) {
+ res = kint32min;
+ errno = ERANGE;
+ }
+#endif
+ return static_cast<int>(res);
+}
+
+static unsigned int strtoui(const char *nptr, char **endptr, int base) {
+ unsigned long res = strtoul(nptr, endptr, base);
+#if __LP64__
+ // Long is 64-bits, we have to handle under/overflow ourselves. Test to see
+ // if the result can fit into 32-bits (as signed or unsigned).
+ if (static_cast<int>(static_cast<long>(res)) != static_cast<long>(res) &&
+ static_cast<unsigned int>(res) != res) {
+ res = kuint32max;
+ errno = ERANGE;
+ }
+#endif
+ return static_cast<unsigned int>(res);
+}
+
+class StringToIntTraits {
+ public:
+ typedef std::string string_type;
+ typedef int value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return strtoi(str, endptr, kBase);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class String16ToIntTraits {
+ public:
+ typedef string16 string_type;
+ typedef int value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#if defined(WCHAR_T_IS_UTF16)
+ return wcstol(str, endptr, kBase);
+#elif defined(WCHAR_T_IS_UTF32)
+ std::string ascii_string = UTF16ToUTF8(string16(str));
+ char* ascii_end = NULL;
+ value_type ret = strtoi(ascii_string.c_str(), &ascii_end, kBase);
+ if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
+ *endptr =
+ const_cast<string_type::value_type*>(str) + ascii_string.length();
+ }
+ return ret;
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !iswspace(str[0]);
+ }
+};
+
+class StringToInt64Traits {
+ public:
+ typedef std::string string_type;
+ typedef int64 value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#ifdef OS_WIN
+ return _strtoi64(str, endptr, kBase);
+#else // assume OS_POSIX
+ return strtoll(str, endptr, kBase);
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class String16ToInt64Traits {
+ public:
+ typedef string16 string_type;
+ typedef int64 value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#ifdef OS_WIN
+ return _wcstoi64(str, endptr, kBase);
+#else // assume OS_POSIX
+ std::string ascii_string = UTF16ToUTF8(string16(str));
+ char* ascii_end = NULL;
+ value_type ret = strtoll(ascii_string.c_str(), &ascii_end, kBase);
+ if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
+ *endptr =
+ const_cast<string_type::value_type*>(str) + ascii_string.length();
+ }
+ return ret;
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !iswspace(str[0]);
+ }
+};
+
+// For the HexString variants, use the unsigned variants like strtoul for
+// convert_func so that input like "0x80000000" doesn't result in an overflow.
+
+class HexStringToIntTraits {
+ public:
+ typedef std::string string_type;
+ typedef int value_type;
+ static const int kBase = 16;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return strtoui(str, endptr, kBase);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class StringToDoubleTraits {
+ public:
+ typedef std::string string_type;
+ typedef double value_type;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return dmg_fp::strtod(str, endptr);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+template<class CHAR>
+bool HexDigitToIntT(const CHAR digit, uint8* val) {
+ if (digit >= '0' && digit <= '9')
+ *val = digit - '0';
+ else if (digit >= 'a' && digit <= 'f')
+ *val = 10 + digit - 'a';
+ else if (digit >= 'A' && digit <= 'F')
+ *val = 10 + digit - 'A';
+ else
+ return false;
+ return true;
+}
+
+template<typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
+ DCHECK(output->size() == 0);
+ size_t count = input.size();
+ if (count == 0 || (count % 2) != 0)
+ return false;
+ for (uintptr_t i = 0; i < count / 2; ++i) {
+ uint8 msb = 0; // most significant 4 bits
+ uint8 lsb = 0; // least significant 4 bits
+ if (!HexDigitToIntT(input[i * 2], &msb) ||
+ !HexDigitToIntT(input[i * 2 + 1], &lsb))
+ return false;
+ output->push_back((msb << 4) | lsb);
+ }
+ return true;
+}
+
+} // namespace
+
+std::string IntToString(int value) {
+ return IntToStringT<std::string, int, unsigned int, true>::
+ IntToString(value);
+}
+
+string16 IntToString16(int value) {
+ return IntToStringT<string16, int, unsigned int, true>::
+ IntToString(value);
+}
+
+std::string UintToString(unsigned int value) {
+ return IntToStringT<std::string, unsigned int, unsigned int, false>::
+ IntToString(value);
+}
+
+string16 UintToString16(unsigned int value) {
+ return IntToStringT<string16, unsigned int, unsigned int, false>::
+ IntToString(value);
+}
+
+std::string Int64ToString(int64 value) {
+ return IntToStringT<std::string, int64, uint64, true>::
+ IntToString(value);
+}
+
+string16 Int64ToString16(int64 value) {
+ return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+}
+
+std::string Uint64ToString(uint64 value) {
+ return IntToStringT<std::string, uint64, uint64, false>::
+ IntToString(value);
+}
+
+string16 Uint64ToString16(uint64 value) {
+ return IntToStringT<string16, uint64, uint64, false>::
+ IntToString(value);
+}
+
+std::string DoubleToString(double value) {
+ // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+ char buffer[32];
+ dmg_fp::g_fmt(buffer, value);
+ return std::string(buffer);
+}
+
+bool StringToInt(const std::string& input, int* output) {
+ return StringToNumber<StringToIntTraits>(input, output);
+}
+
+bool StringToInt(const string16& input, int* output) {
+ return StringToNumber<String16ToIntTraits>(input, output);
+}
+
+bool StringToInt64(const std::string& input, int64* output) {
+ return StringToNumber<StringToInt64Traits>(input, output);
+}
+
+bool StringToInt64(const string16& input, int64* output) {
+ return StringToNumber<String16ToInt64Traits>(input, output);
+}
+
+bool StringToDouble(const std::string& input, double* output) {
+ return StringToNumber<StringToDoubleTraits>(input, output);
+}
+
+// Note: if you need to add String16ToDouble, first ask yourself if it's
+// really necessary. If it is, probably the best implementation here is to
+// convert to 8-bit and then use the 8-bit version.
+
+std::string HexEncode(const void* bytes, size_t size) {
+ static const char kHexChars[] = "0123456789ABCDEF";
+
+ // Each input byte creates two output hex characters.
+ std::string ret(size * 2, '\0');
+
+ for (size_t i = 0; i < size; ++i) {
+ char b = reinterpret_cast<const char*>(bytes)[i];
+ ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+ ret[(i * 2) + 1] = kHexChars[b & 0xf];
+ }
+ return ret;
+}
+
+bool HexStringToInt(const std::string& input, int* output) {
+ return StringToNumber<HexStringToIntTraits>(input, output);
+}
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+ return HexStringToBytesT(input, output);
+}
+
+} // namespace base
diff --git a/base/string_number_conversions.h b/base/string_number_conversions.h
new file mode 100644
index 0000000..928cb8a
--- /dev/null
+++ b/base/string_number_conversions.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRING_NUMBER_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+// ----------------------------------------------------------------------------
+// IMPORTANT MESSAGE FROM YOUR SPONSOR
+//
+// This file contains no "wstring" variants. New code should use string16. If
+// you need to make old code work, use the UTF8 version and convert. Please do
+// not add wstring variants.
+//
+// Please do not add "convenience" functions for converting strings to integers
+// that return the value and ignore success/failure. That encourages people to
+// write code that doesn't properly handle the error conditions.
+// ----------------------------------------------------------------------------
+
+namespace base {
+
+// Number -> string conversions ------------------------------------------------
+
+std::string IntToString(int value);
+string16 IntToString16(int value);
+
+std::string UintToString(unsigned value);
+string16 UintToString16(unsigned value);
+
+std::string Int64ToString(int64 value);
+string16 Int64ToString16(int64 value);
+
+std::string Uint64ToString(uint64 value);
+string16 Uint64ToString16(uint64 value);
+
+// DoubleToString converts the double to a string format that ignores the
+// locale. If you want to use locale specific formatting, use ICU.
+std::string DoubleToString(double value);
+
+// String -> number conversions ------------------------------------------------
+
+// Perform a best-effort conversion of the input string to a numeric type,
+// setting |*output| to the result of the conversion. Returns true for
+// "perfect" conversions; returns false in the following cases:
+// - Overflow/underflow. |*output| will be set to the maximum value supported
+// by the data type.
+// - Trailing characters in the string after parsing the number. |*output|
+// will be set to the value of the number that was parsed.
+// - No characters parseable as a number at the beginning of the string.
+// |*output| will be set to 0.
+// - Empty string. |*output| will be set to 0.
+bool StringToInt(const std::string& input, int* output);
+bool StringToInt(const string16& input, int* output);
+bool StringToInt64(const std::string& input, int64* output);
+bool StringToInt64(const string16& input, int64* output);
+
+// For floating-point conversions, only conversions of input strings in decimal
+// form are defined to work. Behavior with strings representing floating-point
+// numbers in hexadecimal, and strings representing non-fininte values (such as
+// NaN and inf) is undefined. Otherwise, these behave the same as the integral
+// variants. This expects the input string to NOT be specific to the locale.
+// If your input is locale specific, use ICU to read the number.
+bool StringToDouble(const std::string& input, double* output);
+
+// Hex encoding ----------------------------------------------------------------
+
+// Returns a hex string representation of a binary buffer. The returned hex
+// string will be in upper case. This function does not check if |size| is
+// within reasonable limits since it's written with trusted data in mind. If
+// you suspect that the data you want to format might be large, the absolute
+// max size for |size| should be is
+// std::numeric_limits<size_t>::max() / 2
+std::string HexEncode(const void* bytes, size_t size);
+
+// Best effort conversion, see StringToInt above for restrictions.
+bool HexStringToInt(const std::string& input, int* output);
+
+// Similar to the previous functions, except that output is a vector of bytes.
+// |*output| will contain as many bytes as were successfully parsed prior to the
+// error. There is no overflow, but input.size() must be evenly divisible by 2.
+// Leading 0x or +/- are not allowed.
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output);
+
+} // namespace base
+
+#endif // BASE_STRING_NUMBER_CONVERSIONS_H_
diff --git a/base/string_number_conversions_unittest.cc b/base/string_number_conversions_unittest.cc
new file mode 100644
index 0000000..2d4747e
--- /dev/null
+++ b/base/string_number_conversions_unittest.cc
@@ -0,0 +1,339 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+#include <math.h> // For HUGE_VAL.
+
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+template <typename INT>
+struct IntToStringTest {
+ INT num;
+ const char* sexpected;
+ const char* uexpected;
+};
+
+} // namespace
+
+TEST(StringNumberConversionsTest, IntToString) {
+ static const IntToStringTest<int> int_tests[] = {
+ { 0, "0", "0" },
+ { -1, "-1", "4294967295" },
+ { std::numeric_limits<int>::max(), "2147483647", "2147483647" },
+ { std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
+ };
+ static const IntToStringTest<int64> int64_tests[] = {
+ { 0, "0", "0" },
+ { -1, "-1", "18446744073709551615" },
+ { std::numeric_limits<int64>::max(),
+ "9223372036854775807",
+ "9223372036854775807", },
+ { std::numeric_limits<int64>::min(),
+ "-9223372036854775808",
+ "9223372036854775808" },
+ };
+
+ for (size_t i = 0; i < arraysize(int_tests); ++i) {
+ const IntToStringTest<int>* test = &int_tests[i];
+ EXPECT_EQ(IntToString(test->num), test->sexpected);
+ EXPECT_EQ(IntToString16(test->num), UTF8ToUTF16(test->sexpected));
+ EXPECT_EQ(UintToString(test->num), test->uexpected);
+ EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected));
+ }
+ for (size_t i = 0; i < arraysize(int64_tests); ++i) {
+ const IntToStringTest<int64>* test = &int64_tests[i];
+ EXPECT_EQ(Int64ToString(test->num), test->sexpected);
+ EXPECT_EQ(Int64ToString16(test->num), UTF8ToUTF16(test->sexpected));
+ EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
+ EXPECT_EQ(Uint64ToString16(test->num), UTF8ToUTF16(test->uexpected));
+ }
+}
+
+TEST(StringNumberConversionsTest, Uint64ToString) {
+ static const struct {
+ uint64 input;
+ std::string output;
+ } cases[] = {
+ {0, "0"},
+ {42, "42"},
+ {INT_MAX, "2147483647"},
+ {kuint64max, "18446744073709551615"},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)
+ EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
+}
+
+TEST(StringNumberConversionsTest, StringToInt) {
+ static const struct {
+ std::string input;
+ int output;
+ bool success;
+ } cases[] = {
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", INT_MIN, true},
+ {"2147483647", INT_MAX, true},
+ {"", 0, false},
+ {" 42", 42, false},
+ {"42 ", 42, false},
+ {"\t\n\v\f\r 42", 42, false},
+ {"blah42", 0, false},
+ {"42blah", 42, false},
+ {"blah42blah", 0, false},
+ {"-273.15", -273, false},
+ {"+98.6", 98, false},
+ {"--123", 0, false},
+ {"++123", 0, false},
+ {"-+123", 0, false},
+ {"+-123", 0, false},
+ {"-", 0, false},
+ {"-2147483649", INT_MIN, false},
+ {"-99999999999", INT_MIN, false},
+ {"2147483648", INT_MAX, false},
+ {"99999999999", INT_MAX, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ int output;
+ EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
+ EXPECT_EQ(cases[i].output, output);
+
+ string16 utf16_input = UTF8ToUTF16(cases[i].input);
+ EXPECT_EQ(cases[i].success, StringToInt(utf16_input, &output));
+ EXPECT_EQ(cases[i].output, output);
+ }
+
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "6\06";
+ std::string input_string(input, arraysize(input) - 1);
+ int output;
+ EXPECT_FALSE(StringToInt(input_string, &output));
+ EXPECT_EQ(6, output);
+
+ string16 utf16_input = UTF8ToUTF16(input_string);
+ EXPECT_FALSE(StringToInt(utf16_input, &output));
+ EXPECT_EQ(6, output);
+}
+
+TEST(StringNumberConversionsTest, StringToInt64) {
+ static const struct {
+ std::string input;
+ int64 output;
+ bool success;
+ } cases[] = {
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", INT_MIN, true},
+ {"2147483647", INT_MAX, true},
+ {"-2147483649", GG_INT64_C(-2147483649), true},
+ {"-99999999999", GG_INT64_C(-99999999999), true},
+ {"2147483648", GG_INT64_C(2147483648), true},
+ {"99999999999", GG_INT64_C(99999999999), true},
+ {"9223372036854775807", kint64max, true},
+ {"-9223372036854775808", kint64min, true},
+ {"09", 9, true},
+ {"-09", -9, true},
+ {"", 0, false},
+ {" 42", 42, false},
+ {"42 ", 42, false},
+ {"\t\n\v\f\r 42", 42, false},
+ {"blah42", 0, false},
+ {"42blah", 42, false},
+ {"blah42blah", 0, false},
+ {"-273.15", -273, false},
+ {"+98.6", 98, false},
+ {"--123", 0, false},
+ {"++123", 0, false},
+ {"-+123", 0, false},
+ {"+-123", 0, false},
+ {"-", 0, false},
+ {"-9223372036854775809", kint64min, false},
+ {"-99999999999999999999", kint64min, false},
+ {"9223372036854775808", kint64max, false},
+ {"99999999999999999999", kint64max, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ int64 output;
+ EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
+ EXPECT_EQ(cases[i].output, output);
+
+ string16 utf16_input = UTF8ToUTF16(cases[i].input);
+ EXPECT_EQ(cases[i].success, StringToInt64(utf16_input, &output));
+ EXPECT_EQ(cases[i].output, output);
+ }
+
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "6\06";
+ std::string input_string(input, arraysize(input) - 1);
+ int64 output;
+ EXPECT_FALSE(StringToInt64(input_string, &output));
+ EXPECT_EQ(6, output);
+
+ string16 utf16_input = UTF8ToUTF16(input_string);
+ EXPECT_FALSE(StringToInt64(utf16_input, &output));
+ EXPECT_EQ(6, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt) {
+ static const struct {
+ std::string input;
+ int output;
+ bool success;
+ } cases[] = {
+ {"0", 0, true},
+ {"42", 66, true},
+ {"-42", -66, true},
+ {"+42", 66, true},
+ {"7fffffff", INT_MAX, true},
+ {"80000000", INT_MIN, true},
+ {"ffffffff", -1, true},
+ {"DeadBeef", 0xdeadbeef, true},
+ {"0x42", 66, true},
+ {"-0x42", -66, true},
+ {"+0x42", 66, true},
+ {"0x7fffffff", INT_MAX, true},
+ {"0x80000000", INT_MIN, true},
+ {"0xffffffff", -1, true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x0f", 15, true},
+ {"0f", 15, true},
+ {" 45", 0x45, false},
+ {"\t\n\v\f\r 0x45", 0x45, false},
+ {" 45", 0x45, false},
+ {"45 ", 0x45, false},
+ {"efgh", 0xef, false},
+ {"0xefgh", 0xef, false},
+ {"hgfe", 0, false},
+ {"100000000", -1, false}, // don't care about |output|, just |success|
+ {"-", 0, false},
+ {"", 0, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ int output;
+ EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output));
+ EXPECT_EQ(cases[i].output, output);
+ }
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "0xc0ffee\09";
+ std::string input_string(input, arraysize(input) - 1);
+ int output;
+ EXPECT_FALSE(HexStringToInt(input_string, &output));
+ EXPECT_EQ(0xc0ffee, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToBytes) {
+ static const struct {
+ const std::string input;
+ const char* output;
+ size_t output_len;
+ bool success;
+ } cases[] = {
+ {"0", "", 0, false}, // odd number of characters fails
+ {"00", "\0", 1, true},
+ {"42", "\x42", 1, true},
+ {"-42", "", 0, false}, // any non-hex value fails
+ {"+42", "", 0, false},
+ {"7fffffff", "\x7f\xff\xff\xff", 4, true},
+ {"80000000", "\x80\0\0\0", 4, true},
+ {"deadbeef", "\xde\xad\xbe\xef", 4, true},
+ {"DeadBeef", "\xde\xad\xbe\xef", 4, true},
+ {"0x42", "", 0, false}, // leading 0x fails (x is not hex)
+ {"0f", "\xf", 1, true},
+ {"45 ", "\x45", 1, false},
+ {"efgh", "\xef", 1, false},
+ {"", "", 0, false},
+ {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true},
+ {"0123456789ABCDEF012345",
+ "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true},
+ };
+
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ std::vector<uint8> output;
+ std::vector<uint8> compare;
+ EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
+ i << ": " << cases[i].input;
+ for (size_t j = 0; j < cases[i].output_len; ++j)
+ compare.push_back(static_cast<uint8>(cases[i].output[j]));
+ ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
+ EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
+ i << ": " << cases[i].input;
+ }
+}
+
+TEST(StringNumberConversionsTest, StringToDouble) {
+ static const struct {
+ std::string input;
+ double output;
+ bool success;
+ } cases[] = {
+ {"0", 0.0, true},
+ {"42", 42.0, true},
+ {"-42", -42.0, true},
+ {"123.45", 123.45, true},
+ {"-123.45", -123.45, true},
+ {"+123.45", 123.45, true},
+ {"2.99792458e8", 299792458.0, true},
+ {"149597870.691E+3", 149597870691.0, true},
+ {"6.", 6.0, true},
+ {"9e99999999999999999999", HUGE_VAL, false},
+ {"-9e99999999999999999999", -HUGE_VAL, false},
+ {"1e-2", 0.01, true},
+ {" 1e-2", 0.01, false},
+ {"1e-2 ", 0.01, false},
+ {"-1E-7", -0.0000001, true},
+ {"01e02", 100, true},
+ {"2.3e15", 2.3e15, true},
+ {"\t\n\v\f\r -123.45e2", -12345.0, false},
+ {"+123 e4", 123.0, false},
+ {"123e ", 123.0, false},
+ {"123e", 123.0, false},
+ {" 2.99", 2.99, false},
+ {"1e3.4", 1000.0, false},
+ {"nothing", 0.0, false},
+ {"-", 0.0, false},
+ {"+", 0.0, false},
+ {"", 0.0, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ double output;
+ EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
+ EXPECT_DOUBLE_EQ(cases[i].output, output);
+ }
+
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "3.14\0159";
+ std::string input_string(input, arraysize(input) - 1);
+ double output;
+ EXPECT_FALSE(StringToDouble(input_string, &output));
+ EXPECT_DOUBLE_EQ(3.14, output);
+}
+
+TEST(StringNumberConversionsTest, HexEncode) {
+ std::string hex(HexEncode(NULL, 0));
+ EXPECT_EQ(hex.length(), 0U);
+ unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
+ hex = HexEncode(bytes, sizeof(bytes));
+ EXPECT_EQ(hex.compare("01FF02FE038081"), 0);
+}
+
+} // namespace base \ No newline at end of file
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
index 7afc0bd..f063fcc 100644
--- a/base/string_util_unittest.cc
+++ b/base/string_util_unittest.cc
@@ -633,365 +633,6 @@ TEST(StringUtilTest, ReplaceFirstSubstringAfterOffset) {
}
}
-namespace {
-
-template <typename INT>
-struct IntToStringTest {
- INT num;
- const char* sexpected;
- const char* uexpected;
-};
-
-} // namespace
-
-TEST(StringUtilTest, IntToString) {
- static const IntToStringTest<int> int_tests[] = {
- { 0, "0", "0" },
- { -1, "-1", "4294967295" },
- { std::numeric_limits<int>::max(), "2147483647", "2147483647" },
- { std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
- };
- static const IntToStringTest<int64> int64_tests[] = {
- { 0, "0", "0" },
- { -1, "-1", "18446744073709551615" },
- { std::numeric_limits<int64>::max(),
- "9223372036854775807",
- "9223372036854775807", },
- { std::numeric_limits<int64>::min(),
- "-9223372036854775808",
- "9223372036854775808" },
- };
-
- for (size_t i = 0; i < arraysize(int_tests); ++i) {
- const IntToStringTest<int>* test = &int_tests[i];
- EXPECT_EQ(IntToString(test->num), test->sexpected);
- EXPECT_EQ(IntToWString(test->num), UTF8ToWide(test->sexpected));
- EXPECT_EQ(UintToString(test->num), test->uexpected);
- EXPECT_EQ(UintToWString(test->num), UTF8ToWide(test->uexpected));
- }
- for (size_t i = 0; i < arraysize(int64_tests); ++i) {
- const IntToStringTest<int64>* test = &int64_tests[i];
- EXPECT_EQ(Int64ToString(test->num), test->sexpected);
- EXPECT_EQ(Int64ToWString(test->num), UTF8ToWide(test->sexpected));
- EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
- EXPECT_EQ(Uint64ToWString(test->num), UTF8ToWide(test->uexpected));
- }
-}
-
-TEST(StringUtilTest, Uint64ToString) {
- static const struct {
- uint64 input;
- std::string output;
- } cases[] = {
- {0, "0"},
- {42, "42"},
- {INT_MAX, "2147483647"},
- {kuint64max, "18446744073709551615"},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)
- EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
-}
-
-TEST(StringUtilTest, StringToInt) {
- static const struct {
- std::string input;
- int output;
- bool success;
- } cases[] = {
- {"0", 0, true},
- {"42", 42, true},
- {"-2147483648", INT_MIN, true},
- {"2147483647", INT_MAX, true},
- {"", 0, false},
- {" 42", 42, false},
- {"42 ", 42, false},
- {"\t\n\v\f\r 42", 42, false},
- {"blah42", 0, false},
- {"42blah", 42, false},
- {"blah42blah", 0, false},
- {"-273.15", -273, false},
- {"+98.6", 98, false},
- {"--123", 0, false},
- {"++123", 0, false},
- {"-+123", 0, false},
- {"+-123", 0, false},
- {"-", 0, false},
- {"-2147483649", INT_MIN, false},
- {"-99999999999", INT_MIN, false},
- {"2147483648", INT_MAX, false},
- {"99999999999", INT_MAX, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(cases[i].output, StringToInt(cases[i].input));
- int output;
- EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
- EXPECT_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].output, StringToInt(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, StringToInt(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_EQ(cases[i].output, output);
- }
-
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "6\06";
- std::string input_string(input, arraysize(input) - 1);
- int output;
- EXPECT_FALSE(StringToInt(input_string, &output));
- EXPECT_EQ(6, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(StringToInt(WideToUTF16Hack(wide_input), &output));
- EXPECT_EQ(6, output);
-}
-
-TEST(StringUtilTest, StringToInt64) {
- static const struct {
- std::string input;
- int64 output;
- bool success;
- } cases[] = {
- {"0", 0, true},
- {"42", 42, true},
- {"-2147483648", INT_MIN, true},
- {"2147483647", INT_MAX, true},
- {"-2147483649", GG_INT64_C(-2147483649), true},
- {"-99999999999", GG_INT64_C(-99999999999), true},
- {"2147483648", GG_INT64_C(2147483648), true},
- {"99999999999", GG_INT64_C(99999999999), true},
- {"9223372036854775807", kint64max, true},
- {"-9223372036854775808", kint64min, true},
- {"09", 9, true},
- {"-09", -9, true},
- {"", 0, false},
- {" 42", 42, false},
- {"42 ", 42, false},
- {"\t\n\v\f\r 42", 42, false},
- {"blah42", 0, false},
- {"42blah", 42, false},
- {"blah42blah", 0, false},
- {"-273.15", -273, false},
- {"+98.6", 98, false},
- {"--123", 0, false},
- {"++123", 0, false},
- {"-+123", 0, false},
- {"+-123", 0, false},
- {"-", 0, false},
- {"-9223372036854775809", kint64min, false},
- {"-99999999999999999999", kint64min, false},
- {"9223372036854775808", kint64max, false},
- {"99999999999999999999", kint64max, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(cases[i].output, StringToInt64(cases[i].input));
- int64 output;
- EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
- EXPECT_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].output, StringToInt64(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, StringToInt64(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_EQ(cases[i].output, output);
- }
-
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "6\06";
- std::string input_string(input, arraysize(input) - 1);
- int64 output;
- EXPECT_FALSE(StringToInt64(input_string, &output));
- EXPECT_EQ(6, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(StringToInt64(WideToUTF16Hack(wide_input), &output));
- EXPECT_EQ(6, output);
-}
-
-TEST(StringUtilTest, HexStringToInt) {
- static const struct {
- std::string input;
- int output;
- bool success;
- } cases[] = {
- {"0", 0, true},
- {"42", 66, true},
- {"-42", -66, true},
- {"+42", 66, true},
- {"7fffffff", INT_MAX, true},
- {"80000000", INT_MIN, true},
- {"ffffffff", -1, true},
- {"DeadBeef", 0xdeadbeef, true},
- {"0x42", 66, true},
- {"-0x42", -66, true},
- {"+0x42", 66, true},
- {"0x7fffffff", INT_MAX, true},
- {"0x80000000", INT_MIN, true},
- {"0xffffffff", -1, true},
- {"0XDeadBeef", 0xdeadbeef, true},
- {"0x0f", 15, true},
- {"0f", 15, true},
- {" 45", 0x45, false},
- {"\t\n\v\f\r 0x45", 0x45, false},
- {" 45", 0x45, false},
- {"45 ", 0x45, false},
- {"efgh", 0xef, false},
- {"0xefgh", 0xef, false},
- {"hgfe", 0, false},
- {"100000000", -1, false}, // don't care about |output|, just |success|
- {"-", 0, false},
- {"", 0, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(cases[i].output, HexStringToInt(cases[i].input));
- int output;
- EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output));
- EXPECT_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].output, HexStringToInt(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, HexStringToInt(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_EQ(cases[i].output, output);
- }
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "0xc0ffee\09";
- std::string input_string(input, arraysize(input) - 1);
- int output;
- EXPECT_FALSE(HexStringToInt(input_string, &output));
- EXPECT_EQ(0xc0ffee, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(HexStringToInt(WideToUTF16Hack(wide_input), &output));
- EXPECT_EQ(0xc0ffee, output);
-}
-
-TEST(StringUtilTest, HexStringToBytes) {
- static const struct {
- const std::string input;
- const char* output;
- size_t output_len;
- bool success;
- } cases[] = {
- {"0", "", 0, false}, // odd number of characters fails
- {"00", "\0", 1, true},
- {"42", "\x42", 1, true},
- {"-42", "", 0, false}, // any non-hex value fails
- {"+42", "", 0, false},
- {"7fffffff", "\x7f\xff\xff\xff", 4, true},
- {"80000000", "\x80\0\0\0", 4, true},
- {"deadbeef", "\xde\xad\xbe\xef", 4, true},
- {"DeadBeef", "\xde\xad\xbe\xef", 4, true},
- {"0x42", "", 0, false}, // leading 0x fails (x is not hex)
- {"0f", "\xf", 1, true},
- {"45 ", "\x45", 1, false},
- {"efgh", "\xef", 1, false},
- {"", "", 0, false},
- {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true},
- {"0123456789ABCDEF012345",
- "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true},
- };
-
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<uint8> output;
- std::vector<uint8> compare;
- EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
- i << ": " << cases[i].input;
- for (size_t j = 0; j < cases[i].output_len; ++j)
- compare.push_back(static_cast<uint8>(cases[i].output[j]));
- ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
- EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
- i << ": " << cases[i].input;
-
- output.clear();
- compare.clear();
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].success,
- HexStringToBytes(WideToUTF16Hack(wide_input), &output)) <<
- i << ": " << cases[i].input;
- for (size_t j = 0; j < cases[i].output_len; ++j)
- compare.push_back(static_cast<uint8>(cases[i].output[j]));
- ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
- EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
- i << ": " << cases[i].input;
- }
-}
-
-TEST(StringUtilTest, StringToDouble) {
- static const struct {
- std::string input;
- double output;
- bool success;
- } cases[] = {
- {"0", 0.0, true},
- {"42", 42.0, true},
- {"-42", -42.0, true},
- {"123.45", 123.45, true},
- {"-123.45", -123.45, true},
- {"+123.45", 123.45, true},
- {"2.99792458e8", 299792458.0, true},
- {"149597870.691E+3", 149597870691.0, true},
- {"6.", 6.0, true},
- {"9e99999999999999999999", HUGE_VAL, false},
- {"-9e99999999999999999999", -HUGE_VAL, false},
- {"1e-2", 0.01, true},
- {" 1e-2", 0.01, false},
- {"1e-2 ", 0.01, false},
- {"-1E-7", -0.0000001, true},
- {"01e02", 100, true},
- {"2.3e15", 2.3e15, true},
- {"\t\n\v\f\r -123.45e2", -12345.0, false},
- {"+123 e4", 123.0, false},
- {"123e ", 123.0, false},
- {"123e", 123.0, false},
- {" 2.99", 2.99, false},
- {"1e3.4", 1000.0, false},
- {"nothing", 0.0, false},
- {"-", 0.0, false},
- {"+", 0.0, false},
- {"", 0.0, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_DOUBLE_EQ(cases[i].output, StringToDouble(cases[i].input));
- double output;
- EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
- EXPECT_DOUBLE_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_DOUBLE_EQ(cases[i].output,
- StringToDouble(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, StringToDouble(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_DOUBLE_EQ(cases[i].output, output);
- }
-
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "3.14\0159";
- std::string input_string(input, arraysize(input) - 1);
- double output;
- EXPECT_FALSE(StringToDouble(input_string, &output));
- EXPECT_DOUBLE_EQ(3.14, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(StringToDouble(WideToUTF16Hack(wide_input), &output));
- EXPECT_DOUBLE_EQ(3.14, output);
-}
-
// This checks where we can use the assignment operator for a va_list. We need
// a way to do this since Visual C doesn't support va_copy, but assignment on
// va_list is not guaranteed to be a copy. See StringAppendVT which uses this
@@ -1655,14 +1296,6 @@ TEST(StringUtilTest, ElideString) {
}
}
-TEST(StringUtilTest, HexEncode) {
- std::string hex(HexEncode(NULL, 0));
- EXPECT_EQ(hex.length(), 0U);
- unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
- hex = HexEncode(bytes, sizeof(bytes));
- EXPECT_EQ(hex.compare("01FF02FE038081"), 0);
-}
-
TEST(StringUtilTest, RemoveChars) {
const char* kRemoveChars = "-/+*";
std::string input = "A-+bc/d!*";
diff --git a/base/version.cc b/base/version.cc
index 2271fcf..c784082 100644
--- a/base/version.cc
+++ b/base/version.cc
@@ -5,13 +5,15 @@
#include "base/version.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
// static
Version* Version::GetVersionFromString(const std::wstring& version_str) {
if (!IsStringASCII(version_str))
return NULL;
- return GetVersionFromString(WideToASCII(version_str));
+ return GetVersionFromString(WideToUTF8(version_str));
}
// static
@@ -60,10 +62,10 @@ const std::string Version::GetString() const {
std::string version_str;
int count = components_.size();
for (int i = 0; i < count - 1; ++i) {
- version_str.append(IntToString(components_[i]));
+ version_str.append(base::IntToString(components_[i]));
version_str.append(".");
}
- version_str.append(IntToString(components_[count - 1]));
+ version_str.append(base::IntToString(components_[count - 1]));
return version_str;
}
@@ -76,7 +78,7 @@ bool Version::InitFromString(const std::string& version_str) {
for (std::vector<std::string>::iterator i = numbers.begin();
i != numbers.end(); ++i) {
int num;
- if (!StringToInt(*i, &num))
+ if (!base::StringToInt(*i, &num))
return false;
if (num < 0)
return false;
@@ -84,7 +86,7 @@ bool Version::InitFromString(const std::string& version_str) {
if (num > max)
return false;
// This throws out things like +3, or 032.
- if (IntToString(num) != *i)
+ if (base::IntToString(num) != *i)
return false;
uint16 component = static_cast<uint16>(num);
components_.push_back(component);