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.
18 from string
import strip
21 from Carbon
.AppleEvents
import *
26 from aetypes
import mkenum
, mktype
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
= type(AE
.AECreateDesc('TEXT', ''))
61 _sample_fss
= macfs
.FSSpec(':')
62 _sample_alias
= _sample_fss
.NewAliasMinimal()
63 FSSType
= type(_sample_fss
)
64 AliasType
= type(_sample_alias
)
66 def pack(x
, forcetype
= None):
67 """Pack a python object into an AE descriptor"""
70 if type(x
) is StringType
:
71 return AE
.AECreateDesc(forcetype
, x
)
73 return pack(x
).AECoerceDesc(forcetype
)
76 return AE
.AECreateDesc('null', '')
82 return AE
.AECreateDesc('fss ', x
.data
)
84 return AE
.AECreateDesc('alis', x
.data
)
86 return AE
.AECreateDesc('long', struct
.pack('l', x
))
88 return AE
.AECreateDesc('doub', struct
.pack('d', x
))
90 return AE
.AECreateDesc('TEXT', x
)
92 data
= t
.encode('utf16')
93 if data
[:2] == '\xfe\xff':
95 return AE
.AECreateDesc('utxt', data
)
97 list = AE
.AECreateList('', 0)
99 list.AEPutDesc(0, pack(item
))
101 if t
== DictionaryType
:
102 record
= AE
.AECreateList('', 1)
103 for key
, value
in x
.items():
104 record
.AEPutParamDesc(key
, pack(value
))
106 if t
== InstanceType
and hasattr(x
, '__aepack__'):
107 return x
.__aepack
__()
108 return AE
.AECreateDesc('TEXT', repr(x
)) # Copout
111 """Unpack an AE descriptor to a python object"""
114 if unpacker_coercions
.has_key(t
):
115 desc
= desc
.AECoerceDesc(unpacker_coercions
[t
])
116 t
= desc
.type # This is a guess by Jack....
120 for i
in range(desc
.AECountItems()):
121 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
122 l
.append(unpack(item
))
124 if t
== typeAERecord
:
126 for i
in range(desc
.AECountItems()):
127 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
128 d
[keyword
] = unpack(item
)
131 record
= desc
.AECoerceDesc('reco')
132 return mkaetext(unpack(record
))
134 return macfs
.RawAlias(desc
.data
)
135 # typeAppleEvent returned as unknown
137 return struct
.unpack('b', desc
.data
)[0]
140 if t
== typeUnicodeText
:
141 return unicode(desc
.data
, 'utf16')
142 # typeColorTable coerced to typeAEList
143 # typeComp coerced to extended
144 # typeData returned as unknown
145 # typeDrawingArea coerced to typeAERecord
146 if t
== typeEnumeration
:
147 return mkenum(desc
.data
)
148 # typeEPS returned as unknown
153 return struct
.unpack('d', data
)[0]
155 return macfs
.RawFSSpec(desc
.data
)
156 if t
== typeInsertionLoc
:
157 record
= desc
.AECoerceDesc('reco')
158 return mkinsertionloc(unpack(record
))
159 # typeInteger equal to typeLongInteger
160 if t
== typeIntlText
:
161 script
, language
= struct
.unpack('hh', desc
.data
[:4])
162 return aetypes
.IntlText(script
, language
, desc
.data
[4:])
163 if t
== typeIntlWritingCode
:
164 script
, language
= struct
.unpack('hh', desc
.data
)
165 return aetypes
.IntlWritingCode(script
, language
)
167 return mkkeyword(desc
.data
)
168 if t
== typeLongInteger
:
169 return struct
.unpack('l', desc
.data
)[0]
170 if t
== typeLongDateTime
:
171 a
, b
= struct
.unpack('lL', desc
.data
)
172 return (long(a
) << 32) + b
175 if t
== typeMagnitude
:
176 v
= struct
.unpack('l', desc
.data
)
180 if t
== typeObjectSpecifier
:
181 record
= desc
.AECoerceDesc('reco')
182 return mkobject(unpack(record
))
183 # typePict returned as unknown
184 # typePixelMap coerced to typeAERecord
185 # typePixelMapMinus returned as unknown
186 # typeProcessSerialNumber returned as unknown
188 v
, h
= struct
.unpack('hh', desc
.data
)
189 return aetypes
.QDPoint(v
, h
)
190 if t
== typeQDRectangle
:
191 v0
, h0
, v1
, h1
= struct
.unpack('hhhh', desc
.data
)
192 return aetypes
.QDRectangle(v0
, h0
, v1
, h1
)
193 if t
== typeRGBColor
:
194 r
, g
, b
= struct
.unpack('hhh', desc
.data
)
195 return aetypes
.RGBColor(r
, g
, b
)
196 # typeRotation coerced to typeAERecord
197 # typeScrapStyles returned as unknown
198 # typeSessionID returned as unknown
199 if t
== typeShortFloat
:
200 return struct
.unpack('f', desc
.data
)[0]
201 if t
== typeShortInteger
:
202 return struct
.unpack('h', desc
.data
)[0]
203 # typeSMFloat identical to typeShortFloat
204 # typeSMInt indetical to typeShortInt
205 # typeStyledText coerced to typeAERecord
206 if t
== typeTargetID
:
207 return mktargetid(desc
.data
)
208 # typeTextStyles coerced to typeAERecord
209 # typeTIFF returned as unknown
213 return mktype(desc
.data
)
215 # The following are special
218 record
= desc
.AECoerceDesc('reco')
219 return mkrange(unpack(record
))
221 record
= desc
.AECoerceDesc('reco')
222 return mkcomparison(unpack(record
))
224 record
= desc
.AECoerceDesc('reco')
225 return mklogical(unpack(record
))
226 return mkunknown(desc
.type, desc
.data
)
228 def coerce(data
, egdata
):
229 """Coerce a python object to another type using the AE coercers"""
231 pegdata
= pack(egdata
)
232 pdata
= pdata
.AECoerceDesc(pegdata
.type)
236 # Helper routines for unpack
238 def mktargetid(data
):
239 sessionID
= getlong(data
[:4])
240 name
= mkppcportrec(data
[4:4+72])
241 location
= mklocationnamerec(data
[76:76+36])
242 rcvrName
= mkppcportrec(data
[112:112+72])
243 return sessionID
, name
, location
, rcvrName
245 def mkppcportrec(rec
):
246 namescript
= getword(rec
[:2])
247 name
= getpstr(rec
[2:2+33])
248 portkind
= getword(rec
[36:38])
252 identity
= (ctor
, type)
254 identity
= getpstr(rec
[38:38+33])
255 return namescript
, name
, portkind
, identity
257 def mklocationnamerec(rec
):
258 kind
= getword(rec
[:2])
260 if kind
== 0: stuff
= None
261 if kind
== 2: stuff
= getpstr(stuff
)
264 def mkunknown(type, data
):
265 return aetypes
.Unknown(type, data
)
268 return s
[1:1+ord(s
[0])]
271 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
274 return (ord(s
[0])<<8) |
(ord(s
[1])<<0)
276 def mkkeyword(keyword
):
277 return aetypes
.Keyword(keyword
)
280 return aetypes
.Range(dict['star'], dict['stop'])
282 def mkcomparison(dict):
283 return aetypes
.Comparison(dict['obj1'], dict['relo'].enum
, dict['obj2'])
286 return aetypes
.Logical(dict['logc'], dict['term'])
288 def mkstyledtext(dict):
289 return aetypes
.StyledText(dict['ksty'], dict['ktxt'])
292 return aetypes
.AEText(dict[keyAEScriptTag
], dict[keyAEStyles
], dict[keyAEText
])
294 def mkinsertionloc(dict):
295 return aetypes
.InsertionLoc(dict[keyAEObject
], dict[keyAEPosition
])
298 want
= dict['want'].type
299 form
= dict['form'].enum
302 if form
in ('name', 'indx', 'rang', 'test'):
303 if want
== 'text': return aetypes
.Text(seld
, fr
)
304 if want
== 'cha ': return aetypes
.Character(seld
, fr
)
305 if want
== 'cwor': return aetypes
.Word(seld
, fr
)
306 if want
== 'clin': return aetypes
.Line(seld
, fr
)
307 if want
== 'cpar': return aetypes
.Paragraph(seld
, fr
)
308 if want
== 'cwin': return aetypes
.Window(seld
, fr
)
309 if want
== 'docu': return aetypes
.Document(seld
, fr
)
310 if want
== 'file': return aetypes
.File(seld
, fr
)
311 if want
== 'cins': return aetypes
.InsertionPoint(seld
, fr
)
312 if want
== 'prop' and form
== 'prop' and aetypes
.IsType(seld
):
313 return aetypes
.Property(seld
.type, fr
)
314 return aetypes
.ObjectSpecifier(want
, form
, seld
, fr
)
317 """Test program. Pack and unpack various things"""
323 ['a', 'list', 'of', 'strings'],
324 {'key1': 'value1', 'key2':'value2'},
326 macfs
.FSSpec(':').NewAliasMinimal(),
327 aetypes
.Enum('enum'),
328 aetypes
.Type('type'),
329 aetypes
.Keyword('kwrd'),
330 aetypes
.Range(1, 10),
331 aetypes
.Comparison(1, '< ', 10),
332 aetypes
.Logical('not ', 1),
333 # Cannot do StyledText
335 aetypes
.IntlText(0, 0, 'international text'),
336 aetypes
.IntlWritingCode(0,0),
337 aetypes
.QDPoint(50,100),
338 aetypes
.QDRectangle(50,100,150,200),
339 aetypes
.RGBColor(0x7000, 0x6000, 0x5000),
340 aetypes
.Unknown('xxxx', 'unknown type data'),
341 aetypes
.Character(1),
342 aetypes
.Character(2, aetypes
.Line(2)),
345 print 'BEFORE', o
, `o`
347 unpacked
= unpack(packed
)
348 print 'AFTER ', unpacked
, `unpacked`
352 if __name__
== '__main__':