| // 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 |
| } |