summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/string_util.cc38
-rw-r--r--base/string_util.h7
-rw-r--r--base/string_util_unittest.cc52
3 files changed, 97 insertions, 0 deletions
diff --git a/base/string_util.cc b/base/string_util.cc
index 5a06b64..036e61d 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -1409,6 +1409,44 @@ bool HexStringToInt(const std::wstring& input, int* output) {
input, reinterpret_cast<long*>(output));
}
+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);
+ int count = input.size();
+ if (count == 0 || (count % 2) != 0)
+ return false;
+ for (int 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;
+}
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+ return HexStringToBytesT(input, output);
+}
+
+bool HexStringToBytes(const std::wstring& input, std::vector<uint8>* output) {
+ return HexStringToBytesT(input, output);
+}
+
int StringToInt(const std::string& value) {
int result;
StringToInt(value, &result);
diff --git a/base/string_util.h b/base/string_util.h
index 68142cb..28c5d35 100644
--- a/base/string_util.h
+++ b/base/string_util.h
@@ -377,6 +377,13 @@ bool StringToInt64(const std::wstring& input, int64* output);
bool HexStringToInt(const std::string& input, int* output);
bool HexStringToInt(const std::wstring& 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);
+bool HexStringToBytes(const std::wstring& input, std::vector<uint8>* 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
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
index a3ca7ee..7676f81 100644
--- a/base/string_util_unittest.cc
+++ b/base/string_util_unittest.cc
@@ -945,6 +945,58 @@ TEST(StringUtilTest, HexStringToInt) {
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(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;