| /* | |
| * Copyright (c) 2023 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 "logging/rtc_event_log/encoder/optional_blob_encoding.h" | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <optional> | |
| #include <string> | |
| #include <vector> | |
| #include "absl/strings/string_view.h" | |
| #include "rtc_base/bit_buffer.h" | |
| #include "rtc_base/bitstream_reader.h" | |
| #include "rtc_base/checks.h" | |
| namespace webrtc { | |
| std::string EncodeOptionalBlobs( | |
| const std::vector<std::optional<std::string>>& blobs) { | |
| if (blobs.empty()) { | |
| return {}; | |
| } | |
| size_t reserve_size_bits = 1; | |
| size_t num_blobs_present = 0; | |
| for (const auto& blob : blobs) { | |
| if (blob.has_value()) { | |
| ++num_blobs_present; | |
| reserve_size_bits += | |
| (BitBufferWriter::kMaxLeb128Length.bytes() + blob->size()) * 8; | |
| } | |
| } | |
| if (num_blobs_present == 0) { | |
| return {}; | |
| } | |
| const bool all_blobs_present = num_blobs_present == blobs.size(); | |
| if (!all_blobs_present) { | |
| reserve_size_bits += blobs.size(); | |
| } | |
| std::vector<uint8_t> buffer((reserve_size_bits + 7) / 8); | |
| BitBufferWriter writer(buffer); | |
| // Write present bits if all blobs are not present. | |
| writer.WriteBits(all_blobs_present, 1); | |
| if (!all_blobs_present) { | |
| for (const auto& blob : blobs) { | |
| writer.WriteBits(blob.has_value(), 1); | |
| } | |
| } | |
| // Byte align the writer. | |
| writer.ZeroBits(writer.RemainingBitCount() % 8); | |
| // Write blobs. | |
| for (const auto& blob : blobs) { | |
| if (blob.has_value()) { | |
| writer.WriteLeb128(blob->length()); | |
| writer.WriteString(*blob); | |
| } | |
| } | |
| size_t bytes_written; | |
| size_t bits_written; | |
| writer.GetCurrentOffset(&bytes_written, &bits_written); | |
| RTC_CHECK_EQ(bits_written, 0); | |
| RTC_CHECK_LE(bytes_written, buffer.size()); | |
| return std::string(buffer.data(), buffer.data() + bytes_written); | |
| } | |
| std::vector<std::optional<std::string>> DecodeOptionalBlobs( | |
| absl::string_view encoded_blobs, | |
| size_t num_of_blobs) { | |
| std::vector<std::optional<std::string>> res(num_of_blobs); | |
| if (encoded_blobs.empty() || num_of_blobs == 0) { | |
| return res; | |
| } | |
| BitstreamReader reader(encoded_blobs); | |
| const bool all_blobs_present = reader.ReadBit(); | |
| // Read present bits if all blobs are not present. | |
| std::vector<uint8_t> present; | |
| if (!all_blobs_present) { | |
| present.resize(num_of_blobs); | |
| for (size_t i = 0; i < num_of_blobs; ++i) { | |
| present[i] = reader.ReadBit(); | |
| } | |
| } | |
| // Byte align the reader. | |
| reader.ConsumeBits(reader.RemainingBitCount() % 8); | |
| // Read the blobs. | |
| for (size_t i = 0; i < num_of_blobs; ++i) { | |
| if (!all_blobs_present && !present[i]) { | |
| continue; | |
| } | |
| res[i] = reader.ReadString(reader.ReadLeb128()); | |
| } | |
| // The result is only valid if exactly all bits was consumed during decoding. | |
| if (!reader.Ok() || reader.RemainingBitCount() > 0) { | |
| return {}; | |
| } | |
| return res; | |
| } | |
| } // namespace webrtc |