]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/flattened_file_object.go
Misc cleanup
[rbdr/mobius] / hotline / flattened_file_object.go
index dfdd8a871770ce3136f75828a02e8e1efb4f57b1..fae8ab8051f6588288f9b81962d95937cb4dcece 100644 (file)
@@ -2,7 +2,6 @@ package hotline
 
 import (
        "encoding/binary"
-       "fmt"
        "os"
 )
 
@@ -16,19 +15,19 @@ type flattenedFileObject struct {
 
 // FlatFileHeader is the first section of a "Flattened File Object".  All fields have static values.
 type FlatFileHeader struct {
-       Format    []byte // Always "FILP"
-       Version   []byte // Always 1
-       RSVD      []byte // Always empty zeros
-       ForkCount []byte // Always 2
+       Format    [4]byte  // Always "FILP"
+       Version   [2]byte  // Always 1
+       RSVD      [16]byte // Always empty zeros
+       ForkCount [2]byte  // Always 2
 }
 
 // NewFlatFileHeader returns a FlatFileHeader struct
 func NewFlatFileHeader() FlatFileHeader {
        return FlatFileHeader{
-               Format:    []byte("FILP"),
-               Version:   []byte{0, 1},
-               RSVD:      make([]byte, 16),
-               ForkCount: []byte{0, 2},
+               Format:    [4]byte{0x46, 0x49, 0x4c, 0x50}, // FILP
+               Version:   [2]byte{0, 1},
+               RSVD:      [16]byte{},
+               ForkCount: [2]byte{0, 2},
        }
 }
 
@@ -56,30 +55,30 @@ type FlatFileInformationFork struct {
        Comment          []byte // File comment
 }
 
-func NewFlatFileInformationFork(fileName string) FlatFileInformationFork {
+func NewFlatFileInformationFork(fileName string, modifyTime []byte) FlatFileInformationFork {
        return FlatFileInformationFork{
-               Platform:         []byte("AMAC"),                                         // TODO: Remove hardcode to support "AWIN" Platform (maybe?)
-               TypeSignature:    []byte(fileTypeFromFilename(fileName)),                 // TODO: Don't infer types from filename
-               CreatorSignature: []byte(fileCreatorFromFilename(fileName)),              // TODO: Don't infer types from filename
-               Flags:            []byte{0, 0, 0, 0},                                     // TODO: What is this?
-               PlatformFlags:    []byte{0, 0, 1, 0},                                     // TODO: What is this?
-               RSVD:             make([]byte, 32),                                       // Unimplemented in Hotline Protocol
-               CreateDate:       []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}, // TODO: implement
-               ModifyDate:       []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}, // TODO: implement
-               NameScript:       make([]byte, 2),                                        // TODO: What is this?
+               Platform:         []byte("AMAC"),                                     // TODO: Remove hardcode to support "AWIN" Platform (maybe?)
+               TypeSignature:    []byte(fileTypeFromFilename(fileName).TypeCode),    // TODO: Don't infer types from filename
+               CreatorSignature: []byte(fileTypeFromFilename(fileName).CreatorCode), // TODO: Don't infer types from filename
+               Flags:            []byte{0, 0, 0, 0},                                 // TODO: What is this?
+               PlatformFlags:    []byte{0, 0, 1, 0},                                 // TODO: What is this?
+               RSVD:             make([]byte, 32),                                   // Unimplemented in Hotline Protocol
+               CreateDate:       modifyTime,                                         // some filesystems don't support createTime
+               ModifyDate:       modifyTime,
+               NameScript:       make([]byte, 2), // TODO: What is this?
                Name:             []byte(fileName),
-               Comment:          []byte("TODO"), // TODO: implement (maybe?)
+               CommentSize:      []byte{0, 0},
+               Comment:          []byte{}, // TODO: implement (maybe?)
        }
 }
 
