blob: fd1a3e86ca90ab2a03696a50c57e114df817c5b9 [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'):
Tim Peters182b5ac2004-07-18 06:16:08 +000021 """Merge all files in srclist into a new file dst.
22
Jack Jansen0ae32202003-04-09 13:25:43 +000023 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 """
Tim Peters182b5ac2004-07-18 06:16:08 +000028
Jack Jansen0ae32202003-04-09 13:25:43 +000029 srclist = list(srclist)
30 for i in range(len(srclist)):
31 srclist[i] = Carbon.File.pathname(srclist[i])
32 dst = Carbon.File.pathname(dst)
Tim Peters182b5ac2004-07-18 06:16:08 +000033
Jack Jansen0ae32202003-04-09 13:25:43 +000034 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)
Tim Peters182b5ac2004-07-18 06:16:08 +000046
Jack Jansen0ae32202003-04-09 13:25:43 +000047 frag.copydata(dstfile)
Tim Peters182b5ac2004-07-18 06:16:08 +000048
Jack Jansen0ae32202003-04-09 13:25:43 +000049 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:
Tim Peters182b5ac2004-07-18 06:16:08 +000058
Jack Jansen0ae32202003-04-09 13:25:43 +000059 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:
Tim Peters182b5ac2004-07-18 06:16:08 +000077 raise error, "unknown 'cfrg' resource format"
78
Jack Jansen0ae32202003-04-09 13:25:43 +000079 def parse(self, data):
Tim Peters182b5ac2004-07-18 06:16:08 +000080 (res1, res2, self.version,
81 res3, res4, res5, res6,
Jack Jansen0ae32202003-04-09 13:25:43 +000082 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)
Tim Peters182b5ac2004-07-18 06:16:08 +000088
Jack Jansen0ae32202003-04-09 13:25:43 +000089 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
Tim Peters182b5ac2004-07-18 06:16:08 +000095
Jack Jansen0ae32202003-04-09 13:25:43 +000096 def append(self, frag):
97 self.fragments.append(frag)
Jack Jansen87440e41998-07-31 09:41:59 +000098
99
100class FragmentDescriptor:
Tim Peters182b5ac2004-07-18 06:16:08 +0000101
Jack Jansen0ae32202003-04-09 13:25:43 +0000102 def __init__(self, path, data = None):
103 self.path = path
104 if data is not None:
105 self.parse(data)
Tim Peters182b5ac2004-07-18 06:16:08 +0000106
Jack Jansen0ae32202003-04-09 13:25:43 +0000107 def parse(self, data):
108 self.architecture = data[:4]
Tim Peters182b5ac2004-07-18 06:16:08 +0000109 ( self.updatelevel,
110 self.currentVersion,
111 self.oldDefVersion,
Jack Jansen0ae32202003-04-09 13:25:43 +0000112 self.stacksize,
Tim Peters182b5ac2004-07-18 06:16:08 +0000113 self.applibdir,
Jack Jansen0ae32202003-04-09 13:25:43 +0000114 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])]
Tim Peters182b5ac2004-07-18 06:16:08 +0000122
Jack Jansen0ae32202003-04-09 13:25:43 +0000123 def build(self):
124 data = self.architecture
125 data = data + struct.pack("4lhBB4l",
Tim Peters182b5ac2004-07-18 06:16:08 +0000126 self.updatelevel,
127 self.currentVersion,
128 self.oldDefVersion,
Jack Jansen0ae32202003-04-09 13:25:43 +0000129 self.stacksize,
Tim Peters182b5ac2004-07-18 06:16:08 +0000130 self.applibdir,
Jack Jansen0ae32202003-04-09 13:25:43 +0000131 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
Tim Peters182b5ac2004-07-18 06:16:08 +0000144
Jack Jansen0ae32202003-04-09 13:25:43 +0000145 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
Tim Peters182b5ac2004-07-18 06:16:08 +0000156
Jack Jansen0ae32202003-04-09 13:25:43 +0000157 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()
Tim Peters182b5ac2004-07-18 06:16:08 +0000164
Jack Jansen0ae32202003-04-09 13:25:43 +0000165 # Position input file and record new offset from output file
166 infile.seek(self.offset)
Tim Peters182b5ac2004-07-18 06:16:08 +0000167
Jack Jansen0ae32202003-04-09 13:25:43 +0000168 # 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
Tim Peters182b5ac2004-07-18 06:16:08 +0000174
Jack Jansen0ae32202003-04-09 13:25:43 +0000175 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()