blob: 48316b052be3864233f15880866fd90252f53a5a [file] [log] [blame]
Elad Aloncb21ffe2018-10-19 18:30:30 +02001/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "logging/rtc_event_log/encoder/blob_encoding.h"
12
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <cstdint>
Elad Aloncb21ffe2018-10-19 18:30:30 +020014
Steve Anton10542f22019-01-11 09:11:00 -080015#include "logging/rtc_event_log/encoder/var_int.h"
Yves Gerey3e707812018-11-28 16:47:49 +010016#include "rtc_base/checks.h"
Elad Aloncb21ffe2018-10-19 18:30:30 +020017#include "rtc_base/logging.h"
18
19namespace webrtc {
20
Elad Aloncb21ffe2018-10-19 18:30:30 +020021std::string EncodeBlobs(const std::vector<std::string>& blobs) {
22 RTC_DCHECK(!blobs.empty());
23
24 size_t result_length_bound = kMaxVarIntLengthBytes * blobs.size();
25 for (const auto& blob : blobs) {
26 // Providing an input so long that it would cause a wrap-around is an error.
27 RTC_DCHECK_GE(result_length_bound + blob.length(), result_length_bound);
28 result_length_bound += blob.length();
29 }
30
31 std::string result;
32 result.reserve(result_length_bound);
33
34 // First, encode all of the lengths.
35 for (absl::string_view blob : blobs) {
36 result += EncodeVarInt(blob.length());
37 }
38
39 // Second, encode the actual blobs.
40 for (absl::string_view blob : blobs) {
41 result.append(blob.data(), blob.length());
42 }
43
44 RTC_DCHECK_LE(result.size(), result_length_bound);
45 return result;
46}
47
48std::vector<absl::string_view> DecodeBlobs(absl::string_view encoded_blobs,
49 size_t num_of_blobs) {
50 if (encoded_blobs.empty()) {
51 RTC_LOG(LS_WARNING) << "Corrupt input; empty input.";
52 return std::vector<absl::string_view>();
53 }
54
55 if (num_of_blobs == 0u) {
56 RTC_LOG(LS_WARNING)
57 << "Corrupt input; number of blobs must be greater than 0.";
58 return std::vector<absl::string_view>();
59 }
60
61 size_t read_idx = 0;
62
63 // Read the lengths of all blobs.
64 std::vector<uint64_t> lengths(num_of_blobs);
65 for (size_t i = 0; i < num_of_blobs; ++i) {
66 if (read_idx >= encoded_blobs.length()) {
67 RTC_DCHECK_EQ(read_idx, encoded_blobs.length());
68 RTC_LOG(LS_WARNING) << "Corrupt input; excessive number of blobs.";
69 return std::vector<absl::string_view>();
70 }
71
72 const size_t read_bytes =
73 DecodeVarInt(encoded_blobs.substr(read_idx), &lengths[i]);
74 if (read_bytes == 0) {
75 RTC_LOG(LS_WARNING) << "Corrupt input; varint decoding failed.";
76 return std::vector<absl::string_view>();
77 }
78
79 read_idx += read_bytes;
80
81 // Note: It might be that read_idx == encoded_blobs.length(), if this
82 // is the last iteration, and all of the blobs are the empty string.
83 RTC_DCHECK_LE(read_idx, encoded_blobs.length());
84 }
85
86 // Read the blobs themselves.
87 std::vector<absl::string_view> blobs(num_of_blobs);
88 for (size_t i = 0; i < num_of_blobs; ++i) {
89 if (read_idx + lengths[i] < read_idx) { // Wrap-around detection.
90 RTC_LOG(LS_WARNING) << "Corrupt input; unreasonably large blob sequence.";
91 return std::vector<absl::string_view>();
92 }
93
94 if (read_idx + lengths[i] > encoded_blobs.length()) {
95 RTC_LOG(LS_WARNING) << "Corrupt input; blob sizes exceed input size.";
96 return std::vector<absl::string_view>();
97 }
98
99 blobs[i] = encoded_blobs.substr(read_idx, lengths[i]);
100 read_idx += lengths[i];
101 }
102
103 if (read_idx != encoded_blobs.length()) {
104 RTC_LOG(LS_WARNING) << "Corrupt input; unrecognized trailer.";
105 return std::vector<absl::string_view>();
106 }
107
108 return blobs;
109}
110
111} // namespace webrtc