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 memcpy(dest, data, data_len);
103
104 length_ += data_len;
105 return true;
106 }
107
WriteRepeatedByte(uint8_t byte,size_t count)108 bool QuicheDataWriter::WriteRepeatedByte(uint8_t byte, size_t count) {
109 char* dest = BeginWrite(count);
110 if (!dest) {
111 return false;
112 }
113
114 memset(dest, byte, count);
115
116 length_ += count;
117 return true;
118 }
119
WritePadding()120 void QuicheDataWriter::WritePadding() {
121 QUICHE_DCHECK_LE(length_, capacity_);
122 if (length_ > capacity_) {
123 return;
124 }
125 memset(buffer_ + length_, 0x00, capacity_ - length_);
126 length_ = capacity_;
127 }
128
WritePaddingBytes(size_t count)129 bool QuicheDataWriter::WritePaddingBytes(size_t count) {
130 return WriteRepeatedByte(0x00, count);
131 }
132
WriteTag(uint32_t tag)133 bool QuicheDataWriter::WriteTag(uint32_t tag) {
134 return WriteBytes(&tag, sizeof(tag));
135 }
136
137 // Converts a uint64_t into a 62-bit RFC 9000 Variable Length Integer.
138 //
139 // Performance notes
140 //
141 // Measurements and experiments showed that unrolling the four cases
142 // like this and dereferencing next_ as we do (*(next_+n)) gains about
143 // 10% over making a loop and dereferencing it as *(next_++)
144 //
145 // Using a register for next didn't help.
146 //
147 // Branches are ordered to increase the likelihood of the first being
148 // taken.
149 //
150 // Low-level optimization is useful here because this function will be
151 // called frequently, leading to outsize benefits.
WriteVarInt62(uint64_t value)152 bool QuicheDataWriter::WriteVarInt62(uint64_t value) {
153 QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER);
154
155 size_t remaining_bytes = remaining();
156 char* next = buffer() + length();
157
158 if ((value & kVarInt62ErrorMask) == 0) {
159 // We know the high 2 bits are 0 so |value| is legal.
160 // We can do the encoding.
161 if ((value & kVarInt62Mask8Bytes) != 0) {
162 // Someplace in the high-4 bytes is a 1-bit. Do an 8-byte
163 // encoding.
164 if (remaining_bytes >= 8) {
165 *(next + 0) = ((value >> 56) & 0x3f) + 0xc0;
166 *(next + 1) = (value >> 48) & 0xff;
167 *(next + 2) = (value >> 40) & 0xff;
168 *(next + 3) = (value >> 32) & 0xff;
169 *(next + 4) = (value >> 24) & 0xff;
170 *(next + 5) = (value >> 16) & 0xff;
171 *(next + 6) = (value >> 8) & 0xff;
172 *(next + 7) = value & 0xff;
173 IncreaseLength(8);
174 return true;
175 }
176 return false;
177 }
178 // The high-order-4 bytes are all 0, check for a 1, 2, or 4-byte
179 // encoding
180 if ((value & kVarInt62Mask4Bytes) != 0) {
181 // The encoding will not fit into 2 bytes, Do a 4-byte
182 // encoding.
183 if (remaining_bytes >= 4) {
184 *(next + 0) = ((value >> 24) & 0x3f) + 0x80;
185 *(next + 1) = (value >> 16) & 0xff;
186 *(next + 2) = (value >> 8) & 0xff;
187 *(next + 3) = value & 0xff;
188 IncreaseLength(4);
189 return true;
190 }
191 return false;
192 }
193 // The high-order bits are all 0. Check to see if the number
194 // can be encoded as one or two bytes. One byte encoding has
195 // only 6 significant bits (bits 0xffffffff ffffffc0 are all 0).
196 // Two byte encoding has more than 6, but 14 or less significant
197 // bits (bits 0xffffffff ffffc000 are 0 and 0x00000000 00003fc0
198 // are not 0)
199 if ((value & kVarInt62Mask2Bytes) != 0) {
200 // Do 2-byte encoding
201 if (remaining_bytes >= 2) {
202 *(next + 0) = ((value >> 8) & 0x3f) + 0x40;
203 *(next + 1) = (value)&0xff;
204 IncreaseLength(2);
205 return true;
206 }
207 return false;
208 }
209 if (remaining_bytes >= 1) {
210 // Do 1-byte encoding
211 *next = (value & 0x3f);
212 IncreaseLength(1);
213 return true;
214 }
215 return false;
216 }
217 // Can not encode, high 2 bits not 0
218 return false;
219 }
220
WriteStringPieceVarInt62(const absl::string_view & string_piece)221 bool QuicheDataWriter::WriteStringPieceVarInt62(
222 const absl::string_view& string_piece) {
223 if (!WriteVarInt62(string_piece.size())) {
224 return false;
225 }
226 if (!string_piece.empty()) {
227 if (!WriteBytes(string_piece.data(), string_piece.size())) {
228 return false;
229 }
230 }
231 return true;
232 }
233
234 // static
GetVarInt62Len(uint64_t value)235 QuicheVariableLengthIntegerLength QuicheDataWriter::GetVarInt62Len(
236 uint64_t value) {
237 if ((value & kVarInt62ErrorMask) != 0) {
238 QUICHE_BUG(invalid_varint) << "Attempted to encode a value, " << value
239 << ", that is too big for VarInt62";
240 return VARIABLE_LENGTH_INTEGER_LENGTH_0;
241 }
242 if ((value & kVarInt62Mask8Bytes) != 0) {
243 return VARIABLE_LENGTH_INTEGER_LENGTH_8;
244 }
245 if ((value & kVarInt62Mask4Bytes) != 0) {
246 return VARIABLE_LENGTH_INTEGER_LENGTH_4;
247 }
248 if ((value & kVarInt62Mask2Bytes) != 0) {
249 return VARIABLE_LENGTH_INTEGER_LENGTH_2;
250 }
251 return VARIABLE_LENGTH_INTEGER_LENGTH_1;
252 }
253
WriteVarInt62WithForcedLength(uint64_t value,QuicheVariableLengthIntegerLength write_length)254 bool QuicheDataWriter::WriteVarInt62WithForcedLength(
255 uint64_t value, QuicheVariableLengthIntegerLength write_length) {
256 QUICHE_DCHECK_EQ(endianness(), NETWORK_BYTE_ORDER);
257
258 size_t remaining_bytes = remaining();
259 if (remaining_bytes < write_length) {
260 return false;
261 }
262
263 const QuicheVariableLengthIntegerLength min_length = GetVarInt62Len(value);
264 if (write_length < min_length) {
265 QUICHE_BUG(invalid_varint_forced) << "Cannot write value " << value
266 << " with write_length " << write_length;
267 return false;
268 }
269 if (write_length == min_length) {
270 return WriteVarInt62(value);
271 }
272
273 if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_2) {
274 return WriteUInt8(0b01000000) && WriteUInt8(value);
275 }
276 if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_4) {
277 return WriteUInt8(0b10000000) && WriteUInt8(0) && WriteUInt16(value);
278 }
279 if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_8) {
280 return WriteUInt8(0b11000000) && WriteUInt8(0) && WriteUInt16(0) &&
281 WriteUInt32(value);
282 }
283
284 QUICHE_BUG(invalid_write_length)
285 << "Invalid write_length " << static_cast<int>(write_length);
286 return false;
287 }
288
Seek(size_t length)289 bool QuicheDataWriter::Seek(size_t length) {
290 if (!BeginWrite(length)) {
291 return false;
292 }
293 length_ += length;
294 return true;
295 }
296
DebugString() const297 std::string QuicheDataWriter::DebugString() const {
298 return absl::StrCat(" { capacity: ", capacity_, ", length: ", length_, " }");
299 }
300
301 } // namespace quiche
302