mirror of https://github.com/python/cpython
Module to merge 'cfrg' resources (to create fat ppc/cfm68k programs
and shared libraries).
This commit is contained in:
parent
2e146b332c
commit
c70c350f5d
|
@ -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()
|
||||
|
||||
|
Loading…
Reference in New Issue