Skip to content

Commit

Permalink
Merge branch 'master' into feature/writer
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostiam committed Apr 3, 2024
2 parents 48c2648 + 82103a4 commit cccb446
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 23 deletions.
26 changes: 26 additions & 0 deletions binstruct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,3 +891,29 @@ func Test_LeAndBeInOneStruct(t *testing.T) {
require.NoError(t, err)
require.Equal(t, wantBE, actual)
}

func Test_sliceSkipWithoutPanic(t *testing.T) {
var v struct {
_ []int8 `bin:"len:2"`
I int32
}
err := UnmarshalBE([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, &v)
require.NoError(t, err)
require.Equal(t, int32(0x02030405), v.I)
}

func Test_InnerSubField(t *testing.T) {
type child struct {
Len int8
}

var v struct {
Child child
S []byte `bin:"len:Child.Len"`
}

err := UnmarshalBE([]byte{0x05, 0x01, 0x02, 0x03, 0x04, 0x05}, &v)
require.NoError(t, err)
require.Equal(t, int8(5), v.Child.Len)
require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04, 0x05}, v.S)
}
3 changes: 2 additions & 1 deletion example02_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"

"github.com/davecgh/go-spew/spew"

"github.com/ghostiam/binstruct"
)

Expand Down Expand Up @@ -146,7 +147,7 @@ func Example_decodeCustom() {
// },
// TypeLen: (int16) 4,
// Type: (string) (len=4) "test",
// B: ([]uint8) (len=3 cap=4) {
// B: ([]uint8) (len=3 cap=3) {
// 00000000 68 69 21 |hi!|
// }
// }
Expand Down
14 changes: 12 additions & 2 deletions tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,24 @@ func parseValue(structValue reflect.Value, v string) (int64, error) {
// parse value or get from field
l, err := strconv.ParseInt(v, 10, 0)
if err != nil {
lenVal := structValue.FieldByName(v)
sv := structValue

split := strings.Split(v, ".")
for _, s := range split {
sv = sv.FieldByName(s)
if sv.Kind() != reflect.Struct {
break
}
}

lenVal := sv
switch lenVal.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
l = lenVal.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
l = int64(lenVal.Uint())
default:
return 0, errors.New("can't get field len from " + v + " field")
return 0, errors.New("can't get field len from \"" + v + "\" field")
}
}
return l, nil
Expand Down
64 changes: 44 additions & 20 deletions unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ func (u *unmarshal) unmarshal(v interface{}, parentStructValues []reflect.Value)
return nil
}

func (u *unmarshal) setValueToField(structValue, fieldValue reflect.Value, fieldData *fieldReadData, parentStructValues []reflect.Value) error {
func (u *unmarshal) setValueToField(
structValue, fieldValue reflect.Value, fieldData *fieldReadData, parentStructValues []reflect.Value,
) error {
if fieldData == nil {
fieldData = &fieldReadData{}
}
Expand Down Expand Up @@ -239,37 +241,42 @@ or
return errors.New("need set tag with len for slice")
}

for i := int64(0); i < *fieldData.Length; i++ {
tmpV := reflect.New(fieldValue.Type().Elem()).Elem()
err = u.setValueToField(structValue, tmpV, fieldData.ElemFieldData, parentStructValues)
arrLen := int(*fieldData.Length)

// If slice of bytes, read bytes and set to slice.
if fieldValue.Type().Elem().Kind() == reflect.Uint8 {
n, b, err := u.r.ReadBytes(arrLen)
if err != nil {
return err
}

if n != arrLen {
return fmt.Errorf("expected %d, got %d", *fieldData.Length, n)
}

if fieldValue.CanSet() {
fieldValue.Set(reflect.Append(fieldValue, tmpV))
fieldValue.SetBytes(b)
}

return nil
}

if fieldValue.CanSet() {
// Create slice before populate.
fieldValue.Set(reflect.MakeSlice(fieldValue.Type(), arrLen, arrLen))
}

return u.setArrayValueToField(arrLen, structValue, fieldValue, fieldData, parentStructValues)

case reflect.Array:
var arrLen int64
arrLen := fieldValue.Len()

if fieldData.Length != nil {
arrLen = *fieldData.Length
arrLen = int(*fieldData.Length)
}

if arrLen == 0 {
arrLen = int64(fieldValue.Len())
}
return u.setArrayValueToField(arrLen, structValue, fieldValue, fieldData, parentStructValues)

for i := int64(0); i < arrLen; i++ {
tmpV := reflect.New(fieldValue.Type().Elem()).Elem()
err = u.setValueToField(structValue, tmpV, fieldData.ElemFieldData, parentStructValues)
if err != nil {
return err
}
if fieldValue.CanSet() {
fieldValue.Index(int(i)).Set(tmpV)
}
}
case reflect.Struct:
err = u.unmarshal(fieldValue.Addr().Interface(), append(parentStructValues, structValue))
if err != nil {
Expand All @@ -282,6 +289,23 @@ or
return nil
}

func (u *unmarshal) setArrayValueToField(
arrLen int, structValue, fieldValue reflect.Value, fieldData *fieldReadData, parentStructValues []reflect.Value,
) error {
for i := 0; i < arrLen; i++ {
tmpV := reflect.New(fieldValue.Type().Elem()).Elem()
err := u.setValueToField(structValue, tmpV, fieldData.ElemFieldData, parentStructValues)
if err != nil {
return err
}
if fieldValue.CanSet() {
fieldValue.Index(i).Set(tmpV)
}
}

return nil
}

func callFunc(r Reader, funcName string, structValue, fieldValue reflect.Value) (bool, error) {
// Call methods
m := structValue.Addr().MethodByName(funcName)
Expand Down

0 comments on commit cccb446

Please sign in to comment.