blob: 2a7e59f66c7fd15738c2d6b5a8ac985a182671a7 [file] [log] [blame]
package codec
import (
"errors"
"fmt"
"io"
"math"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
)
// ErrOverflow is returned when an integer is too large to be represented.
var ErrOverflow = errors.New("proto: integer overflow")
// ErrBadWireType is returned when decoding a wire-type from a buffer that
// is not valid.
var ErrBadWireType = errors.New("proto: bad wiretype")
var varintTypes = map[descriptor.FieldDescriptorProto_Type]bool{}
var fixed32Types = map[descriptor.FieldDescriptorProto_Type]bool{}
var fixed64Types = map[descriptor.FieldDescriptorProto_Type]bool{}
func init() {
varintTypes[descriptor.FieldDescriptorProto_TYPE_BOOL] = true
varintTypes[descriptor.FieldDescriptorProto_TYPE_INT32] = true
varintTypes[descriptor.FieldDescriptorProto_TYPE_INT64] = true
varintTypes[descriptor.FieldDescriptorProto_TYPE_UINT32] = true
varintTypes[descriptor.FieldDescriptorProto_TYPE_UINT64] = true
varintTypes[descriptor.FieldDescriptorProto_TYPE_SINT32] = true
varintTypes[descriptor.FieldDescriptorProto_TYPE_SINT64] = true
varintTypes[descriptor.FieldDescriptorProto_TYPE_ENUM] = true
fixed32Types[descriptor.FieldDescriptorProto_TYPE_FIXED32] = true
fixed32Types[descriptor.FieldDescriptorProto_TYPE_SFIXED32] = true
fixed32Types[descriptor.FieldDescriptorProto_TYPE_FLOAT] = true
fixed64Types[descriptor.FieldDescriptorProto_TYPE_FIXED64] = true
fixed64Types[descriptor.FieldDescriptorProto_TYPE_SFIXED64] = true
fixed64Types[descriptor.FieldDescriptorProto_TYPE_DOUBLE] = true
}
func (cb *Buffer) decodeVarintSlow() (x uint64, err error) {
i := cb.index
l := len(cb.buf)
for shift := uint(0); shift < 64; shift += 7 {
if i >= l {
err = io.ErrUnexpectedEOF
return
}
b := cb.buf[i]
i++
x |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
cb.index = i
return
}
}
// The number is too large to represent in a 64-bit value.
err = ErrOverflow
return
}
// DecodeVarint reads a varint-encoded integer from the Buffer.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func (cb *Buffer) DecodeVarint() (uint64, error) {
i := cb.index
buf := cb.buf
if i >= len(buf) {
return 0, io.ErrUnexpectedEOF
} else if buf[i] < 0x80 {
cb.index++
return uint64(buf[i]), nil
} else if len(buf)-i < 10 {
return cb.decodeVarintSlow()
}
var b uint64
// we already checked the first byte
x := uint64(buf[i]) - 0x80
i++
b = uint64(buf[i])
i++
x += b << 7
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 7
b = uint64(buf[i])
i++
x += b << 14
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 14
b = uint64(buf[i])
i++
x += b << 21
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 21
b = uint64(buf[i])
i++
x += b << 28
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 28
b = uint64(buf[i])
i++
x += b << 35
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 35
b = uint64(buf[i])
i++
x += b << 42
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 42
b = uint64(buf[i])
i++
x += b << 49
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 49
b = uint64(buf[i])
i++
x += b << 56
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 56
b = uint64(buf[i])
i++
x += b << 63
if b&0x80 == 0 {
goto done
}
// x -= 0x80 << 63 // Always zero.
return 0, ErrOverflow
done:
cb.index = i
return x, nil
}
// DecodeTagAndWireType decodes a field tag and wire type from input.
// This reads a varint and then extracts the two fields from the varint
// value read.
func (cb *Buffer) DecodeTagAndWireType() (tag int32, wireType int8, err error) {
var v uint64
v, err = cb.DecodeVarint()
if err != nil {
return
}
// low 7 bits is wire type
wireType = int8(v & 7)
// rest is int32 tag number
v = v >> 3
if v > math.MaxInt32 {
err = fmt.Errorf("tag number out of range: %d", v)
return
}
tag = int32(v)
return
}
// DecodeFixed64 reads a 64-bit integer from the Buffer.
// This is the format for the
// fixed64, sfixed64, and double protocol buffer types.
func (cb *Buffer) DecodeFixed64() (x uint64, err error) {
// x, err already 0
i := cb.index + 8
if i < 0 || i > len(cb.buf) {
err = io.ErrUnexpectedEOF
return
}
cb.index = i
x = uint64(cb.buf[i-8])
x |= uint64(cb.buf[i-7]) << 8
x |= uint64(cb.buf[i-6]) << 16
x |= uint64(cb.buf[i-5]) << 24
x |= uint64(cb.buf[i-4]) << 32
x |= uint64(cb.buf[i-3]) << 40
x |= uint64(cb.buf[i-2]) << 48
x |= uint64(cb.buf[i-1]) << 56
return
}
// DecodeFixed32 reads a 32-bit integer from the Buffer.
// This is the format for the
// fixed32, sfixed32, and float protocol buffer types.
func (cb *Buffer) DecodeFixed32() (x uint64, err error) {
// x, err already 0
i := cb.index + 4
if i < 0 || i > len(cb.buf) {
err = io.ErrUnexpectedEOF
return
}
cb.index = i
x = uint64(cb.buf[i-4])
x |= uint64(cb.buf[i-3]) << 8
x |= uint64(cb.buf[i-2]) << 16
x |= uint64(cb.buf[i-1]) << 24
return
}
// DecodeZigZag32 decodes a signed 32-bit integer from the given
// zig-zag encoded value.
func DecodeZigZag32(v uint64) int32 {
return int32((uint32(v) >> 1) ^ uint32((int32(v&1)<<31)>>31))
}
// DecodeZigZag64 decodes a signed 64-bit integer from the given
// zig-zag encoded value.
func DecodeZigZag64(v uint64) int64 {
return int64((v >> 1) ^ uint64((int64(v&1)<<63)>>63))
}
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
// This is the format used for the bytes protocol buffer
// type and for embedded messages.
func (cb *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) {
n, err := cb.DecodeVarint()
if err != nil {
return nil, err
}
nb := int(n)
if nb < 0 {
return nil, fmt.Errorf("proto: bad byte length %d", nb)
}
end := cb.index + nb
if end < cb.index || end > len(cb.buf) {
return nil, io.ErrUnexpectedEOF
}
if !alloc {
buf = cb.buf[cb.index:end]
cb.index = end
return
}
buf = make([]byte, nb)
copy(buf, cb.buf[cb.index:])
cb.index = end
return
}
// ReadGroup reads the input until a "group end" tag is found
// and returns the data up to that point. Subsequent reads from
// the buffer will read data after the group end tag. If alloc
// is true, the data is copied to a new slice before being returned.
// Otherwise, the returned slice is a view into the buffer's
// underlying byte slice.
//
// This function correctly handles nested groups: if a "group start"
// tag is found, then that group's end tag will be included in the
// returned data.
func (cb *Buffer) ReadGroup(alloc bool) ([]byte, error) {
var groupEnd, dataEnd int
groupEnd, dataEnd, err := cb.findGroupEnd()
if err != nil {
return nil, err
}
var results []byte
if !alloc {
results = cb.buf[cb.index:dataEnd]
} else {
results = make([]byte, dataEnd-cb.index)
copy(results, cb.buf[cb.index:])
}
cb.index = groupEnd
return results, nil
}
// SkipGroup is like ReadGroup, except that it discards the
// data and just advances the buffer to point to the input
// right *after* the "group end" tag.
func (cb *Buffer) SkipGroup() error {
groupEnd, _, err := cb.findGroupEnd()
if err != nil {
return err
}
cb.index = groupEnd
return nil
}
func (cb *Buffer) findGroupEnd() (groupEnd int, dataEnd int, err error) {
bs := cb.buf
start := cb.index
defer func() {
cb.index = start
}()
for {
fieldStart := cb.index
// read a field tag
_, wireType, err := cb.DecodeTagAndWireType()
if err != nil {
return 0, 0, err
}
// skip past the field's data
switch wireType {
case proto.WireFixed32:
if err := cb.Skip(4); err != nil {
return 0, 0, err
}
case proto.WireFixed64:
if err := cb.Skip(8); err != nil {
return 0, 0, err
}
case proto.WireVarint:
// skip varint by finding last byte (has high bit unset)
i := cb.index
limit := i + 10 // varint cannot be >10 bytes
for {
if i >= limit {
return 0, 0, ErrOverflow
}
if i >= len(bs) {
return 0, 0, io.ErrUnexpectedEOF
}
if bs[i]&0x80 == 0 {
break
}
i++
}
// TODO: This would only overflow if buffer length was MaxInt and we
// read the last byte. This is not a real/feasible concern on 64-bit
// systems. Something to worry about for 32-bit systems? Do we care?
cb.index = i + 1
case proto.WireBytes:
l, err := cb.DecodeVarint()
if err != nil {
return 0, 0, err
}
if err := cb.Skip(int(l)); err != nil {
return 0, 0, err
}
case proto.WireStartGroup:
if err := cb.SkipGroup(); err != nil {
return 0, 0, err
}
case proto.WireEndGroup:
return cb.index, fieldStart, nil
default:
return 0, 0, ErrBadWireType
}
}
}