]> git.r.bdr.sh - rbdr/mobius/blame - hotline/flattened_file_object.go
Clean up various linter warnings
[rbdr/mobius] / hotline / flattened_file_object.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
9cf66aea 4 "bytes"
6988a057 5 "encoding/binary"
7cd900d6 6 "io"
9cf66aea 7 "slices"
6988a057
JH
8)
9
10type flattenedFileObject struct {
11 FlatFileHeader FlatFileHeader
7cd900d6 12 FlatFileInformationForkHeader FlatFileForkHeader
6988a057 13 FlatFileInformationFork FlatFileInformationFork
7cd900d6
JH
14 FlatFileDataForkHeader FlatFileForkHeader
15 FlatFileResForkHeader FlatFileForkHeader
45ca5d60
JH
16
17 readOffset int // Internal offset to track read progress
6988a057
JH
18}
19
20// FlatFileHeader is the first section of a "Flattened File Object". All fields have static values.
21type FlatFileHeader struct {
72dd37f1
JH
22 Format [4]byte // Always "FILP"
23 Version [2]byte // Always 1
24 RSVD [16]byte // Always empty zeros
7cd900d6 25 ForkCount [2]byte // Number of forks, either 2 or 3 if there is a resource fork
6988a057
JH
26}
27
28type FlatFileInformationFork struct {
29 Platform []byte // Operating System used. ("AMAC" or "MWIN")
30 TypeSignature []byte // File type signature
31 CreatorSignature []byte // File creator signature
32 Flags []byte
33 PlatformFlags []byte
34 RSVD []byte
35 CreateDate []byte
36 ModifyDate []byte
7cd900d6 37 NameScript []byte
6988a057
JH
38 NameSize []byte // Length of file name (Maximum 128 characters)
39 Name []byte // File name
7cd900d6 40 CommentSize []byte // Length of the comment
6988a057 41 Comment []byte // File comment
45ca5d60
JH
42
43 readOffset int // Internal offset to track read progress
6988a057
JH
44}
45
2d52424e 46func NewFlatFileInformationFork(fileName string, modifyTime []byte, typeSignature string, creatorSignature string) FlatFileInformationFork {
6988a057 47 return FlatFileInformationFork{
2d52424e
JH
48 Platform: []byte("AMAC"), // TODO: Remove hardcode to support "AWIN" Platform (maybe?)
49 TypeSignature: []byte(typeSignature), // TODO: Don't infer types from filename
50 CreatorSignature: []byte(creatorSignature), // TODO: Don't infer types from filename
51 Flags: []byte{0, 0, 0, 0}, // TODO: What is this?
52 PlatformFlags: []byte{0, 0, 1, 0}, // TODO: What is this?
53 RSVD: make([]byte, 32), // Unimplemented in Hotline Protocol
54 CreateDate: modifyTime, // some filesystems don't support createTime
29f329ae
JH
55 ModifyDate: modifyTime,
56 NameScript: make([]byte, 2), // TODO: What is this?
6988a057 57 Name: []byte(fileName),
5218c782
JH
58 CommentSize: []byte{0, 0},
59 Comment: []byte{}, // TODO: implement (maybe?)
6988a057
JH
60 }
61}
62
2d52424e 63func (ffif *FlatFileInformationFork) friendlyType() []byte {
2d52424e
JH
64 if name, ok := friendlyCreatorNames[string(ffif.TypeSignature)]; ok {
65 return []byte(name)
66 }
7cd900d6
JH
67 return ffif.TypeSignature
68}
69
70func (ffif *FlatFileInformationFork) friendlyCreator() []byte {
71 if name, ok := friendlyCreatorNames[string(ffif.CreatorSignature)]; ok {
72 return []byte(name)
73 }
2d52424e
JH
74 return ffif.CreatorSignature
75}
76
7cd900d6 77func (ffif *FlatFileInformationFork) setComment(comment []byte) error {
a1ac9a6f 78 ffif.CommentSize = make([]byte, 2)
7cd900d6
JH
79 ffif.Comment = comment
80 binary.BigEndian.PutUint16(ffif.CommentSize, uint16(len(comment)))
81
82 // TODO: return err if comment is too long
83 return nil
84}
85
bb7fe19f
JH
86// DataSize calculates the size of the flat file information fork, which is
87// 72 bytes for the fixed length fields plus the length of the Name + Comment
85767504 88func (ffif *FlatFileInformationFork) DataSize() []byte {
6988a057 89 size := make([]byte, 4)
bb7fe19f 90
7cd900d6 91 dataSize := len(ffif.Name) + len(ffif.Comment) + 74 // 74 = len of fixed size headers
6988a057
JH
92
93 binary.BigEndian.PutUint32(size, uint32(dataSize))
94
95 return size
96}
97
7cd900d6
JH
98func (ffif *FlatFileInformationFork) Size() [4]byte {
99 size := [4]byte{}
100
101 dataSize := len(ffif.Name) + len(ffif.Comment) + 74 // 74 = len of fixed size headers
102
103 binary.BigEndian.PutUint32(size[:], uint32(dataSize))
104
105 return size
106}
107
108func (ffo *flattenedFileObject) TransferSize(offset int64) []byte {
109 // get length of the flattenedFileObject, including the info fork
9cf66aea
JH
110 b, _ := io.ReadAll(ffo)
111 payloadSize := len(b)
7cd900d6
JH
112
113 // length of data fork
85767504 114 dataSize := binary.BigEndian.Uint32(ffo.FlatFileDataForkHeader.DataSize[:])
6988a057 115
7cd900d6
JH
116 // length of resource fork
117 resForkSize := binary.BigEndian.Uint32(ffo.FlatFileResForkHeader.DataSize[:])
118
119 size := make([]byte, 4)
aeb97482 120 binary.BigEndian.PutUint32(size, dataSize+resForkSize+uint32(payloadSize)-uint32(offset))
6988a057 121
7cd900d6 122 return size
6988a057
JH
123}
124
85767504 125func (ffif *FlatFileInformationFork) ReadNameSize() []byte {
6988a057
JH
126 size := make([]byte, 2)
127 binary.BigEndian.PutUint16(size, uint16(len(ffif.Name)))
128
129 return size
130}
131
7cd900d6
JH
132type FlatFileForkHeader struct {
133 ForkType [4]byte // Either INFO, DATA or MACR
85767504
JH
134 CompressionType [4]byte
135 RSVD [4]byte
136 DataSize [4]byte
6988a057
JH
137}
138
9cf66aea 139func (ffif *FlatFileInformationFork) Read(p []byte) (int, error) {
45ca5d60
JH
140 buf := slices.Concat(
141 ffif.Platform,
142 ffif.TypeSignature,
143 ffif.CreatorSignature,
144 ffif.Flags,
145 ffif.PlatformFlags,
146 ffif.RSVD,
147 ffif.CreateDate,
148 ffif.ModifyDate,
149 ffif.NameScript,
150 ffif.ReadNameSize(),
151 ffif.Name,
152 ffif.CommentSize,
153 ffif.Comment,
154 )
155
156 if ffif.readOffset >= len(buf) {
157 return 0, io.EOF // All bytes have been read
158 }
159
160 n := copy(p, buf[ffif.readOffset:])
161 ffif.readOffset += n
162
163 return n, nil
9cf66aea
JH
164}
165
95159e55 166// Write implements the io.Writer interface for FlatFileInformationFork
9cf66aea
JH
167func (ffif *FlatFileInformationFork) Write(p []byte) (int, error) {
168 nameSize := p[70:72]
169 bs := binary.BigEndian.Uint16(nameSize)
170 total := 72 + bs
171
172 ffif.Platform = p[0:4]
173 ffif.TypeSignature = p[4:8]
174 ffif.CreatorSignature = p[8:12]
175 ffif.Flags = p[12:16]
176 ffif.PlatformFlags = p[16:20]
177 ffif.RSVD = p[20:52]
178 ffif.CreateDate = p[52:60]
179 ffif.ModifyDate = p[60:68]
180 ffif.NameScript = p[68:70]
181 ffif.NameSize = p[70:72]
182 ffif.Name = p[72:total]
183
184 if len(p) > int(total) {
185 ffif.CommentSize = p[total : total+2]
186 commentLen := binary.BigEndian.Uint16(ffif.CommentSize)
9cf66aea
JH
187 commentStartPos := int(total) + 2
188 commentEndPos := int(total) + 2 + int(commentLen)
189
190 ffif.Comment = p[commentStartPos:commentEndPos]
7cd900d6 191
f8e4cd54 192 //total = uint16(commentEndPos)
9cf66aea
JH
193 }
194
45ca5d60 195 return len(p), nil
7cd900d6
JH
196}
197
85767504 198func (ffif *FlatFileInformationFork) UnmarshalBinary(b []byte) error {
85767504 199 nameSize := b[70:72]
6988a057 200 bs := binary.BigEndian.Uint16(nameSize)
85767504 201 nameEnd := 72 + bs
6988a057 202
85767504
JH
203 ffif.Platform = b[0:4]
204 ffif.TypeSignature = b[4:8]
205 ffif.CreatorSignature = b[8:12]
206 ffif.Flags = b[12:16]
207 ffif.PlatformFlags = b[16:20]
208 ffif.RSVD = b[20:52]
209 ffif.CreateDate = b[52:60]
210 ffif.ModifyDate = b[60:68]
211 ffif.NameScript = b[68:70]
212 ffif.NameSize = b[70:72]
213 ffif.Name = b[72:nameEnd]
050407a3
JH
214
215 if len(b) > int(nameEnd) {
216 ffif.CommentSize = b[nameEnd : nameEnd+2]
217 commentLen := binary.BigEndian.Uint16(ffif.CommentSize)
218
219 commentStartPos := int(nameEnd) + 2
220 commentEndPos := int(nameEnd) + 2 + int(commentLen)
221
222 ffif.Comment = b[commentStartPos:commentEndPos]
223 }
85767504
JH
224
225 return nil
6988a057
JH
226}
227
9cf66aea
JH
228// Read implements the io.Reader interface for flattenedFileObject
229func (ffo *flattenedFileObject) Read(p []byte) (int, error) {
45ca5d60 230 buf := slices.Concat(
9cf66aea
JH
231 ffo.FlatFileHeader.Format[:],
232 ffo.FlatFileHeader.Version[:],
233 ffo.FlatFileHeader.RSVD[:],
234 ffo.FlatFileHeader.ForkCount[:],
235 []byte("INFO"),
236 []byte{0, 0, 0, 0},
237 make([]byte, 4),
238 ffo.FlatFileInformationFork.DataSize(),
239 ffo.FlatFileInformationFork.Platform,
240 ffo.FlatFileInformationFork.TypeSignature,
241 ffo.FlatFileInformationFork.CreatorSignature,
242 ffo.FlatFileInformationFork.Flags,
243 ffo.FlatFileInformationFork.PlatformFlags,
244 ffo.FlatFileInformationFork.RSVD,
245 ffo.FlatFileInformationFork.CreateDate,
246 ffo.FlatFileInformationFork.ModifyDate,
247 ffo.FlatFileInformationFork.NameScript,
248 ffo.FlatFileInformationFork.ReadNameSize(),
249 ffo.FlatFileInformationFork.Name,
250 ffo.FlatFileInformationFork.CommentSize,
251 ffo.FlatFileInformationFork.Comment,
252 ffo.FlatFileDataForkHeader.ForkType[:],
253 ffo.FlatFileDataForkHeader.CompressionType[:],
254 ffo.FlatFileDataForkHeader.RSVD[:],
255 ffo.FlatFileDataForkHeader.DataSize[:],
45ca5d60
JH
256 )
257
258 if ffo.readOffset >= len(buf) {
259 return 0, io.EOF // All bytes have been read
260 }
261
262 n := copy(p, buf[ffo.readOffset:])
263 ffo.readOffset += n
264
265 return n, nil
6988a057
JH
266}
267
9cf66aea
JH
268func (ffo *flattenedFileObject) ReadFrom(r io.Reader) (int64, error) {
269 var n int64
7cd900d6
JH
270
271 if err := binary.Read(r, binary.BigEndian, &ffo.FlatFileHeader); err != nil {
272 return n, err
92a7e455 273 }
7cd900d6
JH
274
275 if err := binary.Read(r, binary.BigEndian, &ffo.FlatFileInformationForkHeader); err != nil {
276 return n, err
6988a057 277 }
16a4ad70 278
7cd900d6
JH
279 dataLen := binary.BigEndian.Uint32(ffo.FlatFileInformationForkHeader.DataSize[:])
280 ffifBuf := make([]byte, dataLen)
281 if _, err := io.ReadFull(r, ffifBuf); err != nil {
282 return n, err
283 }
6988a057 284
9cf66aea
JH
285 _, err := io.Copy(&ffo.FlatFileInformationFork, bytes.NewReader(ffifBuf))
286 if err != nil {
7cd900d6 287 return n, err
6988a057
JH
288 }
289
7cd900d6
JH
290 if err := binary.Read(r, binary.BigEndian, &ffo.FlatFileDataForkHeader); err != nil {
291 return n, err
292 }
6988a057 293
7cd900d6
JH
294 return n, nil
295}
29f329ae 296
7cd900d6
JH
297func (ffo *flattenedFileObject) dataSize() int64 {
298 return int64(binary.BigEndian.Uint32(ffo.FlatFileDataForkHeader.DataSize[:]))
299}
2d52424e 300
7cd900d6
JH
301func (ffo *flattenedFileObject) rsrcSize() int64 {
302 return int64(binary.BigEndian.Uint32(ffo.FlatFileResForkHeader.DataSize[:]))
6988a057 303}