mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	This patch makes inheritance for OSA classes work. The implementation is a bit convoluted, but I don't immedeately see a simpler way of doing it. I added calls to ascii() everywhere we output strings that may contain non-ascii characters (Python has gotten very picky since the encoding patch:-). I also removed Donovan's different way of opening resource files: I don't seem to need it.
		
			
				
	
	
		
			385 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			385 lines
		
	
	
	
		
			11 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 *
 | 
						|
from Carbon import AE
 | 
						|
from Carbon.AppleEvents import *
 | 
						|
import MacOS
 | 
						|
import macfs
 | 
						|
import StringIO
 | 
						|
import aetypes
 | 
						|
from aetypes import mkenum, mktype
 | 
						|
import os
 | 
						|
 | 
						|
# 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 = AE.AEDescType
 | 
						|
FSSType = macfs.FSSpecType
 | 
						|
AliasType = macfs.AliasType
 | 
						|
 | 
						|
def packkey(ae, key, value):
 | 
						|
	if hasattr(key, 'which'):
 | 
						|
		keystr = key.which
 | 
						|
	elif hasattr(key, 'want'):
 | 
						|
		keystr = key.want
 | 
						|
	else:
 | 
						|
		keystr = key
 | 
						|
	ae.AEPutParamDesc(keystr, pack(value))
 | 
						|
 | 
						|
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 == UnicodeType:
 | 
						|
		data = t.encode('utf16')
 | 
						|
		if data[:2] == '\xfe\xff':
 | 
						|
			data = data[2:]
 | 
						|
		return AE.AECreateDesc('utxt', data)
 | 
						|
	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():
 | 
						|
			packkey(record, key, value)
 | 
						|
			#record.AEPutParamDesc(key, pack(value))
 | 
						|
		return record
 | 
						|
	if t == InstanceType and hasattr(x, '__aepack__'):
 | 
						|
		return x.__aepack__()
 | 
						|
	if hasattr(x, 'which'):
 | 
						|
		return AE.AECreateDesc('TEXT', x.which)
 | 
						|
	if hasattr(x, 'want'):
 | 
						|
		return AE.AECreateDesc('TEXT', x.want)
 | 
						|
	return AE.AECreateDesc('TEXT', repr(x)) # Copout
 | 
						|
 | 
						|
def unpack(desc, formodulename=""):
 | 
						|
	"""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, formodulename))
 | 
						|
		return l
 | 
						|
	if t == typeAERecord:
 | 
						|
		d = {}
 | 
						|
		for i in range(desc.AECountItems()):
 | 
						|
			keyword, item = desc.AEGetNthDesc(i+1, '****')
 | 
						|
			d[keyword] = unpack(item, formodulename)
 | 
						|
		return d
 | 
						|
	if t == typeAEText:
 | 
						|
		record = desc.AECoerceDesc('reco')
 | 
						|
		return mkaetext(unpack(record, formodulename))
 | 
						|
	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
 | 
						|
	if t == typeUnicodeText:
 | 
						|
		return unicode(desc.data, 'utf16')
 | 
						|
	# 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, formodulename))
 | 
						|
	# 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')
 | 
						|
		# If we have been told the name of the module we are unpacking aedescs for,
 | 
						|
		# we can attempt to create the right type of python object from that module.
 | 
						|
		if formodulename:
 | 
						|
			return mkobjectfrommodule(unpack(record, formodulename), formodulename)
 | 
						|
		return mkobject(unpack(record, formodulename))
 | 
						|
	# 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, formodulename))
 | 
						|
	if t == 'cmpd':
 | 
						|
		record = desc.AECoerceDesc('reco')
 | 
						|
		return mkcomparison(unpack(record, formodulename))
 | 
						|
	if t == 'logi':
 | 
						|
		record = desc.AECoerceDesc('reco')
 | 
						|
		return mklogical(unpack(record, formodulename))
 | 
						|
	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)
 | 
						|
 | 
						|
# Note by Jack: I'm not 100% sure of the following code. This was
 | 
						|
# provided by Donovan Preston, but I wonder whether the assignment
 | 
						|
# to __class__ is safe. Moreover, shouldn't there be a better
 | 
						|
# initializer for the classes in the suites?
 | 
						|
def mkobjectfrommodule(dict, modulename):
 | 
						|
	want = dict['want'].type
 | 
						|
	module = __import__(modulename)
 | 
						|
	codenamemapper = module._classdeclarations
 | 
						|
	classtype = codenamemapper.get(want, None)
 | 
						|
	newobj = mkobject(dict)
 | 
						|
	if classtype:
 | 
						|
		newobj.__class__ = classtype
 | 
						|
	return newobj
 | 
						|
 | 
						|
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()
 | 
						|
	
 |