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 *
26 from baetypes
import mkenum
, mktype
30 OSL
= calldll
.getlibrary('ObjectSupportLib')
32 # These ones seem to be missing from AppleEvents
33 # (they're in AERegistry.h)
35 #typeColorTable = 'clrt'
36 #typeDrawingArea = 'cdrw'
37 #typePixelMap = 'cpix'
38 #typePixelMapMinus = 'tpmm'
39 #typeRotation = 'trot'
40 #typeTextStyles = 'tsty'
41 #typeStyledText = 'STXT'
43 #typeEnumeration = 'enum'
46 # Some AE types are immedeately coerced into something
47 # we like better (and which is equivalent)
49 unpacker_coercions
= {
50 typeComp
: typeExtended
,
51 typeColorTable
: typeAEList
,
52 typeDrawingArea
: typeAERecord
,
53 typeFixed
: typeExtended
,
54 typeFloat
: typeExtended
,
55 typePixelMap
: typeAERecord
,
56 typeRotation
: typeAERecord
,
57 typeStyledText
: typeAERecord
,
58 typeTextStyles
: typeAERecord
,
62 # Some python types we need in the packer:
64 AEDescType
= type(AE
.AECreateDesc('TEXT', ''))
65 _sample_fss
= macfs
.FSSpec(':')
66 _sample_alias
= _sample_fss
.NewAliasMinimal()
67 FSSType
= type(_sample_fss
)
68 AliasType
= type(_sample_alias
)
70 def pack(x
, forcetype
= None):
71 """Pack a python object into an AE descriptor"""
72 # print 'aepack', x, type(x), forcetype
73 # if type(x) == TupleType:
77 if type(x
) is StringType
:
78 return AE
.AECreateDesc(forcetype
, x
)
80 return pack(x
).AECoerceDesc(forcetype
)
83 return AE
.AECreateDesc('null', '')
89 return AE
.AECreateDesc('fss ', x
.data
)
91 return AE
.AECreateDesc('alis', x
.data
)
93 return AE
.AECreateDesc('long', struct
.pack('l', x
))
96 # XXXX (note by Guido) Weird thing -- Think C's "double" is 10 bytes, but
97 # struct.pack('d') return 12 bytes (and struct.unpack requires
98 # them, too). The first 2 bytes seem to be repeated...
99 # Probably an alignment problem
100 # XXXX (note by Jack) haven't checked this under MW
102 # return AE.AECreateDesc('exte', struct.pack('d', x)[2:])
103 return AE
.AECreateDesc('exte', struct
.pack('d', x
))
105 return AE
.AECreateDesc('TEXT', x
)
107 list = AE
.AECreateList('', 0)
109 list.AEPutDesc(0, pack(item
))
111 if t
== DictionaryType
:
112 record
= AE
.AECreateList('', 1)
113 for key
, value
in x
.items():
114 record
.AEPutParamDesc(key
, pack(value
))
116 if t
== InstanceType
and hasattr(x
, '__aepack__'):
117 return x
.__aepack
__()
118 return AE
.AECreateDesc('TEXT', repr(x
)) # Copout
121 """Unpack an AE descriptor to a python object"""
125 if unpacker_coercions
.has_key(t
):
126 desc
= desc
.AECoerceDesc(unpacker_coercions
[t
])
127 t
= desc
.type # This is a guess by Jack....
131 for i
in range(desc
.AECountItems()):
132 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
133 l
.append(unpack(item
))
135 if t
== typeAERecord
:
137 for i
in range(desc
.AECountItems()):
138 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
139 d
[keyword
] = unpack(item
)
142 record
= desc
.AECoerceDesc('reco')
143 return mkaetext(unpack(record
))
145 return macfs
.RawAlias(desc
.data
)
146 # typeAppleEvent returned as unknown
148 return struct
.unpack('b', desc
.data
)[0]
151 # typeColorTable coerced to typeAEList
152 # typeComp coerced to extended
153 # typeData returned as unknown
154 # typeDrawingArea coerced to typeAERecord
155 if t
== typeEnumeration
:
156 return mkenum(desc
.data
)
157 # typeEPS returned as unknown
158 if t
== typeExtended
:
159 # print desc, type(desc), len(desc)
161 # print `data[:8]`, type(data), len(data[:8])
162 # print struct.unpack('=d', data[:8])[0]
163 # print string.atoi(data), type(data), len(data)
164 # print struct.calcsize(data)
165 # XXX See corresponding note for pack()
166 # return struct.unpack('d', data[:2] + data)[0]
167 return struct
.unpack('d', data
[:8])[0]
170 # typeFixed coerced to extended
171 # typeFloat coerced to extended
173 return macfs
.RawFSSpec(desc
.data
)
174 if t
== typeInsertionLoc
:
175 record
= desc
.AECoerceDesc('reco')
176 return mkinsertionloc(unpack(record
))
177 # typeInteger equal to typeLongInteger
178 if t
== typeIntlText
:
179 script
, language
= struct
.unpack('hh', desc
.data
[:4])
180 return baetypes
.IntlText(script
, language
, desc
.data
[4:])
181 if t
== typeIntlWritingCode
:
182 script
, language
= struct
.unpack('hh', desc
.data
)
183 return baetypes
.IntlWritingCode(script
, language
)
185 return mkkeyword(desc
.data
)
186 # typeLongFloat is equal to typeFloat
187 if t
== typeLongInteger
:
188 # print t, struct.unpack('l', desc.data)
189 return struct
.unpack('l', desc
.data
)[0]
192 if t
== typeMagnitude
:
193 v
= struct
.unpack('l', desc
.data
)
197 if t
== typeObjectSpecifier
:
199 # print desc, type(desc)
200 # print desc.__members__
201 # print desc.data, desc.type
203 # getOSL = calldll.newcall(OSL.AEResolve, 'OSErr', 'InHandle', 'InShort')#, 'InString')
204 # print 'OSL', getOSL(rdesc, 0)#, desc.data)
205 record
= desc
.AECoerceDesc('reco')
207 return mkobject(unpack(record
))
208 # typePict returned as unknown
209 # typePixelMap coerced to typeAERecord
210 # typePixelMapMinus returned as unknown
211 # typeProcessSerialNumber returned as unknown
213 v
, h
= struct
.unpack('hh', desc
.data
)
214 return baetypes
.QDPoint(v
, h
)
215 if t
== typeQDRectangle
:
216 v0
, h0
, v1
, h1
= struct
.unpack('hhhh', desc
.data
)
217 return baetypes
.QDRectangle(v0
, h0
, v1
, h1
)
218 if t
== typeRGBColor
:
219 r
, g
, b
= struct
.unpack('hhh', desc
.data
)
220 return baetypes
.RGBColor(r
, g
, b
)
221 # typeRotation coerced to typeAERecord
222 # typeScrapStyles returned as unknown
223 # typeSessionID returned as unknown
224 if t
== typeShortFloat
:
225 return struct
.unpack('f', desc
.data
)[0]
226 if t
== typeShortInteger
:
228 # print struct.unpack('h', desc.data)[0]
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
241 return mktype(desc
.data
)
243 # The following are special
246 record
= desc
.AECoerceDesc('reco')
247 return mkrange(unpack(record
))
249 record
= desc
.AECoerceDesc('reco')
250 return mkcomparison(unpack(record
))
252 record
= desc
.AECoerceDesc('reco')
253 return mklogical(unpack(record
))
254 return mkunknown(desc
.type, desc
.data
)
256 def coerce(data
, egdata
):
257 """Coerce a python object to another type using the AE coercers"""
259 pegdata
= pack(egdata
)
260 pdata
= pdata
.AECoerceDesc(pegdata
.type)
264 # Helper routines for unpack
266 def mktargetid(data
):
267 sessionID
= getlong(data
[:4])
268 name
= mkppcportrec(data
[4:4+72])
269 location
= mklocationnamerec(data
[76:76+36])
270 rcvrName
= mkppcportrec(data
[112:112+72])
271 return sessionID
, name
, location
, rcvrName
273 def mkppcportrec(rec
):
274 namescript
= getword(rec
[:2])
275 name
= getpstr(rec
[2:2+33])
276 portkind
= getword(rec
[36:38])
280 identity
= (ctor
, type)
282 identity
= getpstr(rec
[38:38+33])
283 return namescript
, name
, portkind
, identity
285 def mklocationnamerec(rec
):
286 kind
= getword(rec
[:2])
288 if kind
== 0: stuff
= None
289 if kind
== 2: stuff
= getpstr(stuff
)
292 def mkunknown(type, data
):
293 return baetypes
.Unknown(type, data
)
296 return s
[1:1+ord(s
[0])]
299 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
302 return (ord(s
[0])<<8) |
(ord(s
[1])<<0)
304 def mkkeyword(keyword
):
305 return baetypes
.Keyword(keyword
)
308 return baetypes
.Range(dict['star'], dict['stop'])
310 def mkcomparison(dict):
311 return baetypes
.Comparison(dict['obj1'], dict['relo'].enum
, dict['obj2'])
314 return baetypes
.Logical(dict['logc'], dict['term'])
316 def mkstyledtext(dict):
317 return baetypes
.StyledText(dict['ksty'], dict['ktxt'])
320 return baetypes
.AEText(dict[keyAEScriptTag
], dict[keyAEStyles
], dict[keyAEText
])
322 def mkinsertionloc(dict):
323 return baetypes
.InsertionLoc(dict[keyAEObject
], dict[keyAEPosition
])
326 want
= dict['want'].type
327 form
= dict['form'].enum
330 if form
in ('name', 'indx', 'rang', 'test'):
331 if want
== 'text': return baetypes
.Text(seld
, fr
)
332 if want
== 'cha ': return baetypes
.Character(seld
, fr
)
333 if want
== 'cwor': return baetypes
.Word(seld
, fr
)
334 if want
== 'clin': return baetypes
.Line(seld
, fr
)
335 if want
== 'cpar': return baetypes
.Paragraph(seld
, fr
)
336 if want
== 'cwin': return baetypes
.Window(seld
, fr
)
337 if want
== 'docu': return baetypes
.Document(seld
, fr
)
338 if want
== 'file': return baetypes
.File(seld
, fr
)
339 if want
== 'cins': return baetypes
.InsertionPoint(seld
, fr
)
340 if want
== 'prop' and form
== 'prop' and baetypes
.IsType(seld
):
341 return baetypes
.Property(seld
.type, fr
)
342 return baetypes
.ObjectSpecifier(want
, form
, seld
, fr
)
345 """Test program. Pack and unpack various things"""
351 ['a', 'list', 'of', 'strings'],
352 {'key1': 'value1', 'key2':'value2'},
354 macfs
.FSSpec(':').NewAliasMinimal(),
355 baetypes
.Enum('enum'),
356 baetypes
.Type('type'),
357 baetypes
.Keyword('kwrd'),
358 baetypes
.Range(1, 10),
359 baetypes
.Comparison(1, '< ', 10),
360 baetypes
.Logical('not ', 1),
361 # Cannot do StyledText
363 baetypes
.IntlText(0, 0, 'international text'),
364 baetypes
.IntlWritingCode(0,0),
365 baetypes
.QDPoint(50,100),
366 baetypes
.QDRectangle(50,100,150,200),
367 baetypes
.RGBColor(0x7000, 0x6000, 0x5000),
368 baetypes
.Unknown('xxxx', 'unknown type data'),
369 baetypes
.Character(1),
370 baetypes
.Character(2, baetypes
.Line(2)),
373 print 'BEFORE', o
, `o`
376 unpacked
= unpack(packed
)
377 print 'AFTER ', unpacked
, `unpacked`
381 if __name__
== '__main__':