1"""codefragments.py -- wrapper to modify code fragments.""" 2 3# (c) 1998, Just van Rossum, Letterror 4 5__version__ = "0.8b3" 6__author__ = "jvr" 7 8import warnings 9warnings.warnpy3k("the cfmfile module is deprecated and is removed in 3,0", 10 stacklevel=2) 11 12import Carbon.File 13import struct 14from Carbon import Res 15import os 16import sys 17 18DEBUG = 0 19 20error = "cfm.error" 21 22BUFSIZE = 0x80000 23 24def mergecfmfiles(srclist, dst, architecture = 'fat'): 25 """Merge all files in srclist into a new file dst. 26 27 If architecture is given, only code fragments of that type will be used: 28 "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic" 29 68k code, since it does not use code fragments to begin with. 30 If architecture is None, all fragments will be used, enabling FAT binaries. 31 """ 32 33 srclist = list(srclist) 34 for i in range(len(srclist)): 35 srclist[i] = Carbon.File.pathname(srclist[i]) 36 dst = Carbon.File.pathname(dst) 37 38 dstfile = open(dst, "wb") 39 rf = Res.FSpOpenResFile(dst, 3) 40 try: 41 dstcfrg = CfrgResource() 42 for src in srclist: 43 srccfrg = CfrgResource(src) 44 for frag in srccfrg.fragments: 45 if frag.architecture == 'pwpc' and architecture == 'm68k': 46 continue 47 if frag.architecture == 'm68k' and architecture == 'pwpc': 48 continue 49 dstcfrg.append(frag) 50 51 frag.copydata(dstfile) 52 53 cfrgres = Res.Resource(dstcfrg.build()) 54 Res.UseResFile(rf) 55 cfrgres.AddResource('cfrg', 0, "") 56 finally: 57 dstfile.close() 58 rf = Res.CloseResFile(rf) 59 60 61class CfrgResource: 62 63 def __init__(self, path = None): 64 self.version = 1 65 self.fragments = [] 66 self.path = path 67 if path is not None and os.path.exists(path): 68 currentresref = Res.CurResFile() 69 resref = Res.FSpOpenResFile(path, 1) 70 Res.UseResFile(resref) 71 try: 72 try: 73 data = Res.Get1Resource('cfrg', 0).data 74 except Res.Error: 75 raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback 76 finally: 77 Res.CloseResFile(resref) 78 Res.UseResFile(currentresref) 79 self.parse(data) 80 if self.version != 1: 81 raise error, "unknown 'cfrg' resource format" 82 83 def parse(self, data): 84 (res1, res2, self.version, 85 res3, res4, res5, res6, 86 self.memberCount) = struct.unpack("8l", data[:32]) 87 data = data[32:] 88 while data: 89 frag = FragmentDescriptor(self.path, data) 90 data = data[frag.memberSize:] 91 self.fragments.append(frag) 92 93 def build(self): 94 self.memberCount = len(self.fragments) 95 data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount) 96 for frag in self.fragments: 97 data = data + frag.build() 98 return data 99 100 def append(self, frag): 101 self.fragments.append(frag) 102 103 104class FragmentDescriptor: 105 106 def __init__(self, path, data = None): 107 self.path = path 108 if data is not None: 109 self.parse(data) 110 111 def parse(self, data): 112 self.architecture = data[:4] 113 ( self.updatelevel, 114 self.currentVersion, 115 self.oldDefVersion, 116 self.stacksize, 117 self.applibdir, 118 self.fragtype, 119 self.where, 120 self.offset, 121 self.length, 122 self.res1, self.res2, 123 self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42]) 124 pname = data[42:self.memberSize] 125 self.name = pname[1:1+ord(pname[0])] 126 127 def build(self): 128 data = self.architecture 129 data = data + struct.pack("4lhBB4l", 130 self.updatelevel, 131 self.currentVersion, 132 self.oldDefVersion, 133 self.stacksize, 134 self.applibdir, 135 self.fragtype, 136 self.where, 137 self.offset, 138 self.length, 139 self.res1, self.res2) 140 self.memberSize = len(data) + 2 + 1 + len(self.name) 141 # pad to 4 byte boundaries 142 if self.memberSize % 4: 143 self.memberSize = self.memberSize + 4 - (self.memberSize % 4) 144 data = data + struct.pack("hb", self.memberSize, len(self.name)) 145 data = data + self.name 146 data = data + '\000' * (self.memberSize - len(data)) 147 return data 148 149 def getfragment(self): 150 if self.where != 1: 151 raise error, "can't read fragment, unsupported location" 152 f = open(self.path, "rb") 153 f.seek(self.offset) 154 if self.length: 155 frag = f.read(self.length) 156 else: 157 frag = f.read() 158 f.close() 159 return frag 160 161 def copydata(self, outfile): 162 if self.where != 1: 163 raise error, "can't read fragment, unsupported location" 164 infile = open(self.path, "rb") 165 if self.length == 0: 166 infile.seek(0, 2) 167 self.length = infile.tell() 168 169 # Position input file and record new offset from output file 170 infile.seek(self.offset) 171 172 # pad to 16 byte boundaries 173 offset = outfile.tell() 174 if offset % 16: 175 offset = offset + 16 - (offset % 16) 176 outfile.seek(offset) 177 self.offset = offset 178 179 l = self.length 180 while l: 181 if l > BUFSIZE: 182 outfile.write(infile.read(BUFSIZE)) 183 l = l - BUFSIZE 184 else: 185 outfile.write(infile.read(l)) 186 l = 0 187 infile.close() 188