[Stackless-checkins] CVS: slpdev/src/2.2/src/Lib/plat-mac Audio_mac.py, NONE, 1.1 EasyDialogs.py, NONE, 1.1 FrameWork.py, NONE, 1.1 MiniAEFrame.py, NONE, 1.1 PixMapWrapper.py, NONE, 1.1 WASTEconst.py, NONE, 1.1 aepack.py, NONE, 1.1 aetools.py, NONE, 1.1 aetypes.py, NONE, 1.1 applesingle.py, NONE, 1.1 appletrawmain.py, NONE, 1.1 appletrunner.py, NONE, 1.1 argvemulator.py, NONE, 1.1 bgenlocations.py, NONE, 1.1 buildtools.py, NONE, 1.1 bundlebuilder.py, NONE, 1.1 cfmfile.py, NONE, 1.1 dialogs.rsrc, NONE, 1.1 errors.rsrc, NONE, 1.1 findertools.py, NONE, 1.1 gensuitemodule.py, NONE, 1.1 ic.py, NONE, 1.1 icopen.py, NONE, 1.1 macerrors.py, NONE, 1.1 macfs.py, NONE, 1.1 macostools.py, NONE, 1.1 macresource.py, NONE, 1.1 pimp.py, NONE, 1.1 plistlib.py, NONE, 1.1 terminalcommand.py, NONE, 1.1 videoreader.py, NONE, 1.1

Christian Tismer tismer at centera.de
Sat May 1 02:54:14 CEST 2004


Update of /home/cvs/slpdev/src/2.2/src/Lib/plat-mac
In directory centera.de:/home/tismer/slpdev/src/2.2/src/Lib/plat-mac

Added Files:
	Audio_mac.py EasyDialogs.py FrameWork.py MiniAEFrame.py 
	PixMapWrapper.py WASTEconst.py aepack.py aetools.py aetypes.py 
	applesingle.py appletrawmain.py appletrunner.py 
	argvemulator.py bgenlocations.py buildtools.py 
	bundlebuilder.py cfmfile.py dialogs.rsrc errors.rsrc 
	findertools.py gensuitemodule.py ic.py icopen.py macerrors.py 
	macfs.py macostools.py macresource.py pimp.py plistlib.py 
	terminalcommand.py videoreader.py 
Log Message:
added files

--- NEW FILE: Audio_mac.py ---
QSIZE = 100000
error='Audio_mac.error'

class Play_Audio_mac:

    def __init__(self, qsize=QSIZE):
        self._chan = None
        self._qsize = qsize
        self._outrate = 22254
        self._sampwidth = 1
        self._nchannels = 1
        self._gc = []
        self._usercallback = None

    def __del__(self):
        self.stop()
        self._usercallback = None

    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 Carbon.Sound import bufferCmd, callBackCmd, extSH
        import struct
        import MacOS
        if not self._chan:
            from Carbon 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 error, '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)+MacOS.string_id_to_buffer,
            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]
        if self._usercallback:
            self._usercallback()
            
    def setcallback(self, callback):
        self._usercallback = callback

    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._nchannels / self._sampwidth) - self.getfilled()

    def ulaw2lin(self, data):
        import audioop
        return audioop.ulaw2lin(data, 2)

def test():
    import aifc
    import EasyDialogs
    fn = EasyDialogs.AskFileForOpen(message="Select an AIFF soundfile", typeList=("AIFF",))
    if not fn: return
    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)
        print 'wrote', len(data), 'space', p.getfillable()
    p.wait()

if __name__ == '__main__':
    test()

--- NEW FILE: EasyDialogs.py ---
"""Easy to use dialogs.

Message(msg) -- display a message and an OK button.
AskString(prompt, default) -- ask for a string, display OK and Cancel buttons.
AskPassword(prompt, default) -- like AskString(), but shows text as bullets.
AskYesNoCancel(question, default) -- display a question and Yes, No and Cancel buttons.
GetArgv(optionlist, commandlist) -- fill a sys.argv-like list using a dialog
AskFileForOpen(...) -- Ask the user for an existing file
AskFileForSave(...) -- Ask the user for an output file
AskFolder(...) -- Ask the user to select a folder
bar = Progress(label, maxvalue) -- Display a progress bar
bar.set(value) -- Set value
bar.inc( *amount ) -- increment value by amount (default=1)
bar.label( *newlabel ) -- get or set text label.

More documentation in each function.
This module uses DLOG resources 260 and on.
Based upon STDWIN dialogs with the same names and functions.
"""

from Carbon.Dlg import GetNewDialog, SetDialogItemText, GetDialogItemText, ModalDialog
from Carbon import Qd
from Carbon import QuickDraw
from Carbon import Dialogs
from Carbon import Windows
from Carbon import Dlg,Win,Evt,Events # sdm7g
from Carbon import Ctl
from Carbon import Controls
from Carbon import Menu
from Carbon import AE
import Nav
import MacOS
import string
from Carbon.ControlAccessor import *    # Also import Controls constants
import Carbon.File
import macresource
import os
import sys

__all__ = ['Message', 'AskString', 'AskPassword', 'AskYesNoCancel',
    'GetArgv', 'AskFileForOpen', 'AskFileForSave', 'AskFolder',
    'ProgressBar']

_initialized = 0

def _initialize():
    global _initialized
    if _initialized: return
    macresource.need("DLOG", 260, "dialogs.rsrc", __name__)

def _interact():
    """Make sure the application is in the foreground"""
    AE.AEInteractWithUser(50000000)

def cr2lf(text):
    if '\r' in text:
        text = string.join(string.split(text, '\r'), '\n')
    return text

def lf2cr(text):
    if '\n' in text:
        text = string.join(string.split(text, '\n'), '\r')
    if len(text) > 253:
        text = text[:253] + '\311'
    return text

def Message(msg, id=260, ok=None):
    """Display a MESSAGE string.

    Return when the user clicks the OK button or presses Return.

    The MESSAGE string can be at most 255 characters long.
    """
    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    h = d.GetDialogItemAsControl(2)
    SetDialogItemText(h, lf2cr(msg))
    if ok != None:
        h = d.GetDialogItemAsControl(1)
        h.SetControlTitle(ok)
    d.SetDialogDefaultItem(1)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1:
            return


def AskString(prompt, default = "", id=261, ok=None, cancel=None):
    """Display a PROMPT string and a text entry field with a DEFAULT string.

    Return the contents of the text entry field when the user clicks the
    OK button or presses Return.
    Return None when the user clicks the Cancel button.

    If omitted, DEFAULT is empty.

    The PROMPT and DEFAULT strings, as well as the return value,
    can be at most 255 characters long.
    """

    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    h = d.GetDialogItemAsControl(3)
    SetDialogItemText(h, lf2cr(prompt))
    h = d.GetDialogItemAsControl(4)
    SetDialogItemText(h, lf2cr(default))
    d.SelectDialogItemText(4, 0, 999)
#       d.SetDialogItem(4, 0, 255)
    if ok != None:
        h = d.GetDialogItemAsControl(1)
        h.SetControlTitle(ok)
    if cancel != None:
        h = d.GetDialogItemAsControl(2)
        h.SetControlTitle(cancel)
    d.SetDialogDefaultItem(1)
    d.SetDialogCancelItem(2)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1:
            h = d.GetDialogItemAsControl(4)
            return cr2lf(GetDialogItemText(h))
        if n == 2: return None

def AskPassword(prompt,  default='', id=264, ok=None, cancel=None):
    """Display a PROMPT string and a text entry field with a DEFAULT string.
    The string is displayed as bullets only.

    Return the contents of the text entry field when the user clicks the
    OK button or presses Return.
    Return None when the user clicks the Cancel button.

    If omitted, DEFAULT is empty.

    The PROMPT and DEFAULT strings, as well as the return value,
    can be at most 255 characters long.
    """
    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    h = d.GetDialogItemAsControl(3)
    SetDialogItemText(h, lf2cr(prompt))
    pwd = d.GetDialogItemAsControl(4)
    bullets = '\245'*len(default)
##      SetControlData(pwd, kControlEditTextPart, kControlEditTextTextTag, bullets)
    SetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag, default)
    d.SelectDialogItemText(4, 0, 999)
    Ctl.SetKeyboardFocus(d.GetDialogWindow(), pwd, kControlEditTextPart)
    if ok != None:
        h = d.GetDialogItemAsControl(1)
        h.SetControlTitle(ok)
    if cancel != None:
        h = d.GetDialogItemAsControl(2)
        h.SetControlTitle(cancel)
    d.SetDialogDefaultItem(Dialogs.ok)
    d.SetDialogCancelItem(Dialogs.cancel)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1:
            h = d.GetDialogItemAsControl(4)
            return cr2lf(GetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag))
        if n == 2: return None

def AskYesNoCancel(question, default = 0, yes=None, no=None, cancel=None, id=262):
    """Display a QUESTION string which can be answered with Yes or No.

    Return 1 when the user clicks the Yes button.
    Return 0 when the user clicks the No button.
    Return -1 when the user clicks the Cancel button.

    When the user presses Return, the DEFAULT value is returned.
    If omitted, this is 0 (No).

    The QUESTION string can be at most 255 characters.
    """

    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
    # Button assignments:
    # 1 = default (invisible)
    # 2 = Yes
    # 3 = No
    # 4 = Cancel
    # The question string is item 5
    h = d.GetDialogItemAsControl(5)
    SetDialogItemText(h, lf2cr(question))
    if yes != None:
        if yes == '':
            d.HideDialogItem(2)
        else:
            h = d.GetDialogItemAsControl(2)
            h.SetControlTitle(yes)
    if no != None:
        if no == '':
            d.HideDialogItem(3)
        else:
            h = d.GetDialogItemAsControl(3)
            h.SetControlTitle(no)
    if cancel != None:
        if cancel == '':
            d.HideDialogItem(4)
        else:
            h = d.GetDialogItemAsControl(4)
            h.SetControlTitle(cancel)
    d.SetDialogCancelItem(4)
    if default == 1:
        d.SetDialogDefaultItem(2)
    elif default == 0:
        d.SetDialogDefaultItem(3)
    elif default == -1:
        d.SetDialogDefaultItem(4)
    d.AutoSizeDialog()
    d.GetDialogWindow().ShowWindow()
    while 1:
        n = ModalDialog(None)
        if n == 1: return default
        if n == 2: return 1
        if n == 3: return 0
        if n == 4: return -1




screenbounds = Qd.GetQDGlobalsScreenBits().bounds
screenbounds = screenbounds[0]+4, screenbounds[1]+4, \
    screenbounds[2]-4, screenbounds[3]-4

kControlProgressBarIndeterminateTag = 'inde'    # from Controls.py


class ProgressBar:
    def __init__(self, title="Working...", maxval=0, label="", id=263):
        self.w = None
        self.d = None
        _initialize()
        self.d = GetNewDialog(id, -1)
        self.w = self.d.GetDialogWindow()
        self.label(label)
        self.title(title)
        self.set(0, maxval)
        self.d.AutoSizeDialog()
        self.w.ShowWindow()
        self.d.DrawDialog()

    def __del__( self ):
        if self.w:
            self.w.BringToFront()
            self.w.HideWindow()
        del self.w
        del self.d

    def title(self, newstr=""):
        """title(text) - Set title of progress window"""
        self.w.BringToFront()
        self.w.SetWTitle(newstr)

    def label( self, *newstr ):
        """label(text) - Set text in progress box"""
        self.w.BringToFront()
        if newstr:
            self._label = lf2cr(newstr[0])
        text_h = self.d.GetDialogItemAsControl(2)
        SetDialogItemText(text_h, self._label)

    def _update(self, value):
        maxval = self.maxval
        if maxval == 0:     # an indeterminate bar
            Ctl.IdleControls(self.w)    # spin the barber pole
        else:               # a determinate bar
            if maxval > 32767:
                value = int(value/(maxval/32767.0))
                maxval = 32767
            maxval = int(maxval)
            value = int(value)
            progbar = self.d.GetDialogItemAsControl(3)
            progbar.SetControlMaximum(maxval)
            progbar.SetControlValue(value)  # set the bar length

        # Test for cancel button
        ready, ev = Evt.WaitNextEvent( Events.mDownMask, 1  )
        if ready :
            what,msg,when,where,mod = ev
            part = Win.FindWindow(where)[0]
            if Dlg.IsDialogEvent(ev):
                ds = Dlg.DialogSelect(ev)
                if ds[0] and ds[1] == self.d and ds[-1] == 1:
                    self.w.HideWindow()
                    self.w = None
                    self.d = None
                    raise KeyboardInterrupt, ev
            else:
                if part == 4:   # inDrag
                    self.w.DragWindow(where, screenbounds)
                else:
                    MacOS.HandleEvent(ev)


    def set(self, value, max=None):
        """set(value) - Set progress bar position"""
        if max != None:
            self.maxval = max
            bar = self.d.GetDialogItemAsControl(3)
            if max <= 0:    # indeterminate bar
                bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x01')
            else:           # determinate bar
                bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x00')
        if value < 0:
            value = 0
        elif value > self.maxval:
            value = self.maxval
        self.curval = value
        self._update(value)

    def inc(self, n=1):
        """inc(amt) - Increment progress bar position"""
        self.set(self.curval + n)

ARGV_ID=265
ARGV_ITEM_OK=1
ARGV_ITEM_CANCEL=2
ARGV_OPTION_GROUP=3
ARGV_OPTION_EXPLAIN=4
ARGV_OPTION_VALUE=5
ARGV_OPTION_ADD=6
ARGV_COMMAND_GROUP=7
ARGV_COMMAND_EXPLAIN=8
ARGV_COMMAND_ADD=9
ARGV_ADD_OLDFILE=10
ARGV_ADD_NEWFILE=11
ARGV_ADD_FOLDER=12
ARGV_CMDLINE_GROUP=13
ARGV_CMDLINE_DATA=14

##def _myModalDialog(d):
##      while 1:
##          ready, ev = Evt.WaitNextEvent(0xffff, -1)
##          print 'DBG: WNE', ready, ev
##          if ready :
##              what,msg,when,where,mod = ev
##              part, window = Win.FindWindow(where)
##              if Dlg.IsDialogEvent(ev):
##                  didit, dlgdone, itemdone = Dlg.DialogSelect(ev)
##                  print 'DBG: DialogSelect', didit, dlgdone, itemdone, d
##                  if didit and dlgdone == d:
##                      return itemdone
##              elif window == d.GetDialogWindow():
##                  d.GetDialogWindow().SelectWindow()
##                  if part == 4:   # inDrag
##                          d.DragWindow(where, screenbounds)
##                  else:
##                      MacOS.HandleEvent(ev)
##              else:
##                  MacOS.HandleEvent(ev)
##
def _setmenu(control, items):
        mhandle = control.GetControlData_Handle(Controls.kControlMenuPart,
                Controls.kControlPopupButtonMenuHandleTag)
        menu = Menu.as_Menu(mhandle)
        for item in items:
            if type(item) == type(()):
                label = item[0]
            else:
                label = item
            if label[-1] == '=' or label[-1] == ':':
                label = label[:-1]
            menu.AppendMenu(label)
##          mhandle, mid = menu.getpopupinfo()
##          control.SetControlData_Handle(Controls.kControlMenuPart,
##                  Controls.kControlPopupButtonMenuHandleTag, mhandle)
        control.SetControlMinimum(1)
        control.SetControlMaximum(len(items)+1)

def _selectoption(d, optionlist, idx):
    if idx < 0 or idx >= len(optionlist):
        MacOS.SysBeep()
        return
    option = optionlist[idx]
    if type(option) == type(()):
        if len(option) == 4:
            help = option[2]
        elif len(option) > 1:
            help = option[-1]
        else:
            help = ''
    else:
        help = ''
    h = d.GetDialogItemAsControl(ARGV_OPTION_EXPLAIN)
    if help and len(help) > 250:
        help = help[:250] + '...'
    Dlg.SetDialogItemText(h, help)
    hasvalue = 0
    if type(option) == type(()):
        label = option[0]
    else:
        label = option
    if label[-1] == '=' or label[-1] == ':':
        hasvalue = 1
    h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
    Dlg.SetDialogItemText(h, '')
    if hasvalue:
        d.ShowDialogItem(ARGV_OPTION_VALUE)
        d.SelectDialogItemText(ARGV_OPTION_VALUE, 0, 0)
    else:
        d.HideDialogItem(ARGV_OPTION_VALUE)


def GetArgv(optionlist=None, commandlist=None, addoldfile=1, addnewfile=1, addfolder=1, id=ARGV_ID):
    _initialize()
    _interact()
    d = GetNewDialog(id, -1)
    if not d:
        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
        return
#       h = d.GetDialogItemAsControl(3)
#       SetDialogItemText(h, lf2cr(prompt))
#       h = d.GetDialogItemAsControl(4)
#       SetDialogItemText(h, lf2cr(default))
#       d.SelectDialogItemText(4, 0, 999)
#       d.SetDialogItem(4, 0, 255)
    if optionlist:
        _setmenu(d.GetDialogItemAsControl(ARGV_OPTION_GROUP), optionlist)
        _selectoption(d, optionlist, 0)
    else:
        d.GetDialogItemAsControl(ARGV_OPTION_GROUP).DeactivateControl()
    if commandlist:
        _setmenu(d.GetDialogItemAsControl(ARGV_COMMAND_GROUP), commandlist)
        if type(commandlist[0]) == type(()) and len(commandlist[0]) > 1:
            help = commandlist[0][-1]
            h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
            Dlg.SetDialogItemText(h, help)
    else:
        d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).DeactivateControl()
    if not addoldfile:
        d.GetDialogItemAsControl(ARGV_ADD_OLDFILE).DeactivateControl()
    if not addnewfile:
        d.GetDialogItemAsControl(ARGV_ADD_NEWFILE).DeactivateControl()
    if not addfolder:
        d.GetDialogItemAsControl(ARGV_ADD_FOLDER).DeactivateControl()
    d.SetDialogDefaultItem(ARGV_ITEM_OK)
    d.SetDialogCancelItem(ARGV_ITEM_CANCEL)
    d.GetDialogWindow().ShowWindow()
    d.DrawDialog()
    if hasattr(MacOS, 'SchedParams'):
        appsw = MacOS.SchedParams(1, 0)
    try:
        while 1:
            stringstoadd = []
            n = ModalDialog(None)
            if n == ARGV_ITEM_OK:
                break
            elif n == ARGV_ITEM_CANCEL:
                raise SystemExit
            elif n == ARGV_OPTION_GROUP:
                idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
                _selectoption(d, optionlist, idx)
            elif n == ARGV_OPTION_VALUE:
                pass
            elif n == ARGV_OPTION_ADD:
                idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
                if 0 <= idx < len(optionlist):
                    option = optionlist[idx]
                    if type(option) == type(()):
                        option = option[0]
                    if option[-1] == '=' or option[-1] == ':':
                        option = option[:-1]
                        h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
                        value = Dlg.GetDialogItemText(h)
                    else:
                        value = ''
                    if len(option) == 1:
                        stringtoadd = '-' + option
                    else:
                        stringtoadd = '--' + option
                    stringstoadd = [stringtoadd]
                    if value:
                        stringstoadd.append(value)
                else:
                    MacOS.SysBeep()
            elif n == ARGV_COMMAND_GROUP:
                idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
                if 0 <= idx < len(commandlist) and type(commandlist[idx]) == type(()) and \
                        len(commandlist[idx]) > 1:
                    help = commandlist[idx][-1]
                    h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
                    Dlg.SetDialogItemText(h, help)
            elif n == ARGV_COMMAND_ADD:
                idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
                if 0 <= idx < len(commandlist):
                    command = commandlist[idx]
                    if type(command) == type(()):
                        command = command[0]
                    stringstoadd = [command]
                else:
                    MacOS.SysBeep()
            elif n == ARGV_ADD_OLDFILE:
                pathname = AskFileForOpen()
                if pathname:
                    stringstoadd = [pathname]
            elif n == ARGV_ADD_NEWFILE:
                pathname = AskFileForSave()
                if pathname:
                    stringstoadd = [pathname]
            elif n == ARGV_ADD_FOLDER:
                pathname = AskFolder()
                if pathname:
                    stringstoadd = [pathname]
            elif n == ARGV_CMDLINE_DATA:
                pass # Nothing to do
            else:
                raise RuntimeError, "Unknown dialog item %d"%n

            for stringtoadd in stringstoadd:
                if '"' in stringtoadd or "'" in stringtoadd or " " in stringtoadd:
                    stringtoadd = repr(stringtoadd)
                h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
                oldstr = GetDialogItemText(h)
                if oldstr and oldstr[-1] != ' ':
                    oldstr = oldstr + ' '
                oldstr = oldstr + stringtoadd
                if oldstr[-1] != ' ':
                    oldstr = oldstr + ' '
                SetDialogItemText(h, oldstr)
                d.SelectDialogItemText(ARGV_CMDLINE_DATA, 0x7fff, 0x7fff)
        h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
        oldstr = GetDialogItemText(h)
        tmplist = string.split(oldstr)
        newlist = []
        while tmplist:
            item = tmplist[0]
            del tmplist[0]
            if item[0] == '"':
                while item[-1] != '"':
                    if not tmplist:
                        raise RuntimeError, "Unterminated quoted argument"
                    item = item + ' ' + tmplist[0]
                    del tmplist[0]
                item = item[1:-1]
            if item[0] == "'":
                while item[-1] != "'":
                    if not tmplist:
                        raise RuntimeError, "Unterminated quoted argument"
                    item = item + ' ' + tmplist[0]
                    del tmplist[0]
                item = item[1:-1]
            newlist.append(item)
        return newlist
    finally:
        if hasattr(MacOS, 'SchedParams'):
            MacOS.SchedParams(*appsw)
        del d

def _process_Nav_args(dftflags, **args):
    import aepack
    import Carbon.AE
    import Carbon.File
    for k in args.keys():
        if args[k] is None:
            del args[k]
    # Set some defaults, and modify some arguments
    if not args.has_key('dialogOptionFlags'):
        args['dialogOptionFlags'] = dftflags
    if args.has_key('defaultLocation') and \
            not isinstance(args['defaultLocation'], Carbon.AE.AEDesc):
        defaultLocation = args['defaultLocation']
        if isinstance(defaultLocation, (Carbon.File.FSSpec, Carbon.File.FSRef)):
            args['defaultLocation'] = aepack.pack(defaultLocation)
        else:
            defaultLocation = Carbon.File.FSRef(defaultLocation)
            args['defaultLocation'] = aepack.pack(defaultLocation)
    if args.has_key('typeList') and not isinstance(args['typeList'], Carbon.Res.ResourceType):
        typeList = args['typeList'][:]
        # Workaround for OSX typeless files:
        if 'TEXT' in typeList and not '\0\0\0\0' in typeList:
            typeList = typeList + ('\0\0\0\0',)
        data = 'Pyth' + struct.pack("hh", 0, len(typeList))
        for type in typeList:
            data = data+type
        args['typeList'] = Carbon.Res.Handle(data)
    tpwanted = str
    if args.has_key('wanted'):
        tpwanted = args['wanted']
        del args['wanted']
    return args, tpwanted

def _dummy_Nav_eventproc(msg, data):
    pass

_default_Nav_eventproc = _dummy_Nav_eventproc

def SetDefaultEventProc(proc):
    global _default_Nav_eventproc
    rv = _default_Nav_eventproc
    if proc is None:
        proc = _dummy_Nav_eventproc
    _default_Nav_eventproc = proc
    return rv

def AskFileForOpen(
        message=None,
        typeList=None,
        # From here on the order is not documented
        version=None,
        defaultLocation=None,
        dialogOptionFlags=None,
        location=None,
        clientName=None,
        windowTitle=None,
        actionButtonLabel=None,
        cancelButtonLabel=None,
        preferenceKey=None,
        popupExtension=None,
        eventProc=_dummy_Nav_eventproc,
        previewProc=None,
        filterProc=None,
        wanted=None,
        multiple=None):
    """Display a dialog asking the user for a file to open.

    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    the other arguments can be looked up in Apple's Navigation Services documentation"""

    default_flags = 0x56 # Or 0xe4?
    args, tpwanted = _process_Nav_args(default_flags, version=version,
        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
        location=location,clientName=clientName,windowTitle=windowTitle,
        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
        message=message,preferenceKey=preferenceKey,
        popupExtension=popupExtension,eventProc=eventProc,previewProc=previewProc,
        filterProc=filterProc,typeList=typeList,wanted=wanted,multiple=multiple)
    _interact()
    try:
        rr = Nav.NavChooseFile(args)
        good = 1
    except Nav.error, arg:
        if arg[0] != -128: # userCancelledErr
            raise Nav.error, arg
        return None
    if not rr.validRecord or not rr.selection:
        return None
    if issubclass(tpwanted, Carbon.File.FSRef):
        return tpwanted(rr.selection_fsr[0])
    if issubclass(tpwanted, Carbon.File.FSSpec):
        return tpwanted(rr.selection[0])
    if issubclass(tpwanted, str):
        return tpwanted(rr.selection_fsr[0].as_pathname())
    if issubclass(tpwanted, unicode):
        return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)

def AskFileForSave(
        message=None,
        savedFileName=None,
        # From here on the order is not documented
        version=None,
        defaultLocation=None,
        dialogOptionFlags=None,
        location=None,
        clientName=None,
        windowTitle=None,
        actionButtonLabel=None,
        cancelButtonLabel=None,
        preferenceKey=None,
        popupExtension=None,
        eventProc=_dummy_Nav_eventproc,
        fileType=None,
        fileCreator=None,
        wanted=None,
        multiple=None):
    """Display a dialog asking the user for a filename to save to.

    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    the other arguments can be looked up in Apple's Navigation Services documentation"""


    default_flags = 0x07
    args, tpwanted = _process_Nav_args(default_flags, version=version,
        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
        location=location,clientName=clientName,windowTitle=windowTitle,
        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
        savedFileName=savedFileName,message=message,preferenceKey=preferenceKey,
        popupExtension=popupExtension,eventProc=eventProc,fileType=fileType,
        fileCreator=fileCreator,wanted=wanted,multiple=multiple)
    _interact()
    try:
        rr = Nav.NavPutFile(args)
        good = 1
    except Nav.error, arg:
        if arg[0] != -128: # userCancelledErr
            raise Nav.error, arg
        return None
    if not rr.validRecord or not rr.selection:
        return None
    if issubclass(tpwanted, Carbon.File.FSRef):
        raise TypeError, "Cannot pass wanted=FSRef to AskFileForSave"
    if issubclass(tpwanted, Carbon.File.FSSpec):
        return tpwanted(rr.selection[0])
    if issubclass(tpwanted, (str, unicode)):
        if sys.platform == 'mac':
            fullpath = rr.selection[0].as_pathname()
        else:
            # This is gross, and probably incorrect too
            vrefnum, dirid, name = rr.selection[0].as_tuple()
            pardir_fss = Carbon.File.FSSpec((vrefnum, dirid, ''))
            pardir_fsr = Carbon.File.FSRef(pardir_fss)
            pardir_path = pardir_fsr.FSRefMakePath()  # This is utf-8
            name_utf8 = unicode(name, 'macroman').encode('utf8')
            fullpath = os.path.join(pardir_path, name_utf8)
        if issubclass(tpwanted, unicode):
            return unicode(fullpath, 'utf8')
        return tpwanted(fullpath)
    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)

def AskFolder(
        message=None,
        # From here on the order is not documented
        version=None,
        defaultLocation=None,
        dialogOptionFlags=None,
        location=None,
        clientName=None,
        windowTitle=None,
        actionButtonLabel=None,
        cancelButtonLabel=None,
        preferenceKey=None,
        popupExtension=None,
        eventProc=_dummy_Nav_eventproc,
        filterProc=None,
        wanted=None,
        multiple=None):
    """Display a dialog asking the user for select a folder.

    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    the other arguments can be looked up in Apple's Navigation Services documentation"""

    default_flags = 0x17
    args, tpwanted = _process_Nav_args(default_flags, version=version,
        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
        location=location,clientName=clientName,windowTitle=windowTitle,
        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
        message=message,preferenceKey=preferenceKey,
        popupExtension=popupExtension,eventProc=eventProc,filterProc=filterProc,
        wanted=wanted,multiple=multiple)
    _interact()
    try:
        rr = Nav.NavChooseFolder(args)
        good = 1
    except Nav.error, arg:
        if arg[0] != -128: # userCancelledErr
            raise Nav.error, arg
        return None
    if not rr.validRecord or not rr.selection:
        return None
    if issubclass(tpwanted, Carbon.File.FSRef):
        return tpwanted(rr.selection_fsr[0])
    if issubclass(tpwanted, Carbon.File.FSSpec):
        return tpwanted(rr.selection[0])
    if issubclass(tpwanted, str):
        return tpwanted(rr.selection_fsr[0].as_pathname())
    if issubclass(tpwanted, unicode):
        return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)


