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/quic/core/quic_data_writer.h"
6
7 #include <algorithm>
8 #include <limits>
9
10 #include "absl/strings/string_view.h"
11 #include "quiche/quic/core/crypto/quic_random.h"
12 #include "quiche/quic/core/quic_constants.h"
13 #include "quiche/quic/platform/api/quic_bug_tracker.h"
14 #include "quiche/quic/platform/api/quic_flags.h"
15 #include "quiche/common/quiche_endian.h"
16
17 namespace quic {
18
QuicDataWriter(size_t size,char * buffer)19 QuicDataWriter::QuicDataWriter(size_t size, char* buffer)
20 : quiche::QuicheDataWriter(size, buffer) {}
21
QuicDataWriter(size_t size,char * buffer,quiche::Endianness endianness)22 QuicDataWriter::QuicDataWriter(size_t size, char* buffer,
23 quiche::Endianness endianness)
24 : quiche::QuicheDataWriter(size, buffer, endianness) {}
25
~QuicDataWriter()26 QuicDataWriter::~QuicDataWriter() {}
27
WriteUFloat16(uint64_t value)28 bool QuicDataWriter::WriteUFloat16(uint64_t value) {
29 uint16_t result;
30 if (value < (UINT64_C(1) << kUFloat16MantissaEffectiveBits)) {
31 // Fast path: either the value is denormalized, or has exponent zero.
32 // Both cases are represented by the value itself.
33 result = static_cast<uint16_t>(value);
34 } else if (value >= kUFloat16MaxValue) {
35 // Value is out of range; clamp it to the maximum representable.
36 result = std::numeric_limits<uint16_t>::max();
37 } else {
38 // The highest bit is between position 13 and 42 (zero-based), which
39 // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10,
40 // hidden bit is 11 and exponent is 11 to 15. Shift the highest bit to 11
41 // and count the shifts.
42 uint16_t exponent = 0;
43 for (uint16_t offset = 16; offset > 0; offset /= 2) {
44 // Right-shift the value until the highest bit is in position 11.
45 // For offset of 16, 8, 4, 2 and 1 (binary search over 1-30),
46 // shift if the bit is at or above 11 + offset.
47 if (value >= (UINT64_C(1) << (kUFloat16MantissaBits + offset))) {
48 exponent += offset;
49 value >>= offset;
50 }
51 }
52
53 QUICHE_DCHECK_GE(exponent, 1);
54 QUICHE_DCHECK_LE(exponent, kUFloat16MaxExponent);
55 QUICHE_DCHECK_GE(value, UINT64_C(1) << kUFloat16MantissaBits);
56 QUICHE_DCHECK_LT(value, UINT64_C(1) << kUFloat16MantissaEffectiveBits);
57
58 // Hidden bit (position 11) is set. We should remove it and increment the
59 // exponent. Equivalently, we just add it to the exponent.
60 // This hides the bit.
61 result = static_cast<uint16_t>(value + (exponent << kUFloat16MantissaBits));
62 }
63
64 if (endianness() == quiche::NETWORK_BYTE_ORDER) {
65 result = quiche::QuicheEndian::HostToNet16(result);
66 }
67 return WriteBytes(&result, sizeof(result));
68 }
69
WriteConnectionId(QuicConnectionId connection_id)70 bool QuicDataWriter::WriteConnectionId(QuicConnectionId connection_id) {
71 if (connection_id.IsEmpty()) {
72 return true;
73 }
74 return WriteBytes(connection_id.data(), connection_id.length());
75 }
76
WriteLengthPrefixedConnectionId(QuicConnectionId connection_id)77 bool QuicDataWriter::WriteLengthPrefixedConnectionId(
78 QuicConnectionId connection_id) {
79 return WriteUInt8(connection_id.length()) && WriteConnectionId(connection_id);
80 }
81
WriteRandomBytes(QuicRandom * random,size_t length)82 bool QuicDataWriter::WriteRandomBytes(QuicRandom* random, size_t length) {
83 char* dest = BeginWrite(length);
84 if (!dest) {
85 return false;
86 }
87
88 random->RandBytes(dest, length);
89 IncreaseLength(length);
90 return true;
91 }
92
WriteInsecureRandomBytes(QuicRandom * random,size_t length)93 bool QuicDataWriter::WriteInsecureRandomBytes(QuicRandom* random,
94 size_t length) {
95 char* dest = BeginWrite(length);
96 if (!dest) {
97 return false;
98 }
99
100 random->InsecureRandBytes(dest, length);
101 IncreaseLength(length);
102 return true;
103 }
104
105 } // namespace quic
106