1d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen"""Tools for use in AppleEvent clients and servers:
2d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenconversion between AE types and python types
3d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
4d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenpack(x) converts a Python object to an AEDesc object
5d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenunpack(desc) does the reverse
6d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansencoerce(x, wanted_sample) coerces a python object to another python object
7d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen"""
8d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
9d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
10d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# This code was originally written by Guido, and modified/extended by Jack
11d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# to include the various types that were missing. The reference used is
12d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# Apple Event Registry, chapter 9.
13d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
14d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
15236819310db3fe6f2fb22d48b780fa6ec253b6c7Benjamin Petersonfrom warnings import warnpy3k
16a6864e0d9f1fc06c50db36ed913ac48a3d2ddde5Benjamin Petersonwarnpy3k("In 3.x, the aepack module is removed.", stacklevel=2)
17236819310db3fe6f2fb22d48b780fa6ec253b6c7Benjamin Peterson
18d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenimport struct
19d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenimport types
20d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenfrom types import *
215a6fdcd3718927109592c6df692fe24a8fdaee31Jack Jansenfrom Carbon import AE
225a6fdcd3718927109592c6df692fe24a8fdaee31Jack Jansenfrom Carbon.AppleEvents import *
23d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenimport MacOS
242b88dec606511edb90d3a1efdaec03d19d75ff02Jack Jansenimport Carbon.File
25d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenimport aetypes
26fc71026c8ad67e26cfef26e61b10471647a9f261Jack Jansenfrom aetypes import mkenum, ObjectSpecifier
27d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
28d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# These ones seem to be missing from AppleEvents
29d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# (they're in AERegistry.h)
30d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
31d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typeColorTable = 'clrt'
32d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typeDrawingArea = 'cdrw'
33d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typePixelMap = 'cpix'
34d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typePixelMapMinus = 'tpmm'
35d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typeRotation = 'trot'
36d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typeTextStyles = 'tsty'
37d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typeStyledText = 'STXT'
38d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typeAEText = 'tTXT'
39d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#typeEnumeration = 'enum'
40d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
41d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
42d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# Some AE types are immedeately coerced into something
43d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# we like better (and which is equivalent)
44d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
45d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansenunpacker_coercions = {
460ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeComp : typeFloat,
470ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeColorTable : typeAEList,
480ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeDrawingArea : typeAERecord,
490ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeFixed : typeFloat,
500ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeExtended : typeFloat,
510ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typePixelMap : typeAERecord,
520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeRotation : typeAERecord,
530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeStyledText : typeAERecord,
540ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    typeTextStyles : typeAERecord,
55d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen};
56d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
57d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
58d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# Some python types we need in the packer:
59d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
60ad5dcafac42018ea2b4eaebb666943625a66e67cJack JansenAEDescType = AE.AEDescType
612596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussorentry:
622596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren    FSSType = Carbon.File.FSSpecType
632596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussorenexcept AttributeError:
642596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren    class FSSType:
652596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren        pass
662b88dec606511edb90d3a1efdaec03d19d75ff02Jack JansenFSRefType = Carbon.File.FSRefType
672b88dec606511edb90d3a1efdaec03d19d75ff02Jack JansenAliasType = Carbon.File.AliasType
68d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
698b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansendef packkey(ae, key, value):
700ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if hasattr(key, 'which'):
710ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        keystr = key.which
720ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    elif hasattr(key, 'want'):
730ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        keystr = key.want
740ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    else:
750ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        keystr = key
760ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    ae.AEPutParamDesc(keystr, pack(value))
778b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansen
78d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef pack(x, forcetype = None):
790ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    """Pack a python object into an AE descriptor"""
80182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
810ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if forcetype:
820ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if type(x) is StringType:
830ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            return AE.AECreateDesc(forcetype, x)
840ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        else:
850ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            return pack(x).AECoerceDesc(forcetype)
86182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
875b63acd31e0e40c1a9a9e9762905b0054ff37994Benjamin Peterson    if x is None:
880ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('null', '')
89182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
900ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, AEDescType):
910ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return x
920ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, FSSType):
930ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('fss ', x.data)
940ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, FSRefType):
950ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('fsrf', x.data)
960ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, AliasType):
970ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('alis', x.data)
980ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, IntType):
990ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('long', struct.pack('l', x))
1000ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, FloatType):
1010ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('doub', struct.pack('d', x))
1020ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, StringType):
1030ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('TEXT', x)
1040ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, UnicodeType):
1050ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        data = x.encode('utf16')
1060ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if data[:2] == '\xfe\xff':
1070ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            data = data[2:]
1080ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('utxt', data)
1090ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, ListType):
1100ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        list = AE.AECreateList('', 0)
1110ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        for item in x:
1120ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            list.AEPutDesc(0, pack(item))
1130ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return list
1140ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if isinstance(x, DictionaryType):
1150ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        record = AE.AECreateList('', 1)
1160ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        for key, value in x.items():
1170ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            packkey(record, key, value)
1180ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            #record.AEPutParamDesc(key, pack(value))
1190ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return record
1200ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if type(x) == types.ClassType and issubclass(x, ObjectSpecifier):
1210ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        # Note: we are getting a class object here, not an instance
1220ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('type', x.want)
1230ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if hasattr(x, '__aepack__'):
1240ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return x.__aepack__()
1250ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if hasattr(x, 'which'):
1260ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('TEXT', x.which)
1270ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if hasattr(x, 'want'):
1280ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return AE.AECreateDesc('TEXT', x.want)
1290ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return AE.AECreateDesc('TEXT', repr(x)) # Copout
130d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
1318b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansendef unpack(desc, formodulename=""):
1320ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    """Unpack an AE descriptor to a python object"""
1330ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    t = desc.type
134182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
135a3a505076efc19ec23669370778c5fa22d030ffaMark Dickinson    if t in unpacker_coercions:
1360ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        desc = desc.AECoerceDesc(unpacker_coercions[t])
1370ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        t = desc.type # This is a guess by Jack....
138182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
1390ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeAEList:
1400ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        l = []
1410ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        for i in range(desc.AECountItems()):
1420ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            keyword, item = desc.AEGetNthDesc(i+1, '****')
1430ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            l.append(unpack(item, formodulename))
1440ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return l
1450ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeAERecord:
1460ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        d = {}
1470ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        for i in range(desc.AECountItems()):
1480ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            keyword, item = desc.AEGetNthDesc(i+1, '****')
1490ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            d[keyword] = unpack(item, formodulename)
1500ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return d
1510ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeAEText:
1520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        record = desc.AECoerceDesc('reco')
1530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mkaetext(unpack(record, formodulename))
1540ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeAlias:
1550ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return Carbon.File.Alias(rawdata=desc.data)
1560ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeAppleEvent returned as unknown
1570ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeBoolean:
1580ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return struct.unpack('b', desc.data)[0]
1590ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeChar:
1600ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return desc.data
1610ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeUnicodeText:
1620ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return unicode(desc.data, 'utf16')
1630ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeColorTable coerced to typeAEList
1640ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeComp coerced to extended
1650ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeData returned as unknown
1660ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeDrawingArea coerced to typeAERecord
1670ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeEnumeration:
1680ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mkenum(desc.data)
1690ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeEPS returned as unknown
1700ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeFalse:
1710ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return 0
1720ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeFloat:
1730ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        data = desc.data
1740ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return struct.unpack('d', data)[0]
1750ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeFSS:
1760ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return Carbon.File.FSSpec(rawdata=desc.data)
1770ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeFSRef:
1780ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return Carbon.File.FSRef(rawdata=desc.data)
1790ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeInsertionLoc:
1800ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        record = desc.AECoerceDesc('reco')
1810ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mkinsertionloc(unpack(record, formodulename))
1820ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeInteger equal to typeLongInteger
1830ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeIntlText:
1840ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        script, language = struct.unpack('hh', desc.data[:4])
1850ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return aetypes.IntlText(script, language, desc.data[4:])
1860ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeIntlWritingCode:
1870ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        script, language = struct.unpack('hh', desc.data)
1880ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return aetypes.IntlWritingCode(script, language)
1890ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeKeyword:
1900ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mkkeyword(desc.data)
1910ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeLongInteger:
1920ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return struct.unpack('l', desc.data)[0]
1930ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeLongDateTime:
1940ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        a, b = struct.unpack('lL', desc.data)
1950ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return (long(a) << 32) + b
1960ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeNull:
1970ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return None
1980ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeMagnitude:
1990ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        v = struct.unpack('l', desc.data)
2000ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if v < 0:
2010ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            v = 0x100000000L + v
2020ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return v
2030ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeObjectSpecifier:
2040ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        record = desc.AECoerceDesc('reco')
2050ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        # If we have been told the name of the module we are unpacking aedescs for,
2060ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        # we can attempt to create the right type of python object from that module.
2070ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if formodulename:
2080ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            return mkobjectfrommodule(unpack(record, formodulename), formodulename)
2090ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mkobject(unpack(record, formodulename))
2100ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typePict returned as unknown
2110ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typePixelMap coerced to typeAERecord
2120ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typePixelMapMinus returned as unknown
2130ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeProcessSerialNumber returned as unknown
2140ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeQDPoint:
2150ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        v, h = struct.unpack('hh', desc.data)
2160ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return aetypes.QDPoint(v, h)
2170ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeQDRectangle:
2180ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
2190ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return aetypes.QDRectangle(v0, h0, v1, h1)
2200ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeRGBColor:
2210ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        r, g, b = struct.unpack('hhh', desc.data)
2220ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return aetypes.RGBColor(r, g, b)
2230ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeRotation coerced to typeAERecord
2240ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeScrapStyles returned as unknown
2250ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeSessionID returned as unknown
2260ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeShortFloat:
2270ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return struct.unpack('f', desc.data)[0]
2280ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeShortInteger:
2290ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return struct.unpack('h', desc.data)[0]
2300ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeSMFloat identical to typeShortFloat
2310ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeSMInt indetical to typeShortInt
2320ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeStyledText coerced to typeAERecord
2330ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeTargetID:
2340ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mktargetid(desc.data)
2350ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeTextStyles coerced to typeAERecord
2360ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # typeTIFF returned as unknown
2370ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeTrue:
2380ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return 1
2390ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == typeType:
2400ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mktype(desc.data, formodulename)
2410ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    #
2420ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    # The following are special
2430ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    #
2440ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == 'rang':
2450ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        record = desc.AECoerceDesc('reco')
2460ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mkrange(unpack(record, formodulename))
2470ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == 'cmpd':
2480ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        record = desc.AECoerceDesc('reco')
2490ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mkcomparison(unpack(record, formodulename))
2500ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if t == 'logi':
2510ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        record = desc.AECoerceDesc('reco')
2520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return mklogical(unpack(record, formodulename))
2530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return mkunknown(desc.type, desc.data)
254182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
255d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef coerce(data, egdata):
2560ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    """Coerce a python object to another type using the AE coercers"""
2570ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    pdata = pack(data)
2580ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    pegdata = pack(egdata)
2590ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    pdata = pdata.AECoerceDesc(pegdata.type)
2600ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return unpack(pdata)
261d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
262d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
263d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen# Helper routines for unpack
264d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen#
265d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mktargetid(data):
2660ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    sessionID = getlong(data[:4])
2670ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    name = mkppcportrec(data[4:4+72])
2680ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    location = mklocationnamerec(data[76:76+36])
2690ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    rcvrName = mkppcportrec(data[112:112+72])
2700ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return sessionID, name, location, rcvrName
271d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
272d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkppcportrec(rec):
2730ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    namescript = getword(rec[:2])
2740ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    name = getpstr(rec[2:2+33])
2750ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    portkind = getword(rec[36:38])
2760ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if portkind == 1:
2770ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        ctor = rec[38:42]
2780ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        type = rec[42:46]
2790ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        identity = (ctor, type)
2800ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    else:
2810ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        identity = getpstr(rec[38:38+33])
2820ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return namescript, name, portkind, identity
283d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
284d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mklocationnamerec(rec):
2850ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    kind = getword(rec[:2])
2860ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    stuff = rec[2:]
2870ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if kind == 0: stuff = None
2880ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if kind == 2: stuff = getpstr(stuff)
2890ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return kind, stuff
290d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
291d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkunknown(type, data):
2920ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.Unknown(type, data)
293d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
294d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef getpstr(s):
2950ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return s[1:1+ord(s[0])]
296d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
297d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef getlong(s):
2980ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
299d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
300d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef getword(s):
3010ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return (ord(s[0])<<8) | (ord(s[1])<<0)
302d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
303d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkkeyword(keyword):
3040ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.Keyword(keyword)
305d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
306d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkrange(dict):
3070ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.Range(dict['star'], dict['stop'])
308d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
309d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkcomparison(dict):
3100ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])
311d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
312d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mklogical(dict):
3130ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.Logical(dict['logc'], dict['term'])
314d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
315d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkstyledtext(dict):
3160ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.StyledText(dict['ksty'], dict['ktxt'])
317182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
318d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkaetext(dict):
3190ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
320182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
321d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkinsertionloc(dict):
3220ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])
323d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
324d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansendef mkobject(dict):
3250ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    want = dict['want'].type
3260ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    form = dict['form'].enum
3270ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    seld = dict['seld']
3280ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    fr   = dict['from']
3290ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if form in ('name', 'indx', 'rang', 'test'):
3300ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'text': return aetypes.Text(seld, fr)
3310ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'cha ': return aetypes.Character(seld, fr)
3320ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'cwor': return aetypes.Word(seld, fr)
3330ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'clin': return aetypes.Line(seld, fr)
3340ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'cpar': return aetypes.Paragraph(seld, fr)
3350ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'cwin': return aetypes.Window(seld, fr)
3360ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'docu': return aetypes.Document(seld, fr)
3370ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'file': return aetypes.File(seld, fr)
3380ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if want == 'cins': return aetypes.InsertionPoint(seld, fr)
3390ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if want == 'prop' and form == 'prop' and aetypes.IsType(seld):
3400ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        return aetypes.Property(seld.type, fr)
3410ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.ObjectSpecifier(want, form, seld, fr)
342d0fc42f43968dbe0fc6f762fad527a684d557396Jack Jansen
3438b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansen# Note by Jack: I'm not 100% sure of the following code. This was
3448b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansen# provided by Donovan Preston, but I wonder whether the assignment
3458b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansen# to __class__ is safe. Moreover, shouldn't there be a better
3468b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansen# initializer for the classes in the suites?
3478b77767094ba4bf3fb497ce974261366470d6aa3Jack Jansendef mkobjectfrommodule(dict, modulename):
3480ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if type(dict['want']) == types.ClassType and issubclass(dict['want'], ObjectSpecifier):
3490ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        # The type has already been converted to Python. Convert back:-(
3500ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        classtype = dict['want']
3510ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        dict['want'] = aetypes.mktype(classtype.want)
3520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    want = dict['want'].type
3530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    module = __import__(modulename)
3540ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    codenamemapper = module._classdeclarations
3550ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    classtype = codenamemapper.get(want, None)
3560ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    newobj = mkobject(dict)
3570ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if classtype:
3580ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        assert issubclass(classtype, ObjectSpecifier)
3590ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        newobj.__class__ = classtype
3600ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return newobj
361182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
362fc71026c8ad67e26cfef26e61b10471647a9f261Jack Jansendef mktype(typecode, modulename=None):
3630ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    if modulename:
3640ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        module = __import__(modulename)
3650ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        codenamemapper = module._classdeclarations
3660ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        classtype = codenamemapper.get(typecode, None)
3670ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen        if classtype:
3680ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen            return classtype
3690ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen    return aetypes.mktype(typecode)
370