Adopt absl::string_view in rtc_base/string_encode.*

Bug: webrtc:13579
Change-Id: If52108d151a12bde0e8d552ce7940948c08cef3a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/256812
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Commit-Queue: Ali Tofigh <alito@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36424}
This commit is contained in:
Ali Tofigh 2022-03-31 10:36:48 +02:00 committed by WebRTC LUCI CQ
parent f2599a7f43
commit fd6a4d6e2a
17 changed files with 125 additions and 114 deletions

View file

@ -67,7 +67,11 @@ rtc_library("read_auth_file") {
"turnserver/read_auth_file.cc", "turnserver/read_auth_file.cc",
"turnserver/read_auth_file.h", "turnserver/read_auth_file.h",
] ]
deps = [ "../rtc_base" ] deps = [
"../api:array_view",
"../rtc_base",
]
absl_deps = [ "//third_party/abseil-cpp/absl/strings:strings" ]
} }
if (rtc_include_tests) { if (rtc_include_tests) {

View file

@ -12,6 +12,8 @@
#include <stddef.h> #include <stddef.h>
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "rtc_base/string_encode.h" #include "rtc_base/string_encode.h"
namespace webrtc_examples { namespace webrtc_examples {
@ -23,8 +25,8 @@ std::map<std::string, std::string> ReadAuthFile(std::istream* s) {
if (sep == std::string::npos) if (sep == std::string::npos)
continue; continue;
char buf[32]; char buf[32];
size_t len = rtc::hex_decode(buf, sizeof(buf), line.data() + sep + 1, size_t len = rtc::hex_decode(rtc::ArrayView<char>(buf),
line.size() - sep - 1); absl::string_view(line).substr(sep + 1));
if (len > 0) { if (len > 0) {
name_to_key.emplace(line.substr(0, sep), std::string(buf, len)); name_to_key.emplace(line.substr(0, sep), std::string(buf, len));
} }

View file

@ -1114,8 +1114,7 @@ class AcmSenderBitExactnessOldApi : public ::testing::Test,
// Extract and verify the payload checksum. // Extract and verify the payload checksum.
rtc::Buffer checksum_result(payload_checksum_->Size()); rtc::Buffer checksum_result(payload_checksum_->Size());
payload_checksum_->Finish(checksum_result.data(), checksum_result.size()); payload_checksum_->Finish(checksum_result.data(), checksum_result.size());
checksum_string = checksum_string = rtc::hex_encode(checksum_result);
rtc::hex_encode(checksum_result.data<char>(), checksum_result.size());
ExpectChecksumEq(payload_checksum_ref, checksum_string); ExpectChecksumEq(payload_checksum_ref, checksum_string);
// Verify number of packets produced. // Verify number of packets produced.

View file

@ -10,8 +10,9 @@
#include "modules/audio_coding/neteq/test/result_sink.h" #include "modules/audio_coding/neteq/test/result_sink.h"
#include <vector> #include <string>
#include "absl/strings/string_view.h"
#include "rtc_base/ignore_wundef.h" #include "rtc_base/ignore_wundef.h"
#include "rtc_base/message_digest.h" #include "rtc_base/message_digest.h"
#include "rtc_base/string_encode.h" #include "rtc_base/string_encode.h"
@ -91,10 +92,10 @@ void ResultSink::AddResult(const NetEqNetworkStatistics& stats_raw) {
} }
void ResultSink::VerifyChecksum(const std::string& checksum) { void ResultSink::VerifyChecksum(const std::string& checksum) {
std::vector<char> buffer; std::string buffer;
buffer.resize(digest_->Size()); buffer.resize(digest_->Size());
digest_->Finish(&buffer[0], buffer.size()); digest_->Finish(buffer.data(), buffer.size());
const std::string result = rtc::hex_encode(&buffer[0], digest_->Size()); const std::string result = rtc::hex_encode(buffer);
if (checksum.size() == result.size()) { if (checksum.size() == result.size()) {
EXPECT_EQ(checksum, result); EXPECT_EQ(checksum, result);
} else { } else {

View file

@ -50,8 +50,7 @@ class AudioChecksum : public AudioSink {
finished_ = true; finished_ = true;
checksum_->Finish(checksum_result_.data(), checksum_result_.size()); checksum_->Finish(checksum_result_.data(), checksum_result_.size());
} }
return rtc::hex_encode(checksum_result_.data<char>(), return rtc::hex_encode(checksum_result_);
checksum_result_.size());
} }
private: private:

View file

@ -284,6 +284,7 @@ rtc_library("p2p_server_utils") {
] ]
deps = [ deps = [
":rtc_p2p", ":rtc_p2p",
"../api:array_view",
"../api:packet_socket_factory", "../api:packet_socket_factory",
"../api:sequence_checker", "../api:sequence_checker",
"../api/transport:stun_types", "../api/transport:stun_types",

View file

@ -16,6 +16,7 @@
#include "absl/algorithm/container.h" #include "absl/algorithm/container.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "api/array_view.h"
#include "api/packet_socket_factory.h" #include "api/packet_socket_factory.h"
#include "api/transport/stun.h" #include "api/transport/stun.h"
#include "p2p/base/async_stun_tcp_socket.h" #include "p2p/base/async_stun_tcp_socket.h"
@ -421,7 +422,7 @@ void TurnServer::HandleAllocateRequest(TurnServerConnection* conn,
std::string TurnServer::GenerateNonce(int64_t now) const { std::string TurnServer::GenerateNonce(int64_t now) const {
// Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now)) // Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now))
std::string input(reinterpret_cast<const char*>(&now), sizeof(now)); std::string input(reinterpret_cast<const char*>(&now), sizeof(now));
std::string nonce = rtc::hex_encode(input.c_str(), input.size()); std::string nonce = rtc::hex_encode(input);
nonce += rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_, input); nonce += rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_, input);
RTC_DCHECK(nonce.size() == kNonceSize); RTC_DCHECK(nonce.size() == kNonceSize);
@ -437,8 +438,8 @@ bool TurnServer::ValidateNonce(const std::string& nonce) const {
// Decode the timestamp. // Decode the timestamp.
int64_t then; int64_t then;
char* p = reinterpret_cast<char*>(&then); char* p = reinterpret_cast<char*>(&then);
size_t len = size_t len = rtc::hex_decode(rtc::ArrayView<char>(p, sizeof(then)),
rtc::hex_decode(p, sizeof(then), nonce.substr(0, sizeof(then) * 2)); nonce.substr(0, sizeof(then) * 2));
if (len != sizeof(then)) { if (len != sizeof(then)) {
return false; return false;
} }

View file

@ -567,7 +567,10 @@ rtc_source_set("srtp_session") {
"../rtc_base/synchronization:mutex", "../rtc_base/synchronization:mutex",
"../system_wrappers:metrics", "../system_wrappers:metrics",
] ]
absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] absl_deps = [
"//third_party/abseil-cpp/absl/base:core_headers",
"//third_party/abseil-cpp/absl/strings:strings",
]
if (rtc_build_libsrtp) { if (rtc_build_libsrtp) {
deps += [ "//third_party/libsrtp" ] deps += [ "//third_party/libsrtp" ]
} }

View file

@ -17,6 +17,7 @@
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/const_init.h" #include "absl/base/const_init.h"
#include "absl/strings/string_view.h"
#include "api/array_view.h" #include "api/array_view.h"
#include "api/field_trials_view.h" #include "api/field_trials_view.h"
#include "modules/rtp_rtcp/source/rtp_util.h" #include "modules/rtp_rtcp/source/rtp_util.h"
@ -471,13 +472,16 @@ void SrtpSession::DumpPacket(const void* buf, int len, bool outbound) {
int64_t minutes = (time_of_day / (60 * 1000)) % 60; int64_t minutes = (time_of_day / (60 * 1000)) % 60;
int64_t seconds = (time_of_day / 1000) % 60; int64_t seconds = (time_of_day / 1000) % 60;
int64_t millis = time_of_day % 1000; int64_t millis = time_of_day % 1000;
RTC_LOG(LS_VERBOSE) << "\n" << (outbound ? "O" : "I") << " " RTC_LOG(LS_VERBOSE) << "\n"
<< std::setfill('0') << std::setw(2) << hours << ":" << (outbound ? "O" : "I") << " " << std::setfill('0')
<< std::setfill('0') << std::setw(2) << minutes << ":" << std::setw(2) << hours << ":" << std::setfill('0')
<< std::setfill('0') << std::setw(2) << seconds << "." << std::setw(2) << minutes << ":" << std::setfill('0')
<< std::setfill('0') << std::setw(3) << millis << " " << std::setw(2) << seconds << "." << std::setfill('0')
<< "000000 " << rtc::hex_encode_with_delimiter((const char *)buf, len, ' ') << std::setw(3) << millis << " "
<< " # RTP_DUMP"; << "000000 "
<< rtc::hex_encode_with_delimiter(
absl::string_view((const char*)buf, len), ' ')
<< " # RTP_DUMP";
} }
} // namespace cricket } // namespace cricket

View file

@ -19,6 +19,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "absl/strings/string_view.h"
#include "api/array_view.h" #include "api/array_view.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/type_traits.h" #include "rtc_base/type_traits.h"
@ -117,6 +118,13 @@ class BufferT {
~BufferT() { MaybeZeroCompleteBuffer(); } ~BufferT() { MaybeZeroCompleteBuffer(); }
// Implicit conversion to absl::string_view if T is compatible with char.
template <typename U = T>
operator typename std::enable_if<internal::BufferCompat<U, char>::value,
absl::string_view>::type() const {
return absl::string_view(data<char>(), size());
}
// Get a pointer to the data. Just .data() will give you a (const) T*, but if // Get a pointer to the data. Just .data() will give you a (const) T*, but if
// T is a byte-sized integer, you may also use .data<U>() for any other // T is a byte-sized integer, you may also use .data<U>() for any other
// byte-sized integer U. // byte-sized integer U.

View file

@ -13,6 +13,7 @@
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
#include "absl/strings/string_view.h"
#include "api/array_view.h" #include "api/array_view.h"
#include "test/gmock.h" #include "test/gmock.h"
#include "test/gtest.h" #include "test/gtest.h"
@ -73,6 +74,13 @@ TEST(BufferTest, TestConstructArray) {
EXPECT_EQ(0, memcmp(buf.data(), kTestData, 16)); EXPECT_EQ(0, memcmp(buf.data(), kTestData, 16));
} }
TEST(BufferTest, TestStringViewConversion) {
Buffer buf(kTestData);
absl::string_view view = buf;
EXPECT_EQ(view,
absl::string_view(reinterpret_cast<const char*>(kTestData), 16u));
}
TEST(BufferTest, TestSetData) { TEST(BufferTest, TestSetData) {
Buffer buf(kTestData + 4, 7); Buffer buf(kTestData + 4, 7);
buf.SetData(kTestData, 9); buf.SetData(kTestData, 9);

View file

@ -74,7 +74,7 @@ std::string ComputeDigest(MessageDigest* digest, absl::string_view input) {
std::unique_ptr<char[]> output(new char[digest->Size()]); std::unique_ptr<char[]> output(new char[digest->Size()]);
ComputeDigest(digest, input.data(), input.size(), output.get(), ComputeDigest(digest, input.data(), input.size(), output.get(),
digest->Size()); digest->Size());
return hex_encode(output.get(), digest->Size()); return hex_encode(absl::string_view(output.get(), digest->Size()));
} }
bool ComputeDigest(absl::string_view alg, bool ComputeDigest(absl::string_view alg,
@ -157,7 +157,7 @@ std::string ComputeHmac(MessageDigest* digest,
std::unique_ptr<char[]> output(new char[digest->Size()]); std::unique_ptr<char[]> output(new char[digest->Size()]);
ComputeHmac(digest, key.data(), key.size(), input.data(), input.size(), ComputeHmac(digest, key.data(), key.size(), input.data(), input.size(),
output.get(), digest->Size()); output.get(), digest->Size());
return hex_encode(output.get(), digest->Size()); return hex_encode(absl::string_view(output.get(), digest->Size()));
} }
bool ComputeHmac(absl::string_view alg, bool ComputeHmac(absl::string_view alg,

View file

@ -10,6 +10,7 @@
#include "rtc_base/message_digest.h" #include "rtc_base/message_digest.h"
#include "absl/strings/string_view.h"
#include "rtc_base/string_encode.h" #include "rtc_base/string_encode.h"
#include "test/gtest.h" #include "test/gtest.h"
@ -29,7 +30,7 @@ TEST(MessageDigestTest, TestMd5Digest) {
EXPECT_EQ(sizeof(output), EXPECT_EQ(sizeof(output),
ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output))); ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output)));
EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72", EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72",
hex_encode(output, sizeof(output))); hex_encode(absl::string_view(output, sizeof(output))));
EXPECT_EQ(0U, EXPECT_EQ(0U,
ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output) - 1)); ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output) - 1));
} }
@ -51,7 +52,7 @@ TEST(MessageDigestTest, TestSha1Digest) {
EXPECT_EQ(sizeof(output), EXPECT_EQ(sizeof(output),
ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output))); ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output)));
EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d",
hex_encode(output, sizeof(output))); hex_encode(absl::string_view(output, sizeof(output))));
EXPECT_EQ(0U, EXPECT_EQ(0U,
ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output) - 1)); ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output) - 1));
} }
@ -99,7 +100,7 @@ TEST(MessageDigestTest, TestMd5Hmac) {
ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(), ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(),
input.size(), output, sizeof(output))); input.size(), output, sizeof(output)));
EXPECT_EQ("9294727a3638bb1c13f48ef8158bfc9d", EXPECT_EQ("9294727a3638bb1c13f48ef8158bfc9d",
hex_encode(output, sizeof(output))); hex_encode(absl::string_view(output, sizeof(output))));
EXPECT_EQ(0U, ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(), EXPECT_EQ(0U, ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(),
input.size(), output, sizeof(output) - 1)); input.size(), output, sizeof(output) - 1));
} }
@ -140,7 +141,7 @@ TEST(MessageDigestTest, TestSha1Hmac) {
ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(), ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(),
input.size(), output, sizeof(output))); input.size(), output, sizeof(output)));
EXPECT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", EXPECT_EQ("b617318655057264e28bc0b6fb378c8ef146be00",
hex_encode(output, sizeof(output))); hex_encode(absl::string_view(output, sizeof(output))));
EXPECT_EQ(0U, EXPECT_EQ(0U,
ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(), ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(),
input.size(), output, sizeof(output) - 1)); input.size(), output, sizeof(output) - 1));

