| import struct |
| import types |
| import AE |
| import MacOS |
| import StringIO |
| |
| AEDescType = type(AE.AECreateDesc('TEXT', '')) |
| |
| def pack(x): |
| if x == None: |
| return AE.AECreateDesc('null', '') |
| t = type(x) |
| if t == AEDescType: |
| return x |
| if t == types.IntType: |
| return AE.AECreateDesc('long', struct.pack('l', x)) |
| if t == types.FloatType: |
| return AE.AECreateDesc('exte', struct.pack('d', x)[2:]) |
| if t == types.StringType: |
| return AE.AECreateDesc('TEXT', x) |
| if t == types.ListType: |
| list = AE.AECreateList('', 0) |
| for item in x: |
| list.AEPutDesc(0, pack(item)) |
| return list |
| if t == types.TupleType: |
| t, d = x |
| return AE.AECreateDesc(t, d) |
| if t == types.DictionaryType: |
| record = AE.AECreateList('', 1) |
| for key, value in x.items(): |
| record.AEPutKeyDesc(key, pack(value)) |
| if t == types.InstanceType and hasattr(x, '__aepack__'): |
| return x.__aepack__() |
| return AE.AECreateDesc('TEXT', repr(x)) # Copout |
| |
| def unpack(desc): |
| t = desc.type |
| if t == 'TEXT': |
| return desc.data |
| if t == 'fals': |
| return 0 |
| if t == 'true': |
| return 1 |
| if t == 'long': |
| return struct.unpack('l', desc.data)[0] |
| if t == 'shor': |
| return struct.unpack('h', desc.data)[0] |
| if t == 'sing': |
| return struct.unpack('f', desc.data)[0] |
| if t == 'exte': |
| data = desc.data |
| return struct.unpack('d', data[:2] + data)[0] |
| if t in ('doub', 'comp', 'magn'): |
| return unpack(desc.AECoerceDesc('exte')) |
| if t == 'enum': |
| return ('enum', desc.data) |
| if t == 'null': |
| return None |
| if t == 'list': |
| l = [] |
| for i in range(desc.AECountItems()): |
| keyword, item = desc.AEGetNthDesc(i+1, '****') |
| l.append(unpack(item)) |
| return l |
| if t == 'reco': |
| d = {} |
| for i in range(desc.AECountItems()): |
| keyword, item = desc.AEGetNthDesc(i+1, '****') |
| d[keyword] = unpack(item) |
| return d |
| if t == 'obj ': |
| return unpackobject(desc.data) |
| return desc.type, desc.data # Copout |
| |
| class Object: |
| def __init__(self, dict = {}): |
| self.dict = dict |
| for key, value in dict.items(): |
| self.dict[key] = value |
| def __repr__(self): |
| return "Object(%s)" % `self.dict` |
| def __str__(self): |
| want = self.dict['want'] |
| form = self.dict['form'] |
| seld = self.dict['seld'] |
| s = "%s %s %s" % (nicewant(want), niceform(form), niceseld(seld)) |
| fr = self.dict['from'] |
| if fr: |
| s = s + " of " + str(fr) |
| return s |
| def __aepack__(self): |
| f = StringIO.StringIO() |
| putlong(f, len(self.dict)) |
| putlong(f, 0) |
| for key, value in self.dict.items(): |
| putcode(f, key) |
| desc = pack(value) |
| putcode(f, desc.type) |
| data = desc.data |
| putlong(f, len(data)) |
| f.write(data) |
| return AE.AECreateDesc('obj ', f.getvalue()) |
| |
| def nicewant(want): |
| if type(want) == types.TupleType and len(want) == 2: |
| return reallynicewant(want) |
| else: |
| return `want` |
| |
| def reallynicewant((t, w)): |
| if t != 'type': return `t, w` |
| # These should be taken from the "elements" of the 'aete' resource |
| if w == 'cins': return 'insertion point' |
| if w == 'cha ': return 'character' |
| if w == 'word': return 'word' |
| if w == 'para': return 'paragraph' |
| if w == 'ccel': return 'cell' |
| if w == 'ccol': return 'column' |
| if w == 'crow': return 'row' |
| if w == 'crng': return 'range' |
| if w == 'wind': return 'window' |
| if w == 'docu': return 'document' |
| return `w` |
| |
| def niceform(form): |
| if type(form) == types.TupleType and len(form) == 2: |
| return reallyniceform(form) |
| else: |
| return `form` |
| |
| def reallyniceform((t, f)): |
| if t <> 'enum': return `t, f` |
| if f == 'indx': return '' |
| if f == 'name': return '' |
| if f == 'rele': return '' |
| return `f` |
| |
| def niceseld(seld): |
| if type(seld) == types.TupleType and len(seld) == 2: |
| return reallyniceseld(seld) |
| else: |
| return `seld` |
| |
| def reallyniceseld((t, s)): |
| if t == 'long': return `s` |
| if t == 'TEXT': return `s` |
| if t == 'enum': |
| if s == 'next': return 'after' |
| if s == 'prev': return 'before' |
| return `t, s` |
| |
| def unpackobject(data): |
| f = StringIO.StringIO(data) |
| nkey = getlong(f) |
| dumm = getlong(f) |
| dict = {} |
| for i in range(nkey): |
| keyw = getcode(f) |
| type = getcode(f) |
| size = getlong(f) |
| if size: |
| data = f.read(size) |
| else: |
| data = '' |
| desc = AE.AECreateDesc(type, data) |
| dict[keyw] = unpack(desc) |
| return Object(dict) |
| |
| |
| # --- get various data types from a "file" |
| |
| def getword(f, *args): |
| getalgn(f) |
| s = f.read(2) |
| if len(s) < 2: |
| raise EOFError, 'in getword' + str(args) |
| return (ord(s[0])<<8) | ord(s[1]) |
| |
| def getlong(f, *args): |
| getalgn(f) |
| s = f.read(4) |
| if len(s) < 4: |
| raise EOFError, 'in getlong' + str(args) |
| return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3]) |
| |
| def getcode(f, *args): |
| getalgn(f) |
| s = f.read(4) |
| if len(s) < 4: |
| raise EOFError, 'in getcode' + str(args) |
| return s |
| |
| def getpstr(f, *args): |
| c = f.read(1) |
| if len(c) < 1: |
| raise EOFError, 'in getpstr[1]' + str(args) |
| nbytes = ord(c) |
| if nbytes == 0: return '' |
| s = f.read(nbytes) |
| if len(s) < nbytes: |
| raise EOFError, 'in getpstr[2]' + str(args) |
| return s |
| |
| def getalgn(f): |
| if f.tell() & 1: |
| c = f.read(1) |
| ##if c <> '\0': |
| ## print 'align:', `c` |
| |
| # ---- end get routines |
| |
| |
| # ---- put various data types to a "file" |
| |
| def putlong(f, value): |
| putalgn(f) |
| f.write(chr((value>>24)&0xff)) |
| f.write(chr((value>>16)&0xff)) |
| f.write(chr((value>>8)&0xff)) |
| f.write(chr(value&0xff)) |
| |
| def putword(f, value): |
| putalgn(f) |
| f.write(chr((value>>8)&0xff)) |
| f.write(chr(value&0xff)) |
| |
| def putcode(f, value): |
| if type(value) != types.StringType or len(value) != 4: |
| raise TypeError, "ostype must be 4-char string" |
| putalgn(f) |
| f.write(value) |
| |
| def putpstr(f, value): |
| if type(value) != types.StringType or len(value) > 255: |
| raise TypeError, "pstr must be string <= 255 chars" |
| f.write(chr(len(value)) + value) |
| |
| def putalgn(f): |
| if f.tell() & 1: |
| f.write('\0') |
| |
| # ---- end put routines |
| |
| |
| aekeywords = [ |
| 'tran', |
| 'rtid', |
| 'evcl', |
| 'evid', |
| 'addr', |
| 'optk', |
| 'timo', |
| 'inte', # this attribute is read only - will be set in AESend |
| 'esrc', # this attribute is read only |
| 'miss', # this attribute is read only |
| 'from' # new in 1.0.1 |
| ] |
| |
| def missed(ae): |
| try: |
| desc = ae.AEGetAttributeDesc('miss', 'keyw') |
| except AE.Error, msg: |
| return None |
| return desc.data |
| |
| def unpackevent(ae): |
| parameters = {} |
| while 1: |
| key = missed(ae) |
| if not key: break |
| parameters[key] = unpack(ae.AEGetParamDesc(key, '****')) |
| attributes = {} |
| for key in aekeywords: |
| try: |
| desc = ae.AEGetAttributeDesc(key, '****') |
| except (AE.Error, MacOS.Error), msg: |
| if msg[0] != -1701: |
| raise sys.exc_type, sys.exc_value |
| continue |
| attributes[key] = unpack(desc) |
| return parameters, attributes |
| |
| def packevent(ae, parameters = {}, attributes = {}): |
| for key, value in parameters.items(): |
| ae.AEPutParamDesc(key, pack(value)) |
| for key, value in attributes.items(): |
| ae.AEPutAttributeDesc(key, pack(value)) |
| |
| def test(): |
| target = AE.AECreateDesc('sign', 'KAHL') |
| ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0) |
| print unpackevent(ae) |
| |
| if __name__ == '__main__': |
| test() |