| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | """binhex - Macintosh binhex compression/decompression
 | 
					
						
							|  |  |  | easy interface: | 
					
						
							|  |  |  | binhex(inputfilename, outputfilename) | 
					
						
							|  |  |  | hexbin(inputfilename, outputfilename) | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Jack Jansen, CWI, August 1995. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # The module is supposed to be as compatible as possible. Especially the | 
					
						
							|  |  |  | # easy interface should work "as expected" on any platform. | 
					
						
							|  |  |  | # XXXX Note: currently, textfiles appear in mac-form on all platforms. | 
					
						
							|  |  |  | # We seem to lack a simple character-translate in python. | 
					
						
							|  |  |  | # (we should probably use ISO-Latin-1 on all but the mac platform). | 
					
						
							|  |  |  | # XXXX The simeple routines are too simple: they expect to hold the complete | 
					
						
							|  |  |  | # files in-core. Should be fixed. | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | # XXXX It would be nice to handle AppleDouble format on unix | 
					
						
							|  |  |  | # (for servers serving macs). | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | # XXXX I don't understand what happens when you get 0x90 times the same byte on | 
					
						
							|  |  |  | # input. The resulting code (xx 90 90) would appear to be interpreted as an | 
					
						
							|  |  |  | # escaped *value* of 0x90. All coders I've seen appear to ignore this nicety... | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import struct | 
					
						
							|  |  |  | import string | 
					
						
							|  |  |  | import binascii | 
					
						
							| 
									
										
										
										
											1995-08-14 12:41:20 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | Error = 'binhex.Error' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # States (what have we written) | 
					
						
							|  |  |  | [_DID_HEADER, _DID_DATA, _DID_RSRC] = range(3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Various constants | 
					
						
							|  |  |  | REASONABLY_LARGE=32768	# Minimal amount we pass the rle-coder | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | LINELEN=64 | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | RUNCHAR=chr(0x90)	# run-length introducer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | # This code is no longer byte-order dependent | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Workarounds for non-mac machines. | 
					
						
							|  |  |  | if os.name == 'mac': | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	import macfs | 
					
						
							|  |  |  | 	import MacOS | 
					
						
							|  |  |  | 	try: | 
					
						
							|  |  |  | 		openrf = MacOS.openrf | 
					
						
							|  |  |  | 	except AttributeError: | 
					
						
							|  |  |  | 		# Backward compatability | 
					
						
							|  |  |  | 		openrf = open | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def FInfo(): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		return macfs.FInfo() | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	def getfileinfo(name): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		finfo = macfs.FSSpec(name).GetFInfo() | 
					
						
							|  |  |  | 		dir, file = os.path.split(name) | 
					
						
							|  |  |  | 		# XXXX Get resource/data sizes | 
					
						
							|  |  |  | 		fp = open(name, 'rb') | 
					
						
							|  |  |  | 		fp.seek(0, 2) | 
					
						
							|  |  |  | 		dlen = fp.tell() | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		fp = openrf(name, '*rb') | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		fp.seek(0, 2) | 
					
						
							|  |  |  | 		rlen = fp.tell() | 
					
						
							|  |  |  | 		return file, finfo, dlen, rlen | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	def openrsrc(name, *mode): | 
					
						
							|  |  |  | 		if not mode: | 
					
						
							|  |  |  | 			mode = '*rb' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		else: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			mode = '*' + mode[0] | 
					
						
							|  |  |  | 		return openrf(name, mode) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | else: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	# | 
					
						
							|  |  |  | 	# Glue code for non-macintosh useage | 
					
						
							|  |  |  | 	# | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	class FInfo: | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		def __init__(self): | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			self.Type = '????' | 
					
						
							|  |  |  | 			self.Creator = '????' | 
					
						
							|  |  |  | 			self.Flags = 0 | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def getfileinfo(name): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		finfo = FInfo() | 
					
						
							|  |  |  | 		# Quick check for textfile | 
					
						
							|  |  |  | 		fp = open(name) | 
					
						
							|  |  |  | 		data = open(name).read(256) | 
					
						
							|  |  |  | 		for c in data: | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 			if not c in string.whitespace \ | 
					
						
							|  |  |  | 			    and (c<' ' or ord(c) > 0177): | 
					
						
							|  |  |  | 				break | 
					
						
							| 
									
										
										
										
											1997-02-11 16:39:31 +00:00
										 |  |  | 		else: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			finfo.Type = 'TEXT' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		fp.seek(0, 2) | 
					
						
							|  |  |  | 		dsize = fp.tell() | 
					
						
							|  |  |  | 		fp.close() | 
					
						
							|  |  |  | 		dir, file = os.path.split(name) | 
					
						
							| 
									
										
										
										
											1997-12-24 21:18:41 +00:00
										 |  |  | 		file = string.replace(file, ':', '-', 1) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		return file, finfo, dsize, 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	class openrsrc: | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		def __init__(self, *args): | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			pass | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 		def read(self, *args): | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			return '' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 		def write(self, *args): | 
					
						
							|  |  |  | 			pass | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		def close(self): | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			pass | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | class _Hqxcoderengine: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	"""Write data to the coder in 3-byte chunks""" | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def __init__(self, ofp): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ofp = ofp | 
					
						
							|  |  |  | 		self.data = '' | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		self.hqxdata = '' | 
					
						
							|  |  |  | 		self.linelen = LINELEN-1 | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def write(self, data): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.data = self.data + data | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		datalen = len(self.data) | 
					
						
							|  |  |  | 		todo = (datalen/3)*3 | 
					
						
							|  |  |  | 		data = self.data[:todo] | 
					
						
							|  |  |  | 		self.data = self.data[todo:] | 
					
						
							| 
									
										
										
										
											1996-03-25 18:54:33 +00:00
										 |  |  | 		if not data: | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		self.hqxdata = self.hqxdata + binascii.b2a_hqx(data) | 
					
						
							| 
									
										
										
										
											1996-03-25 18:54:33 +00:00
										 |  |  | 		self._flush(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def _flush(self, force): | 
					
						
							|  |  |  | 		first = 0 | 
					
						
							|  |  |  | 		while first <= len(self.hqxdata)-self.linelen: | 
					
						
							|  |  |  | 			last = first + self.linelen | 
					
						
							|  |  |  | 			self.ofp.write(self.hqxdata[first:last]+'\n') | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			self.linelen = LINELEN | 
					
						
							| 
									
										
										
										
											1996-03-25 18:54:33 +00:00
										 |  |  | 			first = last | 
					
						
							|  |  |  | 		self.hqxdata = self.hqxdata[first:] | 
					
						
							|  |  |  | 		if force: | 
					
						
							|  |  |  | 			self.ofp.write(self.hqxdata + ':\n') | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	def close(self): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.data: | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 			self.hqxdata = \ | 
					
						
							|  |  |  | 			     self.hqxdata + binascii.b2a_hqx(self.data) | 
					
						
							| 
									
										
										
										
											1996-03-25 18:54:33 +00:00
										 |  |  | 		self._flush(1) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ofp.close() | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		del self.ofp | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _Rlecoderengine: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	"""Write data to the RLE-coder in suitably large chunks""" | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def __init__(self, ofp): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ofp = ofp | 
					
						
							|  |  |  | 		self.data = '' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def write(self, data): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.data = self.data + data | 
					
						
							|  |  |  | 		if len(self.data) < REASONABLY_LARGE: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		rledata = binascii.rlecode_hqx(self.data) | 
					
						
							|  |  |  | 		self.ofp.write(rledata) | 
					
						
							|  |  |  | 		self.data = '' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def close(self): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.data: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			rledata = binascii.rlecode_hqx(self.data) | 
					
						
							|  |  |  | 			self.ofp.write(rledata) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ofp.close() | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		del self.ofp | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class BinHex: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def __init__(self, (name, finfo, dlen, rlen), ofp): | 
					
						
							|  |  |  | 		if type(ofp) == type(''): | 
					
						
							|  |  |  | 			ofname = ofp | 
					
						
							|  |  |  | 			ofp = open(ofname, 'w') | 
					
						
							|  |  |  | 			if os.name == 'mac': | 
					
						
							|  |  |  | 				fss = macfs.FSSpec(ofname) | 
					
						
							|  |  |  | 				fss.SetCreatorType('BnHq', 'TEXT') | 
					
						
							|  |  |  | 		ofp.write('(This file must be converted with BinHex 4.0)\n\n:') | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		hqxer = _Hqxcoderengine(ofp) | 
					
						
							|  |  |  | 		self.ofp = _Rlecoderengine(hqxer) | 
					
						
							|  |  |  | 		self.crc = 0 | 
					
						
							|  |  |  | 		if finfo == None: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			finfo = FInfo() | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.dlen = dlen | 
					
						
							|  |  |  | 		self.rlen = rlen | 
					
						
							|  |  |  | 		self._writeinfo(name, finfo) | 
					
						
							|  |  |  | 		self.state = _DID_HEADER | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def _writeinfo(self, name, finfo): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		name = name | 
					
						
							|  |  |  | 		nl = len(name) | 
					
						
							|  |  |  | 		if nl > 63: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			raise Error, 'Filename too long' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		d = chr(nl) + name + '\0' | 
					
						
							|  |  |  | 		d2 = finfo.Type + finfo.Creator | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		# Force all structs to be packed with big-endian | 
					
						
							|  |  |  | 		d3 = struct.pack('>h', finfo.Flags) | 
					
						
							|  |  |  | 		d4 = struct.pack('>ii', self.dlen, self.rlen) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		info = d + d2 + d3 + d4 | 
					
						
							|  |  |  | 		self._write(info) | 
					
						
							|  |  |  | 		self._writecrc() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def _write(self, data): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.crc = binascii.crc_hqx(data, self.crc) | 
					
						
							|  |  |  | 		self.ofp.write(data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def _writecrc(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 20:56:10 +00:00
										 |  |  | 		# XXXX Should this be here?? | 
					
						
							|  |  |  | 		# self.crc = binascii.crc_hqx('\0\0', self.crc) | 
					
						
							|  |  |  | 		self.ofp.write(struct.pack('>h', self.crc)) | 
					
						
							|  |  |  | 		self.crc = 0 | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def write(self, data): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.state != _DID_HEADER: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			raise Error, 'Writing data at the wrong time' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.dlen = self.dlen - len(data) | 
					
						
							|  |  |  | 		self._write(data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def close_data(self): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.dlen <> 0: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			raise Error, 'Incorrect data size, diff='+`self.rlen` | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self._writecrc() | 
					
						
							|  |  |  | 		self.state = _DID_DATA | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def write_rsrc(self, data): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.state < _DID_DATA: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			self.close_data() | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.state != _DID_DATA: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			raise Error, 'Writing resource data at the wrong time' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.rlen = self.rlen - len(data) | 
					
						
							|  |  |  | 		self._write(data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def close(self): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.state < _DID_DATA: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			self.close_data() | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.state != _DID_DATA: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			raise Error, 'Close at the wrong time' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.rlen <> 0: | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 			raise Error, \ | 
					
						
							|  |  |  | 			      "Incorrect resource-datasize, diff="+`self.rlen` | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self._writecrc() | 
					
						
							|  |  |  | 		self.ofp.close() | 
					
						
							|  |  |  | 		self.state = None | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		del self.ofp | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | def binhex(inp, out): | 
					
						
							|  |  |  | 	"""(infilename, outfilename) - Create binhex-encoded copy of a file""" | 
					
						
							|  |  |  | 	finfo = getfileinfo(inp) | 
					
						
							|  |  |  | 	ofp = BinHex(finfo, out) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	ifp = open(inp, 'rb') | 
					
						
							|  |  |  | 	# XXXX Do textfile translation on non-mac systems | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	while 1: | 
					
						
							|  |  |  | 		d = ifp.read(128000) | 
					
						
							|  |  |  | 		if not d: break | 
					
						
							|  |  |  | 		ofp.write(d) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	ofp.close_data() | 
					
						
							|  |  |  | 	ifp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ifp = openrsrc(inp, 'rb') | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	while 1: | 
					
						
							|  |  |  | 		d = ifp.read(128000) | 
					
						
							|  |  |  | 		if not d: break | 
					
						
							|  |  |  | 		ofp.write_rsrc(d) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	ofp.close() | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	ifp.close()  | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class _Hqxdecoderengine: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	"""Read data via the decoder in 4-byte chunks""" | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def __init__(self, ifp): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ifp = ifp | 
					
						
							|  |  |  | 		self.eof = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def read(self, totalwtd): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		"""Read at least wtd bytes (or until EOF)""" | 
					
						
							|  |  |  | 		decdata = '' | 
					
						
							| 
									
										
										
										
											1995-10-03 14:41:15 +00:00
										 |  |  | 		wtd = totalwtd | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		# | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 		# The loop here is convoluted, since we don't really now how  | 
					
						
							|  |  |  | 		# much to decode: there may be newlines in the incoming data. | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		while wtd > 0: | 
					
						
							|  |  |  | 			if self.eof: return decdata | 
					
						
							|  |  |  | 			wtd = ((wtd+2)/3)*4 | 
					
						
							|  |  |  | 			data = self.ifp.read(wtd) | 
					
						
							|  |  |  | 			# | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 			# Next problem: there may not be a complete number of | 
					
						
							|  |  |  | 			# bytes in what we pass to a2b. Solve by yet another | 
					
						
							|  |  |  | 			# loop. | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 			# | 
					
						
							|  |  |  | 			while 1: | 
					
						
							|  |  |  | 				try: | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 					decdatacur, self.eof = \ | 
					
						
							|  |  |  | 						    binascii.a2b_hqx(data) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 					break | 
					
						
							|  |  |  | 				except binascii.Incomplete: | 
					
						
							|  |  |  | 					pass | 
					
						
							|  |  |  | 				newdata = self.ifp.read(1) | 
					
						
							|  |  |  | 				if not newdata: | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 					raise Error, \ | 
					
						
							|  |  |  | 					      'Premature EOF on binhex file' | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 				data = data + newdata | 
					
						
							|  |  |  | 			decdata = decdata + decdatacur | 
					
						
							| 
									
										
										
										
											1995-10-03 14:41:15 +00:00
										 |  |  | 			wtd = totalwtd - len(decdata) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 			if not decdata and not self.eof: | 
					
						
							|  |  |  | 				raise Error, 'Premature EOF on binhex file' | 
					
						
							|  |  |  | 		return decdata | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def close(self): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ifp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _Rledecoderengine: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	"""Read data via the RLE-coder""" | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def __init__(self, ifp): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ifp = ifp | 
					
						
							|  |  |  | 		self.pre_buffer = '' | 
					
						
							|  |  |  | 		self.post_buffer = '' | 
					
						
							|  |  |  | 		self.eof = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def read(self, wtd): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if wtd > len(self.post_buffer): | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			self._fill(wtd-len(self.post_buffer)) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		rv = self.post_buffer[:wtd] | 
					
						
							|  |  |  | 		self.post_buffer = self.post_buffer[wtd:] | 
					
						
							|  |  |  | 		return rv | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def _fill(self, wtd): | 
					
						
							| 
									
										
										
										
											1997-02-11 16:39:31 +00:00
										 |  |  | 		self.pre_buffer = self.pre_buffer + self.ifp.read(wtd+4) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.ifp.eof: | 
					
						
							|  |  |  | 			self.post_buffer = self.post_buffer + \ | 
					
						
							|  |  |  | 				binascii.rledecode_hqx(self.pre_buffer) | 
					
						
							|  |  |  | 			self.pre_buffer = '' | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											1997-02-11 16:39:31 +00:00
										 |  |  | 		# | 
					
						
							|  |  |  | 		# Obfuscated code ahead. We have to take care that we don't | 
					
						
							|  |  |  | 		# end up with an orphaned RUNCHAR later on. So, we keep a couple | 
					
						
							|  |  |  | 		# of bytes in the buffer, depending on what the end of | 
					
						
							|  |  |  | 		# the buffer looks like: | 
					
						
							|  |  |  | 		# '\220\0\220' - Keep 3 bytes: repeated \220 (escaped as \220\0) | 
					
						
							|  |  |  | 		# '?\220' - Keep 2 bytes: repeated something-else | 
					
						
							|  |  |  | 		# '\220\0' - Escaped \220: Keep 2 bytes. | 
					
						
							|  |  |  | 		# '?\220?' - Complete repeat sequence: decode all | 
					
						
							|  |  |  | 		# otherwise: keep 1 byte. | 
					
						
							|  |  |  | 		# | 
					
						
							|  |  |  | 		mark = len(self.pre_buffer) | 
					
						
							|  |  |  | 		if self.pre_buffer[-3:] == RUNCHAR + '\0' + RUNCHAR: | 
					
						
							|  |  |  | 			mark = mark - 3 | 
					
						
							|  |  |  | 		elif self.pre_buffer[-1] == RUNCHAR: | 
					
						
							|  |  |  | 			mark = mark - 2 | 
					
						
							|  |  |  | 		elif self.pre_buffer[-2:] == RUNCHAR + '\0': | 
					
						
							|  |  |  | 			mark = mark - 2 | 
					
						
							|  |  |  | 		elif self.pre_buffer[-2] == RUNCHAR: | 
					
						
							|  |  |  | 			pass # Decode all | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		else: | 
					
						
							| 
									
										
										
										
											1997-02-11 16:39:31 +00:00
										 |  |  | 			mark = mark - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.post_buffer = self.post_buffer + \ | 
					
						
							|  |  |  | 			binascii.rledecode_hqx(self.pre_buffer[:mark]) | 
					
						
							|  |  |  | 		self.pre_buffer = self.pre_buffer[mark:] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def close(self): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.ifp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HexBin: | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def __init__(self, ifp): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if type(ifp) == type(''): | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 			ifp = open(ifp) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		# | 
					
						
							|  |  |  | 		# Find initial colon. | 
					
						
							|  |  |  | 		# | 
					
						
							|  |  |  | 		while 1: | 
					
						
							|  |  |  | 			ch = ifp.read(1) | 
					
						
							|  |  |  | 			if not ch: | 
					
						
							|  |  |  | 				raise Error, "No binhex data found" | 
					
						
							| 
									
										
										
										
											1997-02-11 16:39:31 +00:00
										 |  |  | 			# Cater for \r\n terminated lines (which show up as \n\r, hence | 
					
						
							|  |  |  | 			# all lines start with \r) | 
					
						
							|  |  |  | 			if ch == '\r': | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 			if ch == ':': | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			if ch != '\n': | 
					
						
							|  |  |  | 				dummy = ifp.readline() | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		hqxifp = _Hqxdecoderengine(ifp) | 
					
						
							|  |  |  | 		self.ifp = _Rledecoderengine(hqxifp) | 
					
						
							|  |  |  | 		self.crc = 0 | 
					
						
							|  |  |  | 		self._readheader() | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def _read(self, len): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		data = self.ifp.read(len) | 
					
						
							|  |  |  | 		self.crc = binascii.crc_hqx(data, self.crc) | 
					
						
							|  |  |  | 		return data | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def _checkcrc(self): | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 		filecrc = struct.unpack('>h', self.ifp.read(2))[0] & 0xffff | 
					
						
							|  |  |  | 		#self.crc = binascii.crc_hqx('\0\0', self.crc) | 
					
						
							|  |  |  | 		# XXXX Is this needed?? | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.crc = self.crc & 0xffff | 
					
						
							| 
									
										
										
										
											1995-10-03 14:41:15 +00:00
										 |  |  | 		if filecrc != self.crc: | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 			raise Error, 'CRC error, computed %x, read %x' \ | 
					
						
							|  |  |  | 			      %(self.crc, filecrc) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.crc = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def _readheader(self): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		len = self._read(1) | 
					
						
							|  |  |  | 		fname = self._read(ord(len)) | 
					
						
							|  |  |  | 		rest = self._read(1+4+4+2+4+4) | 
					
						
							|  |  |  | 		self._checkcrc() | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		type = rest[1:5] | 
					
						
							|  |  |  | 		creator = rest[5:9] | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 		flags = struct.unpack('>h', rest[9:11])[0] | 
					
						
							|  |  |  | 		self.dlen = struct.unpack('>l', rest[11:15])[0] | 
					
						
							|  |  |  | 		self.rlen = struct.unpack('>l', rest[15:19])[0] | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		self.FName = fname | 
					
						
							|  |  |  | 		self.FInfo = FInfo() | 
					
						
							|  |  |  | 		self.FInfo.Creator = creator | 
					
						
							|  |  |  | 		self.FInfo.Type = type | 
					
						
							|  |  |  | 		self.FInfo.Flags = flags | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		self.state = _DID_HEADER | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def read(self, *n): | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if self.state != _DID_HEADER: | 
					
						
							|  |  |  | 			raise Error, 'Read data at wrong time' | 
					
						
							|  |  |  | 		if n: | 
					
						
							|  |  |  | 			n = n[0] | 
					
						
							|  |  |  | 			n = min(n, self.dlen) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			n = self.dlen | 
					
						
							| 
									
										
										
										
											1997-02-11 16:39:31 +00:00
										 |  |  | 		rv = '' | 
					
						
							|  |  |  | 		while len(rv) < n: | 
					
						
							|  |  |  | 			rv = rv + self._read(n-len(rv)) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		self.dlen = self.dlen - n | 
					
						
							| 
									
										
										
										
											1997-02-11 16:39:31 +00:00
										 |  |  | 		return rv | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def close_data(self): | 
					
						
							|  |  |  | 		if self.state != _DID_HEADER: | 
					
						
							|  |  |  | 			raise Error, 'close_data at wrong time' | 
					
						
							|  |  |  | 		if self.dlen: | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 			dummy = self._read(self.dlen) | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		self._checkcrc() | 
					
						
							|  |  |  | 		self.state = _DID_DATA | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def read_rsrc(self, *n): | 
					
						
							|  |  |  | 		if self.state == _DID_HEADER: | 
					
						
							|  |  |  | 			self.close_data() | 
					
						
							|  |  |  | 		if self.state != _DID_DATA: | 
					
						
							|  |  |  | 			raise Error, 'Read resource data at wrong time' | 
					
						
							|  |  |  | 		if n: | 
					
						
							|  |  |  | 			n = n[0] | 
					
						
							|  |  |  | 			n = min(n, self.rlen) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			n = self.rlen | 
					
						
							|  |  |  | 		self.rlen = self.rlen - n | 
					
						
							|  |  |  | 		return self._read(n) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	def close(self): | 
					
						
							|  |  |  | 		if self.rlen: | 
					
						
							|  |  |  | 			dummy = self.read_rsrc(self.rlen) | 
					
						
							|  |  |  | 		self._checkcrc() | 
					
						
							|  |  |  | 		self.state = _DID_RSRC | 
					
						
							|  |  |  | 		self.ifp.close() | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | def hexbin(inp, out): | 
					
						
							|  |  |  | 	"""(infilename, outfilename) - Decode binhexed file""" | 
					
						
							|  |  |  | 	ifp = HexBin(inp) | 
					
						
							|  |  |  | 	finfo = ifp.FInfo | 
					
						
							|  |  |  | 	if not out: | 
					
						
							|  |  |  | 		out = ifp.FName | 
					
						
							|  |  |  | 	if os.name == 'mac': | 
					
						
							|  |  |  | 		ofss = macfs.FSSpec(out) | 
					
						
							|  |  |  | 		out = ofss.as_pathname() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ofp = open(out, 'wb') | 
					
						
							|  |  |  | 	# XXXX Do translation on non-mac systems | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	while 1: | 
					
						
							|  |  |  | 		d = ifp.read(128000) | 
					
						
							|  |  |  | 		if not d: break | 
					
						
							|  |  |  | 		ofp.write(d) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	ofp.close() | 
					
						
							|  |  |  | 	ifp.close_data() | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 	d = ifp.read_rsrc(128000) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	if d: | 
					
						
							|  |  |  | 		ofp = openrsrc(out, 'wb') | 
					
						
							|  |  |  | 		ofp.write(d) | 
					
						
							| 
									
										
										
										
											1996-03-23 19:19:04 +00:00
										 |  |  | 		while 1: | 
					
						
							|  |  |  | 			d = ifp.read_rsrc(128000) | 
					
						
							|  |  |  | 			if not d: break | 
					
						
							|  |  |  | 			ofp.write(d) | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		ofp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if os.name == 'mac': | 
					
						
							|  |  |  | 		nfinfo = ofss.GetFInfo() | 
					
						
							|  |  |  | 		nfinfo.Creator = finfo.Creator | 
					
						
							|  |  |  | 		nfinfo.Type = finfo.Type | 
					
						
							|  |  |  | 		nfinfo.Flags = finfo.Flags | 
					
						
							|  |  |  | 		ofss.SetFInfo(nfinfo) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	ifp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _test(): | 
					
						
							|  |  |  | 	if os.name == 'mac': | 
					
						
							| 
									
										
										
										
											1995-08-14 12:41:20 +00:00
										 |  |  | 		fss, ok = macfs.PromptGetFile('File to convert:') | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 		if not ok: | 
					
						
							|  |  |  | 			sys.exit(0) | 
					
						
							|  |  |  | 		fname = fss.as_pathname() | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		fname = sys.argv[1] | 
					
						
							| 
									
										
										
										
											1997-01-16 16:51:57 +00:00
										 |  |  | 	binhex(fname, fname+'.hqx') | 
					
						
							|  |  |  | 	hexbin(fname+'.hqx', fname+'.viahqx') | 
					
						
							|  |  |  | 	#hexbin(fname, fname+'.unpacked') | 
					
						
							| 
									
										
										
										
											1995-08-07 14:36:51 +00:00
										 |  |  | 	sys.exit(1) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  | 	_test() |