1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/common/quiche_data_writer.h"
6
7 #include <algorithm>
8 #include <limits>
9
10 #include "absl/strings/str_cat.h"
11 #include "absl/strings/string_view.h"
12 #include "quiche/common/platform/api/quiche_bug_tracker.h"
13 #include "quiche/common/quiche_endian.h"
14
15 namespace quiche {
16
QuicheDataWriter(size_t size,char * buffer)17 QuicheDataWriter::QuicheDataWriter(size_t size, char* buffer)
18 : QuicheDataWriter(size, buffer, quiche::NETWORK_BYTE_ORDER) {}
19
QuicheDataWriter(size_t size,char * buffer,quiche::Endianness endianness)20 QuicheDataWriter::QuicheDataWriter(size_t size, char* buffer,
21 quiche::Endianness endianness)
22 : buffer_(buffer), capacity_(size), length_(0), endianness_(endianness) {}
23
~QuicheDataWriter()24 QuicheDataWriter::~QuicheDataWriter() {}
25
data()26 char* QuicheDataWriter::data() { return buffer_; }
27
WriteUInt8(uint8_t value)28 bool QuicheDataWriter::WriteUInt8(uint8_t value) {
29 return WriteBytes(&value, sizeof(value));
30 }
31
WriteUInt16(uint16_t value)32 bool QuicheDataWriter::WriteUInt16(uint16_t value) {
33 if (endianness_ == quiche::NETWORK_BYTE_ORDER) {
34 value = quiche::QuicheEndian::HostToNet16(value);
35 }
36 return WriteBytes(&value, sizeof(value));
37 }
38
WriteUInt32(uint32_t value)39 bool QuicheDataWriter::WriteUInt32(uint32_t value) {
40 if (endianness_ == quiche::NETWORK_BYTE_ORDER) {
41 value = quiche::QuicheEndian::HostToNet32(value);
42 }
43 return WriteBytes(&value, sizeof(value));
44 }
45
WriteUInt64(uint64_t value)46 bool QuicheDataWriter::WriteUInt64(uint64_t value) {
47 if (endianness_ == quiche::NETWORK_BYTE_ORDER) {
48 value = quiche::QuicheEndian::HostToNet64(value);
49 }
50 return WriteBytes(&value, sizeof(value));
51 }
52
WriteBytesToUInt64(size_t num_bytes,uint64_t value)53 bool QuicheDataWriter::WriteBytesToUInt64(size_t num_bytes, uint64_t value) {
54 if (num_bytes > sizeof(value)) {
55 return false;
56 }
57 if (endianness_ == quiche::HOST_BYTE_ORDER) {
58 return WriteBytes(&value, num_bytes);
59 }
60
61 value = quiche::QuicheEndian::HostToNet64(value);
62 return WriteBytes(reinterpret_cast<char*>(&value) + sizeof(value) - num_bytes,
63 num_bytes);
64 }
65
WriteStringPiece16(absl::string_view val)66 bool QuicheDataWriter::WriteStringPiece16(absl::string_view val) {
67 if (val.size() > std::numeric_limits<uint16_t>::max()) {
68 return false;
69 }
70 if (!WriteUInt16(static_cast<uint16_t>(val.size()))) {
71 return false;
72 }
73 return WriteBytes(val.data(), val.size());
74 }
75
WriteStringPiece(absl::string_view val)76 bool QuicheDataWriter::WriteStringPiece(absl::string_view val) {
77 return WriteBytes(val.data(), val.size());
78 }
79
BeginWrite(size_t length)80 char* QuicheDataWriter::BeginWrite(size_t length) {
81 if (length_ > capacity_) {
82 return nullptr;
83 }
84
85 if (capacity_ - length_ < length) {
86 return nullptr;
87 }
88
89 #ifdef ARCH_CPU_64_BITS
90 QUICHE_DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
91 #endif
92
93 return buffer_ + length_;
94 }
95
WriteBytes(const void * data,size_t data_len)96 bool QuicheDataWriter::WriteBytes(const void* data, size_t data_len) {
97 char* dest = BeginWrite(data_len);
98 if (!dest) {
99 return false;
100 }
101
102 std::copy(static_cast<const char*>(data),
103 static_cast<const char*>(data) + data_len, dest);
104
105 length_ += data_len;
106 return true;
107 }
108
WriteRepeatedByte(uint8_t byte,size_t count)109 bool QuicheDataWriter::WriteRepeatedByte(uint8_t byte, size_t count) {
110 char* dest = BeginWrite(count);
111 if (!dest) {
112 return false;
113 }
114
115 std::fill(dest, dest + count, byte);
116
117 length_ += count;
118 return true;
119 }
120
WritePadding()121 void QuicheDataWriter::WritePadding() {
122 QUICHE_DCHECK_LE(length_, capacity_);
123 if (length_ > capacity_) {
124 return;
125 }
126 std::fill(buffer_ + length_, buffer_ + capacity_, 0x00);
127 length_ = capacity_;
128 }
129
WritePaddingBytes(size_t count)130 bool QuicheDataWriter::WritePaddingBytes(size_t count) {
131 return WriteRepeatedByte(0x00, count);
132 }
133
WriteTag(uint32_t tag)134 bool QuicheDataWriter::WriteTag(uint32_t tag) {
135 return WriteBytes(&tag, sizeof(tag));
136 }
137
138 // Converts a uint64_t into a 62-bit RFC 9000 Variable Length Integer.
139 //
140 // Performance notes
141 //
142 // Measurements and experiments showed that unrolling the four cases
143 // like this and dereferencing next_ as we do (*(next_+n)) gains about
144 // 10% over making a loop and dereferencing it as *(next_++)
145 //
146 // Using a register for next didn't help.
147 //
148 // Branches are ordered to increase the likelihood of the first being
149 // taken.
150 //
151 // Low-level optimization is useful here because this function will be
152 // called frequently, leading to outsize benefits.
WriteVarInt62(uint64_t value)153 bool QuicheDataWriter::WriteVarInt62(uint64_t value) {
154 QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER);
155
156 size_t remaining_bytes = remaining();
157 char* next = buffer() + length();
158
159 if ((value & kVarInt62ErrorMask) == 0) {
160 // We know the high 2 bits are 0 so |value| is legal.
161 // We can do the encoding.
162 if ((value & kVarInt62Mask8Bytes) != 0) {
163 // Someplace in the high-4 bytes is a 1-bit. Do an 8-byte
164 // encoding.
165 if (remaining_bytes >= 8) {
166 *(next + 0) = ((value >> 56) & 0x3f) + 0xc0;
167 *(next + 1) = (value >> 48) & 0xff;
168 *(next + 2) = (value >> 40) & 0xff;
169 *(next + 3) = (value >> 32) & 0xff;
170 *(next + 4) = (value >> 24) & 0xff;
171 *(next + 5) = (value >> 16) & 0xff;
172 *(next + 6) = (value >> 8) & 0xff;
173 *(next + 7) = value & 0xff;
174 IncreaseLength(8);
175 return true;
176 }
177 return false;
178 }
179 // The high-order-4 bytes are all 0, check for a 1, 2, or 4-byte
180 // encoding
181 if ((value & kVarInt62Mask4Bytes) != 0) {
182 // The encoding will not fit into 2 bytes, Do a 4-byte
183 // encoding.
184 if (remaining_bytes >= 4) {
185 *(next + 0) = ((value >> 24) & 0x3f) + 0x80;
186 *(next + 1) = (value >> 16) & 0xff;
187 *(next + 2) = (value >> 8) & 0xff;
188 *(next + 3) = value & 0xff;
189 IncreaseLength(4);
190 return true;
191 }
192 return false;
193 }
194 // The high-order bits are all 0. Check to see if the number
195 // can be encoded as one or two bytes. One byte encoding has
196 // only 6 significant bits (bits 0xffffffff ffffffc0 are all 0).
197 // Two byte encoding has more than 6, but 14 or less significant
198 // bits (bits 0xffffffff ffffc000 are 0 and 0x00000000 00003fc0
199 // are not 0)
200 if ((value & kVarInt62Mask2Bytes) != 0) {
201 // Do 2-byte encoding
202 if (remaining_bytes >= 2) {
203 *(next + 0) = ((value >> 8) & 0x3f) + 0x40;
204 *(next + 1) = (value)&0xff;
205 IncreaseLength(2);
206 return true;
207 }
208 return false;
209 }
210 if (remaining_bytes >= 1) {
211 // Do 1-byte encoding
212 *next = (value & 0x3f);
213 IncreaseLength(1);
214 return true;
215 }
216 return false;
217 }
218 // Can not encode, high 2 bits not 0
219 return false;
220 }
221
WriteStringPieceVarInt62(const absl::string_view & string_piece)222 bool QuicheDataWriter::WriteStringPieceVarInt62(
223 const absl::string_view& string_piece) {
224 if (!WriteVarInt62(string_piece.size())) {
225 return false;
226 }
227 if (!string_piece.empty()) {
228 if (!WriteBytes(string_piece.data(), string_piece.size())) {
229 return false;
230 }
231 }
232 return true;
233 }
234
235 // static
GetVarInt62Len(uint64_t value)236 QuicheVariableLengthIntegerLength QuicheDataWriter::GetVarInt62Len(
237 uint64_t value) {
238 if ((value & kVarInt62ErrorMask) != 0) {
239 QUICHE_BUG(invalid_varint) << "Attempted to encode a value, " << value
240 << ", that is too big for VarInt62";
241 return VARIABLE_LENGTH_INTEGER_LENGTH_0;
242 }
243 if ((value & kVarInt62Mask8Bytes) != 0) {
244 return VARIABLE_LENGTH_INTEGER_LENGTH_8;
245 }
246 if ((value & kVarInt62Mask4Bytes) != 0) {
247 return VARIABLE_LENGTH_INTEGER_LENGTH_4;
248 }
249 if ((value & kVarInt62Mask2Bytes) != 0) {
250 return VARIABLE_LENGTH_INTEGER_LENGTH_2;
251 }
252 return VARIABLE_LENGTH_INTEGER_LENGTH_1;
253 }
254
WriteVarInt62WithForcedLength(uint64_t value,QuicheVariableLengthIntegerLength write_length)255 bool QuicheDataWriter::WriteVarInt62WithForcedLength(
256 uint64_t value, QuicheVariableLengthIntegerLength write_length) {
257 QUICHE_DCHECK_EQ(endianness(), NETWORK_BYTE_ORDER);
258
259 size_t remaining_bytes = remaining();
260 if (remaining_bytes < write_length) {
261 return false;
262 }
263
264 const QuicheVariableLengthIntegerLength min_length = GetVarInt62Len(value);
265 if (write_length < min_length) {
266 QUICHE_BUG(invalid_varint_forced) << "Cannot write value " << value
267 << " with write_length " << write_length;
268 return false;
269 }
270 if (write_length == min_length) {
271 return WriteVarInt62(value);
272 }
273
274 if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_2) {
275 return WriteUInt8(0b01000000) && WriteUInt8(value);
276 }
277 if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_4) {
278 return WriteUInt8(0b10000000) && WriteUInt8(0) && WriteUInt16(value);
279 }
280 if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_8) {
281 return WriteUInt8(0b11000000) && WriteUInt8(0) && WriteUInt16(0) &&
282 WriteUInt32(value);
283 }
284
285 QUICHE_BUG(invalid_write_length)
286 << "Invalid write_length " << static_cast<int>(write_length);
287 return false;
288 }
289
Seek(size_t length)290 bool QuicheDataWriter::Seek(size_t length) {
291 if (!BeginWrite(length)) {
292 return false;
293 }
294 length_ += length;
295 return true;
296 }
297
DebugString() const298 std::string QuicheDataWriter::DebugString() const {
299 return absl::StrCat(" { capacity: ", capacity_, ", length: ", length_, " }");
300 }
301
302 } // namespace quiche
303