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 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 list = AE
.AECreateList('', 0)
94 list.AEPutDesc(0, pack(item
))
96 if t
== DictionaryType
:
97 record
= AE
.AECreateList('', 1)
98 for key
, value
in x
.items():
99 record
.AEPutParamDesc(key
, pack(value
))
101 if t
== InstanceType
and hasattr(x
, '__aepack__'):
102 return x
.__aepack
__()
103 return AE
.AECreateDesc('TEXT', repr(x
)) # Copout
106 """Unpack an AE descriptor to a python object"""
109 if unpacker_coercions
.has_key(t
):
110 desc
= desc
.AECoerceDesc(unpacker_coercions
[t
])
111 t
= desc
.type # This is a guess by Jack....
115 for i
in range(desc
.AECountItems()):
116 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
117 l
.append(unpack(item
))
119 if t
== typeAERecord
:
121 for i
in range(desc
.AECountItems()):
122 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
123 d
[keyword
] = unpack(item
)
126 record
= desc
.AECoerceDesc('reco')
127 return mkaetext(unpack(record
))
129 return macfs
.RawAlias(desc
.data
)
130 # typeAppleEvent returned as unknown
132 return struct
.unpack('b', desc
.data
)[0]
135 # typeColorTable coerced to typeAEList
136 # typeComp coerced to extended
137 # typeData returned as unknown
138 # typeDrawingArea coerced to typeAERecord
139 if t
== typeEnumeration
:
140 return mkenum(desc
.data
)
141 # typeEPS returned as unknown
146 return struct
.unpack('d', data
)[0]
148 return macfs
.RawFSSpec(desc
.data
)
149 if t
== typeInsertionLoc
:
150 record
= desc
.AECoerceDesc('reco')
151 return mkinsertionloc(unpack(record
))
152 # typeInteger equal to typeLongInteger
153 if t
== typeIntlText
:
154 script
, language
= struct
.unpack('hh', desc
.data
[:4])
155 return aetypes
.IntlText(script
, language
, desc
.data
[4:])
156 if t
== typeIntlWritingCode
:
157 script
, language
= struct
.unpack('hh', desc
.data
)
158 return aetypes
.IntlWritingCode(script
, language
)
160 return mkkeyword(desc
.data
)
161 if t
== typeLongInteger
:
162 return struct
.unpack('l', desc
.data
)[0]
163 if t
== typeLongDateTime
:
164 a
, b
= struct
.unpack('lL', desc
.data
)
165 return (long(a
) << 32) + b
168 if t
== typeMagnitude
:
169 v
= struct
.unpack('l', desc
.data
)
173 if t
== typeObjectSpecifier
:
174 record
= desc
.AECoerceDesc('reco')
175 return mkobject(unpack(record
))
176 # typePict returned as unknown
177 # typePixelMap coerced to typeAERecord
178 # typePixelMapMinus returned as unknown
179 # typeProcessSerialNumber returned as unknown
181 v
, h
= struct
.unpack('hh', desc
.data
)
182 return aetypes
.QDPoint(v
, h
)
183 if t
== typeQDRectangle
:
184 v0
, h0
, v1
, h1
= struct
.unpack('hhhh', desc
.data
)
185 return aetypes
.QDRectangle(v0
, h0
, v1
, h1
)
186 if t
== typeRGBColor
:
187 r
, g
, b
= struct
.unpack('hhh', desc
.data
)
188 return aetypes
.RGBColor(r
, g
, b
)
189 # typeRotation coerced to typeAERecord
190 # typeScrapStyles returned as unknown
191 # typeSessionID returned as unknown
192 if t
== typeShortFloat
:
193 return struct
.unpack('f', desc
.data
)[0]
194 if t
== typeShortInteger
:
195 return struct
.unpack('h', desc
.data
)[0]
196 # typeSMFloat identical to typeShortFloat
197 # typeSMInt indetical to typeShortInt
198 # typeStyledText coerced to typeAERecord
199 if t
== typeTargetID
:
200 return mktargetid(desc
.data
)
201 # typeTextStyles coerced to typeAERecord
202 # typeTIFF returned as unknown
206 return mktype(desc
.data
)
208 # The following are special
211 record
= desc
.AECoerceDesc('reco')
212 return mkrange(unpack(record
))
214 record
= desc
.AECoerceDesc('reco')
215 return mkcomparison(unpack(record
))
217 record
= desc
.AECoerceDesc('reco')
218 return mklogical(unpack(record
))
219 return mkunknown(desc
.type, desc
.data
)
221 def coerce(data
, egdata
):
222 """Coerce a python object to another type using the AE coercers"""
224 pegdata
= pack(egdata
)
225 pdata
= pdata
.AECoerceDesc(pegdata
.type)
229 # Helper routines for unpack
231 def mktargetid(data
):
232 sessionID
= getlong(data
[:4])
233 name
= mkppcportrec(data
[4:4+72])
234 location
= mklocationnamerec(data
[76:76+36])
235 rcvrName
= mkppcportrec(data
[112:112+72])
236 return sessionID
, name
, location
, rcvrName
238 def mkppcportrec(rec
):
239 namescript
= getword(rec
[:2])
240 name
= getpstr(rec
[2:2+33])
241 portkind
= getword(rec
[36:38])
245 identity
= (ctor
, type)
247 identity
= getpstr(rec
[38:38+33])
248 return namescript
, name
, portkind
, identity
250 def mklocationnamerec(rec
):
251 kind
= getword(rec
[:2])
253 if kind
== 0: stuff
= None
254 if kind
== 2: stuff
= getpstr(stuff
)
257 def mkunknown(type, data
):
258 return aetypes
.Unknown(type, data
)
261 return s
[1:1+ord(s
[0])]
264 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
267 return (ord(s
[0])<<8) |
(ord(s
[1])<<0)
269 def mkkeyword(keyword
):
270 return aetypes
.Keyword(keyword
)
273 return aetypes
.Range(dict['star'], dict['stop'])
275 def mkcomparison(dict):
276 return aetypes
.Comparison(dict['obj1'], dict['relo'].enum
, dict['obj2'])
279 return aetypes
.Logical(dict['logc'], dict['term'])
281 def mkstyledtext(dict):
282 return aetypes
.StyledText(dict['ksty'], dict['ktxt'])
285 return aetypes
.AEText(dict[keyAEScriptTag
], dict[keyAEStyles
], dict[keyAEText
])
287 def mkinsertionloc(dict):
288 return aetypes
.InsertionLoc(dict[keyAEObject
], dict[keyAEPosition
])
291 want
= dict['want'].type
292 form
= dict['form'].enum
295 if form
in ('name', 'indx', 'rang', 'test'):
296 if want
== 'text': return aetypes
.Text(seld
, fr
)
297 if want
== 'cha ': return aetypes
.Character(seld
, fr
)
298 if want
== 'cwor': return aetypes
.Word(seld
, fr
)
299 if want
== 'clin': return aetypes
.Line(seld
, fr
)
300 if want
== 'cpar': return aetypes
.Paragraph(seld
, fr
)
301 if want
== 'cwin': return aetypes
.Window(seld
, fr
)
302 if want
== 'docu': return aetypes
.Document(seld
, fr
)
303 if want
== 'file': return aetypes
.File(seld
, fr
)
304 if want
== 'cins': return aetypes
.InsertionPoint(seld
, fr
)
305 if want
== 'prop' and form
== 'prop' and aetypes
.IsType(seld
):
306 return aetypes
.Property(seld
.type, fr
)
307 return aetypes
.ObjectSpecifier(want
, form
, seld
, fr
)
310 """Test program. Pack and unpack various things"""
316 ['a', 'list', 'of', 'strings'],
317 {'key1': 'value1', 'key2':'value2'},
319 macfs
.FSSpec(':').NewAliasMinimal(),
320 aetypes
.Enum('enum'),
321 aetypes
.Type('type'),
322 aetypes
.Keyword('kwrd'),
323 aetypes
.Range(1, 10),
324 aetypes
.Comparison(1, '< ', 10),
325 aetypes
.Logical('not ', 1),
326 # Cannot do StyledText
328 aetypes
.IntlText(0, 0, 'international text'),
329 aetypes
.IntlWritingCode(0,0),
330 aetypes
.QDPoint(50,100),
331 aetypes
.QDRectangle(50,100,150,200),
332 aetypes
.RGBColor(0x7000, 0x6000, 0x5000),
333 aetypes
.Unknown('xxxx', 'unknown type data'),
334 aetypes
.Character(1),
335 aetypes
.Character(2, aetypes
.Line(2)),
338 print 'BEFORE', o
, `o`
340 unpacked
= unpack(packed
)
341 print 'AFTER ', unpacked
, `unpacked`
345 if __name__
== '__main__':