1 """Tools for use in AppleEvent clients and servers:
2 conversion between AE types and python types
4 pack(x) converts a Python object to an AEDesc object
5 unpack(desc) does the reverse
6 coerce(x, wanted_sample) coerces a python object to another python object
10 # This code was originally written by Guido, and modified/extended by Jack
11 # to include the various types that were missing. The reference used is
12 # Apple Event Registry, chapter 9.
15 from warnings
import warnpy3k
16 warnpy3k("In 3.x, the aepack module is removed.", stacklevel
=2)
22 from Carbon
.AppleEvents
import *
26 from aetypes
import mkenum
, ObjectSpecifier
28 # These ones seem to be missing from AppleEvents
29 # (they're in AERegistry.h)
31 #typeColorTable = 'clrt'
32 #typeDrawingArea = 'cdrw'
33 #typePixelMap = 'cpix'
34 #typePixelMapMinus = 'tpmm'
35 #typeRotation = 'trot'
36 #typeTextStyles = 'tsty'
37 #typeStyledText = 'STXT'
39 #typeEnumeration = 'enum'
42 # Some AE types are immedeately coerced into something
43 # we like better (and which is equivalent)
45 unpacker_coercions
= {
47 typeColorTable
: typeAEList
,
48 typeDrawingArea
: typeAERecord
,
49 typeFixed
: typeFloat
,
50 typeExtended
: typeFloat
,
51 typePixelMap
: typeAERecord
,
52 typeRotation
: typeAERecord
,
53 typeStyledText
: typeAERecord
,
54 typeTextStyles
: typeAERecord
,
58 # Some python types we need in the packer:
60 AEDescType
= AE
.AEDescType
62 FSSType
= Carbon
.File
.FSSpecType
63 except AttributeError:
66 FSRefType
= Carbon
.File
.FSRefType
67 AliasType
= Carbon
.File
.AliasType
69 def packkey(ae
, key
, value
):
70 if hasattr(key
, 'which'):
72 elif hasattr(key
, 'want'):
76 ae
.AEPutParamDesc(keystr
, pack(value
))
78 def pack(x
, forcetype
= None):
79 """Pack a python object into an AE descriptor"""
82 if type(x
) is StringType
:
83 return AE
.AECreateDesc(forcetype
, x
)
85 return pack(x
).AECoerceDesc(forcetype
)
88 return AE
.AECreateDesc('null', '')
90 if isinstance(x
, AEDescType
):
92 if isinstance(x
, FSSType
):
93 return AE
.AECreateDesc('fss ', x
.data
)
94 if isinstance(x
, FSRefType
):
95 return AE
.AECreateDesc('fsrf', x
.data
)
96 if isinstance(x
, AliasType
):
97 return AE
.AECreateDesc('alis', x
.data
)
98 if isinstance(x
, IntType
):
99 return AE
.AECreateDesc('long', struct
.pack('l', x
))
100 if isinstance(x
, FloatType
):
101 return AE
.AECreateDesc('doub', struct
.pack('d', x
))
102 if isinstance(x
, StringType
):
103 return AE
.AECreateDesc('TEXT', x
)
104 if isinstance(x
, UnicodeType
):
105 data
= x
.encode('utf16')
106 if data
[:2] == '\xfe\xff':
108 return AE
.AECreateDesc('utxt', data
)
109 if isinstance(x
, ListType
):
110 list = AE
.AECreateList('', 0)
112 list.AEPutDesc(0, pack(item
))
114 if isinstance(x
, DictionaryType
):
115 record
= AE
.AECreateList('', 1)
116 for key
, value
in x
.items():
117 packkey(record
, key
, value
)
118 #record.AEPutParamDesc(key, pack(value))
120 if type(x
) == types
.ClassType
and issubclass(x
, ObjectSpecifier
):
121 # Note: we are getting a class object here, not an instance
122 return AE
.AECreateDesc('type', x
.want
)
123 if hasattr(x
, '__aepack__'):
124 return x
.__aepack
__()
125 if hasattr(x
, 'which'):
126 return AE
.AECreateDesc('TEXT', x
.which
)
127 if hasattr(x
, 'want'):
128 return AE
.AECreateDesc('TEXT', x
.want
)
129 return AE
.AECreateDesc('TEXT', repr(x
)) # Copout
131 def unpack(desc
, formodulename
=""):
132 """Unpack an AE descriptor to a python object"""
135 if unpacker_coercions
.has_key(t
):
136 desc
= desc
.AECoerceDesc(unpacker_coercions
[t
])
137 t
= desc
.type # This is a guess by Jack....
141 for i
in range(desc
.AECountItems()):
142 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
143 l
.append(unpack(item
, formodulename
))
145 if t
== typeAERecord
:
147 for i
in range(desc
.AECountItems()):
148 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
149 d
[keyword
] = unpack(item
, formodulename
)
152 record
= desc
.AECoerceDesc('reco')
153 return mkaetext(unpack(record
, formodulename
))
155 return Carbon
.File
.Alias(rawdata
=desc
.data
)
156 # typeAppleEvent returned as unknown
158 return struct
.unpack('b', desc
.data
)[0]
161 if t
== typeUnicodeText
:
162 return unicode(desc
.data
, 'utf16')
163 # typeColorTable coerced to typeAEList
164 # typeComp coerced to extended
165 # typeData returned as unknown
166 # typeDrawingArea coerced to typeAERecord
167 if t
== typeEnumeration
:
168 return mkenum(desc
.data
)
169 # typeEPS returned as unknown
174 return struct
.unpack('d', data
)[0]
176 return Carbon
.File
.FSSpec(rawdata
=desc
.data
)
178 return Carbon
.File
.FSRef(rawdata
=desc
.data
)
179 if t
== typeInsertionLoc
:
180 record
= desc
.AECoerceDesc('reco')
181 return mkinsertionloc(unpack(record
, formodulename
))
182 # typeInteger equal to typeLongInteger
183 if t
== typeIntlText
:
184 script
, language
= struct
.unpack('hh', desc
.data
[:4])
185 return aetypes
.IntlText(script
, language
, desc
.data
[4:])
186 if t
== typeIntlWritingCode
:
187 script
, language
= struct
.unpack('hh', desc
.data
)
188 return aetypes
.IntlWritingCode(script
, language
)
190 return mkkeyword(desc
.data
)
191 if t
== typeLongInteger
:
192 return struct
.unpack('l', desc
.data
)[0]
193 if t
== typeLongDateTime
:
194 a
, b
= struct
.unpack('lL', desc
.data
)
195 return (long(a
) << 32) + b
198 if t
== typeMagnitude
:
199 v
= struct
.unpack('l', desc
.data
)
203 if t
== typeObjectSpecifier
:
204 record
= desc
.AECoerceDesc('reco')
205 # If we have been told the name of the module we are unpacking aedescs for,
206 # we can attempt to create the right type of python object from that module.
208 return mkobjectfrommodule(unpack(record
, formodulename
), formodulename
)
209 return mkobject(unpack(record
, formodulename
))
210 # typePict returned as unknown
211 # typePixelMap coerced to typeAERecord
212 # typePixelMapMinus returned as unknown
213 # typeProcessSerialNumber returned as unknown
215 v
, h
= struct
.unpack('hh', desc
.data
)
216 return aetypes
.QDPoint(v
, h
)
217 if t
== typeQDRectangle
:
218 v0
, h0
, v1
, h1
= struct
.unpack('hhhh', desc
.data
)
219 return aetypes
.QDRectangle(v0
, h0
, v1
, h1
)
220 if t
== typeRGBColor
:
221 r
, g
, b
= struct
.unpack('hhh', desc
.data
)
222 return aetypes
.RGBColor(r
, g
, b
)
223 # typeRotation coerced to typeAERecord
224 # typeScrapStyles returned as unknown
225 # typeSessionID returned as unknown
226 if t
== typeShortFloat
:
227 return struct
.unpack('f', desc
.data
)[0]
228 if t
== typeShortInteger
:
229 return struct
.unpack('h', desc
.data
)[0]
230 # typeSMFloat identical to typeShortFloat
231 # typeSMInt indetical to typeShortInt
232 # typeStyledText coerced to typeAERecord
233 if t
== typeTargetID
:
234 return mktargetid(desc
.data
)
235 # typeTextStyles coerced to typeAERecord
236 # typeTIFF returned as unknown
240 return mktype(desc
.data
, formodulename
)
242 # The following are special
245 record
= desc
.AECoerceDesc('reco')
246 return mkrange(unpack(record
, formodulename
))
248 record
= desc
.AECoerceDesc('reco')
249 return mkcomparison(unpack(record
, formodulename
))
251 record
= desc
.AECoerceDesc('reco')
252 return mklogical(unpack(record
, formodulename
))
253 return mkunknown(desc
.type, desc
.data
)
255 def coerce(data
, egdata
):
256 """Coerce a python object to another type using the AE coercers"""
258 pegdata
= pack(egdata
)
259 pdata
= pdata
.AECoerceDesc(pegdata
.type)
263 # Helper routines for unpack
265 def mktargetid(data
):
266 sessionID
= getlong(data
[:4])
267 name
= mkppcportrec(data
[4:4+72])
268 location
= mklocationnamerec(data
[76:76+36])
269 rcvrName
= mkppcportrec(data
[112:112+72])
270 return sessionID
, name
, location
, rcvrName
272 def mkppcportrec(rec
):
273 namescript
= getword(rec
[:2])
274 name
= getpstr(rec
[2:2+33])
275 portkind
= getword(rec
[36:38])
279 identity
= (ctor
, type)
281 identity
= getpstr(rec
[38:38+33])
282 return namescript
, name
, portkind
, identity
284 def mklocationnamerec(rec
):
285 kind
= getword(rec
[:2])
287 if kind
== 0: stuff
= None
288 if kind
== 2: stuff
= getpstr(stuff
)
291 def mkunknown(type, data
):
292 return aetypes
.Unknown(type, data
)
295 return s
[1:1+ord(s
[0])]
298 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
301 return (ord(s
[0])<<8) |
(ord(s
[1])<<0)
303 def mkkeyword(keyword
):
304 return aetypes
.Keyword(keyword
)
307 return aetypes
.Range(dict['star'], dict['stop'])
309 def mkcomparison(dict):
310 return aetypes
.Comparison(dict['obj1'], dict['relo'].enum
, dict['obj2'])
313 return aetypes
.Logical(dict['logc'], dict['term'])
315 def mkstyledtext(dict):
316 return aetypes
.StyledText(dict['ksty'], dict['ktxt'])
319 return aetypes
.AEText(dict[keyAEScriptTag
], dict[keyAEStyles
], dict[keyAEText
])
321 def mkinsertionloc(dict):
322 return aetypes
.InsertionLoc(dict[keyAEObject
], dict[keyAEPosition
])
325 want
= dict['want'].type
326 form
= dict['form'].enum
329 if form
in ('name', 'indx', 'rang', 'test'):
330 if want
== 'text': return aetypes
.Text(seld
, fr
)
331 if want
== 'cha ': return aetypes
.Character(seld
, fr
)
332 if want
== 'cwor': return aetypes
.Word(seld
, fr
)
333 if want
== 'clin': return aetypes
.Line(seld
, fr
)
334 if want
== 'cpar': return aetypes
.Paragraph(seld
, fr
)
335 if want
== 'cwin': return aetypes
.Window(seld
, fr
)
336 if want
== 'docu': return aetypes
.Document(seld
, fr
)
337 if want
== 'file': return aetypes
.File(seld
, fr
)
338 if want
== 'cins': return aetypes
.InsertionPoint(seld
, fr
)
339 if want
== 'prop' and form
== 'prop' and aetypes
.IsType(seld
):
340 return aetypes
.Property(seld
.type, fr
)
341 return aetypes
.ObjectSpecifier(want
, form
, seld
, fr
)
343 # Note by Jack: I'm not 100% sure of the following code. This was
344 # provided by Donovan Preston, but I wonder whether the assignment
345 # to __class__ is safe. Moreover, shouldn't there be a better
346 # initializer for the classes in the suites?
347 def mkobjectfrommodule(dict, modulename
):
348 if type(dict['want']) == types
.ClassType
and issubclass(dict['want'], ObjectSpecifier
):
349 # The type has already been converted to Python. Convert back:-(
350 classtype
= dict['want']
351 dict['want'] = aetypes
.mktype(classtype
.want
)
352 want
= dict['want'].type
353 module
= __import__(modulename
)
354 codenamemapper
= module
._classdeclarations
355 classtype
= codenamemapper
.get(want
, None)
356 newobj
= mkobject(dict)
358 assert issubclass(classtype
, ObjectSpecifier
)
359 newobj
.__class
__ = classtype
362 def mktype(typecode
, modulename
=None):
364 module
= __import__(modulename
)
365 codenamemapper
= module
._classdeclarations
366 classtype
= codenamemapper
.get(typecode
, None)
369 return aetypes
.mktype(typecode
)