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]
167 if t
== typeMagnitude
:
168 v
= struct
.unpack('l', desc
.data
)
172 if t
== typeObjectSpecifier
:
173 record
= desc
.AECoerceDesc('reco')
174 return mkobject(unpack(record
))
175 # typePict returned as unknown
176 # typePixelMap coerced to typeAERecord
177 # typePixelMapMinus returned as unknown
178 # typeProcessSerialNumber returned as unknown
180 v
, h
= struct
.unpack('hh', desc
.data
)
181 return aetypes
.QDPoint(v
, h
)
182 if t
== typeQDRectangle
:
183 v0
, h0
, v1
, h1
= struct
.unpack('hhhh', desc
.data
)
184 return aetypes
.QDRectangle(v0
, h0
, v1
, h1
)
185 if t
== typeRGBColor
:
186 r
, g
, b
= struct
.unpack('hhh', desc
.data
)
187 return aetypes
.RGBColor(r
, g
, b
)
188 # typeRotation coerced to typeAERecord
189 # typeScrapStyles returned as unknown
190 # typeSessionID returned as unknown
191 if t
== typeShortFloat
:
192 return struct
.unpack('f', desc
.data
)[0]
193 if t
== typeShortInteger
:
194 return struct
.unpack('h', desc
.data
)[0]
195 # typeSMFloat identical to typeShortFloat
196 # typeSMInt indetical to typeShortInt
197 # typeStyledText coerced to typeAERecord
198 if t
== typeTargetID
:
199 return mktargetid(desc
.data
)
200 # typeTextStyles coerced to typeAERecord
201 # typeTIFF returned as unknown
205 return mktype(desc
.data
)
207 # The following are special
210 record
= desc
.AECoerceDesc('reco')
211 return mkrange(unpack(record
))
213 record
= desc
.AECoerceDesc('reco')
214 return mkcomparison(unpack(record
))
216 record
= desc
.AECoerceDesc('reco')
217 return mklogical(unpack(record
))
218 return mkunknown(desc
.type, desc
.data
)
220 def coerce(data
, egdata
):
221 """Coerce a python object to another type using the AE coercers"""
223 pegdata
= pack(egdata
)
224 pdata
= pdata
.AECoerceDesc(pegdata
.type)
228 # Helper routines for unpack
230 def mktargetid(data
):
231 sessionID
= getlong(data
[:4])
232 name
= mkppcportrec(data
[4:4+72])
233 location
= mklocationnamerec(data
[76:76+36])
234 rcvrName
= mkppcportrec(data
[112:112+72])
235 return sessionID
, name
, location
, rcvrName
237 def mkppcportrec(rec
):
238 namescript
= getword(rec
[:2])
239 name
= getpstr(rec
[2:2+33])
240 portkind
= getword(rec
[36:38])
244 identity
= (ctor
, type)
246 identity
= getpstr(rec
[38:38+33])
247 return namescript
, name
, portkind
, identity
249 def mklocationnamerec(rec
):
250 kind
= getword(rec
[:2])
252 if kind
== 0: stuff
= None
253 if kind
== 2: stuff
= getpstr(stuff
)
256 def mkunknown(type, data
):
257 return aetypes
.Unknown(type, data
)
260 return s
[1:1+ord(s
[0])]
263 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
266 return (ord(s
[0])<<8) |
(ord(s
[1])<<0)
268 def mkkeyword(keyword
):
269 return aetypes
.Keyword(keyword
)
272 return aetypes
.Range(dict['star'], dict['stop'])
274 def mkcomparison(dict):
275 return aetypes
.Comparison(dict['obj1'], dict['relo'].enum
, dict['obj2'])
278 return aetypes
.Logical(dict['logc'], dict['term'])
280 def mkstyledtext(dict):
281 return aetypes
.StyledText(dict['ksty'], dict['ktxt'])
284 return aetypes
.AEText(dict[keyAEScriptTag
], dict[keyAEStyles
], dict[keyAEText
])
286 def mkinsertionloc(dict):
287 return aetypes
.InsertionLoc(dict[keyAEObject
], dict[keyAEPosition
])
290 want
= dict['want'].type
291 form
= dict['form'].enum
294 if form
in ('name', 'indx', 'rang', 'test'):
295 if want
== 'text': return aetypes
.Text(seld
, fr
)
296 if want
== 'cha ': return aetypes
.Character(seld
, fr
)
297 if want
== 'cwor': return aetypes
.Word(seld
, fr
)
298 if want
== 'clin': return aetypes
.Line(seld
, fr
)
299 if want
== 'cpar': return aetypes
.Paragraph(seld
, fr
)
300 if want
== 'cwin': return aetypes
.Window(seld
, fr
)
301 if want
== 'docu': return aetypes
.Document(seld
, fr
)
302 if want
== 'file': return aetypes
.File(seld
, fr
)
303 if want
== 'cins': return aetypes
.InsertionPoint(seld
, fr
)
304 if want
== 'prop' and form
== 'prop' and aetypes
.IsType(seld
):
305 return aetypes
.Property(seld
.type, fr
)
306 return aetypes
.ObjectSpecifier(want
, form
, seld
, fr
)
309 """Test program. Pack and unpack various things"""
315 ['a', 'list', 'of', 'strings'],
316 {'key1': 'value1', 'key2':'value2'},
318 macfs
.FSSpec(':').NewAliasMinimal(),
319 aetypes
.Enum('enum'),
320 aetypes
.Type('type'),
321 aetypes
.Keyword('kwrd'),
322 aetypes
.Range(1, 10),
323 aetypes
.Comparison(1, '< ', 10),
324 aetypes
.Logical('not ', 1),
325 # Cannot do StyledText
327 aetypes
.IntlText(0, 0, 'international text'),
328 aetypes
.IntlWritingCode(0,0),
329 aetypes
.QDPoint(50,100),
330 aetypes
.QDRectangle(50,100,150,200),
331 aetypes
.RGBColor(0x7000, 0x6000, 0x5000),
332 aetypes
.Unknown('xxxx', 'unknown type data'),
333 aetypes
.Character(1),
334 aetypes
.Character(2, aetypes
.Line(2)),
337 print 'BEFORE', o
, `o`
339 unpacked
= unpack(packed
)
340 print 'AFTER ', unpacked
, `unpacked`
344 if __name__
== '__main__':