diff options
-rw-r--r-- | Mac/Lib/cfmfile.py | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/Mac/Lib/cfmfile.py b/Mac/Lib/cfmfile.py new file mode 100644 index 0000000..27c0f1c --- /dev/null +++ b/Mac/Lib/cfmfile.py @@ -0,0 +1,186 @@ +"""codefragments.py -- wrapper to modify code fragments.""" + +# © 1998, Just van Rossum, Letterror + +__version__ = "0.8b3" +__author__ = "jvr" + +import macfs +import struct +import Res +import os +import sys + +DEBUG = 0 + +error = "cfm.error" + +BUFSIZE = 0x80000 + +def mergecfmfiles(srclist, dst, architecture = 'fat'): + """Merge all files in srclist into a new file dst. + + If architecture is given, only code fragments of that type will be used: + "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic" + 68k code, since it does not use code fragments to begin with. + If architecture is None, all fragments will be used, enabling FAT binaries. + """ + + srclist = list(srclist) + for i in range(len(srclist)): + if type(srclist[i]) == macfs.FSSpecType: + srclist[i] = srclist[i].as_pathname() + if type(dst) == macfs.FSSpecType: + dst = dst.as_pathname() + + dstfile = open(dst, "wb") + rf = Res.OpenResFile(dst) + try: + dstcfrg = CfrgResource() + for src in srclist: + srccfrg = CfrgResource(src) + for frag in srccfrg.fragments: + if frag.architecture == 'pwpc' and architecture == 'm68k': + continue + if frag.architecture == 'm68k' and architecture == 'pwpc': + continue + dstcfrg.append(frag) + + frag.copydata(dstfile) + + cfrgres = Res.Resource(dstcfrg.build()) + Res.UseResFile(rf) + cfrgres.AddResource('cfrg', 0, "") + finally: + dstfile.close() + rf = Res.CloseResFile(rf) + + +class CfrgResource: + + def __init__(self, path = None): + self.version = 1 + self.fragments = [] + self.path = path + if path is not None and os.path.exists(path): + currentresref = Res.CurResFile() + resref = Res.OpenResFile(path) + Res.UseResFile(resref) + try: + try: + data = Res.Get1Resource('cfrg', 0).data + except Res.Error: + raise Res.Error, "no Ścfrgą resource found", sys.exc_traceback + finally: + Res.CloseResFile(resref) + Res.UseResFile(currentresref) + self.parse(data) + if self.version <> 1: + raise error, "unknown 'cfrg' resource format" + + def parse(self, data): + (res1, res2, self.version, + res3, res4, res5, res6, + self.memberCount) = struct.unpack("8l", data[:32]) + data = data[32:] + while data: + frag = FragmentDescriptor(self.path, data) + data = data[frag.memberSize:] + self.fragments.append(frag) + + def build(self): + self.memberCount = len(self.fragments) + data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount) + for frag in self.fragments: + data = data + frag.build() + return data + + def append(self, frag): + self.fragments.append(frag) + + +class FragmentDescriptor: + + def __init__(self, path, data = None): + self.path = path + if data is not None: + self.parse(data) + + def parse(self, data): + self.architecture = data[:4] + ( self.updatelevel, + self.currentVersion, + self.oldDefVersion, + self.stacksize, + self.applibdir, + self.fragtype, + self.where, + self.offset, + self.length, + self.res1, self.res2, + self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42]) + pname = data[42:self.memberSize] + self.name = pname[1:1+ord(pname[0])] + + def build(self): + data = self.architecture + data = data + struct.pack("4lhBB4l", + self.updatelevel, + self.currentVersion, + self.oldDefVersion, + self.stacksize, + self.applibdir, + self.fragtype, + self.where, + self.offset, + self.length, + self.res1, self.res2) + self.memberSize = len(data) + 2 + 1 + len(self.name) + # pad to 4 byte boundaries + if self.memberSize % 4: + self.memberSize = self.memberSize + 4 - (self.memberSize % 4) + data = data + struct.pack("hb", self.memberSize, len(self.name)) + data = data + self.name + data = data + '\000' * (self.memberSize - len(data)) + return data + + def getfragment(self): + if self.where <> 1: + raise error, "canąt read fragment, unsupported location" + f = open(self.path, "rb") + f.seek(self.offset) + if self.length: + frag = f.read(self.length) + else: + frag = f.read() + f.close() + return frag + + def copydata(self, outfile): + if self.where <> 1: + raise error, "canąt read fragment, unsupported location" + infile = open(self.path, "rb") + if self.length == 0: + infile.seek(0, 2) + self.length = infile.tell() + + # Position input file and record new offset from output file + infile.seek(self.offset) + + # pad to 16 byte boundaries + offset = outfile.tell() + if offset % 16: + offset = offset + 16 - (offset % 16) + outfile.seek(offset) + self.offset = offset + + l = self.length + while l: + if l > BUFSIZE: + outfile.write(infile.read(BUFSIZE)) + l = l - BUFSIZE + else: + outfile.write(infile.read(l)) + l = 0 + infile.close() + |