blob: f8be3d28e1a459905b9b332d1b728ed8b529eb0e [file] [log] [blame]
Jack Jansena48d4ea2001-09-09 00:35:19 +00001# applesingle - a module to decode AppleSingle files
2import struct
3import MacOS
4import sys
5
6Error="applesingle.Error"
7
8verbose=0
9
10# File header format: magic, version, unused, number of entries
11AS_HEADER_FORMAT="ll16sh"
12AS_HEADER_LENGTH=26
13# The flag words for AppleSingle
14AS_MAGIC=0x00051600
15AS_VERSION=0x00020000
16
17# Entry header format: id, offset, length
18AS_ENTRY_FORMAT="lll"
19AS_ENTRY_LENGTH=12
20
21# The id values
22AS_DATAFORK=1
23AS_RESOURCEFORK=2
24AS_IGNORE=(3,4,5,6,8,9,10,11,12,13,14,15)
25
26def decode(input, output, resonly=0):
27 if type(input) == type(''):
28 input = open(input, 'rb')
29 # Should we also test for FSSpecs or FSRefs?
30 header = input.read(AS_HEADER_LENGTH)
Jack Jansena48d4ea2001-09-09 00:35:19 +000031 try:
32 magic, version, dummy, nentry = struct.unpack(AS_HEADER_FORMAT, header)
33 except ValueError, arg:
34 raise Error, "Unpack header error: %s"%arg
35 if verbose:
36 print 'Magic: 0x%8.8x'%magic
37 print 'Version: 0x%8.8x'%version
38 print 'Entries: %d'%nentry
39 if magic != AS_MAGIC:
40 raise Error, 'Unknown AppleSingle magic number 0x%8.8x'%magic
41 if version != AS_VERSION:
42 raise Error, 'Unknown AppleSingle version number 0x%8.8x'%version
43 if nentry <= 0:
44 raise Error, "AppleSingle file contains no forks"
45 headers = [input.read(AS_ENTRY_LENGTH) for i in range(nentry)]
46 didwork = 0
47 for hdr in headers:
48 try:
49 id, offset, length = struct.unpack(AS_ENTRY_FORMAT, hdr)
50 except ValueError, arg:
51 raise Error, "Unpack entry error: %s"%arg
52 if verbose:
53 print 'Fork %d, offset %d, length %d'%(id, offset, length)
54 input.seek(offset)
55 if length == 0:
56 data = ''
57 else:
58 data = input.read(length)
59 if len(data) != length:
60 raise Error, 'Short read: expected %d bytes got %d'%(length, len(data))
61 if id == AS_DATAFORK:
62 if verbose:
63 print ' (data fork)'
64 if not resonly:
65 didwork = 1
66 fp = open(output, 'wb')
67 fp.write(data)
68 fp.close()
69 elif id == AS_RESOURCEFORK:
70 didwork = 1
71 if verbose:
72 print ' (resource fork)'
73 if resonly:
74 fp = open(output, 'wb')
75 else:
76 fp = MacOS.openrf(output, 'wb')
77 fp.write(data)
78 fp.close()
79 elif id in AS_IGNORE:
80 if verbose:
81 print ' (ignored)'
82 else:
83 raise Error, 'Unknown fork type %d'%id
84 if not didwork:
85 raise Error, 'No useful forks found'
86
87def _test():
88 if len(sys.argv) < 3 or sys.argv[1] == '-r' and len(sys.argv) != 4:
89 print 'Usage: applesingle.py [-r] applesinglefile decodedfile'
90 sys.exit(1)
91 if sys.argv[1] == '-r':
92 resonly = 1
93 del sys.argv[1]
94 else:
95 resonly = 0
96 decode(sys.argv[1], sys.argv[2], resonly=resonly)
97
98if __name__ == '__main__':
99 _test()
100