summaryrefslogtreecommitdiffstats
path: root/Mac
diff options
context:
space:
mode:
Diffstat (limited to 'Mac')
-rw-r--r--Mac/scripts/cfmfile.py235
1 files changed, 235 insertions, 0 deletions
diff --git a/Mac/scripts/cfmfile.py b/Mac/scripts/cfmfile.py
new file mode 100644
index 0000000..b39d1bc
--- /dev/null
+++ b/Mac/scripts/cfmfile.py
@@ -0,0 +1,235 @@
+"""cfmfile - Interface to code fragments on file"""
+import struct
+import Res
+import macfs
+import string
+
+Error = 'cfmfile.Error'
+
+READ = 1
+WRITE = 2
+smAllScripts = -3
+BUFSIZE = 0x100000
+
+class FragmentInfo:
+ """Information on a single fragment"""
+ def __init__(self):
+ self.arch = 'pwpc'
+ self.current_version = 0
+ self.oldest_version = 0
+ self.stacksize = 0
+ self.libdir = 0
+ self.fragtype = 1
+ self.location = 1
+ self.offset = 0
+ self.length = 0
+ self.res_0 = 0
+ self.res_1 = 0
+ self.name = ''
+ self.ifp = None
+
+ def load(self, data):
+ if len(data) < 43:
+ raise Error, 'Not enough data in cfrg resource'
+ self.arch = data[:4]
+ self.update, self.current_version, self.oldest_version, \
+ self.stacksize, self.libdir, self.fragtype, self.location, \
+ self.offset, self.length, self.res_0, self.res_1, length = \
+ struct.unpack("llllhbbllllh", data[4:42])
+ namelen = ord(data[42])
+ self.name = data[43:43+namelen]
+ if len(self.name) != namelen:
+ raise Error, 'Not enough data in cfrg resource'
+ return length
+
+ def save(self):
+ length = (43+len(self.name)+3) & ~3
+ data = self.arch + struct.pack("llllhbbllllh", self.update, \
+ self.current_version, self.oldest_version, self.stacksize, \
+ self.libdir, self.fragtype, self.location, self.offset, \
+ self.length, self.res_0, self.res_1, length)
+ data = data + chr(len(self.name)) + self.name
+ data = data + ('\0'*(length-len(data)))
+ return data
+
+ def copydata(self, ofp):
+ """Copy fragment data to a new file, updating self.offset"""
+ if self.location != 1:
+ raise Error, 'Can only copy kOnDiskFlat (data fork) fragments'
+ if not self.ifp:
+ raise Error, 'No source file for fragment'
+ # Find out real length (if zero)
+ if self.length == 0:
+ self.ifp.seek(0, 2)
+ self.length = self.ifp.tell()
+ # Position input file and record new offset from output file
+ self.ifp.seek(self.offset)
+ self.offset = ofp.tell()
+ l = self.length
+ while l:
+ if l > BUFSIZE:
+ ofp.write(self.ifp.read(BUFSIZE))
+ l = l - BUFSIZE
+ else:
+ ofp.write(self.ifp.read(l))
+ l = 0
+ self.ifp = ofp
+
+ def setfile(self, ifp):
+ self.ifp = ifp
+
+class FragmentResource:
+
+ def __init__(self, data):
+ self.load(data)
+
+ def load(self, data):
+ r0, r1, version, r3, r4, r5, r6, nfrag = struct.unpack("llllllll", data[:32])
+ if version != 1:
+ raise Error, 'Unsupported cfrg version number %d'%version
+ data = data[32:]
+ self.fragments = []
+ for i in range(nfrag):
+ f = FragmentInfo()
+ len = f.load(data)
+ data = data[len:]
+ self.fragments.append(f)
+ if data:
+ raise Error, 'Spurious data after fragment descriptions'
+
+ def save(self):
+ data = struct.pack("llllllll", 0, 0, 1, 0, 0, 0, 0, len(self.fragments))
+ for f in self.fragments:
+ data = data+f.save()
+ return data
+
+ def setfile(self, ifp):
+ for f in self.fragments:
+ f.setfile(ifp)
+
+ def copydata(self, ofp):
+ for f in self.fragments:
+ f.copydata(ofp)
+
+ def getfragments(self):
+ return self.fragments
+
+ def addfragments(self, fragments):
+ self.fragments = self.fragments + fragments
+
+class ResourceCollection:
+ def __init__(self, fhandle):
+ self.reslist = []
+ self.fhandle = fhandle
+ oldresfile = Res.CurResFile()
+ Res.UseResFile(fhandle)
+ Res.SetResLoad(0)
+ ntypes = Res.Count1Types()
+ for itype in range(1, 1+ntypes):
+ type = Res.Get1IndType(itype)
+ nresources = Res.Count1Resources(type)
+ for ires in range(1, 1+nresources):
+ res = Res.Get1IndResource(type, ires)
+ id, type, name = res.GetResInfo()
+ self.reslist.append((type, id))
+ Res.SetResLoad(1)
+ Res.UseResFile(oldresfile)
+
+ def contains(self, type, id):
+ return (type, id) in self.reslist
+
+ def getresource(self, type, id):
+ oldresfile = Res.CurResFile()
+ Res.UseResFile(self.fhandle)
+ Res.SetResLoad(1)
+ resource = Res.Get1Resource(type, id)
+ Res.UseResFile(oldresfile)
+ return resource
+
+ def saveresto(self, type, id, fhandle):
+ oldresfile = Res.CurResFile()
+ resource = self.getresource(type, id)
+ id, type, name = resource.GetResInfo()
+ resource.DetachResource()
+ Res.UseResFile(fhandle)
+ resource.AddResource(type, id, name)
+ Res.UseResFile(oldresfile)
+
+ def getreslist(self):
+ return self.reslist
+
+class CfmFile(ResourceCollection, FragmentResource):
+
+ def __init__(self, fsspec):
+ rfork = Res.FSpOpenResFile(fsspec, READ)
+ dfork = open(fsspec.as_pathname(), 'rb')
+ ResourceCollection.__init__(self, rfork)
+ cfrg_resource = self.getresource('cfrg', 0)
+ FragmentResource.__init__(self, cfrg_resource.data)
+ self.setfile(dfork)
+
+def mergecfmfiles(inputs, output):
+ # Convert inputs/outputs to fsspecs
+ for i in range(len(inputs)):
+ if type(inputs[i]) == type(''):
+ inputs[i] = macfs.FSSpec(inputs[i])
+ if type(output) == type(''):
+ output = macfs.FSSpec(output)
+
+ input_list = []
+ for i in inputs:
+ input_list.append(CfmFile(i))
+
+ # Create output file, if needed
+ creator, tp = inputs[0].GetCreatorType()
+ try:
+ Res.FSpCreateResFile(output, creator, tp, smAllScripts)
+ except Res.Error:
+ pass
+
+ # Copy fragments
+ dfork = open(output.as_pathname(), 'wb')
+ for i in input_list:
+ i.copydata(dfork)
+ dfork.close()
+
+ # Merge cfrg's
+ for i in input_list[1:]:
+ input_list[0].addfragments(i.getfragments())
+
+ old_res_file = Res.CurResFile()
+ rfork = Res.FSpOpenResFile(output, WRITE)
+ Res.UseResFile(rfork)
+
+ # Write cfrg
+ data = input_list[0].save()
+ cfrg_resource = Res.Resource(data)
+ cfrg_resource.AddResource('cfrg', 0, '')
+ resources_done = [('cfrg', 0)]
+
+ # Write other resources
+ for i in input_list:
+ todo = i.getreslist()
+ for tp, id in todo:
+ if (tp, id) in resources_done:
+ continue
+ i.saveresto(tp, id, rfork)
+ resources_done.append(tp, id)
+
+def main():
+ list = []
+ while 1:
+ fss, ok = macfs.PromptGetFile("Next input file:", "shlb", "APPL")
+ if not ok: break
+ list.append(fss)
+ if not list:
+ sys.exit(0)
+ output, ok = macfs.StandardPutFile("Output file:")
+ if not ok:
+ sys.exit(0)
+ mergecfmfiles(list, output)
+
+if __name__ == '__main__':
+ main()
+
+