blob: a4eecf23be833c57f699d5b0f5aada6cf4643297 [file] [log] [blame]
Jack Jansen87440e41998-07-31 09:41:59 +00001"""codefragments.py -- wrapper to modify code fragments."""
2
Jack Jansen3a70e3f2002-09-06 20:43:28 +00003# (c) 1998, Just van Rossum, Letterror
Jack Jansen87440e41998-07-31 09:41:59 +00004
5__version__ = "0.8b3"
6__author__ = "jvr"
7
Jack Jansend66071b2003-02-05 15:44:03 +00008import Carbon.File
Jack Jansen87440e41998-07-31 09:41:59 +00009import struct
Jack Jansen5a6fdcd2001-08-25 12:15:04 +000010from Carbon import Res
Jack Jansen87440e41998-07-31 09:41:59 +000011import os
12import sys
13
14DEBUG = 0
15
16error = "cfm.error"
17
18BUFSIZE = 0x80000
19
20def mergecfmfiles(srclist, dst, architecture = 'fat'):
21 """Merge all files in srclist into a new file dst.
22
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 """
28
29 srclist = list(srclist)
30 for i in range(len(srclist)):
Jack Jansend66071b2003-02-05 15:44:03 +000031 srclist[i] = Carbon.File.pathname(srclist[i])
32 dst = Carbon.File.pathname(dst)
Jack Jansen87440e41998-07-31 09:41:59 +000033
34 dstfile = open(dst, "wb")
Jack Jansend13c3852000-06-20 21:59:25 +000035 rf = Res.FSpOpenResFile(dst, 3)
Jack Jansen87440e41998-07-31 09:41:59 +000036 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)
46
47 frag.copydata(dstfile)
48
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)
55
56
57class CfrgResource:
58
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()
Jack Jansend13c3852000-06-20 21:59:25 +000065 resref = Res.FSpOpenResFile(path, 1)
Jack Jansen87440e41998-07-31 09:41:59 +000066 Res.UseResFile(resref)
67 try:
68 try:
69 data = Res.Get1Resource('cfrg', 0).data
70 except Res.Error:
Jack Jansen3a70e3f2002-09-06 20:43:28 +000071 raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback
Jack Jansen87440e41998-07-31 09:41:59 +000072 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"
78
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)
88
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
95
96 def append(self, frag):
97 self.fragments.append(frag)
98
99
100class FragmentDescriptor:
101
102 def __init__(self, path, data = None):
103 self.path = path
104 if data is not None:
105 self.parse(data)
106
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])]
122
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
144
145 def getfragment(self):
146 if self.where <> 1:
Jack Jansen3a70e3f2002-09-06 20:43:28 +0000147 raise error, "can't read fragment, unsupported location"
Jack Jansen87440e41998-07-31 09:41:59 +0000148 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
156
157 def copydata(self, outfile):
158 if self.where <> 1:
Jack Jansen3a70e3f2002-09-06 20:43:28 +0000159 raise error, "can't read fragment, unsupported location"
Jack Jansen87440e41998-07-31 09:41:59 +0000160 infile = open(self.path, "rb")
161 if self.length == 0:
162 infile.seek(0, 2)
163 self.length = infile.tell()
164
165 # Position input file and record new offset from output file
166 infile.seek(self.offset)
167
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
174
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()
184