1 # Look for scriptable applications -- that is, applications with an 'aete' resource
2 # Also contains (partially) reverse engineered 'aete' resource decoding
15 redirect(filename
, realmain
)
17 def redirect(filename
, func
, *args
):
18 f
= filename
and open(filename
, 'w')
19 save_stdout
= sys
.stdout
22 return apply(func
, args
)
24 sys
.stdout
= save_stdout
28 #list('C:System Folder:Extensions:AppleScript\252')
29 #list('C:Tao AppleScript:Finder Liaison:Finder Liaison 1.0')
30 list('C:Tao AppleScript:Scriptable Text Editor')
31 #list('C:Internet:Eudora 1.4.2:Eudora1.4.2')
32 #list('E:Excel 4.0:Microsoft Excel')
33 #list('C:Internet:Netscape 1.0N:Netscape 1.0N')
39 def find(dir, maxlevel
= 5):
42 names
= os
.listdir(dir)
43 tuples
= map(lambda x
: (os
.path
.normcase(x
), x
), names
)
45 names
= map(lambda (x
, y
): y
, tuples
)
47 if name
in (os
.curdir
, os
.pardir
): continue
48 fullname
= os
.path
.join(dir, name
)
49 if os
.path
.islink(fullname
):
51 if os
.path
.isdir(fullname
):
53 sys
.stderr
.write(" %s\n" % `fullname`
)
54 hits
= hits
+ find(fullname
, maxlevel
-1)
56 ctor
, type = MacOS
.GetCreatorAndType(fullname
)
57 if type in ('APPL', 'FNDR', 'zsys', 'INIT', 'scri', 'cdev'):
58 sys
.stderr
.write(" %s\n" % `fullname`
)
60 rf
= OpenRFPerm(fullname
, 0, '\1')
61 except MacOS
.Error
, msg
:
62 print "Error:", fullname
, msg
65 n
= Count1Resources('aete')
71 sys
.stderr
.write("YES! %d in %s\n" % (n
, `fullname`
))
77 rf
= OpenRFPerm(fullname
, 0, '\1')
81 for i
in range(Count1Resources('aete')):
82 res
= Get1IndResource('aete', 1+i
)
84 for i
in range(Count1Resources('aeut')):
85 res
= Get1IndResource('aeut', 1+i
)
87 print "\nLISTING aete+aeut RESOURCES IN", `fullname`
89 print "decoding", res
.GetResInfo(), "..."
94 print "Checking putaete..."
95 f
= StringIO
.StringIO()
97 newdata
= f
.getvalue()
98 if len(newdata
) == len(data
):
100 print "putaete created identical data"
102 newaete
= decode(newdata
)
104 print "putaete created equivalent data"
106 print "putaete failed the test:"
109 print "putaete created different data:"
113 traceback
.print_exc()
121 f
= StringIO
.StringIO(data
)
122 aete
= generic(getaete
, f
)
123 aete
= simplify(aete
)
125 unprocessed
= len(f
.read())
128 sys
.stderr
.write("%d processed + %d unprocessed = %d total\n" %
129 (processed
, unprocessed
, total
))
133 if type(item
) is types
.ListType
:
134 return map(simplify
, item
)
135 elif type(item
) == types
.TupleType
and len(item
) == 2:
136 return simplify(item
[1])
141 # Here follows the aete resource decoder.
142 # It is presented bottom-up instead of top-down because there are direct
143 # references to the lower-level part-decoders from the high-level part-decoders.
145 def getbyte(f
, *args
):
148 raise EOFError, 'in getbyte' + str(args
)
151 def getword(f
, *args
):
155 raise EOFError, 'in getword' + str(args
)
156 return (ord(s
[0])<<8) |
ord(s
[1])
158 def getlong(f
, *args
):
162 raise EOFError, 'in getlong' + str(args
)
163 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
165 def getostype(f
, *args
):
169 raise EOFError, 'in getostype' + str(args
)
172 def getpstr(f
, *args
):
175 raise EOFError, 'in getpstr[1]' + str(args
)
177 if nbytes
== 0: return ''
180 raise EOFError, 'in getpstr[2]' + str(args
)
187 ## print 'align:', `c`
189 def getlist(f
, description
, getitem
):
192 for i
in range(count
):
193 list.append(generic(getitem
, f
))
197 def alt_generic(what
, f
, *args
):
198 print "generic", `what`
, args
199 res
= vageneric(what
, f
, args
)
203 def generic(what
, f
, *args
):
204 if type(what
) == types
.FunctionType
:
205 return apply(what
, (f
,) + args
)
206 if type(what
) == types
.ListType
:
209 item
= apply(generic
, thing
[:1] + (f
,) + thing
[1:])
210 record
.append((thing
[1], item
))
212 return "BAD GENERIC ARGS: %s" % `what`
216 (getpstr
, "description"),
221 (getostype
, "keyword"),
226 (getpstr
, "description"),
227 (getostype
, "suite code"),
228 (getostype
, "event code"),
229 (getdata
, "returns"),
230 (getdata
, "accepts"),
231 (getlist
, "optional arguments", getargument
)
240 (getlist
, "keyform", getostype
)
244 (getostype
, "class code"),
245 (getpstr
, "description"),
246 (getlist
, "properties", getproperty
),
247 (getlist
, "elements", getelement
)
250 (getpstr
, "operator name"),
251 (getostype
, "operator ID"),
252 (getpstr
, "operator comment"),
255 (getpstr
, "enumerator name"),
256 (getostype
, "enumerator ID"),
257 (getpstr
, "enumerator comment")
260 (getostype
, "enumeration ID"),
261 (getlist
, "enumerator", getenumerator
)
264 (getpstr
, "suite name"),
265 (getpstr
, "suite description"),
266 (getostype
, "suite ID"),
267 (getword
, "suite level"),
268 (getword
, "suite version"),
269 (getlist
, "events", getevent
),
270 (getlist
, "classes", getclass
),
271 (getlist
, "comparisons", getcomparison
),
272 (getlist
, "enumerations", getenumeration
)
275 (getword
, "major/minor version in BCD"),
276 (getword
, "language code"),
277 (getword
, "script code"),
278 (getlist
, "suites", getsuite
)
282 # Display 'aete' resources in a friendly manner.
283 # This one's done top-down again...
286 [version
, language
, script
, suites
] = aete
287 major
, minor
= divmod(version
, 256)
288 print "\nVersion %d/%d, language %d, script %d" % \
289 (major
, minor
, language
, script
)
293 def showsuite(suite
):
294 [name
, desc
, code
, level
, version
, events
, classes
, comps
, enums
] = suite
295 print "\nSuite %s -- %s (%s)" % (`name`
, `desc`
, `code`
)
296 print "Level %d, version %d" % (level
, version
)
304 showenumeration(enum
)
306 def showevent(event
):
307 [name
, desc
, code
, subcode
, returns
, accepts
, arguments
] = event
308 print "\n Command %s -- %s (%s, %s)" % (`name`
, `desc`
, `code`
, `subcode`
)
309 print " returns", showdata(returns
)
310 print " accepts", showdata(accepts
)
311 for arg
in arguments
:
314 def showargument(arg
):
315 [name
, keyword
, what
] = arg
316 print " %s (%s)" % (name
, `keyword`
), showdata(what
)
319 [name
, code
, desc
, properties
, elements
] = cls
320 print "\n Class %s (%s) -- %s" % (`name`
, `code`
, `desc`
)
321 for prop
in properties
:
323 for elem
in elements
:
326 def showproperty(prop
):
327 [name
, code
, what
] = prop
328 print " property %s (%s)" % (`name`
, `code`
), showdata(what
)
330 def showelement(elem
):
331 [code
, keyform
] = elem
332 print " element %s" % `code`
, "as", keyform
334 def showcomparison(comp
):
335 [name
, code
, comment
] = comp
336 print " comparison %s (%s) -- %s" % (`name`
, `code`
, comment
)
338 def showenumeration(enum
):
340 print "\n Enum %s" % `code`
344 def showenumerator(item
):
345 [name
, code
, desc
] = item
346 print " %s (%s) -- %s" % (`name`
, `code`
, `desc`
)
349 [type, description
, flags
] = data
350 return "%s -- %s %s" % (`
type`
, `description`
, showdataflags(flags
))
352 dataflagdict
= {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
353 def showdataflags(flags
):
357 if i
in dataflagdict
.keys():
358 bits
.append(dataflagdict
[i
])
361 return '[%s]' % string
.join(bits
)
364 # Write an 'aete' resource.
365 # Closedly modelled after showaete()...
367 def putaete(f
, aete
):
368 [version
, language
, script
, suites
] = aete
372 putlist(f
, suites
, putsuite
)
374 def putsuite(f
, suite
):
375 [name
, desc
, code
, level
, version
, events
, classes
, comps
, enums
] = suite
381 putlist(f
, events
, putevent
)
382 putlist(f
, classes
, putclass
)
383 putlist(f
, comps
, putcomparison
)
384 putlist(f
, enums
, putenumeration
)
386 def putevent(f
, event
):
387 [name
, desc
, eventclass
, eventid
, returns
, accepts
, arguments
] = event
390 putostype(f
, eventclass
)
391 putostype(f
, eventid
)
394 putlist(f
, arguments
, putargument
)
396 def putargument(f
, arg
):
397 [name
, keyword
, what
] = arg
399 putostype(f
, keyword
)
402 def putclass(f
, cls
):
403 [name
, code
, desc
, properties
, elements
] = cls
407 putlist(f
, properties
, putproperty
)
408 putlist(f
, elements
, putelement
)
410 putproperty
= putargument
412 def putelement(f
, elem
):
415 putlist(f
, parts
, putostype
)
417 def putcomparison(f
, comp
):
418 [name
, id, comment
] = comp
423 def putenumeration(f
, enum
):
426 putlist(f
, items
, putenumerator
)
428 def putenumerator(f
, item
):
429 [name
, code
, desc
] = item
434 def putdata(f
, data
):
435 [type, description
, flags
] = data
437 putpstr(f
, description
)
440 def putlist(f
, list, putitem
):
441 putword(f
, len(list))
450 def putbyte(f
, value
):
453 def putword(f
, value
):
455 f
.write(chr((value
>>8)&0xff))
456 f
.write(chr(value
&0xff))
458 def putostype(f
, value
):
460 if type(value
) != types
.StringType
or len(value
) != 4:
461 raise TypeError, "ostype must be 4-char string"
464 def putpstr(f
, value
):
465 if type(value
) != types
.StringType
or len(value
) > 255:
466 raise TypeError, "pstr must be string <= 255 chars"
467 f
.write(chr(len(value
)) + value
)
470 # Call the main program
472 if __name__
== '__main__':