def test():
    import time

    Message("Testing EasyDialogs.")
    optionlist = (('v', 'Verbose'), ('verbose', 'Verbose as long option'),
                ('flags=', 'Valued option'), ('f:', 'Short valued option'))
    commandlist = (('start', 'Start something'), ('stop', 'Stop something'))
    argv = GetArgv(optionlist=optionlist, commandlist=commandlist, addoldfile=0)
    Message("Command line: %s"%' '.join(argv))
    for i in range(len(argv)):
        print 'arg[%d] = %r' % (i, argv[i])
    ok = AskYesNoCancel("Do you want to proceed?")
    ok = AskYesNoCancel("Do you want to identify?", yes="Identify", no="No")
    if ok > 0:
        s = AskString("Enter your first name", "Joe")
        s2 = AskPassword("Okay %s, tell us your nickname"%s, s, cancel="None")
        if not s2:
            Message("%s has no secret nickname"%s)
        else:
            Message("Hello everybody!!\nThe secret nickname of %s is %s!!!"%(s, s2))
    else:
        s = 'Anonymous'
    rv = AskFileForOpen(message="Gimme a file, %s"%s, wanted=Carbon.File.FSSpec)
    Message("rv: %s"%rv)
    rv = AskFileForSave(wanted=Carbon.File.FSRef, savedFileName="%s.txt"%s)
    Message("rv.as_pathname: %s"%rv.as_pathname())
    rv = AskFolder()
    Message("Folder name: %s"%rv)
    text = ( "Working Hard...", "Hardly Working..." ,
            "So far, so good!", "Keep on truckin'" )
    bar = ProgressBar("Progress, progress...", 0, label="Ramping up...")
    try:
        if hasattr(MacOS, 'SchedParams'):
            appsw = MacOS.SchedParams(1, 0)
        for i in xrange(20):
            bar.inc()
            time.sleep(0.05)
        bar.set(0,100)
        for i in xrange(100):
            bar.set(i)
            time.sleep(0.05)
            if i % 10 == 0:
                bar.label(text[(i/10) % 4])
        bar.label("Done.")
        time.sleep(1.0)     # give'em a chance to see "Done."
    finally:
        del bar
        if hasattr(MacOS, 'SchedParams'):
            MacOS.SchedParams(*appsw)

if __name__ == '__main__':
    try:
        test()
    except KeyboardInterrupt:
        Message("Operation Canceled.")


--- NEW FILE: FrameWork.py ---
"A sort of application framework for the Mac"

DEBUG=0

import MacOS
import traceback

from Carbon.AE import *
from Carbon.AppleEvents import *
from Carbon.Ctl import *
from Carbon.Controls import *
from Carbon.Dlg import *
from Carbon.Dialogs import *
from Carbon.Evt import *
from Carbon.Events import *
from Carbon.Help import *
from Carbon.Menu import *
from Carbon.Menus import *
from Carbon.Qd import *
[...1084 lines suppressed...]
    def enablehelp(self, *args):
        hm = self.gethelpmenu()
        self.nohelpitem = MenuItem(hm, "There isn't any", None, self.nohelp)

    def nohelp(self, *args):
        print "I told you there isn't any!"

    def debug(self, *args):
        import pdb
        pdb.set_trace()


def test():
    "Test program"
    app = TestApp()
    app.mainloop()


if __name__ == '__main__':
    test()

--- NEW FILE: MiniAEFrame.py ---
"""MiniAEFrame - A minimal AppleEvent Application framework.

There are two classes:
    AEServer -- a mixin class offering nice AE handling.
    MiniApplication -- a very minimal alternative to FrameWork.py,
        only suitable for the simplest of AppleEvent servers.
"""

import sys
import traceback
import MacOS
from Carbon import AE
from Carbon.AppleEvents import *
from Carbon import Evt
from Carbon.Events import *
from Carbon import Menu
from Carbon import Win
from Carbon.Windows import *
from Carbon import Qd

import aetools
import EasyDialogs

kHighLevelEvent = 23                # Not defined anywhere for Python yet?


class MiniApplication:

    """A minimal FrameWork.Application-like class"""

    def __init__(self):
        self.quitting = 0
        # Initialize menu
        self.appleid = 1
        self.quitid = 2
        Menu.ClearMenuBar()
        self.applemenu = applemenu = Menu.NewMenu(self.appleid, "\024")
        applemenu.AppendMenu("%s;(-" % self.getaboutmenutext())
        if MacOS.runtimemodel == 'ppc':
            applemenu.AppendResMenu('DRVR')
        applemenu.InsertMenu(0)
        self.quitmenu = Menu.NewMenu(self.quitid, "File")
        self.quitmenu.AppendMenu("Quit")
        self.quitmenu.SetItemCmd(1, ord("Q"))
        self.quitmenu.InsertMenu(0)
        Menu.DrawMenuBar()

    def __del__(self):
        self.close()

    def close(self):
        pass

    def mainloop(self, mask = everyEvent, timeout = 60*60):
        while not self.quitting:
            self.dooneevent(mask, timeout)

    def _quit(self):
        self.quitting = 1

    def dooneevent(self, mask = everyEvent, timeout = 60*60):
            got, event = Evt.WaitNextEvent(mask, timeout)
            if got:
                self.lowlevelhandler(event)

    def lowlevelhandler(self, event):
        what, message, when, where, modifiers = event
        h, v = where
        if what == kHighLevelEvent:
            msg = "High Level Event: %r %r" % (code(message), code(h | (v<<16)))
            try:
                AE.AEProcessAppleEvent(event)
            except AE.Error, err:
                print 'AE error: ', err
                print 'in', msg
                traceback.print_exc()
            return
        elif what == keyDown:
            c = chr(message & charCodeMask)
            if modifiers & cmdKey:
                if c == '.':
                    raise KeyboardInterrupt, "Command-period"
                if c == 'q':
                    if hasattr(MacOS, 'OutputSeen'):
                        MacOS.OutputSeen()
                    self.quitting = 1
                    return
        elif what == mouseDown:
            partcode, window = Win.FindWindow(where)
            if partcode == inMenuBar:
                result = Menu.MenuSelect(where)
                id = (result>>16) & 0xffff      # Hi word
                item = result & 0xffff      # Lo word
                if id == self.appleid:
                    if item == 1:
                        EasyDialogs.Message(self.getabouttext())
                    elif item > 1 and hasattr(Menu, 'OpenDeskAcc'):
                        name = self.applemenu.GetMenuItemText(item)
                        Menu.OpenDeskAcc(name)
                elif id == self.quitid and item == 1:
                    if hasattr(MacOS, 'OutputSeen'):
                        MacOS.OutputSeen()
                    self.quitting = 1
                Menu.HiliteMenu(0)
                return
        # Anything not handled is passed to Python/SIOUX
        if hasattr(MacOS, 'HandleEvent'):
            MacOS.HandleEvent(event)
        else:
            print "Unhandled event:", event

    def getabouttext(self):
        return self.__class__.__name__

    def getaboutmenutext(self):
        return "About %s\311" % self.__class__.__name__


class AEServer:

    def __init__(self):
        self.ae_handlers = {}

    def installaehandler(self, classe, type, callback):
        AE.AEInstallEventHandler(classe, type, self.callback_wrapper)
        self.ae_handlers[(classe, type)] = callback

    def close(self):
        for classe, type in self.ae_handlers.keys():
            AE.AERemoveEventHandler(classe, type)

    def callback_wrapper(self, _request, _reply):
        _parameters, _attributes = aetools.unpackevent(_request)
        _class = _attributes['evcl'].type
        _type = _attributes['evid'].type

        if self.ae_handlers.has_key((_class, _type)):
            _function = self.ae_handlers[(_class, _type)]
        elif self.ae_handlers.has_key((_class, '****')):
            _function = self.ae_handlers[(_class, '****')]
        elif self.ae_handlers.has_key(('****', '****')):
            _function = self.ae_handlers[('****', '****')]
        else:
            raise 'Cannot happen: AE callback without handler', (_class, _type)

        # XXXX Do key-to-name mapping here

        _parameters['_attributes'] = _attributes
        _parameters['_class'] = _class
        _parameters['_type'] = _type
        if _parameters.has_key('----'):
            _object = _parameters['----']
            del _parameters['----']
            # The try/except that used to be here can mask programmer errors.
            # Let the program crash, the programmer can always add a **args
            # to the formal parameter list.
            rv = _function(_object, **_parameters)
        else:
            #Same try/except comment as above
            rv = _function(**_parameters)

        if rv == None:
            aetools.packevent(_reply, {})
        else:
            aetools.packevent(_reply, {'----':rv})


def code(x):
    "Convert a long int to the 4-character code it really is"
    s = ''
    for i in range(4):
        x, c = divmod(x, 256)
        s = chr(c) + s
    return s

class _Test(AEServer, MiniApplication):
    """Mini test application, handles required events"""

    def __init__(self):
        MiniApplication.__init__(self)
        AEServer.__init__(self)
        self.installaehandler('aevt', 'oapp', self.open_app)
        self.installaehandler('aevt', 'quit', self.quit)
        self.installaehandler('****', '****', self.other)
        self.mainloop()

    def quit(self, **args):
        self._quit()

    def open_app(self, **args):
        pass

    def other(self, _object=None, _class=None, _type=None, **args):
        print 'AppleEvent', (_class, _type), 'for', _object, 'Other args:', args


if __name__ == '__main__':
    _Test()

--- NEW FILE: PixMapWrapper.py ---
"""PixMapWrapper - defines the PixMapWrapper class, which wraps an opaque
QuickDraw PixMap data structure in a handy Python class.  Also provides 
methods to convert to/from pixel data (from, e.g., the img module) or a
Python Imaging Library Image object.

J. Strout <joe at strout.net>  February 1999"""

from Carbon import Qd
from Carbon import QuickDraw
import struct
import MacOS
import img
import imgformat

# PixMap data structure element format (as used with struct)
_pmElemFormat = {
    'baseAddr':'l',     # address of pixel data
    'rowBytes':'H',     # bytes per row, plus 0x8000
    'bounds':'hhhh',    # coordinates imposed over pixel data
        'top':'h',
        'left':'h',
        'bottom':'h',
        'right':'h',
    'pmVersion':'h',    # flags for Color QuickDraw
    'packType':'h',     # format of compression algorithm
    'packSize':'l',     # size after compression
    'hRes':'l',         # horizontal pixels per inch
    'vRes':'l',         # vertical pixels per inch
    'pixelType':'h',    # pixel format
    'pixelSize':'h',    # bits per pixel
    'cmpCount':'h',     # color components per pixel
    'cmpSize':'h',      # bits per component
    'planeBytes':'l',   # offset in bytes to next plane
    'pmTable':'l',      # handle to color table
    'pmReserved':'l'    # reserved for future use
}

# PixMap data structure element offset
_pmElemOffset = {
    'baseAddr':0,
    'rowBytes':4,
    'bounds':6,
        'top':6,
        'left':8,
        'bottom':10,
        'right':12,
    'pmVersion':14,
    'packType':16,
    'packSize':18,
    'hRes':22,
    'vRes':26,
    'pixelType':30,
    'pixelSize':32,
    'cmpCount':34,
    'cmpSize':36,
    'planeBytes':38,
    'pmTable':42,
    'pmReserved':46
}

class PixMapWrapper:
    """PixMapWrapper -- wraps the QD PixMap object in a Python class,
    with methods to easily get/set various pixmap fields.  Note: Use the
    PixMap() method when passing to QD calls."""

    def __init__(self):
        self.__dict__['data'] = ''
        self._header = struct.pack("lhhhhhhhlllhhhhlll",
            id(self.data)+MacOS.string_id_to_buffer,
            0,                      # rowBytes
            0, 0, 0, 0,             # bounds
            0,                      # pmVersion
            0, 0,                   # packType, packSize
            72<<16, 72<<16,         # hRes, vRes
            QuickDraw.RGBDirect,    # pixelType
            16,                     # pixelSize
            2, 5,                   # cmpCount, cmpSize,
            0, 0, 0)                # planeBytes, pmTable, pmReserved
        self.__dict__['_pm'] = Qd.RawBitMap(self._header)
    
    def _stuff(self, element, bytes):
        offset = _pmElemOffset[element]
        fmt = _pmElemFormat[element]
        self._header = self._header[:offset] \
            + struct.pack(fmt, bytes) \
            + self._header[offset + struct.calcsize(fmt):]
        self.__dict__['_pm'] = None
    
    def _unstuff(self, element):
        offset = _pmElemOffset[element]
        fmt = _pmElemFormat[element]
        return struct.unpack(fmt, self._header[offset:offset+struct.calcsize(fmt)])[0]

    def __setattr__(self, attr, val):
        if attr == 'baseAddr':
            raise 'UseErr', "don't assign to .baseAddr -- assign to .data instead"
        elif attr == 'data':
            self.__dict__['data'] = val
            self._stuff('baseAddr', id(self.data) + MacOS.string_id_to_buffer)
        elif attr == 'rowBytes':
            # high bit is always set for some odd reason
            self._stuff('rowBytes', val | 0x8000)
        elif attr == 'bounds':
            # assume val is in official Left, Top, Right, Bottom order!
            self._stuff('left',val[0])
            self._stuff('top',val[1])
            self._stuff('right',val[2])
            self._stuff('bottom',val[3])
        elif attr == 'hRes' or attr == 'vRes':
            # 16.16 fixed format, so just shift 16 bits
            self._stuff(attr, int(val) << 16)
        elif attr in _pmElemFormat.keys():
            # any other pm attribute -- just stuff
            self._stuff(attr, val)
        else:
            self.__dict__[attr] = val   

    def __getattr__(self, attr):
        if attr == 'rowBytes':
            # high bit is always set for some odd reason
            return self._unstuff('rowBytes') & 0x7FFF
        elif attr == 'bounds':
            # return bounds in official Left, Top, Right, Bottom order!
            return ( \
                self._unstuff('left'),
                self._unstuff('top'),
                self._unstuff('right'),
                self._unstuff('bottom') )
        elif attr == 'hRes' or attr == 'vRes':
            # 16.16 fixed format, so just shift 16 bits
            return self._unstuff(attr) >> 16
        elif attr in _pmElemFormat.keys():
            # any other pm attribute -- just unstuff
            return self._unstuff(attr)
        else:
            return self.__dict__[attr]  

        
    def PixMap(self):
        "Return a QuickDraw PixMap corresponding to this data."
        if not self.__dict__['_pm']:
            self.__dict__['_pm'] = Qd.RawBitMap(self._header)
        return self.__dict__['_pm']

    def blit(self, x1=0,y1=0,x2=None,y2=None, port=None):
        """Draw this pixmap into the given (default current) grafport.""" 
        src = self.bounds
        dest = [x1,y1,x2,y2]
        if x2 == None:
            dest[2] = x1 + src[2]-src[0]
        if y2 == None:
            dest[3] = y1 + src[3]-src[1]
        if not port: port = Qd.GetPort()
        Qd.CopyBits(self.PixMap(), port.GetPortBitMapForCopyBits(), src, tuple(dest),
                QuickDraw.srcCopy, None)
    
    def fromstring(self,s,width,height,format=imgformat.macrgb):
        """Stuff this pixmap with raw pixel data from a string.
        Supply width, height, and one of the imgformat specifiers."""
        # we only support 16- and 32-bit mac rgb...
        # so convert if necessary
        if format != imgformat.macrgb and format != imgformat.macrgb16:
            # (LATER!)
            raise "NotImplementedError", "conversion to macrgb or macrgb16"
        self.data = s
        self.bounds = (0,0,width,height)
        self.cmpCount = 3
        self.pixelType = QuickDraw.RGBDirect
        if format == imgformat.macrgb:
            self.pixelSize = 32
            self.cmpSize = 8
        else:
            self.pixelSize = 16
            self.cmpSize = 5
        self.rowBytes = width*self.pixelSize/8

    def tostring(self, format=imgformat.macrgb):
        """Return raw data as a string in the specified format."""
        # is the native format requested?  if so, just return data
        if (format == imgformat.macrgb and self.pixelSize == 32) or \
           (format == imgformat.macrgb16 and self.pixelsize == 16):
            return self.data
        # otherwise, convert to the requested format
        # (LATER!)
            raise "NotImplementedError", "data format conversion"

    def fromImage(self,im):
        """Initialize this PixMap from a PIL Image object."""
        # We need data in ARGB format; PIL can't currently do that,
        # but it can do RGBA, which we can use by inserting one null
        # up frontpm = 
        if im.mode != 'RGBA': im = im.convert('RGBA')
        data = chr(0) + im.tostring()
        self.fromstring(data, im.size[0], im.size[1])

    def toImage(self):
        """Return the contents of this PixMap as a PIL Image object."""
        import Image
        # our tostring() method returns data in ARGB format,
        # whereas Image uses RGBA; a bit of slicing fixes this...
        data = self.tostring()[1:] + chr(0)
        bounds = self.bounds
        return Image.fromstring('RGBA',(bounds[2]-bounds[0],bounds[3]-bounds[1]),data)

def test():
    import MacOS
    import EasyDialogs
    import Image
    path = EasyDialogs.AskFileForOpen("Image File:")
    if not path: return
    pm = PixMapWrapper()
    pm.fromImage( Image.open(path) )
    pm.blit(20,20)
    return pm


--- NEW FILE: WASTEconst.py ---
# Generated from 'WASTE.h'

kPascalStackBased = None # workaround for header parsing
def FOUR_CHAR_CODE(x): return x
weCantUndoErr = -10015
weEmptySelectionErr = -10013
weUnknownObjectTypeErr = -9478
weObjectNotFoundErr = -9477
weReadOnlyErr = -9476
weTextNotFoundErr = -9474
weInvalidTextEncodingErr = -9473
weDuplicateAttributeErr = -9472
weInvalidAttributeSizeErr = -9471
weReadOnlyAttributeErr = -9470
weOddByteCountErr = -9469
weHandlerNotFoundErr = -1717
weNotHandledErr = -1708
weNewerVersionErr = -1706
weCorruptDataErr = -1702
weProtocolErr = -603
weUndefinedSelectorErr = -50
weFlushLeft = -2
weFlushRight = -1
weFlushDefault = 0
weCenter = 1
weJustify = 2
weDirDefault = 1
weDirRightToLeft = -1
weDirLeftToRight = 0
weDoFont = 0x0001
weDoFace = 0x0002
weDoSize = 0x0004
weDoColor = 0x0008
weDoAll = weDoFont | weDoFace | weDoSize | weDoColor
weDoAddSize = 0x0010
weDoToggleFace = 0x0020
weDoReplaceFace = 0x0040
weDoPreserveScript = 0x0080
weDoExtractSubscript = 0x0100
weDoFaceMask = 0x0200
weDoDirection = 0x00000001
weDoAlignment = 0x00000002
weDoLeftIndent = 0x00000004
weDoRightIndent = 0x00000008
weDoFirstLineIndent = 0x00000010
weDoLineSpacing = 0x00000020
weDoSpaceBefore = 0x00000040
weDoSpaceAfter = 0x00000080
weDoBottomBorderStyle = 0x00000400
kLeadingEdge = -1
kTrailingEdge = 0
kObjectEdge = 2
weFAutoScroll = 0
weFOutlineHilite = 2
weFReadOnly = 5
weFUndo = 6
weFIntCutAndPaste = 7
weFDragAndDrop = 8
weFInhibitRecal = 9
weFUseTempMem = 10
weFDrawOffscreen = 11
weFInhibitRedraw = 12
weFMonoStyled = 13
weFMultipleUndo = 14
weFNoKeyboardSync = 29
weFInhibitICSupport = 30
weFInhibitColor = 31
weDoAutoScroll = 1 << weFAutoScroll
weDoOutlineHilite = 1 << weFOutlineHilite
weDoReadOnly = 1 << weFReadOnly
weDoUndo = 1 << weFUndo
weDoIntCutAndPaste = 1 << weFIntCutAndPaste
weDoDragAndDrop = 1 << weFDragAndDrop
weDoInhibitRecal = 1 << weFInhibitRecal
weDoUseTempMem = 1 << weFUseTempMem
weDoDrawOffscreen = 1 << weFDrawOffscreen
weDoInhibitRedraw = 1 << weFInhibitRedraw
weDoMonoStyled = 1 << weFMonoStyled
weDoMultipleUndo = 1 << weFMultipleUndo
weDoNoKeyboardSync = 1 << weFNoKeyboardSync
weDoInhibitICSupport = 1 << weFInhibitICSupport
# weDoInhibitColor = 1 << weFInhibitColor
weBitToggle = -2
weBitTest = -1
weBitClear = 0
weBitSet = 1
weLowerCase = 0
weUpperCase = 1
weFindWholeWords = 0x00000001
weFindCaseInsensitive = 0x00000002
weFindDiacriticalInsensitive = 0x00000004
wePutIntCutAndPaste = 0x00000001
wePutAddToTypingSequence = 0x00000002
wePutDetectUnicodeBOM = 0x00000200
weStreamDestinationKindMask = 0x000000FF
weStreamIncludeObjects = 0x00000100
weGetAddUnicodeBOM = 0x00000200
weGetLittleEndian = 0x00000400
weTagFontFamily = FOUR_CHAR_CODE('font')
weTagFontSize = FOUR_CHAR_CODE('ptsz')
weTagPlain = FOUR_CHAR_CODE('plan')
weTagBold = FOUR_CHAR_CODE('bold')
weTagItalic = FOUR_CHAR_CODE('ital')
weTagUnderline = FOUR_CHAR_CODE('undl')
weTagOutline = FOUR_CHAR_CODE('outl')
weTagShadow = FOUR_CHAR_CODE('shad')
weTagCondensed = FOUR_CHAR_CODE('cond')
weTagExtended = FOUR_CHAR_CODE('pexp')
weTagStrikethrough = FOUR_CHAR_CODE('strk')
weTagTextColor = FOUR_CHAR_CODE('colr')
weTagBackgroundColor = FOUR_CHAR_CODE('pbcl')
weTagTransferMode = FOUR_CHAR_CODE('pptm')
weTagVerticalShift = FOUR_CHAR_CODE('xshf')
weTagAlignment = FOUR_CHAR_CODE('pjst')
weTagDirection = FOUR_CHAR_CODE('LDIR')
weTagLineSpacing = FOUR_CHAR_CODE('ledg')
weTagLeftIndent = FOUR_CHAR_CODE('lein')
weTagRightIndent = FOUR_CHAR_CODE('riin')
weTagFirstLineIndent = FOUR_CHAR_CODE('fidt')
weTagSpaceBefore = FOUR_CHAR_CODE('spbe')
weTagSpaceAfter = FOUR_CHAR_CODE('spaf')
weTagBottomBorderStyle = FOUR_CHAR_CODE('BBRD')
weTagForceFontFamily = FOUR_CHAR_CODE('ffnt')
weTagAddFontSize = FOUR_CHAR_CODE('+siz')
weTagAddVerticalShift = FOUR_CHAR_CODE('+shf')
weTagTextEncoding = FOUR_CHAR_CODE('ptxe')
weTagQDStyles = FOUR_CHAR_CODE('qdst')
weTagTETextStyle = FOUR_CHAR_CODE('tets')
weTagAlignmentDefault = FOUR_CHAR_CODE('deft')
weTagAlignmentLeft = FOUR_CHAR_CODE('left')
weTagAlignmentCenter = FOUR_CHAR_CODE('cent')
weTagAlignmentRight = FOUR_CHAR_CODE('rght')
weTagAlignmentFull = FOUR_CHAR_CODE('full')
weTagDirectionDefault = FOUR_CHAR_CODE('deft')
weTagDirectionLeftToRight = FOUR_CHAR_CODE('L->R')
weTagDirectionRightToLeft = FOUR_CHAR_CODE('R->L')
weTagBorderStyleNone = FOUR_CHAR_CODE('NONE')
weTagBorderStyleThin = FOUR_CHAR_CODE('SLDL')
weTagBorderStyleDotted = FOUR_CHAR_CODE('DTDL')
weTagBorderStyleThick = FOUR_CHAR_CODE('THKL')
weLineSpacingSingle = 0x00000000
weLineSpacingOneAndHalf = 0x00008000
weLineSpacingDouble = 0x00010000
weCharByteHook = FOUR_CHAR_CODE('cbyt')
weCharToPixelHook = FOUR_CHAR_CODE('c2p ')
weCharTypeHook = FOUR_CHAR_CODE('ctyp')
weClickLoop = FOUR_CHAR_CODE('clik')
weCurrentDrag = FOUR_CHAR_CODE('drag')
weDrawTextHook = FOUR_CHAR_CODE('draw')
weDrawTSMHiliteHook = FOUR_CHAR_CODE('dtsm')
weEraseHook = FOUR_CHAR_CODE('eras')
weFontFamilyToNameHook = FOUR_CHAR_CODE('ff2n')
weFontNameToFamilyHook = FOUR_CHAR_CODE('fn2f')
weFluxProc = FOUR_CHAR_CODE('flux')
weHiliteDropAreaHook = FOUR_CHAR_CODE('hidr')
weLineBreakHook = FOUR_CHAR_CODE('lbrk')
wePixelToCharHook = FOUR_CHAR_CODE('p2c ')
wePort = FOUR_CHAR_CODE('port')
wePreTrackDragHook = FOUR_CHAR_CODE('ptrk')
weRefCon = FOUR_CHAR_CODE('refc')
weScrollProc = FOUR_CHAR_CODE('scrl')
weText = FOUR_CHAR_CODE('text')
weTranslateDragHook = FOUR_CHAR_CODE('xdrg')
weTranslucencyThreshold = FOUR_CHAR_CODE('tluc')
weTSMDocumentID = FOUR_CHAR_CODE('tsmd')
weTSMPreUpdate = FOUR_CHAR_CODE('pre ')
weTSMPostUpdate = FOUR_CHAR_CODE('post')
weURLHint = FOUR_CHAR_CODE('urlh')
weWordBreakHook = FOUR_CHAR_CODE('wbrk')
weNewHandler = FOUR_CHAR_CODE('new ')
weDisposeHandler = FOUR_CHAR_CODE('free')
weDrawHandler = FOUR_CHAR_CODE('draw')
weClickHandler = FOUR_CHAR_CODE('clik')
weStreamHandler = FOUR_CHAR_CODE('strm')
weHoverHandler = FOUR_CHAR_CODE('hovr')
kTypeText = FOUR_CHAR_CODE('TEXT')
kTypeStyles = FOUR_CHAR_CODE('styl')
kTypeSoup = FOUR_CHAR_CODE('SOUP')
kTypeFontTable = FOUR_CHAR_CODE('FISH')
kTypeParaFormat = FOUR_CHAR_CODE('WEpf')
kTypeRulerScrap = FOUR_CHAR_CODE('WEru')
kTypeCharFormat = FOUR_CHAR_CODE('WEcf')
kTypeStyleScrap = FOUR_CHAR_CODE('WEst')
kTypeUnicodeText = FOUR_CHAR_CODE('utxt')
kTypeUTF8Text = FOUR_CHAR_CODE('UTF8')
kTypeStyledText = FOUR_CHAR_CODE('STXT')
weAKNone = 0
weAKUnspecified = 1
weAKTyping = 2
weAKCut = 3
weAKPaste = 4
weAKClear = 5
weAKDrag = 6
weAKSetStyle = 7
weAKSetRuler = 8
weAKBackspace = 9
weAKFwdDelete = 10
weAKCaseChange = 11
weAKObjectChange = 12
weToScrap = 0
weToDrag = 1
weToSoup = 2
weMouseEnter = 0
weMouseWithin = 1
weMouseLeave = 2
kCurrentSelection = -1
kNullStyle = -2

--- NEW FILE: aepack.py ---
"""Tools for use in AppleEvent clients and servers:
conversion between AE types and python types

pack(x) converts a Python object to an AEDesc object
unpack(desc) does the reverse
coerce(x, wanted_sample) coerces a python object to another python object
"""

#
# This code was originally written by Guido, and modified/extended by Jack
# to include the various types that were missing. The reference used is
# Apple Event Registry, chapter 9.
#

import struct
import string
import types
from string import strip
from types import *
from Carbon import AE
from Carbon.AppleEvents import *
import MacOS
import Carbon.File
import StringIO
import aetypes
from aetypes import mkenum, ObjectSpecifier
import os

# These ones seem to be missing from AppleEvents
# (they're in AERegistry.h)

#typeColorTable = 'clrt'
#typeDrawingArea = 'cdrw'
#typePixelMap = 'cpix'
#typePixelMapMinus = 'tpmm'
#typeRotation = 'trot'
#typeTextStyles = 'tsty'
#typeStyledText = 'STXT'
#typeAEText = 'tTXT'
#typeEnumeration = 'enum'

