Added 'description' class attribute to every command class (to help the
[python/dscho.git] / Mac / Lib / cfmfile.py
blob27c0f1c17f5f420c5f7689549f0195b442ca6720
1 """codefragments.py -- wrapper to modify code fragments."""
3 # © 1998, Just van Rossum, Letterror
5 __version__ = "0.8b3"
6 __author__ = "jvr"
8 import macfs
9 import struct
10 import Res
11 import os
12 import sys
14 DEBUG = 0
16 error = "cfm.error"
18 BUFSIZE = 0x80000
20 def mergecfmfiles(srclist, dst, architecture = 'fat'):
21 """Merge all files in srclist into a new file dst.
23 If architecture is given, only code fragments of that type will be used:
24 "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic"
25 68k code, since it does not use code fragments to begin with.
26 If architecture is None, all fragments will be used, enabling FAT binaries.
27 """
29 srclist = list(srclist)
30 for i in range(len(srclist)):
31 if type(srclist[i]) == macfs.FSSpecType:
32 srclist[i] = srclist[i].as_pathname()
33 if type(dst) == macfs.FSSpecType:
34 dst = dst.as_pathname()
36 dstfile = open(dst, "wb")
37 rf = Res.OpenResFile(dst)
38 try:
39 dstcfrg = CfrgResource()
40 for src in srclist:
41 srccfrg = CfrgResource(src)
42 for frag in srccfrg.fragments:
43 if frag.architecture == 'pwpc' and architecture == 'm68k':
44 continue
45 if frag.architecture == 'm68k' and architecture == 'pwpc':
46 continue
47 dstcfrg.append(frag)
49 frag.copydata(dstfile)
51 cfrgres = Res.Resource(dstcfrg.build())
52 Res.UseResFile(rf)
53 cfrgres.AddResource('cfrg', 0, "")
54 finally:
55 dstfile.close()
56 rf = Res.CloseResFile(rf)
59 class CfrgResource:
61 def __init__(self, path = None):
62 self.version = 1
63 self.fragments = []
64 self.path = path
65 if path is not None and os.path.exists(path):
66 currentresref = Res.CurResFile()
67 resref = Res.OpenResFile(path)
68 Res.UseResFile(resref)
69 try:
70 try:
71 data = Res.Get1Resource('cfrg', 0).data
72 except Res.Error:
73 raise Res.Error, "no Œcfrg¹ resource found", sys.exc_traceback
74 finally:
75 Res.CloseResFile(resref)
76 Res.UseResFile(currentresref)
77 self.parse(data)
78 if self.version <> 1:
79 raise error, "unknown 'cfrg' resource format"
81 def parse(self, data):
82 (res1, res2, self.version,
83 res3, res4, res5, res6,
84 self.memberCount) = struct.unpack("8l", data[:32])
85 data = data[32:]
86 while data:
87 frag = FragmentDescriptor(self.path, data)
88 data = data[frag.memberSize:]
89 self.fragments.append(frag)
91 def build(self):
92 self.memberCount = len(self.fragments)
93 data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
94 for frag in self.fragments:
95 data = data + frag.build()
96 return data
98 def append(self, frag):
99 self.fragments.append(frag)
102 class FragmentDescriptor:
104 def __init__(self, path, data = None):
105 self.path = path
106 if data is not None:
107 self.parse(data)
109 def parse(self, data):
110 self.architecture = data[:4]
111 ( self.updatelevel,
112 self.currentVersion,
113 self.oldDefVersion,
114 self.stacksize,
115 self.applibdir,
116 self.fragtype,
117 self.where,
118 self.offset,
119 self.length,
120 self.res1, self.res2,
121 self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
122 pname = data[42:self.memberSize]
123 self.name = pname[1:1+ord(pname[0])]
125 def build(self):
126 data = self.architecture
127 data = data + struct.pack("4lhBB4l",
128 self.updatelevel,
129 self.currentVersion,
130 self.oldDefVersion,
131 self.stacksize,
132 self.applibdir,
133 self.fragtype,
134 self.where,
135 self.offset,
136 self.length,
137 self.res1, self.res2)
138 self.memberSize = len(data) + 2 + 1 + len(self.name)
139 # pad to 4 byte boundaries
140 if self.memberSize % 4:
141 self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
142 data = data + struct.pack("hb", self.memberSize, len(self.name))
143 data = data + self.name
144 data = data + '\000' * (self.memberSize - len(data))
145 return data
147 def getfragment(self):
148 if self.where <> 1:
149 raise error, "can¹t read fragment, unsupported location"
150 f = open(self.path, "rb")
151 f.seek(self.offset)
152 if self.length:
153 frag = f.read(self.length)
154 else:
155 frag = f.read()
156 f.close()
157 return frag
159 def copydata(self, outfile):
160 if self.where <> 1:
161 raise error, "can¹t read fragment, unsupported location"
162 infile = open(self.path, "rb")
163 if self.length == 0:
164 infile.seek(0, 2)
165 self.length = infile.tell()
167 # Position input file and record new offset from output file
168 infile.seek(self.offset)
170 # pad to 16 byte boundaries
171 offset = outfile.tell()
172 if offset % 16:
173 offset = offset + 16 - (offset % 16)
174 outfile.seek(offset)
175 self.offset = offset
177 l = self.length
178 while l:
179 if l > BUFSIZE:
180 outfile.write(infile.read(BUFSIZE))
181 l = l - BUFSIZE
182 else:
183 outfile.write(infile.read(l))
184 l = 0
185 infile.close()