mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 15:41:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			236 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""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
 | 
						|
	inputs = map(None, inputs)
 | 
						|
	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()
 | 
						|
	
 | 
						|
			
 |