-// Size of the flat file information fork, which is the fixed size of 72 bytes
-// plus the number of bytes in the FileName
-// TODO: plus the size of the Comment!
+// DataSize calculates the size of the flat file information fork, which is
+// 72 bytes for the fixed length fields plus the length of the Name + Comment
 func (ffif FlatFileInformationFork) DataSize() []byte {
        size := make([]byte, 4)
-       nameLen := len(ffif.Name)
-       //TODO: Can I do math directly on two byte slices?
-       dataSize := nameLen + 74
+
+       // TODO: Can I do math directly on two byte slices?
+       dataSize := len(ffif.Name) + len(ffif.Comment) + 74
 
        binary.BigEndian.PutUint32(size, uint32(dataSize))
 
@@ -87,7 +86,7 @@ func (ffif FlatFileInformationFork) DataSize() []byte {
 }
 
 func (ffo flattenedFileObject) TransferSize() []byte {
-       payloadSize := len(ffo.Payload())
+       payloadSize := len(ffo.BinaryMarshal())
        dataSize := binary.BigEndian.Uint32(ffo.FlatFileDataForkHeader.DataSize)
 
        transferSize := make([]byte, 4)
@@ -110,15 +109,6 @@ type FlatFileDataForkHeader struct {
        DataSize        []byte
 }
 
-func NewFlatFileDataForkHeader() FlatFileDataForkHeader {
-       return FlatFileDataForkHeader{
-               ForkType:        []byte("DATA"),
-               CompressionType: []byte{0, 0, 0, 0},
-               RSVD:            []byte{0, 0, 0, 0},
-               //      DataSize:        []byte{0, 0, 0x03, 0xc3},
-       }
-}
-
 // ReadFlattenedFileObject parses a byte slice into a flattenedFileObject
 func ReadFlattenedFileObject(bytes []byte) flattenedFileObject {
        nameSize := bytes[110:112]
@@ -134,16 +124,11 @@ func ReadFlattenedFileObject(bytes []byte) flattenedFileObject {
 
        comment := bytes[commentStartPos:commentEndPos]
 
-       //dataSizeField := bytes[nameEnd+14+commentLen : nameEnd+18+commentLen]
-       //dataSize := binary.BigEndian.Uint32(dataSizeField)
+       // dataSizeField := bytes[nameEnd+14+commentLen : nameEnd+18+commentLen]
+       // dataSize := binary.BigEndian.Uint32(dataSizeField)
 
        ffo := flattenedFileObject{
-               FlatFileHeader: FlatFileHeader{
-                       Format:    bytes[0:4],
-                       Version:   bytes[4:6],
-                       RSVD:      bytes[6:22],
-                       ForkCount: bytes[22:24],
-               },
+               FlatFileHeader: NewFlatFileHeader(),
                FlatFileInformationForkHeader: FlatFileInformationForkHeader{
                        ForkType:        bytes[24:28],
                        CompressionType: bytes[28:32],
@@ -176,12 +161,12 @@ func ReadFlattenedFileObject(bytes []byte) flattenedFileObject {
        return ffo
 }
 
-func (f flattenedFileObject) Payload() []byte {
+func (f flattenedFileObject) BinaryMarshal() []byte {
        var out []byte
-       out = append(out, f.FlatFileHeader.Format...)
-       out = append(out, f.FlatFileHeader.Version...)
-       out = append(out, f.FlatFileHeader.RSVD...)
-       out = append(out, f.FlatFileHeader.ForkCount...)
+       out = append(out, f.FlatFileHeader.Format[:]...)
+       out = append(out, f.FlatFileHeader.Version[:]...)
+       out = append(out, f.FlatFileHeader.RSVD[:]...)
+       out = append(out, f.FlatFileHeader.ForkCount[:]...)
 
        out = append(out, []byte("INFO")...)
        out = append(out, []byte{0, 0, 0, 0}...)
@@ -199,9 +184,8 @@ func (f flattenedFileObject) Payload() []byte {
        out = append(out, f.FlatFileInformationFork.NameScript...)
        out = append(out, f.FlatFileInformationFork.ReadNameSize()...)
        out = append(out, f.FlatFileInformationFork.Name...)
-
-       // TODO: Implement commentlen and comment field
-       out = append(out, []byte{0, 0}...)
+       out = append(out, f.FlatFileInformationFork.CommentSize...)
+       out = append(out, f.FlatFileInformationFork.Comment...)
 
        out = append(out, f.FlatFileDataForkHeader.ForkType...)
        out = append(out, f.FlatFileDataForkHeader.CompressionType...)
@@ -211,24 +195,30 @@ func (f flattenedFileObject) Payload() []byte {
        return out
 }
 
-func NewFlattenedFileObject(filePath string, fileName string) (flattenedFileObject, error) {
-       file, err := os.Open(fmt.Sprintf("%v/%v", filePath, fileName))
+func NewFlattenedFileObject(fileRoot string, filePath, fileName []byte) (*flattenedFileObject, error) {
+       fullFilePath, err := readPath(fileRoot, filePath, fileName)
+       if err != nil {
+               return nil, err
+       }
+       file, err := os.Open(fullFilePath)
        if err != nil {
-               return flattenedFileObject{}, err
+               return nil, err
        }
-       defer file.Close()
+       defer func(file *os.File) { _ = file.Close() }(file)
 
        fileInfo, err := file.Stat()
        if err != nil {
-               return flattenedFileObject{}, err
+               return nil, err
        }
 
        dataSize := make([]byte, 4)
        binary.BigEndian.PutUint32(dataSize, uint32(fileInfo.Size()))
 
-       return flattenedFileObject{
+       mTime := toHotlineTime(fileInfo.ModTime())
+
+       return &flattenedFileObject{
                FlatFileHeader:          NewFlatFileHeader(),
-               FlatFileInformationFork: NewFlatFileInformationFork(fileName),
+               FlatFileInformationFork: NewFlatFileInformationFork(string(fileName), mTime),
                FlatFileDataForkHeader: FlatFileDataForkHeader{
                        ForkType:        []byte("DATA"),
                        CompressionType: []byte{0, 0, 0, 0},