"bytes"
"encoding/binary"
"errors"
+ "io"
"path"
"strings"
)
Name []byte
}
-func NewFilePathItem(b []byte) FilePathItem {
- return FilePathItem{
- Len: b[2],
- Name: b[3:],
- }
-}
-
type FilePath struct {
ItemCount [2]byte
Items []FilePathItem
}
-const minFilePathLen = 2
-
func (fp *FilePath) UnmarshalBinary(b []byte) error {
- if b == nil {
- return nil
- }
- if len(b) < minFilePathLen {
- return errors.New("insufficient bytes")
- }
- err := binary.Read(bytes.NewReader(b[0:2]), binary.BigEndian, &fp.ItemCount)
- if err != nil {
+ reader := bytes.NewReader(b)
+ err := binary.Read(reader, binary.BigEndian, &fp.ItemCount)
+ if err != nil && !errors.Is(err, io.EOF) {
return err
}
+ if errors.Is(err, io.EOF) {
+ return nil
+ }
- pathData := b[2:]
for i := uint16(0); i < fp.Len(); i++ {
- segLen := pathData[2]
- fp.Items = append(fp.Items, NewFilePathItem(pathData[:segLen+3]))
- pathData = pathData[3+segLen:]
+ // skip two bytes for the file path delimiter
+ _, _ = reader.Seek(2, io.SeekCurrent)
+
+ // read the length of the next pathItem
+ segLen, err := reader.ReadByte()
+ if err != nil {
+ return err
+ }
+
+ pBytes := make([]byte, segLen)
+
+ _, err = reader.Read(pBytes)
+ if err != nil && !errors.Is(err, io.EOF) {
+ return err
+ }
+
+ fp.Items = append(fp.Items, FilePathItem{Len: segLen, Name: pBytes})
}
return nil
}
func (ffif *FlatFileInformationFork) UnmarshalBinary(b []byte) error {
-
nameSize := b[70:72]
bs := binary.BigEndian.Uint16(nameSize)
-
nameEnd := 72 + bs
- commentSize := b[nameEnd : nameEnd+2]
- commentLen := binary.BigEndian.Uint16(commentSize)
-
- commentStartPos := int(nameEnd) + 2
- commentEndPos := int(nameEnd) + 2 + int(commentLen)
-
- comment := b[commentStartPos:commentEndPos]
-
ffif.Platform = b[0:4]
ffif.TypeSignature = b[4:8]
ffif.CreatorSignature = b[8:12]
ffif.NameScript = b[68:70]
ffif.NameSize = b[70:72]
ffif.Name = b[72:nameEnd]
- ffif.CommentSize = b[nameEnd : nameEnd+2]
- ffif.Comment = comment
+
+ if len(b) > int(nameEnd) {
+ ffif.CommentSize = b[nameEnd : nameEnd+2]
+ commentLen := binary.BigEndian.Uint16(ffif.CommentSize)
+
+ commentStartPos := int(nameEnd) + 2
+ commentEndPos := int(nameEnd) + 2 + int(commentLen)
+
+ ffif.Comment = b[commentStartPos:commentEndPos]
+ }
return nil
}
import (
"fmt"
+ "github.com/davecgh/go-spew/spew"
"github.com/stretchr/testify/assert"
"os"
"testing"
})
}
}
+
+func TestFlatFileInformationFork_UnmarshalBinary(t *testing.T) {
+ type args struct {
+ b []byte
+ }
+ tests := []struct {
+ name string
+ args args
+ wantErr assert.ErrorAssertionFunc
+ }{
+ {
+ name: "when zero length comment size is omitted (Nostalgia client behavior)",
+ args: args{
+ b: []byte{
+ 0x41, 0x4d, 0x41, 0x43, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x62, 0x65, 0x61, 0x72, 0x2e, 0x74, 0x69, 0x66, 0x66,
+ },
+ },
+ wantErr: assert.NoError,
+ },
+ {
+ name: "when zero length comment size is included",
+ args: args{
+ b: []byte{
+ 0x41, 0x4d, 0x41, 0x43, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x62, 0x65, 0x61, 0x72, 0x2e, 0x74, 0x69, 0x66, 0x66, 0x00, 0x00,
+ },
+ },
+ wantErr: assert.NoError,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ ffif := &FlatFileInformationFork{}
+ tt.wantErr(t, ffif.UnmarshalBinary(tt.args.b), fmt.Sprintf("UnmarshalBinary(%v)", tt.args.b))
+
+ spew.Dump(ffif)
+ })
+ }
+}