| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | """codefragments.py -- wrapper to modify code fragments.""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-09-06 20:43:28 +00:00
										 |  |  | # (c) 1998, Just van Rossum, Letterror | 
					
						
							| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | __version__ = "0.8b3" | 
					
						
							|  |  |  | __author__ = "jvr" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import macfs | 
					
						
							|  |  |  | import struct | 
					
						
							| 
									
										
										
										
											2001-08-25 12:15:04 +00:00
										 |  |  | from Carbon import Res | 
					
						
							| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | 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") | 
					
						
							| 
									
										
										
										
											2000-06-20 21:59:25 +00:00
										 |  |  | 	rf = Res.FSpOpenResFile(dst, 3) | 
					
						
							| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | 	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() | 
					
						
							| 
									
										
										
										
											2000-06-20 21:59:25 +00:00
										 |  |  | 			resref = Res.FSpOpenResFile(path, 1) | 
					
						
							| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | 			Res.UseResFile(resref) | 
					
						
							|  |  |  | 			try: | 
					
						
							|  |  |  | 				try: | 
					
						
							|  |  |  | 					data = Res.Get1Resource('cfrg', 0).data | 
					
						
							|  |  |  | 				except Res.Error: | 
					
						
							| 
									
										
										
										
											2002-09-06 20:43:28 +00:00
										 |  |  | 					raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback | 
					
						
							| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | 			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: | 
					
						
							| 
									
										
										
										
											2002-09-06 20:43:28 +00:00
										 |  |  | 			raise error, "can't read fragment, unsupported location" | 
					
						
							| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | 		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: | 
					
						
							| 
									
										
										
										
											2002-09-06 20:43:28 +00:00
										 |  |  | 			raise error, "can't read fragment, unsupported location" | 
					
						
							| 
									
										
										
										
											1998-07-31 09:41:59 +00:00
										 |  |  | 		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() | 
					
						
							|  |  |  | 
 |