#
# Some AE types are immedeately coerced into something
# we like better (and which is equivalent)
#
unpacker_coercions = {
    typeComp : typeFloat,
    typeColorTable : typeAEList,
    typeDrawingArea : typeAERecord,
    typeFixed : typeFloat,
    typeExtended : typeFloat,
    typePixelMap : typeAERecord,
    typeRotation : typeAERecord,
    typeStyledText : typeAERecord,
    typeTextStyles : typeAERecord,
};

#
# Some python types we need in the packer:
#
AEDescType = AE.AEDescType
FSSType = Carbon.File.FSSpecType
FSRefType = Carbon.File.FSRefType
AliasType = Carbon.File.AliasType

def packkey(ae, key, value):
    if hasattr(key, 'which'):
        keystr = key.which
    elif hasattr(key, 'want'):
        keystr = key.want
    else:
        keystr = key
    ae.AEPutParamDesc(keystr, pack(value))

def pack(x, forcetype = None):
    """Pack a python object into an AE descriptor"""
    
    if forcetype:
        if type(x) is StringType:
            return AE.AECreateDesc(forcetype, x)
        else:
            return pack(x).AECoerceDesc(forcetype)
            
    if x == None:
        return AE.AECreateDesc('null', '')
        
    if isinstance(x, AEDescType):
        return x
    if isinstance(x, FSSType):
        return AE.AECreateDesc('fss ', x.data)
    if isinstance(x, FSRefType):
        return AE.AECreateDesc('fsrf', x.data)
    if isinstance(x, AliasType):
        return AE.AECreateDesc('alis', x.data)
    if isinstance(x, IntType):
        return AE.AECreateDesc('long', struct.pack('l', x))
    if isinstance(x, FloatType):
        return AE.AECreateDesc('doub', struct.pack('d', x))
    if isinstance(x, StringType):
        return AE.AECreateDesc('TEXT', x)
    if isinstance(x, UnicodeType):
        data = x.encode('utf16')
        if data[:2] == '\xfe\xff':
            data = data[2:]
        return AE.AECreateDesc('utxt', data)
    if isinstance(x, ListType):
        list = AE.AECreateList('', 0)
        for item in x:
            list.AEPutDesc(0, pack(item))
        return list
    if isinstance(x, DictionaryType):
        record = AE.AECreateList('', 1)
        for key, value in x.items():
            packkey(record, key, value)
            #record.AEPutParamDesc(key, pack(value))
        return record
    if type(x) == types.ClassType and issubclass(x, ObjectSpecifier):
        # Note: we are getting a class object here, not an instance
        return AE.AECreateDesc('type', x.want)
    if hasattr(x, '__aepack__'):
        return x.__aepack__()
    if hasattr(x, 'which'):
        return AE.AECreateDesc('TEXT', x.which)
    if hasattr(x, 'want'):
        return AE.AECreateDesc('TEXT', x.want)
    return AE.AECreateDesc('TEXT', repr(x)) # Copout

def unpack(desc, formodulename=""):
    """Unpack an AE descriptor to a python object"""
    t = desc.type
    
    if unpacker_coercions.has_key(t):
        desc = desc.AECoerceDesc(unpacker_coercions[t])
        t = desc.type # This is a guess by Jack....
    
    if t == typeAEList:
        l = []
        for i in range(desc.AECountItems()):
            keyword, item = desc.AEGetNthDesc(i+1, '****')
            l.append(unpack(item, formodulename))
        return l
    if t == typeAERecord:
        d = {}
        for i in range(desc.AECountItems()):
            keyword, item = desc.AEGetNthDesc(i+1, '****')
            d[keyword] = unpack(item, formodulename)
        return d
    if t == typeAEText:
        record = desc.AECoerceDesc('reco')
        return mkaetext(unpack(record, formodulename))
    if t == typeAlias:
        return Carbon.File.Alias(rawdata=desc.data)
    # typeAppleEvent returned as unknown
    if t == typeBoolean:
        return struct.unpack('b', desc.data)[0]
    if t == typeChar:
        return desc.data
    if t == typeUnicodeText:
        return unicode(desc.data, 'utf16')
    # typeColorTable coerced to typeAEList
    # typeComp coerced to extended
    # typeData returned as unknown
    # typeDrawingArea coerced to typeAERecord
    if t == typeEnumeration:
        return mkenum(desc.data)
    # typeEPS returned as unknown
    if t == typeFalse:
        return 0
    if t == typeFloat:
        data = desc.data
        return struct.unpack('d', data)[0]
    if t == typeFSS:
        return Carbon.File.FSSpec(rawdata=desc.data)
    if t == typeFSRef:
        return Carbon.File.FSRef(rawdata=desc.data)
    if t == typeInsertionLoc:
        record = desc.AECoerceDesc('reco')
        return mkinsertionloc(unpack(record, formodulename))
    # typeInteger equal to typeLongInteger
    if t == typeIntlText:
        script, language = struct.unpack('hh', desc.data[:4])
        return aetypes.IntlText(script, language, desc.data[4:])
    if t == typeIntlWritingCode:
        script, language = struct.unpack('hh', desc.data)
        return aetypes.IntlWritingCode(script, language)
    if t == typeKeyword:
        return mkkeyword(desc.data)
    if t == typeLongInteger:
        return struct.unpack('l', desc.data)[0]
    if t == typeLongDateTime:
        a, b = struct.unpack('lL', desc.data)
        return (long(a) << 32) + b
    if t == typeNull:
        return None
    if t == typeMagnitude:
        v = struct.unpack('l', desc.data)
        if v < 0:
            v = 0x100000000L + v
        return v
    if t == typeObjectSpecifier:
        record = desc.AECoerceDesc('reco')
        # If we have been told the name of the module we are unpacking aedescs for,
        # we can attempt to create the right type of python object from that module.
        if formodulename:
            return mkobjectfrommodule(unpack(record, formodulename), formodulename)
        return mkobject(unpack(record, formodulename))
    # typePict returned as unknown
    # typePixelMap coerced to typeAERecord
    # typePixelMapMinus returned as unknown
    # typeProcessSerialNumber returned as unknown
    if t == typeQDPoint:
        v, h = struct.unpack('hh', desc.data)
        return aetypes.QDPoint(v, h)
    if t == typeQDRectangle:
        v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
        return aetypes.QDRectangle(v0, h0, v1, h1)
    if t == typeRGBColor:
        r, g, b = struct.unpack('hhh', desc.data)
        return aetypes.RGBColor(r, g, b)
    # typeRotation coerced to typeAERecord
    # typeScrapStyles returned as unknown
    # typeSessionID returned as unknown
    if t == typeShortFloat:
        return struct.unpack('f', desc.data)[0]
    if t == typeShortInteger:
        return struct.unpack('h', desc.data)[0]
    # typeSMFloat identical to typeShortFloat
    # typeSMInt indetical to typeShortInt
    # typeStyledText coerced to typeAERecord
    if t == typeTargetID:
        return mktargetid(desc.data)
    # typeTextStyles coerced to typeAERecord
    # typeTIFF returned as unknown
    if t == typeTrue:
        return 1
    if t == typeType:
        return mktype(desc.data, formodulename)
    #
    # The following are special
    #
    if t == 'rang':
        record = desc.AECoerceDesc('reco')
        return mkrange(unpack(record, formodulename))
    if t == 'cmpd':
        record = desc.AECoerceDesc('reco')
        return mkcomparison(unpack(record, formodulename))
    if t == 'logi':
        record = desc.AECoerceDesc('reco')
        return mklogical(unpack(record, formodulename))
    return mkunknown(desc.type, desc.data)
    
def coerce(data, egdata):
    """Coerce a python object to another type using the AE coercers"""
    pdata = pack(data)
    pegdata = pack(egdata)
    pdata = pdata.AECoerceDesc(pegdata.type)
    return unpack(pdata)

#
# Helper routines for unpack
#
def mktargetid(data):
    sessionID = getlong(data[:4])
    name = mkppcportrec(data[4:4+72])
    location = mklocationnamerec(data[76:76+36])
    rcvrName = mkppcportrec(data[112:112+72])
    return sessionID, name, location, rcvrName

def mkppcportrec(rec):
    namescript = getword(rec[:2])
    name = getpstr(rec[2:2+33])
    portkind = getword(rec[36:38])
    if portkind == 1:
        ctor = rec[38:42]
        type = rec[42:46]
        identity = (ctor, type)
    else:
        identity = getpstr(rec[38:38+33])
    return namescript, name, portkind, identity

def mklocationnamerec(rec):
    kind = getword(rec[:2])
    stuff = rec[2:]
    if kind == 0: stuff = None
    if kind == 2: stuff = getpstr(stuff)
    return kind, stuff

def mkunknown(type, data):
    return aetypes.Unknown(type, data)

def getpstr(s):
    return s[1:1+ord(s[0])]

def getlong(s):
    return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])

def getword(s):
    return (ord(s[0])<<8) | (ord(s[1])<<0)

def mkkeyword(keyword):
    return aetypes.Keyword(keyword)

def mkrange(dict):
    return aetypes.Range(dict['star'], dict['stop'])

def mkcomparison(dict):
    return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])

def mklogical(dict):
    return aetypes.Logical(dict['logc'], dict['term'])

def mkstyledtext(dict):
    return aetypes.StyledText(dict['ksty'], dict['ktxt'])
    
def mkaetext(dict):
    return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
    
def mkinsertionloc(dict):
    return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])

def mkobject(dict):
    want = dict['want'].type
    form = dict['form'].enum
    seld = dict['seld']
    fr   = dict['from']
    if form in ('name', 'indx', 'rang', 'test'):
        if want == 'text': return aetypes.Text(seld, fr)
        if want == 'cha ': return aetypes.Character(seld, fr)
        if want == 'cwor': return aetypes.Word(seld, fr)
        if want == 'clin': return aetypes.Line(seld, fr)
        if want == 'cpar': return aetypes.Paragraph(seld, fr)
        if want == 'cwin': return aetypes.Window(seld, fr)
        if want == 'docu': return aetypes.Document(seld, fr)
        if want == 'file': return aetypes.File(seld, fr)
        if want == 'cins': return aetypes.InsertionPoint(seld, fr)
    if want == 'prop' and form == 'prop' and aetypes.IsType(seld):
        return aetypes.Property(seld.type, fr)
    return aetypes.ObjectSpecifier(want, form, seld, fr)

# Note by Jack: I'm not 100% sure of the following code. This was
# provided by Donovan Preston, but I wonder whether the assignment
# to __class__ is safe. Moreover, shouldn't there be a better
# initializer for the classes in the suites?
def mkobjectfrommodule(dict, modulename):
    if type(dict['want']) == types.ClassType and issubclass(dict['want'], ObjectSpecifier):
        # The type has already been converted to Python. Convert back:-(
        classtype = dict['want']
        dict['want'] = aetypes.mktype(classtype.want)
    want = dict['want'].type
    module = __import__(modulename)
    codenamemapper = module._classdeclarations
    classtype = codenamemapper.get(want, None)
    newobj = mkobject(dict)
    if classtype:
        assert issubclass(classtype, ObjectSpecifier)
        newobj.__class__ = classtype
    return newobj
    
def mktype(typecode, modulename=None):
    if modulename:
        module = __import__(modulename)
        codenamemapper = module._classdeclarations
        classtype = codenamemapper.get(typecode, None)
        if classtype:
            return classtype
    return aetypes.mktype(typecode)

--- NEW FILE: aetools.py ---
"""Tools for use in AppleEvent clients and servers.

pack(x) converts a Python object to an AEDesc object
unpack(desc) does the reverse

packevent(event, parameters, attributes) sets params and attrs in an AEAppleEvent record
unpackevent(event) returns the parameters and attributes from an AEAppleEvent record

Plus...  Lots of classes and routines that help representing AE objects,
ranges, conditionals, logicals, etc., so you can write, e.g.:

    x = Character(1, Document("foobar"))

and pack(x) will create an AE object reference equivalent to AppleScript's

    character 1 of document "foobar"

Some of the stuff that appears to be exported from this module comes from other
files: the pack stuff from aepack, the objects from aetypes.

"""


from types import *
from Carbon import AE
from Carbon import Evt
from Carbon import AppleEvents
import MacOS
import sys
import time

from aetypes import *
from aepack import packkey, pack, unpack, coerce, AEDescType

Error = 'aetools.Error'

# Amount of time to wait for program to be launched
LAUNCH_MAX_WAIT_TIME=10

# Special code to unpack an AppleEvent (which is *not* a disguised record!)
# Note by Jack: No??!? If I read the docs correctly it *is*....

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, formodulename=""):
    parameters = {}
    try:
        dirobj = ae.AEGetParamDesc('----', '****')
    except AE.Error:
        pass
    else:
        parameters['----'] = unpack(dirobj, formodulename)
        del dirobj
    # Workaround for what I feel is a bug in OSX 10.2: 'errn' won't show up in missed...
    try:
        dirobj = ae.AEGetParamDesc('errn', '****')
    except AE.Error:
        pass
    else:
        parameters['errn'] = unpack(dirobj, formodulename)
        del dirobj
    while 1:
        key = missed(ae)
        if not key: break
        parameters[key] = unpack(ae.AEGetParamDesc(key, '****'), formodulename)
    attributes = {}
    for key in aekeywords:
        try:
            desc = ae.AEGetAttributeDesc(key, '****')
        except (AE.Error, MacOS.Error), msg:
            if msg[0] != -1701 and msg[0] != -1704:
                raise
            continue
        attributes[key] = unpack(desc, formodulename)
    return parameters, attributes

def packevent(ae, parameters = {}, attributes = {}):
    for key, value in parameters.items():
        packkey(ae, key, value)
    for key, value in attributes.items():
        ae.AEPutAttributeDesc(key, pack(value))

#
# Support routine for automatically generated Suite interfaces
# These routines are also useable for the reverse function.
#
def keysubst(arguments, keydict):
    """Replace long name keys by their 4-char counterparts, and check"""
    ok = keydict.values()
    for k in arguments.keys():
        if keydict.has_key(k):
            v = arguments[k]
            del arguments[k]
            arguments[keydict[k]] = v
        elif k != '----' and k not in ok:
            raise TypeError, 'Unknown keyword argument: %s'%k
            
def enumsubst(arguments, key, edict):
    """Substitute a single enum keyword argument, if it occurs"""
    if not arguments.has_key(key) or edict is None:
        return
    v = arguments[key]
    ok = edict.values()
    if edict.has_key(v):
        arguments[key] = Enum(edict[v])
    elif not v in ok:
        raise TypeError, 'Unknown enumerator: %s'%v
        
def decodeerror(arguments):
    """Create the 'best' argument for a raise MacOS.Error"""
    errn = arguments['errn']
    err_a1 = errn
    if arguments.has_key('errs'):
        err_a2 = arguments['errs']
    else:
        err_a2 = MacOS.GetErrorString(errn)
    if arguments.has_key('erob'):
        err_a3 = arguments['erob']
    else:
        err_a3 = None
    
    return (err_a1, err_a2, err_a3)

class TalkTo:
    """An AE connection to an application"""
    _signature = None   # Can be overridden by subclasses
    _moduleName = None  # Can be overridden by subclasses
    _elemdict = {}      # Can be overridden by subclasses
    _propdict = {}      # Can be overridden by subclasses
    
    __eventloop_initialized = 0
    def __ensure_WMAvailable(klass):
        if klass.__eventloop_initialized: return 1
        if not MacOS.WMAvailable(): return 0
        # Workaround for a but in MacOSX 10.2: we must have an event
        # loop before we can call AESend.
        Evt.WaitNextEvent(0,0)
        return 1
    __ensure_WMAvailable = classmethod(__ensure_WMAvailable)
    
    def __init__(self, signature=None, start=0, timeout=0):
        """Create a communication channel with a particular application.
        
        Addressing the application is done by specifying either a
        4-byte signature, an AEDesc or an object that will __aepack__
        to an AEDesc.
        """
        self.target_signature = None
        if signature is None:
            signature = self._signature
        if type(signature) == AEDescType:
            self.target = signature
        elif type(signature) == InstanceType and hasattr(signature, '__aepack__'):
            self.target = signature.__aepack__()
        elif type(signature) == StringType and len(signature) == 4:
            self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature)
            self.target_signature = signature
        else:
            raise TypeError, "signature should be 4-char string or AEDesc"
        self.send_flags = AppleEvents.kAEWaitReply
        self.send_priority = AppleEvents.kAENormalPriority
        if timeout:
            self.send_timeout = timeout
        else:
            self.send_timeout = AppleEvents.kAEDefaultTimeout
        if start:
            self._start()
        
    def _start(self):
        """Start the application, if it is not running yet"""
        try:
            self.send('ascr', 'noop')
        except AE.Error:
            _launch(self.target_signature)
            for i in range(LAUNCH_MAX_WAIT_TIME):
                try:
                    self.send('ascr', 'noop')
                except AE.Error:
                    pass
                else:
                    break
                time.sleep(1)
            
    def start(self):
        """Deprecated, used _start()"""
        self._start()
            
    def newevent(self, code, subcode, parameters = {}, attributes = {}):
        """Create a complete structure for an apple event"""
        
        event = AE.AECreateAppleEvent(code, subcode, self.target,
                  AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID)
        packevent(event, parameters, attributes)
        return event
    
    def sendevent(self, event):
        """Send a pre-created appleevent, await the reply and unpack it"""
        if not self.__ensure_WMAvailable():
            raise RuntimeError, "No window manager access, cannot send AppleEvent"
        reply = event.AESend(self.send_flags, self.send_priority,
                                  self.send_timeout)
        parameters, attributes = unpackevent(reply, self._moduleName)
        return reply, parameters, attributes
        
    def send(self, code, subcode, parameters = {}, attributes = {}):
        """Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
        return self.sendevent(self.newevent(code, subcode, parameters, attributes))
    
    #
    # The following events are somehow "standard" and don't seem to appear in any
    # suite...
    #
    def activate(self):
        """Send 'activate' command"""
        self.send('misc', 'actv')

    def _get(self, _object, as=None, _attributes={}):
        """_get: get data from an object
        Required argument: the object
        Keyword argument _attributes: AppleEvent attribute dictionary
        Returns: the data
        """
        _code = 'core'
        _subcode = 'getd'

        _arguments = {'----':_object}
        if as:
            _arguments['rtyp'] = mktype(as)

        _reply, _arguments, _attributes = self.send(_code, _subcode,
                _arguments, _attributes)
        if _arguments.has_key('errn'):
            raise Error, decodeerror(_arguments)

        if _arguments.has_key('----'):
            return _arguments['----']
            if as:
                item.__class__ = as
            return item
    
    get = _get
            
    _argmap_set = {
        'to' : 'data',
    }

    def _set(self, _object, _attributes={}, **_arguments):
        """set: Set an object's data.
        Required argument: the object for the command
        Keyword argument to: The new value.
        Keyword argument _attributes: AppleEvent attribute dictionary
        """
        _code = 'core'
        _subcode = 'setd'

        keysubst(_arguments, self._argmap_set)
        _arguments['----'] = _object


        _reply, _arguments, _attributes = self.send(_code, _subcode,
                _arguments, _attributes)
        if _arguments.get('errn', 0):
            raise Error, decodeerror(_arguments)
        # XXXX Optionally decode result
        if _arguments.has_key('----'):
            return _arguments['----']
            
    set = _set

    # Magic glue to allow suite-generated classes to function somewhat
    # like the "application" class in OSA.
    
    def __getattr__(self, name):
        if self._elemdict.has_key(name):
            cls = self._elemdict[name]
            return DelayedComponentItem(cls, None)
        if self._propdict.has_key(name):
            cls = self._propdict[name]
            return cls()
        raise AttributeError, name
        
# Tiny Finder class, for local use only

class _miniFinder(TalkTo):
    def open(self, _object, _attributes={}, **_arguments):
        """open: Open the specified object(s)
        Required argument: list of objects to open
        Keyword argument _attributes: AppleEvent attribute dictionary
        """
        _code = 'aevt'
        _subcode = 'odoc'

        if _arguments: raise TypeError, 'No optional args expected'
        _arguments['----'] = _object


        _reply, _arguments, _attributes = self.send(_code, _subcode,
                _arguments, _attributes)
        if _arguments.has_key('errn'):
            raise Error, decodeerror(_arguments)
        # XXXX Optionally decode result
        if _arguments.has_key('----'):
            return _arguments['----']
#pass
    
_finder = _miniFinder('MACS')

def _launch(appfile):
    """Open a file thru the finder. Specify file by name or fsspec"""
    _finder.open(_application_file(('ID  ', appfile)))


class _application_file(ComponentItem):
    """application file - An application's file on disk"""
    want = 'appf'
    
_application_file._propdict = {
}
_application_file._elemdict = {
}
    
# Test program
# XXXX Should test more, really...

def test():
    target = AE.AECreateDesc('sign', 'quil')
    ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0)
    print unpackevent(ae)
    raw_input(":")
    ae = AE.AECreateAppleEvent('core', 'getd', target, -1, 0)
    obj = Character(2, Word(1, Document(1)))
    print obj
    print repr(obj)
    packevent(ae, {'----': obj})
    params, attrs = unpackevent(ae)
    print params['----']
    raw_input(":")

if __name__ == '__main__':
    test()
    sys.exit(1)

--- NEW FILE: aetypes.py ---
"""aetypes - Python objects representing various AE types."""

from Carbon.AppleEvents import *
import struct
from types import *
import string

#
# convoluted, since there are cyclic dependencies between this file and
# aetools_convert.
#
def pack(*args, **kwargs):
    from aepack import pack
    return pack( *args, **kwargs)
    
def nice(s):
    """'nice' representation of an object"""
    if type(s) is StringType: return repr(s)
    else: return str(s)

class Unknown:
    """An uninterpreted AE object"""
    
    def __init__(self, type, data):
        self.type = type
        self.data = data
    
    def __repr__(self):
        return "Unknown(%r, %r)" % (self.type, self.data)
    
    def __aepack__(self):
        return pack(self.data, self.type)

class Enum:
    """An AE enumeration value"""
    
    def __init__(self, enum):
        self.enum = "%-4.4s" % str(enum)
    
    def __repr__(self):
        return "Enum(%r)" % (self.enum,)
    
    def __str__(self):
        return string.strip(self.enum)
    
    def __aepack__(self):
        return pack(self.enum, typeEnumeration)

def IsEnum(x):
    return isinstance(x, Enum)

def mkenum(enum):
    if IsEnum(enum): return enum
    return Enum(enum)

# Jack changed the way this is done
class InsertionLoc:
    def __init__(self, of, pos):
        self.of = of
        self.pos = pos
    
    def __repr__(self):
        return "InsertionLoc(%r, %r)" % (self.of, self.pos)
        
    def __aepack__(self):
        rec = {'kobj': self.of, 'kpos': self.pos}
        return pack(rec, forcetype='insl')
        
# Convenience functions for dsp:
def beginning(of):
    return InsertionLoc(of, Enum('bgng'))
    
def end(of):
    return InsertionLoc(of, Enum('end '))

class Boolean:
    """An AE boolean value"""
    
    def __init__(self, bool):
        self.bool = (not not bool)
    
    def __repr__(self):
        return "Boolean(%r)" % (self.bool,)
    
    def __str__(self):
        if self.bool:
            return "True"
        else:
            return "False"
    
    def __aepack__(self):
        return pack(struct.pack('b', self.bool), 'bool')

def IsBoolean(x):
    return isinstance(x, Boolean)

def mkboolean(bool):
    if IsBoolean(bool): return bool
    return Boolean(bool)

class Type:
    """An AE 4-char typename object"""
    
    def __init__(self, type):
        self.type = "%-4.4s" % str(type)
    
    def __repr__(self):
        return "Type(%r)" % (self.type,)
    
    def __str__(self):
        return string.strip(self.type)
    
    def __aepack__(self):
        return pack(self.type, typeType)

def IsType(x):
    return isinstance(x, Type)

def mktype(type):
    if IsType(type): return type
    return Type(type)


class Keyword:
    """An AE 4-char keyword object"""
    
    def __init__(self, keyword):
        self.keyword = "%-4.4s" % str(keyword)
    
    def __repr__(self):
        return "Keyword(%r)" % `self.keyword`
    
    def __str__(self):
        return string.strip(self.keyword)
    
    def __aepack__(self):
        return pack(self.keyword, typeKeyword)

def IsKeyword(x):
    return isinstance(x, Keyword)

class Range:
    """An AE range object"""
    
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop
    
    def __repr__(self):
        return "Range(%r, %r)" % (self.start, self.stop)
    
    def __str__(self):
        return "%s thru %s" % (nice(self.start), nice(self.stop))
    
    def __aepack__(self):
        return pack({'star': self.start, 'stop': self.stop}, 'rang')

def IsRange(x):
    return isinstance(x, Range)

class Comparison:
    """An AE Comparison"""
    
    def __init__(self, obj1, relo, obj2):
        self.obj1 = obj1
        self.relo = "%-4.4s" % str(relo)
        self.obj2 = obj2
    
    def __repr__(self):
        return "Comparison(%r, %r, %r)" % (self.obj1, self.relo, self.obj2)
    
    def __str__(self):
        return "%s %s %s" % (nice(self.obj1), string.strip(self.relo), nice(self.obj2))
    
    def __aepack__(self):
        return pack({'obj1': self.obj1,
                 'relo': mkenum(self.relo),
                 'obj2': self.obj2},
                'cmpd')

def IsComparison(x):
    return isinstance(x, Comparison)
    
class NComparison(Comparison):
    # The class attribute 'relo' must be set in a subclass
    
    def __init__(self, obj1, obj2):
        Comparison.__init__(obj1, self.relo, obj2)

class Ordinal:
    """An AE Ordinal"""
    
    def __init__(self, abso):
#       self.obj1 = obj1
        self.abso = "%-4.4s" % str(abso)
    
    def __repr__(self):
        return "Ordinal(%r)" % (self.abso,)
    
    def __str__(self):
        return "%s" % (string.strip(self.abso))
    
    def __aepack__(self):
        return pack(self.abso, 'abso')

def IsOrdinal(x):
    return isinstance(x, Ordinal)
    
class NOrdinal(Ordinal):
    # The class attribute 'abso' must be set in a subclass
    
    def __init__(self):
        Ordinal.__init__(self, self.abso)

class Logical:
    """An AE logical expression object"""
    
    def __init__(self, logc, term):
        self.logc = "%-4.4s" % str(logc)
        self.term = term
    
    def __repr__(self):
        return "Logical(%r, %r)" % (self.logc, self.term)
    
    def __str__(self):
        if type(self.term) == ListType and len(self.term) == 2:
            return "%s %s %s" % (nice(self.term[0]),
                                 string.strip(self.logc),
                                 nice(self.term[1]))
        else:
            return "%s(%s)" % (string.strip(self.logc), nice(self.term))
    
    def __aepack__(self):
        return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi')

def IsLogical(x):
    return isinstance(x, Logical)

class StyledText:
    """An AE object respresenting text in a certain style"""
    
    def __init__(self, style, text):
        self.style = style
        self.text = text
    
    def __repr__(self):
        return "StyledText(%r, %r)" % (self.style, self.text)
    
    def __str__(self):
        return self.text
    
    def __aepack__(self):
        return pack({'ksty': self.style, 'ktxt': self.text}, 'STXT')

def IsStyledText(x):
    return isinstance(x, StyledText)

class AEText:
    """An AE text object with style, script and language specified"""
    
    def __init__(self, script, style, text):
        self.script = script
        self.style = style
        self.text = text
    
    def __repr__(self):
        return "AEText(%r, %r, %r)" % (self.script, self.style, self.text)
    
    def __str__(self):
        return self.text
    
    def __aepack__(self):
        return pack({keyAEScriptTag: self.script, keyAEStyles: self.style,
                 keyAEText: self.text}, typeAEText)

def IsAEText(x):
    return isinstance(x, AEText)

class IntlText:
    """A text object with script and language specified"""
    
    def __init__(self, script, language, text):
        self.script = script
        self.language = language
        self.text = text
    
    def __repr__(self):
        return "IntlText(%r, %r, %r)" % (self.script, self.language, self.text)
    
    def __str__(self):
        return self.text
    
    def __aepack__(self):
        return pack(struct.pack('hh', self.script, self.language)+self.text,
            typeIntlText)

def IsIntlText(x):
    return isinstance(x, IntlText)

class IntlWritingCode:
    """An object representing script and language"""
    
    def __init__(self, script, language):
        self.script = script
        self.language = language
    
    def __repr__(self):
        return "IntlWritingCode(%r, %r)" % (self.script, self.language)
    
    def __str__(self):
        return "script system %d, language %d"%(self.script, self.language)
    
    def __aepack__(self):
        return pack(struct.pack('hh', self.script, self.language),
            typeIntlWritingCode)

def IsIntlWritingCode(x):
    return isinstance(x, IntlWritingCode)

