From: Jeff Halter Date: Wed, 29 Jun 2022 03:44:19 +0000 (-0700) Subject: Implement Scanner and Writer interface for FilePath X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/commitdiff_plain/8fc43f8e53a60144f49b92a0c28b0c939a69d1c9?ds=sidebyside Implement Scanner and Writer interface for FilePath --- diff --git a/hotline/file_name_with_info_test.go b/hotline/file_name_with_info_test.go index 3ca2c30..1637a64 100644 --- a/hotline/file_name_with_info_test.go +++ b/hotline/file_name_with_info_test.go @@ -72,7 +72,7 @@ func TestFileNameWithInfo_UnmarshalBinary(t *testing.T) { name string fields fields args args - want *FileNameWithInfo + want *FileNameWithInfo wantErr bool }{ { @@ -109,11 +109,11 @@ func TestFileNameWithInfo_UnmarshalBinary(t *testing.T) { 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 +} diff --git a/hotline/file_path.go b/hotline/file_path.go index 460af03..46ef97c 100644 --- a/hotline/file_path.go +++ b/hotline/file_path.go @@ -1,6 +1,7 @@ package hotline import ( + "bufio" "bytes" "encoding/binary" "errors" @@ -10,52 +11,66 @@ import ( ) // 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 @@ -79,7 +94,7 @@ func (fp *FilePath) Len() uint16 { 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 } } diff --git a/hotline/file_path_test.go b/hotline/file_path_test.go index f25941e..c2fa666 100644 --- a/hotline/file_path_test.go +++ b/hotline/file_path_test.go @@ -5,7 +5,7 @@ import ( "testing" ) -func TestFilePath_UnmarshalBinary(t *testing.T) { +func TestFilePath_Write(t *testing.T) { type args struct { b []byte } @@ -56,8 +56,8 @@ func TestFilePath_UnmarshalBinary(t *testing.T) { 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) diff --git a/hotline/flattened_file_object_test.go b/hotline/flattened_file_object_test.go index 596ca2c..274ca2b 100644 --- a/hotline/flattened_file_object_test.go +++ b/hotline/flattened_file_object_test.go @@ -37,7 +37,7 @@ func TestFlatFileInformationFork_UnmarshalBinary(t *testing.T) { 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)) }) } } diff --git a/hotline/transaction_handlers.go b/hotline/transaction_handlers.go index 23ee0e6..8ba3632 100644 --- a/hotline/transaction_handlers.go +++ b/hotline/transaction_handlers.go @@ -582,7 +582,7 @@ func HandleNewFolder(cc *ClientConn, t *Transaction) (res []Transaction, err err // 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 } @@ -1472,7 +1472,7 @@ func HandleDownloadFolder(cc *ClientConn, t *Transaction) (res []Transaction, er 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 } @@ -1496,7 +1496,7 @@ func HandleDownloadFolder(cc *ClientConn, t *Transaction) (res []Transaction, er 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 } } @@ -1541,7 +1541,7 @@ func HandleUploadFile(cc *ClientConn, t *Transaction) (res []Transaction, err er var fp FilePath if filePath != nil { - if err = fp.UnmarshalBinary(filePath); err != nil { + if _, err = fp.Write(filePath); err != nil { return res, err } } @@ -1658,7 +1658,7 @@ func HandleGetFileNameList(cc *ClientConn, t *Transaction) (res []Transaction, e 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 } } diff --git a/hotline/transaction_handlers_test.go b/hotline/transaction_handlers_test.go index 0d6b1dc..b5e0bac 100644 --- a/hotline/transaction_handlers_test.go +++ b/hotline/transaction_handlers_test.go @@ -814,7 +814,7 @@ func TestHandleNewFolder(t *testing.T) { wantErr: false, }, { - name: "when UnmarshalBinary returns an err", + name: "when Write returns an err", args: args{ cc: &ClientConn{ Account: &Account{