github.com/Psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/gquic-go/internal/utils/varint.go (about) 1 package utils 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 8 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic/gquic-go/internal/protocol" 9 ) 10 11 // taken from the QUIC draft 12 const ( 13 maxVarInt1 = 63 14 maxVarInt2 = 16383 15 maxVarInt4 = 1073741823 16 maxVarInt8 = 4611686018427387903 17 ) 18 19 // ReadVarInt reads a number in the QUIC varint format 20 func ReadVarInt(b io.ByteReader) (uint64, error) { 21 firstByte, err := b.ReadByte() 22 if err != nil { 23 return 0, err 24 } 25 // the first two bits of the first byte encode the length 26 len := 1 << ((firstByte & 0xc0) >> 6) 27 b1 := firstByte & (0xff - 0xc0) 28 if len == 1 { 29 return uint64(b1), nil 30 } 31 b2, err := b.ReadByte() 32 if err != nil { 33 return 0, err 34 } 35 if len == 2 { 36 return uint64(b2) + uint64(b1)<<8, nil 37 } 38 b3, err := b.ReadByte() 39 if err != nil { 40 return 0, err 41 } 42 b4, err := b.ReadByte() 43 if err != nil { 44 return 0, err 45 } 46 if len == 4 { 47 return uint64(b4) + uint64(b3)<<8 + uint64(b2)<<16 + uint64(b1)<<24, nil 48 } 49 b5, err := b.ReadByte() 50 if err != nil { 51 return 0, err 52 } 53 b6, err := b.ReadByte() 54 if err != nil { 55 return 0, err 56 } 57 b7, err := b.ReadByte() 58 if err != nil { 59 return 0, err 60 } 61 b8, err := b.ReadByte() 62 if err != nil { 63 return 0, err 64 } 65 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 66 } 67 68 // WriteVarInt writes a number in the QUIC varint format 69 func WriteVarInt(b *bytes.Buffer, i uint64) { 70 if i <= maxVarInt1 { 71 b.WriteByte(uint8(i)) 72 } else if i <= maxVarInt2 { 73 b.Write([]byte{uint8(i>>8) | 0x40, uint8(i)}) 74 } else if i <= maxVarInt4 { 75 b.Write([]byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}) 76 } else if i <= maxVarInt8 { 77 b.Write([]byte{ 78 uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32), 79 uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), 80 }) 81 } else { 82 panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i)) 83 } 84 } 85 86 // VarIntLen determines the number of bytes that will be needed to write a number 87 func VarIntLen(i uint64) protocol.ByteCount { 88 if i <= maxVarInt1 { 89 return 1 90 } 91 if i <= maxVarInt2 { 92 return 2 93 } 94 if i <= maxVarInt4 { 95 return 4 96 } 97 if i <= maxVarInt8 { 98 return 8 99 } 100 panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i)) 101 }