diff --git a/binstruct_test.go b/binstruct_test.go index 2456108..538312c 100644 --- a/binstruct_test.go +++ b/binstruct_test.go @@ -891,3 +891,13 @@ 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) +} diff --git a/example02_test.go b/example02_test.go index 68b15b4..ef71351 100644 --- a/example02_test.go +++ b/example02_test.go @@ -7,6 +7,7 @@ import ( "log" "github.com/davecgh/go-spew/spew" + "github.com/ghostiam/binstruct" ) @@ -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!| // } // } diff --git a/unmarshal.go b/unmarshal.go index 1220dc7..f39f036 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -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{} } @@ -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 { @@ -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)