summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/strings
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/strings
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/strings')
-rw-r--r--third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc54
-rw-r--r--third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h24
-rw-r--r--third_party/libwebrtc/rtc_base/strings/json.cc296
-rw-r--r--third_party/libwebrtc/rtc_base/strings/json.h83
-rw-r--r--third_party/libwebrtc/rtc_base/strings/json_unittest.cc283
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_builder.cc134
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_builder.h170
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc202
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_format.cc41
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_format.h31
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc52
11 files changed, 1370 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc
new file mode 100644
index 0000000000..7e91c3b49d
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/audio_format_to_string.h"
+
+#include <utility>
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace rtc {
+std::string ToString(const webrtc::SdpAudioFormat& saf) {
+ char sb_buf[1024];
+ rtc::SimpleStringBuilder sb(sb_buf);
+ sb << "{name: " << saf.name;
+ sb << ", clockrate_hz: " << saf.clockrate_hz;
+ sb << ", num_channels: " << saf.num_channels;
+ sb << ", parameters: {";
+ const char* sep = "";
+ for (const auto& kv : saf.parameters) {
+ sb << sep << kv.first << ": " << kv.second;
+ sep = ", ";
+ }
+ sb << "}}";
+ return sb.str();
+}
+std::string ToString(const webrtc::AudioCodecInfo& aci) {
+ char sb_buf[1024];
+ rtc::SimpleStringBuilder sb(sb_buf);
+ sb << "{sample_rate_hz: " << aci.sample_rate_hz;
+ sb << ", num_channels: " << aci.num_channels;
+ sb << ", default_bitrate_bps: " << aci.default_bitrate_bps;
+ sb << ", min_bitrate_bps: " << aci.min_bitrate_bps;
+ sb << ", max_bitrate_bps: " << aci.max_bitrate_bps;
+ sb << ", allow_comfort_noise: " << aci.allow_comfort_noise;
+ sb << ", supports_network_adaption: " << aci.supports_network_adaption;
+ sb << "}";
+ return sb.str();
+}
+std::string ToString(const webrtc::AudioCodecSpec& acs) {
+ char sb_buf[1024];
+ rtc::SimpleStringBuilder sb(sb_buf);
+ sb << "{format: " << ToString(acs.format);
+ sb << ", info: " << ToString(acs.info);
+ sb << "}";
+ return sb.str();
+}
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h
new file mode 100644
index 0000000000..6a4535c939
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_
+#define RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_
+
+#include <string>
+
+#include "api/audio_codecs/audio_format.h"
+
+namespace rtc {
+std::string ToString(const webrtc::SdpAudioFormat& saf);
+std::string ToString(const webrtc::AudioCodecInfo& saf);
+std::string ToString(const webrtc::AudioCodecSpec& acs);
+} // namespace rtc
+
+#endif // RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_
diff --git a/third_party/libwebrtc/rtc_base/strings/json.cc b/third_party/libwebrtc/rtc_base/strings/json.cc
new file mode 100644
index 0000000000..5cf153c926
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/json.cc
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/json.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/string_encode.h"
+
+namespace rtc {
+
+bool GetStringFromJson(const Json::Value& in, std::string* out) {
+ if (!in.isString()) {
+ if (in.isBool()) {
+ *out = rtc::ToString(in.asBool());
+ } else if (in.isInt()) {
+ *out = rtc::ToString(in.asInt());
+ } else if (in.isUInt()) {
+ *out = rtc::ToString(in.asUInt());
+ } else if (in.isDouble()) {
+ *out = rtc::ToString(in.asDouble());
+ } else {
+ return false;
+ }
+ } else {
+ *out = in.asString();
+ }
+ return true;
+}
+
+bool GetIntFromJson(const Json::Value& in, int* out) {
+ bool ret;
+ if (!in.isString()) {
+ ret = in.isConvertibleTo(Json::intValue);
+ if (ret) {
+ *out = in.asInt();
+ }
+ } else {
+ long val; // NOLINT
+ const char* c_str = in.asCString();
+ char* end_ptr;
+ errno = 0;
+ val = strtol(c_str, &end_ptr, 10); // NOLINT
+ ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val >= INT_MIN &&
+ val <= INT_MAX);
+ *out = val;
+ }
+ return ret;
+}
+
+bool GetUIntFromJson(const Json::Value& in, unsigned int* out) {
+ bool ret;
+ if (!in.isString()) {
+ ret = in.isConvertibleTo(Json::uintValue);
+ if (ret) {
+ *out = in.asUInt();
+ }
+ } else {
+ unsigned long val; // NOLINT
+ const char* c_str = in.asCString();
+ char* end_ptr;
+ errno = 0;
+ val = strtoul(c_str, &end_ptr, 10); // NOLINT
+ ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val <= UINT_MAX);
+ *out = val;
+ }
+ return ret;
+}
+
+bool GetBoolFromJson(const Json::Value& in, bool* out) {
+ bool ret;
+ if (!in.isString()) {
+ ret = in.isConvertibleTo(Json::booleanValue);
+ if (ret) {
+ *out = in.asBool();
+ }
+ } else {
+ if (in.asString() == "true") {
+ *out = true;
+ ret = true;
+ } else if (in.asString() == "false") {
+ *out = false;
+ ret = true;
+ } else {
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+bool GetDoubleFromJson(const Json::Value& in, double* out) {
+ bool ret;
+ if (!in.isString()) {
+ ret = in.isConvertibleTo(Json::realValue);
+ if (ret) {
+ *out = in.asDouble();
+ }
+ } else {
+ double val;
+ const char* c_str = in.asCString();
+ char* end_ptr;
+ errno = 0;
+ val = strtod(c_str, &end_ptr);
+ ret = (end_ptr != c_str && *end_ptr == '\0' && !errno);
+ *out = val;
+ }
+ return ret;
+}
+
+namespace {
+template <typename T>
+bool JsonArrayToVector(const Json::Value& value,
+ bool (*getter)(const Json::Value& in, T* out),
+ std::vector<T>* vec) {
+ vec->clear();
+ if (!value.isArray()) {
+ return false;
+ }
+
+ for (Json::Value::ArrayIndex i = 0; i < value.size(); ++i) {
+ T val;
+ if (!getter(value[i], &val)) {
+ return false;
+ }
+ vec->push_back(val);
+ }
+
+ return true;
+}
+// Trivial getter helper
+bool GetValueFromJson(const Json::Value& in, Json::Value* out) {
+ *out = in;
+ return true;
+}
+} // unnamed namespace
+
+bool JsonArrayToValueVector(const Json::Value& in,
+ std::vector<Json::Value>* out) {
+ return JsonArrayToVector(in, GetValueFromJson, out);
+}
+
+bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out) {
+ return JsonArrayToVector(in, GetIntFromJson, out);
+}
+
+bool JsonArrayToUIntVector(const Json::Value& in,
+ std::vector<unsigned int>* out) {
+ return JsonArrayToVector(in, GetUIntFromJson, out);
+}
+
+bool JsonArrayToStringVector(const Json::Value& in,
+ std::vector<std::string>* out) {
+ return JsonArrayToVector(in, GetStringFromJson, out);
+}
+
+bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out) {
+ return JsonArrayToVector(in, GetBoolFromJson, out);
+}
+
+bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out) {
+ return JsonArrayToVector(in, GetDoubleFromJson, out);
+}
+
+namespace {
+template <typename T>
+Json::Value VectorToJsonArray(const std::vector<T>& vec) {
+ Json::Value result(Json::arrayValue);
+ for (size_t i = 0; i < vec.size(); ++i) {
+ result.append(Json::Value(vec[i]));
+ }
+ return result;
+}
+} // unnamed namespace
+
+Json::Value ValueVectorToJsonArray(const std::vector<Json::Value>& in) {
+ return VectorToJsonArray(in);
+}
+
+Json::Value IntVectorToJsonArray(const std::vector<int>& in) {
+ return VectorToJsonArray(in);
+}
+
+Json::Value UIntVectorToJsonArray(const std::vector<unsigned int>& in) {
+ return VectorToJsonArray(in);
+}
+
+Json::Value StringVectorToJsonArray(const std::vector<std::string>& in) {
+ return VectorToJsonArray(in);
+}
+
+Json::Value BoolVectorToJsonArray(const std::vector<bool>& in) {
+ return VectorToJsonArray(in);
+}
+
+Json::Value DoubleVectorToJsonArray(const std::vector<double>& in) {
+ return VectorToJsonArray(in);
+}
+
+bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out) {
+ if (!in.isArray() || !in.isValidIndex(static_cast<int>(n))) {
+ return false;
+ }
+
+ *out = in[static_cast<Json::Value::ArrayIndex>(n)];
+ return true;
+}
+
+bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out) {
+ Json::Value x;
+ return GetValueFromJsonArray(in, n, &x) && GetIntFromJson(x, out);
+}
+
+bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out) {
+ Json::Value x;
+ return GetValueFromJsonArray(in, n, &x) && GetUIntFromJson(x, out);
+}
+
+bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out) {
+ Json::Value x;
+ return GetValueFromJsonArray(in, n, &x) && GetStringFromJson(x, out);
+}
+
+bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out) {
+ Json::Value x;
+ return GetValueFromJsonArray(in, n, &x) && GetBoolFromJson(x, out);
+}
+
+bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out) {
+ Json::Value x;
+ return GetValueFromJsonArray(in, n, &x) && GetDoubleFromJson(x, out);
+}
+
+bool GetValueFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ Json::Value* out) {
+ std::string k_str(k);
+ if (!in.isObject() || !in.isMember(k_str)) {
+ return false;
+ }
+
+ *out = in[k_str];
+ return true;
+}
+
+bool GetIntFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ int* out) {
+ Json::Value x;
+ return GetValueFromJsonObject(in, k, &x) && GetIntFromJson(x, out);
+}
+
+bool GetUIntFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ unsigned int* out) {
+ Json::Value x;
+ return GetValueFromJsonObject(in, k, &x) && GetUIntFromJson(x, out);
+}
+
+bool GetStringFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ std::string* out) {
+ Json::Value x;
+ return GetValueFromJsonObject(in, k, &x) && GetStringFromJson(x, out);
+}
+
+bool GetBoolFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ bool* out) {
+ Json::Value x;
+ return GetValueFromJsonObject(in, k, &x) && GetBoolFromJson(x, out);
+}
+
+bool GetDoubleFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ double* out) {
+ Json::Value x;
+ return GetValueFromJsonObject(in, k, &x) && GetDoubleFromJson(x, out);
+}
+
+std::string JsonValueToString(const Json::Value& json) {
+ Json::StreamWriterBuilder builder;
+ std::string output = Json::writeString(builder, json);
+ return output.substr(0, output.size() - 1); // trim trailing newline
+}
+
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/strings/json.h b/third_party/libwebrtc/rtc_base/strings/json.h
new file mode 100644
index 0000000000..3e4bac6d89
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/json.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_STRINGS_JSON_H_
+#define RTC_BASE_STRINGS_JSON_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "json/json.h"
+
+namespace rtc {
+
+///////////////////////////////////////////////////////////////////////////////
+// JSON Helpers
+///////////////////////////////////////////////////////////////////////////////
+
+// Robust conversion operators, better than the ones in JsonCpp.
+bool GetIntFromJson(const Json::Value& in, int* out);
+bool GetUIntFromJson(const Json::Value& in, unsigned int* out);
+bool GetStringFromJson(const Json::Value& in, std::string* out);
+bool GetBoolFromJson(const Json::Value& in, bool* out);
+bool GetDoubleFromJson(const Json::Value& in, double* out);
+
+// Pull values out of a JSON array.
+bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out);
+bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out);
+bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out);
+bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out);
+bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out);
+bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out);
+
+// Convert json arrays to std::vector
+bool JsonArrayToValueVector(const Json::Value& in,
+ std::vector<Json::Value>* out);
+bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out);
+bool JsonArrayToUIntVector(const Json::Value& in,
+ std::vector<unsigned int>* out);
+bool JsonArrayToStringVector(const Json::Value& in,
+ std::vector<std::string>* out);
+bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out);
+bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out);
+
+// Convert std::vector to json array
+Json::Value ValueVectorToJsonArray(const std::vector<Json::Value>& in);
+Json::Value IntVectorToJsonArray(const std::vector<int>& in);
+Json::Value UIntVectorToJsonArray(const std::vector<unsigned int>& in);
+Json::Value StringVectorToJsonArray(const std::vector<std::string>& in);
+Json::Value BoolVectorToJsonArray(const std::vector<bool>& in);
+Json::Value DoubleVectorToJsonArray(const std::vector<double>& in);
+
+// Pull values out of a JSON object.
+bool GetValueFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ Json::Value* out);
+bool GetIntFromJsonObject(const Json::Value& in, absl::string_view k, int* out);
+bool GetUIntFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ unsigned int* out);
+bool GetStringFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ std::string* out);
+bool GetBoolFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ bool* out);
+bool GetDoubleFromJsonObject(const Json::Value& in,
+ absl::string_view k,
+ double* out);
+
+// Writes out a Json value as a string.
+std::string JsonValueToString(const Json::Value& json);
+
+} // namespace rtc
+
+#endif // RTC_BASE_STRINGS_JSON_H_
diff --git a/third_party/libwebrtc/rtc_base/strings/json_unittest.cc b/third_party/libwebrtc/rtc_base/strings/json_unittest.cc
new file mode 100644
index 0000000000..82d26f179e
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/json_unittest.cc
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2009 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/json.h"
+
+#include <vector>
+
+#include "test/gtest.h"
+
+namespace rtc {
+
+static Json::Value in_s("foo");
+static Json::Value in_sn("99");
+static Json::Value in_si("-99");
+static Json::Value in_sb("true");
+static Json::Value in_sd("1.2");
+static Json::Value in_n(12);
+static Json::Value in_i(-12);
+static Json::Value in_u(34U);
+static Json::Value in_b(true);
+static Json::Value in_d(1.2);
+static Json::Value big_sn("12345678901234567890");
+static Json::Value big_si("-12345678901234567890");
+static Json::Value big_u(0xFFFFFFFF);
+static Json::Value bad_a(Json::arrayValue);
+static Json::Value bad_o(Json::objectValue);
+
+TEST(JsonTest, GetString) {
+ std::string out;
+ EXPECT_TRUE(GetStringFromJson(in_s, &out));
+ EXPECT_EQ("foo", out);
+ EXPECT_TRUE(GetStringFromJson(in_sn, &out));
+ EXPECT_EQ("99", out);
+ EXPECT_TRUE(GetStringFromJson(in_si, &out));
+ EXPECT_EQ("-99", out);
+ EXPECT_TRUE(GetStringFromJson(in_i, &out));
+ EXPECT_EQ("-12", out);
+ EXPECT_TRUE(GetStringFromJson(in_n, &out));
+ EXPECT_EQ("12", out);
+ EXPECT_TRUE(GetStringFromJson(in_u, &out));
+ EXPECT_EQ("34", out);
+ EXPECT_TRUE(GetStringFromJson(in_b, &out));
+ EXPECT_EQ("true", out);
+ // Not supported here yet.
+ EXPECT_FALSE(GetStringFromJson(bad_a, &out));
+ EXPECT_FALSE(GetStringFromJson(bad_o, &out));
+}
+
+TEST(JsonTest, GetInt) {
+ int out;
+ EXPECT_TRUE(GetIntFromJson(in_sn, &out));
+ EXPECT_EQ(99, out);
+ EXPECT_TRUE(GetIntFromJson(in_si, &out));
+ EXPECT_EQ(-99, out);
+ EXPECT_TRUE(GetIntFromJson(in_n, &out));
+ EXPECT_EQ(12, out);
+ EXPECT_TRUE(GetIntFromJson(in_i, &out));
+ EXPECT_EQ(-12, out);
+ EXPECT_TRUE(GetIntFromJson(in_u, &out));
+ EXPECT_EQ(34, out);
+ EXPECT_TRUE(GetIntFromJson(in_b, &out));
+ EXPECT_EQ(1, out);
+ EXPECT_FALSE(GetIntFromJson(in_s, &out));
+ EXPECT_FALSE(GetIntFromJson(big_sn, &out));
+ EXPECT_FALSE(GetIntFromJson(big_si, &out));
+ EXPECT_FALSE(GetIntFromJson(big_u, &out));
+ EXPECT_FALSE(GetIntFromJson(bad_a, &out));
+ EXPECT_FALSE(GetIntFromJson(bad_o, &out));
+}
+
+TEST(JsonTest, GetUInt) {
+ unsigned int out;
+ EXPECT_TRUE(GetUIntFromJson(in_sn, &out));
+ EXPECT_EQ(99U, out);
+ EXPECT_TRUE(GetUIntFromJson(in_n, &out));
+ EXPECT_EQ(12U, out);
+ EXPECT_TRUE(GetUIntFromJson(in_u, &out));
+ EXPECT_EQ(34U, out);
+ EXPECT_TRUE(GetUIntFromJson(in_b, &out));
+ EXPECT_EQ(1U, out);
+ EXPECT_TRUE(GetUIntFromJson(big_u, &out));
+ EXPECT_EQ(0xFFFFFFFFU, out);
+ EXPECT_FALSE(GetUIntFromJson(in_s, &out));
+ // TODO(bugs.webrtc.org/9804): Fail reading negative strings.
+ // EXPECT_FALSE(GetUIntFromJson(in_si, &out));
+ EXPECT_FALSE(GetUIntFromJson(in_i, &out));
+ EXPECT_FALSE(GetUIntFromJson(big_sn, &out));
+ EXPECT_FALSE(GetUIntFromJson(big_si, &out));
+ EXPECT_FALSE(GetUIntFromJson(bad_a, &out));
+ EXPECT_FALSE(GetUIntFromJson(bad_o, &out));
+}
+
+TEST(JsonTest, GetBool) {
+ bool out;
+ EXPECT_TRUE(GetBoolFromJson(in_sb, &out));
+ EXPECT_EQ(true, out);
+ EXPECT_TRUE(GetBoolFromJson(in_n, &out));
+ EXPECT_EQ(true, out);
+ EXPECT_TRUE(GetBoolFromJson(in_i, &out));
+ EXPECT_EQ(true, out);
+ EXPECT_TRUE(GetBoolFromJson(in_u, &out));
+ EXPECT_EQ(true, out);
+ EXPECT_TRUE(GetBoolFromJson(in_b, &out));
+ EXPECT_EQ(true, out);
+ EXPECT_TRUE(GetBoolFromJson(big_u, &out));
+ EXPECT_EQ(true, out);
+ EXPECT_FALSE(GetBoolFromJson(in_s, &out));
+ EXPECT_FALSE(GetBoolFromJson(in_sn, &out));
+ EXPECT_FALSE(GetBoolFromJson(in_si, &out));
+ EXPECT_FALSE(GetBoolFromJson(big_sn, &out));
+ EXPECT_FALSE(GetBoolFromJson(big_si, &out));
+ EXPECT_FALSE(GetBoolFromJson(bad_a, &out));
+ EXPECT_FALSE(GetBoolFromJson(bad_o, &out));
+}
+
+TEST(JsonTest, GetDouble) {
+ double out;
+ EXPECT_TRUE(GetDoubleFromJson(in_sn, &out));
+ EXPECT_EQ(99, out);
+ EXPECT_TRUE(GetDoubleFromJson(in_si, &out));
+ EXPECT_EQ(-99, out);
+ EXPECT_TRUE(GetDoubleFromJson(in_sd, &out));
+ EXPECT_EQ(1.2, out);
+ EXPECT_TRUE(GetDoubleFromJson(in_n, &out));
+ EXPECT_EQ(12, out);
+ EXPECT_TRUE(GetDoubleFromJson(in_i, &out));
+ EXPECT_EQ(-12, out);
+ EXPECT_TRUE(GetDoubleFromJson(in_u, &out));
+ EXPECT_EQ(34, out);
+ EXPECT_TRUE(GetDoubleFromJson(in_b, &out));
+ EXPECT_EQ(1, out);
+ EXPECT_TRUE(GetDoubleFromJson(in_d, &out));
+ EXPECT_EQ(1.2, out);
+ EXPECT_FALSE(GetDoubleFromJson(in_s, &out));
+}
+
+TEST(JsonTest, GetFromArray) {
+ Json::Value a, out;
+ a.append(in_s);
+ a.append(in_i);
+ a.append(in_u);
+ a.append(in_b);
+ EXPECT_TRUE(GetValueFromJsonArray(a, 0, &out));
+ EXPECT_TRUE(GetValueFromJsonArray(a, 3, &out));
+ EXPECT_FALSE(GetValueFromJsonArray(a, 99, &out));
+ EXPECT_FALSE(GetValueFromJsonArray(a, 0xFFFFFFFF, &out));
+}
+
+TEST(JsonTest, GetFromObject) {
+ Json::Value o, out;
+ o["string"] = in_s;
+ o["int"] = in_i;
+ o["uint"] = in_u;
+ o["bool"] = in_b;
+ EXPECT_TRUE(GetValueFromJsonObject(o, "int", &out));
+ EXPECT_TRUE(GetValueFromJsonObject(o, "bool", &out));
+ EXPECT_FALSE(GetValueFromJsonObject(o, "foo", &out));
+ EXPECT_FALSE(GetValueFromJsonObject(o, "", &out));
+}
+
+namespace {
+template <typename T>
+std::vector<T> VecOf3(const T& a, const T& b, const T& c) {
+ std::vector<T> in;
+ in.push_back(a);
+ in.push_back(b);
+ in.push_back(c);
+ return in;
+}
+template <typename T>
+Json::Value JsonVecOf3(const T& a, const T& b, const T& c) {
+ Json::Value in(Json::arrayValue);
+ in.append(a);
+ in.append(b);
+ in.append(c);
+ return in;
+}
+} // unnamed namespace
+
+TEST(JsonTest, ValueVectorToFromArray) {
+ std::vector<Json::Value> in = VecOf3<Json::Value>("a", "b", "c");
+ Json::Value out = ValueVectorToJsonArray(in);
+ EXPECT_EQ(in.size(), out.size());
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) {
+ EXPECT_EQ(in[i].asString(), out[i].asString());
+ }
+ Json::Value inj = JsonVecOf3<Json::Value>("a", "b", "c");
+ EXPECT_EQ(inj, out);
+ std::vector<Json::Value> outj;
+ EXPECT_TRUE(JsonArrayToValueVector(inj, &outj));
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) {
+ EXPECT_EQ(in[i], outj[i]);
+ }
+}
+
+TEST(JsonTest, IntVectorToFromArray) {
+ std::vector<int> in = VecOf3<int>(1, 2, 3);
+ Json::Value out = IntVectorToJsonArray(in);
+ EXPECT_EQ(in.size(), out.size());
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) {
+ EXPECT_EQ(in[i], out[i].asInt());
+ }
+ Json::Value inj = JsonVecOf3<int>(1, 2, 3);
+ EXPECT_EQ(inj, out);
+ std::vector<int> outj;
+ EXPECT_TRUE(JsonArrayToIntVector(inj, &outj));
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) {
+ EXPECT_EQ(in[i], outj[i]);
+ }
+}
+
+TEST(JsonTest, UIntVectorToFromArray) {
+ std::vector<unsigned int> in = VecOf3<unsigned int>(1, 2, 3);
+ Json::Value out = UIntVectorToJsonArray(in);
+ EXPECT_EQ(in.size(), out.size());
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) {
+ EXPECT_EQ(in[i], out[i].asUInt());
+ }
+ Json::Value inj = JsonVecOf3<unsigned int>(1, 2, 3);
+ EXPECT_EQ(inj, out);
+ std::vector<unsigned int> outj;
+ EXPECT_TRUE(JsonArrayToUIntVector(inj, &outj));
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) {
+ EXPECT_EQ(in[i], outj[i]);
+ }
+}
+
+TEST(JsonTest, StringVectorToFromArray) {
+ std::vector<std::string> in = VecOf3<std::string>("a", "b", "c");
+ Json::Value out = StringVectorToJsonArray(in);
+ EXPECT_EQ(in.size(), out.size());
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) {
+ EXPECT_EQ(in[i], out[i].asString());
+ }
+ Json::Value inj = JsonVecOf3<std::string>("a", "b", "c");
+ EXPECT_EQ(inj, out);
+ std::vector<std::string> outj;
+ EXPECT_TRUE(JsonArrayToStringVector(inj, &outj));
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) {
+ EXPECT_EQ(in[i], outj[i]);
+ }
+}
+
+TEST(JsonTest, BoolVectorToFromArray) {
+ std::vector<bool> in = VecOf3<bool>(false, true, false);
+ Json::Value out = BoolVectorToJsonArray(in);
+ EXPECT_EQ(in.size(), out.size());
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) {
+ EXPECT_EQ(in[i], out[i].asBool());
+ }
+ Json::Value inj = JsonVecOf3<bool>(false, true, false);
+ EXPECT_EQ(inj, out);
+ std::vector<bool> outj;
+ EXPECT_TRUE(JsonArrayToBoolVector(inj, &outj));
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) {
+ EXPECT_EQ(in[i], outj[i]);
+ }
+}
+
+TEST(JsonTest, DoubleVectorToFromArray) {
+ std::vector<double> in = VecOf3<double>(1.0, 2.0, 3.0);
+ Json::Value out = DoubleVectorToJsonArray(in);
+ EXPECT_EQ(in.size(), out.size());
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) {
+ EXPECT_EQ(in[i], out[i].asDouble());
+ }
+ Json::Value inj = JsonVecOf3<double>(1.0, 2.0, 3.0);
+ EXPECT_EQ(inj, out);
+ std::vector<double> outj;
+ EXPECT_TRUE(JsonArrayToDoubleVector(inj, &outj));
+ for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) {
+ EXPECT_EQ(in[i], outj[i]);
+ }
+}
+
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder.cc b/third_party/libwebrtc/rtc_base/strings/string_builder.cc
new file mode 100644
index 0000000000..a419b0b3cc
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/string_builder.cc
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/string_builder.h"
+
+#include <stdarg.h>
+
+#include <cstdio>
+#include <cstring>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace rtc {
+
+SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView<char> buffer)
+ : buffer_(buffer) {
+ buffer_[0] = '\0';
+ RTC_DCHECK(IsConsistent());
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) {
+ return operator<<(absl::string_view(&ch, 1));
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(absl::string_view str) {
+ RTC_DCHECK_LT(size_ + str.length(), buffer_.size())
+ << "Buffer size was insufficient";
+ const size_t chars_added =
+ rtc::SafeMin(str.length(), buffer_.size() - size_ - 1);
+ memcpy(&buffer_[size_], str.data(), chars_added);
+ size_ += chars_added;
+ buffer_[size_] = '\0';
+ RTC_DCHECK(IsConsistent());
+ return *this;
+}
+
+// Numeric conversion routines.
+//
+// We use std::[v]snprintf instead of std::to_string because:
+// * std::to_string relies on the current locale for formatting purposes,
+// and therefore concurrent calls to std::to_string from multiple threads
+// may result in partial serialization of calls
+// * snprintf allows us to print the number directly into our buffer.
+// * avoid allocating a std::string (potential heap alloc).
+// TODO(tommi): Switch to std::to_chars in C++17.
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(int i) {
+ return AppendFormat("%d", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(unsigned i) {
+ return AppendFormat("%u", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(long i) { // NOLINT
+ return AppendFormat("%ld", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(long long i) { // NOLINT
+ return AppendFormat("%lld", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(
+ unsigned long i) { // NOLINT
+ return AppendFormat("%lu", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(
+ unsigned long long i) { // NOLINT
+ return AppendFormat("%llu", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(float f) {
+ return AppendFormat("%g", f);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(double f) {
+ return AppendFormat("%g", f);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(long double f) {
+ return AppendFormat("%Lg", f);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ const int len =
+ std::vsnprintf(&buffer_[size_], buffer_.size() - size_, fmt, args);
+ if (len >= 0) {
+ const size_t chars_added = rtc::SafeMin(len, buffer_.size() - 1 - size_);
+ size_ += chars_added;
+ RTC_DCHECK_EQ(len, chars_added) << "Buffer size was insufficient";
+ } else {
+ // This should never happen, but we're paranoid, so re-write the
+ // terminator in case vsnprintf() overwrote it.
+ RTC_DCHECK_NOTREACHED();
+ buffer_[size_] = '\0';
+ }
+ va_end(args);
+ RTC_DCHECK(IsConsistent());
+ return *this;
+}
+
+StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) {
+ va_list args, copy;
+ va_start(args, fmt);
+ va_copy(copy, args);
+ const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
+ va_end(copy);
+
+ RTC_DCHECK_GE(predicted_length, 0);
+ if (predicted_length > 0) {
+ const size_t size = str_.size();
+ str_.resize(size + predicted_length);
+ // Pass "+ 1" to vsnprintf to include space for the '\0'.
+ const int actual_length =
+ std::vsnprintf(&str_[size], predicted_length + 1, fmt, args);
+ RTC_DCHECK_GE(actual_length, 0);
+ }
+ va_end(args);
+ return *this;
+}
+
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder.h b/third_party/libwebrtc/rtc_base/strings/string_builder.h
new file mode 100644
index 0000000000..00986371d3
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/string_builder.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_STRINGS_STRING_BUILDER_H_
+#define RTC_BASE_STRINGS_STRING_BUILDER_H_
+
+#include <cstdio>
+#include <string>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "rtc_base/string_encode.h"
+
+namespace rtc {
+
+// This is a minimalistic string builder class meant to cover the most cases of
+// when you might otherwise be tempted to use a stringstream (discouraged for
+// anything except logging). It uses a fixed-size buffer provided by the caller
+// and concatenates strings and numbers into it, allowing the results to be
+// read via `str()`.
+class SimpleStringBuilder {
+ public:
+ explicit SimpleStringBuilder(rtc::ArrayView<char> buffer);
+ SimpleStringBuilder(const SimpleStringBuilder&) = delete;
+ SimpleStringBuilder& operator=(const SimpleStringBuilder&) = delete;
+
+ SimpleStringBuilder& operator<<(char ch);
+ SimpleStringBuilder& operator<<(absl::string_view str);
+ SimpleStringBuilder& operator<<(int i);
+ SimpleStringBuilder& operator<<(unsigned i);
+ SimpleStringBuilder& operator<<(long i); // NOLINT
+ SimpleStringBuilder& operator<<(long long i); // NOLINT
+ SimpleStringBuilder& operator<<(unsigned long i); // NOLINT
+ SimpleStringBuilder& operator<<(unsigned long long i); // NOLINT
+ SimpleStringBuilder& operator<<(float f);
+ SimpleStringBuilder& operator<<(double f);
+ SimpleStringBuilder& operator<<(long double f);
+
+ // Returns a pointer to the built string. The name `str()` is borrowed for
+ // compatibility reasons as we replace usage of stringstream throughout the
+ // code base.
+ const char* str() const { return buffer_.data(); }
+
+ // Returns the length of the string. The name `size()` is picked for STL
+ // compatibility reasons.
+ size_t size() const { return size_; }
+
+// Allows appending a printf style formatted string.
+#if defined(__GNUC__)
+ __attribute__((__format__(__printf__, 2, 3)))
+#endif
+ SimpleStringBuilder&
+ AppendFormat(const char* fmt, ...);
+
+ private:
+ bool IsConsistent() const {
+ return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0';
+ }
+
+ // An always-zero-terminated fixed-size buffer that we write to. The fixed
+ // size allows the buffer to be stack allocated, which helps performance.
+ // Having a fixed size is furthermore useful to avoid unnecessary resizing
+ // while building it.
+ const rtc::ArrayView<char> buffer_;
+
+ // Represents the number of characters written to the buffer.
+ // This does not include the terminating '\0'.
+ size_t size_ = 0;
+};
+
+// A string builder that supports dynamic resizing while building a string.
+// The class is based around an instance of std::string and allows moving
+// ownership out of the class once the string has been built.
+// Note that this class uses the heap for allocations, so SimpleStringBuilder
+// might be more efficient for some use cases.
+class StringBuilder {
+ public:
+ StringBuilder() {}
+ explicit StringBuilder(absl::string_view s) : str_(s) {}
+
+ // TODO(tommi): Support construction from StringBuilder?
+ StringBuilder(const StringBuilder&) = delete;
+ StringBuilder& operator=(const StringBuilder&) = delete;
+
+ StringBuilder& operator<<(const absl::string_view str) {
+ str_.append(str.data(), str.length());
+ return *this;
+ }
+
+ StringBuilder& operator<<(char c) = delete;
+
+ StringBuilder& operator<<(int i) {
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(unsigned i) {
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(long long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(unsigned long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(unsigned long long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(float f) {
+ str_ += rtc::ToString(f);
+ return *this;
+ }
+
+ StringBuilder& operator<<(double f) {
+ str_ += rtc::ToString(f);
+ return *this;
+ }
+
+ StringBuilder& operator<<(long double f) {
+ str_ += rtc::ToString(f);
+ return *this;
+ }
+
+ const std::string& str() const { return str_; }
+
+ void Clear() { str_.clear(); }
+
+ size_t size() const { return str_.size(); }
+
+ std::string Release() {
+ std::string ret = std::move(str_);
+ str_.clear();
+ return ret;
+ }
+
+ // Allows appending a printf style formatted string.
+ StringBuilder& AppendFormat(const char* fmt, ...)
+#if defined(__GNUC__)
+ __attribute__((__format__(__printf__, 2, 3)))
+#endif
+ ;
+
+ private:
+ std::string str_;
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_STRINGS_STRING_BUILDER_H_
diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc b/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc
new file mode 100644
index 0000000000..99dfd86292
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/string_builder.h"
+
+#include <string.h>
+
+#include "rtc_base/checks.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace rtc {
+
+TEST(SimpleStringBuilder, Limit) {
+ char sb_buf[10];
+ SimpleStringBuilder sb(sb_buf);
+ EXPECT_EQ(0u, strlen(sb.str()));
+
+ // Test that for a SSB with a buffer size of 10, that we can write 9 chars
+ // into it.
+ sb << "012345678"; // 9 characters + '\0'.
+ EXPECT_EQ(0, strcmp(sb.str(), "012345678"));
+}
+
+TEST(SimpleStringBuilder, NumbersAndChars) {
+ char sb_buf[100];
+ SimpleStringBuilder sb(sb_buf);
+ sb << 1 << ':' << 2.1 << ":" << 2.2f << ':' << 78187493520ll << ':'
+ << 78187493520ul;
+ EXPECT_EQ(0, strcmp(sb.str(), "1:2.1:2.2:78187493520:78187493520"));
+}
+
+TEST(SimpleStringBuilder, Format) {
+ char sb_buf[100];
+ SimpleStringBuilder sb(sb_buf);
+ sb << "Here we go - ";
+ sb.AppendFormat("This is a hex formatted value: 0x%08llx", 3735928559ULL);
+ EXPECT_EQ(0,
+ strcmp(sb.str(),
+ "Here we go - This is a hex formatted value: 0xdeadbeef"));
+}
+
+TEST(SimpleStringBuilder, StdString) {
+ char sb_buf[100];
+ SimpleStringBuilder sb(sb_buf);
+ std::string str = "does this work?";
+ sb << str;
+ EXPECT_EQ(str, sb.str());
+}
+
+// These tests are safe to run if we have death test support or if DCHECKs are
+// off.
+#if (GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)) || !RTC_DCHECK_IS_ON
+
+TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharP) {
+ char sb_buf[4];
+ SimpleStringBuilder sb(sb_buf);
+ const char* const msg = "This is just too much";
+#if RTC_DCHECK_IS_ON
+ EXPECT_DEATH(sb << msg, "");
+#else
+ sb << msg;
+ EXPECT_THAT(sb.str(), ::testing::StrEq("Thi"));
+#endif
+}
+
+TEST(SimpleStringBuilderDeathTest, BufferOverrunStdString) {
+ char sb_buf[4];
+ SimpleStringBuilder sb(sb_buf);
+ sb << 12;
+ const std::string msg = "Aw, come on!";
+#if RTC_DCHECK_IS_ON
+ EXPECT_DEATH(sb << msg, "");
+#else
+ sb << msg;
+ EXPECT_THAT(sb.str(), ::testing::StrEq("12A"));
+#endif
+}
+
+TEST(SimpleStringBuilderDeathTest, BufferOverrunInt) {
+ char sb_buf[4];
+ SimpleStringBuilder sb(sb_buf);
+ constexpr int num = -12345;
+#if RTC_DCHECK_IS_ON
+ EXPECT_DEATH(sb << num, "");
+#else
+ sb << num;
+ // If we run into the end of the buffer, resonable results are either that
+ // the append has no effect or that it's truncated at the point where the
+ // buffer ends.
+ EXPECT_THAT(sb.str(),
+ ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("-12")));
+#endif
+}
+
+TEST(SimpleStringBuilderDeathTest, BufferOverrunDouble) {
+ char sb_buf[5];
+ SimpleStringBuilder sb(sb_buf);
+ constexpr double num = 123.456;
+#if RTC_DCHECK_IS_ON
+ EXPECT_DEATH(sb << num, "");
+#else
+ sb << num;
+ EXPECT_THAT(sb.str(),
+ ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("123.")));
+#endif
+}
+
+TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharPAlreadyFull) {
+ char sb_buf[4];
+ SimpleStringBuilder sb(sb_buf);
+ sb << 123;
+ const char* const msg = "This is just too much";
+#if RTC_DCHECK_IS_ON
+ EXPECT_DEATH(sb << msg, "");
+#else
+ sb << msg;
+ EXPECT_THAT(sb.str(), ::testing::StrEq("123"));
+#endif
+}
+
+TEST(SimpleStringBuilderDeathTest, BufferOverrunIntAlreadyFull) {
+ char sb_buf[4];
+ SimpleStringBuilder sb(sb_buf);
+ sb << "xyz";
+ constexpr int num = -12345;
+#if RTC_DCHECK_IS_ON
+ EXPECT_DEATH(sb << num, "");
+#else
+ sb << num;
+ EXPECT_THAT(sb.str(), ::testing::StrEq("xyz"));
+#endif
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// StringBuilder.
+
+TEST(StringBuilder, Limit) {
+ StringBuilder sb;
+ EXPECT_EQ(0u, sb.str().size());
+
+ sb << "012345678";
+ EXPECT_EQ(sb.str(), "012345678");
+}
+
+TEST(StringBuilder, NumbersAndChars) {
+ StringBuilder sb;
+ sb << 1 << ":" << 2.1 << ":" << 2.2f << ":" << 78187493520ll << ":"
+ << 78187493520ul;
+ EXPECT_THAT(sb.str(),
+ ::testing::MatchesRegex("1:2.10*:2.20*:78187493520:78187493520"));
+}
+
+TEST(StringBuilder, Format) {
+ StringBuilder sb;
+ sb << "Here we go - ";
+ sb.AppendFormat("This is a hex formatted value: 0x%08llx", 3735928559ULL);
+ EXPECT_EQ(sb.str(), "Here we go - This is a hex formatted value: 0xdeadbeef");
+}
+
+TEST(StringBuilder, StdString) {
+ StringBuilder sb;
+ std::string str = "does this work?";
+ sb << str;
+ EXPECT_EQ(str, sb.str());
+}
+
+TEST(StringBuilder, Release) {
+ StringBuilder sb;
+ std::string str =
+ "This string has to be of a moderate length, or we might "
+ "run into problems with small object optimizations.";
+ EXPECT_LT(sizeof(str), str.size());
+ sb << str;
+ EXPECT_EQ(str, sb.str());
+ const char* original_buffer = sb.str().c_str();
+ std::string moved = sb.Release();
+ EXPECT_TRUE(sb.str().empty());
+ EXPECT_EQ(str, moved);
+ EXPECT_EQ(original_buffer, moved.c_str());
+}
+
+TEST(StringBuilder, Reset) {
+ StringBuilder sb("abc");
+ sb << "def";
+ EXPECT_EQ("abcdef", sb.str());
+ sb.Clear();
+ EXPECT_TRUE(sb.str().empty());
+ sb << 123 << "!";
+ EXPECT_EQ("123!", sb.str());
+}
+
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/strings/string_format.cc b/third_party/libwebrtc/rtc_base/strings/string_format.cc
new file mode 100644
index 0000000000..e69fb6193d
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/string_format.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/string_format.h"
+
+#include <cstdarg>
+
+#include "rtc_base/checks.h"
+
+namespace rtc {
+
+namespace {
+
+// This is an arbitrary limitation that can be changed if necessary, or removed
+// if someone has the time and inclination to replicate the fancy logic from
+// Chromium's base::StringPrinf().
+constexpr int kMaxSize = 512;
+
+} // namespace
+
+std::string StringFormat(const char* fmt, ...) {
+ char buffer[kMaxSize];
+ va_list args;
+ va_start(args, fmt);
+ int result = vsnprintf(buffer, kMaxSize, fmt, args);
+ va_end(args);
+ RTC_DCHECK_GE(result, 0) << "ERROR: vsnprintf() failed with error " << result;
+ RTC_DCHECK_LT(result, kMaxSize)
+ << "WARNING: string was truncated from " << result << " to "
+ << (kMaxSize - 1) << " characters";
+ return std::string(buffer);
+}
+
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/strings/string_format.h b/third_party/libwebrtc/rtc_base/strings/string_format.h
new file mode 100644
index 0000000000..13124d2925
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/string_format.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_STRINGS_STRING_FORMAT_H_
+#define RTC_BASE_STRINGS_STRING_FORMAT_H_
+
+#include <string>
+
+namespace rtc {
+
+#if defined(__GNUC__)
+#define RTC_PRINTF_FORMAT(format_param, dots_param) \
+ __attribute__((format(printf, format_param, dots_param)))
+#else
+#define RTC_PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+// Return a C++ string given printf-like input.
+// Based on base::StringPrintf() in Chrome but without its fancy dynamic memory
+// allocation for any size of the input buffer.
+std::string StringFormat(const char* fmt, ...) RTC_PRINTF_FORMAT(1, 2);
+} // namespace rtc
+
+#endif // RTC_BASE_STRINGS_STRING_FORMAT_H_
diff --git a/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc b/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc
new file mode 100644
index 0000000000..5531001979
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/string_format.h"
+
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/string_encode.h"
+#include "test/gtest.h"
+
+namespace rtc {
+
+TEST(StringFormatTest, Empty) {
+ EXPECT_EQ("", StringFormat("%s", ""));
+}
+
+TEST(StringFormatTest, Misc) {
+ EXPECT_EQ("123hello w", StringFormat("%3d%2s %1c", 123, "hello", 'w'));
+ EXPECT_EQ("3 = three", StringFormat("%d = %s", 1 + 2, "three"));
+}
+
+TEST(StringFormatTest, MaxSizeShouldWork) {
+ const int kSrcLen = 512;
+ char str[kSrcLen];
+ std::fill_n(str, kSrcLen, 'A');
+ str[kSrcLen - 1] = 0;
+ EXPECT_EQ(str, StringFormat("%s", str));
+}
+
+// Test that formating a string using `absl::string_view` works as expected
+// whe using `%.*s`.
+TEST(StringFormatTest, FormatStringView) {
+ const std::string main_string("This is a substring test.");
+ std::vector<absl::string_view> string_views = rtc::split(main_string, ' ');
+ ASSERT_EQ(string_views.size(), 5u);
+
+ const absl::string_view& sv = string_views[3];
+ std::string formatted =
+ StringFormat("We have a %.*s.", static_cast<int>(sv.size()), sv.data());
+ EXPECT_EQ(formatted.compare("We have a substring."), 0);
+}
+
+} // namespace rtc