class QDPoint:
    """A point"""
    
    def __init__(self, v, h):
        self.v = v
        self.h = h
    
    def __repr__(self):
        return "QDPoint(%r, %r)" % (self.v, self.h)
    
    def __str__(self):
        return "(%d, %d)"%(self.v, self.h)
    
    def __aepack__(self):
        return pack(struct.pack('hh', self.v, self.h),
            typeQDPoint)

def IsQDPoint(x):
    return isinstance(x, QDPoint)

class QDRectangle:
    """A rectangle"""
    
    def __init__(self, v0, h0, v1, h1):
        self.v0 = v0
        self.h0 = h0
        self.v1 = v1
        self.h1 = h1
    
    def __repr__(self):
        return "QDRectangle(%r, %r, %r, %r)" % (self.v0, self.h0, self.v1, self.h1)
    
    def __str__(self):
        return "(%d, %d)-(%d, %d)"%(self.v0, self.h0, self.v1, self.h1)
    
    def __aepack__(self):
        return pack(struct.pack('hhhh', self.v0, self.h0, self.v1, self.h1),
            typeQDRectangle)

def IsQDRectangle(x):
    return isinstance(x, QDRectangle)

class RGBColor:
    """An RGB color"""
    
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b
            
    def __repr__(self):
        return "RGBColor(%r, %r, %r)" % (self.r, self.g, self.b)
    
    def __str__(self):
        return "0x%x red, 0x%x green, 0x%x blue"% (self.r, self.g, self.b)
    
    def __aepack__(self):
        return pack(struct.pack('hhh', self.r, self.g, self.b),
            typeRGBColor)

def IsRGBColor(x):
    return isinstance(x, RGBColor)

class ObjectSpecifier:
    
    """A class for constructing and manipulation AE object specifiers in python.
    
    An object specifier is actually a record with four fields:
    
    key type    description
    --- ----    -----------
    
    'want'  type    4-char class code of thing we want,
            e.g. word, paragraph or property
    
    'form'  enum    how we specify which 'want' thing(s) we want,
            e.g. by index, by range, by name, or by property specifier
    
    'seld'  any which thing(s) we want,
            e.g. its index, its name, or its property specifier
    
    'from'  object  the object in which it is contained,
            or null, meaning look for it in the application
    
    Note that we don't call this class plain "Object", since that name
    is likely to be used by the application.
    """
    
    def __init__(self, want, form, seld, fr = None):
        self.want = want
        self.form = form
        self.seld = seld
        self.fr = fr
    
    def __repr__(self):
        s = "ObjectSpecifier(%r, %r, %r" % (self.want, self.form, self.seld)
        if self.fr:
            s = s + ", %r)" % (self.fr,)
        else:
            s = s + ")"
        return s
    
    def __aepack__(self):
        return pack({'want': mktype(self.want),
                 'form': mkenum(self.form),
                 'seld': self.seld,
                 'from': self.fr},
                'obj ')

def IsObjectSpecifier(x):
    return isinstance(x, ObjectSpecifier)


# Backwards compatability, sigh...
class Property(ObjectSpecifier):

    def __init__(self, which, fr = None, want='prop'):
        ObjectSpecifier.__init__(self, want, 'prop', mktype(which), fr)

    def __repr__(self):
        if self.fr:
            return "Property(%r, %r)" % (self.seld.type, self.fr)
        else:
            return "Property(%r)" % (self.seld.type,)
    
    def __str__(self):
        if self.fr:
            return "Property %s of %s" % (str(self.seld), str(self.fr))
        else:
            return "Property %s" % str(self.seld)


class NProperty(ObjectSpecifier):
    # Subclasses *must* self baseclass attributes:
    # want is the type of this property
    # which is the property name of this property

    def __init__(self, fr = None):
        #try:
        #   dummy = self.want
        #except:
        #   self.want = 'prop'
        self.want = 'prop'
        ObjectSpecifier.__init__(self, self.want, 'prop', 
                    mktype(self.which), fr)

    def __repr__(self):
        rv = "Property(%r" % (self.seld.type,)
        if self.fr:
            rv = rv + ", fr=%r" % (self.fr,)
        if self.want != 'prop':
            rv = rv + ", want=%r" % (self.want,)
        return rv + ")"
    
    def __str__(self):
        if self.fr:
            return "Property %s of %s" % (str(self.seld), str(self.fr))
        else:
            return "Property %s" % str(self.seld)


class SelectableItem(ObjectSpecifier):
    
    def __init__(self, want, seld, fr = None):
        t = type(seld)
        if t == StringType:
            form = 'name'
        elif IsRange(seld):
            form = 'rang'
        elif IsComparison(seld) or IsLogical(seld):
            form = 'test'
        elif t == TupleType:
            # Breakout: specify both form and seld in a tuple
            # (if you want ID or rele or somesuch)
            form, seld = seld
        else:
            form = 'indx'
        ObjectSpecifier.__init__(self, want, form, seld, fr)


class ComponentItem(SelectableItem):
    # Derived classes *must* set the *class attribute* 'want' to some constant
    # Also, dictionaries _propdict and _elemdict must be set to map property
    # and element names to the correct classes

    _propdict = {}
    _elemdict = {}
    def __init__(self, which, fr = None):
        SelectableItem.__init__(self, self.want, which, fr)
    
    def __repr__(self):
        if not self.fr:
            return "%s(%r)" % (self.__class__.__name__, self.seld)
        return "%s(%r, %r)" % (self.__class__.__name__, self.seld, self.fr)
    
    def __str__(self):
        seld = self.seld
        if type(seld) == StringType:
            ss = repr(seld)
        elif IsRange(seld):
            start, stop = seld.start, seld.stop
            if type(start) == InstanceType == type(stop) and \
               start.__class__ == self.__class__ == stop.__class__:
                ss = str(start.seld) + " thru " + str(stop.seld)
            else:
                ss = str(seld)
        else:
            ss = str(seld)
        s = "%s %s" % (self.__class__.__name__, ss)
        if self.fr: s = s + " of %s" % str(self.fr)
        return s
        
    def __getattr__(self, name):
        if self._elemdict.has_key(name):
            cls = self._elemdict[name]
            return DelayedComponentItem(cls, self)
        if self._propdict.has_key(name):
            cls = self._propdict[name]
            return cls(self)
        raise AttributeError, name
        
        
class DelayedComponentItem:
    def __init__(self, compclass, fr):
        self.compclass = compclass
        self.fr = fr
        
    def __call__(self, which):
        return self.compclass(which, self.fr)
        
    def __repr__(self):
        return "%s(???, %r)" % (self.__class__.__name__, self.fr)
        
    def __str__(self):
        return "selector for element %s of %s"%(self.__class__.__name__, str(self.fr))

template = """
class %s(ComponentItem): want = '%s'
"""

exec template % ("Text", 'text')
exec template % ("Character", 'cha ')
exec template % ("Word", 'cwor')
exec template % ("Line", 'clin')
exec template % ("paragraph", 'cpar')
exec template % ("Window", 'cwin')
exec template % ("Document", 'docu')
exec template % ("File", 'file')
exec template % ("InsertionPoint", 'cins')


--- NEW FILE: applesingle.py ---
r"""Routines to decode AppleSingle files
"""
import struct
import sys
try:
    import MacOS
    import Carbon.File
except:
    class MacOS:
        def openrf(path, mode):
            return open(path + '.rsrc', mode)
        openrf = classmethod(openrf)
    class Carbon:
        class File:
            class FSSpec:
                pass
            class FSRef:
                pass
            class Alias:
                pass

# all of the errors in this module are really errors in the input
# so I think it should test positive against ValueError.
class Error(ValueError):
    pass

# File header format: magic, version, unused, number of entries
AS_HEADER_FORMAT="LL16sh"
AS_HEADER_LENGTH=26
# The flag words for AppleSingle
AS_MAGIC=0x00051600
AS_VERSION=0x00020000

# Entry header format: id, offset, length
AS_ENTRY_FORMAT="lll"
AS_ENTRY_LENGTH=12

# The id values
AS_DATAFORK=1
AS_RESOURCEFORK=2
AS_IGNORE=(3,4,5,6,8,9,10,11,12,13,14,15)

class AppleSingle(object):
    datafork = None
    resourcefork = None

    def __init__(self, fileobj, verbose=False):
        header = fileobj.read(AS_HEADER_LENGTH)
        try:
            magic, version, ig, nentry = struct.unpack(AS_HEADER_FORMAT, header)
        except ValueError, arg:
            raise Error, "Unpack header error: %s" % (arg,)
        if verbose:
            print 'Magic:   0x%8.8x' % (magic,)
            print 'Version: 0x%8.8x' % (version,)
            print 'Entries: %d' % (nentry,)
        if magic != AS_MAGIC:
            raise Error, "Unknown AppleSingle magic number 0x%8.8x" % (magic,)
        if version != AS_VERSION:
            raise Error, "Unknown AppleSingle version number 0x%8.8x" % (version,)
        if nentry <= 0:
            raise Error, "AppleSingle file contains no forks"
        headers = [fileobj.read(AS_ENTRY_LENGTH) for i in xrange(nentry)]
        self.forks = []
        for hdr in headers:
            try:
                restype, offset, length = struct.unpack(AS_ENTRY_FORMAT, hdr)
            except ValueError, arg:
                raise Error, "Unpack entry error: %s" % (arg,)
            if verbose:
                print "Fork %d, offset %d, length %d" % (restype, offset, length)
            fileobj.seek(offset)
            data = fileobj.read(length)
            if len(data) != length:
                raise Error, "Short read: expected %d bytes got %d" % (length, len(data))
            self.forks.append((restype, data))
            if restype == AS_DATAFORK:
                self.datafork = data
            elif restype == AS_RESOURCEFORK:
                self.resourcefork = data
        
    def tofile(self, path, resonly=False):
        outfile = open(path, 'wb')
        data = False
        if resonly:
            if self.resourcefork is None:
                raise Error, "No resource fork found"
            fp = open(path, 'wb')
            fp.write(self.resourcefork)
            fp.close()
        elif (self.resourcefork is None and self.datafork is None):
            raise Error, "No useful forks found"
        else:
            if self.datafork is not None:
                fp = open(path, 'wb')
                fp.write(self.datafork)
                fp.close()
            if self.resourcefork is not None:
                fp = MacOS.openrf(path, '*wb')
                fp.write(self.resourcefork)
                fp.close()
    
def decode(infile, outpath, resonly=False, verbose=False):
    """decode(infile, outpath [, resonly=False, verbose=False])

    Creates a decoded file from an AppleSingle encoded file.
    If resonly is True, then it will create a regular file at 
    outpath containing only the resource fork from infile.
    Otherwise it will create an AppleDouble file at outpath
    with the data and resource forks from infile.  On platforms 
    without the MacOS module, it will create inpath and inpath+'.rsrc'
    with the data and resource forks respectively.

    """
    if not hasattr(infile, 'read'):
        if isinstance(infile, Carbon.File.Alias):
            infile = infile.ResolveAlias()[0]
        if isinstance(infile, (Carbon.File.FSSpec, Carbon.File.FSRef)):
            infile = infile.as_pathname()
        infile = open(infile, 'rb')

    as = AppleSingle(infile, verbose=verbose)
    as.tofile(outpath, resonly=resonly)
    
def _test():
    if len(sys.argv) < 3 or sys.argv[1] == '-r' and len(sys.argv) != 4:
        print 'Usage: applesingle.py [-r] applesinglefile decodedfile'
        sys.exit(1)
    if sys.argv[1] == '-r':
        resonly = True
        del sys.argv[1]
    else:
        resonly = False
    decode(sys.argv[1], sys.argv[2], resonly=resonly)
    
if __name__ == '__main__':
    _test()

--- NEW FILE: appletrawmain.py ---
# Emulate sys.argv and run __main__.py or __main__.pyc in an environment that
# is as close to "normal" as possible.
#
# This script is put into __rawmain__.pyc for applets that need argv
# emulation, by BuildApplet and friends.
#
import argvemulator
import os
import sys
import marshal

#
# Make sure we have an argv[0], and make _dir point to the Resources
# directory.
#
if not sys.argv or sys.argv[0][:1] == '-':
    # Insert our (guessed) name.
    _dir = os.path.split(sys.executable)[0] # removes "python"
    _dir = os.path.split(_dir)[0] # Removes "MacOS"
    _dir = os.path.join(_dir, 'Resources')
    sys.argv.insert(0, '__rawmain__')
else:
    _dir = os.path.split(sys.argv[0])[0]
#
# Add the Resources directory to the path. This is where files installed
# by BuildApplet.py with the --extra option show up, and if those files are 
# modules this sys.path modification is necessary to be able to import them.
#
sys.path.insert(0, _dir)
#
# Create sys.argv
#
argvemulator.ArgvCollector().mainloop()
#
# Find the real main program to run
#
__file__ = os.path.join(_dir, '__main__.py')
if os.path.exists(__file__):
    #
    # Setup something resembling a normal environment and go.
    #
    sys.argv[0] = __file__
    del argvemulator, os, sys, _dir
    execfile(__file__)
else:
    __file__ = os.path.join(_dir, '__main__.pyc')
    if os.path.exists(__file__):
        #
        # If we have only a .pyc file we read the code object from that
        #
        sys.argv[0] = __file__
        _fp = open(__file__, 'rb')
        _fp.read(8)
        __code__ = marshal.load(_fp)
        #
        # Again, we create an almost-normal environment (only __code__ is
        # funny) and go.
        #
        del argvemulator, os, sys, marshal, _dir, _fp
        exec __code__
    else:
        sys.stderr.write("%s: neither __main__.py nor __main__.pyc found\n"%sys.argv[0])
        sys.exit(1)

--- NEW FILE: appletrunner.py ---
#!/usr/bin/env python
# This file is meant as an executable script for running applets.
# BuildApplet will use it as the main executable in the .app bundle if
# we are not running in a framework build.

import os
import sys
for name in ["__rawmain__.py", "__rawmain__.pyc", "__main__.py", "__main__.pyc"]:
    realmain = os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])),
                      "Resources", name)
    if os.path.exists(realmain):
        break
else:
    sys.stderr.write("%s: cannot find applet main program\n" % sys.argv[0])
    sys.exit(1)
sys.argv.insert(1, realmain)
os.execve(sys.executable, sys.argv, os.environ)

--- NEW FILE: argvemulator.py ---
"""argvemulator - create sys.argv from OSA events. Used by applets that
want unix-style arguments.
"""

import sys
import traceback
from Carbon import AE
from Carbon.AppleEvents import *
from Carbon import Evt
from Carbon.Events import *
import aetools

class ArgvCollector:

    """A minimal FrameWork.Application-like class"""

    def __init__(self):
        self.quitting = 0
        self.ae_handlers = {}
        # Remove the funny -psn_xxx_xxx argument
        if len(sys.argv) > 1 and sys.argv[1][:4] == '-psn':
            del sys.argv[1]
        self.installaehandler('aevt', 'oapp', self.open_app)
        self.installaehandler('aevt', 'odoc', self.open_file)

    def installaehandler(self, classe, type, callback):
        AE.AEInstallEventHandler(classe, type, self.callback_wrapper)
        self.ae_handlers[(classe, type)] = callback

    def close(self):
        for classe, type in self.ae_handlers.keys():
            AE.AERemoveEventHandler(classe, type)

    def mainloop(self, mask = highLevelEventMask, timeout = 1*60):
        stoptime = Evt.TickCount() + timeout
        while not self.quitting and Evt.TickCount() < stoptime:
            self.dooneevent(mask, timeout)
        self.close()

    def _quit(self):
        self.quitting = 1

    def dooneevent(self, mask = highLevelEventMask, timeout = 1*60):
        got, event = Evt.WaitNextEvent(mask, timeout)
        if got:
            self.lowlevelhandler(event)

    def lowlevelhandler(self, event):
        what, message, when, where, modifiers = event
        h, v = where
        if what == kHighLevelEvent:
            try:
                AE.AEProcessAppleEvent(event)
            except AE.Error, err:
                msg = "High Level Event: %r %r" % (hex(message), hex(h | (v<<16)))
                print 'AE error: ', err
                print 'in', msg
                traceback.print_exc()
            return
        else:
            print "Unhandled event:", event

    def callback_wrapper(self, _request, _reply):
        _parameters, _attributes = aetools.unpackevent(_request)
        _class = _attributes['evcl'].type
        _type = _attributes['evid'].type

        if self.ae_handlers.has_key((_class, _type)):
            _function = self.ae_handlers[(_class, _type)]
        elif self.ae_handlers.has_key((_class, '****')):
            _function = self.ae_handlers[(_class, '****')]
        elif self.ae_handlers.has_key(('****', '****')):
            _function = self.ae_handlers[('****', '****')]
        else:
            raise 'Cannot happen: AE callback without handler', (_class, _type)

        # XXXX Do key-to-name mapping here

        _parameters['_attributes'] = _attributes
        _parameters['_class'] = _class
        _parameters['_type'] = _type
        if _parameters.has_key('----'):
            _object = _parameters['----']
            del _parameters['----']
            # The try/except that used to be here can mask programmer errors.
            # Let the program crash, the programmer can always add a **args
            # to the formal parameter list.
            rv = _function(_object, **_parameters)
        else:
            #Same try/except comment as above
            rv = _function(**_parameters)

        if rv == None:
            aetools.packevent(_reply, {})
        else:
            aetools.packevent(_reply, {'----':rv})

    def open_app(self, **args):
        self._quit()

    def open_file(self, _object=None, **args):
        for alias in _object:
            fsr = alias.FSResolveAlias(None)[0]
            pathname = fsr.as_pathname()
            sys.argv.append(pathname)
        self._quit()

    def other(self, _object=None, _class=None, _type=None, **args):
        print 'Ignore AppleEvent', (_class, _type), 'for', _object, 'Other args:', args

if __name__ == '__main__':
    ArgvCollector().mainloop()
    print "sys.argv=", sys.argv

--- NEW FILE: bgenlocations.py ---
#
# Local customizations for generating the Carbon interface modules.
# Edit this file to reflect where things should be on your system.
# Note that pathnames are unix-style for OSX MachoPython/unix-Python,
# but mac-style for MacPython, whether running on OS9 or OSX.
#

import sys, os

Error = "bgenlocations.Error"
#
# Where bgen is. For unix-Python bgen isn't installed, so you have to refer to
# the source tree here.
BGENDIR="/Users/jack/src/python/Tools/bgen/bgen"

#
# Where to find the Universal Header include files. If you have CodeWarrior
# installed you can use the Universal Headers from there, otherwise you can
# download them from the Apple website. Bgen can handle both unix- and mac-style
# end of lines, so don't worry about that.
#
INCLUDEDIR="/Users/jack/src/Universal/Interfaces/CIncludes"

#
# Where to put the python definitions files. Note that, on unix-Python,
# if you want to commit your changes to the CVS repository this should refer to
# your source directory, not your installed directory.
#
TOOLBOXDIR="/Users/jack/src/python/Lib/plat-mac/Carbon"

# Creator for C files:
CREATOR="CWIE"

if not os.path.exists(BGENDIR):
    raise Error, "Please fix bgenlocations.py, BGENDIR does not exist: %s" % BGENDIR
if not os.path.exists(INCLUDEDIR):
    raise Error, "Please fix bgenlocations.py, INCLUDEDIR does not exist: %s" % INCLUDEDIR
if not os.path.exists(TOOLBOXDIR):
    raise Error, "Please fix bgenlocations.py, TOOLBOXDIR does not exist: %s" % TOOLBOXDIR
    
# Sigh, due to the way these are used make sure they end with : or /.
if BGENDIR[-1] != os.sep:
    BGENDIR = BGENDIR + os.sep
if INCLUDEDIR[-1] != os.sep:
    INCLUDEDIR = INCLUDEDIR + os.sep
if TOOLBOXDIR[-1] != os.sep:
    TOOLBOXDIR = TOOLBOXDIR + os.sep
    

--- NEW FILE: buildtools.py ---
"""tools for BuildApplet and BuildApplication"""

import sys
import os
import string
import imp
import marshal
from Carbon import Res
import Carbon.Files
import Carbon.File
import MacOS
import macostools
import macresource
import EasyDialogs
import shutil


BuildError = "BuildError"

# .pyc file (and 'PYC ' resource magic number)
MAGIC = imp.get_magic()

# Template file (searched on sys.path)
TEMPLATE = "PythonInterpreter"

# Specification of our resource
RESTYPE = 'PYC '
RESNAME = '__main__'

# A resource with this name sets the "owner" (creator) of the destination
# It should also have ID=0. Either of these alone is not enough.
OWNERNAME = "owner resource"

# Default applet creator code
DEFAULT_APPLET_CREATOR="Pyta"

# OpenResFile mode parameters
READ = 1
WRITE = 2

# Parameter for FSOpenResourceFile
RESOURCE_FORK_NAME=Carbon.File.FSGetResourceForkName()

def findtemplate(template=None):
    """Locate the applet template along sys.path"""
    if MacOS.runtimemodel == 'macho':
        return None
    if not template:
        template=TEMPLATE
    for p in sys.path:
        file = os.path.join(p, template)
        try:
            file, d1, d2 = Carbon.File.FSResolveAliasFile(file, 1)
            break
        except (Carbon.File.Error, ValueError):
            continue
    else:
        raise BuildError, "Template %r not found on sys.path" % (template,)
    file = file.as_pathname()
    return file
    
def process(template, filename, destname, copy_codefragment=0, 
        rsrcname=None, others=[], raw=0, progress="default"):
    
    if progress == "default":
        progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120)
        progress.label("Compiling...")
        progress.inc(0)
    # check for the script name being longer than 32 chars. This may trigger a bug
    # on OSX that can destroy your sourcefile.
    if '#' in os.path.split(filename)[1]:
        raise BuildError, "BuildApplet could destroy your sourcefile on OSX, please rename: %s" % filename
    # Read the source and compile it
    # (there's no point overwriting the destination if it has a syntax error)
    
    fp = open(filename, 'rU')
    text = fp.read()
    fp.close()
    try:
        code = compile(text + '\n', filename, "exec")
    except SyntaxError, arg:
        raise BuildError, "Syntax error in script %s: %s" % (filename, arg)
    except EOFError:
        raise BuildError, "End-of-file in script %s" % (filename,)
    
    # Set the destination file name. Note that basename
    # does contain the whole filepath, only a .py is stripped.
    
    if string.lower(filename[-3:]) == ".py":
        basename = filename[:-3]
        if MacOS.runtimemodel != 'macho' and not destname:
            destname = basename
    else:
        basename = filename
        
    if not destname:
        if MacOS.runtimemodel == 'macho':
            destname = basename + '.app'
        else:
            destname = basename + '.applet'
    if not rsrcname:
        rsrcname = basename + '.rsrc'
        
    # Try removing the output file. This fails in MachO, but it should
    # do any harm.
    try:
        os.remove(destname)
    except os.error:
        pass
    process_common(template, progress, code, rsrcname, destname, 0, 
        copy_codefragment, raw, others, filename)
    

def update(template, filename, output):
    if MacOS.runtimemodel == 'macho':
        raise BuildError, "No updating yet for MachO applets"
    if progress:
        progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120)
    else:
        progress = None
    if not output:
        output = filename + ' (updated)'
    
    # Try removing the output file
    try:
        os.remove(output)
    except os.error:
        pass
    process_common(template, progress, None, filename, output, 1, 1)


def process_common(template, progress, code, rsrcname, destname, is_update, 
        copy_codefragment, raw=0, others=[], filename=None):
    if MacOS.runtimemodel == 'macho':
        return process_common_macho(template, progress, code, rsrcname, destname,
            is_update, raw, others, filename)
    if others:
        raise BuildError, "Extra files only allowed for MachoPython applets"
    # Create FSSpecs for the various files
    template_fsr, d1, d2 = Carbon.File.FSResolveAliasFile(template, 1)
    template = template_fsr.as_pathname()
    
    # Copy data (not resources, yet) from the template
    if progress:
        progress.label("Copy data fork...")
        progress.set(10)
    
    if copy_codefragment:
        tmpl = open(template, "rb")
        dest = open(destname, "wb")
        data = tmpl.read()
        if data:
            dest.write(data)
        dest.close()
        tmpl.close()
        del dest
        del tmpl
    
    # Open the output resource fork
    
    if progress:
        progress.label("Copy resources...")
        progress.set(20)
    try:
        output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
    except MacOS.Error:
        destdir, destfile = os.path.split(destname)
        Res.FSCreateResourceFile(destdir, unicode(destfile), RESOURCE_FORK_NAME)
        output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
    
    # Copy the resources from the target specific resource template, if any
    typesfound, ownertype = [], None
    try:
        input = Res.FSOpenResourceFile(rsrcname, RESOURCE_FORK_NAME, READ)
    except (MacOS.Error, ValueError):
        pass
        if progress:
            progress.inc(50)
    else:
        if is_update:
            skip_oldfile = ['cfrg']
        else:
            skip_oldfile = []
        typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress)
        Res.CloseResFile(input)
    
    # Check which resource-types we should not copy from the template
    skiptypes = []
    if 'vers' in typesfound: skiptypes.append('vers')
    if 'SIZE' in typesfound: skiptypes.append('SIZE')
    if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', 
            'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
    if not copy_codefragment:
        skiptypes.append('cfrg')
##  skipowner = (ownertype <> None)
    
    # Copy the resources from the template
    
    input = Res.FSOpenResourceFile(template, RESOURCE_FORK_NAME, READ)
    dummy, tmplowner = copyres(input, output, skiptypes, 1, progress)
        
    Res.CloseResFile(input)
##  if ownertype == None:
##      raise BuildError, "No owner resource found in either resource file or template"
    # Make sure we're manipulating the output resource file now
    
    Res.UseResFile(output)

    if ownertype == None:
        # No owner resource in the template. We have skipped the
        # Python owner resource, so we have to add our own. The relevant
        # bundle stuff is already included in the interpret/applet template.
        newres = Res.Resource('\0')
        newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource")
        ownertype = DEFAULT_APPLET_CREATOR
    
    if code:
        # Delete any existing 'PYC ' resource named __main__
        
        try:
            res = Res.Get1NamedResource(RESTYPE, RESNAME)
            res.RemoveResource()
        except Res.Error:
            pass
        
        # Create the raw data for the resource from the code object
        if progress:
            progress.label("Write PYC resource...")
            progress.set(120)
        
        data = marshal.dumps(code)
        del code
        data = (MAGIC + '\0\0\0\0') + data
        
        # Create the resource and write it
        
        id = 0
        while id < 128:
            id = Res.Unique1ID(RESTYPE)
        res = Res.Resource(data)
        res.AddResource(RESTYPE, id, RESNAME)
        attrs = res.GetResAttrs()
        attrs = attrs | 0x04    # set preload
        res.SetResAttrs(attrs)
        res.WriteResource()
        res.ReleaseResource()
    
    # Close the output file
    
    Res.CloseResFile(output)
    
    # Now set the creator, type and bundle bit of the destination.
    # Done with FSSpec's, FSRef FInfo isn't good enough yet (2.3a1+)
    dest_fss = Carbon.File.FSSpec(destname)
    dest_finfo = dest_fss.FSpGetFInfo()
    dest_finfo.Creator = ownertype
    dest_finfo.Type = 'APPL'
    dest_finfo.Flags = dest_finfo.Flags | Carbon.Files.kHasBundle | Carbon.Files.kIsShared
    dest_finfo.Flags = dest_finfo.Flags & ~Carbon.Files.kHasBeenInited
    dest_fss.FSpSetFInfo(dest_finfo)
    
    macostools.touched(destname)
    if progress:
        progress.label("Done.")
        progress.inc(0)

def process_common_macho(template, progress, code, rsrcname, destname, is_update, 
        raw=0, others=[], filename=None):
    # Check that we have a filename
    if filename is None:
        raise BuildError, "Need source filename on MacOSX"
    # First make sure the name ends in ".app"
    if destname[-4:] != '.app':
        destname = destname + '.app'
    # Now deduce the short name
    destdir, shortname = os.path.split(destname)
    if shortname[-4:] == '.app':
        # Strip the .app suffix
        shortname = shortname[:-4]
    # And deduce the .plist and .icns names
    plistname = None
    icnsname = None
    if rsrcname and rsrcname[-5:] == '.rsrc':
        tmp = rsrcname[:-5]
        plistname = tmp + '.plist'
        if os.path.exists(plistname):
            icnsname = tmp + '.icns'
            if not os.path.exists(icnsname):
                icnsname = None
        else:
            plistname = None
    if not icnsname:
        dft_icnsname = os.path.join(sys.prefix, 'Resources/Python.app/Contents/Resources/PythonApplet.icns')
        if os.path.exists(dft_icnsname):
            icnsname = dft_icnsname
    if not os.path.exists(rsrcname):
        rsrcname = None
    if progress:
        progress.label('Creating bundle...')
    import bundlebuilder
    builder = bundlebuilder.AppBuilder(verbosity=0)
    builder.mainprogram = filename
    builder.builddir = destdir
    builder.name = shortname
    if rsrcname:
        realrsrcname = macresource.resource_pathname(rsrcname)
        builder.files.append((realrsrcname, 
            os.path.join('Contents/Resources', os.path.basename(rsrcname))))
    for o in others:
        if type(o) == str:
            builder.resources.append(o)
        else:
            builder.files.append(o)
    if plistname:
        import plistlib
        builder.plist = plistlib.Plist.fromFile(plistname)
    if icnsname:
        builder.iconfile = icnsname
    if not raw:
        builder.argv_emulation = 1
    builder.setup()
    builder.build()
    if progress: 
        progress.label('Done.')
        progress.inc(0)
    
