9 type flattenedFileObject struct {
10 FlatFileHeader FlatFileHeader
11 FlatFileInformationForkHeader FlatFileInformationForkHeader
12 FlatFileInformationFork FlatFileInformationFork
13 FlatFileDataForkHeader FlatFileDataForkHeader
17 // FlatFileHeader is the first section of a "Flattened File Object". All fields have static values.
18 type FlatFileHeader struct {
19 Format []byte // Always "FILP"
20 Version []byte // Always 1
21 RSVD []byte // Always empty zeros
22 ForkCount []byte // Always 2
25 // NewFlatFileHeader returns a FlatFileHeader struct
26 func NewFlatFileHeader() FlatFileHeader {
27 return FlatFileHeader{
28 Format: []byte("FILP"),
29 Version: []byte{0, 1},
30 RSVD: make([]byte, 16),
31 ForkCount: []byte{0, 2},
35 // FlatFileInformationForkHeader is the second section of a "Flattened File Object"
36 type FlatFileInformationForkHeader struct {
37 ForkType []byte // Always "INFO"
38 CompressionType []byte // Always 0; Compression was never implemented in the Hotline protocol
39 RSVD []byte // Always zeros
40 DataSize []byte // Size of the flat file information fork
43 type FlatFileInformationFork struct {
44 Platform []byte // Operating System used. ("AMAC" or "MWIN")
45 TypeSignature []byte // File type signature
46 CreatorSignature []byte // File creator signature
52 NameScript []byte // TODO: what is this?
53 NameSize []byte // Length of file name (Maximum 128 characters)
54 Name []byte // File name
55 CommentSize []byte // Length of file comment
56 Comment []byte // File comment
59 func NewFlatFileInformationFork(fileName string) FlatFileInformationFork {
60 return FlatFileInformationFork{
61 Platform: []byte("AMAC"), // TODO: Remove hardcode to support "AWIN" Platform (maybe?)
62 TypeSignature: []byte(fileTypeFromFilename(fileName)), // TODO: Don't infer types from filename
63 CreatorSignature: []byte(fileCreatorFromFilename(fileName)), // TODO: Don't infer types from filename
64 Flags: []byte{0, 0, 0, 0}, // TODO: What is this?
65 PlatformFlags: []byte{0, 0, 1, 0}, // TODO: What is this?
66 RSVD: make([]byte, 32), // Unimplemented in Hotline Protocol
67 CreateDate: []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}, // TODO: implement
68 ModifyDate: []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}, // TODO: implement
69 NameScript: make([]byte, 2), // TODO: What is this?
70 Name: []byte(fileName),
71 Comment: []byte("TODO"), // TODO: implement (maybe?)
75 // Size of the flat file information fork, which is the fixed size of 72 bytes
76 // plus the number of bytes in the FileName
77 // TODO: plus the size of the Comment!
78 func (ffif FlatFileInformationFork) DataSize() []byte {
79 size := make([]byte, 4)
80 nameLen := len(ffif.Name)
81 //TODO: Can I do math directly on two byte slices?
82 dataSize := nameLen + 74
84 binary.BigEndian.PutUint32(size, uint32(dataSize))
89 func (ffo flattenedFileObject) TransferSize() []byte {
90 payloadSize := len(ffo.Payload())
91 dataSize := binary.BigEndian.Uint32(ffo.FlatFileDataForkHeader.DataSize)
93 transferSize := make([]byte, 4)
94 binary.BigEndian.PutUint32(transferSize, dataSize+uint32(payloadSize))
99 func (ffif FlatFileInformationFork) ReadNameSize() []byte {
100 size := make([]byte, 2)
101 binary.BigEndian.PutUint16(size, uint16(len(ffif.Name)))
106 type FlatFileDataForkHeader struct {
108 CompressionType []byte
113 func NewFlatFileDataForkHeader() FlatFileDataForkHeader {
114 return FlatFileDataForkHeader{
115 ForkType: []byte("DATA"),
116 CompressionType: []byte{0, 0, 0, 0},
117 RSVD: []byte{0, 0, 0, 0},
118 // DataSize: []byte{0, 0, 0x03, 0xc3},
122 // ReadFlattenedFileObject parses a byte slice into a flattenedFileObject
123 func ReadFlattenedFileObject(bytes []byte) flattenedFileObject {
124 nameSize := bytes[110:112]
125 bs := binary.BigEndian.Uint16(nameSize)
129 commentSize := bytes[nameEnd : nameEnd+2]
130 commentLen := binary.BigEndian.Uint16(commentSize)
132 commentStartPos := int(nameEnd) + 2
133 commentEndPos := int(nameEnd) + 2 + int(commentLen)
135 comment := bytes[commentStartPos:commentEndPos]
137 //dataSizeField := bytes[nameEnd+14+commentLen : nameEnd+18+commentLen]
138 //dataSize := binary.BigEndian.Uint32(dataSizeField)
140 ffo := flattenedFileObject{
141 FlatFileHeader: FlatFileHeader{
145 ForkCount: bytes[22:24],
147 FlatFileInformationForkHeader: FlatFileInformationForkHeader{
148 ForkType: bytes[24:28],
149 CompressionType: bytes[28:32],
151 DataSize: bytes[36:40],
153 FlatFileInformationFork: FlatFileInformationFork{
154 Platform: bytes[40:44],
155 TypeSignature: bytes[44:48],
156 CreatorSignature: bytes[48:52],
158 PlatformFlags: bytes[56:60],
160 CreateDate: bytes[92:100],
161 ModifyDate: bytes[100:108],
162 NameScript: bytes[108:110],
163 NameSize: bytes[110:112],
164 Name: bytes[112:nameEnd],
165 CommentSize: bytes[nameEnd : nameEnd+2],
168 FlatFileDataForkHeader: FlatFileDataForkHeader{
169 ForkType: bytes[commentEndPos : commentEndPos+4],
170 CompressionType: bytes[commentEndPos+4 : commentEndPos+8],
171 RSVD: bytes[commentEndPos+8 : commentEndPos+12],
172 DataSize: bytes[commentEndPos+12 : commentEndPos+16],
179 func (f flattenedFileObject) Payload() []byte {
181 out = append(out, f.FlatFileHeader.Format...)
182 out = append(out, f.FlatFileHeader.Version...)
183 out = append(out, f.FlatFileHeader.RSVD...)
184 out = append(out, f.FlatFileHeader.ForkCount...)
186 out = append(out, []byte("INFO")...)
187 out = append(out, []byte{0, 0, 0, 0}...)
188 out = append(out, make([]byte, 4)...)
189 out = append(out, f.FlatFileInformationFork.DataSize()...)
191 out = append(out, f.FlatFileInformationFork.Platform...)
192 out = append(out, f.FlatFileInformationFork.TypeSignature...)
193 out = append(out, f.FlatFileInformationFork.CreatorSignature...)
194 out = append(out, f.FlatFileInformationFork.Flags...)
195 out = append(out, f.FlatFileInformationFork.PlatformFlags...)
196 out = append(out, f.FlatFileInformationFork.RSVD...)
197 out = append(out, f.FlatFileInformationFork.CreateDate...)
198 out = append(out, f.FlatFileInformationFork.ModifyDate...)
199 out = append(out, f.FlatFileInformationFork.NameScript...)
200 out = append(out, f.FlatFileInformationFork.ReadNameSize()...)
201 out = append(out, f.FlatFileInformationFork.Name...)
203 // TODO: Implement commentlen and comment field
204 out = append(out, []byte{0, 0}...)
206 out = append(out, f.FlatFileDataForkHeader.ForkType...)
207 out = append(out, f.FlatFileDataForkHeader.CompressionType...)
208 out = append(out, f.FlatFileDataForkHeader.RSVD...)
209 out = append(out, f.FlatFileDataForkHeader.DataSize...)
214 func NewFlattenedFileObject(filePath string, fileName string) (flattenedFileObject, error) {
215 file, err := os.Open(fmt.Sprintf("%v/%v", filePath, fileName))
217 return flattenedFileObject{}, err
221 fileInfo, err := file.Stat()
223 return flattenedFileObject{}, err
226 dataSize := make([]byte, 4)
227 binary.BigEndian.PutUint32(dataSize, uint32(fileInfo.Size()))
229 return flattenedFileObject{
230 FlatFileHeader: NewFlatFileHeader(),
231 FlatFileInformationFork: NewFlatFileInformationFork(fileName),
232 FlatFileDataForkHeader: FlatFileDataForkHeader{
233 ForkType: []byte("DATA"),
234 CompressionType: []byte{0, 0, 0, 0},
235 RSVD: []byte{0, 0, 0, 0},