varint.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. package qpack
  2. // copied from the Go standard library HPACK implementation
  3. import "errors"
  4. var errVarintOverflow = errors.New("varint integer overflow")
  5. // appendVarInt appends i, as encoded in variable integer form using n
  6. // bit prefix, to dst and returns the extended buffer.
  7. //
  8. // See
  9. // http://http2.github.io/http2-spec/compression.html#integer.representation
  10. func appendVarInt(dst []byte, n byte, i uint64) []byte {
  11. k := uint64((1 << n) - 1)
  12. if i < k {
  13. return append(dst, byte(i))
  14. }
  15. dst = append(dst, byte(k))
  16. i -= k
  17. for ; i >= 128; i >>= 7 {
  18. dst = append(dst, byte(0x80|(i&0x7f)))
  19. }
  20. return append(dst, byte(i))
  21. }
  22. // readVarInt reads an unsigned variable length integer off the
  23. // beginning of p. n is the parameter as described in
  24. // http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
  25. //
  26. // n must always be between 1 and 8.
  27. //
  28. // The returned remain buffer is either a smaller suffix of p, or err != nil.
  29. // The error is errNeedMore if p doesn't contain a complete integer.
  30. func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
  31. if n < 1 || n > 8 {
  32. panic("bad n")
  33. }
  34. if len(p) == 0 {
  35. return 0, p, errNeedMore
  36. }
  37. i = uint64(p[0])
  38. if n < 8 {
  39. i &= (1 << uint64(n)) - 1
  40. }
  41. if i < (1<<uint64(n))-1 {
  42. return i, p[1:], nil
  43. }
  44. origP := p
  45. p = p[1:]
  46. var m uint64
  47. for len(p) > 0 {
  48. b := p[0]
  49. p = p[1:]
  50. i += uint64(b&127) << m
  51. if b&128 == 0 {
  52. return i, p, nil
  53. }
  54. m += 7
  55. if m >= 63 { // TODO: proper overflow check. making this up.
  56. return 0, origP, errVarintOverflow
  57. }
  58. }
  59. return 0, origP, errNeedMore
  60. }