##  macostools.touched(dest_fss)

# Copy resources between two resource file descriptors.
# skip a resource named '__main__' or (if skipowner is set) with ID zero.
# Also skip resources with a type listed in skiptypes.
#
def copyres(input, output, skiptypes, skipowner, progress=None):
    ctor = None
    alltypes = []
    Res.UseResFile(input)
    ntypes = Res.Count1Types()
    progress_type_inc = 50/ntypes
    for itype in range(1, 1+ntypes):
        type = Res.Get1IndType(itype)
        if type in skiptypes:
            continue
        alltypes.append(type)
        nresources = Res.Count1Resources(type)
        progress_cur_inc = progress_type_inc/nresources
        for ires in range(1, 1+nresources):
            res = Res.Get1IndResource(type, ires)
            id, type, name = res.GetResInfo()
            lcname = string.lower(name)

            if lcname == OWNERNAME and id == 0:
                if skipowner:
                    continue # Skip this one
                else:
                    ctor = type
            size = res.size
            attrs = res.GetResAttrs()
            if progress:
                progress.label("Copy %s %d %s"%(type, id, name))
                progress.inc(progress_cur_inc)
            res.LoadResource()
            res.DetachResource()
            Res.UseResFile(output)
            try:
                res2 = Res.Get1Resource(type, id)
            except MacOS.Error:
                res2 = None
            if res2:
                if progress:
                    progress.label("Overwrite %s %d %s"%(type, id, name))
                    progress.inc(0)
                res2.RemoveResource()
            res.AddResource(type, id, name)
            res.WriteResource()
            attrs = attrs | res.GetResAttrs()
            res.SetResAttrs(attrs)
            Res.UseResFile(input)
    return alltypes, ctor

def copyapptree(srctree, dsttree, exceptlist=[], progress=None):
    names = []
    if os.path.exists(dsttree):
        shutil.rmtree(dsttree)
    os.mkdir(dsttree)
    todo = os.listdir(srctree)
    while todo:
        this, todo = todo[0], todo[1:]
        if this in exceptlist:
            continue
        thispath = os.path.join(srctree, this)
        if os.path.isdir(thispath):
            thiscontent = os.listdir(thispath)
            for t in thiscontent:
                todo.append(os.path.join(this, t))
        names.append(this)
    for this in names:
        srcpath = os.path.join(srctree, this)
        dstpath = os.path.join(dsttree, this)
        if os.path.isdir(srcpath):
            os.mkdir(dstpath)
        elif os.path.islink(srcpath):
            endpoint = os.readlink(srcpath)
            os.symlink(endpoint, dstpath)
        else:
            if progress:
                progress.label('Copy '+this)
                progress.inc(0)
            shutil.copy2(srcpath, dstpath)
            
def writepycfile(codeobject, cfile):
    import marshal
    fc = open(cfile, 'wb')
    fc.write('\0\0\0\0') # MAGIC placeholder, written later
    fc.write('\0\0\0\0') # Timestap placeholder, not needed
    marshal.dump(codeobject, fc)
    fc.flush()
    fc.seek(0, 0)
    fc.write(MAGIC)
    fc.close()


--- NEW FILE: bundlebuilder.py ---
#! /usr/bin/env python

"""\
bundlebuilder.py -- Tools to assemble MacOS X (application) bundles.

This module contains two classes to build so called "bundles" for
MacOS X. BundleBuilder is a general tool, AppBuilder is a subclass
specialized in building application bundles.

[Bundle|App]Builder objects are instantiated with a bunch of keyword
arguments, and have a build() method that will do all the work. See
the class doc strings for a description of the constructor arguments.

The module contains a main program that can be used in two ways:

  % python bundlebuilder.py [options] build
  % python buildapp.py [options] build

Where "buildapp.py" is a user-supplied setup.py-like script following
this model:

  from bundlebuilder import buildapp
  buildapp(<lots-of-keyword-args>)

"""


__all__ = ["BundleBuilder", "BundleBuilderError", "AppBuilder", "buildapp"]


import sys
import os, errno, shutil
import imp, marshal
import re
from copy import deepcopy
import getopt
from plistlib import Plist
from types import FunctionType as function

class BundleBuilderError(Exception): pass


class Defaults:

    """Class attributes that don't start with an underscore and are
    not functions or classmethods are (deep)copied to self.__dict__.
    This allows for mutable default values.
    """

    def __init__(self, **kwargs):
        defaults = self._getDefaults()
        defaults.update(kwargs)
        self.__dict__.update(defaults)

    def _getDefaults(cls):
        defaults = {}
        for base in cls.__bases__:
            if hasattr(base, "_getDefaults"):
                defaults.update(base._getDefaults())
        for name, value in cls.__dict__.items():
            if name[0] != "_" and not isinstance(value,
                    (function, classmethod)):
                defaults[name] = deepcopy(value)
        return defaults
    _getDefaults = classmethod(_getDefaults)


class BundleBuilder(Defaults):

    """BundleBuilder is a barebones class for assembling bundles. It
    knows nothing about executables or icons, it only copies files
    and creates the PkgInfo and Info.plist files.
    """

    # (Note that Defaults.__init__ (deep)copies these values to
    # instance variables. Mutable defaults are therefore safe.)

    # Name of the bundle, with or without extension.
    name = None

    # The property list ("plist")
    plist = Plist(CFBundleDevelopmentRegion = "English",
                  CFBundleInfoDictionaryVersion = "6.0")

    # The type of the bundle.
    type = "BNDL"
    # The creator code of the bundle.
    creator = None

    # the CFBundleIdentifier (this is used for the preferences file name)
    bundle_id = None

    # List of files that have to be copied to <bundle>/Contents/Resources.
    resources = []

    # List of (src, dest) tuples; dest should be a path relative to the bundle
    # (eg. "Contents/Resources/MyStuff/SomeFile.ext).
    files = []

    # List of shared libraries (dylibs, Frameworks) to bundle with the app
    # will be placed in Contents/Frameworks
    libs = []

    # Directory where the bundle will be assembled.
    builddir = "build"

    # Make symlinks instead copying files. This is handy during debugging, but
    # makes the bundle non-distributable.
    symlink = 0

    # Verbosity level.
    verbosity = 1

    def setup(self):
        # XXX rethink self.name munging, this is brittle.
        self.name, ext = os.path.splitext(self.name)
        if not ext:
            ext = ".bundle"
        bundleextension = ext
        # misc (derived) attributes
        self.bundlepath = pathjoin(self.builddir, self.name + bundleextension)

        plist = self.plist
        plist.CFBundleName = self.name
        plist.CFBundlePackageType = self.type
        if self.creator is None:
            if hasattr(plist, "CFBundleSignature"):
                self.creator = plist.CFBundleSignature
            else:
                self.creator = "????"
        plist.CFBundleSignature = self.creator
        if self.bundle_id:
            plist.CFBundleIdentifier = self.bundle_id
        elif not hasattr(plist, "CFBundleIdentifier"):
            plist.CFBundleIdentifier = self.name

    def build(self):
        """Build the bundle."""
        builddir = self.builddir
        if builddir and not os.path.exists(builddir):
            os.mkdir(builddir)
        self.message("Building %s" % repr(self.bundlepath), 1)
        if os.path.exists(self.bundlepath):
            shutil.rmtree(self.bundlepath)
        os.mkdir(self.bundlepath)
        self.preProcess()
        self._copyFiles()
        self._addMetaFiles()
        self.postProcess()
        self.message("Done.", 1)

    def preProcess(self):
        """Hook for subclasses."""
        pass
    def postProcess(self):
        """Hook for subclasses."""
        pass

    def _addMetaFiles(self):
        contents = pathjoin(self.bundlepath, "Contents")
        makedirs(contents)
        #
        # Write Contents/PkgInfo
        assert len(self.type) == len(self.creator) == 4, \
                "type and creator must be 4-byte strings."
        pkginfo = pathjoin(contents, "PkgInfo")
        f = open(pkginfo, "wb")
        f.write(self.type + self.creator)
        f.close()
        #
        # Write Contents/Info.plist
        infoplist = pathjoin(contents, "Info.plist")
        self.plist.write(infoplist)

    def _copyFiles(self):
        files = self.files[:]
        for path in self.resources:
            files.append((path, pathjoin("Contents", "Resources",
                os.path.basename(path))))
        for path in self.libs:
            files.append((path, pathjoin("Contents", "Frameworks",
                os.path.basename(path))))
        if self.symlink:
            self.message("Making symbolic links", 1)
            msg = "Making symlink from"
        else:
            self.message("Copying files", 1)
            msg = "Copying"
        files.sort()
        for src, dst in files:
            if os.path.isdir(src):
                self.message("%s %s/ to %s/" % (msg, src, dst), 2)
            else:
                self.message("%s %s to %s" % (msg, src, dst), 2)
            dst = pathjoin(self.bundlepath, dst)
            if self.symlink:
                symlink(src, dst, mkdirs=1)
            else:
                copy(src, dst, mkdirs=1)

    def message(self, msg, level=0):
        if level <= self.verbosity:
            indent = ""
            if level > 1:
                indent = (level - 1) * "  "
            sys.stderr.write(indent + msg + "\n")

    def report(self):
        # XXX something decent
        pass


if __debug__:
    PYC_EXT = ".pyc"
else:
    PYC_EXT = ".pyo"

MAGIC = imp.get_magic()
USE_ZIPIMPORT = "zipimport" in sys.builtin_module_names

# For standalone apps, we have our own minimal site.py. We don't need
# all the cruft of the real site.py.
SITE_PY = """\
import sys
if not %(semi_standalone)s:
    del sys.path[1:]  # sys.path[0] is Contents/Resources/
"""

if USE_ZIPIMPORT:
    ZIP_ARCHIVE = "Modules.zip"
    SITE_PY += "sys.path.append(sys.path[0] + '/%s')\n" % ZIP_ARCHIVE
    def getPycData(fullname, code, ispkg):
        if ispkg:
            fullname += ".__init__"
        path = fullname.replace(".", os.sep) + PYC_EXT
        return path, MAGIC + '\0\0\0\0' + marshal.dumps(code)

#
# Extension modules can't be in the modules zip archive, so a placeholder
# is added instead, that loads the extension from a specified location.
#
EXT_LOADER = """\
def __load():
    import imp, sys, os
    for p in sys.path:
        path = os.path.join(p, "%(filename)s")
        if os.path.exists(path):
            break
    else:
        assert 0, "file not found: %(filename)s"
    mod = imp.load_dynamic("%(name)s", path)

__load()
del __load
"""

MAYMISS_MODULES = ['mac', 'os2', 'nt', 'ntpath', 'dos', 'dospath',
    'win32api', 'ce', '_winreg', 'nturl2path', 'sitecustomize',
    'org.python.core', 'riscos', 'riscosenviron', 'riscospath'
]

STRIP_EXEC = "/usr/bin/strip"

#
# We're using a stock interpreter to run the app, yet we need
# a way to pass the Python main program to the interpreter. The
# bootstrapping script fires up the interpreter with the right
# arguments. os.execve() is used as OSX doesn't like us to
# start a real new process. Also, the executable name must match
# the CFBundleExecutable value in the Info.plist, so we lie
# deliberately with argv[0]. The actual Python executable is
# passed in an environment variable so we can "repair"
# sys.executable later.
#
BOOTSTRAP_SCRIPT = """\
#!%(hashbang)s

import sys, os
execdir = os.path.dirname(sys.argv[0])
executable = os.path.join(execdir, "%(executable)s")
resdir = os.path.join(os.path.dirname(execdir), "Resources")
libdir = os.path.join(os.path.dirname(execdir), "Frameworks")
mainprogram = os.path.join(resdir, "%(mainprogram)s")

sys.argv.insert(1, mainprogram)
if %(standalone)s or %(semi_standalone)s:
    os.environ["PYTHONPATH"] = resdir
    if %(standalone)s:
        os.environ["PYTHONHOME"] = resdir
else:
    pypath = os.getenv("PYTHONPATH", "")
    if pypath:
        pypath = ":" + pypath
    os.environ["PYTHONPATH"] = resdir + pypath
os.environ["PYTHONEXECUTABLE"] = executable
os.environ["DYLD_LIBRARY_PATH"] = libdir
os.environ["DYLD_FRAMEWORK_PATH"] = libdir
os.execve(executable, sys.argv, os.environ)
"""


#
# Optional wrapper that converts "dropped files" into sys.argv values.
#
ARGV_EMULATOR = """\
import argvemulator, os

argvemulator.ArgvCollector().mainloop()
execfile(os.path.join(os.path.split(__file__)[0], "%(realmainprogram)s"))
"""

#
# When building a standalone app with Python.framework, we need to copy
# a subset from Python.framework to the bundle. The following list
# specifies exactly what items we'll copy.
#
PYTHONFRAMEWORKGOODIES = [
    "Python",  # the Python core library
    "Resources/English.lproj",
    "Resources/Info.plist",
    "Resources/version.plist",
]

def isFramework():
    return sys.exec_prefix.find("Python.framework") > 0


LIB = os.path.join(sys.prefix, "lib", "python" + sys.version[:3])
SITE_PACKAGES = os.path.join(LIB, "site-packages")


class AppBuilder(BundleBuilder):

    # Override type of the bundle.
    type = "APPL"

    # platform, name of the subfolder of Contents that contains the executable.
    platform = "MacOS"

    # A Python main program. If this argument is given, the main
    # executable in the bundle will be a small wrapper that invokes
    # the main program. (XXX Discuss why.)
    mainprogram = None

    # The main executable. If a Python main program is specified
    # the executable will be copied to Resources and be invoked
    # by the wrapper program mentioned above. Otherwise it will
    # simply be used as the main executable.
    executable = None

    # The name of the main nib, for Cocoa apps. *Must* be specified
    # when building a Cocoa app.
    nibname = None

    # The name of the icon file to be copied to Resources and used for
    # the Finder icon.
    iconfile = None

    # Symlink the executable instead of copying it.
    symlink_exec = 0

    # If True, build standalone app.
    standalone = 0

    # If True, build semi-standalone app (only includes third-party modules).
    semi_standalone = 0

    # If set, use this for #! lines in stead of sys.executable
    python = None

    # If True, add a real main program that emulates sys.argv before calling
    # mainprogram
    argv_emulation = 0

    # The following attributes are only used when building a standalone app.

    # Exclude these modules.
    excludeModules = []

    # Include these modules.
    includeModules = []

    # Include these packages.
    includePackages = []

    # Strip binaries from debug info.
    strip = 0

    # Found Python modules: [(name, codeobject, ispkg), ...]
    pymodules = []

    # Modules that modulefinder couldn't find:
    missingModules = []
    maybeMissingModules = []

    def setup(self):
        if ((self.standalone or self.semi_standalone)
            and self.mainprogram is None):
            raise BundleBuilderError, ("must specify 'mainprogram' when "
                    "building a standalone application.")
        if self.mainprogram is None and self.executable is None:
            raise BundleBuilderError, ("must specify either or both of "
                    "'executable' and 'mainprogram'")

        self.execdir = pathjoin("Contents", self.platform)

        if self.name is not None:
            pass
        elif self.mainprogram is not None:
            self.name = os.path.splitext(os.path.basename(self.mainprogram))[0]
        elif executable is not None:
            self.name = os.path.splitext(os.path.basename(self.executable))[0]
        if self.name[-4:] != ".app":
            self.name += ".app"

        if self.executable is None:
            if not self.standalone and not isFramework():
                self.symlink_exec = 1
            if self.python:
                self.executable = self.python
            else:
                self.executable = sys.executable

        if self.nibname:
            self.plist.NSMainNibFile = self.nibname
            if not hasattr(self.plist, "NSPrincipalClass"):
                self.plist.NSPrincipalClass = "NSApplication"

        if self.standalone and isFramework():
            self.addPythonFramework()

        BundleBuilder.setup(self)

        self.plist.CFBundleExecutable = self.name

        if self.standalone or self.semi_standalone:
            self.findDependencies()

    def preProcess(self):
        resdir = "Contents/Resources"
        if self.executable is not None:
            if self.mainprogram is None:
                execname = self.name
            else:
                execname = os.path.basename(self.executable)
            execpath = pathjoin(self.execdir, execname)
            if not self.symlink_exec:
                self.files.append((self.executable, execpath))
            self.execpath = execpath

        if self.mainprogram is not None:
            mainprogram = os.path.basename(self.mainprogram)
            self.files.append((self.mainprogram, pathjoin(resdir, mainprogram)))
            if self.argv_emulation:
                # Change the main program, and create the helper main program (which
                # does argv collection and then calls the real main).
                # Also update the included modules (if we're creating a standalone
                # program) and the plist
                realmainprogram = mainprogram
                mainprogram = '__argvemulator_' + mainprogram
                resdirpath = pathjoin(self.bundlepath, resdir)
                mainprogrampath = pathjoin(resdirpath, mainprogram)
                makedirs(resdirpath)
                open(mainprogrampath, "w").write(ARGV_EMULATOR % locals())
                if self.standalone or self.semi_standalone:
                    self.includeModules.append("argvemulator")
                    self.includeModules.append("os")
                if not self.plist.has_key("CFBundleDocumentTypes"):
                    self.plist["CFBundleDocumentTypes"] = [
                        { "CFBundleTypeOSTypes" : [
                            "****",
                            "fold",
                            "disk"],
                          "CFBundleTypeRole": "Viewer"}]
            # Write bootstrap script
            executable = os.path.basename(self.executable)
            execdir = pathjoin(self.bundlepath, self.execdir)
            bootstrappath = pathjoin(execdir, self.name)
            makedirs(execdir)
            if self.standalone or self.semi_standalone:
                # XXX we're screwed when the end user has deleted
                # /usr/bin/python
                hashbang = "/usr/bin/python"
            elif self.python:
                hashbang = self.python
            else:
                hashbang = os.path.realpath(sys.executable)
            standalone = self.standalone
            semi_standalone = self.semi_standalone
            open(bootstrappath, "w").write(BOOTSTRAP_SCRIPT % locals())
            os.chmod(bootstrappath, 0775)

        if self.iconfile is not None:
            iconbase = os.path.basename(self.iconfile)
            self.plist.CFBundleIconFile = iconbase
            self.files.append((self.iconfile, pathjoin(resdir, iconbase)))

    def postProcess(self):
        if self.standalone or self.semi_standalone:
            self.addPythonModules()
        if self.strip and not self.symlink:
            self.stripBinaries()

        if self.symlink_exec and self.executable:
            self.message("Symlinking executable %s to %s" % (self.executable,
                    self.execpath), 2)
            dst = pathjoin(self.bundlepath, self.execpath)
            makedirs(os.path.dirname(dst))
            os.symlink(os.path.abspath(self.executable), dst)

        if self.missingModules or self.maybeMissingModules:
            self.reportMissing()

    def addPythonFramework(self):
        # If we're building a standalone app with Python.framework,
        # include a minimal subset of Python.framework, *unless*
        # Python.framework was specified manually in self.libs.
        for lib in self.libs:
            if os.path.basename(lib) == "Python.framework":
                # a Python.framework was specified as a library
                return

        frameworkpath = sys.exec_prefix[:sys.exec_prefix.find(
            "Python.framework") + len("Python.framework")]

        version = sys.version[:3]
        frameworkpath = pathjoin(frameworkpath, "Versions", version)
        destbase = pathjoin("Contents", "Frameworks", "Python.framework",
                            "Versions", version)
        for item in PYTHONFRAMEWORKGOODIES:
            src = pathjoin(frameworkpath, item)
            dst = pathjoin(destbase, item)
            self.files.append((src, dst))

    def _getSiteCode(self):
        return compile(SITE_PY % {"semi_standalone": self.semi_standalone},
                     "<-bundlebuilder.py->", "exec")

    def addPythonModules(self):
        self.message("Adding Python modules", 1)

        if USE_ZIPIMPORT:
            # Create a zip file containing all modules as pyc.
            import zipfile
            relpath = pathjoin("Contents", "Resources", ZIP_ARCHIVE)
            abspath = pathjoin(self.bundlepath, relpath)
            zf = zipfile.ZipFile(abspath, "w", zipfile.ZIP_DEFLATED)
            for name, code, ispkg in self.pymodules:
                self.message("Adding Python module %s" % name, 2)
                path, pyc = getPycData(name, code, ispkg)
                zf.writestr(path, pyc)
            zf.close()
            # add site.pyc
            sitepath = pathjoin(self.bundlepath, "Contents", "Resources",
                    "site" + PYC_EXT)
            writePyc(self._getSiteCode(), sitepath)
        else:
            # Create individual .pyc files.
            for name, code, ispkg in self.pymodules:
                if ispkg:
                    name += ".__init__"
                path = name.split(".")
                path = pathjoin("Contents", "Resources", *path) + PYC_EXT

                if ispkg:
                    self.message("Adding Python package %s" % path, 2)
                else:
                    self.message("Adding Python module %s" % path, 2)

                abspath = pathjoin(self.bundlepath, path)
                makedirs(os.path.dirname(abspath))
                writePyc(code, abspath)

    def stripBinaries(self):
        if not os.path.exists(STRIP_EXEC):
            self.message("Error: can't strip binaries: no strip program at "
                "%s" % STRIP_EXEC, 0)
        else:
            import stat
            self.message("Stripping binaries", 1)
            def walk(top):
                for name in os.listdir(top):
                    path = pathjoin(top, name)
                    if os.path.islink(path):
                        continue
                    if os.path.isdir(path):
                        walk(path)
                    else:
                        mod = os.stat(path)[stat.ST_MODE]
                        if not (mod & 0100):
                            continue
                        relpath = path[len(self.bundlepath):]
                        self.message("Stripping %s" % relpath, 2)
                        inf, outf = os.popen4("%s -S \"%s\"" %
                                              (STRIP_EXEC, path))
                        output = outf.read().strip()
                        if output:
                            # usually not a real problem, like when we're
                            # trying to strip a script
                            self.message("Problem stripping %s:" % relpath, 3)
                            self.message(output, 3)
            walk(self.bundlepath)

    def findDependencies(self):
        self.message("Finding module dependencies", 1)
        import modulefinder
        mf = modulefinder.ModuleFinder(excludes=self.excludeModules)
        if USE_ZIPIMPORT:
            # zipimport imports zlib, must add it manually
            mf.import_hook("zlib")
        # manually add our own site.py
        site = mf.add_module("site")
        site.__code__ = self._getSiteCode()
        mf.scan_code(site.__code__, site)

        # warnings.py gets imported implicitly from C
        mf.import_hook("warnings")

        includeModules = self.includeModules[:]
        for name in self.includePackages:
            includeModules.extend(findPackageContents(name).keys())
        for name in includeModules:
            try:
                mf.import_hook(name)
            except ImportError:
                self.missingModules.append(name)

        mf.run_script(self.mainprogram)
        modules = mf.modules.items()
        modules.sort()
        for name, mod in modules:
            path = mod.__file__
            if path and self.semi_standalone:
                # skip the standard library
                if path.startswith(LIB) and not path.startswith(SITE_PACKAGES):
                    continue
            if path and mod.__code__ is None:
                # C extension
                filename = os.path.basename(path)
                pathitems = name.split(".")[:-1] + [filename]
                dstpath = pathjoin(*pathitems)
                if USE_ZIPIMPORT:
                    if name != "zlib":
                        # neatly pack all extension modules in a subdirectory,
                        # except zlib, since it's neccesary for bootstrapping.
                        dstpath = pathjoin("ExtensionModules", dstpath)
                    # Python modules are stored in a Zip archive, but put
                    # extensions in Contents/Resources/. Add a tiny "loader"
                    # program in the Zip archive. Due to Thomas Heller.
                    source = EXT_LOADER % {"name": name, "filename": dstpath}
                    code = compile(source, "<dynloader for %s>" % name, "exec")
                    mod.__code__ = code
                self.files.append((path, pathjoin("Contents", "Resources", dstpath)))
            if mod.__code__ is not None:
                ispkg = mod.__path__ is not None
                if not USE_ZIPIMPORT or name != "site":
                    # Our site.py is doing the bootstrapping, so we must
                    # include a real .pyc file if USE_ZIPIMPORT is True.
                    self.pymodules.append((name, mod.__code__, ispkg))

        if hasattr(mf, "any_missing_maybe"):
            missing, maybe = mf.any_missing_maybe()
        else:
            missing = mf.any_missing()
            maybe = []
        self.missingModules.extend(missing)
        self.maybeMissingModules.extend(maybe)

    def reportMissing(self):
        missing = [name for name in self.missingModules
                if name not in MAYMISS_MODULES]
        if self.maybeMissingModules:
            maybe = self.maybeMissingModules
        else:
            maybe = [name for name in missing if "." in name]
            missing = [name for name in missing if "." not in name]
        missing.sort()
        maybe.sort()
        if maybe:
            self.message("Warning: couldn't find the following submodules:", 1)
            self.message("    (Note that these could be false alarms -- "
                         "it's not always", 1)
            self.message("    possible to distinguish between \"from package "
                         "import submodule\" ", 1)
            self.message("    and \"from package import name\")", 1)
            for name in maybe:
                self.message("  ? " + name, 1)
        if missing:
            self.message("Warning: couldn't find the following modules:", 1)
            for name in missing:
                self.message("  ? " + name, 1)

    def report(self):
        # XXX something decent
        import pprint
        pprint.pprint(self.__dict__)
        if self.standalone or self.semi_standalone:
            self.reportMissing()

#
# Utilities.
#

SUFFIXES = [_suf for _suf, _mode, _tp in imp.get_suffixes()]
identifierRE = re.compile(r"[_a-zA-z][_a-zA-Z0-9]*$")

def findPackageContents(name, searchpath=None):
    head = name.split(".")[-1]
    if identifierRE.match(head) is None:
        return {}
    try:
        fp, path, (ext, mode, tp) = imp.find_module(head, searchpath)
    except ImportError:
        return {}
    modules = {name: None}
    if tp == imp.PKG_DIRECTORY and path:
        files = os.listdir(path)
        for sub in files:
            sub, ext = os.path.splitext(sub)
            fullname = name + "." + sub
            if sub != "__init__" and fullname not in modules:
                modules.update(findPackageContents(fullname, [path]))
    return modules

def writePyc(code, path):
    f = open(path, "wb")
    f.write(MAGIC)
    f.write("\0" * 4)  # don't bother about a time stamp
    marshal.dump(code, f)
    f.close()

def copy(src, dst, mkdirs=0):
    """Copy a file or a directory."""
    if mkdirs:
        makedirs(os.path.dirname(dst))
    if os.path.isdir(src):
        shutil.copytree(src, dst, symlinks=1)
    else:
        shutil.copy2(src, dst)

def copytodir(src, dstdir):
    """Copy a file or a directory to an existing directory."""
    dst = pathjoin(dstdir, os.path.basename(src))
    copy(src, dst)

def makedirs(dir):
    """Make all directories leading up to 'dir' including the leaf
    directory. Don't moan if any path element already exists."""
    try:
        os.makedirs(dir)
    except OSError, why:
        if why.errno != errno.EEXIST:
            raise

def symlink(src, dst, mkdirs=0):
    """Copy a file or a directory."""
    if not os.path.exists(src):
        raise IOError, "No such file or directory: '%s'" % src
    if mkdirs:
        makedirs(os.path.dirname(dst))
    os.symlink(os.path.abspath(src), dst)

def pathjoin(*args):
    """Safe wrapper for os.path.join: asserts that all but the first
    argument are relative paths."""
    for seg in args[1:]:
        assert seg[0] != "/"
    return os.path.join(*args)


