blob: 317046a89b3153581aee1ef429cd64408747176f [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'):
Jack Jansen0ae32202003-04-09 13:25:43 +000021 """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)):
31 srclist[i] = Carbon.File.pathname(srclist[i])
32 dst = Carbon.File.pathname(dst)
33
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)
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)
Jack Jansen87440e41998-07-31 09:41:59 +000055
56
57class CfrgResource:
Jack Jansen0ae32202003-04-09 13:25:43 +000058
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"
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)
Jack Jansen87440e41998-07-31 09:41:59 +000098
99
100class FragmentDescriptor:
Jack Jansen0ae32202003-04-09 13:25:43 +0000101
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:
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
156
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()
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()
Jack Jansen87440e41998-07-31 09:41:59 +0000184