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