github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/quicvarint/varint.go (about)

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