mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			347 lines
		
	
	
	
		
			9.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
	
		
			9.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Tools for use in AppleEvent clients and servers:
 | |
| conversion between AE types and python types
 | |
| 
 | |
| pack(x) converts a Python object to an AEDesc object
 | |
| unpack(desc) does the reverse
 | |
| coerce(x, wanted_sample) coerces a python object to another python object
 | |
| """
 | |
| 
 | |
| #
 | |
| # This code was originally written by Guido, and modified/extended by Jack
 | |
| # to include the various types that were missing. The reference used is
 | |
| # Apple Event Registry, chapter 9.
 | |
| #
 | |
| 
 | |
| import struct
 | |
| import string
 | |
| import types
 | |
| from string import strip
 | |
| from types import *
 | |
| import AE
 | |
| from AppleEvents import *
 | |
| import MacOS
 | |
| import macfs
 | |
| import StringIO
 | |
| import aetypes
 | |
| from aetypes import mkenum, mktype
 | |
| 
 | |
| # These ones seem to be missing from AppleEvents
 | |
| # (they're in AERegistry.h)
 | |
| 
 | |
| #typeColorTable = 'clrt'
 | |
| #typeDrawingArea = 'cdrw'
 | |
| #typePixelMap = 'cpix'
 | |
| #typePixelMapMinus = 'tpmm'
 | |
| #typeRotation = 'trot'
 | |
| #typeTextStyles = 'tsty'
 | |
| #typeStyledText = 'STXT'
 | |
| #typeAEText = 'tTXT'
 | |
| #typeEnumeration = 'enum'
 | |
| 
 | |
| #
 | |
| # Some AE types are immedeately coerced into something
 | |
| # we like better (and which is equivalent)
 | |
| #
 | |
| unpacker_coercions = {
 | |
| 	typeComp : typeFloat,
 | |
| 	typeColorTable : typeAEList,
 | |
| 	typeDrawingArea : typeAERecord,
 | |
| 	typeFixed : typeFloat,
 | |
| 	typeExtended : typeFloat,
 | |
| 	typePixelMap : typeAERecord,
 | |
| 	typeRotation : typeAERecord,
 | |
| 	typeStyledText : typeAERecord,
 | |
| 	typeTextStyles : typeAERecord,
 | |
| };
 | |
| 
 | |
| #
 | |
| # Some python types we need in the packer:
 | |
| #
 | |
| AEDescType = type(AE.AECreateDesc('TEXT', ''))
 | |
| _sample_fss = macfs.FSSpec(':')
 | |
| _sample_alias = _sample_fss.NewAliasMinimal()
 | |
| FSSType = type(_sample_fss)
 | |
| AliasType = type(_sample_alias)
 | |
| 
 | |
| def pack(x, forcetype = None):
 | |
| 	"""Pack a python object into an AE descriptor"""
 | |
| 	
 | |
| 	if forcetype:
 | |
| 		if type(x) is StringType:
 | |
| 			return AE.AECreateDesc(forcetype, x)
 | |
| 		else:
 | |
| 			return pack(x).AECoerceDesc(forcetype)
 | |
| 			
 | |
| 	if x == None:
 | |
| 		return AE.AECreateDesc('null', '')
 | |
| 		
 | |
| 	t = type(x)
 | |
| 	if t == AEDescType:
 | |
| 		return x
 | |
| 	if t == FSSType:
 | |
| 		return AE.AECreateDesc('fss ', x.data)
 | |
| 	if t == AliasType:
 | |
| 		return AE.AECreateDesc('alis', x.data)
 | |
| 	if t == IntType:
 | |
| 		return AE.AECreateDesc('long', struct.pack('l', x))
 | |
| 	if t == FloatType:
 | |
| 		return AE.AECreateDesc('doub', struct.pack('d', x))
 | |
| 	if t == StringType:
 | |
| 		return AE.AECreateDesc('TEXT', x)
 | |
| 	if t == ListType:
 | |
| 		list = AE.AECreateList('', 0)
 | |
| 		for item in x:
 | |
| 			list.AEPutDesc(0, pack(item))
 | |
| 		return list
 | |
| 	if t == DictionaryType:
 | |
| 		record = AE.AECreateList('', 1)
 | |
| 		for key, value in x.items():
 | |
| 			record.AEPutParamDesc(key, pack(value))
 | |
| 		return record
 | |
| 	if t == InstanceType and hasattr(x, '__aepack__'):
 | |
| 		return x.__aepack__()
 | |
| 	return AE.AECreateDesc('TEXT', repr(x)) # Copout
 | |
| 
 | |
| def unpack(desc):
 | |
| 	"""Unpack an AE descriptor to a python object"""
 | |
| 	t = desc.type
 | |
| 	
 | |
| 	if unpacker_coercions.has_key(t):
 | |
| 		desc = desc.AECoerceDesc(unpacker_coercions[t])
 | |
| 		t = desc.type # This is a guess by Jack....
 | |
| 	
 | |
| 	if t == typeAEList:
 | |
| 		l = []
 | |
| 		for i in range(desc.AECountItems()):
 | |
| 			keyword, item = desc.AEGetNthDesc(i+1, '****')
 | |
| 			l.append(unpack(item))
 | |
| 		return l
 | |
| 	if t == typeAERecord:
 | |
| 		d = {}
 | |
| 		for i in range(desc.AECountItems()):
 | |
| 			keyword, item = desc.AEGetNthDesc(i+1, '****')
 | |
| 			d[keyword] = unpack(item)
 | |
| 		return d
 | |
| 	if t == typeAEText:
 | |
| 		record = desc.AECoerceDesc('reco')
 | |
| 		return mkaetext(unpack(record))
 | |
| 	if t == typeAlias:
 | |
| 		return macfs.RawAlias(desc.data)
 | |
| 	# typeAppleEvent returned as unknown
 | |
| 	if t == typeBoolean:
 | |
| 		return struct.unpack('b', desc.data)[0]
 | |
| 	if t == typeChar:
 | |
| 		return desc.data
 | |
| 	# typeColorTable coerced to typeAEList
 | |
| 	# typeComp coerced to extended
 | |
| 	# typeData returned as unknown
 | |
| 	# typeDrawingArea coerced to typeAERecord
 | |
| 	if t == typeEnumeration:
 | |
| 		return mkenum(desc.data)
 | |
| 	# typeEPS returned as unknown
 | |
| 	if t == typeFalse:
 | |
| 		return 0
 | |
| 	if t == typeFloat:
 | |
| 		data = desc.data
 | |
| 		return struct.unpack('d', data)[0]
 | |
| 	if t == typeFSS:
 | |
| 		return macfs.RawFSSpec(desc.data)
 | |
| 	if t == typeInsertionLoc:
 | |
| 		record = desc.AECoerceDesc('reco')
 | |
| 		return mkinsertionloc(unpack(record))
 | |
| 	# typeInteger equal to typeLongInteger
 | |
| 	if t == typeIntlText:
 | |
| 		script, language = struct.unpack('hh', desc.data[:4])
 | |
| 		return aetypes.IntlText(script, language, desc.data[4:])
 | |
| 	if t == typeIntlWritingCode:
 | |
| 		script, language = struct.unpack('hh', desc.data)
 | |
| 		return aetypes.IntlWritingCode(script, language)
 | |
| 	if t == typeKeyword:
 | |
| 		return mkkeyword(desc.data)
 | |
| 	if t == typeLongInteger:
 | |
| 		return struct.unpack('l', desc.data)[0]
 | |
| 	if t == typeLongDateTime:
 | |
| 		a, b = struct.unpack('lL', desc.data)
 | |
| 		return (long(a) << 32) + b
 | |
| 	if t == typeNull:
 | |
| 		return None
 | |
| 	if t == typeMagnitude:
 | |
| 		v = struct.unpack('l', desc.data)
 | |
| 		if v < 0:
 | |
| 			v = 0x100000000L + v
 | |
| 		return v
 | |
| 	if t == typeObjectSpecifier:
 | |
| 		record = desc.AECoerceDesc('reco')
 | |
| 		return mkobject(unpack(record))
 | |
| 	# typePict returned as unknown
 | |
| 	# typePixelMap coerced to typeAERecord
 | |
| 	# typePixelMapMinus returned as unknown
 | |
| 	# typeProcessSerialNumber returned as unknown
 | |
| 	if t == typeQDPoint:
 | |
| 		v, h = struct.unpack('hh', desc.data)
 | |
| 		return aetypes.QDPoint(v, h)
 | |
| 	if t == typeQDRectangle:
 | |
| 		v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
 | |
| 		return aetypes.QDRectangle(v0, h0, v1, h1)
 | |
| 	if t == typeRGBColor:
 | |
| 		r, g, b = struct.unpack('hhh', desc.data)
 | |
| 		return aetypes.RGBColor(r, g, b)
 | |
| 	# typeRotation coerced to typeAERecord
 | |
| 	# typeScrapStyles returned as unknown
 | |
| 	# typeSessionID returned as unknown
 | |
| 	if t == typeShortFloat:
 | |
| 		return struct.unpack('f', desc.data)[0]
 | |
| 	if t == typeShortInteger:
 | |
| 		return struct.unpack('h', desc.data)[0]
 | |
| 	# typeSMFloat identical to typeShortFloat
 | |
| 	# typeSMInt	indetical to typeShortInt
 | |
| 	# typeStyledText coerced to typeAERecord
 | |
| 	if t == typeTargetID:
 | |
| 		return mktargetid(desc.data)
 | |
| 	# typeTextStyles coerced to typeAERecord
 | |
| 	# typeTIFF returned as unknown
 | |
| 	if t == typeTrue:
 | |
| 		return 1
 | |
| 	if t == typeType:
 | |
| 		return mktype(desc.data)
 | |
| 	#
 | |
| 	# The following are special
 | |
| 	#
 | |
| 	if t == 'rang':
 | |
| 		record = desc.AECoerceDesc('reco')
 | |
| 		return mkrange(unpack(record))
 | |
| 	if t == 'cmpd':
 | |
| 		record = desc.AECoerceDesc('reco')
 | |
| 		return mkcomparison(unpack(record))
 | |
| 	if t == 'logi':
 | |
| 		record = desc.AECoerceDesc('reco')
 | |
| 		return mklogical(unpack(record))
 | |
| 	return mkunknown(desc.type, desc.data)
 | |
| 	
 | |
| def coerce(data, egdata):
 | |
| 	"""Coerce a python object to another type using the AE coercers"""
 | |
| 	pdata = pack(data)
 | |
| 	pegdata = pack(egdata)
 | |
| 	pdata = pdata.AECoerceDesc(pegdata.type)
 | |
| 	return unpack(pdata)
 | |
| 
 | |
| #
 | |
| # Helper routines for unpack
 | |
| #
 | |
| def mktargetid(data):
 | |
| 	sessionID = getlong(data[:4])
 | |
| 	name = mkppcportrec(data[4:4+72])
 | |
| 	location = mklocationnamerec(data[76:76+36])
 | |
| 	rcvrName = mkppcportrec(data[112:112+72])
 | |
| 	return sessionID, name, location, rcvrName
 | |
| 
 | |
| def mkppcportrec(rec):
 | |
| 	namescript = getword(rec[:2])
 | |
| 	name = getpstr(rec[2:2+33])
 | |
| 	portkind = getword(rec[36:38])
 | |
| 	if portkind == 1:
 | |
| 		ctor = rec[38:42]
 | |
| 		type = rec[42:46]
 | |
| 		identity = (ctor, type)
 | |
| 	else:
 | |
| 		identity = getpstr(rec[38:38+33])
 | |
| 	return namescript, name, portkind, identity
 | |
| 
 | |
| def mklocationnamerec(rec):
 | |
| 	kind = getword(rec[:2])
 | |
| 	stuff = rec[2:]
 | |
| 	if kind == 0: stuff = None
 | |
| 	if kind == 2: stuff = getpstr(stuff)
 | |
| 	return kind, stuff
 | |
| 
 | |
| def mkunknown(type, data):
 | |
| 	return aetypes.Unknown(type, data)
 | |
| 
 | |
| def getpstr(s):
 | |
| 	return s[1:1+ord(s[0])]
 | |
| 
 | |
| def getlong(s):
 | |
| 	return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
 | |
| 
 | |
| def getword(s):
 | |
| 	return (ord(s[0])<<8) | (ord(s[1])<<0)
 | |
| 
 | |
| def mkkeyword(keyword):
 | |
| 	return aetypes.Keyword(keyword)
 | |
| 
 | |
| def mkrange(dict):
 | |
| 	return aetypes.Range(dict['star'], dict['stop'])
 | |
| 
 | |
| def mkcomparison(dict):
 | |
| 	return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])
 | |
| 
 | |
| def mklogical(dict):
 | |
| 	return aetypes.Logical(dict['logc'], dict['term'])
 | |
| 
 | |
| def mkstyledtext(dict):
 | |
| 	return aetypes.StyledText(dict['ksty'], dict['ktxt'])
 | |
| 	
 | |
| def mkaetext(dict):
 | |
| 	return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
 | |
| 	
 | |
| def mkinsertionloc(dict):
 | |
| 	return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])
 | |
| 
 | |
| def mkobject(dict):
 | |
| 	want = dict['want'].type
 | |
| 	form = dict['form'].enum
 | |
| 	seld = dict['seld']
 | |
| 	fr   = dict['from']
 | |
| 	if form in ('name', 'indx', 'rang', 'test'):
 | |
| 		if want == 'text': return aetypes.Text(seld, fr)
 | |
| 		if want == 'cha ': return aetypes.Character(seld, fr)
 | |
| 		if want == 'cwor': return aetypes.Word(seld, fr)
 | |
| 		if want == 'clin': return aetypes.Line(seld, fr)
 | |
| 		if want == 'cpar': return aetypes.Paragraph(seld, fr)
 | |
| 		if want == 'cwin': return aetypes.Window(seld, fr)
 | |
| 		if want == 'docu': return aetypes.Document(seld, fr)
 | |
| 		if want == 'file': return aetypes.File(seld, fr)
 | |
| 		if want == 'cins': return aetypes.InsertionPoint(seld, fr)
 | |
| 	if want == 'prop' and form == 'prop' and aetypes.IsType(seld):
 | |
| 		return aetypes.Property(seld.type, fr)
 | |
| 	return aetypes.ObjectSpecifier(want, form, seld, fr)
 | |
| 
 | |
| def _test():
 | |
| 	"""Test program. Pack and unpack various things"""
 | |
| 	objs = [
 | |
| 		'a string',
 | |
| 		12,
 | |
| 		12.0,
 | |
| 		None,
 | |
| 		['a', 'list', 'of', 'strings'],
 | |
| 		{'key1': 'value1', 'key2':'value2'},
 | |
| 		macfs.FSSpec(':'),
 | |
| 		macfs.FSSpec(':').NewAliasMinimal(),
 | |
| 		aetypes.Enum('enum'),
 | |
| 		aetypes.Type('type'),
 | |
| 		aetypes.Keyword('kwrd'),
 | |
| 		aetypes.Range(1, 10),
 | |
| 		aetypes.Comparison(1, '<   ', 10),
 | |
| 		aetypes.Logical('not ', 1),
 | |
| 		# Cannot do StyledText
 | |
| 		# Cannot do AEText
 | |
| 		aetypes.IntlText(0, 0, 'international text'),
 | |
| 		aetypes.IntlWritingCode(0,0),
 | |
| 		aetypes.QDPoint(50,100),
 | |
| 		aetypes.QDRectangle(50,100,150,200),
 | |
| 		aetypes.RGBColor(0x7000, 0x6000, 0x5000),
 | |
| 		aetypes.Unknown('xxxx', 'unknown type data'),
 | |
| 		aetypes.Character(1),
 | |
| 		aetypes.Character(2, aetypes.Line(2)),
 | |
| 	]
 | |
| 	for o in objs:
 | |
| 		print 'BEFORE', o, `o`
 | |
| 		packed = pack(o)
 | |
| 		unpacked = unpack(packed)
 | |
| 		print 'AFTER ', unpacked, `unpacked`
 | |
| 	import sys
 | |
| 	sys.exit(1)
 | |
| 	
 | |
| if __name__ == '__main__':
 | |
| 	_test()
 | |
| 	
 | 
