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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21
package quic
import "encoding/binary"
const (
maxVarintSize = 8 // encoded size in bytes
maxVarint = (1 << 62) - 1
)
// consumeVarint parses a variable-length integer, reporting its length.
// It returns a negative length upon an error.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-16
func consumeVarint(b []byte) (v uint64, n int) {
if len(b) < 1 {
return 0, -1
}
b0 := b[0] & 0x3f
switch b[0] >> 6 {
case 0:
return uint64(b0), 1
case 1:
if len(b) < 2 {
return 0, -1
}
return uint64(b0)<<8 | uint64(b[1]), 2
case 2:
if len(b) < 4 {
return 0, -1
}
return uint64(b0)<<24 | uint64(b[1])<<16 | uint64(b[2])<<8 | uint64(b[3]), 4
case 3:
if len(b) < 8 {
return 0, -1
}
return uint64(b0)<<56 | uint64(b[1])<<48 | uint64(b[2])<<40 | uint64(b[3])<<32 | uint64(b[4])<<24 | uint64(b[5])<<16 | uint64(b[6])<<8 | uint64(b[7]), 8
}
return 0, -1
}
// consumeVarint64 parses a variable-length integer as an int64.
func consumeVarintInt64(b []byte) (v int64, n int) {
u, n := consumeVarint(b)
// QUIC varints are 62-bits large, so this conversion can never overflow.
return int64(u), n
}
// appendVarint appends a variable-length integer to b.
//
// https://www.rfc-editor.org/rfc/rfc9000.html#section-16
func appendVarint(b []byte, v uint64) []byte {
switch {
case v <= 63:
return append(b, byte(v))
case v <= 16383:
return append(b, (1<<6)|byte(v>>8), byte(v))
case v <= 1073741823:
return append(b, (2<<6)|byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
case v <= 4611686018427387903:
return append(b, (3<<6)|byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
default:
panic("varint too large")
}
}
// sizeVarint returns the size of the variable-length integer encoding of f.
func sizeVarint(v uint64) int {
switch {
case v <= 63:
return 1
case v <= 16383:
return 2
case v <= 1073741823:
return 4
case v <= 4611686018427387903:
return 8
default:
panic("varint too large")
}
}
// consumeUint32 parses a 32-bit fixed-length, big-endian integer, reporting its length.
// It returns a negative length upon an error.
func consumeUint32(b []byte) (uint32, int) {
if len(b) < 4 {
return 0, -1
}
return binary.BigEndian.Uint32(b), 4
}
// consumeUint64 parses a 64-bit fixed-length, big-endian integer, reporting its length.
// It returns a negative length upon an error.
func consumeUint64(b []byte) (uint64, int) {
if len(b) < 8 {
return 0, -1
}
return binary.BigEndian.Uint64(b), 8
}
// consumeUint8Bytes parses a sequence of bytes prefixed with an 8-bit length,
// reporting the total number of bytes consumed.
// It returns a negative length upon an error.
func consumeUint8Bytes(b []byte) ([]byte, int) {
if len(b) < 1 {
return nil, -1
}
size := int(b[0])
const n = 1
if size > len(b[n:]) {
return nil, -1
}
return b[n:][:size], size + n
}
// appendUint8Bytes appends a sequence of bytes prefixed by an 8-bit length.
func appendUint8Bytes(b, v []byte) []byte {
if len(v) > 0xff {
panic("uint8-prefixed bytes too large")
}
b = append(b, uint8(len(v)))
b = append(b, v...)
return b
}
// consumeVarintBytes parses a sequence of bytes preceded by a variable-length integer length,
// reporting the total number of bytes consumed.
// It returns a negative length upon an error.
func consumeVarintBytes(b []byte) ([]byte, int) {
size, n := consumeVarint(b)
if n < 0 {
return nil, -1
}
if size > uint64(len(b[n:])) {
return nil, -1
}
return b[n:][:size], int(size) + n
}
// appendVarintBytes appends a sequence of bytes prefixed by a variable-length integer length.
func appendVarintBytes(b, v []byte) []byte {
b = appendVarint(b, uint64(len(v)))
b = append(b, v...)
return b
}
|