1 /*
2 * Copyright (c) 2023, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12
13 #include "iamf/common/leb_generator.h"
14
15 #include <cstdint>
16 #include <memory>
17 #include <variant>
18 #include <vector>
19
20 #include "absl/log/log.h"
21 #include "absl/memory/memory.h"
22 #include "absl/status/status.h"
23 #include "absl/strings/str_cat.h"
24 #include "iamf/obu/types.h"
25
26 namespace iamf_tools {
27
28 namespace {
29
30 /*!\brief A general struct to represent an LEB128.
31 *
32 * When `is_signed` is false this represents a ULEB128. Otherwise this
33 * represents an SLEB128. An LEB128 can be encoded in up to 8 bytes.
34 *
35 * A ULEB128 may have values from 0 to (1 << 32) - 1.
36 * An SLEB128 may have values from -(1 << 31) to (1 << 31) - 1.
37 * These bounds imply the decoded value can be stored in 32 bits.
38 */
39 struct Leb128 {
40 std::variant<DecodedUleb128, DecodedSleb128> decoded_val;
41 int8_t coded_size;
42 bool is_signed;
43 };
44
45 /*!\brief Serializes the LEB128 and returns a status based on the result.
46 *
47 * Serializes a leb128 and returns a status based on the result. Each byte of a
48 * leb128 encodes 7 bits, the upper bit encodes whether it is the last byte in
49 * the sequence. Writes the number of written to the output argument.
50 *
51 * \param val Leb128 to serialize.
52 * \param min_size_encoding Controls whether the function writes the
53 * smallest possible representation of a LEB128. When false codes the
54 * LEB128 in `coded_size` bytes.
55 * \param buffer Buffer to serialize to.
56 * \return `absl::OkStatus()` if successful. `absl::InvalidArgumentError()`
57 * if the initial `coded_size` was invalid. `absl::UnknownError()` if
58 * the `coded_size` was insufficient to encode the value.
59 */
Leb128ToUint8Vector(const Leb128 & val,bool min_size_encoding,std::vector<uint8_t> & buffer)60 absl::Status Leb128ToUint8Vector(const Leb128& val, bool min_size_encoding,
61 std::vector<uint8_t>& buffer) {
62 // Reject LEB128s with invalid size.
63 if (val.coded_size < 1 || kMaxLeb128Size < val.coded_size) {
64 return absl::InvalidArgumentError("Invalid `coded_size`");
65 }
66
67 buffer.clear();
68 buffer.reserve(val.coded_size);
69
70 const bool decoded_is_negative =
71 val.is_signed && std::get<DecodedSleb128>(val.decoded_val) < 0;
72
73 uint32_t temp_val = val.is_signed
74 ? static_cast<DecodedUleb128>(
75 std::get<DecodedSleb128>(val.decoded_val))
76 : std::get<DecodedUleb128>(val.decoded_val);
77 absl::Status status = absl::UnknownError("Unknown error");
78
79 for (int i = 0; i < val.coded_size; i++) {
80 // Encode the next 7 bits.
81 buffer.push_back(0x80 | (temp_val & 0x7f));
82 temp_val >>= 7; // Logical shift clears the upper 7 bits.
83
84 if (decoded_is_negative) {
85 // For a negative SLEB128 set upper 7 bits (arithmetic shift).
86 temp_val |= 0xfe000000;
87 }
88
89 // The encoding could end when it is negative and is all 1s (-1) or positive
90 // and all 0s.
91 uint32_t end_value = 0;
92 if (val.is_signed && (buffer.back() & 0x40))
93 end_value = static_cast<uint32_t>(-1);
94
95 if (temp_val == end_value) {
96 status = absl::OkStatus();
97
98 // Exit early if the `min_size_encoding` flag is set. Otherwise continue
99 // until the encoding is `val->coded_size` bytes long.
100 if (min_size_encoding) {
101 break;
102 }
103 }
104 }
105
106 // Clear the final MSB to 0 to signal the end of the encoding.
107 buffer.back() &= 0x7f;
108
109 if (!status.ok() && !min_size_encoding) {
110 auto error_message = absl::StrCat(
111 (val.is_signed ? std::get<DecodedSleb128>(val.decoded_val)
112 : std::get<DecodedUleb128>(val.decoded_val)),
113 " requires at least ", buffer.size(), " bytes. The caller requested it",
114 " have a fixed size of ", val.coded_size);
115 status = absl::InvalidArgumentError(error_message);
116 }
117
118 return status;
119 }
120
121 } // namespace
122
123 // A trusted private constructor. The `Create()` functions ensure it is only
124 // called with expected arguments.
LebGenerator(GenerationMode generation_mode,int8_t fixed_size)125 LebGenerator::LebGenerator(GenerationMode generation_mode, int8_t fixed_size)
126 : generation_mode_(generation_mode), fixed_size_(fixed_size) {}
127
Create(GenerationMode generation_mode,int8_t fixed_size)128 std::unique_ptr<LebGenerator> LebGenerator::Create(
129 GenerationMode generation_mode, int8_t fixed_size) {
130 switch (generation_mode) {
131 case GenerationMode::kMinimum:
132 return absl::WrapUnique(new LebGenerator(generation_mode, 0));
133 case GenerationMode::kFixedSize:
134 if (1 <= fixed_size && fixed_size <= kMaxLeb128Size) {
135 return absl::WrapUnique(new LebGenerator(generation_mode, fixed_size));
136 } else {
137 LOG(ERROR) << "Invalid fixed size: " << fixed_size;
138 return nullptr;
139 }
140 default:
141 LOG(ERROR) << "Invalid generation mode: "
142 << absl::StrCat(generation_mode);
143 return nullptr;
144 }
145 }
146
Uleb128ToUint8Vector(DecodedUleb128 input,std::vector<uint8_t> & buffer) const147 absl::Status LebGenerator::Uleb128ToUint8Vector(
148 DecodedUleb128 input, std::vector<uint8_t>& buffer) const {
149 switch (generation_mode_) {
150 case GenerationMode::kMinimum:
151 return Leb128ToUint8Vector({input, kMaxLeb128Size, false},
152 /*min_size_encoding=*/true, buffer);
153 case GenerationMode::kFixedSize:
154 return Leb128ToUint8Vector({input, fixed_size_, false},
155 /*min_size_encoding=*/false, buffer);
156 default:
157 return absl::UnknownError("Unknown `generation_mode_`.");
158 }
159 }
160
Sleb128ToUint8Vector(DecodedSleb128 input,std::vector<uint8_t> & buffer) const161 absl::Status LebGenerator::Sleb128ToUint8Vector(
162 DecodedSleb128 input, std::vector<uint8_t>& buffer) const {
163 switch (generation_mode_) {
164 case GenerationMode::kMinimum:
165 return Leb128ToUint8Vector({input, kMaxLeb128Size, true},
166 /*min_size_encoding=*/true, buffer);
167 case GenerationMode::kFixedSize:
168 return Leb128ToUint8Vector({input, fixed_size_, true},
169 /*min_size_encoding=*/false, buffer);
170 default:
171 return absl::UnknownError("Unknown `generation_mode_`.");
172 }
173 }
174
175 } // namespace iamf_tools
176