mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-01 19:27:35 +03:00
uTLS is not yet bumped to the new version, so this commit breaks the dependencies relationship by getting rid of the local replace.
141 lines
3.2 KiB
Go
141 lines
3.2 KiB
Go
package quicvarint
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/refraction-networking/uquic/internal/protocol"
|
|
)
|
|
|
|
// taken from the QUIC draft
|
|
const (
|
|
// Min is the minimum value allowed for a QUIC varint.
|
|
Min = 0
|
|
|
|
// Max is the maximum allowed value for a QUIC varint (2^62-1).
|
|
Max = maxVarInt8
|
|
|
|
maxVarInt1 = 63
|
|
maxVarInt2 = 16383
|
|
maxVarInt4 = 1073741823
|
|
maxVarInt8 = 4611686018427387903
|
|
)
|
|
|
|
// Read reads a number in the QUIC varint format from r.
|
|
func Read(r io.ByteReader) (uint64, error) {
|
|
firstByte, err := r.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 := r.ReadByte()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if len == 2 {
|
|
return uint64(b2) + uint64(b1)<<8, nil
|
|
}
|
|
b3, err := r.ReadByte()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b4, err := r.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 := r.ReadByte()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b6, err := r.ReadByte()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b7, err := r.ReadByte()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
b8, err := r.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
|
|
}
|
|
|
|
// Append appends i in the QUIC varint format.
|
|
func Append(b []byte, i uint64) []byte {
|
|
if i <= maxVarInt1 {
|
|
return append(b, uint8(i))
|
|
}
|
|
if i <= maxVarInt2 {
|
|
return append(b, []byte{uint8(i>>8) | 0x40, uint8(i)}...)
|
|
}
|
|
if i <= maxVarInt4 {
|
|
return append(b, []byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}...)
|
|
}
|
|
if i <= maxVarInt8 {
|
|
return append(b, []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),
|
|
}...)
|
|
}
|
|
panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
|
|
}
|
|
|
|
// AppendWithLen append i in the QUIC varint format with the desired length.
|
|
func AppendWithLen(b []byte, i uint64, length protocol.ByteCount) []byte {
|
|
if length != 1 && length != 2 && length != 4 && length != 8 {
|
|
panic("invalid varint length")
|
|
}
|
|
l := Len(i)
|
|
if l == length {
|
|
return Append(b, i)
|
|
}
|
|
if l > length {
|
|
panic(fmt.Sprintf("cannot encode %d in %d bytes", i, length))
|
|
}
|
|
if length == 2 {
|
|
b = append(b, 0b01000000)
|
|
} else if length == 4 {
|
|
b = append(b, 0b10000000)
|
|
} else if length == 8 {
|
|
b = append(b, 0b11000000)
|
|
}
|
|
for j := protocol.ByteCount(1); j < length-l; j++ {
|
|
b = append(b, 0)
|
|
}
|
|
for j := protocol.ByteCount(0); j < l; j++ {
|
|
b = append(b, uint8(i>>(8*(l-1-j))))
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Len determines the number of bytes that will be needed to write the number i.
|
|
func Len(i uint64) protocol.ByteCount {
|
|
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})
|
|
}
|