cmdline_doc = """\
Usage:
  python bundlebuilder.py [options] command
  python mybuildscript.py [options] command

Commands:
  build      build the application
  report     print a report

Options:
  -b, --builddir=DIR     the build directory; defaults to "build"
  -n, --name=NAME        application name
  -r, --resource=FILE    extra file or folder to be copied to Resources
  -f, --file=SRC:DST     extra file or folder to be copied into the bundle;
                         DST must be a path relative to the bundle root
  -e, --executable=FILE  the executable to be used
  -m, --mainprogram=FILE the Python main program
  -a, --argv             add a wrapper main program to create sys.argv
  -p, --plist=FILE       .plist file (default: generate one)
      --nib=NAME         main nib name
  -c, --creator=CCCC     4-char creator code (default: '????')
      --iconfile=FILE    filename of the icon (an .icns file) to be used
                         as the Finder icon
      --bundle-id=ID     the CFBundleIdentifier, in reverse-dns format
                         (eg. org.python.BuildApplet; this is used for
                         the preferences file name)
  -l, --link             symlink files/folder instead of copying them
      --link-exec        symlink the executable instead of copying it
      --standalone       build a standalone application, which is fully
                         independent of a Python installation
      --semi-standalone  build a standalone application, which depends on
                         an installed Python, yet includes all third-party
                         modules.
      --python=FILE      Python to use in #! line in stead of current Python
      --lib=FILE         shared library or framework to be copied into
                         the bundle
  -x, --exclude=MODULE   exclude module (with --(semi-)standalone)
  -i, --include=MODULE   include module (with --(semi-)standalone)
      --package=PACKAGE  include a whole package (with --(semi-)standalone)
      --strip            strip binaries (remove debug info)
  -v, --verbose          increase verbosity level
  -q, --quiet            decrease verbosity level
  -h, --help             print this message
"""

def usage(msg=None):
    if msg:
        print msg
    print cmdline_doc
    sys.exit(1)

def main(builder=None):
    if builder is None:
        builder = AppBuilder(verbosity=1)

    shortopts = "b:n:r:f:e:m:c:p:lx:i:hvqa"
    longopts = ("builddir=", "name=", "resource=", "file=", "executable=",
        "mainprogram=", "creator=", "nib=", "plist=", "link",
        "link-exec", "help", "verbose", "quiet", "argv", "standalone",
        "exclude=", "include=", "package=", "strip", "iconfile=",
        "lib=", "python=", "semi-standalone", "bundle-id=")

    try:
        options, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
    except getopt.error:
        usage()

    for opt, arg in options:
        if opt in ('-b', '--builddir'):
            builder.builddir = arg
        elif opt in ('-n', '--name'):
            builder.name = arg
        elif opt in ('-r', '--resource'):
            builder.resources.append(os.path.normpath(arg))
        elif opt in ('-f', '--file'):
            srcdst = arg.split(':')
            if len(srcdst) != 2:
                usage("-f or --file argument must be two paths, "
                      "separated by a colon")
            builder.files.append(srcdst)
        elif opt in ('-e', '--executable'):
            builder.executable = arg
        elif opt in ('-m', '--mainprogram'):
            builder.mainprogram = arg
        elif opt in ('-a', '--argv'):
            builder.argv_emulation = 1
        elif opt in ('-c', '--creator'):
            builder.creator = arg
        elif opt == '--bundle-id':
            builder.bundle_id = arg
        elif opt == '--iconfile':
            builder.iconfile = arg
        elif opt == "--lib":
            builder.libs.append(os.path.normpath(arg))
        elif opt == "--nib":
            builder.nibname = arg
        elif opt in ('-p', '--plist'):
            builder.plist = Plist.fromFile(arg)
        elif opt in ('-l', '--link'):
            builder.symlink = 1
        elif opt == '--link-exec':
            builder.symlink_exec = 1
        elif opt in ('-h', '--help'):
            usage()
        elif opt in ('-v', '--verbose'):
            builder.verbosity += 1
        elif opt in ('-q', '--quiet'):
            builder.verbosity -= 1
        elif opt == '--standalone':
            builder.standalone = 1
        elif opt == '--semi-standalone':
            builder.semi_standalone = 1
        elif opt == '--python':
            builder.python = arg
        elif opt in ('-x', '--exclude'):
            builder.excludeModules.append(arg)
        elif opt in ('-i', '--include'):
            builder.includeModules.append(arg)
        elif opt == '--package':
            builder.includePackages.append(arg)
        elif opt == '--strip':
            builder.strip = 1

    if len(args) != 1:
        usage("Must specify one command ('build', 'report' or 'help')")
    command = args[0]

    if command == "build":
        builder.setup()
        builder.build()
    elif command == "report":
        builder.setup()
        builder.report()
    elif command == "help":
        usage()
    else:
        usage("Unknown command '%s'" % command)


def buildapp(**kwargs):
    builder = AppBuilder(**kwargs)
    main(builder)


if __name__ == "__main__":
    main()

--- NEW FILE: cfmfile.py ---
"""codefragments.py -- wrapper to modify code fragments."""

# (c) 1998, Just van Rossum, Letterror

__version__ = "0.8b3"
__author__ = "jvr"

import Carbon.File
import struct
from Carbon import Res
import os
import sys

DEBUG = 0

error = "cfm.error"

BUFSIZE = 0x80000

def mergecfmfiles(srclist, dst, architecture = 'fat'):
    """Merge all files in srclist into a new file dst. 
    
    If architecture is given, only code fragments of that type will be used:
    "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic"
    68k code, since it does not use code fragments to begin with.
    If architecture is None, all fragments will be used, enabling FAT binaries.
    """
    
    srclist = list(srclist)
    for i in range(len(srclist)):
        srclist[i] = Carbon.File.pathname(srclist[i])
    dst = Carbon.File.pathname(dst)
    
    dstfile = open(dst, "wb")
    rf = Res.FSpOpenResFile(dst, 3)
    try:
        dstcfrg = CfrgResource()
        for src in srclist:
            srccfrg = CfrgResource(src)
            for frag in srccfrg.fragments:
                if frag.architecture == 'pwpc' and architecture == 'm68k':
                    continue
                if frag.architecture == 'm68k' and architecture == 'pwpc':
                    continue
                dstcfrg.append(frag)
                
                frag.copydata(dstfile)
                
        cfrgres = Res.Resource(dstcfrg.build())
        Res.UseResFile(rf)
        cfrgres.AddResource('cfrg', 0, "")
    finally:
        dstfile.close()
        rf = Res.CloseResFile(rf)


class CfrgResource:
    
    def __init__(self, path = None):
        self.version = 1
        self.fragments = []
        self.path = path
        if path is not None and os.path.exists(path):
            currentresref = Res.CurResFile()
            resref = Res.FSpOpenResFile(path, 1)
            Res.UseResFile(resref)
            try:
                try:
                    data = Res.Get1Resource('cfrg', 0).data
                except Res.Error:
                    raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback
            finally:
                Res.CloseResFile(resref)
                Res.UseResFile(currentresref)
            self.parse(data)
            if self.version <> 1:
                raise error, "unknown 'cfrg' resource format"   
    
    def parse(self, data):
        (res1, res2, self.version, 
            res3, res4, res5, res6, 
            self.memberCount) = struct.unpack("8l", data[:32])
        data = data[32:]
        while data:
            frag = FragmentDescriptor(self.path, data)
            data = data[frag.memberSize:]
            self.fragments.append(frag)
    
    def build(self):
        self.memberCount = len(self.fragments)
        data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
        for frag in self.fragments:
            data = data + frag.build()
        return data
    
    def append(self, frag):
        self.fragments.append(frag)


class FragmentDescriptor:
    
    def __init__(self, path, data = None):
        self.path = path
        if data is not None:
            self.parse(data)
    
    def parse(self, data):
        self.architecture = data[:4]
        (   self.updatelevel, 
            self.currentVersion, 
            self.oldDefVersion, 
            self.stacksize,
            self.applibdir, 
            self.fragtype,
            self.where,
            self.offset,
            self.length,
            self.res1, self.res2,
            self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
        pname = data[42:self.memberSize]
        self.name = pname[1:1+ord(pname[0])]
    
    def build(self):
        data = self.architecture
        data = data + struct.pack("4lhBB4l",
                self.updatelevel, 
                self.currentVersion, 
                self.oldDefVersion, 
                self.stacksize,
                self.applibdir, 
                self.fragtype,
                self.where,
                self.offset,
                self.length,
                self.res1, self.res2)
        self.memberSize = len(data) + 2 + 1 + len(self.name)
        # pad to 4 byte boundaries
        if self.memberSize % 4:
            self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
        data = data + struct.pack("hb", self.memberSize, len(self.name))
        data = data + self.name
        data = data + '\000' * (self.memberSize - len(data))
        return data
    
    def getfragment(self):
        if self.where <> 1:
            raise error, "can't read fragment, unsupported location"
        f = open(self.path, "rb")
        f.seek(self.offset)
        if self.length:
            frag = f.read(self.length)
        else:
            frag = f.read()
        f.close()
        return frag
    
    def copydata(self, outfile):
        if self.where <> 1:
            raise error, "can't read fragment, unsupported location"
        infile = open(self.path, "rb")
        if self.length == 0:
            infile.seek(0, 2)
            self.length = infile.tell()
        
        # Position input file and record new offset from output file
        infile.seek(self.offset)
        
        # pad to 16 byte boundaries
        offset = outfile.tell()
        if offset % 16:
            offset = offset + 16 - (offset % 16)
        outfile.seek(offset)
        self.offset = offset
        
        l = self.length
        while l:
            if l > BUFSIZE:
                outfile.write(infile.read(BUFSIZE))
                l = l - BUFSIZE
            else:
                outfile.write(infile.read(l))
                l = 0
        infile.close()


--- NEW FILE: dialogs.rsrc ---





DDDDDD

BBBBBB
óÿþ
ýÿ
ýÿ
ÿÿ€÷
ÿÿp÷
ÿßüÿ
õÿ
þÿ
ùÿ
ÿÿp÷
ñÿ
ùÿ
öÿ
ÿÿpü
öÿ
ùÿ
ùÿ
ÿÿpü
öÿ
ùÿ
ùÿ
öÿ
ùÿ
úÿ
çÿ
êÿ





















jackjansen
Debug parser output
Disable site-python
%DonÕt use NavServices for macfs calls

Cancel






ŠMENU
--- NEW FILE: errors.rsrc ---


	I/O error
	recNotFnd
	atpBadRsp
	atpLenErr
extractErr
ify
nrPowerErr
	nrNameErr
 "deflectable"
ailed because the menu uses the system MDEF
reqAborted
noDataArea
noSendResp
cbNotFound
badBuffNum
	badATPSkt
	reqFailed
	rcDBBreak
	rcDBError
	rcDBValue
noCodecErr
 bounds error
	disk full

ÿÿ

3
H
\
“
Á
Ú
ñ


ÿÿ
ÿÿ
ÿÿ
ÿÿ
ÿÿ
ÿÿ
ÿÿ
ÿÿ
.€ÿÿÿ
--- NEW FILE: findertools.py ---
"""Utility routines depending on the finder,
a combination of code by Jack Jansen and erik at letterror.com.

Most events have been captured from
Lasso Capture AE and than translated to python code.

IMPORTANT
Note that the processes() function returns different values
depending on the OS version it is running on. On MacOS 9
the Finder returns the process *names* which can then be
used to find out more about them. On MacOS 8.6 and earlier
the Finder returns a code which does not seem to work.
So bottom line: the processes() stuff does not work on < MacOS9

Mostly written by erik at letterror.com
"""
import Finder
from Carbon import AppleEvents
import aetools
import MacOS
import sys
import Carbon.File
import Carbon.Folder
import aetypes
from types import *

__version__ = '1.1'
Error = 'findertools.Error'

_finder_talker = None

def _getfinder():
    """returns basic (recyclable) Finder AE interface object"""
    global _finder_talker
    if not _finder_talker:
        _finder_talker = Finder.Finder()
    _finder_talker.send_flags = ( _finder_talker.send_flags | 
        AppleEvents.kAECanInteract | AppleEvents.kAECanSwitchLayer)
    return _finder_talker
    
def launch(file):
    """Open a file thru the finder. Specify file by name or fsspec"""
    finder = _getfinder()
    fss = Carbon.File.FSSpec(file)
    return finder.open(fss)
    
def Print(file):
    """Print a file thru the finder. Specify file by name or fsspec"""
    finder = _getfinder()
    fss = Carbon.File.FSSpec(file)
    return finder._print(fss)
    
def copy(src, dstdir):
    """Copy a file to a folder"""
    finder = _getfinder()
    if type(src) == type([]):
        src_fss = []
        for s in src:
            src_fss.append(Carbon.File.FSSpec(s))
    else:
        src_fss = Carbon.File.FSSpec(src)
    dst_fss = Carbon.File.FSSpec(dstdir)
    return finder.duplicate(src_fss, to=dst_fss)

def move(src, dstdir):
    """Move a file to a folder"""
    finder = _getfinder()
    if type(src) == type([]):
        src_fss = []
        for s in src:
            src_fss.append(Carbon.File.FSSpec(s))
    else:
        src_fss = Carbon.File.FSSpec(src)
    dst_fss = Carbon.File.FSSpec(dstdir)
    return finder.move(src_fss, to=dst_fss)
    
def sleep():
    """Put the mac to sleep"""
    finder = _getfinder()
    finder.sleep()
    
def shutdown():
    """Shut the mac down"""
    finder = _getfinder()
    finder.shut_down()
    
def restart():
    """Restart the mac"""
    finder = _getfinder()
    finder.restart()


#---------------------------------------------------
#   Additional findertools
#

def reveal(file):
    """Reveal a file in the finder. Specify file by name, fsref or fsspec."""
    finder = _getfinder()
    fsr = Carbon.File.FSRef(file)
    file_alias = fsr.FSNewAliasMinimal()
    return finder.reveal(file_alias)
    
def select(file):
    """select a file in the finder. Specify file by name, fsref or fsspec."""
    finder = _getfinder()
    fsr = Carbon.File.FSRef(file)
    file_alias = fsr.FSNewAliasMinimal()
    return finder.select(file_alias)
    
def update(file):
    """Update the display of the specified object(s) to match 
    their on-disk representation. Specify file by name, fsref or fsspec."""
    finder = _getfinder()
    fsr = Carbon.File.FSRef(file)
    file_alias = fsr.FSNewAliasMinimal()
    return finder.update(file_alias)


#---------------------------------------------------
#   More findertools
#

def comment(object, comment=None):
    """comment: get or set the Finder-comment of the item, displayed in the 'Get Info' window."""
    object = Carbon.File.FSRef(object)
    object_alias = object.FSNewAliasMonimal()
    if comment == None:
        return _getcomment(object_alias)
    else:
        return _setcomment(object_alias, comment)
    
def _setcomment(object_alias, comment):
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), form="alis", seld=object_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('comt'), fr=aeobj_00)
    args['----'] = aeobj_01
    args["data"] = comment
    _reply, args, attrs = finder.send("core", "setd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def _getcomment(object_alias):
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), form="alis", seld=object_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('comt'), fr=aeobj_00)
    args['----'] = aeobj_01
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']


#---------------------------------------------------
#   Get information about current processes in the Finder.

def processes():
    """processes returns a list of all active processes running on this computer and their creators."""
    finder = _getfinder()
    args = {}
    attrs = {}
    processnames = []
    processnumbers = []
    creators = []
    partitions = []
    used = []
    ## get the processnames or else the processnumbers
    args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prcs'), form="indx", seld=aetypes.Unknown('abso', "all "), fr=None)
    _reply, args, attrs = finder.send('core', 'getd', args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    p = []
    if args.has_key('----'):
        p =  args['----']
        for proc in p:
            if hasattr(proc, 'seld'):
                # it has a real name
                processnames.append(proc.seld)
            elif hasattr(proc, 'type'):
                if proc.type == "psn ":
                    # it has a process number
                    processnumbers.append(proc.data)
    ## get the creators
    args = {}
    attrs = {}
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('prcs'), form="indx", seld=aetypes.Unknown('abso', "all "), fr=None)
    args['----'] =  aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('fcrt'), fr=aeobj_0)
    _reply, args, attrs = finder.send('core', 'getd', args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(_arg)
    if args.has_key('----'):
        p =  args['----']
        creators = p[:]
    ## concatenate in one dict
    result = []
    if len(processnames) > len(processnumbers):
        data = processnames
    else:
        data = processnumbers
    for i in range(len(creators)):
        result.append((data[i], creators[i]))
    return result

class _process:
    pass

def isactiveprocess(processname):
    """Check of processname is active. MacOS9"""
    all = processes()
    ok = 0
    for n, c in all:
        if n == processname:
            return 1
    return 0
    
def processinfo(processname):
    """Return an object with all process properties as attributes for processname. MacOS9"""
    p = _process()
    
    if processname == "Finder":
        p.partition = None
        p.used = None
    else:
        p.partition = _processproperty(processname, 'appt')
        p.used = _processproperty(processname, 'pusd')
    p.visible = _processproperty(processname, 'pvis')       #Is the process' layer visible?
    p.frontmost = _processproperty(processname, 'pisf') #Is the process the frontmost process?
    p.file = _processproperty(processname, 'file')          #the file from which the process was launched
    p.filetype  = _processproperty(processname, 'asty')     #the OSType of the file type of the process
    p.creatortype = _processproperty(processname, 'fcrt')   #the OSType of the creator of the process (the signature)
    p.accepthighlevel = _processproperty(processname, 'revt')   #Is the process high-level event aware (accepts open application, open document, print document, and quit)?
    p.hasscripting = _processproperty(processname, 'hscr')      #Does the process have a scripting terminology, i.e., can it be scripted?
    return p
    
def _processproperty(processname, property):
    """return the partition size and memory used for processname"""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('prcs'), form="name", seld=processname, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type(property), fr=aeobj_00)
    args['----'] = aeobj_01
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']


#---------------------------------------------------
#   Mess around with Finder windows.
    
def openwindow(object):
    """Open a Finder window for object, Specify object by name or fsspec."""
    finder = _getfinder()
    object = Carbon.File.FSRef(object)
    object_alias = object.FSNewAliasMinimal()
    args = {}
    attrs = {}
    _code = 'aevt'
    _subcode = 'odoc'
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
    args['----'] = aeobj_0
    _reply, args, attrs = finder.send(_code, _subcode, args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    
def closewindow(object):
    """Close a Finder window for folder, Specify by path."""
    finder = _getfinder()
    object = Carbon.File.FSRef(object)
    object_alias = object.FSNewAliasMinimal()
    args = {}
    attrs = {}
    _code = 'core'
    _subcode = 'clos'
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
    args['----'] = aeobj_0
    _reply, args, attrs = finder.send(_code, _subcode, args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)

def location(object, pos=None):
    """Set the position of a Finder window for folder to pos=(w, h). Specify file by name or fsspec.
    If pos=None, location will return the current position of the object."""
    object = Carbon.File.FSRef(object)
    object_alias = object.FSNewAliasMinimal()
    if not pos:
        return _getlocation(object_alias)
    return _setlocation(object_alias, pos)
    
def _setlocation(object_alias, (x, y)):
    """_setlocation: Set the location of the icon for the object."""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('posn'), fr=aeobj_00)
    args['----'] = aeobj_01
    args["data"] = [x, y]
    _reply, args, attrs = finder.send("core", "setd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    return (x,y)
    
def _getlocation(object_alias):
    """_getlocation: get the location of the icon for the object."""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=object_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('posn'), fr=aeobj_00)
    args['----'] = aeobj_01
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        pos = args['----']
        return pos.h, pos.v

def label(object, index=None):
    """label: set or get the label of the item. Specify file by name or fsspec."""
    object = Carbon.File.FSRef(object)
    object_alias = object.FSNewAliasMinimal()
    if index == None:
        return _getlabel(object_alias)
    if index < 0 or index > 7:
        index = 0
    return _setlabel(object_alias, index)
    
def _getlabel(object_alias):
    """label: Get the label for the object."""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), form="alis", seld=object_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('labi'), fr=aeobj_00)
    args['----'] = aeobj_01
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def _setlabel(object_alias, index):
    """label: Set the label for the object."""
    finder = _getfinder()
    args = {}
    attrs = {}
    _code = 'core'
    _subcode = 'setd'
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
            form="alis", seld=object_alias, fr=None)
    aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'),
            form="prop", seld=aetypes.Type('labi'), fr=aeobj_0)
    args['----'] = aeobj_1
    args["data"] = index
    _reply, args, attrs = finder.send(_code, _subcode, args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    return index

def windowview(folder, view=None):
    """windowview: Set the view of the window for the folder. Specify file by name or fsspec.
    0 = by icon (default)
    1 = by name
    2 = by button
    """
    fsr = Carbon.File.FSRef(folder)
    folder_alias = fsr.FSNewAliasMinimal()
    if view == None:
        return _getwindowview(folder_alias)
    return _setwindowview(folder_alias, view)
    
def _setwindowview(folder_alias, view=0):
    """set the windowview"""
    attrs = {}
    args = {}
    if view == 1:
        _v = aetypes.Type('pnam')
    elif view == 2:
        _v = aetypes.Type('lgbu')
    else:
        _v = aetypes.Type('iimg')
    finder = _getfinder()
    aeobj_0 = aetypes.ObjectSpecifier(want = aetypes.Type('cfol'), 
            form = 'alis', seld = folder_alias, fr=None)
    aeobj_1 = aetypes.ObjectSpecifier(want = aetypes.Type('prop'), 
            form = 'prop', seld = aetypes.Type('cwnd'), fr=aeobj_0)
    aeobj_2 = aetypes.ObjectSpecifier(want = aetypes.Type('prop'), 
            form = 'prop', seld = aetypes.Type('pvew'), fr=aeobj_1)
    aeobj_3 = aetypes.ObjectSpecifier(want = aetypes.Type('prop'), 
            form = 'prop', seld = _v, fr=None)
    _code = 'core'
    _subcode = 'setd'
    args['----'] = aeobj_2
    args['data'] = aeobj_3
    _reply, args, attrs = finder.send(_code, _subcode, args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def _getwindowview(folder_alias):
    """get the windowview"""
    attrs = {}
    args = {}
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), form="alis", seld=folder_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_00)
    aeobj_02 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('pvew'), fr=aeobj_01)
    args['----'] = aeobj_02
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    views = {'iimg':0, 'pnam':1, 'lgbu':2}
    if args.has_key('----'):
        return views[args['----'].enum]

def windowsize(folder, size=None):
    """Set the size of a Finder window for folder to size=(w, h), Specify by path.
    If size=None, windowsize will return the current size of the window.
    Specify file by name or fsspec.
    """
    fsr = Carbon.File.FSRef(folder)
    folder_alias = fsr.FSNewAliasMinimal()
    openwindow(fsr)
    if not size:
        return _getwindowsize(folder_alias)
    return _setwindowsize(folder_alias, size)
    
def _setwindowsize(folder_alias, (w, h)):
    """Set the size of a Finder window for folder to (w, h)"""
    finder = _getfinder()
    args = {}
    attrs = {}
    _code = 'core'
    _subcode = 'setd'
    aevar00 = [w, h]
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'),
            form="alis", seld=folder_alias, fr=None)
    aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
    aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('ptsz'), fr=aeobj_1)
    args['----'] = aeobj_2
    args["data"] = aevar00
    _reply, args, attrs = finder.send(_code, _subcode, args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    return (w, h)
        
def _getwindowsize(folder_alias):
    """Set the size of a Finder window for folder to (w, h)"""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), 
            form="alis", seld=folder_alias, fr=None)
    aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
    aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('posn'), fr=aeobj_1)
    args['----'] = aeobj_2
    _reply, args, attrs = finder.send('core', 'getd', args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def windowposition(folder, pos=None):
    """Set the position of a Finder window for folder to pos=(w, h)."""
    fsr = Carbon.File.FSRef(folder)
    folder_alias = fsr.FSNewAliasMinimal()
    openwindow(fsr)
    if not pos:
        return _getwindowposition(folder_alias)
    if type(pos) == InstanceType:
        # pos might be a QDPoint object as returned by _getwindowposition
        pos = (pos.h, pos.v)
    return _setwindowposition(folder_alias, pos)
            
def _setwindowposition(folder_alias, (x, y)):
    """Set the size of a Finder window for folder to (w, h)."""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), 
            form="alis", seld=folder_alias, fr=None)
    aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
    aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('posn'), fr=aeobj_1)
    args['----'] = aeobj_2
    args["data"] = [x, y]
    _reply, args, attrs = finder.send('core', 'setd', args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def _getwindowposition(folder_alias):
    """Get the size of a Finder window for folder, Specify by path."""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_0 = aetypes.ObjectSpecifier(want=aetypes.Type('cfol'), 
            form="alis", seld=folder_alias, fr=None)
    aeobj_1 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('cwnd'), fr=aeobj_0)
    aeobj_2 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('ptsz'), fr=aeobj_1)
    args['----'] = aeobj_2
    _reply, args, attrs = finder.send('core', 'getd', args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def icon(object, icondata=None):
    """icon sets the icon of object, if no icondata is given,
    icon will return an AE object with binary data for the current icon.
    If left untouched, this data can be used to paste the icon on another file.
    Development opportunity: get and set the data as PICT."""
    fsr = Carbon.File.FSRef(object)
    object_alias = fsr.FSNewAliasMinimal()
    if icondata == None:
        return _geticon(object_alias)
    return _seticon(object_alias, icondata)
    
def _geticon(object_alias):
    """get the icondata for object. Binary data of some sort."""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), 
            form="alis", seld=object_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('iimg'), fr=aeobj_00)
    args['----'] = aeobj_01
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def _seticon(object_alias, icondata):
    """set the icondata for object, formatted as produced by _geticon()"""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('cobj'), 
            form="alis", seld=object_alias, fr=None)
    aeobj_01 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), 
            form="prop", seld=aetypes.Type('iimg'), fr=aeobj_00)
    args['----'] = aeobj_01
    args["data"] = icondata
    _reply, args, attrs = finder.send("core", "setd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----'].data


#---------------------------------------------------
#   Volumes and servers.
    
def mountvolume(volume, server=None, username=None, password=None):
    """mount a volume, local or on a server on AppleTalk.
    Note: mounting a ASIP server requires a different operation.
    server is the name of the server where the volume belongs
    username, password belong to a registered user of the volume."""
    finder = _getfinder()
    args = {}
    attrs = {}
    if password:
        args["PASS"] = password
    if username:
        args["USER"] = username
    if server:
        args["SRVR"] = server
    args['----'] = volume
    _reply, args, attrs = finder.send("aevt", "mvol", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def unmountvolume(volume):
    """unmount a volume that's on the desktop"""
    putaway(volume)
    
def putaway(object):
    """puth the object away, whereever it came from."""
    finder = _getfinder()
    args = {}
    attrs = {}
    args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('cdis'), form="name", seld=object, fr=None)
    _reply, args, attrs = talker.send("fndr", "ptwy", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']


#---------------------------------------------------
#   Miscellaneous functions
#

def volumelevel(level):
    """set the audio output level, parameter between 0 (silent) and 7 (full blast)"""
    finder = _getfinder()
    args = {}
    attrs = {}
    if level < 0:
        level = 0
    elif level > 7:
        level = 7
    args['----'] = level
    _reply, args, attrs = finder.send("aevt", "stvl", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def OSversion():
    """return the version of the system software"""
    finder = _getfinder()
    args = {}
    attrs = {}
    aeobj_00 = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('ver2'), fr=None)
    args['----'] = aeobj_00
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        return args['----']

def filesharing():
    """return the current status of filesharing and whether it is starting up or not:
        -1  file sharing is off and not starting up
        0   file sharing is off and starting up
        1   file sharing is on"""
    status = -1
    finder = _getfinder()
    # see if it is on
    args = {}
    attrs = {}
    args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('fshr'), fr=None)
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        if args['----'] == 0:
            status = -1
        else:
            status = 1
    # is it starting up perchance?
    args = {}
    attrs = {}
    args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('fsup'), fr=None)
    _reply, args, attrs = finder.send("core", "getd", args, attrs)
    if args.has_key('errn'):
        raise Error, aetools.decodeerror(args)
    if args.has_key('----'):
        if args['----'] == 1:
            status = 0
    return status
    
def movetotrash(path):
    """move the object to the trash"""
    fss = Carbon.File.FSSpec(path)
    trashfolder = Carbon.Folder.FSFindFolder(fss.as_tuple()[0], 'trsh', 0)
    move(path, trashfolder)

def emptytrash():
    """empty the trash"""
    finder = _getfinder()
    args = {}
    attrs = {}
    args['----'] = aetypes.ObjectSpecifier(want=aetypes.Type('prop'), form="prop", seld=aetypes.Type('trsh'), fr=None)
    _reply, args, attrs = finder.send("fndr", "empt", args, attrs)
    if args.has_key('errn'):
        raise aetools.Error, aetools.decodeerror(args)


