148 lines
3.4 KiB
Go
148 lines
3.4 KiB
Go
|
// Copyright © 2016 Abcum Ltd
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
package bytes
|
||
|
|
||
|
import (
|
||
|
"encoding"
|
||
|
"encoding/binary"
|
||
|
"errors"
|
||
|
"io"
|
||
|
"reflect"
|
||
|
)
|
||
|
|
||
|
type Decoder struct {
|
||
|
Order binary.ByteOrder
|
||
|
r *reader
|
||
|
}
|
||
|
|
||
|
func NewDecoder(r io.Reader) *Decoder {
|
||
|
return &Decoder{
|
||
|
Order: binary.BigEndian,
|
||
|
r: &reader{r},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (d *Decoder) Decode(v interface{}) (err error) {
|
||
|
// Check if the type implements the encoding.BinaryUnmarshaler interface, and use it if so.
|
||
|
if i, ok := v.(encoding.BinaryUnmarshaler); ok {
|
||
|
var l uint64
|
||
|
if l, err = binary.ReadUvarint(d.r); err != nil {
|
||
|
return
|
||
|
}
|
||
|
buf := make([]byte, l)
|
||
|
_, err = d.r.Read(buf)
|
||
|
return i.UnmarshalBinary(buf)
|
||
|
}
|
||
|
|
||
|
// Otherwise, use reflection.
|
||
|
rv := reflect.Indirect(reflect.ValueOf(v))
|
||
|
if !rv.CanAddr() {
|
||
|
return errors.New("binary: can only Decode to pointer type")
|
||
|
}
|
||
|
t := rv.Type()
|
||
|
|
||
|
switch t.Kind() {
|
||
|
|
||
|
case reflect.Array:
|
||
|
len := t.Len()
|
||
|
for i := 0; i < int(len); i++ {
|
||
|
if err = d.Decode(rv.Index(i).Addr().Interface()); err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case reflect.Slice:
|
||
|
var l uint64
|
||
|
if l, err = binary.ReadUvarint(d.r); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if t.Kind() == reflect.Slice {
|
||
|
rv.Set(reflect.MakeSlice(t, int(l), int(l)))
|
||
|
} else if int(l) != t.Len() {
|
||
|
return errors.New("binary: encoded size != real size")
|
||
|
}
|
||
|
for i := 0; i < int(l); i++ {
|
||
|
if err = d.Decode(rv.Index(i).Addr().Interface()); err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case reflect.Struct:
|
||
|
l := rv.NumField()
|
||
|
for i := 0; i < l; i++ {
|
||
|
if v := rv.Field(i); v.CanSet() && t.Field(i).Name != "_" {
|
||
|
if err = d.Decode(v.Addr().Interface()); err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case reflect.Map:
|
||
|
var l uint64
|
||
|
if l, err = binary.ReadUvarint(d.r); err != nil {
|
||
|
return
|
||
|
}
|
||
|
kt := t.Key()
|
||
|
vt := t.Elem()
|
||
|
rv.Set(reflect.MakeMap(t))
|
||
|
for i := 0; i < int(l); i++ {
|
||
|
kv := reflect.Indirect(reflect.New(kt))
|
||
|
if err = d.Decode(kv.Addr().Interface()); err != nil {
|
||
|
return
|
||
|
}
|
||
|
vv := reflect.Indirect(reflect.New(vt))
|
||
|
if err = d.Decode(vv.Addr().Interface()); err != nil {
|
||
|
return
|
||
|
}
|
||
|
rv.SetMapIndex(kv, vv)
|
||
|
}
|
||
|
|
||
|
case reflect.String:
|
||
|
var l uint64
|
||
|
if l, err = binary.ReadUvarint(d.r); err != nil {
|
||
|
return
|
||
|
}
|
||
|
buf := make([]byte, l)
|
||
|
_, err = d.r.Read(buf)
|
||
|
rv.SetString(string(buf))
|
||
|
|
||
|
case reflect.Bool:
|
||
|
var out byte
|
||
|
err = binary.Read(d.r, d.Order, &out)
|
||
|
rv.SetBool(out != 0)
|
||
|
|
||
|
case reflect.Int:
|
||
|
var out int64
|
||
|
err = binary.Read(d.r, d.Order, &out)
|
||
|
rv.SetInt(out)
|
||
|
|
||
|
case reflect.Uint:
|
||
|
var out uint64
|
||
|
err = binary.Read(d.r, d.Order, &out)
|
||
|
rv.SetUint(out)
|
||
|
|
||
|
case reflect.Int8, reflect.Uint8, reflect.Int16, reflect.Uint16,
|
||
|
reflect.Int32, reflect.Uint32, reflect.Int64, reflect.Uint64,
|
||
|
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
|
||
|
err = binary.Read(d.r, d.Order, v)
|
||
|
|
||
|
default:
|
||
|
return errors.New("binary: unsupported type " + t.String())
|
||
|
}
|
||
|
|
||
|
return
|
||
|
|
||
|
}
|