| // Copyright 2016 The Vanadium 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 vom |
| |
| import ( |
| "errors" |
| "fmt" |
| "io" |
| "math" |
| "os" |
| |
| "v.io/v23/vdl" |
| "v.io/v23/verror" |
| ) |
| |
| const ( |
| // IEEE 754 represents float64 using 52 bits to represent the mantissa, with |
| // an extra implied leading bit. That gives us 53 bits to store integers |
| // without overflow - i.e. [0, (2^53)-1]. And since 2^53 is a small power of |
| // two, it can also be stored without loss via mantissa=1 exponent=53. Thus |
| // we have our max and min values. Ditto for float32, which uses 23 bits with |
| // an extra implied leading bit. |
| float64MaxInt = (1 << 53) |
| float64MinInt = -(1 << 53) |
| float32MaxInt = (1 << 24) |
| float32MinInt = -(1 << 24) |
| ) |
| |
| var ( |
| errEmptyDecoderStack = errors.New("vom: empty decoder stack") |
| errReadRawBytesAlreadyStarted = errors.New("vom: read into vom.RawBytes after StartValue called") |
| errReadRawBytesFromNonAny = errors.New("vom: read into vom.RawBytes only supported on any values") |
| ) |
| |
| // This is only used for debugging; add this as the first line of NewDecoder to |
| // dump formatted vom bytes to stdout: |
| // r = teeDump(r) |
| func teeDump(r io.Reader) io.Reader { |
| return io.TeeReader(r, NewDumper(NewDumpWriter(os.Stdout))) |
| } |
| |
| // Decoder manages the receipt and unmarshalling of typed values from the other |
| // side of a connection. |
| type Decoder struct { |
| dec decoder81 |
| } |
| |
| type decoder81 struct { |
| buf *decbuf |
| flag decFlag |
| stack []decStackEntry |
| refTypes referencedTypes |
| refAnyLens referencedAnyLens |
| typeDec *TypeDecoder |
| } |
| |
| type decStackEntry struct { |
| Type *vdl.Type // Type of the value that we're decoding. |
| Index int // Index of the key, elem or field. |
| LenHint int // Length of the value, or -1 for unknown. |
| NextEntryType *vdl.Type // type for NextEntryValue* methods |
| Flag decStackFlag // properties of this stack entry |
| NextEntryData nextEntryData // properties of the next entry |
| } |
| |
| // decFlag holds properties of the decoder. |
| type decFlag uint |
| |
| const ( |
| decFlagIgnoreNextStartValue decFlag = 0x1 // ignore the next call to StartValue |
| decFlagIsParentBytes decFlag = 0x2 // parent type is []byte or [N]byte |
| decFlagTypeIncomplete decFlag = 0x4 // type has dependencies on unsent types |
| decFlagSeparateTypeDec decFlag = 0x8 // type decoder is separate |
| |
| // In FinishValue we need to clear both of these bits. |
| decFlagFinishValue decFlag = decFlagIgnoreNextStartValue | decFlagIsParentBytes |
| ) |
| |
| func (f decFlag) Set(bits decFlag) decFlag { return f | bits } |
| func (f decFlag) Clear(bits decFlag) decFlag { return f &^ bits } |
| |
| func (f decFlag) IgnoreNextStartValue() bool { return f&decFlagIgnoreNextStartValue != 0 } |
| func (f decFlag) IsParentBytes() bool { return f&decFlagIsParentBytes != 0 } |
| func (f decFlag) TypeIncomplete() bool { return f&decFlagTypeIncomplete != 0 } |
| func (f decFlag) SeparateTypeDec() bool { return f&decFlagSeparateTypeDec != 0 } |
| |
| // decStackFlag holds type or value properties of the stack entry. |
| type decStackFlag uint |
| |
| const ( |
| decStackFlagIsMapKey decStackFlag = 0x1 // key or elem for dfsNextType |
| decStackFlagIsAny decStackFlag = 0x2 // the static type is Any |
| decStackFlagIsOptional decStackFlag = 0x4 // the static type is Optional |
| decStackFlagFastRead decStackFlag = 0x8 // subtypes use ReadValue fastpath |
| ) |
| |
| func (f decStackFlag) FlipIsMapKey() decStackFlag { return f ^ decStackFlagIsMapKey } |
| func (f decStackFlag) IsMapKey() bool { return f&decStackFlagIsMapKey != 0 } |
| func (f decStackFlag) IsAny() bool { return f&decStackFlagIsAny != 0 } |
| func (f decStackFlag) IsOptional() bool { return f&decStackFlagIsOptional != 0 } |
| func (f decStackFlag) FastRead() bool { return f&decStackFlagFastRead != 0 } |
| |
| // NewDecoder returns a new Decoder that reads from the given reader. The |
| // Decoder understands all formats generated by the Encoder. |
| func NewDecoder(r io.Reader) *Decoder { |
| buf := newDecbuf(r) |
| typeDec := newTypeDecoderInternal(buf) |
| return &Decoder{decoder81{ |
| buf: buf, |
| typeDec: typeDec, |
| }} |
| } |
| |
| // NewDecoderWithTypeDecoder returns a new Decoder that reads from the given |
| // reader. Types are decoded separately through the typeDec. |
| func NewDecoderWithTypeDecoder(r io.Reader, typeDec *TypeDecoder) *Decoder { |
| return &Decoder{decoder81{ |
| buf: newDecbuf(r), |
| typeDec: typeDec, |
| flag: decFlagSeparateTypeDec, |
| }} |
| } |
| |
| // Decoder returns d as a vdl.Decoder. |
| func (d *Decoder) Decoder() vdl.Decoder { |
| return &d.dec |
| } |
| |
| // Decode reads the next value and stores it in value v. The type of v need not |
| // exactly match the type of the originally encoded value; decoding succeeds as |
| // long as the values are convertible. |
| func (d *Decoder) Decode(v interface{}) error { |
| return vdl.Read(&d.dec, v) |
| } |
| |
| func (d *decoder81) IgnoreNextStartValue() { |
| d.flag = d.flag.Set(decFlagIgnoreNextStartValue) |
| } |
| |
| func (d *decoder81) decodeWireType(wt *wireType) (TypeId, error) { |
| // Type messages are just a regularly encoded wireType, which is a union. To |
| // decode we pre-populate the stack with an entry for the wire type, and run |
| // the code-generated __VDLRead_wireType method. |
| tid, err := d.nextMessage() |
| if err != nil { |
| return 0, err |
| } |
| d.stack = append(d.stack, decStackEntry{ |
| Type: wireTypeType, |
| Index: -1, |
| LenHint: 1, // wireType is a union |
| }) |
| d.flag = d.flag.Set(decFlagIgnoreNextStartValue) |
| if err := __VDLRead_wireType(d, wt); err != nil { |
| return 0, err |
| } |
| return tid, nil |
| } |
| |
| // readRawBytes fills in raw with the next value. It can be called for both |
| // top-level and internal values. |
| func (d *decoder81) readRawBytes(raw *RawBytes) error { |
| if d.flag.IgnoreNextStartValue() { |
| // If the user has already called StartValue on the decoder, it's harder to |
| // capture all the raw bytes, since the optional flag and length hints have |
| // already been decoded. So we simply disallow this from happening. |
| return errReadRawBytesAlreadyStarted |
| } |
| tt, err := d.dfsNextType() |
| if err != nil { |
| return err |
| } |
| // Handle top-level values. All types of values are supported, since we can |
| // simply copy the message bytes. |
| if len(d.stack) == 0 { |
| anyLen, err := d.peekValueByteLen(tt) |
| if err != nil { |
| return err |
| } |
| if err := d.decodeRaw(tt, anyLen, raw); err != nil { |
| return err |
| } |
| return d.endMessage() |
| } |
| // Handle internal values. Only any values are supported at the moment, since |
| // they come with a header that tells us the exact length to read. |
| // |
| // TODO(toddw): Handle other types, either by reading and skipping bytes based |
| // on the type, or by falling back to a decode / re-encode slowpath. |
| if tt.Kind() != vdl.Any { |
| return errReadRawBytesFromNonAny |
| } |
| ttElem, anyLen, err := d.readAnyHeader() |
| if err != nil { |
| return err |
| } |
| if ttElem == nil { |
| // This is a nil any value, which has already been read by readAnyHeader. |
| // We simply fill in RawBytes with the single WireCtrlNil byte. |
| raw.Version = d.buf.version |
| raw.Type = vdl.AnyType |
| raw.RefTypes = nil |
| raw.AnyLengths = nil |
| raw.Data = []byte{WireCtrlNil} |
| return nil |
| } |
| return d.decodeRaw(ttElem, anyLen, raw) |
| } |
| |
| func (d *decoder81) StartValue(want *vdl.Type) error { |
| if d.flag.IgnoreNextStartValue() { |
| d.flag = d.flag.Clear(decFlagIgnoreNextStartValue) |
| return nil |
| } |
| tt, err := d.dfsNextType() |
| if err != nil { |
| return err |
| } |
| tt, lenHint, flag, err := d.setupType(tt, want) |
| if err != nil { |
| return err |
| } |
| d.stack = append(d.stack, decStackEntry{ |
| Type: tt, |
| Index: -1, |
| LenHint: lenHint, |
| Flag: flag, |
| }) |
| return nil |
| } |
| |
| func (d *decoder81) setupType(tt, want *vdl.Type) (_ *vdl.Type, lenHint int, flag decStackFlag, _ error) { |
| // Handle any, which may be nil. We "dereference" non-nil any to the inner |
| // type. If that happens to be an optional, it's handled below. |
| if tt.Kind() == vdl.Any { |
| flag |= decStackFlagIsAny |
| var err error |
| switch tt, _, err = d.readAnyHeader(); { |
| case err != nil: |
| return nil, 0, 0, err |
| case tt == nil: |
| tt = vdl.AnyType // nil any |
| } |
| } |
| // Handle optional, which may be nil. Similar to any, we "dereference" |
| // non-nil optional to the inner type, which is never allowed to be another |
| // optional or any type. |
| if tt.Kind() == vdl.Optional { |
| flag |= decStackFlagIsOptional |
| // Read the WireCtrlNil code, but if it's not WireCtrlNil we need to keep |
| // the buffer as-is, since it's the first byte of the value, which may |
| // itself be another control code. |
| switch ctrl, err := binaryPeekControl(d.buf); { |
| case err != nil: |
| return nil, 0, 0, err |
| case ctrl == WireCtrlNil: |
| d.buf.SkipAvailable(1) // nil optional |
| default: |
| tt = tt.Elem() // non-nil optional |
| } |
| } |
| // Check compatibility between the actual type and the want type. Since |
| // compatibility applies to the entire static type, we only need to perform |
| // this check for top-level decoded values, and subsequently for decoded any |
| // values. We skip checking non-composite want types, since those will be |
| // naturally caught by the Decode* calls anyways. |
| if want != nil && (len(d.stack) == 0 || flag.IsAny()) { |
| switch want.Kind() { |
| case vdl.Optional, vdl.Array, vdl.List, vdl.Set, vdl.Map, vdl.Struct, vdl.Union: |
| if tt == want { |
| // Set FastRead flag, which will let us use the fastpath for ReadValue* |
| // in common cases. We can only use this fastpath if tt and want are |
| // identical, which ensures we don't need to perform any conversions. |
| if !flag.IsAny() && isFastReadParent(tt) { |
| flag |= decStackFlagFastRead |
| } |
| // Regardless of whether we can use the fastpath, there's no need to |
| // check compatibility if tt and want are identical. |
| } else { |
| if !vdl.Compatible(tt, want) { |
| return nil, 0, 0, errIncompatibleDecode(tt, want) |
| } |
| } |
| } |
| } |
| // Initialize LenHint for composite types. |
| switch tt.Kind() { |
| case vdl.Array, vdl.List, vdl.Set, vdl.Map: |
| // TODO(toddw): Handle sentry-terminated collections without a length hint. |
| len, err := binaryDecodeLenOrArrayLen(d.buf, tt) |
| if err != nil { |
| return nil, 0, 0, err |
| } |
| lenHint = len |
| case vdl.Union: |
| // Union shouldn't have a LenHint, but we abuse it in NextField as a |
| // convenience for detecting when fields are done, so we initialize it here. |
| // It has to be at least 1, since 0 will cause NextField to think that the |
| // union field has already been decoded. |
| lenHint = 1 |
| case vdl.Struct: |
| // Struct shouldn't have a LenHint, but we abuse it in NextField as a |
| // convenience for detecting when fields are done, so we initialize it here. |
| lenHint = tt.NumField() |
| default: |
| lenHint = -1 |
| } |
| if top := d.top(); top != nil && top.Type.IsBytes() { |
| d.flag = d.flag.Set(decFlagIsParentBytes) |
| } else { |
| d.flag = d.flag.Clear(decFlagIsParentBytes) |
| } |
| return tt, lenHint, flag, nil |
| } |
| |
| func errIncompatibleDecode(tt *vdl.Type, want interface{}) error { |
| return fmt.Errorf("vom: incompatible decode from %v into %v", tt, want) |
| } |
| |
| func (d *decoder81) FinishValue() error { |
| d.flag = d.flag.Clear(decFlagFinishValue) |
| stackTop := len(d.stack) - 1 |
| if stackTop == -1 { |
| return errEmptyDecoderStack |
| } |
| d.stack = d.stack[:stackTop] |
| if stackTop == 0 { |
| return d.endMessage() |
| } |
| return nil |
| } |
| |
| func (d *decoder81) top() *decStackEntry { |
| if stackTop := len(d.stack) - 1; stackTop >= 0 { |
| return &d.stack[stackTop] |
| } |
| return nil |
| } |
| |
| // dfsNextType determines the type of the next value that we will decode, by |
| // walking the static type in DFS order. To bootstrap we retrieve the top-level |
| // type from the VOM value message. |
| func (d *decoder81) dfsNextType() (*vdl.Type, error) { |
| top := d.top() |
| if top == nil { |
| // Bootstrap: start decoding a new top-level value. |
| if !d.flag.SeparateTypeDec() { |
| if err := d.decodeTypeDefs(); err != nil { |
| return nil, err |
| } |
| } |
| tid, err := d.nextMessage() |
| if err != nil { |
| return nil, err |
| } |
| return d.typeDec.lookupType(tid) |
| } |
| // Return the next type from our composite types. |
| tt := top.Type |
| switch tt.Kind() { |
| case vdl.Array, vdl.List: |
| return tt.Elem(), nil |
| case vdl.Set: |
| return tt.Key(), nil |
| case vdl.Map: |
| top.Flag = top.Flag.FlipIsMapKey() |
| if top.Flag.IsMapKey() { |
| return tt.Key(), nil |
| } else { |
| return tt.Elem(), nil |
| } |
| case vdl.Union, vdl.Struct: |
| return tt.Field(top.Index).Type, nil |
| } |
| return nil, fmt.Errorf("vom: can't StartValue on %v", tt) |
| } |
| |
| func (d *decoder81) NextEntry() (bool, error) { |
| // Our strategy is to increment top.Index until it reaches top.LenHint. |
| // Currently the LenHint is always set, so it's stronger than a hint. |
| // |
| // TODO(toddw): Handle sentry-terminated collections without a LenHint. |
| top := d.top() |
| if top == nil { |
| return false, errEmptyDecoderStack |
| } |
| // Increment index and check errors. |
| top.Index++ |
| switch top.Type.Kind() { |
| case vdl.Array, vdl.List, vdl.Set, vdl.Map: |
| if top.Index > top.LenHint && top.LenHint >= 0 { |
| return false, fmt.Errorf("vom: NextEntry called after done, stack: %+v", d.stack) |
| } |
| default: |
| return false, fmt.Errorf("vom: NextEntry called on invalid type, stack: %+v", d.stack) |
| } |
| return top.Index == top.LenHint, nil |
| } |
| |
| func (d *decoder81) NextField() (int, error) { |
| top := d.top() |
| if top == nil { |
| return -1, errEmptyDecoderStack |
| } |
| // Increment index and check errors. Note that the actual top.Index is |
| // decoded from the buf data stream; we use top.LenHint to help detect when |
| // the fields are done, and to detect invalid calls after we're done. |
| top.Index++ |
| switch top.Type.Kind() { |
| case vdl.Union, vdl.Struct: |
| if top.Index > top.LenHint { |
| return -1, fmt.Errorf("vom: NextField called after done, stack: %+v", d.stack) |
| } |
| default: |
| return -1, fmt.Errorf("vom: NextField called on invalid type, stack: %+v", d.stack) |
| } |
| var field int |
| switch top.Type.Kind() { |
| case vdl.Union: |
| if top.Index == top.LenHint { |
| // We know we're done since we set LenHint=Index+1 the first time around, |
| // and we incremented the index above. |
| return -1, nil |
| } |
| // Decode the union field index. |
| switch index, err := binaryDecodeUint(d.buf); { |
| case err != nil: |
| return -1, err |
| case index >= uint64(top.Type.NumField()): |
| return -1, verror.New(errIndexOutOfRange, nil) |
| default: |
| // Set LenHint=Index+1 so that we'll know we're done next time around. |
| field = int(index) |
| top.Index = field |
| top.LenHint = field + 1 |
| } |
| case vdl.Struct: |
| // Handle the end-of-struct sentry. |
| switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlEnd); { |
| case err != nil: |
| return -1, err |
| case ok: |
| // Set Index=LenHint to ensure repeated calls will fail. |
| top.Index = top.LenHint |
| return -1, nil |
| } |
| // Decode the struct field index. |
| switch index, err := binaryDecodeUint(d.buf); { |
| case err != nil: |
| return -1, err |
| case index >= uint64(top.Type.NumField()): |
| return -1, verror.New(errIndexOutOfRange, nil) |
| default: |
| field = int(index) |
| top.Index = field |
| } |
| } |
| return field, nil |
| } |
| |
| func (d *decoder81) Type() *vdl.Type { |
| if top := d.top(); top != nil { |
| return top.Type |
| } |
| return nil |
| } |
| |
| func (d *decoder81) IsAny() bool { |
| if top := d.top(); top != nil { |
| return top.Flag.IsAny() |
| } |
| return false |
| } |
| |
| func (d *decoder81) IsOptional() bool { |
| if top := d.top(); top != nil { |
| return top.Flag.IsOptional() |
| } |
| return false |
| } |
| |
| func (d *decoder81) IsNil() bool { |
| if top := d.top(); top != nil { |
| // Becuase of the "dereferencing" we do, the only time the type is any or |
| // optional is when it's nil. |
| return top.Type == vdl.AnyType || top.Type.Kind() == vdl.Optional |
| } |
| return false |
| } |
| |
| func (d *decoder81) Index() int { |
| if top := d.top(); top != nil { |
| return top.Index |
| } |
| return -1 |
| } |
| |
| func (d *decoder81) LenHint() int { |
| if top := d.top(); top != nil { |
| // Note that union and struct shouldn't have a LenHint, but we abuse it in |
| // NextField as a convenience for detecting when fields are done, so an |
| // "arbitrary" value is returned here. Users shouldn't be looking at it for |
| // union and struct anyways. |
| return top.LenHint |
| } |
| return -1 |
| } |
| |
| func (d *decoder81) DecodeBool() (bool, error) { |
| tt := d.Type() |
| if tt == nil { |
| return false, errEmptyDecoderStack |
| } |
| if tt.Kind() == vdl.Bool { |
| return binaryDecodeBool(d.buf) |
| } |
| return false, errIncompatibleDecode(tt, "bool") |
| } |
| |
| func (d *decoder81) DecodeString() (string, error) { |
| tt := d.Type() |
| if tt == nil { |
| return "", errEmptyDecoderStack |
| } |
| switch tt.Kind() { |
| case vdl.String: |
| return binaryDecodeString(d.buf) |
| case vdl.Enum: |
| return d.binaryDecodeEnum(tt) |
| } |
| return "", errIncompatibleDecode(tt, "string") |
| } |
| |
| func (d *decoder81) binaryDecodeEnum(tt *vdl.Type) (string, error) { |
| index, err := binaryDecodeUint(d.buf) |
| switch { |
| case err != nil: |
| return "", err |
| case index >= uint64(tt.NumEnumLabel()): |
| return "", fmt.Errorf("vom: enum index %d out of range, %v", index, tt) |
| } |
| return tt.EnumLabel(int(index)), nil |
| } |
| |
| func (d *decoder81) binaryDecodeByte() (byte, error) { |
| // Handle a special-case where normally single bytes are written out as |
| // variable sized numbers, which use 2 bytes to encode bytes > 127. But each |
| // byte contained in a list or array is written out as one byte. E.g. |
| // byte(0x81) -> 0xFF81 : single byte with variable-size |
| // []byte("\x81\x82") -> 0x028182 : each elem byte encoded as one byte |
| if d.flag.IsParentBytes() { |
| return d.buf.ReadByte() |
| } |
| x, err := binaryDecodeUint(d.buf) |
| return byte(x), err |
| } |
| |
| func (d *decoder81) DecodeUint(bitlen int) (uint64, error) { |
| tt := d.Type() |
| if tt == nil { |
| return 0, errEmptyDecoderStack |
| } |
| return d.decodeUint(tt, uint(bitlen)) |
| } |
| |
| func (d *decoder81) decodeUint(tt *vdl.Type, ubitlen uint) (uint64, error) { |
| const errFmt = "vom: conversion from %v into uint%d loses precision: %v" |
| switch tt.Kind() { |
| case vdl.Byte: |
| x, err := d.binaryDecodeByte() |
| if err != nil { |
| return 0, err |
| } |
| return uint64(x), err |
| case vdl.Uint16, vdl.Uint32, vdl.Uint64: |
| x, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| if shift := 64 - ubitlen; x != (x<<shift)>>shift { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return x, nil |
| case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64: |
| x, err := binaryDecodeInt(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| ux := uint64(x) |
| if shift := 64 - ubitlen; x < 0 || ux != (ux<<shift)>>shift { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return ux, nil |
| case vdl.Float32, vdl.Float64: |
| x, err := binaryDecodeFloat(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| ux := uint64(x) |
| if shift := 64 - ubitlen; x != float64(ux) || ux != (ux<<shift)>>shift { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return ux, nil |
| } |
| return 0, errIncompatibleDecode(tt, fmt.Sprintf("uint%d", ubitlen)) |
| } |
| |
| func (d *decoder81) DecodeInt(bitlen int) (int64, error) { |
| tt := d.Type() |
| if tt == nil { |
| return 0, errEmptyDecoderStack |
| } |
| return d.decodeInt(tt, uint(bitlen)) |
| } |
| |
| func (d *decoder81) decodeInt(tt *vdl.Type, ubitlen uint) (int64, error) { |
| const errFmt = "vom: conversion from %v into int%d loses precision: %v" |
| switch tt.Kind() { |
| case vdl.Byte: |
| x, err := d.binaryDecodeByte() |
| if err != nil { |
| return 0, err |
| } |
| // The only case that fails is if we're converting byte(x) to int8, and x |
| // uses more than 7 bits (i.e. is greater than 127). |
| if ubitlen <= 8 && x > 0x7f { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return int64(x), nil |
| case vdl.Uint16, vdl.Uint32, vdl.Uint64: |
| x, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| ix := int64(x) |
| // The shift uses 65 since the topmost bit is the sign bit. I.e. 32 bit |
| // numbers should be shifted by 33 rather than 32. |
| if shift := 65 - ubitlen; ix < 0 || x != (x<<shift)>>shift { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return ix, nil |
| case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64: |
| x, err := binaryDecodeInt(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| if shift := 64 - ubitlen; x != (x<<shift)>>shift { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return x, nil |
| case vdl.Float32, vdl.Float64: |
| x, err := binaryDecodeFloat(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| ix := int64(x) |
| if shift := 64 - ubitlen; x != float64(ix) || ix != (ix<<shift)>>shift { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return ix, nil |
| } |
| return 0, errIncompatibleDecode(tt, fmt.Sprintf("int%d", ubitlen)) |
| } |
| |
| func (d *decoder81) DecodeFloat(bitlen int) (float64, error) { |
| tt := d.Type() |
| if tt == nil { |
| return 0, errEmptyDecoderStack |
| } |
| return d.decodeFloat(tt, uint(bitlen)) |
| } |
| |
| func (d *decoder81) decodeFloat(tt *vdl.Type, ubitlen uint) (float64, error) { |
| const errFmt = "vom: conversion from %v into float%d loses precision: %v" |
| switch tt.Kind() { |
| case vdl.Byte: |
| x, err := d.binaryDecodeByte() |
| if err != nil { |
| return 0, err |
| } |
| return float64(x), nil |
| case vdl.Uint16, vdl.Uint32, vdl.Uint64: |
| x, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| var max uint64 |
| if ubitlen > 32 { |
| max = float64MaxInt |
| } else { |
| max = float32MaxInt |
| } |
| if x > max { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return float64(x), nil |
| case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64: |
| x, err := binaryDecodeInt(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| var min, max int64 |
| if ubitlen > 32 { |
| min, max = float64MinInt, float64MaxInt |
| } else { |
| min, max = float32MinInt, float32MaxInt |
| } |
| if x < min || x > max { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return float64(x), nil |
| case vdl.Float32, vdl.Float64: |
| x, err := binaryDecodeFloat(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| if ubitlen <= 32 && (x < -math.MaxFloat32 || x > math.MaxFloat32) { |
| return 0, fmt.Errorf(errFmt, tt, ubitlen, x) |
| } |
| return x, nil |
| } |
| return 0, errIncompatibleDecode(tt, fmt.Sprintf("float%d", ubitlen)) |
| } |
| |
| func (d *decoder81) DecodeBytes(fixedLen int, v *[]byte) error { |
| top := d.top() |
| if top == nil { |
| return errEmptyDecoderStack |
| } |
| tt := top.Type |
| if !tt.IsBytes() { |
| return vdl.DecodeConvertedBytes(d, fixedLen, v) |
| } |
| return d.decodeBytes(tt, top.LenHint, fixedLen, v) |
| } |
| |
| func (d *decoder81) decodeBytes(tt *vdl.Type, lenHint, fixedLen int, v *[]byte) error { |
| switch { |
| case lenHint == -1: |
| return fmt.Errorf("vom: LenHint is currently required, %v", tt) |
| case fixedLen >= 0 && fixedLen != lenHint: |
| return fmt.Errorf("vom: got %d bytes, want fixed len %d, %v", lenHint, fixedLen, tt) |
| case lenHint == 0: |
| *v = nil |
| return nil |
| case fixedLen >= 0: |
| // Only re-use the existing buffer if we're filling in an array. This |
| // sacrifices some performance, but also avoids bugs when repeatedly |
| // decoding into the same value. |
| *v = (*v)[:lenHint] |
| default: |
| *v = make([]byte, lenHint) |
| } |
| return d.buf.ReadIntoBuf(*v) |
| } |
| |
| func (d *decoder81) DecodeTypeObject() (*vdl.Type, error) { |
| tt := d.Type() |
| if tt == nil { |
| return nil, errEmptyDecoderStack |
| } |
| if tt != vdl.TypeObjectType { |
| return nil, errIncompatibleDecode(tt, "typeobject") |
| } |
| return d.binaryDecodeType() |
| } |
| |
| func (d *decoder81) binaryDecodeType() (*vdl.Type, error) { |
| typeIndex, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return nil, err |
| } |
| tid, err := d.refTypes.ReferencedTypeId(typeIndex) |
| if err != nil { |
| return nil, err |
| } |
| return d.typeDec.lookupType(tid) |
| } |
| |
| func (d *decoder81) SkipValue() error { |
| tt, err := d.dfsNextType() |
| if err != nil { |
| return err |
| } |
| if len(d.stack) == 0 { |
| // Handle top-level values. It's easy to determine the byte length of the |
| // value, so we can just skip the bytes. |
| valueLen, err := d.peekValueByteLen(tt) |
| if err != nil { |
| return err |
| } |
| if err := d.buf.Skip(valueLen); err != nil { |
| return err |
| } |
| return d.endMessage() |
| } |
| return d.skipValue(tt) |
| } |