def _test():
    import EasyDialogs
    print 'Original findertools functionality test...'
    print 'Testing launch...'
    pathname = EasyDialogs.AskFileForOpen('File to launch:')
    if pathname:
        result = launch(pathname)
        if result:
            print 'Result: ', result
        print 'Press return-',
        sys.stdin.readline()
    print 'Testing print...'
    pathname = EasyDialogs.AskFileForOpen('File to print:')
    if pathname:
        result = Print(pathname)
        if result:
            print 'Result: ', result
        print 'Press return-',
        sys.stdin.readline()
    print 'Testing copy...'
    pathname = EasyDialogs.AskFileForOpen('File to copy:')
    if pathname:
        destdir = EasyDialogs.AskFolder('Destination:')
        if destdir:
            result = copy(pathname, destdir)
            if result:
                print 'Result:', result
            print 'Press return-',
            sys.stdin.readline()
    print 'Testing move...'
    pathname = EasyDialogs.AskFileForOpen('File to move:')
    if pathname:
        destdir = EasyDialogs.AskFolder('Destination:')
        if destdir:
            result = move(pathname, destdir)
            if result:
                print 'Result:', result
            print 'Press return-',
            sys.stdin.readline()
    print 'Testing sleep...'
    if EasyDialogs.AskYesNoCancel('Sleep?') > 0:
        result = sleep()
        if result:
            print 'Result:', result
        print 'Press return-',
        sys.stdin.readline()
    print 'Testing shutdown...'
    if EasyDialogs.AskYesNoCancel('Shut down?') > 0:
        result = shutdown()
        if result:
            print 'Result:', result
        print 'Press return-',
        sys.stdin.readline()
    print 'Testing restart...'
    if EasyDialogs.AskYesNoCancel('Restart?') > 0:
        result = restart()
        if result:
            print 'Result:', result
        print 'Press return-',
        sys.stdin.readline()

def _test2():
    print '\nmorefindertools version %s\nTests coming up...' %__version__
    import os
    import random

    # miscellaneous
    print '\tfilesharing on?',  filesharing()       # is file sharing on, off, starting up?
    print '\tOS version',       OSversion()     # the version of the system software

    # set the soundvolume in a simple way
    print '\tSystem beep volume'
    for i in range(0, 7):
        volumelevel(i)      
        MacOS.SysBeep()

    # Finder's windows, file location, file attributes
    open("@findertoolstest", "w")
    f = "@findertoolstest"
    reveal(f)               # reveal this file in a Finder window
    select(f)               # select this file

    base, file = os.path.split(f)
    closewindow(base)   # close the window this file is in  (opened by reveal)
    openwindow(base)        # open it again
    windowview(base, 1) # set the view by list

    label(f, 2)             # set the label of this file to something orange
    print '\tlabel', label(f)   # get the label of this file

    # the file location only works in a window with icon view!
    print 'Random locations for an icon'
    windowview(base, 0)     # set the view by icon
    windowsize(base, (600, 600))
    for i in range(50):
        location(f, (random.randint(10, 590), random.randint(10, 590)))

    windowsize(base, (200, 400))
    windowview(base, 1)     # set the view by icon

    orgpos = windowposition(base)
    print 'Animated window location'
    for i in range(10):
        pos = (100+i*10, 100+i*10)
        windowposition(base, pos)
        print '\twindow position', pos
    windowposition(base, orgpos)    # park it where it was before

    print 'Put a comment in file', f, ':'
    print '\t', comment(f)      # print the Finder comment this file has
    s = 'This is a comment no one reads!'
    comment(f, s)           # set the Finder comment
    
def _test3():
    print 'MacOS9 or better specific functions'
    # processes
    pr = processes()        # return a list of tuples with (active_processname, creatorcode)
    print 'Return a list of current active processes:'
    for p in pr:
        print '\t', p
    
    # get attributes of the first process in the list
    print 'Attributes of the first process in the list:'
    pinfo = processinfo(pr[0][0])
    print '\t', pr[0][0]
    print '\t\tmemory partition', pinfo.partition       # the memory allocated to this process
    print '\t\tmemory used', pinfo.used         # the memory actuall used by this process
    print '\t\tis visible', pinfo.visible           # is the process visible to the user
    print '\t\tis frontmost', pinfo.frontmost       # is the process the front most one?
    print '\t\thas scripting', pinfo.hasscripting       # is the process scriptable?
    print '\t\taccepts high level events',  pinfo.accepthighlevel   # does the process accept high level appleevents?

if __name__ == '__main__':
    _test()
    _test2()
    _test3()
    

--- NEW FILE: gensuitemodule.py ---
"""
gensuitemodule - Generate an AE suite module from an aete/aeut resource

Based on aete.py.

Reading and understanding this code is left as an exercise to the reader.
"""

import MacOS
import EasyDialogs
import os
import string
import sys
import types
import StringIO
import keyword
import macresource
import aetools
import distutils.sysconfig
[...1174 lines suppressed...]
    rv = ''
    ok = string.ascii_letters + '_'
    ok2 = ok + string.digits
    for c in str:
        if c in ok:
            rv = rv + c
        elif c == ' ':
            rv = rv + '_'
        else:
            rv = rv + '_%02.2x_'%ord(c)
        ok = ok2
    if keyword.iskeyword(rv):
        rv = rv + '_'
    return rv

# Call the main program

if __name__ == '__main__':
    main()
    sys.exit(1)

--- NEW FILE: ic.py ---
"""IC wrapper module, based on Internet Config 1.3"""

import icglue
import string
import sys
import os
from Carbon import Res
import Carbon.File
import macostools

error=icglue.error

# From ictypes.h:
icPrefNotFoundErr = -666        # preference not found (duh!)
icPermErr = -667                # cannot set preference
icPrefDataErr = -668            # problem with preference data
icInternalErr = -669            # hmm, this is not good
icTruncatedErr = -670           # more data was present than was returned
icNoMoreWritersErr = -671       # you cannot begin a write session because someone else is already doing it */
icNothingToOverrideErr = -672   # no component for the override component to capture
icNoURLErr = -673               # no URL found
icConfigNotFoundErr = -674      # no configuration was found
icConfigInappropriateErr = -675 # incorrect manufacturer code

ICattr_no_change = -1

icNoPerm = 0
icReadOnlyPerm = 1
icReadWritePerm = 2
# End of ictypes.h

class ICOpaqueData:
    """An unparseable IC entry"""
    def __init__(self, data):
        self.data = data

    def __repr__(self):
        return "ICOpaqueData(%r)"%(self.data,)

_ICOpaqueDataType=type(ICOpaqueData(''))
        
def _decode_default(data, key):
    if len(data) == 0:
        return data
    if ord(data[0]) == len(data)-1:
        # Assume Pstring
        return data[1:]
    return ICOpaqueData(data)
    
    
def _decode_multistr(data, key):
    numstr = ord(data[0]) << 8 | ord(data[1])
    rv = []
    ptr = 2
    for i in range(numstr):
        strlen = ord(data[ptr])
        str = data[ptr+1:ptr+strlen+1]
        rv.append(str)
        ptr = ptr + strlen + 1
    return rv
    
def _decode_fontrecord(data, key):
    size = ord(data[0]) << 8 | ord(data[1])
    face = ord(data[2])
    namelen = ord(data[4])
    return size, face, data[5:5+namelen]
    
def _decode_boolean(data, key):
    return ord(data[0])
    
def _decode_text(data, key):
    return data
    
def _decode_charset(data, key):
    return data[:256], data[256:]
    
def _decode_appspec(data, key):
    namelen = ord(data[4])
    return data[0:4], data[5:5+namelen]

def _code_default(data, key):
    return chr(len(data)) + data
        
def _code_multistr(data, key):
    numstr = len(data)
    rv = chr((numstr>>8) & 0xff) + chr(numstr & 0xff)
    for i in data:
        rv = rv + _code_default(i)
    return rv
    
def _code_fontrecord(data, key):
    size, face, name = data
    return chr((size>>8) & 0xff) + chr(size & 0xff) + chr(face & 0xff) + \
        chr(0) + _code_default(name)
    
def _code_boolean(data, key):
    print 'XXXX boolean:', repr(data)
    return chr(data)
    
def _code_text(data, key):
    return data
    
def _code_charset(data, key):
    return data[0] + data[1]
    
def _code_appspec(data, key):
    return data[0] + _code_default(data[1])
    
_decoder_table = {
    "ArchieAll" : (_decode_multistr , _code_multistr),
    "UMichAll" : (_decode_multistr , _code_multistr),
    "InfoMacAll" : (_decode_multistr , _code_multistr),
    "ListFont" : (_decode_fontrecord , _code_fontrecord),
    "ScreenFont" : (_decode_fontrecord , _code_fontrecord),
    "PrinterFont" : (_decode_fontrecord , _code_fontrecord),
#   "DownloadFolder" : (_decode_filespec , _code_filespec),
    "Signature": (_decode_text , _code_text),
    "Plan" : (_decode_text , _code_text),
    "MailHeaders" : (_decode_text , _code_text),
    "NewsHeaders" : (_decode_text , _code_text),
#   "Mapping" 
    "CharacterSet" : (_decode_charset , _code_charset),
    "Helper\245" : (_decode_appspec , _code_appspec),
#   "Services" : (_decode_services, ????),
    "NewMailFlashIcon" : (_decode_boolean , _code_boolean),
    "NewMailDialog" : (_decode_boolean , _code_boolean),
    "NewMailPlaySound" : (_decode_boolean , _code_boolean),
#   "WebBackgroundColor" : _decode_color,
    "NoProxyDomains" : (_decode_multistr , _code_multistr),
    "UseHTTPProxy" : (_decode_boolean , _code_boolean),
    "UseGopherProxy": (_decode_boolean , _code_boolean),
    "UseFTPProxy" : (_decode_boolean , _code_boolean),
    "UsePassiveFTP" : (_decode_boolean , _code_boolean),
}

def _decode(data, key):
    if '\245' in key:
        key2 = key[:string.index(key, '\245')+1]
    else:
        key2 = key
    if _decoder_table.has_key(key2):
        decoder = _decoder_table[key2][0]
    else:
        decoder = _decode_default
    return decoder(data, key)

def _code(data, key):
    if type(data) == _ICOpaqueDataType:
        return data.data
    if '\245' in key:
        key2 = key[:string.index(key, '\245')+1]
    else:
        key2 = key
    if _decoder_table.has_key(key2):
        coder = _decoder_table[key2][1]
    else:
        coder = _code_default
    return coder(data, key)
    
class IC:
    def __init__(self, signature='Pyth', ic=None):
        if ic:
            self.ic = ic
        else:
            self.ic = icglue.ICStart(signature)
            if hasattr(self.ic, 'ICFindConfigFile'):
                self.ic.ICFindConfigFile()
        self.h = Res.Resource('')
            
    def keys(self):
        rv = []
        self.ic.ICBegin(icReadOnlyPerm)
        num = self.ic.ICCountPref()
        for i in range(num):
            rv.append(self.ic.ICGetIndPref(i+1))
        self.ic.ICEnd()
        return rv
        
    def has_key(self, key):
        return self.__contains__(key)
        
    def __contains__(self, key):
        try:
            dummy = self.ic.ICFindPrefHandle(key, self.h)
        except icglue.error:
            return 0
        return 1
        
    def __getitem__(self, key):
        attr = self.ic.ICFindPrefHandle(key, self.h)
        return _decode(self.h.data, key)
        
    def __setitem__(self, key, value):
        value = _code(value, key)
        self.ic.ICSetPref(key, ICattr_no_change, value)
        
    def launchurl(self, url, hint=""):
        # Work around a bug in ICLaunchURL: file:/foo does
        # not work but file:///foo does.
        if url[:6] == 'file:/' and url[6] != '/':
            url = 'file:///' + url[6:]
        self.ic.ICLaunchURL(hint, url, 0, len(url))
        
    def parseurl(self, data, start=None, end=None, hint=""):
        if start == None:
            selStart = 0
            selEnd = len(data)
        else:
            selStart = selEnd = start
        if end != None:
            selEnd = end
        selStart, selEnd = self.ic.ICParseURL(hint, data, selStart, selEnd, self.h)
        return self.h.data, selStart, selEnd
        
    def mapfile(self, file):
        if type(file) != type(''):
            file = file.as_tuple()[2]
        return self.ic.ICMapFilename(file)
        
    def maptypecreator(self, type, creator, filename=""):
        return self.ic.ICMapTypeCreator(type, creator, filename)
        
    def settypecreator(self, file):
        file = Carbon.File.pathname(file)
        record = self.mapfile(os.path.split(file)[1])
        MacOS.SetCreatorAndType(file, record[2], record[1])
        macostools.touched(fss)
        
# Convenience routines
_dft_ic = None

def launchurl(url, hint=""):
    global _dft_ic
    if _dft_ic == None: _dft_ic = IC()
    return _dft_ic.launchurl(url, hint)
    
def parseurl(data, start=None, end=None, hint=""):
    global _dft_ic
    if _dft_ic == None: _dft_ic = IC()
    return _dft_ic.parseurl(data, start, end, hint)
    
def mapfile(filename):
    global _dft_ic
    if _dft_ic == None: _dft_ic = IC()
    return _dft_ic.mapfile(filename)
    
def maptypecreator(type, creator, filename=""):
    global _dft_ic
    if _dft_ic == None: _dft_ic = IC()
    return _dft_ic.maptypecreator(type, creator, filename)
    
def settypecreator(file):
    global _dft_ic
    if _dft_ic == None: _dft_ic = IC()
    return _dft_ic.settypecreator(file)
        
def _test():
    ic = IC()
    for k in ic.keys():
        try:
            v = ic[k]
        except error:
            v = '????'
        print k, '\t', v
    sys.exit(1)
    
if __name__ == '__main__':
    _test()
    

--- NEW FILE: icopen.py ---
"""icopen patch

OVERVIEW

icopen patches MacOS Python to use the Internet Config file mappings to select
the type and creator for a file.

Version 1 released to the public domain 3 November 1999
by Oliver Steele (steele at cs.brandeis.edu).

DETAILS

This patch causes files created by Python's open(filename, 'w') command (and
by functions and scripts that call it) to set the type and creator of the file
to the type and creator associated with filename's extension (the
portion of the filename after the last period), according to Internet Config.
Thus, a script that creates a file foo.html will create one that opens in whatever
browser you've set to handle *.html files, and so on.

Python IDE uses its own algorithm to select the type and creator for saved
editor windows, so this patch won't effect their types.

As of System 8.6 at least, Internet Config is built into the system, and the
file mappings are accessed from the Advanced pane of the Internet control
panel.  User Mode (in the Edit menu) needs to be set to Advanced in order to
access this pane.

INSTALLATION

Put this file in your Python path, and create a file named {Python}:sitecustomize.py
that contains:
        import icopen

(If {Python}:sitecustomizer.py already exists, just add the 'import' line to it.)

The next time you launch PythonInterpreter or Python IDE, the patch will take
effect.
"""

import __builtin__

_builtin_open = globals().get('_builtin_open', __builtin__.open)

def _open_with_typer(*args):
        file = _builtin_open(*args)
        filename = args[0]
        mode = 'r'
        if args[1:]:
                mode = args[1]
        if mode[0] == 'w':
                from ic import error, settypecreator
                try:
                        settypecreator(filename)
                except error:
                        pass
        return file

__builtin__.open = _open_with_typer

"""
open('test.py')
_open_with_typer('test.py', 'w')
_open_with_typer('test.txt', 'w')
_open_with_typer('test.html', 'w')
_open_with_typer('test.foo', 'w')
"""

--- NEW FILE: macerrors.py ---
svTempDisable   =   -32768  #svTempDisable
svDisabled  =   -32640  #Reserve range -32640 to -32768 for Apple temp disables.
fontNotOutlineErr   =   -32615  #bitmap font passed to routine that does outlines only
kURL68kNotSupportedError    =   -30788  #kURL68kNotSupportedError
kURLAccessNotAvailableError =   -30787  #kURLAccessNotAvailableError
kURLInvalidConfigurationError   =   -30786  #kURLInvalidConfigurationError
kURLExtensionFailureError   =   -30785  #kURLExtensionFailureError
kURLFileEmptyError  =   -30783  #kURLFileEmptyError
kURLInvalidCallError    =   -30781  #kURLInvalidCallError
kURLUnsettablePropertyError =   -30780  #kURLUnsettablePropertyError
kURLPropertyBufferTooSmallError =   -30779  #kURLPropertyBufferTooSmallError
kURLUnknownPropertyError    =   -30778  #kURLUnknownPropertyError
kURLPropertyNotYetKnownError    =   -30777  #kURLPropertyNotYetKnownError
kURLAuthenticationError =   -30776  #kURLAuthenticationError
kURLServerBusyError =   -30775  #kURLServerBusyError
kURLUnsupportedSchemeError  =   -30774  #kURLUnsupportedSchemeError
kURLInvalidURLError =   -30773  #kURLInvalidURLError
kURLDestinationExistsError  =   -30772  #kURLDestinationExistsError
kURLProgressAlreadyDisplayedError   =   -30771  #kURLProgressAlreadyDisplayedError
[...1813 lines suppressed...]
ENETRESET   =   52  #Network dropped connection on reset
ECONNABORTED    =   53  #Software caused connection abort
ECONNRESET  =   54  #Connection reset by peer
ENOBUFS =   55  #No buffer space available
EISCONN =   56  #Socket is already connected
ENOTCONN    =   57  #Socket is not connected
ESHUTDOWN   =   58  #Can't send after socket shutdown
ETOOMANYREFS    =   59  #Too many references: can't splice
ETIMEDOUT   =   60  #Operation timed out
ECONNREFUSED    =   61  #Connection refused
ELOOP   =   62  #Too many levels of symbolic links
ENAMETOOLONG    =   63  #File name too long
EHOSTDOWN   =   64  #Host is down
EHOSTUNREACH    =   65  #No route to host
ENOTEMPTY   =   66  #Directory not empty
ELOOK   =   67  #Internal mapping for kOTLookErr, don't return to client
ENOLCK  =   77  #No locks available
ENOSYS  =   78  #Function not implemented
EILSEQ  =   88  #Wide character encoding error
EUNKNOWN    =   99  #Unknown error

--- NEW FILE: macfs.py ---
"""macfs - Pure Python module designed to be backward compatible with
macfs and MACFS.
"""
import sys
import struct
import Carbon.Res
import Carbon.File
import warnings

warnings.warn("macfs is deprecated, use Carbon.File, Carbon.Folder or EasyDialogs",
              DeprecationWarning, stacklevel=2)
              
# First step: ensure we also emulate the MACFS module, which contained
# all the constants

sys.modules['MACFS'] = sys.modules[__name__]

# Import all those constants
from Carbon.Files import *
from Carbon.Folders import *

# For some obscure historical reason these are here too:
READ = 1
WRITE = 2
smAllScripts = -3

#
# Find the epoch conversion for file dates in a way that works on OS9 and OSX
import time
if time.gmtime(0)[0] == 1970:
    _EPOCHCONVERT = -((1970-1904)*365 + 17) * (24*60*60) + 0x100000000L
    def _utc2time(utc):
        t = utc[1] + _EPOCHCONVERT
        return int(t)
    def _time2utc(t):
        t = int(t) - _EPOCHCONVERT
        if t < -0x7fffffff:
            t = t + 0x10000000L
        return (0, int(t), 0)
else:
    def _utc2time(utc): 
        t = utc[1]
        if t < 0:
            t = t + 0x100000000L
        return t
    def _time2utc(t):
        if t > 0x7fffffff:
            t = t - 0x100000000L
        return (0, int(t), 0)

# The old name of the error object:
error = Carbon.File.Error

#
# The various objects macfs used to export. We override them here, because some
# of the method names are subtly different.
#
class FSSpec(Carbon.File.FSSpec):
    def as_fsref(self):
        return FSRef(self)
        
    def NewAlias(self, src=None):
        return Alias(Carbon.File.NewAlias(src, self))
        
    def GetCreatorType(self):
        finfo = self.FSpGetFInfo()
        return finfo.Creator, finfo.Type
        
    def SetCreatorType(self, ctor, tp):
        finfo = self.FSpGetFInfo()
        finfo.Creator = ctor
        finfo.Type = tp
        self.FSpSetFInfo(finfo)
        
    def GetFInfo(self):
        return self.FSpGetFInfo()
        
    def SetFInfo(self, info):
        return self.FSpSetFInfo(info)
        
    def GetDates(self):
        catInfoFlags = kFSCatInfoCreateDate|kFSCatInfoContentMod|kFSCatInfoBackupDate
        catinfo, d1, d2, d3 = FSRef(self).FSGetCatalogInfo(catInfoFlags)
        cdate = catinfo.createDate
        mdate = catinfo.contentModDate
        bdate = catinfo.backupDate
        return _utc2time(cdate), _utc2time(mdate), _utc2time(bdate)
    
    def SetDates(self, cdate, mdate, bdate):
        catInfoFlags = kFSCatInfoCreateDate|kFSCatInfoContentMod|kFSCatInfoBackupDate
        catinfo = Carbon.File.FSCatalogInfo(
            createDate = _time2utc(cdate),
            contentModDate = _time2utc(mdate),
            backupDate = _time2utc(bdate))
        FSRef(self).FSSetCatalogInfo(catInfoFlags, catinfo)
    
class FSRef(Carbon.File.FSRef):
    def as_fsspec(self):
        return FSSpec(self)
    
class Alias(Carbon.File.Alias):

    def GetInfo(self, index):
        return self.GetAliasInfo(index)
        
    def Update(self, *args):
        pass # print "Alias.Update not yet implemented"
        
    def Resolve(self, src=None):
        fss, changed = self.ResolveAlias(src)
        return FSSpec(fss), changed
        
from Carbon.File import FInfo

# Backward-compatible type names:
FSSpecType = FSSpec
FSRefType = FSRef
AliasType = Alias
FInfoType = FInfo

# Global functions:
def ResolveAliasFile(fss, chain=1):
    fss, isdir, isalias = Carbon.File.ResolveAliasFile(fss, chain)
    return FSSpec(fss), isdir, isalias
    
def RawFSSpec(data):
    return FSSpec(rawdata=data)
    
def RawAlias(data):
    return Alias(rawdata=data)
    
def FindApplication(*args):
    raise NotImplementedError, "FindApplication no longer implemented"
    
def NewAliasMinimalFromFullPath(path):
    return Alias(Carbon.File.NewAliasMinimalFromFullPath(path, '', ''))
    
# Another global function:
from Carbon.Folder import FindFolder

#
# Finally the old Standard File routine emulators.
#

_curfolder = None

def StandardGetFile(*typelist):
    """Ask for an input file, optionally specifying 4-char file types that are
    allowable"""
    return PromptGetFile('', *typelist)
    
def PromptGetFile(prompt, *typelist):
    """Ask for an input file giving the user a prompt message. Optionally you can
    specifying 4-char file types that are allowable"""
    import EasyDialogs
    warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
              DeprecationWarning, stacklevel=2)
    if not typelist:
        typelist = None
    fss = EasyDialogs.AskFileForOpen(message=prompt, wanted=FSSpec, 
        typeList=typelist, defaultLocation=_handleSetFolder())
    return fss, not fss is None

def StandardPutFile(prompt, default=None):
    """Ask the user for an output file, with a prompt. Optionally you cn supply a
    default output filename"""
    import EasyDialogs
    warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
              DeprecationWarning, stacklevel=2)
    fss = EasyDialogs.AskFileForSave(wanted=FSSpec, message=prompt, 
    savedFileName=default, defaultLocation=_handleSetFolder())
    return fss, not fss is None
    
def SetFolder(folder):
    global _curfolder
    warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
              DeprecationWarning, stacklevel=2)
    if _curfolder:
        rv = FSSpec(_curfolder)
    else:
        rv = None
    _curfolder = folder
    return rv
    
def _handleSetFolder():
    global _curfolder
    rv = _curfolder
    _curfolder = None
    return rv
    
def GetDirectory(prompt=None):
    """Ask the user to select a folder. Optionally you can give a prompt."""
    import EasyDialogs
    warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
              DeprecationWarning, stacklevel=2)
    fss = EasyDialogs.AskFolder(message=prompt, wanted=FSSpec, 
        defaultLocation=_handleSetFolder())
    return fss, not fss is None

--- NEW FILE: macostools.py ---
"""macostools - Various utility functions for MacOS.

mkalias(src, dst) - Create a finder alias 'dst' pointing to 'src'
copy(src, dst) - Full copy of 'src' to 'dst'
"""

from Carbon import Res
from Carbon import File, Files
import os
import sys
import MacOS
import time
try:
    openrf = MacOS.openrf
except AttributeError:
    # Backward compatability
    openrf = open

Error = 'macostools.Error'

BUFSIZ=0x80000      # Copy in 0.5Mb chunks

COPY_FLAGS = (Files.kIsStationary|Files.kNameLocked|Files.kHasBundle|
              Files.kIsInvisible|Files.kIsAlias)

#
# Not guaranteed to be correct or stay correct (Apple doesn't tell you
# how to do this), but it seems to work.
#
def mkalias(src, dst, relative=None):
    """Create a finder alias"""
    srcfsr = File.FSRef(src)
    # The next line will fail under unix-Python if the destination
    # doesn't exist yet. We should change this code to be fsref-based.
    dstdir, dstname = os.path.split(dst)
    if not dstdir: dstdir = os.curdir
    dstdirfsr = File.FSRef(dstdir)
    if relative:
        relativefsr = File.FSRef(relative)
        # ik mag er geen None in stoppen :-(
        alias = File.FSNewAlias(relativefsr, srcfsr)
    else:
        alias = srcfsr.FSNewAliasMinimal()
    
    dstfsr, dstfss = Res.FSCreateResourceFile(dstdirfsr, unicode(dstname), 
        File.FSGetResourceForkName())
    h = Res.FSOpenResourceFile(dstfsr, File.FSGetResourceForkName(), 3)
    resource = Res.Resource(alias.data)
    resource.AddResource('alis', 0, '')
    Res.CloseResFile(h)
    
    dstfinfo = dstfss.FSpGetFInfo()
    dstfinfo.Flags = dstfinfo.Flags|0x8000    # Alias flag
    dstfss.FSpSetFInfo(dstfinfo)
    
def mkdirs(dst):
    """Make directories leading to 'dst' if they don't exist yet"""
    if dst == '' or os.path.exists(dst):
        return
    head, tail = os.path.split(dst)
    if os.sep == ':' and not ':' in head:
        head = head + ':'
    mkdirs(head)
    os.mkdir(dst, 0777)
    
def touched(dst):
    """Tell the finder a file has changed. No-op on MacOSX."""
    if sys.platform != 'mac': return
    import warnings
    warnings.filterwarnings("ignore", "macfs.*", DeprecationWarning, __name__)
    import macfs
    file_fss = macfs.FSSpec(dst)
    vRefNum, dirID, name = file_fss.as_tuple()
    dir_fss = macfs.FSSpec((vRefNum, dirID, ''))
    crdate, moddate, bkdate = dir_fss.GetDates()
    now = time.time()
    if now == moddate:
        now = now + 1
    try:
        dir_fss.SetDates(crdate, now, bkdate)
    except macfs.error:
        pass
    
def touched_ae(dst):
    """Tell the finder a file has changed"""
    pardir = os.path.split(dst)[0]
    if not pardir:
        pardir = os.curdir
    import Finder
    f = Finder.Finder()
    f.update(File.FSRef(pardir))
    
def copy(src, dst, createpath=0, copydates=1, forcetype=None):
    """Copy a file, including finder info, resource fork, etc"""
    src = File.pathname(src)
    dst = File.pathname(dst)
    if createpath:
        mkdirs(os.path.split(dst)[0])
    
    ifp = open(src, 'rb')
    ofp = open(dst, 'wb')
    d = ifp.read(BUFSIZ)
    while d:
        ofp.write(d)
        d = ifp.read(BUFSIZ)
    ifp.close()
    ofp.close()
    
    ifp = openrf(src, '*rb')
    ofp = openrf(dst, '*wb')
    d = ifp.read(BUFSIZ)
    while d:
        ofp.write(d)
        d = ifp.read(BUFSIZ)
    ifp.close()
    ofp.close()
    
    srcfss = File.FSSpec(src)
    dstfss = File.FSSpec(dst)
    sf = srcfss.FSpGetFInfo()
    df = dstfss.FSpGetFInfo()
    df.Creator, df.Type = sf.Creator, sf.Type
    if forcetype != None:
        df.Type = forcetype
    df.Flags = (sf.Flags & COPY_FLAGS)
    dstfss.FSpSetFInfo(df)
    if copydates:
        srcfsr = File.FSRef(src)
        dstfsr = File.FSRef(dst)
        catinfo, _, _, _ = srcfsr.FSGetCatalogInfo(Files.kFSCatInfoAllDates)
        dstfsr.FSSetCatalogInfo(Files.kFSCatInfoAllDates, catinfo)
    touched(dstfss)
    
def copytree(src, dst, copydates=1):
    """Copy a complete file tree to a new destination"""
    if os.path.isdir(src):
        mkdirs(dst)
        files = os.listdir(src)
        for f in files:
            copytree(os.path.join(src, f), os.path.join(dst, f), copydates)
    else:
        copy(src, dst, 1, copydates)

