name string
fields fields
args args
- want *FileNameWithInfo
+ want *FileNameWithInfo
wantErr bool
}{
{
name: tt.fields.name,
}
if err := f.UnmarshalBinary(tt.args.data); (err != nil) != tt.wantErr {
- t.Errorf("UnmarshalBinary() error = %v, wantErr %v", err, tt.wantErr)
+ t.Errorf("Write() error = %v, wantErr %v", err, tt.wantErr)
}
if !assert.Equal(t, tt.want, f) {
t.Errorf("Read() got = %v, want %v", f, tt.want)
}
})
}
-}
\ No newline at end of file
+}
package hotline
import (
+ "bufio"
"bytes"
"encoding/binary"
"errors"
)
// FilePathItem represents the file or directory portion of a delimited file path (e.g. foo and bar in "/foo/bar")
+// Example bytes:
// 00 00
// 09
-// 73 75 62 66 6f 6c 64 65 72 // "subfolder"
+// 73 75 62 66 6f 6c 64 65 72 "subfolder"
type FilePathItem struct {
Len byte
Name []byte
}
+const fileItemMinLen = 3
+
+// fileItemScanner implements bufio.SplitFunc for parsing incoming byte slices into complete tokens
+func fileItemScanner(data []byte, _ bool) (advance int, token []byte, err error) {
+ if len(data) < fileItemMinLen {
+ return 0, nil, nil
+ }
+
+ advance = fileItemMinLen + int(data[2])
+ return advance, data[0:advance], nil
+}
+
+// Write implements the io.Writer interface for FilePathItem
+func (fpi *FilePathItem) Write(b []byte) (n int, err error) {
+ fpi.Len = b[2]
+ fpi.Name = b[fileItemMinLen : fpi.Len+fileItemMinLen]
+
+ return int(fpi.Len) + fileItemMinLen, nil
+}
+
type FilePath struct {
ItemCount [2]byte
Items []FilePathItem
}
-func (fp *FilePath) UnmarshalBinary(b []byte) error {
+func (fp *FilePath) Write(b []byte) (n int, err error) {
reader := bytes.NewReader(b)
- err := binary.Read(reader, binary.BigEndian, &fp.ItemCount)
+ err = binary.Read(reader, binary.BigEndian, &fp.ItemCount)
if err != nil && !errors.Is(err, io.EOF) {
- return err
+ return n, err
}
if errors.Is(err, io.EOF) {
- return nil
+ return n, nil
}
- for i := uint16(0); i < fp.Len(); i++ {
- // 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)
+ scanner := bufio.NewScanner(reader)
+ scanner.Split(fileItemScanner)
- _, err = reader.Read(pBytes)
- if err != nil && !errors.Is(err, io.EOF) {
- return err
+ for i := 0; i < int(binary.BigEndian.Uint16(fp.ItemCount[:])); i++ {
+ var fpi FilePathItem
+ scanner.Scan()
+ if _, err := fpi.Write(scanner.Bytes()); err != nil {
+ return n, err
}
-
- fp.Items = append(fp.Items, FilePathItem{Len: segLen, Name: pBytes})
+ fp.Items = append(fp.Items, fpi)
}
- return nil
+ return n, nil
}
+// IsDropbox checks if a FilePath matches the special drop box folder type
func (fp *FilePath) IsDropbox() bool {
if fp.Len() == 0 {
return false
func readPath(fileRoot string, filePath, fileName []byte) (fullPath string, err error) {
var fp FilePath
if filePath != nil {
- if err = fp.UnmarshalBinary(filePath); err != nil {
+ if _, err = fp.Write(filePath); err != nil {
return "", err
}
}
"testing"
)
-func TestFilePath_UnmarshalBinary(t *testing.T) {
+func TestFilePath_Write(t *testing.T) {
type args struct {
b []byte
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var fp FilePath
- if err := fp.UnmarshalBinary(tt.args.b); (err != nil) != tt.wantErr {
- t.Errorf("UnmarshalBinary() error = %v, wantErr %v", err, tt.wantErr)
+ if _, err := fp.Write(tt.args.b); (err != nil) != tt.wantErr {
+ t.Errorf("Write() error = %v, wantErr %v", err, tt.wantErr)
}
if !assert.Equal(t, tt.want, fp) {
t.Errorf("Read() got = %v, want %v", fp, tt.want)
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))
+ tt.wantErr(t, ffif.UnmarshalBinary(tt.args.b), fmt.Sprintf("Write(%v)", tt.args.b))
})
}
}
// fieldFilePath is only present for nested paths
if t.GetField(fieldFilePath).Data != nil {
var newFp FilePath
- err := newFp.UnmarshalBinary(t.GetField(fieldFilePath).Data)
+ _, err := newFp.Write(t.GetField(fieldFilePath).Data)
if err != nil {
return nil, err
}
fileTransfer := cc.newFileTransfer(FolderDownload, t.GetField(fieldFileName).Data, t.GetField(fieldFilePath).Data, transferSize)
var fp FilePath
- err = fp.UnmarshalBinary(t.GetField(fieldFilePath).Data)
+ _, err = fp.Write(t.GetField(fieldFilePath).Data)
if err != nil {
return res, err
}
func HandleUploadFolder(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
var fp FilePath
if t.GetField(fieldFilePath).Data != nil {
- if err = fp.UnmarshalBinary(t.GetField(fieldFilePath).Data); err != nil {
+ if _, err = fp.Write(t.GetField(fieldFilePath).Data); err != nil {
return res, err
}
}
var fp FilePath
if filePath != nil {
- if err = fp.UnmarshalBinary(filePath); err != nil {
+ if _, err = fp.Write(filePath); err != nil {
return res, err
}
}
var fp FilePath
if t.GetField(fieldFilePath).Data != nil {
- if err = fp.UnmarshalBinary(t.GetField(fieldFilePath).Data); err != nil {
+ if _, err = fp.Write(t.GetField(fieldFilePath).Data); err != nil {
return res, err
}
}
wantErr: false,
},
{
- name: "when UnmarshalBinary returns an err",
+ name: "when Write returns an err",
args: args{
cc: &ClientConn{
Account: &Account{