Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame^] | 1 | import struct |
| 2 | import types |
| 3 | import AE |
| 4 | import MacOS |
| 5 | import StringIO |
| 6 | |
| 7 | AEDescType = type(AE.AECreateDesc('TEXT', '')) |
| 8 | |
| 9 | def pack(x): |
| 10 | if x == None: |
| 11 | return AE.AECreateDesc('null', '') |
| 12 | t = type(x) |
| 13 | if t == AEDescType: |
| 14 | return x |
| 15 | if t == types.IntType: |
| 16 | return AE.AECreateDesc('long', struct.pack('l', x)) |
| 17 | if t == types.FloatType: |
| 18 | return AE.AECreateDesc('exte', struct.pack('d', x)[2:]) |
| 19 | if t == types.StringType: |
| 20 | return AE.AECreateDesc('TEXT', x) |
| 21 | if t == types.ListType: |
| 22 | list = AE.AECreateList('', 0) |
| 23 | for item in x: |
| 24 | list.AEPutDesc(0, pack(item)) |
| 25 | return list |
| 26 | if t == types.TupleType: |
| 27 | t, d = x |
| 28 | return AE.AECreateDesc(t, d) |
| 29 | if t == types.DictionaryType: |
| 30 | record = AE.AECreateList('', 1) |
| 31 | for key, value in x.items(): |
| 32 | record.AEPutKeyDesc(key, pack(value)) |
| 33 | if t == types.InstanceType and hasattr(x, '__aepack__'): |
| 34 | return x.__aepack__() |
| 35 | return AE.AECreateDesc('TEXT', repr(x)) # Copout |
| 36 | |
| 37 | def unpack(desc): |
| 38 | t = desc.type |
| 39 | if t == 'TEXT': |
| 40 | return desc.data |
| 41 | if t == 'fals': |
| 42 | return 0 |
| 43 | if t == 'true': |
| 44 | return 1 |
| 45 | if t == 'long': |
| 46 | return struct.unpack('l', desc.data)[0] |
| 47 | if t == 'shor': |
| 48 | return struct.unpack('h', desc.data)[0] |
| 49 | if t == 'sing': |
| 50 | return struct.unpack('f', desc.data)[0] |
| 51 | if t == 'exte': |
| 52 | data = desc.data |
| 53 | return struct.unpack('d', data[:2] + data)[0] |
| 54 | if t in ('doub', 'comp', 'magn'): |
| 55 | return unpack(desc.AECoerceDesc('exte')) |
| 56 | if t == 'enum': |
| 57 | return ('enum', desc.data) |
| 58 | if t == 'null': |
| 59 | return None |
| 60 | if t == 'list': |
| 61 | l = [] |
| 62 | for i in range(desc.AECountItems()): |
| 63 | keyword, item = desc.AEGetNthDesc(i+1, '****') |
| 64 | l.append(unpack(item)) |
| 65 | return l |
| 66 | if t == 'reco': |
| 67 | d = {} |
| 68 | for i in range(desc.AECountItems()): |
| 69 | keyword, item = desc.AEGetNthDesc(i+1, '****') |
| 70 | d[keyword] = unpack(item) |
| 71 | return d |
| 72 | if t == 'obj ': |
| 73 | return unpackobject(desc.data) |
| 74 | return desc.type, desc.data # Copout |
| 75 | |
| 76 | class Object: |
| 77 | def __init__(self, dict = {}): |
| 78 | self.dict = dict |
| 79 | for key, value in dict.items(): |
| 80 | self.dict[key] = value |
| 81 | def __repr__(self): |
| 82 | return "Object(%s)" % `self.dict` |
| 83 | def __str__(self): |
| 84 | want = self.dict['want'] |
| 85 | form = self.dict['form'] |
| 86 | seld = self.dict['seld'] |
| 87 | s = "%s %s %s" % (nicewant(want), niceform(form), niceseld(seld)) |
| 88 | fr = self.dict['from'] |
| 89 | if fr: |
| 90 | s = s + " of " + str(fr) |
| 91 | return s |
| 92 | def __aepack__(self): |
| 93 | f = StringIO.StringIO() |
| 94 | putlong(f, len(self.dict)) |
| 95 | putlong(f, 0) |
| 96 | for key, value in self.dict.items(): |
| 97 | putcode(f, key) |
| 98 | desc = pack(value) |
| 99 | putcode(f, desc.type) |
| 100 | data = desc.data |
| 101 | putlong(f, len(data)) |
| 102 | f.write(data) |
| 103 | return AE.AECreateDesc('obj ', f.getvalue()) |
| 104 | |
| 105 | def nicewant(want): |
| 106 | if type(want) == types.TupleType and len(want) == 2: |
| 107 | return reallynicewant(want) |
| 108 | else: |
| 109 | return `want` |
| 110 | |
| 111 | def reallynicewant((t, w)): |
| 112 | if t != 'type': return `t, w` |
| 113 | # These should be taken from the "elements" of the 'aete' resource |
| 114 | if w == 'cins': return 'insertion point' |
| 115 | if w == 'cha ': return 'character' |
| 116 | if w == 'word': return 'word' |
| 117 | if w == 'para': return 'paragraph' |
| 118 | if w == 'ccel': return 'cell' |
| 119 | if w == 'ccol': return 'column' |
| 120 | if w == 'crow': return 'row' |
| 121 | if w == 'crng': return 'range' |
| 122 | if w == 'wind': return 'window' |
| 123 | if w == 'docu': return 'document' |
| 124 | return `w` |
| 125 | |
| 126 | def niceform(form): |
| 127 | if type(form) == types.TupleType and len(form) == 2: |
| 128 | return reallyniceform(form) |
| 129 | else: |
| 130 | return `form` |
| 131 | |
| 132 | def reallyniceform((t, f)): |
| 133 | if t <> 'enum': return `t, f` |
| 134 | if f == 'indx': return '' |
| 135 | if f == 'name': return '' |
| 136 | if f == 'rele': return '' |
| 137 | return `f` |
| 138 | |
| 139 | def niceseld(seld): |
| 140 | if type(seld) == types.TupleType and len(seld) == 2: |
| 141 | return reallyniceseld(seld) |
| 142 | else: |
| 143 | return `seld` |
| 144 | |
| 145 | def reallyniceseld((t, s)): |
| 146 | if t == 'long': return `s` |
| 147 | if t == 'TEXT': return `s` |
| 148 | if t == 'enum': |
| 149 | if s == 'next': return 'after' |
| 150 | if s == 'prev': return 'before' |
| 151 | return `t, s` |
| 152 | |
| 153 | def unpackobject(data): |
| 154 | f = StringIO.StringIO(data) |
| 155 | nkey = getlong(f) |
| 156 | dumm = getlong(f) |
| 157 | dict = {} |
| 158 | for i in range(nkey): |
| 159 | keyw = getcode(f) |
| 160 | type = getcode(f) |
| 161 | size = getlong(f) |
| 162 | if size: |
| 163 | data = f.read(size) |
| 164 | else: |
| 165 | data = '' |
| 166 | desc = AE.AECreateDesc(type, data) |
| 167 | dict[keyw] = unpack(desc) |
| 168 | return Object(dict) |
| 169 | |
| 170 | |
| 171 | # --- get various data types from a "file" |
| 172 | |
| 173 | def getword(f, *args): |
| 174 | getalgn(f) |
| 175 | s = f.read(2) |
| 176 | if len(s) < 2: |
| 177 | raise EOFError, 'in getword' + str(args) |
| 178 | return (ord(s[0])<<8) | ord(s[1]) |
| 179 | |
| 180 | def getlong(f, *args): |
| 181 | getalgn(f) |
| 182 | s = f.read(4) |
| 183 | if len(s) < 4: |
| 184 | raise EOFError, 'in getlong' + str(args) |
| 185 | return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3]) |
| 186 | |
| 187 | def getcode(f, *args): |
| 188 | getalgn(f) |
| 189 | s = f.read(4) |
| 190 | if len(s) < 4: |
| 191 | raise EOFError, 'in getcode' + str(args) |
| 192 | return s |
| 193 | |
| 194 | def getpstr(f, *args): |
| 195 | c = f.read(1) |
| 196 | if len(c) < 1: |
| 197 | raise EOFError, 'in getpstr[1]' + str(args) |
| 198 | nbytes = ord(c) |
| 199 | if nbytes == 0: return '' |
| 200 | s = f.read(nbytes) |
| 201 | if len(s) < nbytes: |
| 202 | raise EOFError, 'in getpstr[2]' + str(args) |
| 203 | return s |
| 204 | |
| 205 | def getalgn(f): |
| 206 | if f.tell() & 1: |
| 207 | c = f.read(1) |
| 208 | ##if c <> '\0': |
| 209 | ## print 'align:', `c` |
| 210 | |
| 211 | # ---- end get routines |
| 212 | |
| 213 | |
| 214 | # ---- put various data types to a "file" |
| 215 | |
| 216 | def putlong(f, value): |
| 217 | putalgn(f) |
| 218 | f.write(chr((value>>24)&0xff)) |
| 219 | f.write(chr((value>>16)&0xff)) |
| 220 | f.write(chr((value>>8)&0xff)) |
| 221 | f.write(chr(value&0xff)) |
| 222 | |
| 223 | def putword(f, value): |
| 224 | putalgn(f) |
| 225 | f.write(chr((value>>8)&0xff)) |
| 226 | f.write(chr(value&0xff)) |
| 227 | |
| 228 | def putcode(f, value): |
| 229 | if type(value) != types.StringType or len(value) != 4: |
| 230 | raise TypeError, "ostype must be 4-char string" |
| 231 | putalgn(f) |
| 232 | f.write(value) |
| 233 | |
| 234 | def putpstr(f, value): |
| 235 | if type(value) != types.StringType or len(value) > 255: |
| 236 | raise TypeError, "pstr must be string <= 255 chars" |
| 237 | f.write(chr(len(value)) + value) |
| 238 | |
| 239 | def putalgn(f): |
| 240 | if f.tell() & 1: |
| 241 | f.write('\0') |
| 242 | |
| 243 | # ---- end put routines |
| 244 | |
| 245 | |
| 246 | aekeywords = [ |
| 247 | 'tran', |
| 248 | 'rtid', |
| 249 | 'evcl', |
| 250 | 'evid', |
| 251 | 'addr', |
| 252 | 'optk', |
| 253 | 'timo', |
| 254 | 'inte', # this attribute is read only - will be set in AESend |
| 255 | 'esrc', # this attribute is read only |
| 256 | 'miss', # this attribute is read only |
| 257 | 'from' # new in 1.0.1 |
| 258 | ] |
| 259 | |
| 260 | def missed(ae): |
| 261 | try: |
| 262 | desc = ae.AEGetAttributeDesc('miss', 'keyw') |
| 263 | except AE.Error, msg: |
| 264 | return None |
| 265 | return desc.data |
| 266 | |
| 267 | def unpackevent(ae): |
| 268 | parameters = {} |
| 269 | while 1: |
| 270 | key = missed(ae) |
| 271 | if not key: break |
| 272 | parameters[key] = unpack(ae.AEGetParamDesc(key, '****')) |
| 273 | attributes = {} |
| 274 | for key in aekeywords: |
| 275 | try: |
| 276 | desc = ae.AEGetAttributeDesc(key, '****') |
| 277 | except (AE.Error, MacOS.Error), msg: |
| 278 | if msg[0] != -1701: |
| 279 | raise sys.exc_type, sys.exc_value |
| 280 | continue |
| 281 | attributes[key] = unpack(desc) |
| 282 | return parameters, attributes |
| 283 | |
| 284 | def packevent(ae, parameters = {}, attributes = {}): |
| 285 | for key, value in parameters.items(): |
| 286 | ae.AEPutParamDesc(key, pack(value)) |
| 287 | for key, value in attributes.items(): |
| 288 | ae.AEPutAttributeDesc(key, pack(value)) |
| 289 | |
| 290 | def test(): |
| 291 | target = AE.AECreateDesc('sign', 'KAHL') |
| 292 | ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0) |
| 293 | print unpackevent(ae) |
| 294 | |
| 295 | if __name__ == '__main__': |
| 296 | test() |