diff --git a/README.md b/README.md index 8a5d4b5..113ee87 100755 --- a/README.md +++ b/README.md @@ -278,6 +278,7 @@ type test struct { OffsetStart byte `bin:"offsetStart:42"` // move to 42 bytes from start position and read byte OffsetEnd byte `bin:"offsetEnd:-42"` // move to -42 bytes from end position and read byte OffsetStart byte `bin:"offsetStart:42, offset:10"` // also worked and equally `offsetStart:52` + OffsetWithRestore byte `bin:"offset:42, offsetRestore"` // move to 42 bytes from current position and read byte, then restore position to the previous one (before offset) // Calculations supported +,-,/,* and are performed from left to right that is 2+2*2=8 not 6!!! CalcTagValue []byte `bin:"len:10+5+2+3"` // equally len:20 diff --git a/binstruct_test.go b/binstruct_test.go index ce4b5a8..3044a2d 100644 --- a/binstruct_test.go +++ b/binstruct_test.go @@ -917,3 +917,19 @@ func Test_InnerSubField(t *testing.T) { require.Equal(t, int8(5), v.Child.Len) require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04, 0x05}, v.S) } + +func Test_OffsetRestore(t *testing.T) { + var v struct { + Offset uint8 + Size uint8 + Data []byte `bin:"offsetStart:Offset,len:Size,offsetRestore"` + Other []byte `bin:"len:3"` + } + + err := UnmarshalBE([]byte{0x05, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05}, &v) + require.NoError(t, err) + require.Equal(t, uint8(5), v.Offset) + require.Equal(t, uint8(2), v.Size) + require.Equal(t, []byte{0x04, 0x05}, v.Data) + require.Equal(t, []byte{0x01, 0x02, 0x03}, v.Other) +} diff --git a/tag.go b/tag.go index 83f01a2..70ecf5e 100644 --- a/tag.go +++ b/tag.go @@ -26,6 +26,7 @@ const ( tagTypeOffsetFromCurrent = "offset" tagTypeOffsetFromStart = "offsetStart" tagTypeOffsetFromEnd = "offsetEnd" + tagTypeOffsetRestore = "offsetRestore" ) type tag struct { @@ -59,6 +60,9 @@ func parseTag(t string) ([]tag, error) { case v == tagTypeIgnore: tags = append(tags, tag{Type: tagTypeIgnore}) + case v == tagTypeOffsetRestore: + tags = append(tags, tag{Type: tagTypeOffsetRestore}) + case strings.HasPrefix(v, "["): v = v + "," + t var arrBalance int @@ -130,11 +134,12 @@ type fieldOffset struct { } type fieldReadData struct { - Ignore bool - Length *int64 - Offsets []fieldOffset - FuncName string - Order binary.ByteOrder + Ignore bool + Length *int64 + Offsets []fieldOffset + OffsetRestore bool + FuncName string + Order binary.ByteOrder ElemFieldData *fieldReadData // if type Element } @@ -258,6 +263,9 @@ func parseReadDataFromTags(structValue reflect.Value, tags []tag) (*fieldReadDat Whence: io.SeekEnd, }) + case tagTypeOffsetRestore: + data.OffsetRestore = true + case tagTypeFunc: data.FuncName = t.Value diff --git a/tag_test.go b/tag_test.go index 6acd33d..ed8ae08 100644 --- a/tag_test.go +++ b/tag_test.go @@ -66,12 +66,13 @@ func Test_parseTag(t *testing.T) { }, { name: "multi tag", - tag: "len:1, offset:2, offsetStart:3, offsetEnd:4", + tag: "len:1, offset:2, offsetStart:3, offsetEnd:4, offsetRestore", want: []tag{ {Type: "len", Value: "1"}, {Type: "offset", Value: "2"}, {Type: "offsetStart", Value: "3"}, {Type: "offsetEnd", Value: "4"}, + {Type: "offsetRestore"}, }, }, { diff --git a/unmarshal.go b/unmarshal.go index f39f036..841d737 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -3,6 +3,7 @@ package binstruct import ( "errors" "fmt" + "io" "reflect" "strings" ) @@ -80,6 +81,14 @@ func (u *unmarshal) setValueToField( r = r.WithOrder(fieldData.Order) } + if fieldData.OffsetRestore { + currentOffset, err := r.Seek(0, io.SeekCurrent) + if err != nil { + return fmt.Errorf("get current offset: %w", err) + } + defer r.Seek(currentOffset, io.SeekStart) + } + err := setOffset(r, fieldData) if err != nil { return fmt.Errorf("set offset: %w", err)