123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- package encoder
- import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "reflect"
- "strconv"
- "strings"
- )
- type BinaryMarshallable interface {
- MarshalBinary(*Metadata) ([]byte, error)
- UnmarshalBinary([]byte, *Metadata) (interface{}, error)
- }
- type Metadata struct {
- Tags *TagMap
- Lens map[string]uint64
- Offsets map[string]uint64
- Count map[string]uint64
- Parent interface{}
- ParentBuf []byte
- CurrOffset uint64
- CurrField string
- }
- type TagMap struct {
- m map[string]interface{}
- has map[string]bool
- }
- func (t Metadata) CurrOffsetMove(move uint64) {
- t.CurrOffset += move
- }
- func (t TagMap) Has(key string) bool {
- return t.has[key]
- }
- func (t TagMap) Set(key string, val interface{}) {
- t.m[key] = val
- t.has[key] = true
- }
- func (t TagMap) Get(key string) interface{} {
- return t.m[key]
- }
- func (t TagMap) GetInt(key string) (int, error) {
- if !t.Has(key) {
- return 0, errors.New("Key does not exist in tag")
- }
- return t.Get(key).(int), nil
- }
- func (t TagMap) GetString(key string) (string, error) {
- if !t.Has(key) {
- return "", errors.New("Key does not exist in tag")
- }
- return t.Get(key).(string), nil
- }
- func parseTags(sf reflect.StructField) (*TagMap, error) {
- ret := &TagMap{
- m: make(map[string]interface{}),
- has: make(map[string]bool),
- }
- tag := sf.Tag.Get("smb")
- smbTags := strings.Split(tag, ",")
- for _, smbTag := range smbTags {
- tokens := strings.Split(smbTag, ":")
- switch tokens[0] {
- case "len", "offset", "count":
- if len(tokens) != 2 {
- return nil, errors.New("Missing required tag data. Expecting key:val")
- }
- ret.Set(tokens[0], tokens[1])
- case "fixed":
- if len(tokens) != 2 {
- return nil, errors.New("Missing required tag data. Expecting key:val")
- }
- i, err := strconv.Atoi(tokens[1])
- if err != nil {
- return nil, err
- }
- ret.Set(tokens[0], i)
- case "asn1":
- ret.Set(tokens[0], true)
- }
- }
- return ret, nil
- }
- func getOffsetByFieldName(fieldName string, meta *Metadata) (uint64, error) {
- if meta == nil || meta.Tags == nil || meta.Parent == nil || meta.Lens == nil {
- return 0, errors.New("Cannot determine field offset. Missing required metadata")
- }
- var ret uint64
- var found bool
- parentvf := reflect.Indirect(reflect.ValueOf(meta.Parent))
- // To determine offset, we loop through all fields of the struct, summing lengths of previous elements
- // until we reach our field
- for i := 0; i < parentvf.NumField(); i++ {
- tf := parentvf.Type().Field(i)
- if tf.Name == fieldName {
- found = true
- break
- }
- if l, ok := meta.Lens[tf.Name]; ok {
- // Length of field is in cache
- ret += l
- } else {
- tags, err := parseTags(tf)
- if err != nil {
- return 0, err
- }
- if tags.Has("fixed") {
- length, err := tags.GetInt("fixed")
- if err != nil {
- return 0, err
- }
- meta.Lens[tf.Name] = uint64(length)
- } else {
- // Not in cache. Must marshal field to determine length. Add to cache after
- buf, err := Marshal(parentvf.Field(i).Interface())
- if err != nil {
- return 0, err
- }
- l := uint64(len(buf))
- meta.Lens[tf.Name] = l
- ret += l
- }
- }
- }
- if !found {
- return 0, errors.New("Cannot find field name within struct: " + fieldName)
- }
- return ret, nil
- }
- func getFieldLengthByName(fieldName string, meta *Metadata) (uint64, error) {
- var ret uint64
- if meta == nil || meta.Tags == nil || meta.Parent == nil || meta.Lens == nil {
- return 0, errors.New("Cannot determine field length. Missing required metadata")
- }
- // Check if length is stored in field length cache
- if val, ok := meta.Lens[fieldName]; ok {
- return uint64(val), nil
- }
- parentvf := reflect.Indirect(reflect.ValueOf(meta.Parent))
- field := parentvf.FieldByName(fieldName)
- if !field.IsValid() {
- return 0, errors.New("Invalid field. Cannot determine length.")
- }
- bm, ok := field.Interface().(BinaryMarshallable)
- if ok {
- // Custom marshallable interface found.
- buf, err := bm.(BinaryMarshallable).MarshalBinary(meta)
- if err != nil {
- return 0, err
- }
- return uint64(len(buf)), nil
- }
- if field.Kind() == reflect.Ptr {
- field = field.Elem()
- }
- switch field.Kind() {
- case reflect.Struct:
- buf, err := Marshal(field.Interface())
- if err != nil {
- return 0, err
- }
- ret = uint64(len(buf))
- case reflect.Interface:
- return 0, errors.New("Interface length calculation not implemented")
- case reflect.Slice, reflect.Array:
- switch field.Type().Elem().Kind() {
- case reflect.Uint8:
- ret = uint64(len(field.Interface().([]byte)))
- default:
- return 0, errors.New("Cannot calculate the length of unknown slice type for " + fieldName)
- }
- case reflect.Uint8:
- ret = uint64(binary.Size(field.Interface().(uint8)))
- case reflect.Uint16:
- ret = uint64(binary.Size(field.Interface().(uint16)))
- case reflect.Uint32:
- ret = uint64(binary.Size(field.Interface().(uint32)))
- case reflect.Uint64:
- ret = uint64(binary.Size(field.Interface().(uint64)))
- default:
- return 0, errors.New("Cannot calculate the length of unknown kind for field " + fieldName)
- }
- meta.Lens[fieldName] = ret
- return ret, nil
- }
- func Marshal(v interface{}) ([]byte, error) {
- m := &Metadata{
- Tags: &TagMap{},
- Lens: make(map[string]uint64),
- Parent: v,
- }
- return marshal(v, m)
- }
- func marshal(v interface{}, meta *Metadata) ([]byte, error) {
- var ret []byte
- typev := reflect.TypeOf(v)
- valuev := reflect.ValueOf(v)
- bm, ok := v.(BinaryMarshallable)
- if ok {
- // Custom marshallable interface found.
- buf, err := bm.MarshalBinary(meta)
- if err != nil {
- return nil, err
- }
- return buf, nil
- }
- if typev.Kind() == reflect.Ptr {
- valuev = reflect.Indirect(reflect.ValueOf(v))
- typev = valuev.Type()
- }
- lenOffset := func(data uint64) (uint64, error) {
- if meta != nil && meta.Tags.Has("len") {
- fieldName, err := meta.Tags.GetString("len")
- if err != nil {
- return 0, err
- }
- l, err := getFieldLengthByName(fieldName, meta)
- if err != nil {
- return 0, err
- }
- return uint64(l), nil
- }
- if meta != nil && meta.Tags.Has("offset") {
- fieldName, err := meta.Tags.GetString("offset")
- if err != nil {
- return 0, err
- }
- l, err := getOffsetByFieldName(fieldName, meta)
- if err != nil {
- return 0, err
- }
- return uint64(l), nil
- }
- return data, nil
- }
- w := bytes.NewBuffer(ret)
- switch typev.Kind() {
- case reflect.Struct:
- m := &Metadata{
- Tags: &TagMap{},
- Lens: make(map[string]uint64),
- Parent: v,
- }
- for j := 0; j < valuev.NumField(); j++ {
- tags, err := parseTags(typev.Field(j))
- name := typev.Field(j).Name
- if err != nil {
- return nil, err
- }
- m.Tags = tags
- buf, err := marshal(valuev.Field(j).Interface(), m)
- if err != nil {
- return nil, err
- }
- m.Lens[name] = uint64(len(buf))
- if err := binary.Write(w, binary.LittleEndian, buf); err != nil {
- return nil, err
- }
- }
- case reflect.Slice, reflect.Array:
- switch typev.Elem().Kind() {
- case reflect.Uint8:
- if meta.Tags.Has("fixed") {
- length, err := meta.Tags.GetInt("fixed")
- if err != nil {
- return nil, err
- }
- v8 := v.([]uint8)
- if len(v8) != length {
- vv := make([]uint8, length)
- copy(vv, v8)
- v = vv
- }
- }
- if err := binary.Write(w, binary.LittleEndian, v.([]uint8)); err != nil {
- return nil, err
- }
- case reflect.Uint16:
- if err := binary.Write(w, binary.LittleEndian, v.([]uint16)); err != nil {
- return nil, err
- }
- }
- case reflect.Uint8:
- if err := binary.Write(w, binary.LittleEndian, valuev.Interface().(uint8)); err != nil {
- return nil, err
- }
- case reflect.Uint16:
- data := valuev.Interface().(uint16)
- if data2, err := lenOffset(uint64(data)); err != nil {
- return nil, err
- } else {
- data = uint16(data2)
- }
- // if meta != nil && meta.Tags.Has("len") {
- // fieldName, err := meta.Tags.GetString("len")
- // if err != nil {
- // return nil, err
- // }
- // l, err := getFieldLengthByName(fieldName, meta)
- // if err != nil {
- // return nil, err
- // }
- // data = uint16(l)
- // }
- // if meta != nil && meta.Tags.Has("offset") {
- // fieldName, err := meta.Tags.GetString("offset")
- // if err != nil {
- // return nil, err
- // }
- // l, err := getOffsetByFieldName(fieldName, meta)
- // if err != nil {
- // return nil, err
- // }
- // data = uint16(l)
- // }
- if err := binary.Write(w, binary.LittleEndian, data); err != nil {
- return nil, err
- }
- case reflect.Uint32:
- data := valuev.Interface().(uint32)
- if data2, err := lenOffset(uint64(data)); err != nil {
- return nil, err
- } else {
- data = uint32(data2)
- }
- // if meta != nil && meta.Tags.Has("len") {
- // fieldName, err := meta.Tags.GetString("len")
- // if err != nil {
- // return nil, err
- // }
- // l, err := getFieldLengthByName(fieldName, meta)
- // if err != nil {
- // return nil, err
- // }
- // data = uint32(l)
- // }
- // if meta != nil && meta.Tags.Has("offset") {
- // fieldName, err := meta.Tags.GetString("offset")
- // if err != nil {
- // return nil, err
- // }
- // l, err := getOffsetByFieldName(fieldName, meta)
- // if err != nil {
- // return nil, err
- // }
- // data = uint32(l)
- // }
- if err := binary.Write(w, binary.LittleEndian, data); err != nil {
- return nil, err
- }
- case reflect.Uint64:
- if err := binary.Write(w, binary.LittleEndian, valuev.Interface().(uint64)); err != nil {
- return nil, err
- }
- default:
- return nil, errors.New(fmt.Sprintf("Marshal not implemented for kind: %s", typev.Kind()))
- }
- return w.Bytes(), nil
- }
- func unmarshal(buf []byte, v interface{}, meta *Metadata) (interface{}, error) {
- typev := reflect.TypeOf(v)
- valuev := reflect.ValueOf(v)
- if meta == nil {
- meta = &Metadata{
- Tags: &TagMap{},
- Lens: make(map[string]uint64),
- Parent: v,
- ParentBuf: buf,
- Offsets: make(map[string]uint64),
- Count: make(map[string]uint64),
- CurrOffset: 0,
- }
- }
- bm, ok := v.(BinaryMarshallable)
- if ok {
- // Custom marshallable interface found.
- newbm, err := bm.UnmarshalBinary(buf, meta)
- if err != nil {
- return nil, err
- }
- if newbm != nil {
- return newbm, nil
- }
- return bm, nil
- }
- if typev.Kind() == reflect.Ptr {
- valuev = reflect.ValueOf(v).Elem()
- typev = valuev.Type()
- }
- offsetLen := func(ret uint64) error {
- if meta.Tags.Has("len") {
- ref, err := meta.Tags.GetString("len")
- if err != nil {
- return err
- }
- meta.Lens[ref] = ret
- }
- if meta.Tags.Has("offset") {
- ref, err := meta.Tags.GetString("offset")
- if err != nil {
- return err
- }
- meta.Offsets[ref] = ret
- }
- if meta.Tags.Has("count") {
- ref, err := meta.Tags.GetString("count")
- if err != nil {
- return err
- }
- meta.Count[ref] = ret
- }
- return nil
- }
- r := bytes.NewBuffer(buf)
- switch typev.Kind() {
- case reflect.Struct:
- m := &Metadata{
- Tags: &TagMap{},
- Lens: make(map[string]uint64),
- Parent: v,
- ParentBuf: buf,
- Offsets: make(map[string]uint64),
- Count: make(map[string]uint64),
- CurrOffset: 0,
- }
- for i := 0; i < typev.NumField(); i++ {
- m.CurrField = typev.Field(i).Name
- tags, err := parseTags(typev.Field(i))
- if err != nil {
- return nil, err
- }
- m.Tags = tags
- var data interface{}
- k := typev.Field(i).Type.Kind()
- switch k {
- case reflect.Struct:
- data, err = unmarshal(buf[m.CurrOffset:], valuev.Field(i).Addr().Interface(), m)
- default:
- data, err = unmarshal(buf[m.CurrOffset:], valuev.Field(i).Interface(), m)
- }
- if err != nil {
- return nil, err
- }
- // logx.Printf("name: %v, offset: %v", m.CurrField, m.CurrOffset)
- valuev.Field(i).Set(reflect.ValueOf(data))
- }
- v = reflect.Indirect(reflect.ValueOf(v)).Interface()
- meta.CurrOffset += m.CurrOffset
- return v, nil
- case reflect.Uint8:
- var ret uint8
- if err := binary.Read(r, binary.LittleEndian, &ret); err != nil {
- return nil, err
- }
- meta.CurrOffset += uint64(binary.Size(ret))
- return ret, nil
- case reflect.Uint16:
- var ret uint16
- if err := binary.Read(r, binary.LittleEndian, &ret); err != nil {
- return nil, err
- }
- if err := offsetLen(uint64(ret)); err != nil {
- return nil, err
- }
- meta.CurrOffset += uint64(binary.Size(ret))
- return ret, nil
- case reflect.Uint32:
- var ret uint32
- if err := binary.Read(r, binary.LittleEndian, &ret); err != nil {
- return nil, err
- }
- if err := offsetLen(uint64(ret)); err != nil {
- return nil, err
- }
- meta.CurrOffset += uint64(binary.Size(ret))
- return ret, nil
- case reflect.Uint64:
- var ret uint64
- if err := binary.Read(r, binary.LittleEndian, &ret); err != nil {
- return nil, err
- }
- meta.CurrOffset += uint64(binary.Size(ret))
- return ret, nil
- case reflect.Slice, reflect.Array:
- switch typev.Elem().Kind() {
- case reflect.Uint8:
- var length, offset int
- var err error
- if meta.Tags.Has("fixed") {
- if length, err = meta.Tags.GetInt("fixed"); err != nil {
- return nil, err
- }
- // Fixed length fields advance current offset
- meta.CurrOffset += uint64(length)
- } else {
- if val, ok := meta.Lens[meta.CurrField]; ok {
- length = int(val)
- } else {
- return nil, errors.New("Variable length field missing length reference in struct: " + meta.CurrField)
- }
- if val, ok := meta.Offsets[meta.CurrField]; ok {
- offset = int(val)
- } else {
- // No offset found in map. Use current offset
- offset = int(meta.CurrOffset)
- }
- // Variable length data is relative to parent/outer struct. Reset reader to point to beginning of data
- r = bytes.NewBuffer(meta.ParentBuf[offset : offset+length])
- // Variable length data fields do NOT advance current offset.
- meta.CurrOffset += uint64(length)
- }
- data := make([]byte, length)
- if err := binary.Read(r, binary.LittleEndian, &data); err != nil {
- return nil, err
- }
- // meta.CurrOffset += uint64(length)
- return data, nil
- case reflect.Uint16:
- length := len(buf) / 2
- if val, ok := meta.Count[meta.CurrField]; ok {
- length = int(val)
- }
- data := make([]uint16, length)
- if err := binary.Read(r, binary.LittleEndian, &data); err != nil {
- return nil, err
- }
- meta.CurrOffset += uint64(length * 2)
- return data, nil
- }
- default:
- return errors.New("Unmarshal not implemented for kind:" + typev.Kind().String()), nil
- }
- return nil, nil
- }
- func Unmarshal(buf []byte, v interface{}) error {
- _, err := Unmarshal2(buf, v)
- return err
- }
- func Unmarshal2(buf []byte, v interface{}) ([]byte, error) {
- meta := &Metadata{
- Tags: &TagMap{},
- Lens: make(map[string]uint64),
- Parent: v,
- ParentBuf: buf,
- Offsets: make(map[string]uint64),
- Count: make(map[string]uint64),
- CurrOffset: 0,
- }
- _, err := unmarshal(buf, v, meta)
- return buf[meta.CurrOffset:], err
- }
|