You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
2.3 KiB
118 lines
2.3 KiB
// Copyright 2018 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package osp
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
const (
|
|
maxInt6 = 1<<5 - 1
|
|
maxInt14 = 1<<13 - 1
|
|
maxInt30 = 1<<29 - 1
|
|
maxInt62 = 1<<63 - 1
|
|
)
|
|
|
|
// https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-16
|
|
func ReadVaruint(r io.Reader) (uint64, error) {
|
|
b0, err := readByte(r)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var a [8]byte
|
|
b := a[:]
|
|
e := binary.BigEndian
|
|
b[0] = last6Bits(b0)
|
|
switch first2Bits(b0) {
|
|
case 0:
|
|
return uint64(b[0]), nil
|
|
case 1:
|
|
err = readBytes(r, b[1:2])
|
|
return uint64(e.Uint16(b)), err
|
|
case 2:
|
|
err = readBytes(r, b[1:4])
|
|
return uint64(e.Uint32(b)), err
|
|
case 3:
|
|
err = readBytes(r, b[1:8])
|
|
return uint64(e.Uint64(b)), err
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
// https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-16
|
|
func WriteVaruint(v uint64, w io.Writer) error {
|
|
var a [8]byte
|
|
b := a[:]
|
|
e := binary.BigEndian
|
|
if v <= maxInt6 {
|
|
b[0] = byte(v)
|
|
setFirst2Bits(0, b)
|
|
return writeBytes(b[:1], w)
|
|
} else if v <= maxInt14 {
|
|
e.PutUint16(b, uint16(v))
|
|
setFirst2Bits(1, b)
|
|
return writeBytes(b[:2], w)
|
|
} else if v <= maxInt30 {
|
|
e.PutUint32(b, uint32(v))
|
|
setFirst2Bits(2, b)
|
|
return writeBytes(b[:4], w)
|
|
} else if v <= maxInt62 {
|
|
e.PutUint64(b, v)
|
|
setFirst2Bits(3, b)
|
|
return writeBytes(b[:8], w)
|
|
}
|
|
return errors.New("Too big")
|
|
}
|
|
|
|
func first2Bits(b byte) byte {
|
|
return b >> 6
|
|
}
|
|
|
|
func last6Bits(b byte) byte {
|
|
return b & 0x3f // 0b00111111
|
|
}
|
|
|
|
func setFirst2Bits(first byte, b []byte) {
|
|
b[0] = (first << 6) | b[0]
|
|
}
|
|
|
|
func readByte(r io.Reader) (byte, error) {
|
|
var b [1]byte
|
|
err := readBytes(r, b[:])
|
|
return b[0], err
|
|
}
|
|
|
|
// Read len(b) bytes from r into b
|
|
// If you hit an error (of the end), propogate the error from r.Read
|
|
func readBytes(r io.Reader, b []byte) error {
|
|
start := 0
|
|
end := len(b)
|
|
for start < end {
|
|
n, err := r.Read(b[start:end])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
start += n
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Write len(b) bytes from b to w
|
|
// If you hit an error, propogate the error from w.Write
|
|
func writeBytes(b []byte, w io.Writer) error {
|
|
start := 0
|
|
end := len(b)
|
|
for start < end {
|
|
n, err := w.Write(b[start:end])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
start += n
|
|
}
|
|
return nil
|
|
}
|