mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			369 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			369 lines
		
	
	
	
		
			12 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.
 | |
| #
 | |
| 
 | |
| from warnings import warnpy3k
 | |
| warnpy3k("In 3.x, the aepack module is removed.", stacklevel=2)
 | |
| 
 | |
| import struct
 | |
| import types
 | |
| from types import *
 | |
| from Carbon import AE
 | |
| from Carbon.AppleEvents import *
 | |
| import MacOS
 | |
| import Carbon.File
 | |
| import aetypes
 | |
| from aetypes import mkenum, ObjectSpecifier
 | |
| 
 | |
| # 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
 | |
| try:
 | |
|     FSSType = Carbon.File.FSSpecType
 | |
| except AttributeError:
 | |
|     class FSSType:
 | |
|         pass
 | |
| FSRefType = Carbon.File.FSRefType
 | |
| AliasType = Carbon.File.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 is None:
 | |
|         return AE.AECreateDesc('null', '')
 | |
| 
 | |
|     if isinstance(x, AEDescType):
 | |
|         return x
 | |
|     if isinstance(x, FSSType):
 | |
|         return AE.AECreateDesc('fss ', x.data)
 | |
|     if isinstance(x, FSRefType):
 | |
|         return AE.AECreateDesc('fsrf', x.data)
 | |
|     if isinstance(x, AliasType):
 | |
|         return AE.AECreateDesc('alis', x.data)
 | |
|     if isinstance(x, IntType):
 | |
|         return AE.AECreateDesc('long', struct.pack('l', x))
 | |
|     if isinstance(x, FloatType):
 | |
|         return AE.AECreateDesc('doub', struct.pack('d', x))
 | |
|     if isinstance(x, StringType):
 | |
|         return AE.AECreateDesc('TEXT', x)
 | |
|     if isinstance(x, UnicodeType):
 | |
|         data = x.encode('utf16')
 | |
|         if data[:2] == '\xfe\xff':
 | |
|             data = data[2:]
 | |
|         return AE.AECreateDesc('utxt', data)
 | |
|     if isinstance(x, ListType):
 | |
|         list = AE.AECreateList('', 0)
 | |
|         for item in x:
 | |
|             list.AEPutDesc(0, pack(item))
 | |
|         return list
 | |
|     if isinstance(x, DictionaryType):
 | |
|         record = AE.AECreateList('', 1)
 | |
|         for key, value in x.items():
 | |
|             packkey(record, key, value)
 | |
|             #record.AEPutParamDesc(key, pack(value))
 | |
|         return record
 | |
|     if type(x) == types.ClassType and issubclass(x, ObjectSpecifier):
 | |
|         # Note: we are getting a class object here, not an instance
 | |
|         return AE.AECreateDesc('type', x.want)
 | |
|     if 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 t in unpacker_coercions:
 | |
|         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 Carbon.File.Alias(rawdata=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 Carbon.File.FSSpec(rawdata=desc.data)
 | |
|     if t == typeFSRef:
 | |
|         return Carbon.File.FSRef(rawdata=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, formodulename)
 | |
|     #
 | |
|     # 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):
 | |
|     if type(dict['want']) == types.ClassType and issubclass(dict['want'], ObjectSpecifier):
 | |
|         # The type has already been converted to Python. Convert back:-(
 | |
|         classtype = dict['want']
 | |
|         dict['want'] = aetypes.mktype(classtype.want)
 | |
|     want = dict['want'].type
 | |
|     module = __import__(modulename)
 | |
|     codenamemapper = module._classdeclarations
 | |
|     classtype = codenamemapper.get(want, None)
 | |
|     newobj = mkobject(dict)
 | |
|     if classtype:
 | |
|         assert issubclass(classtype, ObjectSpecifier)
 | |
|         newobj.__class__ = classtype
 | |
|     return newobj
 | |
| 
 | |
| def mktype(typecode, modulename=None):
 | |
|     if modulename:
 | |
|         module = __import__(modulename)
 | |
|         codenamemapper = module._classdeclarations
 | |
|         classtype = codenamemapper.get(typecode, None)
 | |
|         if classtype:
 | |
|             return classtype
 | |
|     return aetypes.mktype(typecode)
 | 