View file

@ -18,6 +18,7 @@
#include "absl/algorithm/container.h" #include "absl/algorithm/container.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/message_digest.h" #include "rtc_base/message_digest.h"
#include "rtc_base/rtc_certificate.h" #include "rtc_base/rtc_certificate.h"
@ -68,8 +69,8 @@ std::unique_ptr<SSLFingerprint> SSLFingerprint::CreateUniqueFromRfc4572(
return nullptr; return nullptr;
char value[rtc::MessageDigest::kMaxSize]; char value[rtc::MessageDigest::kMaxSize];
size_t value_len = rtc::hex_decode_with_delimiter( size_t value_len =
value, sizeof(value), fingerprint.data(), fingerprint.length(), ':'); rtc::hex_decode_with_delimiter(ArrayView<char>(value), fingerprint, ':');
if (!value_len) if (!value_len)
return nullptr; return nullptr;
@ -110,8 +111,8 @@ bool SSLFingerprint::operator==(const SSLFingerprint& other) const {
} }
std::string SSLFingerprint::GetRfc4572Fingerprint() const { std::string SSLFingerprint::GetRfc4572Fingerprint() const {
std::string fingerprint = std::string fingerprint = rtc::hex_encode_with_delimiter(
rtc::hex_encode_with_delimiter(digest.data<char>(), digest.size(), ':'); absl::string_view(digest.data<char>(), digest.size()), ':');
absl::c_transform(fingerprint, fingerprint.begin(), ::toupper); absl::c_transform(fingerprint, fingerprint.begin(), ::toupper);
return fingerprint; return fingerprint;
} }

