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 aetypes
import mkenum
, mktype
30 # These ones seem to be missing from AppleEvents
31 # (they're in AERegistry.h)
33 #typeColorTable = 'clrt'
34 #typeDrawingArea = 'cdrw'
35 #typePixelMap = 'cpix'
36 #typePixelMapMinus = 'tpmm'
37 #typeRotation = 'trot'
38 #typeTextStyles = 'tsty'
39 #typeStyledText = 'STXT'
41 #typeEnumeration = 'enum'
44 # Some AE types are immedeately coerced into something
45 # we like better (and which is equivalent)
47 unpacker_coercions
= {
49 typeColorTable
: typeAEList
,
50 typeDrawingArea
: typeAERecord
,
51 typeFixed
: typeFloat
,
52 typeExtended
: typeFloat
,
53 typePixelMap
: typeAERecord
,
54 typeRotation
: typeAERecord
,
55 typeStyledText
: typeAERecord
,
56 typeTextStyles
: typeAERecord
,
60 # Some python types we need in the packer:
62 AEDescType
= type(AE
.AECreateDesc('TEXT', ''))
63 _sample_fss
= macfs
.FSSpec(':')
64 _sample_alias
= _sample_fss
.NewAliasMinimal()
65 FSSType
= type(_sample_fss
)
66 AliasType
= type(_sample_alias
)
68 def pack(x
, forcetype
= None):
69 """Pack a python object into an AE descriptor"""
72 if type(x
) is StringType
:
73 return AE
.AECreateDesc(forcetype
, x
)
75 return pack(x
).AECoerceDesc(forcetype
)
78 return AE
.AECreateDesc('null', '')
84 return AE
.AECreateDesc('fss ', x
.data
)
86 return AE
.AECreateDesc('alis', x
.data
)
88 return AE
.AECreateDesc('long', struct
.pack('l', x
))
90 return AE
.AECreateDesc('doub', struct
.pack('d', x
))
92 return AE
.AECreateDesc('TEXT', x
)
94 list = AE
.AECreateList('', 0)
96 list.AEPutDesc(0, pack(item
))
98 if t
== DictionaryType
:
99 record
= AE
.AECreateList('', 1)
100 for key
, value
in x
.items():
101 record
.AEPutParamDesc(key
, pack(value
))
103 if t
== InstanceType
and hasattr(x
, '__aepack__'):
104 return x
.__aepack
__()
105 return AE
.AECreateDesc('TEXT', repr(x
)) # Copout
108 """Unpack an AE descriptor to a python object"""
111 if unpacker_coercions
.has_key(t
):
112 desc
= desc
.AECoerceDesc(unpacker_coercions
[t
])
113 t
= desc
.type # This is a guess by Jack....
117 for i
in range(desc
.AECountItems()):
118 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
119 l
.append(unpack(item
))
121 if t
== typeAERecord
:
123 for i
in range(desc
.AECountItems()):
124 keyword
, item
= desc
.AEGetNthDesc(i
+1, '****')
125 d
[keyword
] = unpack(item
)
128 record
= desc
.AECoerceDesc('reco')
129 return mkaetext(unpack(record
))
131 return macfs
.RawAlias(desc
.data
)
132 # typeAppleEvent returned as unknown
134 return struct
.unpack('b', desc
.data
)[0]
137 # typeColorTable coerced to typeAEList
138 # typeComp coerced to extended
139 # typeData returned as unknown
140 # typeDrawingArea coerced to typeAERecord
141 if t
== typeEnumeration
:
142 return mkenum(desc
.data
)
143 # typeEPS returned as unknown
148 return struct
.unpack('d', data
)[0]
150 return macfs
.RawFSSpec(desc
.data
)
151 if t
== typeInsertionLoc
:
152 record
= desc
.AECoerceDesc('reco')
153 return mkinsertionloc(unpack(record
))
154 # typeInteger equal to typeLongInteger
155 if t
== typeIntlText
:
156 script
, language
= struct
.unpack('hh', desc
.data
[:4])
157 return aetypes
.IntlText(script
, language
, desc
.data
[4:])
158 if t
== typeIntlWritingCode
:
159 script
, language
= struct
.unpack('hh', desc
.data
)
160 return aetypes
.IntlWritingCode(script
, language
)
162 return mkkeyword(desc
.data
)
163 if t
== typeLongInteger
:
164 return struct
.unpack('l', desc
.data
)[0]
165 if t
== typeLongDateTime
:
166 a
, b
= struct
.unpack('lL', desc
.data
)
167 return (long(a
) << 32) + b
170 if t
== typeMagnitude
:
171 v
= struct
.unpack('l', desc
.data
)
175 if t
== typeObjectSpecifier
:
176 record
= desc
.AECoerceDesc('reco')
177 return mkobject(unpack(record
))
178 # typePict returned as unknown
179 # typePixelMap coerced to typeAERecord
180 # typePixelMapMinus returned as unknown
181 # typeProcessSerialNumber returned as unknown
183 v
, h
= struct
.unpack('hh', desc
.data
)
184 return aetypes
.QDPoint(v
, h
)
185 if t
== typeQDRectangle
:
186 v0
, h0
, v1
, h1
= struct
.unpack('hhhh', desc
.data
)
187 return aetypes
.QDRectangle(v0
, h0
, v1
, h1
)
188 if t
== typeRGBColor
:
189 r
, g
, b
= struct
.unpack('hhh', desc
.data
)
190 return aetypes
.RGBColor(r
, g
, b
)
191 # typeRotation coerced to typeAERecord
192 # typeScrapStyles returned as unknown
193 # typeSessionID returned as unknown
194 if t
== typeShortFloat
:
195 return struct
.unpack('f', desc
.data
)[0]
196 if t
== typeShortInteger
:
197 return struct
.unpack('h', desc
.data
)[0]
198 # typeSMFloat identical to typeShortFloat
199 # typeSMInt indetical to typeShortInt
200 # typeStyledText coerced to typeAERecord
201 if t
== typeTargetID
:
202 return mktargetid(desc
.data
)
203 # typeTextStyles coerced to typeAERecord
204 # typeTIFF returned as unknown
208 return mktype(desc
.data
)
210 # The following are special
213 record
= desc
.AECoerceDesc('reco')
214 return mkrange(unpack(record
))
216 record
= desc
.AECoerceDesc('reco')
217 return mkcomparison(unpack(record
))
219 record
= desc
.AECoerceDesc('reco')
220 return mklogical(unpack(record
))
221 return mkunknown(desc
.type, desc
.data
)
223 def coerce(data
, egdata
):
224 """Coerce a python object to another type using the AE coercers"""
226 pegdata
= pack(egdata
)
227 pdata
= pdata
.AECoerceDesc(pegdata
.type)
231 # Helper routines for unpack
233 def mktargetid(data
):
234 sessionID
= getlong(data
[:4])
235 name
= mkppcportrec(data
[4:4+72])
236 location
= mklocationnamerec(data
[76:76+36])
237 rcvrName
= mkppcportrec(data
[112:112+72])
238 return sessionID
, name
, location
, rcvrName
240 def mkppcportrec(rec
):
241 namescript
= getword(rec
[:2])
242 name
= getpstr(rec
[2:2+33])
243 portkind
= getword(rec
[36:38])
247 identity
= (ctor
, type)
249 identity
= getpstr(rec
[38:38+33])
250 return namescript
, name
, portkind
, identity
252 def mklocationnamerec(rec
):
253 kind
= getword(rec
[:2])
255 if kind
== 0: stuff
= None
256 if kind
== 2: stuff
= getpstr(stuff
)
259 def mkunknown(type, data
):
260 return aetypes
.Unknown(type, data
)
263 return s
[1:1+ord(s
[0])]
266 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
269 return (ord(s
[0])<<8) |
(ord(s
[1])<<0)
271 def mkkeyword(keyword
):
272 return aetypes
.Keyword(keyword
)
275 return aetypes
.Range(dict['star'], dict['stop'])
277 def mkcomparison(dict):
278 return aetypes
.Comparison(dict['obj1'], dict['relo'].enum
, dict['obj2'])
281 return aetypes
.Logical(dict['logc'], dict['term'])
283 def mkstyledtext(dict):
284 return aetypes
.StyledText(dict['ksty'], dict['ktxt'])
287 return aetypes
.AEText(dict[keyAEScriptTag
], dict[keyAEStyles
], dict[keyAEText
])
289 def mkinsertionloc(dict):
290 return aetypes
.InsertionLoc(dict[keyAEObject
], dict[keyAEPosition
])
293 want
= dict['want'].type
294 form
= dict['form'].enum
297 if form
in ('name', 'indx', 'rang', 'test'):
298 if want
== 'text': return aetypes
.Text(seld
, fr
)
299 if want
== 'cha ': return aetypes
.Character(seld
, fr
)
300 if want
== 'cwor': return aetypes
.Word(seld
, fr
)
301 if want
== 'clin': return aetypes
.Line(seld
, fr
)
302 if want
== 'cpar': return aetypes
.Paragraph(seld
, fr
)
303 if want
== 'cwin': return aetypes
.Window(seld
, fr
)
304 if want
== 'docu': return aetypes
.Document(seld
, fr
)
305 if want
== 'file': return aetypes
.File(seld
, fr
)
306 if want
== 'cins': return aetypes
.InsertionPoint(seld
, fr
)
307 if want
== 'prop' and form
== 'prop' and aetypes
.IsType(seld
):
308 return aetypes
.Property(seld
.type, fr
)
309 return aetypes
.ObjectSpecifier(want
, form
, seld
, fr
)
312 """Test program. Pack and unpack various things"""
318 ['a', 'list', 'of', 'strings'],
319 {'key1': 'value1', 'key2':'value2'},
321 macfs
.FSSpec(':').NewAliasMinimal(),
322 aetypes
.Enum('enum'),
323 aetypes
.Type('type'),
324 aetypes
.Keyword('kwrd'),
325 aetypes
.Range(1, 10),
326 aetypes
.Comparison(1, '< ', 10),
327 aetypes
.Logical('not ', 1),
328 # Cannot do StyledText
330 aetypes
.IntlText(0, 0, 'international text'),
331 aetypes
.IntlWritingCode(0,0),
332 aetypes
.QDPoint(50,100),
333 aetypes
.QDRectangle(50,100,150,200),
334 aetypes
.RGBColor(0x7000, 0x6000, 0x5000),
335 aetypes
.Unknown('xxxx', 'unknown type data'),
336 aetypes
.Character(1),
337 aetypes
.Character(2, aetypes
.Line(2)),
340 print 'BEFORE', o
, `o`
342 unpacked
= unpack(packed
)
343 print 'AFTER ', unpacked
, `unpacked`
347 if __name__
== '__main__':