Commit 0e289dc5 by Derek Mauro Committed by Copybara-Service

Add a version of absl::HexStringToBytes() that returns a bool

to validate that the input was actually valid hexadecimal data.

Mark the version of absl::HexStringToBytes() that does not validate
the input as deprecated.

Fixes #141

PiperOrigin-RevId: 604495678
Change-Id: Iac3020c33c9dbc6d8e31a43b746783fb345edaa7
parent ddcf8be9
...@@ -837,6 +837,24 @@ constexpr char kHexValueLenient[256] = { ...@@ -837,6 +837,24 @@ constexpr char kHexValueLenient[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}; };
constexpr signed char kHexValueStrict[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // '0'..'9'
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 'A'..'F'
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 'a'..'f'
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
/* clang-format on */ /* clang-format on */
// This is a templated function so that T can be either a char* // This is a templated function so that T can be either a char*
...@@ -931,6 +949,30 @@ std::string WebSafeBase64Escape(absl::string_view src) { ...@@ -931,6 +949,30 @@ std::string WebSafeBase64Escape(absl::string_view src) {
return dest; return dest;
} }
bool HexStringToBytes(absl::string_view hex,
absl::Nonnull<std::string*> bytes) {
size_t num_bytes = hex.size() / 2;
bytes->clear();
if (hex.size() != num_bytes * 2) {
return false;
}
absl::strings_internal::STLStringResizeUninitialized(bytes, num_bytes);
auto hex_p = hex.cbegin();
for (std::string::iterator bin_p = bytes->begin();
bin_p != bytes->end(); ++bin_p) {
int h1 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)];
int h2 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)];
if (h1 == -1 || h2 == -1) {
bytes->resize(static_cast<size_t>(bin_p - bytes->begin()));
return false;
}
*bin_p = static_cast<char>((h1 << 4) + h2);
}
return true;
}
std::string HexStringToBytes(absl::string_view from) { std::string HexStringToBytes(absl::string_view from) {
std::string result; std::string result;
const auto num = from.size() / 2; const auto num = from.size() / 2;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/base/attributes.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/base/nullability.h" #include "absl/base/nullability.h"
#include "absl/strings/ascii.h" #include "absl/strings/ascii.h"
...@@ -158,8 +159,19 @@ bool WebSafeBase64Unescape(absl::string_view src, ...@@ -158,8 +159,19 @@ bool WebSafeBase64Unescape(absl::string_view src,
// HexStringToBytes() // HexStringToBytes()
// //
// Converts the hexadecimal encoded data in `hex` into raw bytes in the `bytes`
// output string. If `hex` does not consist of valid hexadecimal data, this
// function returns false and leaves `bytes` in an unspecified state. Returns
// true on success.
ABSL_MUST_USE_RESULT bool HexStringToBytes(absl::string_view hex,
absl::Nonnull<std::string*> bytes);
// HexStringToBytes()
//
// Converts an ASCII hex string into bytes, returning binary data of length // Converts an ASCII hex string into bytes, returning binary data of length
// `from.size()/2`. // `from.size()/2`. The input must be valid hexadecimal data, otherwise the
// return value is unspecified.
ABSL_DEPRECATED("Use the HexStringToBytes() that returns a bool")
std::string HexStringToBytes(absl::string_view from); std::string HexStringToBytes(absl::string_view from);
// BytesToHexString() // BytesToHexString()
......
...@@ -689,6 +689,35 @@ TEST(Base64, DISABLED_HugeData) { ...@@ -689,6 +689,35 @@ TEST(Base64, DISABLED_HugeData) {
EXPECT_EQ(huge, unescaped); EXPECT_EQ(huge, unescaped);
} }
TEST(Escaping, HexStringToBytesBackToHex) {
std::string bytes, hex;
constexpr absl::string_view kTestHexLower = "1c2f0032f40123456789abcdef";
constexpr absl::string_view kTestHexUpper = "1C2F0032F40123456789ABCDEF";
constexpr absl::string_view kTestBytes = absl::string_view(
"\x1c\x2f\x00\x32\xf4\x01\x23\x45\x67\x89\xab\xcd\xef", 13);
EXPECT_TRUE(absl::HexStringToBytes(kTestHexLower, &bytes));
EXPECT_EQ(bytes, kTestBytes);
EXPECT_TRUE(absl::HexStringToBytes(kTestHexUpper, &bytes));
EXPECT_EQ(bytes, kTestBytes);
hex = absl::BytesToHexString(kTestBytes);
EXPECT_EQ(hex, kTestHexLower);
// Length not a multiple of two.
EXPECT_FALSE(absl::HexStringToBytes("1c2f003", &bytes));
// Not hex.
EXPECT_FALSE(absl::HexStringToBytes("1c2f00ft", &bytes));
// Empty input.
bytes = "abc";
EXPECT_TRUE(absl::HexStringToBytes("", &bytes));
EXPECT_EQ("", bytes); // Results in empty output.
}
TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) { TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) {
std::string hex_mixed = "0123456789abcdefABCDEF"; std::string hex_mixed = "0123456789abcdefABCDEF";
std::string bytes_expected = "\x01\x23\x45\x67\x89\xab\xcd\xef\xAB\xCD\xEF"; std::string bytes_expected = "\x01\x23\x45\x67\x89\xab\xcd\xef\xAB\xCD\xEF";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment