-
Notifications
You must be signed in to change notification settings - Fork 8
/
varint.go
134 lines (127 loc) · 3.02 KB
/
varint.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package ohttp
// Modified from from https://github.com/lucas-clemente/quic-go/blob/d9c7467b569526b3e4d9df2e2bd4d8e9805fd82e/quicvarint/varint.go
import (
"bytes"
"fmt"
"io"
)
// taken from the QUIC draft
const (
maxVarInt1 = 63
maxVarInt2 = 16383
maxVarInt4 = 1073741823
maxVarInt8 = 4611686018427387903
)
// Read reads a number in the QUIC varint format
func Read(b io.ByteReader) (uint64, error) {
firstByte, err := b.ReadByte()
if err != nil {
return 0, err
}
// the first two bits of the first byte encode the length
len := 1 << ((firstByte & 0xc0) >> 6)
b1 := firstByte & (0xff - 0xc0)
if len == 1 {
return uint64(b1), nil
}
b2, err := b.ReadByte()
if err != nil {
return 0, err
}
if len == 2 {
return uint64(b2) + uint64(b1)<<8, nil
}
b3, err := b.ReadByte()
if err != nil {
return 0, err
}
b4, err := b.ReadByte()
if err != nil {
return 0, err
}
if len == 4 {
return uint64(b4) + uint64(b3)<<8 + uint64(b2)<<16 + uint64(b1)<<24, nil
}
b5, err := b.ReadByte()
if err != nil {
return 0, err
}
b6, err := b.ReadByte()
if err != nil {
return 0, err
}
b7, err := b.ReadByte()
if err != nil {
return 0, err
}
b8, err := b.ReadByte()
if err != nil {
return 0, err
}
return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil
}
// Write writes a number in the QUIC varint format
func Write(b *bytes.Buffer, i uint64) {
if i <= maxVarInt1 {
b.WriteByte(uint8(i))
} else if i <= maxVarInt2 {
b.Write([]byte{uint8(i>>8) | 0x40, uint8(i)})
} else if i <= maxVarInt4 {
b.Write([]byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)})
} else if i <= maxVarInt8 {
b.Write([]byte{
uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32),
uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i),
})
} else {
panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
}
}
// WriteWithLen writes a number in the QUIC varint format, with the desired length.
func WriteWithLen(b *bytes.Buffer, i uint64, length int64) {
if length != 1 && length != 2 && length != 4 && length != 8 {
panic("invalid varint length")
}
l := Len(i)
if l == length {
Write(b, i)
return
}
if l > length {
panic(fmt.Sprintf("cannot encode %d in %d bytes", i, length))
}
if length == 2 {
b.WriteByte(0b01000000)
} else if length == 4 {
b.WriteByte(0b10000000)
} else if length == 8 {
b.WriteByte(0b11000000)
}
for j := int64(1); j < length-l; j++ {
b.WriteByte(0)
}
for j := int64(0); j < l; j++ {
b.WriteByte(uint8(i >> (8 * (l - 1 - j))))
}
}
// Len determines the number of bytes that will be needed to write a number
func Len(i uint64) int64 {
if i <= maxVarInt1 {
return 1
}
if i <= maxVarInt2 {
return 2
}
if i <= maxVarInt4 {
return 4
}
if i <= maxVarInt8 {
return 8
}
// Don't use a fmt.Sprintf here to format the error message.
// The function would then exceed the inlining budget.
panic(struct {
message string
num uint64
}{"value doesn't fit into 62 bits: ", i})
}