Fix a bug in the ``compiler`` package that caused invalid code to be
[python/dscho.git] / Lib / plat-mac / cfmfile.py
blobfd1a3e86ca90ab2a03696a50c57e114df817c5b9
1 """codefragments.py -- wrapper to modify code fragments."""
3 # (c) 1998, Just van Rossum, Letterror
5 __version__ = "0.8b3"
6 __author__ = "jvr"
8 import Carbon.File
9 import struct
10 from Carbon 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 srclist[i] = Carbon.File.pathname(srclist[i])
32 dst = Carbon.File.pathname(dst)
34 dstfile = open(dst, "wb")
35 rf = Res.FSpOpenResFile(dst, 3)
36 try:
37 dstcfrg = CfrgResource()
38 for src in srclist:
39 srccfrg = CfrgResource(src)
40 for frag in srccfrg.fragments:
41 if frag.architecture == 'pwpc' and architecture == 'm68k':
42 continue
43 if frag.architecture == 'm68k' and architecture == 'pwpc':
44 continue
45 dstcfrg.append(frag)
47 frag.copydata(dstfile)
49 cfrgres = Res.Resource(dstcfrg.build())
50 Res.UseResFile(rf)
51 cfrgres.AddResource('cfrg', 0, "")
52 finally:
53 dstfile.close()
54 rf = Res.CloseResFile(rf)
57 class CfrgResource:
59 def __init__(self, path = None):
60 self.version = 1
61 self.fragments = []
62 self.path = path
63 if path is not None and os.path.exists(path):
64 currentresref = Res.CurResFile()
65 resref = Res.FSpOpenResFile(path, 1)
66 Res.UseResFile(resref)
67 try:
68 try:
69 data = Res.Get1Resource('cfrg', 0).data
70 except Res.Error:
71 raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback
72 finally:
73 Res.CloseResFile(resref)
74 Res.UseResFile(currentresref)
75 self.parse(data)
76 if self.version <> 1:
77 raise error, "unknown 'cfrg' resource format"
79 def parse(self, data):
80 (res1, res2, self.version,
81 res3, res4, res5, res6,
82 self.memberCount) = struct.unpack("8l", data[:32])
83 data = data[32:]
84 while data:
85 frag = FragmentDescriptor(self.path, data)
86 data = data[frag.memberSize:]
87 self.fragments.append(frag)
89 def build(self):
90 self.memberCount = len(self.fragments)
91 data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
92 for frag in self.fragments:
93 data = data + frag.build()
94 return data
96 def append(self, frag):
97 self.fragments.append(frag)
100 class FragmentDescriptor:
102 def __init__(self, path, data = None):
103 self.path = path
104 if data is not None:
105 self.parse(data)
107 def parse(self, data):
108 self.architecture = data[:4]
109 ( self.updatelevel,
110 self.currentVersion,
111 self.oldDefVersion,
112 self.stacksize,
113 self.applibdir,
114 self.fragtype,
115 self.where,
116 self.offset,
117 self.length,
118 self.res1, self.res2,
119 self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
120 pname = data[42:self.memberSize]
121 self.name = pname[1:1+ord(pname[0])]
123 def build(self):
124 data = self.architecture
125 data = data + struct.pack("4lhBB4l",
126 self.updatelevel,
127 self.currentVersion,
128 self.oldDefVersion,
129 self.stacksize,
130 self.applibdir,
131 self.fragtype,
132 self.where,
133 self.offset,
134 self.length,
135 self.res1, self.res2)
136 self.memberSize = len(data) + 2 + 1 + len(self.name)
137 # pad to 4 byte boundaries
138 if self.memberSize % 4:
139 self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
140 data = data + struct.pack("hb", self.memberSize, len(self.name))
141 data = data + self.name
142 data = data + '\000' * (self.memberSize - len(data))
143 return data
145 def getfragment(self):
146 if self.where <> 1:
147 raise error, "can't read fragment, unsupported location"
148 f = open(self.path, "rb")
149 f.seek(self.offset)
150 if self.length:
151 frag = f.read(self.length)
152 else:
153 frag = f.read()
154 f.close()
155 return frag
157 def copydata(self, outfile):
158 if self.where <> 1:
159 raise error, "can't read fragment, unsupported location"
160 infile = open(self.path, "rb")
161 if self.length == 0:
162 infile.seek(0, 2)
163 self.length = infile.tell()
165 # Position input file and record new offset from output file
166 infile.seek(self.offset)
168 # pad to 16 byte boundaries
169 offset = outfile.tell()
170 if offset % 16:
171 offset = offset + 16 - (offset % 16)
172 outfile.seek(offset)
173 self.offset = offset
175 l = self.length
176 while l:
177 if l > BUFSIZE:
178 outfile.write(infile.read(BUFSIZE))
179 l = l - BUFSIZE
180 else:
181 outfile.write(infile.read(l))
182 l = 0
183 infile.close()