View file

@ -13,6 +13,7 @@
#include <cstdio> #include <cstdio>
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "rtc_base/arraysize.h" #include "rtc_base/arraysize.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
@ -52,16 +53,16 @@ size_t hex_encode_output_length(size_t srclen, char delimiter) {
// hex_encode shows the hex representation of binary data in ascii, with // hex_encode shows the hex representation of binary data in ascii, with
// `delimiter` between bytes, or none if `delimiter` == 0. // `delimiter` between bytes, or none if `delimiter` == 0.
void hex_encode_with_delimiter(char* buffer, void hex_encode_with_delimiter(char* buffer,
const char* csource, absl::string_view source,
size_t srclen,
char delimiter) { char delimiter) {
RTC_DCHECK(buffer); RTC_DCHECK(buffer);
// Init and check bounds. // Init and check bounds.
const unsigned char* bsource = const unsigned char* bsource =
reinterpret_cast<const unsigned char*>(csource); reinterpret_cast<const unsigned char*>(source.data());
size_t srcpos = 0, bufpos = 0; size_t srcpos = 0, bufpos = 0;
size_t srclen = source.length();
while (srcpos < srclen) { while (srcpos < srclen) {
unsigned char ch = bsource[srcpos++]; unsigned char ch = bsource[srcpos++];
buffer[bufpos] = hex_encode((ch >> 4) & 0xF); buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
@ -79,42 +80,29 @@ void hex_encode_with_delimiter(char* buffer,
} // namespace } // namespace
std::string hex_encode(absl::string_view str) { std::string hex_encode(absl::string_view str) {
return hex_encode(str.data(), str.size()); return hex_encode_with_delimiter(str, 0);
} }
std::string hex_encode(const char* source, size_t srclen) { std::string hex_encode_with_delimiter(absl::string_view source,
return hex_encode_with_delimiter(source, srclen, 0);
}
std::string hex_encode_with_delimiter(const char* source,
size_t srclen,
char delimiter) { char delimiter) {
std::string s(hex_encode_output_length(srclen, delimiter), 0); std::string s(hex_encode_output_length(source.length(), delimiter), 0);
hex_encode_with_delimiter(&s[0], source, srclen, delimiter); hex_encode_with_delimiter(&s[0], source, delimiter);
return s; return s;
} }
size_t hex_decode(char* cbuffer, size_t hex_decode_with_delimiter(ArrayView<char> cbuffer,
size_t buflen, absl::string_view source,
const char* source,
size_t srclen) {
return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
}
size_t hex_decode_with_delimiter(char* cbuffer,
size_t buflen,
const char* source,
size_t srclen,
char delimiter) { char delimiter) {
RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size if (cbuffer.empty())
if (buflen == 0)
return 0; return 0;
// Init and bounds check. // Init and bounds check.
unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer); unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer.data());
size_t srcpos = 0, bufpos = 0; size_t srcpos = 0, bufpos = 0;
size_t srclen = source.length();
size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2; size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
if (buflen < needed) if (cbuffer.size() < needed)
return 0; return 0;
while (srcpos < srclen) { while (srcpos < srclen) {
@ -142,15 +130,16 @@ size_t hex_decode_with_delimiter(char* cbuffer,
return bufpos; return bufpos;
} }
size_t hex_decode(char* buffer, size_t buflen, absl::string_view source) {
return hex_decode_with_delimiter(buffer, buflen, source, 0);
}
size_t hex_decode_with_delimiter(char* buffer, size_t hex_decode_with_delimiter(char* buffer,
size_t buflen, size_t buflen,
absl::string_view source, absl::string_view source,
char delimiter) { char delimiter) {
return hex_decode_with_delimiter(buffer, buflen, source.data(), return hex_decode_with_delimiter(ArrayView<char>(buffer, buflen), source,
source.length(), delimiter); delimiter);
}
size_t hex_decode(ArrayView<char> buffer, absl::string_view source) {
return hex_decode_with_delimiter(buffer, source, 0);
} }
size_t tokenize(absl::string_view source, size_t tokenize(absl::string_view source,
@ -243,11 +232,11 @@ std::string ToString(const bool b) {
return b ? "true" : "false"; return b ? "true" : "false";
} }
std::string ToString(const char* const s) { std::string ToString(absl::string_view s) {
return std::string(s); return std::string(s);
} }
std::string ToString(absl::string_view s) { std::string ToString(const char* s) {
return std::string(s); return std::string(s);
} }
@ -321,7 +310,7 @@ std::string ToString(const void* const p) {
return std::string(&buf[0], len); return std::string(&buf[0], len);
} }
bool FromString(const std::string& s, bool* b) { bool FromString(absl::string_view s, bool* b) {
if (s == "false") { if (s == "false") {
*b = false; *b = false;
return true; return true;

View file

@ -19,6 +19,7 @@
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "api/array_view.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/string_to_number.h" #include "rtc_base/string_to_number.h"
@ -29,29 +30,18 @@ namespace rtc {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
std::string hex_encode(absl::string_view str); std::string hex_encode(absl::string_view str);
std::string hex_encode(const char* source, size_t srclen); std::string hex_encode_with_delimiter(absl::string_view source, char delimiter);
std::string hex_encode_with_delimiter(const char* source,
size_t srclen,
char delimiter);
// hex_decode converts ascii hex to binary. // hex_decode converts ascii hex to binary.
size_t hex_decode(char* buffer, size_t hex_decode(ArrayView<char> buffer, absl::string_view source);
size_t buflen,
const char* source,
size_t srclen);
// hex_decode, assuming that there is a delimiter between every byte // hex_decode, assuming that there is a delimiter between every byte
// pair. // pair.
// `delimiter` == 0 means no delimiter // `delimiter` == 0 means no delimiter
// If the buffer is too short or the data is invalid, we return 0. // If the buffer is too short or the data is invalid, we return 0.
size_t hex_decode_with_delimiter(char* buffer, size_t hex_decode_with_delimiter(ArrayView<char> buffer,
size_t buflen, absl::string_view source,
const char* source,
size_t srclen,
char delimiter); char delimiter);
// Helper functions for hex_decode.
size_t hex_decode(char* buffer, size_t buflen, absl::string_view source);
size_t hex_decode_with_delimiter(char* buffer, size_t hex_decode_with_delimiter(char* buffer,
size_t buflen, size_t buflen,
absl::string_view source, absl::string_view source,
@ -88,8 +78,10 @@ bool tokenize_first(absl::string_view source,
// TODO(jonasolsson): Remove these when absl::StrCat becomes available. // TODO(jonasolsson): Remove these when absl::StrCat becomes available.
std::string ToString(bool b); std::string ToString(bool b);
std::string ToString(const char* s);
std::string ToString(absl::string_view s); std::string ToString(absl::string_view s);
// The const char* overload is needed for correct overload resolution because of
// the const void* version of ToString() below.
std::string ToString(const char* s);
std::string ToString(short s); std::string ToString(short s);
std::string ToString(unsigned short s); std::string ToString(unsigned short s);
@ -109,7 +101,7 @@ template <typename T,
typename std::enable_if<std::is_arithmetic<T>::value && typename std::enable_if<std::is_arithmetic<T>::value &&
!std::is_same<T, bool>::value, !std::is_same<T, bool>::value,
int>::type = 0> int>::type = 0>
static bool FromString(const std::string& s, T* t) { static bool FromString(absl::string_view s, T* t) {
RTC_DCHECK(t); RTC_DCHECK(t);
absl::optional<T> result = StringToNumber<T>(s); absl::optional<T> result = StringToNumber<T>(s);
@ -119,10 +111,10 @@ static bool FromString(const std::string& s, T* t) {
return result.has_value(); return result.has_value();
} }
bool FromString(const std::string& s, bool* b); bool FromString(absl::string_view s, bool* b);
template <typename T> template <typename T>
static inline T FromString(const std::string& str) { static inline T FromString(absl::string_view str) {
T val; T val;
FromString(str, &val); FromString(str, &val);
return val; return val;

View file

@ -14,6 +14,7 @@
#include <sstream> // no-presubmit-check TODO(webrtc:8982) #include <sstream> // no-presubmit-check TODO(webrtc:8982)
#include "api/array_view.h"
#include "test/gtest.h" #include "test/gtest.h"
namespace rtc { namespace rtc {
@ -28,109 +29,106 @@ class HexEncodeTest : public ::testing::Test {
} }
char data_[10]; char data_[10];
absl::string_view data_view_{data_, sizeof(data_)};
char decoded_[11]; char decoded_[11];
size_t dec_res_; size_t dec_res_;
}; };
// Test that we can convert to/from hex with no delimiter. // Test that we can convert to/from hex with no delimiter.
TEST_F(HexEncodeTest, TestWithNoDelimiter) { TEST_F(HexEncodeTest, TestWithNoDelimiter) {
std::string encoded = hex_encode(data_, sizeof(data_)); std::string encoded = hex_encode(data_view_);
EXPECT_EQ("80818283848586878889", encoded); EXPECT_EQ("80818283848586878889", encoded);
dec_res_ = dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded);
hex_decode(decoded_, sizeof(decoded_), encoded.data(), encoded.size());
ASSERT_EQ(sizeof(data_), dec_res_); ASSERT_EQ(sizeof(data_), dec_res_);
ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_)); ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_));
} }
// Test that we can convert to/from hex with a colon delimiter. // Test that we can convert to/from hex with a colon delimiter.
TEST_F(HexEncodeTest, TestWithDelimiter) { TEST_F(HexEncodeTest, TestWithDelimiter) {
std::string encoded = hex_encode_with_delimiter(data_, sizeof(data_), ':'); std::string encoded = hex_encode_with_delimiter(data_view_, ':');
EXPECT_EQ("80:81:82:83:84:85:86:87:88:89", encoded); EXPECT_EQ("80:81:82:83:84:85:86:87:88:89", encoded);
dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':');
encoded.data(), encoded.size(), ':');
ASSERT_EQ(sizeof(data_), dec_res_); ASSERT_EQ(sizeof(data_), dec_res_);
ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_)); ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_));
} }
// Test that encoding with one delimiter and decoding with another fails. // Test that encoding with one delimiter and decoding with another fails.
TEST_F(HexEncodeTest, TestWithWrongDelimiter) { TEST_F(HexEncodeTest, TestWithWrongDelimiter) {
std::string encoded = hex_encode_with_delimiter(data_, sizeof(data_), ':'); std::string encoded = hex_encode_with_delimiter(data_view_, ':');
dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, '/');
encoded.data(), encoded.size(), '/');
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that encoding without a delimiter and decoding with one fails. // Test that encoding without a delimiter and decoding with one fails.
TEST_F(HexEncodeTest, TestExpectedDelimiter) { TEST_F(HexEncodeTest, TestExpectedDelimiter) {
std::string encoded = hex_encode(data_, sizeof(data_)); std::string encoded = hex_encode(data_view_);
EXPECT_EQ(sizeof(data_) * 2, encoded.size()); EXPECT_EQ(sizeof(data_) * 2, encoded.size());
dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':');
encoded.data(), encoded.size(), ':');
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that encoding with a delimiter and decoding without one fails. // Test that encoding with a delimiter and decoding without one fails.
TEST_F(HexEncodeTest, TestExpectedNoDelimiter) { TEST_F(HexEncodeTest, TestExpectedNoDelimiter) {
std::string encoded = hex_encode_with_delimiter(data_, sizeof(data_), ':'); std::string encoded = hex_encode_with_delimiter(data_view_, ':');
EXPECT_EQ(sizeof(data_) * 3 - 1, encoded.size()); EXPECT_EQ(sizeof(data_) * 3 - 1, encoded.size());
dec_res_ = dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded);
hex_decode(decoded_, sizeof(decoded_), encoded.data(), encoded.size());
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that we handle a zero-length buffer with no delimiter. // Test that we handle a zero-length buffer with no delimiter.
TEST_F(HexEncodeTest, TestZeroLengthNoDelimiter) { TEST_F(HexEncodeTest, TestZeroLengthNoDelimiter) {
std::string encoded = hex_encode("", 0); std::string encoded = hex_encode("");
EXPECT_TRUE(encoded.empty()); EXPECT_TRUE(encoded.empty());
dec_res_ = dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded);
hex_decode(decoded_, sizeof(decoded_), encoded.data(), encoded.size());
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that we handle a zero-length buffer with a delimiter. // Test that we handle a zero-length buffer with a delimiter.
TEST_F(HexEncodeTest, TestZeroLengthWithDelimiter) { TEST_F(HexEncodeTest, TestZeroLengthWithDelimiter) {
std::string encoded = hex_encode_with_delimiter("", 0, ':'); std::string encoded = hex_encode_with_delimiter("", ':');
EXPECT_TRUE(encoded.empty()); EXPECT_TRUE(encoded.empty());
dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':');
encoded.data(), encoded.size(), ':');
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that decoding into a too-small output buffer fails. // Test that decoding into a too-small output buffer fails.
TEST_F(HexEncodeTest, TestDecodeTooShort) { TEST_F(HexEncodeTest, TestDecodeTooShort) {
dec_res_ = hex_decode_with_delimiter(decoded_, 4, "0123456789", 10, 0); dec_res_ =
hex_decode_with_delimiter(ArrayView<char>(decoded_, 4), "0123456789", 0);
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
ASSERT_EQ(0x7f, decoded_[4]); ASSERT_EQ(0x7f, decoded_[4]);
} }
// Test that decoding non-hex data fails. // Test that decoding non-hex data fails.
TEST_F(HexEncodeTest, TestDecodeBogusData) { TEST_F(HexEncodeTest, TestDecodeBogusData) {
dec_res_ = dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), "axyz", 0);
hex_decode_with_delimiter(decoded_, sizeof(decoded_), "axyz", 4, 0);
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that decoding an odd number of hex characters fails. // Test that decoding an odd number of hex characters fails.
TEST_F(HexEncodeTest, TestDecodeOddHexDigits) { TEST_F(HexEncodeTest, TestDecodeOddHexDigits) {
dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), "012", 3, 0); dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), "012", 0);
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that decoding a string with too many delimiters fails. // Test that decoding a string with too many delimiters fails.
TEST_F(HexEncodeTest, TestDecodeWithDelimiterTooManyDelimiters) { TEST_F(HexEncodeTest, TestDecodeWithDelimiterTooManyDelimiters) {
dec_res_ = hex_decode_with_delimiter(decoded_, 4, "01::23::45::67", 14, ':'); dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4),
"01::23::45::67", ':');
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that decoding a string with a leading delimiter fails. // Test that decoding a string with a leading delimiter fails.
TEST_F(HexEncodeTest, TestDecodeWithDelimiterLeadingDelimiter) { TEST_F(HexEncodeTest, TestDecodeWithDelimiterLeadingDelimiter) {
dec_res_ = hex_decode_with_delimiter(decoded_, 4, ":01:23:45:67", 12, ':'); dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4),
":01:23:45:67", ':');
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }
// Test that decoding a string with a trailing delimiter fails. // Test that decoding a string with a trailing delimiter fails.
TEST_F(HexEncodeTest, TestDecodeWithDelimiterTrailingDelimiter) { TEST_F(HexEncodeTest, TestDecodeWithDelimiterTrailingDelimiter) {
dec_res_ = hex_decode_with_delimiter(decoded_, 4, "01:23:45:67:", 12, ':'); dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4),
"01:23:45:67:", ':');
ASSERT_EQ(0U, dec_res_); ASSERT_EQ(0U, dec_res_);
} }