summaryrefslogtreecommitdiffstats
path: root/Mac/Lib
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1995-01-30 11:53:55 (GMT)
committerGuido van Rossum <guido@python.org>1995-01-30 11:53:55 (GMT)
commit17448e24081eb713ac00d7bcb681f4f0d8abfcbf (patch)
tree4f9d6768ef326173e1141b1a92af63247a42b13a /Mac/Lib
parent80ffd6683ca7b06ed743c629459b06b07defbfb3 (diff)
downloadcpython-17448e24081eb713ac00d7bcb681f4f0d8abfcbf.zip
cpython-17448e24081eb713ac00d7bcb681f4f0d8abfcbf.tar.gz
cpython-17448e24081eb713ac00d7bcb681f4f0d8abfcbf.tar.bz2
Committed a more or less working version.
Diffstat (limited to 'Mac/Lib')
-rw-r--r--Mac/Lib/Audio_mac.py108
-rw-r--r--Mac/Lib/audiodev.py241
-rw-r--r--Mac/Lib/test/aete.py402
-rw-r--r--Mac/Lib/test/tctl.py17
-rw-r--r--Mac/Lib/test/tdlg.py15
-rw-r--r--Mac/Lib/test/tmenu.py60
-rw-r--r--Mac/Lib/test/tsnd.py18
-rw-r--r--Mac/Lib/test/twin.py9
-rw-r--r--Mac/Lib/toolbox/AppleEvents.py103
-rw-r--r--Mac/Lib/toolbox/Controls.py41
-rw-r--r--Mac/Lib/toolbox/Dialogs.py20
-rw-r--r--Mac/Lib/toolbox/Events.py49
-rw-r--r--Mac/Lib/toolbox/Menus.py12
-rw-r--r--Mac/Lib/toolbox/Resources.py12
-rw-r--r--Mac/Lib/toolbox/Sound.py101
-rw-r--r--Mac/Lib/toolbox/Windows.py41
-rw-r--r--Mac/Lib/toolbox/aetools.py296
17 files changed, 1545 insertions, 0 deletions
diff --git a/Mac/Lib/Audio_mac.py b/Mac/Lib/Audio_mac.py
new file mode 100644
index 0000000..373f16a
--- /dev/null
+++ b/Mac/Lib/Audio_mac.py
@@ -0,0 +1,108 @@
+QSIZE = 100000
+
+class Play_Audio_mac:
+
+ def __init__(self):
+ self._chan = None
+ self._qsize = QSIZE
+ self._outrate = 22254
+ self._sampwidth = 1
+ self._nchannels = 1
+ self._gc = []
+
+ def __del__(self):
+ self.stop()
+
+ def wait(self):
+ import time
+ while self.getfilled():
+ time.sleep(0.1)
+ self._chan = None
+ self._gc = []
+
+ def stop(self, quietNow = 1):
+ ##chan = self._chan
+ self._chan = None
+ ##chan.SndDisposeChannel(1)
+ self._gc = []
+
+ def setoutrate(self, outrate):
+ self._outrate = outrate
+
+ def setsampwidth(self, sampwidth):
+ self._sampwidth = sampwidth
+
+ def setnchannels(self, nchannels):
+ self._nchannels = nchannels
+
+ def writeframes(self, data):
+ import time
+ from Sound import *
+ import struct
+ if not self._chan:
+ import Snd
+ self._chan = Snd.SndNewChannel(5, 0, self._callback)
+ nframes = len(data) / self._nchannels / self._sampwidth
+ if len(data) != nframes * self._nchannels * self._sampwidth:
+ raise ValueError, 'data is not a whole number of frames'
+ while self._gc and \
+ self.getfilled() + nframes > \
+ self._qsize / self._nchannels / self._sampwidth:
+ time.sleep(0.1)
+ if self._sampwidth == 1:
+ import audioop
+ data = audioop.add(data, '\x80'*len(data), 1)
+ h1 = struct.pack('llhhllbbl',
+ id(data)+12,
+ self._nchannels,
+ self._outrate, 0,
+ 0,
+ 0,
+ extSH,
+ 60,
+ nframes)
+ h2 = 22*'\0'
+ h3 = struct.pack('hhlll',
+ self._sampwidth*8,
+ 0,
+ 0,
+ 0,
+ 0)
+ header = h1+h2+h3
+ self._gc.append((header, data))
+ self._chan.SndDoCommand((bufferCmd, 0, header), 0)
+ self._chan.SndDoCommand((callBackCmd, 0, 0), 0)
+
+ def _callback(self, *args):
+ del self._gc[0]
+
+ def getfilled(self):
+ filled = 0
+ for header, data in self._gc:
+ filled = filled + len(data)
+ return filled / self._nchannels / self._sampwidth
+
+ def getfillable(self):
+ return self._qsize - self.getfilled()
+
+ def ulaw2lin(self, data):
+ import audioop
+ return audioop.ulaw2lin(data, 2)
+
+def test(fn = 'f:just samples:just.aif'):
+ import aifc
+ af = aifc.open(fn, 'r')
+ print af.getparams()
+ p = Play_Audio_mac()
+ p.setoutrate(af.getframerate())
+ p.setsampwidth(af.getsampwidth())
+ p.setnchannels(af.getnchannels())
+ BUFSIZ = 10000
+ while 1:
+ data = af.readframes(BUFSIZ)
+ if not data: break
+ p.writeframes(data)
+ p.wait()
+
+if __name__ == '__main__':
+ test()
diff --git a/Mac/Lib/audiodev.py b/Mac/Lib/audiodev.py
new file mode 100644
index 0000000..adfeb96
--- /dev/null
+++ b/Mac/Lib/audiodev.py
@@ -0,0 +1,241 @@
+error = 'audiodev.error'
+
+class Play_Audio_sgi:
+ # Private instance variables
+ access frameratelist, nchannelslist, sampwidthlist, oldparams, \
+ params, config, inited_outrate, inited_width, \
+ inited_nchannels, port, converter, classinited: private
+
+ classinited = 0
+ frameratelist = nchannelslist = sampwidthlist = None
+
+ def initclass(self):
+ import AL
+ Play_Audio_sgi.frameratelist = [
+ (48000, AL.RATE_48000),
+ (44100, AL.RATE_44100),
+ (32000, AL.RATE_32000),
+ (22050, AL.RATE_22050),
+ (16000, AL.RATE_16000),
+ (11025, AL.RATE_11025),
+ ( 8000, AL.RATE_8000),
+ ]
+ Play_Audio_sgi.nchannelslist = [
+ (1, AL.MONO),
+ (2, AL.STEREO),
+ ]
+ Play_Audio_sgi.sampwidthlist = [
+ (1, AL.SAMPLE_8),
+ (2, AL.SAMPLE_16),
+ (3, AL.SAMPLE_24),
+ ]
+ Play_Audio_sgi.classinited = 1
+
+ def __init__(self):
+ import al, AL
+ if not self.classinited:
+ self.initclass()
+ self.oldparams = []
+ self.params = [AL.OUTPUT_RATE, 0]
+ self.config = al.newconfig()
+ self.inited_outrate = 0
+ self.inited_width = 0
+ self.inited_nchannels = 0
+ self.converter = None
+ self.port = None
+ return
+
+ def __del__(self):
+ if self.port:
+ self.stop()
+ if self.oldparams:
+ import al, AL
+ al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
+ self.oldparams = []
+
+ def wait(self):
+ if not self.port:
+ return
+ import time
+ while self.port.getfilled() > 0:
+ time.sleep(0.1)
+ self.stop()
+
+ def stop(self):
+ if self.port:
+ self.port.closeport()
+ self.port = None
+ if self.oldparams:
+ import al, AL
+ al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
+ self.oldparams = []
+
+ def setoutrate(self, rate):
+ for (raw, cooked) in self.frameratelist:
+ if rate == raw:
+ self.params[1] = cooked
+ self.inited_outrate = 1
+ break
+ else:
+ raise error, 'bad output rate'
+
+ def setsampwidth(self, width):
+ for (raw, cooked) in self.sampwidthlist:
+ if width == raw:
+ self.config.setwidth(cooked)
+ self.inited_width = 1
+ break
+ else:
+ if width == 0:
+ import AL
+ self.inited_width = 0
+ self.config.setwidth(AL.SAMPLE_16)
+ self.converter = self.ulaw2lin
+ else:
+ raise error, 'bad sample width'
+
+ def setnchannels(self, nchannels):
+ for (raw, cooked) in self.nchannelslist:
+ if nchannels == raw:
+ self.config.setchannels(cooked)
+ self.inited_nchannels = 1
+ break
+ else:
+ raise error, 'bad # of channels'
+
+ def writeframes(self, data):
+ if not (self.inited_outrate and self.inited_nchannels):
+ raise error, 'params not specified'
+ if not self.port:
+ import al, AL
+ self.port = al.openport('Python', 'w', self.config)
+ self.oldparams = self.params[:]
+ al.getparams(AL.DEFAULT_DEVICE, self.oldparams)
+ al.setparams(AL.DEFAULT_DEVICE, self.params)
+ if self.converter:
+ data = self.converter(data)
+ self.port.writesamps(data)
+
+ def getfilled(self):
+ if self.port:
+ return self.port.getfilled()
+ else:
+ return 0
+
+ def getfillable(self):
+ if self.port:
+ return self.port.getfillable()
+ else:
+ return self.config.getqueuesize()
+
+ # private methods
+ access *: private
+
+ def ulaw2lin(self, data):
+ import audioop
+ return audioop.ulaw2lin(data, 2)
+
+class Play_Audio_sun:
+ access outrate, sampwidth, nchannels, inited_outrate, inited_width, \
+ inited_nchannels, converter: private
+
+ def __init__(self):
+ self.outrate = 0
+ self.sampwidth = 0
+ self.nchannels = 0
+ self.inited_outrate = 0
+ self.inited_width = 0
+ self.inited_nchannels = 0
+ self.converter = None
+ self.port = None
+ return
+
+ def __del__(self):
+ self.stop()
+
+ def setoutrate(self, rate):
+ self.outrate = rate
+ self.inited_outrate = 1
+
+ def setsampwidth(self, width):
+ self.sampwidth = width
+ self.inited_width = 1
+
+ def setnchannels(self, nchannels):
+ self.nchannels = nchannels
+ self.inited_nchannels = 1
+
+ def writeframes(self, data):
+ if not (self.inited_outrate and self.inited_width and self.inited_nchannels):
+ raise error, 'params not specified'
+ if not self.port:
+ import sunaudiodev, SUNAUDIODEV
+ self.port = sunaudiodev.open('w')
+ info = self.port.getinfo()
+ info.o_sample_rate = self.outrate
+ info.o_channels = self.nchannels
+ if self.sampwidth == 0:
+ info.o_precision = 8
+ self.o_encoding = ENCODING_ULAW
+ else:
+ info.o_precision = 8 * self.sampwidth
+ info.o_encoding = SUNAUDIODEV.ENCODING_LINEAR
+ self.port.setinfo(info)
+ if self.converter:
+ data = self.converter(data)
+ self.port.write(data)
+
+ def wait(self):
+ if not self.port:
+ return
+ self.port.drain()
+ self.stop()
+
+ def stop(self):
+ if self.port:
+ self.port.flush()
+ self.port.close()
+ self.port = None
+
+ def getfilled(self):
+ if self.port:
+ return self.port.obufcount()
+ else:
+ return 0
+
+ def getfillable(self):
+ return BUFFERSIZE - self.getfilled()
+
+def AudioDev():
+ try:
+ import al
+ return Play_Audio_sgi()
+ except ImportError:
+ try:
+ import sunaudiodev
+ return Play_Audio_sun()
+ except ImportError:
+ try:
+ import Audio_mac
+ return Audio_mac.Play_Audio_mac()
+ except ImportError:
+ raise error, 'no audio device'
+
+def test(fn = 'f:just samples:just.aif'):
+ import aifc
+ af = aifc.open(fn, 'r')
+ print fn, af.getparams()
+ p = AudioDev()
+ p.setoutrate(af.getframerate())
+ p.setsampwidth(af.getsampwidth())
+ p.setnchannels(af.getnchannels())
+ BUFSIZ = af.getframerate()/af.getsampwidth()/af.getnchannels()
+ while 1:
+ data = af.readframes(BUFSIZ)
+ if not data: break
+ print len(data)
+ p.writeframes(data)
+ p.wait()
+
+if __name__ == '__main__':
+ test()
diff --git a/Mac/Lib/test/aete.py b/Mac/Lib/test/aete.py
new file mode 100644
index 0000000..5a91d89
--- /dev/null
+++ b/Mac/Lib/test/aete.py
@@ -0,0 +1,402 @@
+# Look for scriptable applications -- that is, applications with an 'aete' resource
+# Also contains (partially) reverse engineered 'aete' resource decoding
+
+import MacOS
+import os
+import string
+import sys
+import types
+import StringIO
+
+from Res import *
+
+def main():
+ filename = raw_input("Listing file? (default stdout): ")
+ redirect(filename, realmain)
+
+def redirect(filename, func, *args):
+ f = filename and open(filename, 'w')
+ save_stdout = sys.stdout
+ try:
+ if f: sys.stdout = f
+ return apply(func, args)
+ finally:
+ sys.stdout = save_stdout
+ if f: f.close()
+
+def realmain():
+ #list('C:Tao AppleScript:Finder Liaison:Finder Liaison 1.0')
+ #list('C:Internet:Eudora 1.4.2:Eudora1.4.2')
+ list('E:Excel 4.0:Microsoft Excel')
+ #list('C:Internet:Netscape 1.0N:Netscape 1.0N')
+ #find('C:')
+ #find('D:')
+ #find('E:')
+ #find('F:')
+
+def find(dir, maxlevel = 5):
+ hits = []
+ cur = CurResFile()
+ names = os.listdir(dir)
+ tuples = map(lambda x: (os.path.normcase(x), x), names)
+ tuples.sort()
+ names = map(lambda (x, y): y, tuples)
+ for name in names:
+ if name in (os.curdir, os.pardir): continue
+ fullname = os.path.join(dir, name)
+ if os.path.islink(fullname):
+ pass
+ if os.path.isdir(fullname):
+ if maxlevel > 0:
+ sys.stderr.write(" %s\n" % `fullname`)
+ hits = hits + find(fullname, maxlevel-1)
+ else:
+ ctor, type = MacOS.GetCreatorAndType(fullname)
+ if type == 'APPL':
+ sys.stderr.write(" %s\n" % `fullname`)
+ try:
+ rf = OpenRFPerm(fullname, 0, '\1')
+ except MacOS.Error, msg:
+ print "Error:", fullname, msg
+ continue
+ UseResFile(rf)
+ n = Count1Resources('aete')
+ if rf <> cur:
+ CloseResFile(rf)
+ UseResFile(cur)
+ if n > 1:
+ hits.append(fullname)
+ sys.stderr.write("YES! %d in %s\n" % (n, `fullname`))
+ list(fullname)
+ return hits
+
+def list(fullname):
+ cur = CurResFile()
+ rf = OpenRFPerm(fullname, 0, '\1')
+ try:
+ UseResFile(rf)
+ resources = []
+ for i in range(Count1Resources('aete')):
+ res = Get1IndResource('aete', 1+i)
+ resources.append(res)
+ for i in range(Count1Resources('aeut')):
+ res = Get1IndResource('aeut', 1+i)
+ resources.append(res)
+ print "\nLISTING aete+aeut RESOURCE IN", `fullname`
+ for res in resources:
+ print res.GetResInfo()
+ data = res.data
+ try:
+ aete = decode(data)
+ showaete(aete)
+ f = StringIO.StringIO()
+ putaete(f, aete)
+ newdata = f.getvalue()
+ if len(newdata) == len(data):
+ if newdata == data:
+ print "putaete created identical data"
+ else:
+ newaete = decode(newdata)
+ if newaete == aete:
+ print "putaete created equivalent data"
+ else:
+ print "putaete failed the test:"
+ showaete(newaete)
+ else:
+ print "putaete created different data:"
+ print `newdata`
+ except:
+ import traceback
+ traceback.print_exc()
+ sys.stdout.flush()
+ finally:
+ if rf <> cur:
+ CloseResFile(rf)
+ UseResFile(cur)
+
+def decode(data):
+ f = StringIO.StringIO(data)
+ aete = generic(getaete, f)
+ aete = simplify(aete)
+ processed = f.tell()
+ unprocessed = len(f.read())
+ total = f.tell()
+ if unprocessed:
+ sys.stderr.write("%d processed + %d unprocessed = %d total\n" %
+ (processed, unprocessed, total))
+ return aete
+
+def simplify(item):
+ if type(item) is types.ListType:
+ return map(simplify, item)
+ elif type(item) == types.TupleType and len(item) == 2:
+ return simplify(item[1])
+ else:
+ return item
+
+
+# Here follows the aete resource decoder.
+# It is presented bottom-up instead of top-down because there are direct
+# references to the lower-level part-decoders from the high-level part-decoders.
+
+def getword(f, *args):
+ getalign(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):
+ getalign(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 getostype(f, *args):
+ getalign(f)
+ s = f.read(4)
+ if len(s) < 4:
+ raise EOFError, 'in getostype' + 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 getalign(f):
+ if f.tell() & 1:
+ c = f.read(1)
+ ##if c <> '\0':
+ ## print 'align:', `c`
+
+def getlist(f, description, getitem):
+ count = getword(f)
+ list = []
+ for i in range(count):
+ getalign(f)
+ list.append(generic(getitem, f))
+ return list
+
+def alt_generic(what, f, *args):
+ print "generic", `what`, args
+ res = vageneric(what, f, args)
+ print '->', `res`
+ return res
+
+def generic(what, f, *args):
+ if type(what) == types.FunctionType:
+ return apply(what, (f,) + args)
+ if type(what) == types.ListType:
+ record = []
+ for thing in what:
+ item = apply(generic, thing[:1] + (f,) + thing[1:])
+ record.append((thing[1], item))
+ return record
+ return "BAD GENERIC ARGS: %s" % `what`
+
+getdata = [(getostype, "type"), (getpstr, "description"), (getword, "flags")]
+getoptarg = [(getpstr, "name"), (getostype, "keyword"), (getdata, "what")]
+getcommand = [(getpstr, "name"), (getpstr, "description"),
+ (getostype, "suite code"), (getostype, "command code"),
+ (getdata, "returns"),
+ (getdata, "accepts"),
+ (getlist, "optional arguments", getoptarg)]
+getprop = [(getpstr, "name"), (getostype, "code"), (getdata, "what")]
+getelem = [(getostype, "type"), (getlist, "accessibility", getostype)]
+getclass = [(getpstr, "name"), (getostype, "class code"), (getpstr, "description"),
+ (getlist, "properties", getprop), (getlist, "elements", getelem)]
+getenumitem = [(getpstr, "name"), (getostype, "value"), (getpstr, "description")]
+getenum = [(getostype, "enumtype"), (getlist, "enumitem", getenumitem)]
+getsuite = [(getpstr, "name"), (getpstr, "description"), (getostype, "code"),
+ (getword, "flags1"), (getword, "flags2"),
+ (getlist, "commands", getcommand),
+ (getlist, "classes", getclass),
+ (getword, "count???"), (getlist, "enums", getenum)]
+getaete = [(getword, "skip1"), (getword, "skip2"), (getword, "skip3"),
+ (getlist, "suites", getsuite)]
+
+
+# Display 'aete' resources in a friendly manner.
+# This one's done top-down again...
+
+def showaete(aete):
+ [flags1, flags2, flags3, suites] = aete
+ print "\nGlobal flags: x%x, x%x, x%x\n" % (flags1, flags2, flags3)
+ for suite in suites:
+ showsuite(suite)
+
+def showsuite(suite):
+ [name, desc, code, flags1, flags2, commands, classes, skip1, enums] = suite
+ print "\nSuite %s -- %s (%s)" % (`name`, `desc`, `code`)
+ for command in commands:
+ showcommand(command)
+ for classe in classes:
+ showclass(classe)
+ for enum in enums:
+ showenum(enum)
+
+def showcommand(command):
+ [name, desc, code, subcode, returns, accepts, arguments] = command
+ print "\n Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
+ print " returns", showdata(returns)
+ print " accepts", showdata(accepts)
+ for arg in arguments:
+ showargument(arg)
+
+def showargument(arg):
+ [name, keyword, what] = arg
+ print " %s (%s)" % (name, `keyword`), showdata(what)
+
+def showclass(classe):
+ [name, code, desc, properties, elements] = classe
+ print "\n Class %s (%s) -- %s" % (`name`, `code`, `desc`)
+ for prop in properties:
+ showproperty(prop)
+ for elem in elements:
+ showelement(elem)
+
+def showproperty(prop):
+ [name, code, what] = prop
+ print " property %s (%s)" % (name, code), showdata(what)
+
+def showelement(elem):
+ [code, accessibility] = elem
+ print " element %s" % `code`, "as", accessibility
+
+def showenum(enum):
+ [code, items] = enum
+ print "\n Enum %s" % `code`
+ for item in items:
+ showitem(item)
+
+def showitem(item):
+ [name, code, desc] = item
+ print " %s (%s) -- %s" % (`name`, `code`, `desc`)
+
+def showdata(data):
+ [type, description, flags] = data
+ return "%s -- %s %s" % (`type`, `description`, showdataflags(flags))
+
+dataflagdict = {15: "optional", 14: "list", 13: "enum", 12: "writable"}
+def showdataflags(flags):
+ bits = []
+ for i in range(16):
+ if flags & (1<<i):
+ if i in dataflagdict.keys():
+ bits.append(dataflagdict[i])
+ else:
+ bits.append(`i`)
+ return '[%s]' % string.join(bits)
+
+
+# Write an 'aete' resource.
+# Closedly modelled after showaete()...
+
+def putaete(f, aete):
+ [flags1, flags2, flags3, suites] = aete
+ putword(f, flags1)
+ putword(f, flags2)
+ putword(f, flags3)
+ putlist(f, suites, putsuite)
+
+def putsuite(f, suite):
+ [name, desc, code, flags1, flags2, commands, classes, skip1, enums] = suite
+ putpstr(f, name)
+ putpstr(f, desc)
+ putostype(f, code)
+ putword(f, flags1)
+ putword(f, flags2)
+ putlist(f, commands, putcommand)
+ putlist(f, classes, putclass)
+ putword(f, skip1)
+ putlist(f, enums, putenum)
+
+def putcommand(f, command):
+ [name, desc, code, subcode, returns, accepts, arguments] = command
+ putpstr(f, name)
+ putpstr(f, desc)
+ putostype(f, code)
+ putostype(f, subcode)
+ putdata(f, returns)
+ putdata(f, accepts)
+ putlist(f, arguments, putargument)
+
+def putargument(f, arg):
+ [name, keyword, what] = arg
+ putpstr(f, name)
+ putostype(f, keyword)
+ putdata(f, what)
+
+def putclass(f, classe):
+ [name, code, desc, properties, elements] = classe
+ putpstr(f, name)
+ putostype(f, code)
+ putpstr(f, desc)
+ putlist(f, properties, putproperty)
+ putlist(f, elements, putelement)
+
+putproperty = putargument
+
+def putelement(f, elem):
+ [code, parts] = elem
+ putostype(f, code)
+ putlist(f, parts, putostype)
+
+def putenum(f, enum):
+ [code, items] = enum
+ putostype(f, code)
+ putlist(f, items, putitem)
+
+def putitem(f, item):
+ [name, code, desc] = item
+ putpstr(f, name)
+ putostype(f, code)
+ putpstr(f, desc)
+
+def putdata(f, data):
+ [type, description, flags] = data
+ putostype(f, type)
+ putpstr(f, description)
+ putword(f, flags)
+
+def putlist(f, list, putitem):
+ putword(f, len(list))
+ for item in list:
+ putalign(f)
+ putitem(f, item)
+
+def putalign(f):
+ if f.tell() & 1:
+ f.write('\0')
+
+def putword(f, value):
+ putalign(f)
+ f.write(chr((value>>8)&0xff))
+ f.write(chr(value&0xff))
+
+def putostype(f, value):
+ putalign(f)
+ if type(value) != types.StringType or len(value) != 4:
+ raise TypeError, "ostype must be 4-char string"
+ 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)
+
+
+# Call the main program
+
+if __name__ == '__main__':
+ main()
+else:
+ realmain()
diff --git a/Mac/Lib/test/tctl.py b/Mac/Lib/test/tctl.py
new file mode 100644
index 0000000..862eeb5
--- /dev/null
+++ b/Mac/Lib/test/tctl.py
@@ -0,0 +1,17 @@
+# play with controls
+
+from Dlg import *
+from Ctl import *
+from Win import *
+from Evt import *
+import time
+
+def main():
+ r = (40, 40, 400, 300)
+ w = NewWindow(r, "The Spanish Inquisition", 1, 0, -1, 1, 0x55555555)
+ w.DrawGrowIcon()
+ r = (40, 40, 100, 60)
+ c = NewControl(w, r, "SPAM!", 1, 0, 0, 1, 0, 0)
+
+
+main()
diff --git a/Mac/Lib/test/tdlg.py b/Mac/Lib/test/tdlg.py
new file mode 100644
index 0000000..f234a70
--- /dev/null
+++ b/Mac/Lib/test/tdlg.py
@@ -0,0 +1,15 @@
+# This program requires that a DLOG resource with ID=128 exists.
+# You can make one with ResEdit if necessary.
+
+from Res import *
+from Dlg import *
+
+ires = 128
+
+def filter(*args): print 'filter:', args
+
+d = GetNewDialog(ires, -1)
+while 1:
+ n = ModalDialog(filter)
+ print 'item:', n
+ if n == 1: break
diff --git a/Mac/Lib/test/tmenu.py b/Mac/Lib/test/tmenu.py
new file mode 100644
index 0000000..1b156d7
--- /dev/null
+++ b/Mac/Lib/test/tmenu.py
@@ -0,0 +1,60 @@
+# Create hierarchical menus for some volumes.
+
+import os
+from Menu import *
+
+# Since we can't (yet) list the mounted volumes, here's a list of some:
+my_volumes = ['C:', 'D:', 'E:', 'F:']
+
+def main():
+ global oldbar
+ oldbar = GetMenuBar()
+ ClearMenuBar()
+ makevolmenus(my_volumes)
+ DrawMenuBar()
+
+def reset():
+ oldbar.SetMenuBar()
+ DrawMenuBar()
+
+id = 1
+def nextid():
+ global id
+ nid = id
+ id = id+1
+ return nid
+
+def makevolmenus(volumes):
+ for vol in volumes:
+ makevolmenu(vol)
+
+def makevolmenu(vol):
+ menu = NewMenu(nextid(), vol)
+ adddirectory(menu, vol)
+ menu.InsertMenu(0)
+
+def adddirectory(menu, dir, maxdepth = 1):
+ print "adddirectory:", `dir`, maxdepth
+ files = os.listdir(dir)
+ item = 0
+ for file in files:
+ item = item+1
+ menu.AppendMenu('x') # add a dummy string
+ menu.SetItem(item, file) # set the actual text
+ fullname = os.path.join(dir, file)
+ if os.path.isdir(fullname):
+ menu.SetItem(item, ':' + file + ':') # append colons
+ if maxdepth > 0:
+ id = nextid()
+ submenu = NewMenu(id, fullname)
+ adddirectory(submenu, fullname, maxdepth-1)
+ submenu.InsertMenu(-1)
+ # If the 'Cmd' is 0x1B, then the 'Mark' is the submenu id
+ menu.SetItemMark(item, id)
+ menu.SetItemCmd(item, 0x1B)
+ if not files:
+ menu.AppendMenu(':') # dummy item to make it selectable
+ return menu
+
+if __name__ == '__main__':
+ main()
diff --git a/Mac/Lib/test/tsnd.py b/Mac/Lib/test/tsnd.py
new file mode 100644
index 0000000..ac347cb
--- /dev/null
+++ b/Mac/Lib/test/tsnd.py
@@ -0,0 +1,18 @@
+# Show off SndPlay (and some resource manager functions).
+# Get a list of all 'snd ' resources in the system and play them all.
+
+from Res import *
+from Snd import *
+
+ch = SndNewChannel(0, 0, None)
+print "Channel:", ch
+
+type = 'snd '
+
+for i in range(CountResources(type)):
+ r = GetIndResource(type, i+1)
+ print r.GetResInfo(), r.size
+ if r.GetResInfo()[0] == 1:
+ print "Skipping simple beep"
+ continue
+ ch.SndPlay(r, 0)
diff --git a/Mac/Lib/test/twin.py b/Mac/Lib/test/twin.py
new file mode 100644
index 0000000..0904d32
--- /dev/null
+++ b/Mac/Lib/test/twin.py
@@ -0,0 +1,9 @@
+# Test Win module
+
+from Win import *
+
+r = (40, 40, 400, 300)
+w = NewWindow(r, "Hello world", 1, 0, -1, 1, 0x55555555)
+w.DrawGrowIcon()
+import time
+time.sleep(10)
diff --git a/Mac/Lib/toolbox/AppleEvents.py b/Mac/Lib/toolbox/AppleEvents.py
new file mode 100644
index 0000000..b3780d0
--- /dev/null
+++ b/Mac/Lib/toolbox/AppleEvents.py
@@ -0,0 +1,103 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:AppleEvents.h'
+typeBoolean = 'bool'
+typeChar = 'TEXT'
+typeSMInt = 'shor'
+typeInteger = 'long'
+typeSMFloat = 'sing'
+typeFloat = 'doub'
+typeLongInteger = 'long'
+typeShortInteger = 'shor'
+typeLongFloat = 'doub'
+typeShortFloat = 'sing'
+typeExtended = 'exte'
+typeComp = 'comp'
+typeMagnitude = 'magn'
+typeAEList = 'list'
+typeAERecord = 'reco'
+typeAppleEvent = 'aevt'
+typeTrue = 'true'
+typeFalse = 'fals'
+typeAlias = 'alis'
+typeEnumerated = 'enum'
+typeType = 'type'
+typeAppParameters = 'appa'
+typeProperty = 'prop'
+typeFSS = 'fss '
+typeKeyword = 'keyw'
+typeSectionH = 'sect'
+typeWildCard = '****'
+typeApplSignature = 'sign'
+typeSessionID = 'ssid'
+typeTargetID = 'targ'
+typeProcessSerialNumber = 'psn '
+typeNull = 'null'
+keyDirectObject = '----'
+keyErrorNumber = 'errn'
+keyErrorString = 'errs'
+keyProcessSerialNumber = 'psn '
+keyTransactionIDAttr = 'tran'
+keyReturnIDAttr = 'rtid'
+keyEventClassAttr = 'evcl'
+keyEventIDAttr = 'evid'
+keyAddressAttr = 'addr'
+keyOptionalKeywordAttr = 'optk'
+keyTimeoutAttr = 'timo'
+keyInteractLevelAttr = 'inte'
+keyEventSourceAttr = 'esrc'
+keyMissedKeywordAttr = 'miss'
+keyOriginalAddressAttr = 'from'
+keyPreDispatch = 'phac'
+keySelectProc = 'selh'
+keyAERecorderCount = 'recr'
+keyAEVersion = 'vers'
+kCoreEventClass = 'aevt'
+kAEOpenApplication = 'oapp'
+kAEOpenDocuments = 'odoc'
+kAEPrintDocuments = 'pdoc'
+kAEQuitApplication = 'quit'
+kAEAnswer = 'ansr'
+kAEApplicationDied = 'obit'
+kAENoReply = 0x00000001
+kAEQueueReply = 0x00000002
+kAEWaitReply = 0x00000003
+kAENeverInteract = 0x00000010
+kAECanInteract = 0x00000020
+kAEAlwaysInteract = 0x00000030
+kAECanSwitchLayer = 0x00000040
+kAEDontReconnect = 0x00000080
+kAEDontRecord = 0x00001000
+kAEDontExecute = 0x00002000
+kAENormalPriority = 0x00000000
+kAEStartRecording = 'reca'
+kAEStopRecording = 'recc'
+kAENotifyStartRecording = 'rec1'
+kAENotifyStopRecording = 'rec0'
+kAENotifyRecording = 'recr'
+kAutoGenerateReturnID = -1
+kAnyTransactionID = 0
+kAEDefaultTimeout = -1
+kNoTimeOut = -2
+kAENoDispatch = 0
+kAEUseStandardDispatch = -1
+errAECoercionFail = -1700
+errAEDescNotFound = -1701
+errAECorruptData = -1702
+errAEWrongDataType = -1703
+errAENotAEDesc = -1704
+errAEBadListItem = -1705
+errAENewerVersion = -1706
+errAENotAppleEvent = -1707
+errAEEventNotHandled = -1708
+errAEReplyNotValid = -1709
+errAEUnknownSendMode = -1710
+errAEWaitCanceled = -1711
+errAETimeout = -1712
+errAENoUserInteraction = -1713
+errAENotASpecialFunction = -1714
+errAEParamMissed = -1715
+errAEUnknownAddressType = -1716
+errAEHandlerNotFound = -1717
+errAEReplyNotArrived = -1718
+errAEIllegalIndex = -1719
+errAEUnknownObjectType = -1731
+errAERecordingIsAlreadyOn = -1732
diff --git a/Mac/Lib/toolbox/Controls.py b/Mac/Lib/toolbox/Controls.py
new file mode 100644
index 0000000..c95ea11
--- /dev/null
+++ b/Mac/Lib/toolbox/Controls.py
@@ -0,0 +1,41 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:Controls.h'
+pushButProc = 0
+checkBoxProc = 1
+radioButProc = 2
+useWFont = 8
+scrollBarProc = 16
+inButton = 10
+inCheckBox = 11
+inUpButton = 20
+inDownButton = 21
+inPageUp = 22
+inPageDown = 23
+inThumb = 129
+popupMenuProc = 1008
+inLabel = 1
+inMenu = 2
+inTriangle = 4
+popupUseWFont = 1 << 3
+popupTitleOutline = 1 << 11
+popupTitleExtend = 1 << 14
+popupTitleLeftJust = 0x00000000
+popupTitleCenterJust = 0x00000001
+popupTitleRightJust = 0x000000FF
+noConstraint = 0
+hAxisOnly = 1
+vAxisOnly = 2
+drawCntl = 0
+testCntl = 1
+calcCRgns = 2
+initCntl = 3
+dispCntl = 4
+posCntl = 5
+thumbCntl = 6
+dragCntl = 7
+autoTrack = 8
+calcCntlRgn = 10
+calcThumbRgn = 11
+cFrameColor = 0
+cBodyColor = 1
+cTextColor = 2
+cThumbColor = 3
diff --git a/Mac/Lib/toolbox/Dialogs.py b/Mac/Lib/toolbox/Dialogs.py
new file mode 100644
index 0000000..297568c
--- /dev/null
+++ b/Mac/Lib/toolbox/Dialogs.py
@@ -0,0 +1,20 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:Dialogs.h'
+ctrlItem = 4
+btnCtrl = 0
+chkCtrl = 1
+radCtrl = 2
+resCtrl = 3
+statText = 8
+editText = 16
+iconItem = 32
+picItem = 64
+userItem = 0
+itemDisable = 128
+ok = 1
+cancel = 2
+stopIcon = 0
+noteIcon = 1
+cautionIcon = 2
+overlayDITL = 0
+appendDITLRight = 1
+appendDITLBottom = 2
diff --git a/Mac/Lib/toolbox/Events.py b/Mac/Lib/toolbox/Events.py
new file mode 100644
index 0000000..ac32c3f
--- /dev/null
+++ b/Mac/Lib/toolbox/Events.py
@@ -0,0 +1,49 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:Events.h'
+nullEvent = 0
+mouseDown = 1
+mouseUp = 2
+keyDown = 3
+keyUp = 4
+autoKey = 5
+updateEvt = 6
+diskEvt = 7
+activateEvt = 8
+osEvt = 15
+mDownMask = 2
+mUpMask = 4
+keyDownMask = 8
+keyUpMask = 16
+autoKeyMask = 32
+updateMask = 64
+diskMask = 128
+activMask = 256
+highLevelEventMask = 1024
+osMask = -32768
+everyEvent = -1
+charCodeMask = 0x000000FF
+keyCodeMask = 0x0000FF00
+adbAddrMask = 0x00FF0000
+osEvtMessageMask = 0xFF000000
+mouseMovedMessage = 0xFA
+suspendResumeMessage = 0x01
+resumeFlag = 1
+convertClipboardFlag = 2
+activeFlag = 1
+btnState = 128
+cmdKey = 256
+shiftKey = 512
+alphaLock = 1024
+optionKey = 2048
+controlKey = 4096
+networkEvt = 10
+driverEvt = 11
+app1Evt = 12
+app2Evt = 13
+app3Evt = 14
+app4Evt = 15
+networkMask = 1024
+driverMask = 2048
+app1Mask = 4096
+app2Mask = 8192
+app3Mask = 16384
+app4Mask = -32768
diff --git a/Mac/Lib/toolbox/Menus.py b/Mac/Lib/toolbox/Menus.py
new file mode 100644
index 0000000..11b9a48
--- /dev/null
+++ b/Mac/Lib/toolbox/Menus.py
@@ -0,0 +1,12 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:Menus.h'
+mDrawMsg = 0
+mChooseMsg = 1
+mSizeMsg = 2
+mDrawItemMsg = 4
+mCalcItemMsg = 5
+textMenuProc = 0
+hMenuCmd = 27
+hierMenu = -1
+mPopUpMsg = 3
+mctAllItems = -98
+mctLastIDIndic = -99 /*last color table entry has this in ID field*/
diff --git a/Mac/Lib/toolbox/Resources.py b/Mac/Lib/toolbox/Resources.py
new file mode 100644
index 0000000..743c656
--- /dev/null
+++ b/Mac/Lib/toolbox/Resources.py
@@ -0,0 +1,12 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:Resources.h'
+resSysHeap = 64
+resPurgeable = 32
+resLocked = 16
+resProtected = 8
+resPreload = 4
+resChanged = 2
+mapReadOnly = 128
+mapCompact = 64
+mapChanged = 32
+mapTrue = 0xFFFF
+mapFalse = 0xFF00
diff --git a/Mac/Lib/toolbox/Sound.py b/Mac/Lib/toolbox/Sound.py
new file mode 100644
index 0000000..600adcd
--- /dev/null
+++ b/Mac/Lib/toolbox/Sound.py
@@ -0,0 +1,101 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:Sound.h'
+swMode = -1
+ftMode = 1
+ffMode = 0
+rate22khz = 0x56EE8BA3
+rate11khz = 0x2B7745D1
+squareWaveSynth = 1
+waveTableSynth = 3
+sampledSynth = 5
+MACE3snthID = 11
+MACE6snthID = 13
+nullCmd = 0
+initCmd = 1
+freeCmd = 2
+quietCmd = 3
+flushCmd = 4
+reInitCmd = 5
+waitCmd = 10
+pauseCmd = 11
+resumeCmd = 12
+callBackCmd = 13
+syncCmd = 14
+emptyCmd = 15
+tickleCmd = 20
+requestNextCmd = 21
+howOftenCmd = 22
+wakeUpCmd = 23
+availableCmd = 24
+versionCmd = 25
+totalLoadCmd = 26
+loadCmd = 27
+scaleCmd = 30
+tempoCmd = 31
+freqDurationCmd = 40
+restCmd = 41
+freqCmd = 42
+ampCmd = 43
+timbreCmd = 44
+getAmpCmd = 45
+waveTableCmd = 60
+phaseCmd = 61
+soundCmd = 80
+bufferCmd = 81
+rateCmd = 82
+continueCmd = 83
+doubleBufferCmd = 84
+getRateCmd = 85
+sizeCmd = 90
+convertCmd = 91
+stdQLength = 128
+dataOffsetFlag = 0x8000
+waveInitChannelMask = 0x07
+waveInitChannel0 = 0x04
+waveInitChannel1 = 0x05
+waveInitChannel2 = 0x06
+waveInitChannel3 = 0x07
+initPanMask = 0x0003
+initSRateMask = 0x0030
+initStereoMask = 0x00C0
+initCompMask = 0xFF00
+initChanLeft = 0x0002
+initChanRight = 0x0003
+initNoInterp = 0x0004
+initNoDrop = 0x0008
+initMono = 0x0080
+initStereo = 0x00C0
+initMACE3 = 0x0300
+initMACE6 = 0x0400
+initChan0 = 0x0004
+initChan1 = 0x0005
+initChan2 = 0x0006
+initChan3 = 0x0007
+stdSH = 0x00
+extSH = 0xFF
+cmpSH = 0xFE
+notCompressed = 0
+twoToOne = 1
+eightToThree = 2
+threeToOne = 3
+sixToOne = 4
+outsideCmpSH = 0
+insideCmpSH = 1
+aceSuccess = 0
+aceMemFull = 1
+aceNilBlock = 2
+aceBadComp = 3
+aceBadEncode = 4
+aceBadDest = 5
+aceBadCmd = 6
+sixToOnePacketSize = 8
+threeToOnePacketSize = 16
+stateBlockSize = 64
+leftOverBlockSize = 32
+firstSoundFormat = 0x0001
+secondSoundFormat = 0x0002
+dbBufferReady = 0x00000001
+dbLastBuffer = 0x00000004
+sysBeepDisable = 0x0000
+sysBeepEnable = 0x0001
+unitTypeNoSelection = 0xFFFF
+unitTypeSeconds = 0x0000
diff --git a/Mac/Lib/toolbox/Windows.py b/Mac/Lib/toolbox/Windows.py
new file mode 100644
index 0000000..5d5bd7a
--- /dev/null
+++ b/Mac/Lib/toolbox/Windows.py
@@ -0,0 +1,41 @@
+# Generated from 'D:Development:THINK C:Mac #includes:Apple #includes:Windows.h'
+documentProc = 0
+dBoxProc = 1
+plainDBox = 2
+altDBoxProc = 3
+noGrowDocProc = 4
+movableDBoxProc = 5
+zoomDocProc = 8
+zoomNoGrow = 12
+rDocProc = 16
+dialogKind = 2
+userKind = 8
+inDesk = 0
+inMenuBar = 1
+inSysWindow = 2
+inContent = 3
+inDrag = 4
+inGrow = 5
+inGoAway = 6
+inZoomIn = 7
+inZoomOut = 8
+wDraw = 0
+wHit = 1
+wCalcRgns = 2
+wNew = 3
+wDispose = 4
+wGrow = 5
+wDrawGIcon = 6
+wNoHit = 0
+wInContent = 1
+wInDrag = 2
+wInGrow = 3
+wInGoAway = 4
+wInZoomIn = 5
+wInZoomOut = 6
+deskPatID = 16
+wContentColor = 0
+wFrameColor = 1
+wTextColor = 2
+wHiliteColor = 3
+wTitleBarColor = 4
diff --git a/Mac/Lib/toolbox/aetools.py b/Mac/Lib/toolbox/aetools.py
new file mode 100644
index 0000000..745bce7
--- /dev/null
+++ b/Mac/Lib/toolbox/aetools.py
@@ -0,0 +1,296 @@
+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()