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