118 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
| // 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
 | |
| }
 |