--- NEW FILE: macresource.py ---
"""macresource - Locate and open the resources needed for a script."""

from Carbon import Res
import os
import sys
import MacOS
import macostools

class ArgumentError(TypeError): pass
class ResourceFileNotFoundError(ImportError): pass

def need(restype, resid, filename=None, modname=None):
    """Open a resource file, if needed. restype and resid
    are required parameters, and identify the resource for which to test. If it
    is available we are done. If it is not available we look for a file filename
    (default: modname with .rsrc appended) either in the same folder as
    where modname was loaded from, or otherwise across sys.path.
    
    Returns the refno of the resource file opened (or None)"""

    if modname is None and filename is None:
        raise ArgumentError, "Either filename or modname argument (or both) must be given"
    
    if type(resid) is type(1):
        try:
            h = Res.GetResource(restype, resid)
        except Res.Error:
            pass
        else:
            return None
    else:
        try:
            h = Res.GetNamedResource(restype, resid)
        except Res.Error:
            pass
        else:
            return None
            
    # Construct a filename if we don't have one
    if not filename:
        if '.' in modname:
            filename = modname.split('.')[-1] + '.rsrc'
        else:
            filename = modname + '.rsrc'
    
    # Now create a list of folders to search
    searchdirs = []
    if modname == '__main__':
        # If we're main we look in the current directory
        searchdirs = [os.curdir]
    if sys.modules.has_key(modname):
        mod = sys.modules[modname]
        if hasattr(mod, '__file__'):
            searchdirs = [os.path.dirname(mod.__file__)]
    searchdirs.extend(sys.path)
    
    # And look for the file
    for dir in searchdirs:
        pathname = os.path.join(dir, filename)
        if os.path.exists(pathname):
            break
    else:
        raise ResourceFileNotFoundError, filename
    
    refno = open_pathname(pathname)
    
    # And check that the resource exists now
    if type(resid) is type(1):
        h = Res.GetResource(restype, resid)
    else:
        h = Res.GetNamedResource(restype, resid)
    return refno
    
def open_pathname(pathname, verbose=0):
    """Open a resource file given by pathname, possibly decoding an
    AppleSingle file"""
    try:
        refno = Res.FSpOpenResFile(pathname, 1)
    except Res.Error, arg:
        if arg[0] in (-37, -39):
            # No resource fork. We may be on OSX, and this may be either
            # a data-fork based resource file or a AppleSingle file
            # from the CVS repository.
            try:
                refno = Res.FSOpenResourceFile(pathname, u'', 1)
            except Res.Error, arg:
                if arg[0] != -199:
                    # -199 is "bad resource map"
                    raise
            else:
                return refno
            # Finally try decoding an AppleSingle file
            pathname = _decode(pathname, verbose=verbose)
            refno = Res.FSOpenResourceFile(pathname, u'', 1)
        else:
            raise
    return refno
    
def resource_pathname(pathname, verbose=0):
    """Return the pathname for a resource file (either DF or RF based).
    If the pathname given already refers to such a file simply return it,
    otherwise first decode it."""
    try:
        refno = Res.FSpOpenResFile(pathname, 1)
        Res.CloseResFile(refno)
    except Res.Error, arg:
        if arg[0] in (-37, -39):
            # No resource fork. We may be on OSX, and this may be either
            # a data-fork based resource file or a AppleSingle file
            # from the CVS repository.
            try:
                refno = Res.FSOpenResourceFile(pathname, u'', 1)
            except Res.Error, arg:
                if arg[0] != -199:
                    # -199 is "bad resource map"
                    raise
            else:
                return refno
            # Finally try decoding an AppleSingle file
            pathname = _decode(pathname, verbose=verbose)
        else:
            raise
    return pathname
    
def open_error_resource():
    """Open the resource file containing the error code to error message
    mapping."""
    need('Estr', 1, filename="errors.rsrc", modname=__name__)
    
def _decode(pathname, verbose=0):
    # Decode an AppleSingle resource file, return the new pathname.
    newpathname = pathname + '.df.rsrc'
    if os.path.exists(newpathname) and \
        os.stat(newpathname).st_mtime >= os.stat(pathname).st_mtime:
        return newpathname
    if hasattr(os, 'access') and not \
        os.access(os.path.dirname(pathname), os.W_OK|os.X_OK):
        # The destination directory isn't writeable. Create the file in
        # a temporary directory
        import tempfile
        fd, newpathname = tempfile.mkstemp(".rsrc")
    if verbose:
        print 'Decoding', pathname, 'to', newpathname
    import applesingle
    applesingle.decode(pathname, newpathname, resonly=1)
    return newpathname

--- NEW FILE: pimp.py ---
"""Package Install Manager for Python.

This is currently a MacOSX-only strawman implementation. 
Despite other rumours the name stands for "Packman IMPlementation".

Tools to allow easy installation of packages. The idea is that there is
an online XML database per (platform, python-version) containing packages
known to work with that combination. This module contains tools for getting
and parsing the database, testing whether packages are installed, computing
dependencies and installing packages.

There is a minimal main program that works as a command line tool, but the
intention is that the end user will use this through a GUI.
"""
import sys
import os
import popen2
import urllib
import urllib2
[...1101 lines suppressed...]
# If the end-user updates pimp through pimp the new version
# will be called pimp_update and live in site-packages
# or somewhere similar
if __name__ != 'pimp_update':
    try:
        import pimp_update
    except ImportError:
        pass
    else:
        if pimp_update.PIMP_VERSION <= PIMP_VERSION:
            import warnings
            warnings.warn("pimp_update is version %s, not newer than pimp version %s" %
                (pimp_update.PIMP_VERSION, PIMP_VERSION))
        else:
            from pimp_update import *
    
if __name__ == '__main__':
    main()
    
    

--- NEW FILE: plistlib.py ---
"""plistlib.py -- a tool to generate and parse MacOSX .plist files.

The main class in this module is Plist. It takes a set of arbitrary
keyword arguments, which will be the top level elements of the plist
dictionary. After instantiation you can add more elements by assigning
new attributes to the Plist instance.

To write out a plist file, call the write() method of the Plist
instance with a filename or a file object.

To parse a plist from a file, use the Plist.fromFile(pathOrFile)
classmethod, with a file name or a file object as the only argument.
(Warning: you need pyexpat installed for this to work, ie. it doesn't
work with a vanilla Python 2.2 as shipped with MacOS X.2.)

Values can be strings, integers, floats, booleans, tuples, lists,
dictionaries, Data or Date objects. String values (including dictionary
keys) may be unicode strings -- they will be written out as UTF-8.

For convenience, this module exports a class named Dict(), which
allows you to easily construct (nested) dicts using keyword arguments.
But regular dicts work, too.

To support Boolean values in plists with Python < 2.3, "bool", "True"
and "False" are exported. Use these symbols from this module if you
want to be compatible with Python 2.2.x (strongly recommended).

The <data> plist type is supported through the Data class. This is a
thin wrapper around a Python string.

The <date> plist data has (limited) support through the Date class.
(Warning: Dates are only supported if the PyXML package is installed.)

Generate Plist example:

    pl = Plist(
        aString="Doodah",
        aList=["A", "B", 12, 32.1, [1, 2, 3]],
        aFloat = 0.1,
        anInt = 728,
        aDict=Dict(
            anotherString="<hello & hi there!>",
            aUnicodeValue=u'M\xe4ssig, Ma\xdf',
            aTrueValue=True,
            aFalseValue=False,
        ),
        someData = Data("<binary gunk>"),
        someMoreData = Data("<lots of binary gunk>" * 10),
        aDate = Date(time.mktime(time.gmtime())),
    )
    # unicode keys are possible, but a little awkward to use:
    pl[u'\xc5benraa'] = "That was a unicode key."
    pl.write(fileName)

Parse Plist example:

    pl = Plist.fromFile(pathOrFile)
    print pl.aKey


"""

# written by Just van Rossum (just at letterror.com), 2002-11-19


__all__ = ["Plist", "Data", "Date", "Dict", "False", "True", "bool"]


INDENT = "\t"


class DumbXMLWriter:

    def __init__(self, file):
        self.file = file
        self.stack = []
        self.indentLevel = 0

    def beginElement(self, element):
        self.stack.append(element)
        self.writeln("<%s>" % element)
        self.indentLevel += 1

    def endElement(self, element):
        assert self.indentLevel > 0
        assert self.stack.pop() == element
        self.indentLevel -= 1
        self.writeln("</%s>" % element)

    def simpleElement(self, element, value=None):
        if value is not None:
            value = _encode(value)
            self.writeln("<%s>%s</%s>" % (element, value, element))
        else:
            self.writeln("<%s/>" % element)

    def writeln(self, line):
        if line:
            self.file.write(self.indentLevel * INDENT + line + "\n")
        else:
            self.file.write("\n")


def _encode(text):
    text = text.replace("&", "&amp;")
    text = text.replace("<", "&lt;")
    return text.encode("utf-8")


PLISTHEADER = """\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
"""

class PlistWriter(DumbXMLWriter):

    def __init__(self, file):
        file.write(PLISTHEADER)
        DumbXMLWriter.__init__(self, file)

    def writeValue(self, value):
        if isinstance(value, (str, unicode)):
            self.simpleElement("string", value)
        elif isinstance(value, bool):
            # must switch for bool before int, as bool is a
            # subclass of int...
            if value:
                self.simpleElement("true")
            else:
                self.simpleElement("false")
        elif isinstance(value, int):
            self.simpleElement("integer", str(value))
        elif isinstance(value, float):
            # should perhaps use repr() for better precision?
            self.simpleElement("real", str(value))
        elif isinstance(value, (dict, Dict)):
            self.writeDict(value)
        elif isinstance(value, Data):
            self.writeData(value)
        elif isinstance(value, Date):
            self.simpleElement("date", value.toString())
        elif isinstance(value, (tuple, list)):
            self.writeArray(value)
        else:
            raise TypeError("unsuported type: %s" % type(value))

    def writeData(self, data):
        self.beginElement("data")
        for line in data.asBase64().split("\n"):
            if line:
                self.writeln(line)
        self.endElement("data")

    def writeDict(self, d):
        self.beginElement("dict")
        items = d.items()
        items.sort()
        for key, value in items:
            if not isinstance(key, (str, unicode)):
                raise TypeError("keys must be strings")
            self.simpleElement("key", key)
            self.writeValue(value)
        self.endElement("dict")

    def writeArray(self, array):
        self.beginElement("array")
        for value in array:
            self.writeValue(value)
        self.endElement("array")


class Dict:

    """Dict wrapper for convenient access of values through attributes."""

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def __cmp__(self, other):
        if isinstance(other, self.__class__):
            return cmp(self.__dict__, other.__dict__)
        elif isinstance(other, dict):
            return cmp(self.__dict__, other)
        else:
            return cmp(id(self), id(other))

    def __str__(self):
        return "%s(**%s)" % (self.__class__.__name__, self.__dict__)
    __repr__ = __str__

    def copy(self):
        return self.__class__(**self.__dict__)

    def __getattr__(self, attr):
        """Delegate everything else to the dict object."""
        return getattr(self.__dict__, attr)


class Plist(Dict):

    """The main Plist object. Basically a dict (the toplevel object
    of a plist is a dict) with two additional methods to read from
    and write to files.
    """

    def fromFile(cls, pathOrFile):
        didOpen = 0
        if isinstance(pathOrFile, (str, unicode)):
            pathOrFile = open(pathOrFile)
            didOpen = 1
        p = PlistParser()
        plist = p.parse(pathOrFile)
        if didOpen:
            pathOrFile.close()
        return plist
    fromFile = classmethod(fromFile)

    def write(self, pathOrFile):
        if isinstance(pathOrFile, (str, unicode)):
            pathOrFile = open(pathOrFile, "w")
            didOpen = 1
        else:
            didOpen = 0

        writer = PlistWriter(pathOrFile)
        writer.writeln("<plist version=\"1.0\">")
        writer.writeDict(self.__dict__)
        writer.writeln("</plist>")

        if didOpen:
            pathOrFile.close()


class Data:

    """Wrapper for binary data."""

    def __init__(self, data):
        self.data = data

    def fromBase64(cls, data):
        import base64
        return cls(base64.decodestring(data))
    fromBase64 = classmethod(fromBase64)

    def asBase64(self):
        import base64
        return base64.encodestring(self.data)

    def __cmp__(self, other):
        if isinstance(other, self.__class__):
            return cmp(self.data, other.data)
        elif isinstance(other, str):
            return cmp(self.data, other)
        else:
            return cmp(id(self), id(other))

    def __repr__(self):
        return "%s(%s)" % (self.__class__.__name__, repr(self.data))


class Date:

    """Primitive date wrapper, uses time floats internally, is agnostic
    about time zones.
    """

    def __init__(self, date):
        if isinstance(date, str):
            from xml.utils.iso8601 import parse
            date = parse(date)
        self.date = date

    def toString(self):
        from xml.utils.iso8601 import tostring
        return tostring(self.date)

    def __cmp__(self, other):
        if isinstance(other, self.__class__):
            return cmp(self.date, other.date)
        elif isinstance(other, (int, float)):
            return cmp(self.date, other)
        else:
            return cmp(id(self), id(other))

    def __repr__(self):
        return "%s(%s)" % (self.__class__.__name__, repr(self.toString()))


class PlistParser:

    def __init__(self):
        self.stack = []
        self.currentKey = None
        self.root = None

    def parse(self, file):
        from xml.parsers.expat import ParserCreate
        parser = ParserCreate()
        parser.StartElementHandler = self.handleBeginElement
        parser.EndElementHandler = self.handleEndElement
        parser.CharacterDataHandler = self.handleData
        parser.ParseFile(file)
        return self.root

    def handleBeginElement(self, element, attrs):
        self.data = []
        handler = getattr(self, "begin_" + element, None)
        if handler is not None:
            handler(attrs)

    def handleEndElement(self, element):
        handler = getattr(self, "end_" + element, None)
        if handler is not None:
            handler()

    def handleData(self, data):
        self.data.append(data)

    def addObject(self, value):
        if self.currentKey is not None:
            self.stack[-1][self.currentKey] = value
            self.currentKey = None
        elif not self.stack:
            # this is the root object
            assert self.root is value
        else:
            self.stack[-1].append(value)

    def getData(self):
        data = "".join(self.data)
        try:
            data = data.encode("ascii")
        except UnicodeError:
            pass
        self.data = []
        return data

    # element handlers

    def begin_dict(self, attrs):
        if self.root is None:
            self.root = d = Plist()
        else:
            d = Dict()
        self.addObject(d)
        self.stack.append(d)
    def end_dict(self):
        self.stack.pop()

    def end_key(self):
        self.currentKey = self.getData()

    def begin_array(self, attrs):
        a = []
        self.addObject(a)
        self.stack.append(a)
    def end_array(self):
        self.stack.pop()

    def end_true(self):
        self.addObject(True)
    def end_false(self):
        self.addObject(False)
    def end_integer(self):
        self.addObject(int(self.getData()))
    def end_real(self):
        self.addObject(float(self.getData()))
    def end_string(self):
        self.addObject(self.getData())
    def end_data(self):
        self.addObject(Data.fromBase64(self.getData()))
    def end_date(self):
        self.addObject(Date(self.getData()))


# cruft to support booleans in Python <= 2.3
import sys
if sys.version_info[:2] < (2, 3):
    # Python 2.2 and earlier: no booleans
    # Python 2.2.x: booleans are ints
    class bool(int):
        """Imitation of the Python 2.3 bool object."""
        def __new__(cls, value):
            return int.__new__(cls, not not value)
        def __repr__(self):
            if self:
                return "True"
            else:
                return "False"
    True = bool(1)
    False = bool(0)
else:
    # Bind the boolean builtins to local names
    True = True
    False = False
    bool = bool


if __name__ == "__main__":
    from StringIO import StringIO
    import time
    if len(sys.argv) == 1:
        pl = Plist(
            aString="Doodah",
            aList=["A", "B", 12, 32.1, [1, 2, 3]],
            aFloat = 0.1,
            anInt = 728,
            aDict=Dict(
                anotherString="<hello & hi there!>",
                aUnicodeValue=u'M\xe4ssig, Ma\xdf',
                aTrueValue=True,
                aFalseValue=False,
            ),
            someData = Data("<binary gunk>"),
            someMoreData = Data("<lots of binary gunk>" * 10),
            aDate = Date(time.mktime(time.gmtime())),
        )
    elif len(sys.argv) == 2:
        pl = Plist.fromFile(sys.argv[1])
    else:
        print "Too many arguments: at most 1 plist file can be given."
        sys.exit(1)

    # unicode keys are possible, but a little awkward to use:
    pl[u'\xc5benraa'] = "That was a unicode key."
    f = StringIO()
    pl.write(f)
    xml = f.getvalue()
    print xml
    f.seek(0)
    pl2 = Plist.fromFile(f)
    assert pl == pl2
    f = StringIO()
    pl2.write(f)
    assert xml == f.getvalue()
    #print repr(pl2)

--- NEW FILE: terminalcommand.py ---
"""terminalcommand.py -- A minimal interface to Terminal.app.

To run a shell command in a new Terminal.app window:

    import terminalcommand
    terminalcommand.run("ls -l")

No result is returned; it is purely meant as a quick way to run a script
with a decent input/output window.
"""

#
# This module is a fairly straightforward translation of Jack Jansen's
# Mac/OSX/PythonLauncher/doscript.m.
#

import time
import os
from Carbon import AE
from Carbon.AppleEvents import *


TERMINAL_SIG = "trmx"
START_TERMINAL = "/usr/bin/open /Applications/Utilities/Terminal.app"
SEND_MODE = kAENoReply  # kAEWaitReply hangs when run from Terminal.app itself


def run(command):
    """Run a shell command in a new Terminal.app window."""
    termAddress = AE.AECreateDesc(typeApplSignature, TERMINAL_SIG)
    theEvent = AE.AECreateAppleEvent(kAECoreSuite, kAEDoScript, termAddress,
                                     kAutoGenerateReturnID, kAnyTransactionID)
    commandDesc = AE.AECreateDesc(typeChar, command)
    theEvent.AEPutParamDesc(kAECommandClass, commandDesc)

    try:
        theEvent.AESend(SEND_MODE, kAENormalPriority, kAEDefaultTimeout)
    except AE.Error, why:
        if why[0] != -600:  # Terminal.app not yet running
            raise
        os.system(START_TERMINAL)
        time.sleep(1)
        theEvent.AESend(SEND_MODE, kAENormalPriority, kAEDefaultTimeout)


if __name__ == "__main__":
    run("ls -l")

--- NEW FILE: videoreader.py ---
# Video file reader, using QuickTime
#
# This module was quickly ripped out of another software package, so there is a good
# chance that it does not work as-is and it needs some hacking.
#
# Jack Jansen, August 2000
#
import sys
from Carbon import Qt
from Carbon import QuickTime
from Carbon import Qd
from Carbon import Qdoffs
from Carbon import QDOffscreen
from Carbon import Res
try:
    import MediaDescr
except ImportError:
    def _audiodescr(data):
        return None
else:
    def _audiodescr(data):
        return MediaDescr.SoundDescription.decode(data)
try:
    from imgformat import macrgb
except ImportError:
    macrgb = "Macintosh RGB format"
import os
# import audio.format

class VideoFormat:
    def __init__(self, name, descr, width, height, format):
        self.__name = name
        self.__descr = descr
        self.__width = width
        self.__height = height
        self.__format = format
        
    def getname(self):
        return self.__name
        
    def getdescr(self):
        return self.__descr
        
    def getsize(self):
        return self.__width, self.__height
        
    def getformat(self):
        return self.__format
        
class _Reader:
    def __init__(self, path):
        fd = Qt.OpenMovieFile(path, 0)
        self.movie, d1, d2 = Qt.NewMovieFromFile(fd, 0, 0)
        self.movietimescale = self.movie.GetMovieTimeScale()
        try:
            self.audiotrack = self.movie.GetMovieIndTrackType(1,
                QuickTime.AudioMediaCharacteristic, QuickTime.movieTrackCharacteristic)
            self.audiomedia = self.audiotrack.GetTrackMedia()
        except Qt.Error:
            self.audiotrack = self.audiomedia = None
            self.audiodescr = {}
        else:
            handle = Res.Handle('')
            n = self.audiomedia.GetMediaSampleDescriptionCount()
            self.audiomedia.GetMediaSampleDescription(1, handle)
            self.audiodescr = _audiodescr(handle.data)
            self.audiotimescale = self.audiomedia.GetMediaTimeScale()
            del handle
    
        try:    
            self.videotrack = self.movie.GetMovieIndTrackType(1,
                QuickTime.VisualMediaCharacteristic, QuickTime.movieTrackCharacteristic)
            self.videomedia = self.videotrack.GetTrackMedia()
        except Qt.Error:
            self.videotrack = self.videomedia = self.videotimescale = None
        if self.videotrack:
            self.videotimescale = self.videomedia.GetMediaTimeScale()
            x0, y0, x1, y1 = self.movie.GetMovieBox()
            self.videodescr = {'width':(x1-x0), 'height':(y1-y0)}
            self._initgworld()
        self.videocurtime = None
        self.audiocurtime = None

        
    def __del__(self):
        self.audiomedia = None
        self.audiotrack = None
        self.videomedia = None
        self.videotrack = None
        self.movie = None
        
    def _initgworld(self):
        old_port, old_dev = Qdoffs.GetGWorld()
        try:
            movie_w = self.videodescr['width']
            movie_h = self.videodescr['height']
            movie_rect = (0, 0, movie_w, movie_h)
            self.gworld = Qdoffs.NewGWorld(32,  movie_rect, None, None, QDOffscreen.keepLocal)
            self.pixmap = self.gworld.GetGWorldPixMap()
            Qdoffs.LockPixels(self.pixmap)
            Qdoffs.SetGWorld(self.gworld.as_GrafPtr(), None)
            Qd.EraseRect(movie_rect)
            self.movie.SetMovieGWorld(self.gworld.as_GrafPtr(), None)
            self.movie.SetMovieBox(movie_rect)
            self.movie.SetMovieActive(1)
            self.movie.MoviesTask(0)
            self.movie.SetMoviePlayHints(QuickTime.hintsHighQuality, QuickTime.hintsHighQuality)
            # XXXX framerate
        finally:
            Qdoffs.SetGWorld(old_port, old_dev)
        
    def _gettrackduration_ms(self, track):
        tracktime = track.GetTrackDuration()
        return self._movietime_to_ms(tracktime)
        
    def _movietime_to_ms(self, time):
        value, d1, d2 = Qt.ConvertTimeScale((time, self.movietimescale, None), 1000)
        return value
        
    def _videotime_to_ms(self, time):
        value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), 1000)
        return value
        
    def _audiotime_to_ms(self, time):
        value, d1, d2 = Qt.ConvertTimeScale((time, self.audiotimescale, None), 1000)
        return value
        
    def _videotime_to_movietime(self, time):
        value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None),
                self.movietimescale)
        return value
        
    def HasAudio(self):
        return not self.audiotrack is None
        
    def HasVideo(self):
        return not self.videotrack is None
        
    def GetAudioDuration(self):
        if not self.audiotrack:
            return 0
        return self._gettrackduration_ms(self.audiotrack)

    def GetVideoDuration(self):
        if not self.videotrack:
            return 0
        return self._gettrackduration_ms(self.videotrack)
        
    def GetAudioFormat(self):
        if not self.audiodescr:
            return None, None, None, None, None
        bps = self.audiodescr['sampleSize']
        nch = self.audiodescr['numChannels']
        if nch == 1:
            channels = ['mono']
        elif nch == 2:
            channels = ['left', 'right']
        else:
            channels = map(lambda x: str(x+1), range(nch))
        if bps % 8:
            # Funny bits-per sample. We pretend not to understand
            blocksize = 0
            fpb = 0
        else:
            # QuickTime is easy (for as far as we support it): samples are always a whole
            # number of bytes, so frames are nchannels*samplesize, and there's one frame per block.
            blocksize = (bps/8)*nch
            fpb = 1
        if self.audiodescr['dataFormat'] == 'raw ':
            encoding = 'linear-excess'
        elif self.audiodescr['dataFormat'] == 'twos':
            encoding = 'linear-signed'
        else:
            encoding = 'quicktime-coding-%s'%self.audiodescr['dataFormat']
##      return audio.format.AudioFormatLinear('quicktime_audio', 'QuickTime Audio Format', 
##          channels, encoding, blocksize=blocksize, fpb=fpb, bps=bps)
        return channels, encoding, blocksize, fpb, bps
            
    def GetAudioFrameRate(self):
        if not self.audiodescr:
            return None
        return int(self.audiodescr['sampleRate'])
        
    def GetVideoFormat(self):
        width = self.videodescr['width']
        height = self.videodescr['height']
        return VideoFormat('dummy_format', 'Dummy Video Format', width, height, macrgb)
        
    def GetVideoFrameRate(self):
        tv = self.videocurtime
        if tv == None:
            tv = 0
        flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
        tv, dur = self.videomedia.GetMediaNextInterestingTime(flags, tv, 1.0)
        dur = self._videotime_to_ms(dur)
        return int((1000.0/dur)+0.5)
        
    def ReadAudio(self, nframes, time=None):
        if not time is None:
            self.audiocurtime = time
        flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
        if self.audiocurtime == None:
            self.audiocurtime = 0
        tv = self.audiomedia.GetMediaNextInterestingTimeOnly(flags, self.audiocurtime, 1.0)
        if tv < 0 or (self.audiocurtime and tv < self.audiocurtime):
            return self._audiotime_to_ms(self.audiocurtime), None
        h = Res.Handle('')
        desc_h = Res.Handle('')
        size, actualtime, sampleduration, desc_index, actualcount, flags = \
            self.audiomedia.GetMediaSample(h, 0, tv, desc_h, nframes)
        self.audiocurtime = actualtime + actualcount*sampleduration
        return self._audiotime_to_ms(actualtime), h.data
        
    def ReadVideo(self, time=None):
        if not time is None:
            self.videocurtime = time
        flags = QuickTime.nextTimeStep
        if self.videocurtime == None:
            flags = flags | QuickTime.nextTimeEdgeOK
            self.videocurtime = 0
        tv = self.videomedia.GetMediaNextInterestingTimeOnly(flags, self.videocurtime, 1.0)
        if tv < 0 or (self.videocurtime and tv <= self.videocurtime):
            return self._videotime_to_ms(self.videocurtime), None
        self.videocurtime = tv
        moviecurtime = self._videotime_to_movietime(self.videocurtime)
        self.movie.SetMovieTimeValue(moviecurtime)
        self.movie.MoviesTask(0)
        return self._videotime_to_ms(self.videocurtime), self._getpixmapcontent()
        
    def _getpixmapcontent(self):
        """Shuffle the offscreen PixMap data, because it may have funny stride values"""
        rowbytes = Qdoffs.GetPixRowBytes(self.pixmap)
        width = self.videodescr['width']
        height = self.videodescr['height']
        start = 0
        rv = ''
        for i in range(height):
            nextline = Qdoffs.GetPixMapBytes(self.pixmap, start, width*4)
            start = start + rowbytes
            rv = rv + nextline
        return rv

def reader(url):
    try:
        rdr = _Reader(url)
    except IOError:
        return None
    return rdr

def _test():
    import EasyDialogs
    try:
        import img
    except ImportError:
        img = None
    import MacOS
    Qt.EnterMovies()
    path = EasyDialogs.AskFileForOpen(message='Video to convert')
    if not path: sys.exit(0)
    rdr = reader(path)
    if not rdr:
        sys.exit(1)
    dstdir = EasyDialogs.AskFileForSave(message='Name for output folder')
    if not dstdir: sys.exit(0)
    num = 0
    os.mkdir(dstdir)
    videofmt = rdr.GetVideoFormat()
    imgfmt = videofmt.getformat()
    imgw, imgh = videofmt.getsize()
    timestamp, data = rdr.ReadVideo()
    while data:
        fname = 'frame%04.4d.jpg'%num
        num = num+1
        pname = os.path.join(dstdir, fname)
        if not img: print 'Not',
        print 'Writing %s, size %dx%d, %d bytes'%(fname, imgw, imgh, len(data))
        if img:
            wrt = img.writer(imgfmt, pname)
            wrt.width = imgw
            wrt.height = imgh
            wrt.write(data)
            timestamp, data = rdr.ReadVideo()
            MacOS.SetCreatorAndType(pname, 'ogle', 'JPEG')
            if num > 20: 
                print 'stopping at 20 frames so your disk does not fill up:-)'
                break
    print 'Total frames:', num
        
if __name__ == '__main__':
    _test()
    sys.exit(1)
        


_______________________________________________
Stackless-checkins mailing list
Stackless-checkins at stackless.com
http://www.stackless.com/mailman/listinfo/stackless-checkins



More information about the Stackless-checkins mailing list