blob: 91ab0a61c82fabe9da093a2adc1d2564298018ec [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
Brett Cannonf0cb1d72007-05-31 20:01:11 +000014import warnings
15warnings.warn("the cfmfile module is deprecated", DeprecationWarning, 2)
16
Jack Jansen87440e41998-07-31 09:41:59 +000017DEBUG = 0
18
19error = "cfm.error"
20
21BUFSIZE = 0x80000
22
23def mergecfmfiles(srclist, dst, architecture = 'fat'):
Tim Peters182b5ac2004-07-18 06:16:08 +000024 """Merge all files in srclist into a new file dst.
25
Jack Jansen0ae32202003-04-09 13:25:43 +000026 If architecture is given, only code fragments of that type will be used:
27 "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic"
28 68k code, since it does not use code fragments to begin with.
29 If architecture is None, all fragments will be used, enabling FAT binaries.
30 """
Tim Peters182b5ac2004-07-18 06:16:08 +000031
Jack Jansen0ae32202003-04-09 13:25:43 +000032 srclist = list(srclist)
33 for i in range(len(srclist)):
34 srclist[i] = Carbon.File.pathname(srclist[i])
35 dst = Carbon.File.pathname(dst)
Tim Peters182b5ac2004-07-18 06:16:08 +000036
Jack Jansen0ae32202003-04-09 13:25:43 +000037 dstfile = open(dst, "wb")
38 rf = Res.FSpOpenResFile(dst, 3)
39 try:
40 dstcfrg = CfrgResource()
41 for src in srclist:
42 srccfrg = CfrgResource(src)
43 for frag in srccfrg.fragments:
44 if frag.architecture == 'pwpc' and architecture == 'm68k':
45 continue
46 if frag.architecture == 'm68k' and architecture == 'pwpc':
47 continue
48 dstcfrg.append(frag)
Tim Peters182b5ac2004-07-18 06:16:08 +000049
Jack Jansen0ae32202003-04-09 13:25:43 +000050 frag.copydata(dstfile)
Tim Peters182b5ac2004-07-18 06:16:08 +000051
Jack Jansen0ae32202003-04-09 13:25:43 +000052 cfrgres = Res.Resource(dstcfrg.build())
53 Res.UseResFile(rf)
54 cfrgres.AddResource('cfrg', 0, "")
55 finally:
56 dstfile.close()
57 rf = Res.CloseResFile(rf)
Jack Jansen87440e41998-07-31 09:41:59 +000058
59
60class CfrgResource:
Tim Peters182b5ac2004-07-18 06:16:08 +000061
Jack Jansen0ae32202003-04-09 13:25:43 +000062 def __init__(self, path = None):
63 self.version = 1
64 self.fragments = []
65 self.path = path
66 if path is not None and os.path.exists(path):
67 currentresref = Res.CurResFile()
68 resref = Res.FSpOpenResFile(path, 1)
69 Res.UseResFile(resref)
70 try:
71 try:
72 data = Res.Get1Resource('cfrg', 0).data
73 except Res.Error:
74 raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback
75 finally:
76 Res.CloseResFile(resref)
77 Res.UseResFile(currentresref)
78 self.parse(data)
79 if self.version <> 1:
Tim Peters182b5ac2004-07-18 06:16:08 +000080 raise error, "unknown 'cfrg' resource format"
81
Jack Jansen0ae32202003-04-09 13:25:43 +000082 def parse(self, data):
Tim Peters182b5ac2004-07-18 06:16:08 +000083 (res1, res2, self.version,
84 res3, res4, res5, res6,
Jack Jansen0ae32202003-04-09 13:25:43 +000085 self.memberCount) = struct.unpack("8l", data[:32])
86 data = data[32:]
87 while data:
88 frag = FragmentDescriptor(self.path, data)
89 data = data[frag.memberSize:]
90 self.fragments.append(frag)
Tim Peters182b5ac2004-07-18 06:16:08 +000091
Jack Jansen0ae32202003-04-09 13:25:43 +000092 def build(self):
93 self.memberCount = len(self.fragments)
94 data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
95 for frag in self.fragments:
96 data = data + frag.build()
97 return data
Tim Peters182b5ac2004-07-18 06:16:08 +000098
Jack Jansen0ae32202003-04-09 13:25:43 +000099 def append(self, frag):
100 self.fragments.append(frag)
Jack Jansen87440e41998-07-31 09:41:59 +0000101
102
103class FragmentDescriptor:
Tim Peters182b5ac2004-07-18 06:16:08 +0000104
Jack Jansen0ae32202003-04-09 13:25:43 +0000105 def __init__(self, path, data = None):
106 self.path = path
107 if data is not None:
108 self.parse(data)
Tim Peters182b5ac2004-07-18 06:16:08 +0000109
Jack Jansen0ae32202003-04-09 13:25:43 +0000110 def parse(self, data):
111 self.architecture = data[:4]
Tim Peters182b5ac2004-07-18 06:16:08 +0000112 ( self.updatelevel,
113 self.currentVersion,
114 self.oldDefVersion,
Jack Jansen0ae32202003-04-09 13:25:43 +0000115 self.stacksize,
Tim Peters182b5ac2004-07-18 06:16:08 +0000116 self.applibdir,
Jack Jansen0ae32202003-04-09 13:25:43 +0000117 self.fragtype,
118 self.where,
119 self.offset,
120 self.length,
121 self.res1, self.res2,
122 self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
123 pname = data[42:self.memberSize]
124 self.name = pname[1:1+ord(pname[0])]
Tim Peters182b5ac2004-07-18 06:16:08 +0000125
Jack Jansen0ae32202003-04-09 13:25:43 +0000126 def build(self):
127 data = self.architecture
128 data = data + struct.pack("4lhBB4l",
Tim Peters182b5ac2004-07-18 06:16:08 +0000129 self.updatelevel,
130 self.currentVersion,
131 self.oldDefVersion,
Jack Jansen0ae32202003-04-09 13:25:43 +0000132 self.stacksize,
Tim Peters182b5ac2004-07-18 06:16:08 +0000133 self.applibdir,
Jack Jansen0ae32202003-04-09 13:25:43 +0000134 self.fragtype,
135 self.where,
136 self.offset,
137 self.length,
138 self.res1, self.res2)
139 self.memberSize = len(data) + 2 + 1 + len(self.name)
140 # pad to 4 byte boundaries
141 if self.memberSize % 4:
142 self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
143 data = data + struct.pack("hb", self.memberSize, len(self.name))
144 data = data + self.name
145 data = data + '\000' * (self.memberSize - len(data))
146 return data
Tim Peters182b5ac2004-07-18 06:16:08 +0000147
Jack Jansen0ae32202003-04-09 13:25:43 +0000148 def getfragment(self):
149 if self.where <> 1:
150 raise error, "can't read fragment, unsupported location"
151 f = open(self.path, "rb")
152 f.seek(self.offset)
153 if self.length:
154 frag = f.read(self.length)
155 else:
156 frag = f.read()
157 f.close()
158 return frag
Tim Peters182b5ac2004-07-18 06:16:08 +0000159
Jack Jansen0ae32202003-04-09 13:25:43 +0000160 def copydata(self, outfile):
161 if self.where <> 1:
162 raise error, "can't read fragment, unsupported location"
163 infile = open(self.path, "rb")
164 if self.length == 0:
165 infile.seek(0, 2)
166 self.length = infile.tell()
Tim Peters182b5ac2004-07-18 06:16:08 +0000167
Jack Jansen0ae32202003-04-09 13:25:43 +0000168 # Position input file and record new offset from output file
169 infile.seek(self.offset)
Tim Peters182b5ac2004-07-18 06:16:08 +0000170
Jack Jansen0ae32202003-04-09 13:25:43 +0000171 # pad to 16 byte boundaries
172 offset = outfile.tell()
173 if offset % 16:
174 offset = offset + 16 - (offset % 16)
175 outfile.seek(offset)
176 self.offset = offset
Tim Peters182b5ac2004-07-18 06:16:08 +0000177
Jack Jansen0ae32202003-04-09 13:25:43 +0000178 l = self.length
179 while l:
180 if l > BUFSIZE:
181 outfile.write(infile.read(BUFSIZE))
182 l = l - BUFSIZE
183 else:
184 outfile.write(infile.read(l))
185 l = 0
186 infile.close()