| // Copyright 2015 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 ( |
| "io" |
| "os" |
| "reflect" |
| |
| "v.io/v23/vdl" |
| "v.io/v23/verror" |
| ) |
| |
| var ( |
| errDecodeNil = verror.Register(pkgPath+".errDecodeNil", verror.NoRetry, "{1:}{2:} vom: invalid decode into nil interface{}{:_}") |
| errDecodeZeroTypeID = verror.Register(pkgPath+".errDecodeZeroTypeID", verror.NoRetry, "{1:}{2:} vom: zero type id{:_}") |
| errIndexOutOfRange = verror.Register(pkgPath+".errIndexOutOfRange", verror.NoRetry, "{1:}{2:} vom: index out of range{:_}") |
| errLeftOverBytes = verror.Register(pkgPath+".errLeftOverBytes", verror.NoRetry, "{1:}{2:} vom: {3} leftover bytes{:_}") |
| errUnexpectedControlByte = verror.Register(pkgPath+".errUnexpectedControlByte", verror.NoRetry, "{1:}{2:} vom: unexpected control byte {3}{:_}") |
| errDecodeValueUnhandledType = verror.Register(pkgPath+".errDecodeValueUnhandledType", verror.NoRetry, "{1:}{2:} vom: decodeValue unhandled type {3}{:_}") |
| errIgnoreValueUnhandledType = verror.Register(pkgPath+".errIgnoreValueUnhandledType", verror.NoRetry, "{1:}{2:} vom: ignoreValue unhandled type {3}{:_}") |
| errInvalidTypeIdIndex = verror.Register(pkgPath+".errInvalidTypeIdIndex", verror.NoRetry, "{1:}{2:} vom: value referenced invalid index into type id table {:_}") |
| errInvalidAnyIndex = verror.Register(pkgPath+".errInvalidAnyIndex", verror.NoRetry, "{1:}{2:} vom: value referenced invalid index into anyLen table {:_}") |
| ) |
| |
| // Decoder manages the receipt and unmarshalling of typed values from the other |
| // side of a connection. |
| type Decoder struct { |
| typeDec *TypeDecoder |
| |
| hasSeparateTypeDec bool // TODO(bprosnitz) This should probably be removed. |
| |
| // Stream data: |
| buf *decbuf |
| |
| // Message data: |
| typeIncomplete bool // Type message was flagged as having dependencies on unsent types. |
| refTypes referencedTypes |
| refAnyLens referencedAnyLens |
| } |
| |
| // 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))) |
| } |
| |
| // 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 { |
| // When the TypeDecoder isn't shared, we always decode type messages in |
| // Decoder.decodeValueType() and feed them to the TypeDecoder. That is, |
| // the TypeDecoder will never read messages from the buffer. So we pass |
| // a nil buffer to newTypeDecoder. |
| buf := newDecbuf(r) |
| typeDec := newTypeDecoderInternal(buf) |
| return &Decoder{ |
| buf: buf, |
| typeDec: typeDec, |
| hasSeparateTypeDec: false, |
| } |
| } |
| |
| // NewDecoderWithTypeDecoder returns a new Decoder that reads from the given |
| // reader. Types will be decoded separately through the given typeDec. |
| func NewDecoderWithTypeDecoder(r io.Reader, typeDec *TypeDecoder) *Decoder { |
| return &Decoder{ |
| buf: newDecbuf(r), |
| typeDec: typeDec, |
| hasSeparateTypeDec: true, |
| } |
| } |
| |
| // Decode reads the next value from the reader(s) 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 compatible. |
| // |
| // Types that are special-cased, only for v: |
| // *RawBytes - Store raw (uninterpreted) bytes in v. |
| // |
| // Types that are special-cased, recursively throughout v: |
| // *vdl.Value - Decode into v. |
| // reflect.Value - Decode into v, which must be settable. |
| // |
| // Decoding into a RawBytes captures the value in a raw form, which may be |
| // subsequently passed to an Encoder for transcoding. |
| // |
| // Decode(nil) always returns an error. Use Ignore() to ignore the next value. |
| func (d *Decoder) Decode(v interface{}) error { |
| if v == nil { |
| return verror.New(errDecodeNil, nil) |
| } |
| target, err := vdl.ReflectTarget(reflect.ValueOf(v)) |
| if err != nil { |
| return err |
| } |
| return d.decodeToTarget(target) |
| } |
| |
| func (d *Decoder) decodeTypeDefs() error { |
| if !d.hasSeparateTypeDec { |
| for { |
| typeNext, err := d.typeIsNext() |
| if err != nil { |
| return err |
| } |
| if !typeNext { |
| break |
| } |
| if err := d.typeDec.readSingleType(); err != nil { |
| return err |
| } |
| } |
| } |
| return nil |
| } |
| |
| func (d *Decoder) decodeToTarget(target vdl.Target) error { |
| if err := d.decodeTypeDefs(); err != nil { |
| return err |
| } |
| tid, err := d.nextMessage() |
| if err != nil { |
| return err |
| } |
| valType, err := d.typeDec.lookupType(tid) |
| if err != nil { |
| return err |
| } |
| if hax, ok := target.(hasRvHack); ok { |
| rv := hax.HackGetRv() |
| valLen, err := d.peekValueByteLen(valType) |
| if err != nil { |
| return err |
| } |
| if isRawBytes, err := d.tryDecodeRaw(valType, valLen, rv); err != nil { |
| return err |
| } else if isRawBytes { |
| return d.endMessage() |
| } |
| } |
| if err := d.decodeValue(valType, target); err != nil { |
| return err |
| } |
| return d.endMessage() |
| } |
| |
| // Ignore ignores the next value from the reader. |
| func (d *Decoder) Ignore() error { |
| if err := d.decodeTypeDefs(); err != nil { |
| return err |
| } |
| tid, err := d.nextMessage() |
| if err != nil { |
| return err |
| } |
| valType, err := d.typeDec.lookupType(tid) |
| if err != nil { |
| return err |
| } |
| valLen, err := d.peekValueByteLen(valType) |
| if err != nil { |
| return err |
| } |
| |
| if err := d.buf.Skip(valLen); err != nil { |
| return err |
| } |
| return d.endMessage() |
| } |
| |
| // decodeWireType decodes the next type definition message and returns its |
| // type id. |
| func (d *Decoder) decodeWireType(wt *wireType) (TypeId, error) { |
| tid, err := d.nextMessage() |
| if err != nil { |
| return 0, err |
| } |
| // Decode the wire type like a regular value. |
| target, err := vdl.ReflectTarget(reflect.ValueOf(wt)) |
| if err != nil { |
| return 0, err |
| } |
| if err := d.decodeValue(wireTypeType, target); err != nil { |
| return 0, err |
| } |
| return tid, d.endMessage() |
| } |
| |
| // peekValueByteLen returns the byte length of the next value. |
| func (d *Decoder) peekValueByteLen(tt *vdl.Type) (int, error) { |
| if hasChunkLen(tt) { |
| // Use the explicit message length. |
| return d.buf.lim, nil |
| } |
| // No explicit message length, but the length can be computed. |
| switch { |
| case tt.Kind() == vdl.Byte: |
| if d.buf.version == Version80 { |
| return 1, nil |
| } else { |
| return binaryPeekUintByteLen(d.buf) |
| } |
| case tt.Kind() == vdl.Array && tt.IsBytes(): |
| // Byte arrays are exactly their length and encoded with 1-byte header. |
| return tt.Len() + 1, nil |
| case tt.Kind() == vdl.String || tt.IsBytes(): |
| // Strings and byte lists are encoded with a length header. |
| strlen, bytelen, err := binaryPeekUint(d.buf) |
| switch { |
| case err != nil: |
| return 0, err |
| case strlen > maxBinaryMsgLen: |
| return 0, verror.New(errMsgLen, nil) |
| } |
| return int(strlen) + bytelen, nil |
| default: |
| // Must be a primitive, which is encoded as an underlying uint. |
| return binaryPeekUintByteLen(d.buf) |
| } |
| } |
| |
| func (d *Decoder) decodeRaw(tt *vdl.Type, valLen int, raw *RawBytes) error { |
| raw.Version = d.buf.version |
| raw.Type = tt |
| raw.Data = make([]byte, valLen) |
| if err := d.buf.ReadIntoBuf(raw.Data); err != nil { |
| return err |
| } |
| refTypeLen := len(d.refTypes.tids) |
| if cap(raw.RefTypes) >= refTypeLen { |
| raw.RefTypes = raw.RefTypes[:refTypeLen] |
| } else { |
| raw.RefTypes = make([]*vdl.Type, refTypeLen) |
| } |
| for i, tid := range d.refTypes.tids { |
| var err error |
| if raw.RefTypes[i], err = d.typeDec.lookupType(tid); err != nil { |
| return err |
| } |
| } |
| raw.AnyLengths = d.refAnyLens.lens |
| return nil |
| } |
| |
| type hasRvHack interface { |
| HackGetRv() reflect.Value |
| } |
| |
| func (d *Decoder) tryDecodeRaw(tt *vdl.Type, valLen int, rv reflect.Value) (isRawBytes bool, _ error) { |
| // Dereference pointers down to at most one remaining *. |
| for rv.IsValid() && rv.Kind() == reflect.Ptr && rv.Elem().IsValid() && rv.Elem().Kind() == reflect.Ptr { |
| rv = rv.Elem() |
| } |
| if rv.IsValid() && rv.Type() == rtPtrToRawBytes { |
| rb := rv.Interface().(*RawBytes) |
| if rb == nil { |
| rb = new(RawBytes) |
| rv.Set(reflect.ValueOf(rb)) |
| } |
| return true, d.decodeRaw(tt, valLen, rb) |
| } |
| if rv.IsValid() && rv.Type() == rtRawBytes { |
| rb := rv.Addr().Interface().(*RawBytes) |
| if err := d.decodeRaw(tt, valLen, rb); err != nil { |
| return true, err |
| } |
| return true, nil |
| } |
| return false, nil |
| } |
| |
| // decodeValue decodes the rest of the message assuming type tt. |
| func (d *Decoder) decodeValue(tt *vdl.Type, target vdl.Target) error { |
| ttFrom := tt |
| if tt.Kind() == vdl.Optional { |
| // If the type is optional, we expect to see either WireCtrlNil or the actual |
| // value, but not both. And thus, we can just peek for the WireCtrlNil here. |
| switch ctrl, err := binaryPeekControl(d.buf); { |
| case err != nil: |
| return err |
| case ctrl == WireCtrlNil: |
| d.buf.Skip(1) |
| return target.FromNil(ttFrom) |
| } |
| tt = tt.Elem() |
| } |
| if tt.IsBytes() { |
| len, err := binaryDecodeLenOrArrayLen(d.buf, tt) |
| if err != nil { |
| return err |
| } |
| // TODO(toddw): remove allocation |
| buf := make([]byte, len) |
| if err := d.buf.ReadIntoBuf(buf); err != nil { |
| return err |
| } |
| return target.FromBytes(buf, ttFrom) |
| } |
| switch kind := tt.Kind(); kind { |
| case vdl.Bool: |
| v, err := binaryDecodeBool(d.buf) |
| if err != nil { |
| return err |
| } |
| return target.FromBool(v, ttFrom) |
| case vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64: |
| var v uint64 |
| if tt.Kind() == vdl.Byte && d.buf.version == Version80 { |
| b, err := d.buf.ReadByte() |
| if err != nil { |
| return err |
| } |
| v = uint64(b) |
| } else { |
| var err error |
| v, err = binaryDecodeUint(d.buf) |
| if err != nil { |
| return err |
| } |
| } |
| return target.FromUint(v, ttFrom) |
| case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64: |
| if d.buf.version == Version80 && tt.Kind() == vdl.Int8 { |
| return verror.New(errUnsupportedInVOMVersion, nil, "int8", d.buf.version) |
| } |
| v, err := binaryDecodeInt(d.buf) |
| if err != nil { |
| return err |
| } |
| return target.FromInt(v, ttFrom) |
| case vdl.Float32, vdl.Float64: |
| v, err := binaryDecodeFloat(d.buf) |
| if err != nil { |
| return err |
| } |
| return target.FromFloat(v, ttFrom) |
| case vdl.String: |
| v, err := binaryDecodeString(d.buf) |
| if err != nil { |
| return err |
| } |
| return target.FromString(v, ttFrom) |
| case vdl.Enum: |
| index, err := binaryDecodeUint(d.buf) |
| switch { |
| case err != nil: |
| return err |
| case index >= uint64(tt.NumEnumLabel()): |
| return verror.New(errIndexOutOfRange, nil) |
| } |
| return target.FromEnumLabel(tt.EnumLabel(int(index)), ttFrom) |
| case vdl.TypeObject: |
| x, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return err |
| } |
| var tid TypeId |
| if d.buf.version == Version80 { |
| tid = TypeId(x) |
| } else { |
| tid, err = d.refTypes.ReferencedTypeId(x) |
| if err != nil { |
| return err |
| } |
| } |
| typeobject, err := d.typeDec.lookupType(tid) |
| if err != nil { |
| return err |
| } |
| return target.FromTypeObject(typeobject) |
| case vdl.Array, vdl.List: |
| len, err := binaryDecodeLenOrArrayLen(d.buf, tt) |
| if err != nil { |
| return err |
| } |
| listTarget, err := target.StartList(ttFrom, len) |
| if err != nil { |
| return err |
| } |
| for ix := 0; ix < len; ix++ { |
| elem, err := listTarget.StartElem(ix) |
| if err != nil { |
| return err |
| } |
| if err := d.decodeValue(tt.Elem(), elem); err != nil { |
| return err |
| } |
| if err := listTarget.FinishElem(elem); err != nil { |
| return err |
| } |
| } |
| return target.FinishList(listTarget) |
| case vdl.Set: |
| len, err := binaryDecodeLen(d.buf) |
| if err != nil { |
| return err |
| } |
| setTarget, err := target.StartSet(ttFrom, len) |
| if err != nil { |
| return err |
| } |
| for ix := 0; ix < len; ix++ { |
| key, err := setTarget.StartKey() |
| if err != nil { |
| return err |
| } |
| if err := d.decodeValue(tt.Key(), key); err != nil { |
| return err |
| } |
| switch err := setTarget.FinishKey(key); { |
| case err == vdl.ErrFieldNoExist: |
| continue |
| case err != nil: |
| return err |
| } |
| } |
| return target.FinishSet(setTarget) |
| case vdl.Map: |
| len, err := binaryDecodeLen(d.buf) |
| if err != nil { |
| return err |
| } |
| mapTarget, err := target.StartMap(ttFrom, len) |
| if err != nil { |
| return err |
| } |
| for ix := 0; ix < len; ix++ { |
| key, err := mapTarget.StartKey() |
| if err != nil { |
| return err |
| } |
| if err := d.decodeValue(tt.Key(), key); err != nil { |
| return err |
| } |
| switch field, err := mapTarget.FinishKeyStartField(key); { |
| case err == vdl.ErrFieldNoExist: |
| if err := d.ignoreValue(tt.Elem()); err != nil { |
| return err |
| } |
| case err != nil: |
| return err |
| default: |
| if err := d.decodeValue(tt.Elem(), field); err != nil { |
| return err |
| } |
| if err := mapTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| } |
| } |
| return target.FinishMap(mapTarget) |
| case vdl.Struct: |
| fieldsTarget, err := target.StartFields(ttFrom) |
| if err != nil { |
| return err |
| } |
| // Loop through decoding the 0-based field index and corresponding field. |
| decodedFields := make([]bool, tt.NumField()) |
| for { |
| index, ctrl, err := binaryDecodeUintWithControl(d.buf) |
| switch { |
| case err != nil: |
| return err |
| case ctrl == WireCtrlEnd: |
| // Fill not-yet-decoded fields with their zero values. |
| for index, decoded := range decodedFields { |
| if decoded { |
| continue |
| } |
| ttfield := tt.Field(index) |
| switch err := fieldsTarget.ZeroField(ttfield.Name); { |
| case err == vdl.ErrFieldNoExist: |
| // Ignore it. |
| case err != nil: |
| return err |
| |
| } |
| } |
| return target.FinishFields(fieldsTarget) |
| case ctrl != 0: |
| return verror.New(errUnexpectedControlByte, nil, ctrl) |
| case index >= uint64(tt.NumField()): |
| return verror.New(errIndexOutOfRange, nil) |
| } |
| ttfield := tt.Field(int(index)) |
| switch key, field, err := fieldsTarget.StartField(ttfield.Name); { |
| case err == vdl.ErrFieldNoExist: |
| if err := d.ignoreValue(ttfield.Type); err != nil { |
| return err |
| } |
| case err != nil: |
| return err |
| default: |
| if err := d.decodeValue(ttfield.Type, field); err != nil { |
| return err |
| } |
| if err := fieldsTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| } |
| decodedFields[index] = true |
| } |
| case vdl.Union: |
| fieldsTarget, err := target.StartFields(ttFrom) |
| if err != nil { |
| return err |
| } |
| index, err := binaryDecodeUint(d.buf) |
| switch { |
| case err != nil: |
| return err |
| case index >= uint64(tt.NumField()): |
| return verror.New(errIndexOutOfRange, nil) |
| } |
| ttfield := tt.Field(int(index)) |
| key, field, err := fieldsTarget.StartField(ttfield.Name) |
| if err != nil { |
| return err |
| } |
| if err := d.decodeValue(ttfield.Type, field); err != nil { |
| return err |
| } |
| if err := fieldsTarget.FinishField(key, field); err != nil { |
| return err |
| } |
| return target.FinishFields(fieldsTarget) |
| case vdl.Any: |
| elemType, valLen, err := d.readAnyHeader() |
| if err != nil { |
| return err |
| } |
| if elemType == nil { |
| return target.FromNil(tt) |
| } |
| if hax, ok := target.(hasRvHack); ok { |
| rv := hax.HackGetRv() |
| if isRawBytes, err := d.tryDecodeRaw(elemType, valLen, rv); isRawBytes { |
| return err |
| } |
| } |
| return d.decodeValue(elemType, target) |
| default: |
| panic(verror.New(errDecodeValueUnhandledType, nil, tt)) |
| } |
| } |
| |
| func (d *Decoder) readAnyHeader() (*vdl.Type, int, error) { |
| // Read either WireCtrlNil or the index of the referenced type id. |
| typeIndex, ctrl, err := binaryDecodeUintWithControl(d.buf) |
| switch { |
| case err != nil: |
| return nil, 0, err |
| case ctrl == WireCtrlNil: |
| return nil, 0, nil // nil any |
| case ctrl != 0: |
| return nil, 0, verror.New(errUnexpectedControlByte, nil, ctrl) |
| } |
| var tid TypeId |
| if d.buf.version == Version80 { |
| tid = TypeId(typeIndex) |
| } else if tid, err = d.refTypes.ReferencedTypeId(typeIndex); err != nil { |
| return nil, 0, err |
| } |
| // Look up the referenced type id. |
| ttElem, err := d.typeDec.lookupType(tid) |
| if err != nil { |
| return nil, 0, err |
| } |
| var anyLen int |
| if d.buf.version != Version80 { |
| // Read and lookup the index of the any byte length. Reference the any len, |
| // even if it isn't used, to report missing references. |
| lenIndex, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return nil, 0, err |
| } |
| if anyLen, err = d.refAnyLens.ReferencedAnyLen(lenIndex); err != nil { |
| return nil, 0, err |
| } |
| } |
| return ttElem, anyLen, nil |
| } |
| |
| // ignoreValue ignores the rest of the value of type t. This is used to ignore |
| // unknown struct fields. |
| func (d *Decoder) ignoreValue(tt *vdl.Type) error { |
| // TODO(toddw): How about ignoring optional values? |
| if tt.IsBytes() { |
| len, err := binaryDecodeLenOrArrayLen(d.buf, tt) |
| if err != nil { |
| return err |
| } |
| return d.buf.Skip(len) |
| } |
| switch kind := tt.Kind(); kind { |
| case vdl.Bool: |
| return d.buf.Skip(1) |
| case vdl.Byte: |
| if d.buf.version == Version80 { |
| return d.buf.Skip(1) |
| } else { |
| return binaryIgnoreUint(d.buf) |
| } |
| case vdl.Uint16, vdl.Uint32, vdl.Uint64, vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Float32, vdl.Float64, vdl.Enum, vdl.TypeObject: |
| if d.buf.version == Version80 && tt.Kind() == vdl.Int8 { |
| return verror.New(errUnsupportedInVOMVersion, nil, "int8", d.buf.version) |
| } |
| // The underlying encoding of all these types is based on uint. |
| return binaryIgnoreUint(d.buf) |
| case vdl.String: |
| return binaryIgnoreString(d.buf) |
| case vdl.Array, vdl.List, vdl.Set, vdl.Map: |
| len, err := binaryDecodeLenOrArrayLen(d.buf, tt) |
| if err != nil { |
| return err |
| } |
| for ix := 0; ix < len; ix++ { |
| if kind == vdl.Set || kind == vdl.Map { |
| if err := d.ignoreValue(tt.Key()); err != nil { |
| return err |
| } |
| } |
| if kind == vdl.Array || kind == vdl.List || kind == vdl.Map { |
| if err := d.ignoreValue(tt.Elem()); err != nil { |
| return err |
| } |
| } |
| } |
| return nil |
| case vdl.Struct: |
| // Loop through decoding the 0-based field index and corresponding field. |
| for { |
| switch index, ctrl, err := binaryDecodeUintWithControl(d.buf); { |
| case err != nil: |
| return err |
| case ctrl == WireCtrlEnd: |
| return nil |
| case ctrl != 0: |
| return verror.New(errUnexpectedControlByte, nil, ctrl) |
| case index >= uint64(tt.NumField()): |
| return verror.New(errIndexOutOfRange, nil) |
| default: |
| ttfield := tt.Field(int(index)) |
| if err := d.ignoreValue(ttfield.Type); err != nil { |
| return err |
| } |
| } |
| } |
| case vdl.Union: |
| switch index, err := binaryDecodeUint(d.buf); { |
| case err != nil: |
| return err |
| case index >= uint64(tt.NumField()): |
| return verror.New(errIndexOutOfRange, nil) |
| default: |
| ttfield := tt.Field(int(index)) |
| return d.ignoreValue(ttfield.Type) |
| } |
| case vdl.Any: |
| var elemTid TypeId |
| switch x, ctrl, err := binaryDecodeUintWithControl(d.buf); { |
| case err != nil: |
| return err |
| case ctrl == WireCtrlNil: |
| return nil |
| case ctrl != 0: |
| return verror.New(errUnexpectedControlByte, nil, ctrl) |
| case d.buf.version == Version80: |
| elemTid = TypeId(x) |
| default: |
| if elemTid, err = d.refTypes.ReferencedTypeId(x); err != nil { |
| return err |
| } |
| } |
| elemType, err := d.typeDec.lookupType(elemTid) |
| if err != nil { |
| return err |
| } |
| return d.ignoreValue(elemType) |
| default: |
| panic(verror.New(errIgnoreValueUnhandledType, nil, tt)) |
| } |
| } |
| |
| func (d *Decoder) nextMessage() (TypeId, error) { |
| if leftover := d.buf.RemoveLimit(); leftover > 0 { |
| return 0, verror.New(errLeftOverBytes, nil, leftover) |
| } |
| |
| if d.buf.version == 0 { |
| version, err := d.buf.ReadByte() |
| if err != nil { |
| return 0, verror.New(errEndedBeforeVersionByte, nil, err) |
| } |
| d.buf.version = Version(version) |
| if !isAllowedVersion(d.buf.version) { |
| return 0, verror.New(errBadVersionByte, nil, d.buf.version) |
| } |
| } |
| |
| mid, cr, err := binaryDecodeIntWithControl(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| |
| if cr == WireCtrlTypeIncomplete { |
| mid, cr, err = binaryDecodeIntWithControl(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| |
| if cr != 0 || mid >= 0 { |
| // only can have incomplete types on new type messages |
| return 0, verror.New(errInvalid, nil) |
| } |
| |
| d.typeIncomplete = true |
| } else if mid < 0 { |
| d.typeIncomplete = false |
| } |
| |
| if cr != 0 { |
| return 0, verror.New(errBadControlCode, nil) |
| } |
| |
| var tid TypeId |
| var hasAny, hasTypeObject bool |
| var hasLength bool |
| switch { |
| case mid < 0: |
| tid = TypeId(-mid) |
| hasLength = true |
| hasAny = false |
| hasTypeObject = false |
| case mid > 0: |
| tid = TypeId(mid) |
| t, err := d.typeDec.lookupType(tid) |
| if err != nil { |
| return 0, err |
| } |
| hasLength = hasChunkLen(t) |
| hasAny = containsAny(t) |
| hasTypeObject = containsTypeObject(t) |
| default: |
| return 0, verror.New(errDecodeZeroTypeID, nil) |
| } |
| |
| if (hasAny || hasTypeObject) && d.buf.version != Version80 { |
| l, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| for i := 0; i < int(l); i++ { |
| refId, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| d.refTypes.AddTypeID(TypeId(refId)) |
| } |
| } |
| if hasAny && d.buf.version != Version80 { |
| l, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| for i := 0; i < int(l); i++ { |
| refAnyLen, err := binaryDecodeLen(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| d.refAnyLens.AddAnyLen(refAnyLen) |
| } |
| } |
| |
| if hasLength { |
| chunkLen, err := binaryDecodeUint(d.buf) |
| if err != nil { |
| return 0, err |
| } |
| d.buf.SetLimit(int(chunkLen)) |
| } |
| |
| return tid, nil |
| } |
| |
| func (d *Decoder) typeIsNext() (bool, error) { |
| if d.buf.version == 0 { |
| version, err := d.buf.ReadByte() |
| if err != nil { |
| return false, verror.New(errEndedBeforeVersionByte, nil, err) |
| } |
| d.buf.version = Version(version) |
| if !isAllowedVersion(d.buf.version) { |
| return false, verror.New(errBadVersionByte, nil, d.buf.version) |
| } |
| } |
| mid, cr, _, err := binaryPeekIntWithControl(d.buf) |
| if err != nil { |
| return false, err |
| } |
| return mid < 0 || cr == WireCtrlTypeIncomplete, nil |
| } |
| |
| func (d *Decoder) endMessage() error { |
| if leftover := d.buf.RemoveLimit(); leftover > 0 { |
| return verror.New(errLeftOverBytes, nil, leftover) |
| } |
| if err := d.refTypes.Reset(); err != nil { |
| return err |
| } |
| if err := d.refAnyLens.Reset(); err != nil { |
| return err |
| } |
| return nil |
| } |
| |
| func (d *Decoder) reset() error { |
| return nil |
| } |
| |
| type referencedTypes struct { |
| tids []TypeId |
| marker int |
| } |
| |
| func (refTypes *referencedTypes) Reset() (err error) { |
| refTypes.tids = refTypes.tids[:0] |
| refTypes.marker = 0 |
| return |
| } |
| |
| func (refTypes *referencedTypes) AddTypeID(tid TypeId) { |
| refTypes.tids = append(refTypes.tids, tid) |
| } |
| |
| func (refTypes *referencedTypes) ReferencedTypeId(index uint64) (TypeId, error) { |
| if index >= uint64(len(refTypes.tids)) { |
| return 0, verror.New(errInvalidTypeIdIndex, nil) |
| } |
| return refTypes.tids[index], nil |
| } |
| |
| func (refTypes *referencedTypes) Mark() { |
| refTypes.marker = len(refTypes.tids) |
| } |
| |
| type referencedAnyLens struct { |
| lens []int |
| marker int |
| } |
| |
| func (refAnys *referencedAnyLens) Reset() (err error) { |
| refAnys.lens = refAnys.lens[:0] |
| return |
| } |
| |
| func (refAnys *referencedAnyLens) AddAnyLen(len int) { |
| refAnys.lens = append(refAnys.lens, len) |
| } |
| |
| func (refAnys *referencedAnyLens) ReferencedAnyLen(index uint64) (int, error) { |
| if index >= uint64(len(refAnys.lens)) { |
| return 0, verror.New(errInvalidAnyIndex, nil) |
| } |
| return refAnys.lens[index], nil |
| } |
| |
| func (refAnys *referencedAnyLens) Mark() { |
| refAnys.marker = len(refAnys.lens) |
| } |