summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/base.xcodeproj/project.pbxproj16
-rw-r--r--base/build/base.vcproj4
-rw-r--r--base/float_util.h50
-rw-r--r--base/json_reader.cc44
-rw-r--r--base/json_reader_unittest.cc23
-rw-r--r--base/string_util.cc58
-rw-r--r--base/string_util.h10
-rw-r--r--base/string_util_unittest.cc63
8 files changed, 214 insertions, 54 deletions
diff --git a/base/base.xcodeproj/project.pbxproj b/base/base.xcodeproj/project.pbxproj
index 75041cc..a27f5c5 100644
--- a/base/base.xcodeproj/project.pbxproj
+++ b/base/base.xcodeproj/project.pbxproj
@@ -23,6 +23,8 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 7B4C5D840E49157E00679E8F /* json_reader_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4562C3B0E28017F005E4685 /* json_reader_unittest.cc */; };
+ 7B4C5D890E4915D800679E8F /* float_util.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B4C5D880E4915D800679E8F /* float_util.h */; };
820EB4F00E3A610A009668FC /* linked_ptr.h in Headers */ = {isa = PBXBuildFile; fileRef = 820EB4EF0E3A610A009668FC /* linked_ptr.h */; };
820EB4F70E3A613F009668FC /* string_piece.cc in Sources */ = {isa = PBXBuildFile; fileRef = 820EB4F50E3A613F009668FC /* string_piece.cc */; };
820EB4F80E3A613F009668FC /* string_piece.h in Headers */ = {isa = PBXBuildFile; fileRef = 820EB4F60E3A613F009668FC /* string_piece.h */; };
@@ -294,6 +296,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ 7B4C5D880E4915D800679E8F /* float_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = float_util.h; sourceTree = "<group>"; };
7B5AD60D0D9DD8050012BCF1 /* scoped_cftyperef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scoped_cftyperef.h; sourceTree = "<group>"; };
7BD9E84E0DA447F800FC7A01 /* singleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = singleton.h; sourceTree = "<group>"; };
7BEB81100D9AD288009BA8DD /* prcpucfg_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = prcpucfg_mac.h; path = third_party/nspr/prcpucfg_mac.h; sourceTree = "<group>"; };
@@ -571,6 +574,7 @@
8254030B0D92D1D10006B936 /* fix_wp64.h */,
8254030D0D92D1DB0006B936 /* fixed_string.h */,
E4562C310E2800DE005E4685 /* fixed_string_unittest.cc */,
+ 7B4C5D880E4915D800679E8F /* float_util.h */,
824652C00DC12044007C2BAA /* hash_tables.h */,
8254030F0D92D1E80006B936 /* iat_patch.cc */,
825403100D92D1E80006B936 /* iat_patch.h */,
@@ -841,6 +845,7 @@
E48A066B0E3F70B500172919 /* convolver.h in Headers */,
E49357230E422A38008F8B09 /* timer.h in Headers */,
E49115EE0E47B461001EE8C3 /* at_exit.h in Headers */,
+ 7B4C5D890E4915D800679E8F /* float_util.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1149,17 +1154,18 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- E45A2C260E47ACC300DB1196 /* string_util.cc in Sources */,
- E45A2C7C0E47B20B00DB1196 /* string_util_mac.cc in Sources */,
- E45A2C7D0E47B20E00DB1196 /* string_util_icu.cc in Sources */,
E49115ED0E47B461001EE8C3 /* at_exit.cc in Sources */,
E49115F40E47B496001EE8C3 /* at_exit_unittest.cc in Sources */,
- E49115F90E47B4CB001EE8C3 /* logging.cc in Sources */,
+ E49115FD0E47B502001EE8C3 /* base_switches.cc in Sources */,
E49115FA0E47B4D3001EE8C3 /* command_line.cc in Sources */,
E49115FB0E47B4D3001EE8C3 /* command_line_unittest.cc in Sources */,
- E49115FD0E47B502001EE8C3 /* base_switches.cc in Sources */,
E491162D0E4895E2001EE8C3 /* fixed_string_unittest.cc in Sources */,
+ 7B4C5D840E49157E00679E8F /* json_reader_unittest.cc in Sources */,
+ E49115F90E47B4CB001EE8C3 /* logging.cc in Sources */,
E491165D0E48A51E001EE8C3 /* stack_container_unittest.cc in Sources */,
+ E45A2C260E47ACC300DB1196 /* string_util.cc in Sources */,
+ E45A2C7D0E47B20E00DB1196 /* string_util_icu.cc in Sources */,
+ E45A2C7C0E47B20B00DB1196 /* string_util_mac.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/base/build/base.vcproj b/base/build/base.vcproj
index c76886f..7a45722 100644
--- a/base/build/base.vcproj
+++ b/base/build/base.vcproj
@@ -294,6 +294,10 @@
>
</File>
<File
+ RelativePath="..\float_util.h"
+ >
+ </File>
+ <File
RelativePath="..\histogram.cc"
>
</File>
diff --git a/base/float_util.h b/base/float_util.h
new file mode 100644
index 0000000..6047417
--- /dev/null
+++ b/base/float_util.h
@@ -0,0 +1,50 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef BASE_FLOAT_UTIL_H_
+#define BASE_FLOAT_UTIL_H_
+
+#include "build/build_config.h"
+
+#include <float.h>
+#include <math.h>
+
+namespace base {
+
+inline bool IsFinite(const double& number) {
+#if defined(OS_POSIX)
+ return finite(number) != 0;
+#elif defined(OS_WIN)
+ return _finite(number) != 0;
+#endif
+}
+
+} // namespace base
+
+#endif // BASE_FLOAT_UTIL_H_
diff --git a/base/json_reader.cc b/base/json_reader.cc
index 257f635..66d8f68 100644
--- a/base/json_reader.cc
+++ b/base/json_reader.cc
@@ -29,8 +29,7 @@
#include "base/json_reader.h"
-#include <float.h>
-
+#include "base/float_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/values.h"
@@ -343,39 +342,20 @@ JSONReader::Token JSONReader::ParseNumberToken() {
}
bool JSONReader::DecodeNumber(const Token& token, Value** node) {
- // Determine if we want to try to parse as an int or a double.
- bool is_double = false;
- for (int i = 0; i < token.length; ++i) {
- wchar_t c = *(token.begin + i);
- if ('e' == c || 'E' == c || '.' == c) {
- is_double = true;
- break;
- }
+ const std::wstring num_string(token.begin, token.length);
+
+ int num_int;
+ if (StringToInt(num_string, &num_int)) {
+ *node = Value::CreateIntegerValue(num_int);
+ return true;
}
- if (is_double) {
- // Try parsing as a double.
- double num_double;
- int parsed_values = swscanf_s(token.begin, L"%lf", &num_double);
- // Make sure we're not -INF, INF or NAN.
- if (1 == parsed_values && _finite(num_double)) {
- *node = Value::CreateRealValue(num_double);
- return true;
- }
- } else {
- int num_int;
- int parsed_values = swscanf_s(token.begin, L"%d", &num_int);
- if (1 == parsed_values) {
- // Ensure the parsed value matches the string. This makes sure we don't
- // overflow/underflow.
- const std::wstring& back_to_str = StringPrintf(L"%d", num_int);
- if (0 == wcsncmp(back_to_str.c_str(), token.begin,
- back_to_str.length())) {
- *node = Value::CreateIntegerValue(num_int);
- return true;
- }
- }
+ double num_double;
+ if (StringToDouble(num_string, &num_double) && base::IsFinite(num_double)) {
+ *node = Value::CreateRealValue(num_double);
+ return true;
}
+
return false;
}
diff --git a/base/json_reader_unittest.cc b/base/json_reader_unittest.cc
index 130c8e8..1a81425 100644
--- a/base/json_reader_unittest.cc
+++ b/base/json_reader_unittest.cc
@@ -83,13 +83,14 @@ TEST(JSONReaderTest, Reading) {
ASSERT_EQ(0, int_val);
delete root;
- // Numbers that overflow ints should fail
+ // Numbers that overflow ints should succeed, being internally promoted to
+ // storage as doubles
root = NULL;
- ASSERT_FALSE(JSONReader::JsonToValue("2147483648", &root, false, false));
- ASSERT_FALSE(root);
+ ASSERT_TRUE(JSONReader::JsonToValue("2147483648", &root, false, false));
+ ASSERT_TRUE(root);
root = NULL;
- ASSERT_FALSE(JSONReader::JsonToValue("-2147483649", &root, false, false));
- ASSERT_FALSE(root);
+ ASSERT_TRUE(JSONReader::JsonToValue("-2147483649", &root, false, false));
+ ASSERT_TRUE(root);
// Parse a double
root = NULL;
@@ -264,7 +265,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root);
ASSERT_TRUE(root->IsType(Value::TYPE_LIST));
ListValue* list = static_cast<ListValue*>(root);
- ASSERT_EQ(3, list->GetSize());
+ ASSERT_EQ(static_cast<size_t>(3), list->GetSize());
// Test with trailing comma. Should be parsed the same as above.
Value* root2 = NULL;
@@ -279,7 +280,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root);
ASSERT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root);
- ASSERT_EQ(0, list->GetSize());
+ ASSERT_EQ(static_cast<size_t>(0), list->GetSize());
delete root;
// Nested arrays
@@ -289,7 +290,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root);
ASSERT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root);
- ASSERT_EQ(4, list->GetSize());
+ ASSERT_EQ(static_cast<size_t>(4), list->GetSize());
// Lots of trailing commas.
root2 = NULL;
@@ -327,7 +328,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root);
ASSERT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root);
- EXPECT_EQ(1, list->GetSize());
+ EXPECT_EQ(static_cast<size_t>(1), list->GetSize());
Value* tmp_value = NULL;
ASSERT_TRUE(list->Get(0, &tmp_value));
EXPECT_TRUE(tmp_value->IsType(Value::TYPE_BOOLEAN));
@@ -391,7 +392,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(dict_val->GetDictionary(L"inner", &inner_dict));
ListValue* inner_array = NULL;
ASSERT_TRUE(inner_dict->GetList(L"array", &inner_array));
- ASSERT_EQ(1, inner_array->GetSize());
+ ASSERT_EQ(static_cast<size_t>(1), inner_array->GetSize());
bool_value = true;
ASSERT_TRUE(dict_val->GetBoolean(L"false", &bool_value));
ASSERT_FALSE(bool_value);
@@ -465,7 +466,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root);
ASSERT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root);
- ASSERT_EQ(5001, list->GetSize());
+ ASSERT_EQ(static_cast<size_t>(5001), list->GetSize());
delete root;
// Test utf8 encoded input
diff --git a/base/string_util.cc b/base/string_util.cc
index 3c7bb87..4f095b7 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -144,7 +144,7 @@ class StringToLongTraits {
return strtol(str, endptr, kBase);
}
static inline bool valid_func(const string_type& str) {
- return !isspace(str[0]);
+ return !str.empty() && !isspace(str[0]);
}
};
@@ -158,7 +158,7 @@ class WStringToLongTraits {
return wcstol(str, endptr, kBase);
}
static inline bool valid_func(const string_type& str) {
- return !iswspace(str[0]);
+ return !str.empty() && !iswspace(str[0]);
}
};
@@ -176,7 +176,7 @@ class StringToInt64Traits {
#endif
}
static inline bool valid_func(const string_type& str) {
- return !isspace(str[0]);
+ return !str.empty() && !isspace(str[0]);
}
};
@@ -194,7 +194,7 @@ class WStringToInt64Traits {
#endif
}
static inline bool valid_func(const string_type& str) {
- return !iswspace(str[0]);
+ return !str.empty() && !iswspace(str[0]);
}
};
@@ -211,7 +211,7 @@ class HexStringToLongTraits {
return strtoul(str, endptr, kBase);
}
static inline bool valid_func(const string_type& str) {
- return !isspace(str[0]);
+ return !str.empty() && !isspace(str[0]);
}
};
@@ -225,7 +225,33 @@ class HexWStringToLongTraits {
return wcstoul(str, endptr, kBase);
}
static inline bool valid_func(const string_type& str) {
- return !iswspace(str[0]);
+ return !str.empty() && !iswspace(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 strtod(str, endptr);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class WStringToDoubleTraits {
+ public:
+ typedef std::wstring string_type;
+ typedef double value_type;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return wcstod(str, endptr);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !iswspace(str[0]);
}
};
@@ -1197,6 +1223,14 @@ bool HexStringToInt(const std::wstring& input, int* output) {
input, reinterpret_cast<long*>(output));
}
+bool StringToDouble(const std::string& input, double* output) {
+ return StringToNumber<StringToDoubleTraits>(input, output);
+}
+
+bool StringToDouble(const std::wstring& input, double* output) {
+ return StringToNumber<WStringToDoubleTraits>(input, output);
+}
+
int StringToInt(const std::string& value) {
int result;
StringToInt(value, &result);
@@ -1232,3 +1266,15 @@ int HexStringToInt(const std::wstring& value) {
HexStringToInt(value, &result);
return result;
}
+
+double StringToDouble(const std::string& value) {
+ double result;
+ StringToDouble(value, &result);
+ return result;
+}
+
+double StringToDouble(const std::wstring& value) {
+ double result;
+ StringToDouble(value, &result);
+ return result;
+}
diff --git a/base/string_util.h b/base/string_util.h
index 129f124..b89694f 100644
--- a/base/string_util.h
+++ b/base/string_util.h
@@ -342,6 +342,14 @@ bool StringToInt64(const std::wstring& input, int64* output);
bool HexStringToInt(const std::string& input, int* output);
bool HexStringToInt(const std::wstring& input, int* 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 above.
+bool StringToDouble(const std::string& input, double* output);
+bool StringToDouble(const std::wstring& input, double* output);
+
// Convenience forms of the above, when the caller is uninterested in the
// boolean return value. These return only the |*output| value from the
// above conversions: a best-effort conversion when possible, otherwise, 0.
@@ -351,6 +359,8 @@ int64 StringToInt64(const std::string& value);
int64 StringToInt64(const std::wstring& value);
int HexStringToInt(const std::string& value);
int HexStringToInt(const std::wstring& value);
+double StringToDouble(const std::string& value);
+double StringToDouble(const std::wstring& value);
// Return a C++ string given printf-like input.
std::string StringPrintf(const char* format, ...);
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
index 1aa4043..dcebddf 100644
--- a/base/string_util_unittest.cc
+++ b/base/string_util_unittest.cc
@@ -735,6 +735,8 @@ TEST(StringUtilTest, StringToInt64) {
{"99999999999", GG_INT64_C(99999999999), true},
{"9223372036854775807", kint64max, true},
{"-9223372036854775808", kint64min, true},
+ {"09", 9, true},
+ {"-09", -9, true},
{"", 0, false},
{" 42", 42, false},
{"\t\n\v\f\r 42", 42, false},
@@ -801,6 +803,8 @@ TEST(StringUtilTest, HexStringToInt) {
{"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},
{"efgh", 0xef, false},
@@ -836,6 +840,65 @@ TEST(StringUtilTest, HexStringToInt) {
EXPECT_EQ(0xc0ffee, output);
}
+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-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 (int i = 0; i < arraysize(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(wide_input));
+ EXPECT_EQ(cases[i].success, StringToDouble(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(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