1 r
"""Routines to decode AppleSingle files
4 from warnings
import warnpy3k
5 warnpy3k("In 3.x, the applesingle module is removed.", stacklevel
=2)
14 def openrf(path
, mode
):
15 return open(path
+ '.rsrc', mode
)
16 openrf
= classmethod(openrf
)
26 # all of the errors in this module are really errors in the input
27 # so I think it should test positive against ValueError.
28 class Error(ValueError):
31 # File header format: magic, version, unused, number of entries
32 AS_HEADER_FORMAT
=">LL16sh"
34 # The flag words for AppleSingle
38 # Entry header format: id, offset, length
39 AS_ENTRY_FORMAT
=">lll"
45 AS_IGNORE
=(3,4,5,6,8,9,10,11,12,13,14,15)
47 class AppleSingle(object):
51 def __init__(self
, fileobj
, verbose
=False):
52 header
= fileobj
.read(AS_HEADER_LENGTH
)
54 magic
, version
, ig
, nentry
= struct
.unpack(AS_HEADER_FORMAT
, header
)
55 except ValueError, arg
:
56 raise Error
, "Unpack header error: %s" % (arg
,)
58 print 'Magic: 0x%8.8x' % (magic
,)
59 print 'Version: 0x%8.8x' % (version
,)
60 print 'Entries: %d' % (nentry
,)
62 raise Error
, "Unknown AppleSingle magic number 0x%8.8x" % (magic
,)
63 if version
!= AS_VERSION
:
64 raise Error
, "Unknown AppleSingle version number 0x%8.8x" % (version
,)
66 raise Error
, "AppleSingle file contains no forks"
67 headers
= [fileobj
.read(AS_ENTRY_LENGTH
) for i
in xrange(nentry
)]
71 restype
, offset
, length
= struct
.unpack(AS_ENTRY_FORMAT
, hdr
)
72 except ValueError, arg
:
73 raise Error
, "Unpack entry error: %s" % (arg
,)
75 print "Fork %d, offset %d, length %d" % (restype
, offset
, length
)
77 data
= fileobj
.read(length
)
78 if len(data
) != length
:
79 raise Error
, "Short read: expected %d bytes got %d" % (length
, len(data
))
80 self
.forks
.append((restype
, data
))
81 if restype
== AS_DATAFORK
:
83 elif restype
== AS_RESOURCEFORK
:
84 self
.resourcefork
= data
86 def tofile(self
, path
, resonly
=False):
87 outfile
= open(path
, 'wb')
90 if self
.resourcefork
is None:
91 raise Error
, "No resource fork found"
93 fp
.write(self
.resourcefork
)
95 elif (self
.resourcefork
is None and self
.datafork
is None):
96 raise Error
, "No useful forks found"
98 if self
.datafork
is not None:
100 fp
.write(self
.datafork
)
102 if self
.resourcefork
is not None:
103 fp
= MacOS
.openrf(path
, '*wb')
104 fp
.write(self
.resourcefork
)
107 def decode(infile
, outpath
, resonly
=False, verbose
=False):
108 """decode(infile, outpath [, resonly=False, verbose=False])
110 Creates a decoded file from an AppleSingle encoded file.
111 If resonly is True, then it will create a regular file at
112 outpath containing only the resource fork from infile.
113 Otherwise it will create an AppleDouble file at outpath
114 with the data and resource forks from infile. On platforms
115 without the MacOS module, it will create inpath and inpath+'.rsrc'
116 with the data and resource forks respectively.
119 if not hasattr(infile
, 'read'):
120 if isinstance(infile
, Carbon
.File
.Alias
):
121 infile
= infile
.ResolveAlias()[0]
122 if isinstance(infile
, (Carbon
.File
.FSSpec
, Carbon
.File
.FSRef
)):
123 infile
= infile
.as_pathname()
124 infile
= open(infile
, 'rb')
126 asfile
= AppleSingle(infile
, verbose
=verbose
)
127 asfile
.tofile(outpath
, resonly
=resonly
)
130 if len(sys
.argv
) < 3 or sys
.argv
[1] == '-r' and len(sys
.argv
) != 4:
131 print 'Usage: applesingle.py [-r] applesinglefile decodedfile'
133 if sys
.argv
[1] == '-r':
138 decode(sys
.argv
[1], sys
.argv
[2], resonly
=resonly
)
140 if __name__
== '__main__':