blob: ee137f13fc1a402f6d808387a76a409494585fe8 [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
13#include <algorithm>
14
Elad Alonff435412018-10-26 19:09:41 +020015#include "logging/rtc_event_log/encoder/varint.h"
Elad Aloncb21ffe2018-10-19 18:30:30 +020016#include "rtc_base/logging.h"
17
18namespace webrtc {
19
Elad Aloncb21ffe2018-10-19 18:30:30 +020020std::string EncodeBlobs(const std::vector<std::string>& blobs) {
21 RTC_DCHECK(!blobs.empty());
22
23 size_t result_length_bound = kMaxVarIntLengthBytes * blobs.size();
24 for (const auto& blob : blobs) {
25 // Providing an input so long that it would cause a wrap-around is an error.
26 RTC_DCHECK_GE(result_length_bound + blob.length(), result_length_bound);
27 result_length_bound += blob.length();
28 }
29
30 std::string result;
31 result.reserve(result_length_bound);
32
33 // First, encode all of the lengths.
34 for (absl::string_view blob : blobs) {
35 result += EncodeVarInt(blob.length());
36 }
37
38 // Second, encode the actual blobs.
39 for (absl::string_view blob : blobs) {
40 result.append(blob.data(), blob.length());
41 }
42
43 RTC_DCHECK_LE(result.size(), result_length_bound);
44 return result;
45}
46
47std::vector<absl::string_view> DecodeBlobs(absl::string_view encoded_blobs,
48 size_t num_of_blobs) {
49 if (encoded_blobs.empty()) {
50 RTC_LOG(LS_WARNING) << "Corrupt input; empty input.";
51 return std::vector<absl::string_view>();
52 }
53
54 if (num_of_blobs == 0u) {
55 RTC_LOG(LS_WARNING)
56 << "Corrupt input; number of blobs must be greater than 0.";
57 return std::vector<absl::string_view>();
58 }
59
60 size_t read_idx = 0;
61
62 // Read the lengths of all blobs.
63 std::vector<uint64_t> lengths(num_of_blobs);
64 for (size_t i = 0; i < num_of_blobs; ++i) {
65 if (read_idx >= encoded_blobs.length()) {
66 RTC_DCHECK_EQ(read_idx, encoded_blobs.length());
67 RTC_LOG(LS_WARNING) << "Corrupt input; excessive number of blobs.";
68 return std::vector<absl::string_view>();
69 }
70
71 const size_t read_bytes =
72 DecodeVarInt(encoded_blobs.substr(read_idx), &lengths[i]);
73 if (read_bytes == 0) {
74 RTC_LOG(LS_WARNING) << "Corrupt input; varint decoding failed.";
75 return std::vector<absl::string_view>();
76 }
77
78 read_idx += read_bytes;
79
80 // Note: It might be that read_idx == encoded_blobs.length(), if this
81 // is the last iteration, and all of the blobs are the empty string.
82 RTC_DCHECK_LE(read_idx, encoded_blobs.length());
83 }
84
85 // Read the blobs themselves.
86 std::vector<absl::string_view> blobs(num_of_blobs);
87 for (size_t i = 0; i < num_of_blobs; ++i) {
88 if (read_idx + lengths[i] < read_idx) { // Wrap-around detection.
89 RTC_LOG(LS_WARNING) << "Corrupt input; unreasonably large blob sequence.";
90 return std::vector<absl::string_view>();
91 }
92
93 if (read_idx + lengths[i] > encoded_blobs.length()) {
94 RTC_LOG(LS_WARNING) << "Corrupt input; blob sizes exceed input size.";
95 return std::vector<absl::string_view>();
96 }
97
98 blobs[i] = encoded_blobs.substr(read_idx, lengths[i]);
99 read_idx += lengths[i];
100 }
101
102 if (read_idx != encoded_blobs.length()) {
103 RTC_LOG(LS_WARNING) << "Corrupt input; unrecognized trailer.";
104 return std::vector<absl::string_view>();
105 }
106
107 return blobs;
108}
109
110} // namespace webrtc