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 AppleEvents
import *
22 from AERegistry
import *
23 from AEObjects
import *
28 from baetypes
import mkenum
, mktype
32 OSL
= calldll
.getlibrary('ObjectSupportLib')
34 # These ones seem to be missing from AppleEvents
35 # (they're in AERegistry.h)
37 #typeColorTable = 'clrt'
38 #typeDrawingArea = 'cdrw'
39 #typePixelMap = 'cpix'
40 #typePixelMapMinus = 'tpmm'
41 #typeRotation = 'trot'
42 #typeTextStyles = 'tsty'
43 #typeStyledText = 'STXT'
45 #typeEnumeration = 'enum'
48 # Some AE types are immedeately coerced into something
49 # we like better (and which is equivalent)
51 unpacker_coercions
= {
52 typeComp
: typeExtended
,
53 typeColorTable
: typeAEList
,
54 typeDrawingArea
: typeAERecord
,
55 typeFixed
: typeExtended
,
56 typeFloat
: typeExtended
,
57 typePixelMap
: typeAERecord
,
58 typeRotation
: typeAERecord
,
59 typeStyledText
: typeAERecord
,
60 typeTextStyles
: typeAERecord
,
64 # Some python types we need in the packer:
66 AEDescType
= type(AE
.AECreateDesc('TEXT', ''))
67 _sample_fss
= macfs
.FSSpec(':')
68 _sample_alias
= _sample_fss
.NewAliasMinimal()
69 FSSType
= type(_sample_fss
)
70 AliasType
= type(_sample_alias
)
72 def pack(x
, forcetype
= None):
73 """Pack a python object into an AE descriptor"""
74 # print 'aepack', x, type(x), forcetype
75 # if type(x) == TupleType:
79 if type(x
) is StringType
:
80 return AE
.AECreateDesc(forcetype
, x
)
82 return pack(x
).AECoerceDesc(forcetype
)
85 return AE
.AECreateDesc('null', '')
91 return AE
.AECreateDesc('fss ', x
.data
)
93 return AE
.AECreateDesc('alis', x
.data
)
95 return AE
.AECreateDesc('long', struct
.pack('l', x
))
98 # XXXX (note by Guido) Weird thing -- Think C's "double" is 10 bytes, but
99 # struct.pack('d') return 12 bytes (and struct.unpack requires
100 # them, too). The first 2 bytes seem to be repeated...
101 # Probably an alignment problem
102 # XXXX (note by Jack) haven't checked this under MW
104 # return AE.AECreateDesc('exte', struct.pack('d', x)[2:])
105 return AE
.AECreateDesc('exte', struct
.pack('d', x
))
107 return AE
.AECreateDesc('TEXT', x
)
109 list = AE
.AECreateList('', 0)
111 list.AEPutDesc(0, pack(item
))
113 if t
== DictionaryType
:
114 record
= AE
.AECreateList('', 1)
115 for key
, value
in x
.items():
116 record
.AEPutParamDesc(key
, pack(value
))
118 if t
== InstanceType
and hasattr(x
, '__aepack__'):
119 return x
.__aepack
__()
120 return AE
.AECreateDesc('TEXT', repr(x
)) # Copout
123 """Unpack an AE descriptor to a python object"""
127 if unpacker_coercions
.has_key(t
):
128 desc
= desc
.AECoerceDesc(unpacker_coercions
[t
])
129 t
= desc
.type # This is a guess by Jack....
133 for i
in range(desc
.AECountItems()):
134 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
135 l
.append(unpack(item
))
137 if t
== typeAERecord
:
139 for i
in range(desc
.AECountItems()):
140 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
141 d
[keyword
] = unpack(item
)
144 record
= desc
.AECoerceDesc('reco')
145 return mkaetext(unpack(record
))
147 return macfs
.RawAlias(desc
.data
)
148 # typeAppleEvent returned as unknown
150 return struct
.unpack('b', desc
.data
)[0]
153 # typeColorTable coerced to typeAEList
154 # typeComp coerced to extended
155 # typeData returned as unknown
156 # typeDrawingArea coerced to typeAERecord
157 if t
== typeEnumeration
:
158 return mkenum(desc
.data
)
159 # typeEPS returned as unknown
160 if t
== typeExtended
:
161 # print desc, type(desc), len(desc)
163 # print `data[:8]`, type(data), len(data[:8])
164 # print struct.unpack('=d', data[:8])[0]
165 # print string.atoi(data), type(data), len(data)
166 # print struct.calcsize(data)
167 # XXX See corresponding note for pack()
168 # return struct.unpack('d', data[:2] + data)[0]
169 return struct
.unpack('d', data
[:8])[0]
172 # typeFixed coerced to extended
173 # typeFloat coerced to extended
175 return macfs
.RawFSSpec(desc
.data
)
176 if t
== typeInsertionLoc
:
177 record
= desc
.AECoerceDesc('reco')
178 return mkinsertionloc(unpack(record
))
179 # typeInteger equal to typeLongInteger
180 if t
== typeIntlText
:
181 script
, language
= struct
.unpack('hh', desc
.data
[:4])
182 return baetypes
.IntlText(script
, language
, desc
.data
[4:])
183 if t
== typeIntlWritingCode
:
184 script
, language
= struct
.unpack('hh', desc
.data
)
185 return baetypes
.IntlWritingCode(script
, language
)
187 return mkkeyword(desc
.data
)
188 # typeLongFloat is equal to typeFloat
189 if t
== typeLongInteger
:
190 # print t, struct.unpack('l', desc.data)
191 return struct
.unpack('l', desc
.data
)[0]
194 if t
== typeMagnitude
:
195 v
= struct
.unpack('l', desc
.data
)
199 if t
== typeObjectSpecifier
:
201 # print desc, type(desc)
202 # print desc.__members__
203 # print desc.data, desc.type
205 # getOSL = calldll.newcall(OSL.AEResolve, 'OSErr', 'InHandle', 'InShort')#, 'InString')
206 # print 'OSL', getOSL(rdesc, 0)#, desc.data)
207 record
= desc
.AECoerceDesc('reco')
209 return mkobject(unpack(record
))
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 baetypes
.QDPoint(v
, h
)
217 if t
== typeQDRectangle
:
218 v0
, h0
, v1
, h1
= struct
.unpack('hhhh', desc
.data
)
219 return baetypes
.QDRectangle(v0
, h0
, v1
, h1
)
220 if t
== typeRGBColor
:
221 r
, g
, b
= struct
.unpack('hhh', desc
.data
)
222 return baetypes
.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
:
230 # print struct.unpack('h', desc.data)[0]
231 return struct
.unpack('h', desc
.data
)[0]
232 # typeSMFloat identical to typeShortFloat
233 # typeSMInt indetical to typeShortInt
234 # typeStyledText coerced to typeAERecord
235 if t
== typeTargetID
:
236 return mktargetid(desc
.data
)
237 # typeTextStyles coerced to typeAERecord
238 # typeTIFF returned as unknown
243 return mktype(desc
.data
)
245 # The following are special
248 record
= desc
.AECoerceDesc('reco')
249 return mkrange(unpack(record
))
251 record
= desc
.AECoerceDesc('reco')
252 return mkcomparison(unpack(record
))
254 record
= desc
.AECoerceDesc('reco')
255 return mklogical(unpack(record
))
256 return mkunknown(desc
.type, desc
.data
)
258 def coerce(data
, egdata
):
259 """Coerce a python object to another type using the AE coercers"""
261 pegdata
= pack(egdata
)
262 pdata
= pdata
.AECoerceDesc(pegdata
.type)
266 # Helper routines for unpack
268 def mktargetid(data
):
269 sessionID
= getlong(data
[:4])
270 name
= mkppcportrec(data
[4:4+72])
271 location
= mklocationnamerec(data
[76:76+36])
272 rcvrName
= mkppcportrec(data
[112:112+72])
273 return sessionID
, name
, location
, rcvrName
275 def mkppcportrec(rec
):
276 namescript
= getword(rec
[:2])
277 name
= getpstr(rec
[2:2+33])
278 portkind
= getword(rec
[36:38])
282 identity
= (ctor
, type)
284 identity
= getpstr(rec
[38:38+33])
285 return namescript
, name
, portkind
, identity
287 def mklocationnamerec(rec
):
288 kind
= getword(rec
[:2])
290 if kind
== 0: stuff
= None
291 if kind
== 2: stuff
= getpstr(stuff
)
294 def mkunknown(type, data
):
295 return baetypes
.Unknown(type, data
)
298 return s
[1:1+ord(s
[0])]
301 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
304 return (ord(s
[0])<<8) |
(ord(s
[1])<<0)
306 def mkkeyword(keyword
):
307 return baetypes
.Keyword(keyword
)
310 return baetypes
.Range(dict['star'], dict['stop'])
312 def mkcomparison(dict):
313 return baetypes
.Comparison(dict['obj1'], dict['relo'].enum
, dict['obj2'])
316 return baetypes
.Logical(dict['logc'], dict['term'])
318 def mkstyledtext(dict):
319 return baetypes
.StyledText(dict['ksty'], dict['ktxt'])
322 return baetypes
.AEText(dict[keyAEScriptTag
], dict[keyAEStyles
], dict[keyAEText
])
324 def mkinsertionloc(dict):
325 return baetypes
.InsertionLoc(dict[keyAEObject
], dict[keyAEPosition
])
328 want
= dict['want'].type
329 form
= dict['form'].enum
332 if form
in ('name', 'indx', 'rang', 'test'):
333 if want
== 'text': return baetypes
.Text(seld
, fr
)
334 if want
== 'cha ': return baetypes
.Character(seld
, fr
)
335 if want
== 'cwor': return baetypes
.Word(seld
, fr
)
336 if want
== 'clin': return baetypes
.Line(seld
, fr
)
337 if want
== 'cpar': return baetypes
.Paragraph(seld
, fr
)
338 if want
== 'cwin': return baetypes
.Window(seld
, fr
)
339 if want
== 'docu': return baetypes
.Document(seld
, fr
)
340 if want
== 'file': return baetypes
.File(seld
, fr
)
341 if want
== 'cins': return baetypes
.InsertionPoint(seld
, fr
)
342 if want
== 'prop' and form
== 'prop' and baetypes
.IsType(seld
):
343 return baetypes
.Property(seld
.type, fr
)
344 return baetypes
.ObjectSpecifier(want
, form
, seld
, fr
)
347 """Test program. Pack and unpack various things"""
353 ['a', 'list', 'of', 'strings'],
354 {'key1': 'value1', 'key2':'value2'},
356 macfs
.FSSpec(':').NewAliasMinimal(),
357 baetypes
.Enum('enum'),
358 baetypes
.Type('type'),
359 baetypes
.Keyword('kwrd'),
360 baetypes
.Range(1, 10),
361 baetypes
.Comparison(1, '< ', 10),
362 baetypes
.Logical('not ', 1),
363 # Cannot do StyledText
365 baetypes
.IntlText(0, 0, 'international text'),
366 baetypes
.IntlWritingCode(0,0),
367 baetypes
.QDPoint(50,100),
368 baetypes
.QDRectangle(50,100,150,200),
369 baetypes
.RGBColor(0x7000, 0x6000, 0x5000),
370 baetypes
.Unknown('xxxx', 'unknown type data'),
371 baetypes
.Character(1),
372 baetypes
.Character(2, baetypes
.Line(2)),
375 print 'BEFORE', o
, `o`
378 unpacked
= unpack(packed
)
379 print 'AFTER ', unpacked
, `unpacked`
383 if __name__
== '__main__':