mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +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
							 | 
						||
| 
								 | 
							
									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()
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
											
							 |