Detabbed.

This commit is contained in:
Jack Jansen 2003-04-09 13:25:43 +00:00
parent 058a84f36a
commit 0ae3220736
23 changed files with 7860 additions and 7846 deletions

View File

@ -3,119 +3,119 @@ error='Audio_mac.error'
class Play_Audio_mac: class Play_Audio_mac:
def __init__(self, qsize=QSIZE): def __init__(self, qsize=QSIZE):
self._chan = None self._chan = None
self._qsize = qsize self._qsize = qsize
self._outrate = 22254 self._outrate = 22254
self._sampwidth = 1 self._sampwidth = 1
self._nchannels = 1 self._nchannels = 1
self._gc = [] self._gc = []
self._usercallback = None self._usercallback = None
def __del__(self): def __del__(self):
self.stop() self.stop()
self._usercallback = None self._usercallback = None
def wait(self): def wait(self):
import time import time
while self.getfilled(): while self.getfilled():
time.sleep(0.1) time.sleep(0.1)
self._chan = None self._chan = None
self._gc = [] self._gc = []
def stop(self, quietNow = 1): def stop(self, quietNow = 1):
##chan = self._chan ##chan = self._chan
self._chan = None self._chan = None
##chan.SndDisposeChannel(1) ##chan.SndDisposeChannel(1)
self._gc = [] self._gc = []
def setoutrate(self, outrate): def setoutrate(self, outrate):
self._outrate = outrate self._outrate = outrate
def setsampwidth(self, sampwidth): def setsampwidth(self, sampwidth):
self._sampwidth = sampwidth self._sampwidth = sampwidth
def setnchannels(self, nchannels): def setnchannels(self, nchannels):
self._nchannels = nchannels self._nchannels = nchannels
def writeframes(self, data): def writeframes(self, data):
import time import time
from Carbon.Sound import bufferCmd, callBackCmd, extSH from Carbon.Sound import bufferCmd, callBackCmd, extSH
import struct import struct
import MacOS import MacOS
if not self._chan: if not self._chan:
from Carbon import Snd from Carbon import Snd
self._chan = Snd.SndNewChannel(5, 0, self._callback) self._chan = Snd.SndNewChannel(5, 0, self._callback)
nframes = len(data) / self._nchannels / self._sampwidth nframes = len(data) / self._nchannels / self._sampwidth
if len(data) != nframes * self._nchannels * self._sampwidth: if len(data) != nframes * self._nchannels * self._sampwidth:
raise error, 'data is not a whole number of frames' raise error, 'data is not a whole number of frames'
while self._gc and \ while self._gc and \
self.getfilled() + nframes > \ self.getfilled() + nframes > \
self._qsize / self._nchannels / self._sampwidth: self._qsize / self._nchannels / self._sampwidth:
time.sleep(0.1) time.sleep(0.1)
if self._sampwidth == 1: if self._sampwidth == 1:
import audioop import audioop
data = audioop.add(data, '\x80'*len(data), 1) data = audioop.add(data, '\x80'*len(data), 1)
h1 = struct.pack('llHhllbbl', h1 = struct.pack('llHhllbbl',
id(data)+MacOS.string_id_to_buffer, id(data)+MacOS.string_id_to_buffer,
self._nchannels, self._nchannels,
self._outrate, 0, self._outrate, 0,
0, 0,
0, 0,
extSH, extSH,
60, 60,
nframes) nframes)
h2 = 22*'\0' h2 = 22*'\0'
h3 = struct.pack('hhlll', h3 = struct.pack('hhlll',
self._sampwidth*8, self._sampwidth*8,
0, 0,
0, 0,
0, 0,
0) 0)
header = h1+h2+h3 header = h1+h2+h3
self._gc.append((header, data)) self._gc.append((header, data))
self._chan.SndDoCommand((bufferCmd, 0, header), 0) self._chan.SndDoCommand((bufferCmd, 0, header), 0)
self._chan.SndDoCommand((callBackCmd, 0, 0), 0) self._chan.SndDoCommand((callBackCmd, 0, 0), 0)
def _callback(self, *args): def _callback(self, *args):
del self._gc[0] del self._gc[0]
if self._usercallback: if self._usercallback:
self._usercallback() self._usercallback()
def setcallback(self, callback): def setcallback(self, callback):
self._usercallback = callback self._usercallback = callback
def getfilled(self): def getfilled(self):
filled = 0 filled = 0
for header, data in self._gc: for header, data in self._gc:
filled = filled + len(data) filled = filled + len(data)
return filled / self._nchannels / self._sampwidth return filled / self._nchannels / self._sampwidth
def getfillable(self): def getfillable(self):
return (self._qsize / self._nchannels / self._sampwidth) - self.getfilled() return (self._qsize / self._nchannels / self._sampwidth) - self.getfilled()
def ulaw2lin(self, data): def ulaw2lin(self, data):
import audioop import audioop
return audioop.ulaw2lin(data, 2) return audioop.ulaw2lin(data, 2)
def test(): def test():
import aifc import aifc
import EasyDialogs import EasyDialogs
fn = EasyDialogs.AskFileForOpen(message="Select an AIFF soundfile", typeList=("AIFF",)) fn = EasyDialogs.AskFileForOpen(message="Select an AIFF soundfile", typeList=("AIFF",))
if not fn: return if not fn: return
af = aifc.open(fn, 'r') af = aifc.open(fn, 'r')
print af.getparams() print af.getparams()
p = Play_Audio_mac() p = Play_Audio_mac()
p.setoutrate(af.getframerate()) p.setoutrate(af.getframerate())
p.setsampwidth(af.getsampwidth()) p.setsampwidth(af.getsampwidth())
p.setnchannels(af.getnchannels()) p.setnchannels(af.getnchannels())
BUFSIZ = 10000 BUFSIZ = 10000
while 1: while 1:
data = af.readframes(BUFSIZ) data = af.readframes(BUFSIZ)
if not data: break if not data: break
p.writeframes(data) p.writeframes(data)
print 'wrote', len(data), 'space', p.getfillable() print 'wrote', len(data), 'space', p.getfillable()
p.wait() p.wait()
if __name__ == '__main__': if __name__ == '__main__':
test() test()

View File

@ -5,53 +5,53 @@ import struct
# These needn't go through this module, but are here for completeness # These needn't go through this module, but are here for completeness
def SetControlData_Handle(control, part, selector, data): def SetControlData_Handle(control, part, selector, data):
control.SetControlData_Handle(part, selector, data) control.SetControlData_Handle(part, selector, data)
def GetControlData_Handle(control, part, selector): def GetControlData_Handle(control, part, selector):
return control.GetControlData_Handle(part, selector) return control.GetControlData_Handle(part, selector)
_accessdict = { _accessdict = {
kControlPopupButtonMenuHandleTag: (SetControlData_Handle, GetControlData_Handle), kControlPopupButtonMenuHandleTag: (SetControlData_Handle, GetControlData_Handle),
} }
_codingdict = { _codingdict = {
kControlPushButtonDefaultTag : ("b", None, None), kControlPushButtonDefaultTag : ("b", None, None),
kControlEditTextTextTag: (None, None, None), kControlEditTextTextTag: (None, None, None),
kControlEditTextPasswordTag: (None, None, None), kControlEditTextPasswordTag: (None, None, None),
kControlPopupButtonMenuIDTag: ("h", None, None), kControlPopupButtonMenuIDTag: ("h", None, None),
kControlListBoxDoubleClickTag: ("b", None, None), kControlListBoxDoubleClickTag: ("b", None, None),
} }
def SetControlData(control, part, selector, data): def SetControlData(control, part, selector, data):
if _accessdict.has_key(selector): if _accessdict.has_key(selector):
setfunc, getfunc = _accessdict[selector] setfunc, getfunc = _accessdict[selector]
setfunc(control, part, selector, data) setfunc(control, part, selector, data)
return return
if not _codingdict.has_key(selector): if not _codingdict.has_key(selector):
raise KeyError, ('Unknown control selector', selector) raise KeyError, ('Unknown control selector', selector)
structfmt, coder, decoder = _codingdict[selector] structfmt, coder, decoder = _codingdict[selector]
if coder: if coder:
data = coder(data) data = coder(data)
if structfmt: if structfmt:
data = struct.pack(structfmt, data) data = struct.pack(structfmt, data)
control.SetControlData(part, selector, data) control.SetControlData(part, selector, data)
def GetControlData(control, part, selector): def GetControlData(control, part, selector):
if _accessdict.has_key(selector): if _accessdict.has_key(selector):
setfunc, getfunc = _accessdict[selector] setfunc, getfunc = _accessdict[selector]
return getfunc(control, part, selector, data) return getfunc(control, part, selector, data)
if not _codingdict.has_key(selector): if not _codingdict.has_key(selector):
raise KeyError, ('Unknown control selector', selector) raise KeyError, ('Unknown control selector', selector)
structfmt, coder, decoder = _codingdict[selector] structfmt, coder, decoder = _codingdict[selector]
data = control.GetControlData(part, selector) data = control.GetControlData(part, selector)
if structfmt: if structfmt:
data = struct.unpack(structfmt, data) data = struct.unpack(structfmt, data)
if decoder: if decoder:
data = decoder(data) data = decoder(data)
if type(data) == type(()) and len(data) == 1: if type(data) == type(()) and len(data) == 1:
data = data[0] data = data[0]
return data return data

View File

@ -1,4 +1,4 @@
try: try:
from OverrideFrom23._Res import * from OverrideFrom23._Res import *
except ImportError: except ImportError:
from _Res import * from _Res import *

View File

@ -14,202 +14,202 @@ import imgformat
# PixMap data structure element format (as used with struct) # PixMap data structure element format (as used with struct)
_pmElemFormat = { _pmElemFormat = {
'baseAddr':'l', # address of pixel data 'baseAddr':'l', # address of pixel data
'rowBytes':'H', # bytes per row, plus 0x8000 'rowBytes':'H', # bytes per row, plus 0x8000
'bounds':'hhhh', # coordinates imposed over pixel data 'bounds':'hhhh', # coordinates imposed over pixel data
'top':'h', 'top':'h',
'left':'h', 'left':'h',
'bottom':'h', 'bottom':'h',
'right':'h', 'right':'h',
'pmVersion':'h', # flags for Color QuickDraw 'pmVersion':'h', # flags for Color QuickDraw
'packType':'h', # format of compression algorithm 'packType':'h', # format of compression algorithm
'packSize':'l', # size after compression 'packSize':'l', # size after compression
'hRes':'l', # horizontal pixels per inch 'hRes':'l', # horizontal pixels per inch
'vRes':'l', # vertical pixels per inch 'vRes':'l', # vertical pixels per inch
'pixelType':'h', # pixel format 'pixelType':'h', # pixel format
'pixelSize':'h', # bits per pixel 'pixelSize':'h', # bits per pixel
'cmpCount':'h', # color components per pixel 'cmpCount':'h', # color components per pixel
'cmpSize':'h', # bits per component 'cmpSize':'h', # bits per component
'planeBytes':'l', # offset in bytes to next plane 'planeBytes':'l', # offset in bytes to next plane
'pmTable':'l', # handle to color table 'pmTable':'l', # handle to color table
'pmReserved':'l' # reserved for future use 'pmReserved':'l' # reserved for future use
} }
# PixMap data structure element offset # PixMap data structure element offset
_pmElemOffset = { _pmElemOffset = {
'baseAddr':0, 'baseAddr':0,
'rowBytes':4, 'rowBytes':4,
'bounds':6, 'bounds':6,
'top':6, 'top':6,
'left':8, 'left':8,
'bottom':10, 'bottom':10,
'right':12, 'right':12,
'pmVersion':14, 'pmVersion':14,
'packType':16, 'packType':16,
'packSize':18, 'packSize':18,
'hRes':22, 'hRes':22,
'vRes':26, 'vRes':26,
'pixelType':30, 'pixelType':30,
'pixelSize':32, 'pixelSize':32,
'cmpCount':34, 'cmpCount':34,
'cmpSize':36, 'cmpSize':36,
'planeBytes':38, 'planeBytes':38,
'pmTable':42, 'pmTable':42,
'pmReserved':46 'pmReserved':46
} }
class PixMapWrapper: class PixMapWrapper:
"""PixMapWrapper -- wraps the QD PixMap object in a Python class, """PixMapWrapper -- wraps the QD PixMap object in a Python class,
with methods to easily get/set various pixmap fields. Note: Use the with methods to easily get/set various pixmap fields. Note: Use the
PixMap() method when passing to QD calls.""" PixMap() method when passing to QD calls."""
def __init__(self): def __init__(self):
self.__dict__['data'] = '' self.__dict__['data'] = ''
self._header = struct.pack("lhhhhhhhlllhhhhlll", self._header = struct.pack("lhhhhhhhlllhhhhlll",
id(self.data)+MacOS.string_id_to_buffer, id(self.data)+MacOS.string_id_to_buffer,
0, # rowBytes 0, # rowBytes
0, 0, 0, 0, # bounds 0, 0, 0, 0, # bounds
0, # pmVersion 0, # pmVersion
0, 0, # packType, packSize 0, 0, # packType, packSize
72<<16, 72<<16, # hRes, vRes 72<<16, 72<<16, # hRes, vRes
QuickDraw.RGBDirect, # pixelType QuickDraw.RGBDirect, # pixelType
16, # pixelSize 16, # pixelSize
2, 5, # cmpCount, cmpSize, 2, 5, # cmpCount, cmpSize,
0, 0, 0) # planeBytes, pmTable, pmReserved 0, 0, 0) # planeBytes, pmTable, pmReserved
self.__dict__['_pm'] = Qd.RawBitMap(self._header) self.__dict__['_pm'] = Qd.RawBitMap(self._header)
def _stuff(self, element, bytes): def _stuff(self, element, bytes):
offset = _pmElemOffset[element] offset = _pmElemOffset[element]
fmt = _pmElemFormat[element] fmt = _pmElemFormat[element]
self._header = self._header[:offset] \ self._header = self._header[:offset] \
+ struct.pack(fmt, bytes) \ + struct.pack(fmt, bytes) \
+ self._header[offset + struct.calcsize(fmt):] + self._header[offset + struct.calcsize(fmt):]
self.__dict__['_pm'] = None self.__dict__['_pm'] = None
def _unstuff(self, element): def _unstuff(self, element):
offset = _pmElemOffset[element] offset = _pmElemOffset[element]
fmt = _pmElemFormat[element] fmt = _pmElemFormat[element]
return struct.unpack(fmt, self._header[offset:offset+struct.calcsize(fmt)])[0] return struct.unpack(fmt, self._header[offset:offset+struct.calcsize(fmt)])[0]
def __setattr__(self, attr, val): def __setattr__(self, attr, val):
if attr == 'baseAddr': if attr == 'baseAddr':
raise 'UseErr', "don't assign to .baseAddr -- assign to .data instead" raise 'UseErr', "don't assign to .baseAddr -- assign to .data instead"
elif attr == 'data': elif attr == 'data':
self.__dict__['data'] = val self.__dict__['data'] = val
self._stuff('baseAddr', id(self.data) + MacOS.string_id_to_buffer) self._stuff('baseAddr', id(self.data) + MacOS.string_id_to_buffer)
elif attr == 'rowBytes': elif attr == 'rowBytes':
# high bit is always set for some odd reason # high bit is always set for some odd reason
self._stuff('rowBytes', val | 0x8000) self._stuff('rowBytes', val | 0x8000)
elif attr == 'bounds': elif attr == 'bounds':
# assume val is in official Left, Top, Right, Bottom order! # assume val is in official Left, Top, Right, Bottom order!
self._stuff('left',val[0]) self._stuff('left',val[0])
self._stuff('top',val[1]) self._stuff('top',val[1])
self._stuff('right',val[2]) self._stuff('right',val[2])
self._stuff('bottom',val[3]) self._stuff('bottom',val[3])
elif attr == 'hRes' or attr == 'vRes': elif attr == 'hRes' or attr == 'vRes':
# 16.16 fixed format, so just shift 16 bits # 16.16 fixed format, so just shift 16 bits
self._stuff(attr, int(val) << 16) self._stuff(attr, int(val) << 16)
elif attr in _pmElemFormat.keys(): elif attr in _pmElemFormat.keys():
# any other pm attribute -- just stuff # any other pm attribute -- just stuff
self._stuff(attr, val) self._stuff(attr, val)
else: else:
self.__dict__[attr] = val self.__dict__[attr] = val
def __getattr__(self, attr): def __getattr__(self, attr):
if attr == 'rowBytes': if attr == 'rowBytes':
# high bit is always set for some odd reason # high bit is always set for some odd reason
return self._unstuff('rowBytes') & 0x7FFF return self._unstuff('rowBytes') & 0x7FFF
elif attr == 'bounds': elif attr == 'bounds':
# return bounds in official Left, Top, Right, Bottom order! # return bounds in official Left, Top, Right, Bottom order!
return ( \ return ( \
self._unstuff('left'), self._unstuff('left'),
self._unstuff('top'), self._unstuff('top'),
self._unstuff('right'), self._unstuff('right'),
self._unstuff('bottom') ) self._unstuff('bottom') )
elif attr == 'hRes' or attr == 'vRes': elif attr == 'hRes' or attr == 'vRes':
# 16.16 fixed format, so just shift 16 bits # 16.16 fixed format, so just shift 16 bits
return self._unstuff(attr) >> 16 return self._unstuff(attr) >> 16
elif attr in _pmElemFormat.keys(): elif attr in _pmElemFormat.keys():
# any other pm attribute -- just unstuff # any other pm attribute -- just unstuff
return self._unstuff(attr) return self._unstuff(attr)
else: else:
return self.__dict__[attr] return self.__dict__[attr]
def PixMap(self): def PixMap(self):
"Return a QuickDraw PixMap corresponding to this data." "Return a QuickDraw PixMap corresponding to this data."
if not self.__dict__['_pm']: if not self.__dict__['_pm']:
self.__dict__['_pm'] = Qd.RawBitMap(self._header) self.__dict__['_pm'] = Qd.RawBitMap(self._header)
return self.__dict__['_pm'] return self.__dict__['_pm']
def blit(self, x1=0,y1=0,x2=None,y2=None, port=None): def blit(self, x1=0,y1=0,x2=None,y2=None, port=None):
"""Draw this pixmap into the given (default current) grafport.""" """Draw this pixmap into the given (default current) grafport."""
src = self.bounds src = self.bounds
dest = [x1,y1,x2,y2] dest = [x1,y1,x2,y2]
if x2 == None: if x2 == None:
dest[2] = x1 + src[2]-src[0] dest[2] = x1 + src[2]-src[0]
if y2 == None: if y2 == None:
dest[3] = y1 + src[3]-src[1] dest[3] = y1 + src[3]-src[1]
if not port: port = Qd.GetPort() if not port: port = Qd.GetPort()
Qd.CopyBits(self.PixMap(), port.GetPortBitMapForCopyBits(), src, tuple(dest), Qd.CopyBits(self.PixMap(), port.GetPortBitMapForCopyBits(), src, tuple(dest),
QuickDraw.srcCopy, None) QuickDraw.srcCopy, None)
def fromstring(self,s,width,height,format=imgformat.macrgb): def fromstring(self,s,width,height,format=imgformat.macrgb):
"""Stuff this pixmap with raw pixel data from a string. """Stuff this pixmap with raw pixel data from a string.
Supply width, height, and one of the imgformat specifiers.""" Supply width, height, and one of the imgformat specifiers."""
# we only support 16- and 32-bit mac rgb... # we only support 16- and 32-bit mac rgb...
# so convert if necessary # so convert if necessary
if format != imgformat.macrgb and format != imgformat.macrgb16: if format != imgformat.macrgb and format != imgformat.macrgb16:
# (LATER!) # (LATER!)
raise "NotImplementedError", "conversion to macrgb or macrgb16" raise "NotImplementedError", "conversion to macrgb or macrgb16"
self.data = s self.data = s
self.bounds = (0,0,width,height) self.bounds = (0,0,width,height)
self.cmpCount = 3 self.cmpCount = 3
self.pixelType = QuickDraw.RGBDirect self.pixelType = QuickDraw.RGBDirect
if format == imgformat.macrgb: if format == imgformat.macrgb:
self.pixelSize = 32 self.pixelSize = 32
self.cmpSize = 8 self.cmpSize = 8
else: else:
self.pixelSize = 16 self.pixelSize = 16
self.cmpSize = 5 self.cmpSize = 5
self.rowBytes = width*self.pixelSize/8 self.rowBytes = width*self.pixelSize/8
def tostring(self, format=imgformat.macrgb): def tostring(self, format=imgformat.macrgb):
"""Return raw data as a string in the specified format.""" """Return raw data as a string in the specified format."""
# is the native format requested? if so, just return data # is the native format requested? if so, just return data
if (format == imgformat.macrgb and self.pixelSize == 32) or \ if (format == imgformat.macrgb and self.pixelSize == 32) or \
(format == imgformat.macrgb16 and self.pixelsize == 16): (format == imgformat.macrgb16 and self.pixelsize == 16):
return self.data return self.data
# otherwise, convert to the requested format # otherwise, convert to the requested format
# (LATER!) # (LATER!)
raise "NotImplementedError", "data format conversion" raise "NotImplementedError", "data format conversion"
def fromImage(self,im): def fromImage(self,im):
"""Initialize this PixMap from a PIL Image object.""" """Initialize this PixMap from a PIL Image object."""
# We need data in ARGB format; PIL can't currently do that, # 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 # but it can do RGBA, which we can use by inserting one null
# up frontpm = # up frontpm =
if im.mode != 'RGBA': im = im.convert('RGBA') if im.mode != 'RGBA': im = im.convert('RGBA')
data = chr(0) + im.tostring() data = chr(0) + im.tostring()
self.fromstring(data, im.size[0], im.size[1]) self.fromstring(data, im.size[0], im.size[1])
def toImage(self): def toImage(self):
"""Return the contents of this PixMap as a PIL Image object.""" """Return the contents of this PixMap as a PIL Image object."""
import Image import Image
# our tostring() method returns data in ARGB format, # our tostring() method returns data in ARGB format,
# whereas Image uses RGBA; a bit of slicing fixes this... # whereas Image uses RGBA; a bit of slicing fixes this...
data = self.tostring()[1:] + chr(0) data = self.tostring()[1:] + chr(0)
bounds = self.bounds bounds = self.bounds
return Image.fromstring('RGBA',(bounds[2]-bounds[0],bounds[3]-bounds[1]),data) return Image.fromstring('RGBA',(bounds[2]-bounds[0],bounds[3]-bounds[1]),data)
def test(): def test():
import MacOS import MacOS
import EasyDialogs import EasyDialogs
import Image import Image
path = EasyDialogs.AskFileForOpen("Image File:") path = EasyDialogs.AskFileForOpen("Image File:")
if not path: return if not path: return
pm = PixMapWrapper() pm = PixMapWrapper()
pm.fromImage( Image.open(path) ) pm.fromImage( Image.open(path) )
pm.blit(20,20) pm.blit(20,20)
return pm return pm

View File

@ -44,15 +44,15 @@ import os
# we like better (and which is equivalent) # we like better (and which is equivalent)
# #
unpacker_coercions = { unpacker_coercions = {
typeComp : typeFloat, typeComp : typeFloat,
typeColorTable : typeAEList, typeColorTable : typeAEList,
typeDrawingArea : typeAERecord, typeDrawingArea : typeAERecord,
typeFixed : typeFloat, typeFixed : typeFloat,
typeExtended : typeFloat, typeExtended : typeFloat,
typePixelMap : typeAERecord, typePixelMap : typeAERecord,
typeRotation : typeAERecord, typeRotation : typeAERecord,
typeStyledText : typeAERecord, typeStyledText : typeAERecord,
typeTextStyles : typeAERecord, typeTextStyles : typeAERecord,
}; };
# #
@ -64,303 +64,303 @@ FSRefType = Carbon.File.FSRefType
AliasType = Carbon.File.AliasType AliasType = Carbon.File.AliasType
def packkey(ae, key, value): def packkey(ae, key, value):
if hasattr(key, 'which'): if hasattr(key, 'which'):
keystr = key.which keystr = key.which
elif hasattr(key, 'want'): elif hasattr(key, 'want'):
keystr = key.want keystr = key.want
else: else:
keystr = key keystr = key
ae.AEPutParamDesc(keystr, pack(value)) ae.AEPutParamDesc(keystr, pack(value))
def pack(x, forcetype = None): def pack(x, forcetype = None):
"""Pack a python object into an AE descriptor""" """Pack a python object into an AE descriptor"""
if forcetype: if forcetype:
if type(x) is StringType: if type(x) is StringType:
return AE.AECreateDesc(forcetype, x) return AE.AECreateDesc(forcetype, x)
else: else:
return pack(x).AECoerceDesc(forcetype) return pack(x).AECoerceDesc(forcetype)
if x == None: if x == None:
return AE.AECreateDesc('null', '') return AE.AECreateDesc('null', '')
if isinstance(x, AEDescType): if isinstance(x, AEDescType):
return x return x
if isinstance(x, FSSType): if isinstance(x, FSSType):
return AE.AECreateDesc('fss ', x.data) return AE.AECreateDesc('fss ', x.data)
if isinstance(x, FSRefType): if isinstance(x, FSRefType):
return AE.AECreateDesc('fsrf', x.data) return AE.AECreateDesc('fsrf', x.data)
if isinstance(x, AliasType): if isinstance(x, AliasType):
return AE.AECreateDesc('alis', x.data) return AE.AECreateDesc('alis', x.data)
if isinstance(x, IntType): if isinstance(x, IntType):
return AE.AECreateDesc('long', struct.pack('l', x)) return AE.AECreateDesc('long', struct.pack('l', x))
if isinstance(x, FloatType): if isinstance(x, FloatType):
return AE.AECreateDesc('doub', struct.pack('d', x)) return AE.AECreateDesc('doub', struct.pack('d', x))
if isinstance(x, StringType): if isinstance(x, StringType):
return AE.AECreateDesc('TEXT', x) return AE.AECreateDesc('TEXT', x)
if isinstance(x, UnicodeType): if isinstance(x, UnicodeType):
data = x.encode('utf16') data = x.encode('utf16')
if data[:2] == '\xfe\xff': if data[:2] == '\xfe\xff':
data = data[2:] data = data[2:]
return AE.AECreateDesc('utxt', data) return AE.AECreateDesc('utxt', data)
if isinstance(x, ListType): if isinstance(x, ListType):
list = AE.AECreateList('', 0) list = AE.AECreateList('', 0)
for item in x: for item in x:
list.AEPutDesc(0, pack(item)) list.AEPutDesc(0, pack(item))
return list return list
if isinstance(x, DictionaryType): if isinstance(x, DictionaryType):
record = AE.AECreateList('', 1) record = AE.AECreateList('', 1)
for key, value in x.items(): for key, value in x.items():
packkey(record, key, value) packkey(record, key, value)
#record.AEPutParamDesc(key, pack(value)) #record.AEPutParamDesc(key, pack(value))
return record return record
if type(x) == types.ClassType and issubclass(x, ObjectSpecifier): if type(x) == types.ClassType and issubclass(x, ObjectSpecifier):
# Note: we are getting a class object here, not an instance # Note: we are getting a class object here, not an instance
return AE.AECreateDesc('type', x.want) return AE.AECreateDesc('type', x.want)
if hasattr(x, '__aepack__'): if hasattr(x, '__aepack__'):
return x.__aepack__() return x.__aepack__()
if hasattr(x, 'which'): if hasattr(x, 'which'):
return AE.AECreateDesc('TEXT', x.which) return AE.AECreateDesc('TEXT', x.which)
if hasattr(x, 'want'): if hasattr(x, 'want'):
return AE.AECreateDesc('TEXT', x.want) return AE.AECreateDesc('TEXT', x.want)
return AE.AECreateDesc('TEXT', repr(x)) # Copout return AE.AECreateDesc('TEXT', repr(x)) # Copout
def unpack(desc, formodulename=""): def unpack(desc, formodulename=""):
"""Unpack an AE descriptor to a python object""" """Unpack an AE descriptor to a python object"""
t = desc.type t = desc.type
if unpacker_coercions.has_key(t): if unpacker_coercions.has_key(t):
desc = desc.AECoerceDesc(unpacker_coercions[t]) desc = desc.AECoerceDesc(unpacker_coercions[t])
t = desc.type # This is a guess by Jack.... t = desc.type # This is a guess by Jack....
if t == typeAEList: if t == typeAEList:
l = [] l = []
for i in range(desc.AECountItems()): for i in range(desc.AECountItems()):
keyword, item = desc.AEGetNthDesc(i+1, '****') keyword, item = desc.AEGetNthDesc(i+1, '****')
l.append(unpack(item, formodulename)) l.append(unpack(item, formodulename))
return l return l
if t == typeAERecord: if t == typeAERecord:
d = {} d = {}
for i in range(desc.AECountItems()): for i in range(desc.AECountItems()):
keyword, item = desc.AEGetNthDesc(i+1, '****') keyword, item = desc.AEGetNthDesc(i+1, '****')
d[keyword] = unpack(item, formodulename) d[keyword] = unpack(item, formodulename)
return d return d
if t == typeAEText: if t == typeAEText:
record = desc.AECoerceDesc('reco') record = desc.AECoerceDesc('reco')
return mkaetext(unpack(record, formodulename)) return mkaetext(unpack(record, formodulename))
if t == typeAlias: if t == typeAlias:
return Carbon.File.Alias(rawdata=desc.data) return Carbon.File.Alias(rawdata=desc.data)
# typeAppleEvent returned as unknown # typeAppleEvent returned as unknown
if t == typeBoolean: if t == typeBoolean:
return struct.unpack('b', desc.data)[0] return struct.unpack('b', desc.data)[0]
if t == typeChar: if t == typeChar:
return desc.data return desc.data
if t == typeUnicodeText: if t == typeUnicodeText:
return unicode(desc.data, 'utf16') return unicode(desc.data, 'utf16')
# typeColorTable coerced to typeAEList # typeColorTable coerced to typeAEList
# typeComp coerced to extended # typeComp coerced to extended
# typeData returned as unknown # typeData returned as unknown
# typeDrawingArea coerced to typeAERecord # typeDrawingArea coerced to typeAERecord
if t == typeEnumeration: if t == typeEnumeration:
return mkenum(desc.data) return mkenum(desc.data)
# typeEPS returned as unknown # typeEPS returned as unknown
if t == typeFalse: if t == typeFalse:
return 0 return 0
if t == typeFloat: if t == typeFloat:
data = desc.data data = desc.data
return struct.unpack('d', data)[0] return struct.unpack('d', data)[0]
if t == typeFSS: if t == typeFSS:
return Carbon.File.FSSpec(rawdata=desc.data) return Carbon.File.FSSpec(rawdata=desc.data)
if t == typeFSRef: if t == typeFSRef:
return Carbon.File.FSRef(rawdata=desc.data) return Carbon.File.FSRef(rawdata=desc.data)
if t == typeInsertionLoc: if t == typeInsertionLoc:
record = desc.AECoerceDesc('reco') record = desc.AECoerceDesc('reco')
return mkinsertionloc(unpack(record, formodulename)) return mkinsertionloc(unpack(record, formodulename))
# typeInteger equal to typeLongInteger # typeInteger equal to typeLongInteger
if t == typeIntlText: if t == typeIntlText:
script, language = struct.unpack('hh', desc.data[:4]) script, language = struct.unpack('hh', desc.data[:4])
return aetypes.IntlText(script, language, desc.data[4:]) return aetypes.IntlText(script, language, desc.data[4:])
if t == typeIntlWritingCode: if t == typeIntlWritingCode:
script, language = struct.unpack('hh', desc.data) script, language = struct.unpack('hh', desc.data)
return aetypes.IntlWritingCode(script, language) return aetypes.IntlWritingCode(script, language)
if t == typeKeyword: if t == typeKeyword:
return mkkeyword(desc.data) return mkkeyword(desc.data)
if t == typeLongInteger: if t == typeLongInteger:
return struct.unpack('l', desc.data)[0] return struct.unpack('l', desc.data)[0]
if t == typeLongDateTime: if t == typeLongDateTime:
a, b = struct.unpack('lL', desc.data) a, b = struct.unpack('lL', desc.data)
return (long(a) << 32) + b return (long(a) << 32) + b
if t == typeNull: if t == typeNull:
return None return None
if t == typeMagnitude: if t == typeMagnitude:
v = struct.unpack('l', desc.data) v = struct.unpack('l', desc.data)
if v < 0: if v < 0:
v = 0x100000000L + v v = 0x100000000L + v
return v return v
if t == typeObjectSpecifier: if t == typeObjectSpecifier:
record = desc.AECoerceDesc('reco') record = desc.AECoerceDesc('reco')
# If we have been told the name of the module we are unpacking aedescs for, # 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. # we can attempt to create the right type of python object from that module.
if formodulename: if formodulename:
return mkobjectfrommodule(unpack(record, formodulename), formodulename) return mkobjectfrommodule(unpack(record, formodulename), formodulename)
return mkobject(unpack(record, formodulename)) return mkobject(unpack(record, formodulename))
# typePict returned as unknown # typePict returned as unknown
# typePixelMap coerced to typeAERecord # typePixelMap coerced to typeAERecord
# typePixelMapMinus returned as unknown # typePixelMapMinus returned as unknown
# typeProcessSerialNumber returned as unknown # typeProcessSerialNumber returned as unknown
if t == typeQDPoint: if t == typeQDPoint:
v, h = struct.unpack('hh', desc.data) v, h = struct.unpack('hh', desc.data)
return aetypes.QDPoint(v, h) return aetypes.QDPoint(v, h)
if t == typeQDRectangle: if t == typeQDRectangle:
v0, h0, v1, h1 = struct.unpack('hhhh', desc.data) v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
return aetypes.QDRectangle(v0, h0, v1, h1) return aetypes.QDRectangle(v0, h0, v1, h1)
if t == typeRGBColor: if t == typeRGBColor:
r, g, b = struct.unpack('hhh', desc.data) r, g, b = struct.unpack('hhh', desc.data)
return aetypes.RGBColor(r, g, b) return aetypes.RGBColor(r, g, b)
# typeRotation coerced to typeAERecord # typeRotation coerced to typeAERecord
# typeScrapStyles returned as unknown # typeScrapStyles returned as unknown
# typeSessionID returned as unknown # typeSessionID returned as unknown
if t == typeShortFloat: if t == typeShortFloat:
return struct.unpack('f', desc.data)[0] return struct.unpack('f', desc.data)[0]
if t == typeShortInteger: if t == typeShortInteger:
return struct.unpack('h', desc.data)[0] return struct.unpack('h', desc.data)[0]
# typeSMFloat identical to typeShortFloat # typeSMFloat identical to typeShortFloat
# typeSMInt indetical to typeShortInt # typeSMInt indetical to typeShortInt
# typeStyledText coerced to typeAERecord # typeStyledText coerced to typeAERecord
if t == typeTargetID: if t == typeTargetID:
return mktargetid(desc.data) return mktargetid(desc.data)
# typeTextStyles coerced to typeAERecord # typeTextStyles coerced to typeAERecord
# typeTIFF returned as unknown # typeTIFF returned as unknown
if t == typeTrue: if t == typeTrue:
return 1 return 1
if t == typeType: if t == typeType:
return mktype(desc.data, formodulename) return mktype(desc.data, formodulename)
# #
# The following are special # The following are special
# #
if t == 'rang': if t == 'rang':
record = desc.AECoerceDesc('reco') record = desc.AECoerceDesc('reco')
return mkrange(unpack(record, formodulename)) return mkrange(unpack(record, formodulename))
if t == 'cmpd': if t == 'cmpd':
record = desc.AECoerceDesc('reco') record = desc.AECoerceDesc('reco')
return mkcomparison(unpack(record, formodulename)) return mkcomparison(unpack(record, formodulename))
if t == 'logi': if t == 'logi':
record = desc.AECoerceDesc('reco') record = desc.AECoerceDesc('reco')
return mklogical(unpack(record, formodulename)) return mklogical(unpack(record, formodulename))
return mkunknown(desc.type, desc.data) return mkunknown(desc.type, desc.data)
def coerce(data, egdata): def coerce(data, egdata):
"""Coerce a python object to another type using the AE coercers""" """Coerce a python object to another type using the AE coercers"""
pdata = pack(data) pdata = pack(data)
pegdata = pack(egdata) pegdata = pack(egdata)
pdata = pdata.AECoerceDesc(pegdata.type) pdata = pdata.AECoerceDesc(pegdata.type)
return unpack(pdata) return unpack(pdata)
# #
# Helper routines for unpack # Helper routines for unpack
# #
def mktargetid(data): def mktargetid(data):
sessionID = getlong(data[:4]) sessionID = getlong(data[:4])
name = mkppcportrec(data[4:4+72]) name = mkppcportrec(data[4:4+72])
location = mklocationnamerec(data[76:76+36]) location = mklocationnamerec(data[76:76+36])
rcvrName = mkppcportrec(data[112:112+72]) rcvrName = mkppcportrec(data[112:112+72])
return sessionID, name, location, rcvrName return sessionID, name, location, rcvrName
def mkppcportrec(rec): def mkppcportrec(rec):
namescript = getword(rec[:2]) namescript = getword(rec[:2])
name = getpstr(rec[2:2+33]) name = getpstr(rec[2:2+33])
portkind = getword(rec[36:38]) portkind = getword(rec[36:38])
if portkind == 1: if portkind == 1:
ctor = rec[38:42] ctor = rec[38:42]
type = rec[42:46] type = rec[42:46]
identity = (ctor, type) identity = (ctor, type)
else: else:
identity = getpstr(rec[38:38+33]) identity = getpstr(rec[38:38+33])
return namescript, name, portkind, identity return namescript, name, portkind, identity
def mklocationnamerec(rec): def mklocationnamerec(rec):
kind = getword(rec[:2]) kind = getword(rec[:2])
stuff = rec[2:] stuff = rec[2:]
if kind == 0: stuff = None if kind == 0: stuff = None
if kind == 2: stuff = getpstr(stuff) if kind == 2: stuff = getpstr(stuff)
return kind, stuff return kind, stuff
def mkunknown(type, data): def mkunknown(type, data):
return aetypes.Unknown(type, data) return aetypes.Unknown(type, data)
def getpstr(s): def getpstr(s):
return s[1:1+ord(s[0])] return s[1:1+ord(s[0])]
def getlong(s): def getlong(s):
return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3]) return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
def getword(s): def getword(s):
return (ord(s[0])<<8) | (ord(s[1])<<0) return (ord(s[0])<<8) | (ord(s[1])<<0)
def mkkeyword(keyword): def mkkeyword(keyword):
return aetypes.Keyword(keyword) return aetypes.Keyword(keyword)
def mkrange(dict): def mkrange(dict):
return aetypes.Range(dict['star'], dict['stop']) return aetypes.Range(dict['star'], dict['stop'])
def mkcomparison(dict): def mkcomparison(dict):
return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2']) return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])
def mklogical(dict): def mklogical(dict):
return aetypes.Logical(dict['logc'], dict['term']) return aetypes.Logical(dict['logc'], dict['term'])
def mkstyledtext(dict): def mkstyledtext(dict):
return aetypes.StyledText(dict['ksty'], dict['ktxt']) return aetypes.StyledText(dict['ksty'], dict['ktxt'])
def mkaetext(dict): def mkaetext(dict):
return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText]) return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
def mkinsertionloc(dict): def mkinsertionloc(dict):
return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition]) return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])
def mkobject(dict): def mkobject(dict):
want = dict['want'].type want = dict['want'].type
form = dict['form'].enum form = dict['form'].enum
seld = dict['seld'] seld = dict['seld']
fr = dict['from'] fr = dict['from']
if form in ('name', 'indx', 'rang', 'test'): if form in ('name', 'indx', 'rang', 'test'):
if want == 'text': return aetypes.Text(seld, fr) if want == 'text': return aetypes.Text(seld, fr)
if want == 'cha ': return aetypes.Character(seld, fr) if want == 'cha ': return aetypes.Character(seld, fr)
if want == 'cwor': return aetypes.Word(seld, fr) if want == 'cwor': return aetypes.Word(seld, fr)
if want == 'clin': return aetypes.Line(seld, fr) if want == 'clin': return aetypes.Line(seld, fr)
if want == 'cpar': return aetypes.Paragraph(seld, fr) if want == 'cpar': return aetypes.Paragraph(seld, fr)
if want == 'cwin': return aetypes.Window(seld, fr) if want == 'cwin': return aetypes.Window(seld, fr)
if want == 'docu': return aetypes.Document(seld, fr) if want == 'docu': return aetypes.Document(seld, fr)
if want == 'file': return aetypes.File(seld, fr) if want == 'file': return aetypes.File(seld, fr)
if want == 'cins': return aetypes.InsertionPoint(seld, fr) if want == 'cins': return aetypes.InsertionPoint(seld, fr)
if want == 'prop' and form == 'prop' and aetypes.IsType(seld): if want == 'prop' and form == 'prop' and aetypes.IsType(seld):
return aetypes.Property(seld.type, fr) return aetypes.Property(seld.type, fr)
return aetypes.ObjectSpecifier(want, form, seld, fr) return aetypes.ObjectSpecifier(want, form, seld, fr)
# Note by Jack: I'm not 100% sure of the following code. This was # Note by Jack: I'm not 100% sure of the following code. This was
# provided by Donovan Preston, but I wonder whether the assignment # provided by Donovan Preston, but I wonder whether the assignment
# to __class__ is safe. Moreover, shouldn't there be a better # to __class__ is safe. Moreover, shouldn't there be a better
# initializer for the classes in the suites? # initializer for the classes in the suites?
def mkobjectfrommodule(dict, modulename): def mkobjectfrommodule(dict, modulename):
if type(dict['want']) == types.ClassType and issubclass(dict['want'], ObjectSpecifier): if type(dict['want']) == types.ClassType and issubclass(dict['want'], ObjectSpecifier):
# The type has already been converted to Python. Convert back:-( # The type has already been converted to Python. Convert back:-(
classtype = dict['want'] classtype = dict['want']
dict['want'] = aetypes.mktype(classtype.want) dict['want'] = aetypes.mktype(classtype.want)
want = dict['want'].type want = dict['want'].type
module = __import__(modulename) module = __import__(modulename)
codenamemapper = module._classdeclarations codenamemapper = module._classdeclarations
classtype = codenamemapper.get(want, None) classtype = codenamemapper.get(want, None)
newobj = mkobject(dict) newobj = mkobject(dict)
if classtype: if classtype:
assert issubclass(classtype, ObjectSpecifier) assert issubclass(classtype, ObjectSpecifier)
newobj.__class__ = classtype newobj.__class__ = classtype
return newobj return newobj
def mktype(typecode, modulename=None): def mktype(typecode, modulename=None):
if modulename: if modulename:
module = __import__(modulename) module = __import__(modulename)
codenamemapper = module._classdeclarations codenamemapper = module._classdeclarations
classtype = codenamemapper.get(typecode, None) classtype = codenamemapper.get(typecode, None)
if classtype: if classtype:
return classtype return classtype
return aetypes.mktype(typecode) return aetypes.mktype(typecode)

View File

@ -9,11 +9,11 @@ unpackevent(event) returns the parameters and attributes from an AEAppleEvent re
Plus... Lots of classes and routines that help representing AE objects, Plus... Lots of classes and routines that help representing AE objects,
ranges, conditionals, logicals, etc., so you can write, e.g.: ranges, conditionals, logicals, etc., so you can write, e.g.:
x = Character(1, Document("foobar")) x = Character(1, Document("foobar"))
and pack(x) will create an AE object reference equivalent to AppleScript's and pack(x) will create an AE object reference equivalent to AppleScript's
character 1 of document "foobar" character 1 of document "foobar"
Some of the stuff that appears to be exported from this module comes from other 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. files: the pack stuff from aepack, the objects from aetypes.
@ -41,306 +41,306 @@ LAUNCH_MAX_WAIT_TIME=10
# Note by Jack: No??!? If I read the docs correctly it *is*.... # Note by Jack: No??!? If I read the docs correctly it *is*....
aekeywords = [ aekeywords = [
'tran', 'tran',
'rtid', 'rtid',
'evcl', 'evcl',
'evid', 'evid',
'addr', 'addr',
'optk', 'optk',
'timo', 'timo',
'inte', # this attribute is read only - will be set in AESend 'inte', # this attribute is read only - will be set in AESend
'esrc', # this attribute is read only 'esrc', # this attribute is read only
'miss', # this attribute is read only 'miss', # this attribute is read only
'from' # new in 1.0.1 'from' # new in 1.0.1
] ]
def missed(ae): def missed(ae):
try: try:
desc = ae.AEGetAttributeDesc('miss', 'keyw') desc = ae.AEGetAttributeDesc('miss', 'keyw')
except AE.Error, msg: except AE.Error, msg:
return None return None
return desc.data return desc.data
def unpackevent(ae, formodulename=""): def unpackevent(ae, formodulename=""):
parameters = {} parameters = {}
try: try:
dirobj = ae.AEGetParamDesc('----', '****') dirobj = ae.AEGetParamDesc('----', '****')
except AE.Error: except AE.Error:
pass pass
else: else:
parameters['----'] = unpack(dirobj, formodulename) parameters['----'] = unpack(dirobj, formodulename)
del dirobj del dirobj
# Workaround for what I feel is a bug in OSX 10.2: 'errn' won't show up in missed... # Workaround for what I feel is a bug in OSX 10.2: 'errn' won't show up in missed...
try: try:
dirobj = ae.AEGetParamDesc('errn', '****') dirobj = ae.AEGetParamDesc('errn', '****')
except AE.Error: except AE.Error:
pass pass
else: else:
parameters['errn'] = unpack(dirobj, formodulename) parameters['errn'] = unpack(dirobj, formodulename)
del dirobj del dirobj
while 1: while 1:
key = missed(ae) key = missed(ae)
if not key: break if not key: break
parameters[key] = unpack(ae.AEGetParamDesc(key, '****'), formodulename) parameters[key] = unpack(ae.AEGetParamDesc(key, '****'), formodulename)
attributes = {} attributes = {}
for key in aekeywords: for key in aekeywords:
try: try:
desc = ae.AEGetAttributeDesc(key, '****') desc = ae.AEGetAttributeDesc(key, '****')
except (AE.Error, MacOS.Error), msg: except (AE.Error, MacOS.Error), msg:
if msg[0] != -1701 and msg[0] != -1704: if msg[0] != -1701 and msg[0] != -1704:
raise raise
continue continue
attributes[key] = unpack(desc, formodulename) attributes[key] = unpack(desc, formodulename)
return parameters, attributes return parameters, attributes
def packevent(ae, parameters = {}, attributes = {}): def packevent(ae, parameters = {}, attributes = {}):
for key, value in parameters.items(): for key, value in parameters.items():
packkey(ae, key, value) packkey(ae, key, value)
for key, value in attributes.items(): for key, value in attributes.items():
ae.AEPutAttributeDesc(key, pack(value)) ae.AEPutAttributeDesc(key, pack(value))
# #
# Support routine for automatically generated Suite interfaces # Support routine for automatically generated Suite interfaces
# These routines are also useable for the reverse function. # These routines are also useable for the reverse function.
# #
def keysubst(arguments, keydict): def keysubst(arguments, keydict):
"""Replace long name keys by their 4-char counterparts, and check""" """Replace long name keys by their 4-char counterparts, and check"""
ok = keydict.values() ok = keydict.values()
for k in arguments.keys(): for k in arguments.keys():
if keydict.has_key(k): if keydict.has_key(k):
v = arguments[k] v = arguments[k]
del arguments[k] del arguments[k]
arguments[keydict[k]] = v arguments[keydict[k]] = v
elif k != '----' and k not in ok: elif k != '----' and k not in ok:
raise TypeError, 'Unknown keyword argument: %s'%k raise TypeError, 'Unknown keyword argument: %s'%k
def enumsubst(arguments, key, edict): def enumsubst(arguments, key, edict):
"""Substitute a single enum keyword argument, if it occurs""" """Substitute a single enum keyword argument, if it occurs"""
if not arguments.has_key(key) or edict is None: if not arguments.has_key(key) or edict is None:
return return
v = arguments[key] v = arguments[key]
ok = edict.values() ok = edict.values()
if edict.has_key(v): if edict.has_key(v):
arguments[key] = Enum(edict[v]) arguments[key] = Enum(edict[v])
elif not v in ok: elif not v in ok:
raise TypeError, 'Unknown enumerator: %s'%v raise TypeError, 'Unknown enumerator: %s'%v
def decodeerror(arguments): def decodeerror(arguments):
"""Create the 'best' argument for a raise MacOS.Error""" """Create the 'best' argument for a raise MacOS.Error"""
errn = arguments['errn'] errn = arguments['errn']
err_a1 = errn err_a1 = errn
if arguments.has_key('errs'): if arguments.has_key('errs'):
err_a2 = arguments['errs'] err_a2 = arguments['errs']
else: else:
err_a2 = MacOS.GetErrorString(errn) err_a2 = MacOS.GetErrorString(errn)
if arguments.has_key('erob'): if arguments.has_key('erob'):
err_a3 = arguments['erob'] err_a3 = arguments['erob']
else: else:
err_a3 = None err_a3 = None
return (err_a1, err_a2, err_a3) return (err_a1, err_a2, err_a3)
class TalkTo: class TalkTo:
"""An AE connection to an application""" """An AE connection to an application"""
_signature = None # Can be overridden by subclasses _signature = None # Can be overridden by subclasses
_moduleName = None # Can be overridden by subclasses _moduleName = None # Can be overridden by subclasses
__eventloop_initialized = 0 __eventloop_initialized = 0
def __ensure_WMAvailable(klass): def __ensure_WMAvailable(klass):
if klass.__eventloop_initialized: return 1 if klass.__eventloop_initialized: return 1
if not MacOS.WMAvailable(): return 0 if not MacOS.WMAvailable(): return 0
# Workaround for a but in MacOSX 10.2: we must have an event # Workaround for a but in MacOSX 10.2: we must have an event
# loop before we can call AESend. # loop before we can call AESend.
Evt.WaitNextEvent(0,0) Evt.WaitNextEvent(0,0)
return 1 return 1
__ensure_WMAvailable = classmethod(__ensure_WMAvailable) __ensure_WMAvailable = classmethod(__ensure_WMAvailable)
def __init__(self, signature=None, start=0, timeout=0): def __init__(self, signature=None, start=0, timeout=0):
"""Create a communication channel with a particular application. """Create a communication channel with a particular application.
Addressing the application is done by specifying either a Addressing the application is done by specifying either a
4-byte signature, an AEDesc or an object that will __aepack__ 4-byte signature, an AEDesc or an object that will __aepack__
to an AEDesc. to an AEDesc.
""" """
self.target_signature = None self.target_signature = None
if signature is None: if signature is None:
signature = self._signature signature = self._signature
if type(signature) == AEDescType: if type(signature) == AEDescType:
self.target = signature self.target = signature
elif type(signature) == InstanceType and hasattr(signature, '__aepack__'): elif type(signature) == InstanceType and hasattr(signature, '__aepack__'):
self.target = signature.__aepack__() self.target = signature.__aepack__()
elif type(signature) == StringType and len(signature) == 4: elif type(signature) == StringType and len(signature) == 4:
self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature) self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature)
self.target_signature = signature self.target_signature = signature
else: else:
raise TypeError, "signature should be 4-char string or AEDesc" raise TypeError, "signature should be 4-char string or AEDesc"
self.send_flags = AppleEvents.kAEWaitReply self.send_flags = AppleEvents.kAEWaitReply
self.send_priority = AppleEvents.kAENormalPriority self.send_priority = AppleEvents.kAENormalPriority
if timeout: if timeout:
self.send_timeout = timeout self.send_timeout = timeout
else: else:
self.send_timeout = AppleEvents.kAEDefaultTimeout self.send_timeout = AppleEvents.kAEDefaultTimeout
if start: if start:
self._start() self._start()
def _start(self): def _start(self):
"""Start the application, if it is not running yet""" """Start the application, if it is not running yet"""
try: try:
self.send('ascr', 'noop') self.send('ascr', 'noop')
except AE.Error: except AE.Error:
_launch(self.target_signature) _launch(self.target_signature)
for i in range(LAUNCH_MAX_WAIT_TIME): for i in range(LAUNCH_MAX_WAIT_TIME):
try: try:
self.send('ascr', 'noop') self.send('ascr', 'noop')
except AE.Error: except AE.Error:
pass pass
else: else:
break break
time.sleep(1) time.sleep(1)
def start(self): def start(self):
"""Deprecated, used _start()""" """Deprecated, used _start()"""
self._start() self._start()
def newevent(self, code, subcode, parameters = {}, attributes = {}): def newevent(self, code, subcode, parameters = {}, attributes = {}):
"""Create a complete structure for an apple event""" """Create a complete structure for an apple event"""
event = AE.AECreateAppleEvent(code, subcode, self.target, event = AE.AECreateAppleEvent(code, subcode, self.target,
AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID) AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID)
packevent(event, parameters, attributes) packevent(event, parameters, attributes)
return event return event
def sendevent(self, event): def sendevent(self, event):
"""Send a pre-created appleevent, await the reply and unpack it""" """Send a pre-created appleevent, await the reply and unpack it"""
if not self.__ensure_WMAvailable(): if not self.__ensure_WMAvailable():
raise RuntimeError, "No window manager access, cannot send AppleEvent" raise RuntimeError, "No window manager access, cannot send AppleEvent"
reply = event.AESend(self.send_flags, self.send_priority, reply = event.AESend(self.send_flags, self.send_priority,
self.send_timeout) self.send_timeout)
parameters, attributes = unpackevent(reply, self._moduleName) parameters, attributes = unpackevent(reply, self._moduleName)
return reply, parameters, attributes return reply, parameters, attributes
def send(self, code, subcode, parameters = {}, attributes = {}): def send(self, code, subcode, parameters = {}, attributes = {}):
"""Send an appleevent given code/subcode/pars/attrs and unpack the reply""" """Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
return self.sendevent(self.newevent(code, subcode, parameters, attributes)) return self.sendevent(self.newevent(code, subcode, parameters, attributes))
# #
# The following events are somehow "standard" and don't seem to appear in any # The following events are somehow "standard" and don't seem to appear in any
# suite... # suite...
# #
def activate(self): def activate(self):
"""Send 'activate' command""" """Send 'activate' command"""
self.send('misc', 'actv') self.send('misc', 'actv')
def _get(self, _object, as=None, _attributes={}): def _get(self, _object, as=None, _attributes={}):
"""_get: get data from an object """_get: get data from an object
Required argument: the object Required argument: the object
Keyword argument _attributes: AppleEvent attribute dictionary Keyword argument _attributes: AppleEvent attribute dictionary
Returns: the data Returns: the data
""" """
_code = 'core' _code = 'core'
_subcode = 'getd' _subcode = 'getd'
_arguments = {'----':_object} _arguments = {'----':_object}
if as: if as:
_arguments['rtyp'] = mktype(as) _arguments['rtyp'] = mktype(as)
_reply, _arguments, _attributes = self.send(_code, _subcode, _reply, _arguments, _attributes = self.send(_code, _subcode,
_arguments, _attributes) _arguments, _attributes)
if _arguments.has_key('errn'): if _arguments.has_key('errn'):
raise Error, decodeerror(_arguments) raise Error, decodeerror(_arguments)
if _arguments.has_key('----'): if _arguments.has_key('----'):
return _arguments['----'] return _arguments['----']
if as: if as:
item.__class__ = as item.__class__ = as
return item return item
get = _get get = _get
_argmap_set = { _argmap_set = {
'to' : 'data', 'to' : 'data',
} }
def _set(self, _object, _attributes={}, **_arguments): def _set(self, _object, _attributes={}, **_arguments):
"""set: Set an object's data. """set: Set an object's data.
Required argument: the object for the command Required argument: the object for the command
Keyword argument to: The new value. Keyword argument to: The new value.
Keyword argument _attributes: AppleEvent attribute dictionary Keyword argument _attributes: AppleEvent attribute dictionary
""" """
_code = 'core' _code = 'core'
_subcode = 'setd' _subcode = 'setd'
keysubst(_arguments, self._argmap_set) keysubst(_arguments, self._argmap_set)
_arguments['----'] = _object _arguments['----'] = _object
_reply, _arguments, _attributes = self.send(_code, _subcode, _reply, _arguments, _attributes = self.send(_code, _subcode,
_arguments, _attributes) _arguments, _attributes)
if _arguments.get('errn', 0): if _arguments.get('errn', 0):
raise Error, decodeerror(_arguments) raise Error, decodeerror(_arguments)
# XXXX Optionally decode result # XXXX Optionally decode result
if _arguments.has_key('----'): if _arguments.has_key('----'):
return _arguments['----'] return _arguments['----']
set = _set set = _set
# Tiny Finder class, for local use only # Tiny Finder class, for local use only
class _miniFinder(TalkTo): class _miniFinder(TalkTo):
def open(self, _object, _attributes={}, **_arguments): def open(self, _object, _attributes={}, **_arguments):
"""open: Open the specified object(s) """open: Open the specified object(s)
Required argument: list of objects to open Required argument: list of objects to open
Keyword argument _attributes: AppleEvent attribute dictionary Keyword argument _attributes: AppleEvent attribute dictionary
""" """
_code = 'aevt' _code = 'aevt'
_subcode = 'odoc' _subcode = 'odoc'
if _arguments: raise TypeError, 'No optional args expected' if _arguments: raise TypeError, 'No optional args expected'
_arguments['----'] = _object _arguments['----'] = _object
_reply, _arguments, _attributes = self.send(_code, _subcode, _reply, _arguments, _attributes = self.send(_code, _subcode,
_arguments, _attributes) _arguments, _attributes)
if _arguments.has_key('errn'): if _arguments.has_key('errn'):
raise Error, decodeerror(_arguments) raise Error, decodeerror(_arguments)
# XXXX Optionally decode result # XXXX Optionally decode result
if _arguments.has_key('----'): if _arguments.has_key('----'):
return _arguments['----'] return _arguments['----']
#pass #pass
_finder = _miniFinder('MACS') _finder = _miniFinder('MACS')
def _launch(appfile): def _launch(appfile):
"""Open a file thru the finder. Specify file by name or fsspec""" """Open a file thru the finder. Specify file by name or fsspec"""
_finder.open(_application_file(('ID ', appfile))) _finder.open(_application_file(('ID ', appfile)))
class _application_file(ComponentItem): class _application_file(ComponentItem):
"""application file - An application's file on disk""" """application file - An application's file on disk"""
want = 'appf' want = 'appf'
_application_file._propdict = { _application_file._propdict = {
} }
_application_file._elemdict = { _application_file._elemdict = {
} }
# Test program # Test program
# XXXX Should test more, really... # XXXX Should test more, really...
def test(): def test():
target = AE.AECreateDesc('sign', 'quil') target = AE.AECreateDesc('sign', 'quil')
ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0) ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0)
print unpackevent(ae) print unpackevent(ae)
raw_input(":") raw_input(":")
ae = AE.AECreateAppleEvent('core', 'getd', target, -1, 0) ae = AE.AECreateAppleEvent('core', 'getd', target, -1, 0)
obj = Character(2, Word(1, Document(1))) obj = Character(2, Word(1, Document(1)))
print obj print obj
print repr(obj) print repr(obj)
packevent(ae, {'----': obj}) packevent(ae, {'----': obj})
params, attrs = unpackevent(ae) params, attrs = unpackevent(ae)
print params['----'] print params['----']
raw_input(":") raw_input(":")
if __name__ == '__main__': if __name__ == '__main__':
test() test()
sys.exit(1) sys.exit(1)

View File

@ -10,549 +10,549 @@ import string
# aetools_convert. # aetools_convert.
# #
def pack(*args, **kwargs): def pack(*args, **kwargs):
from aepack import pack from aepack import pack
return pack( *args, **kwargs) return pack( *args, **kwargs)
def nice(s): def nice(s):
"""'nice' representation of an object""" """'nice' representation of an object"""
if type(s) is StringType: return repr(s) if type(s) is StringType: return repr(s)
else: return str(s) else: return str(s)
class Unknown: class Unknown:
"""An uninterpreted AE object""" """An uninterpreted AE object"""
def __init__(self, type, data): def __init__(self, type, data):
self.type = type self.type = type
self.data = data self.data = data
def __repr__(self): def __repr__(self):
return "Unknown(%s, %s)" % (`self.type`, `self.data`) return "Unknown(%s, %s)" % (`self.type`, `self.data`)
def __aepack__(self): def __aepack__(self):
return pack(self.data, self.type) return pack(self.data, self.type)
class Enum: class Enum:
"""An AE enumeration value""" """An AE enumeration value"""
def __init__(self, enum): def __init__(self, enum):
self.enum = "%-4.4s" % str(enum) self.enum = "%-4.4s" % str(enum)
def __repr__(self): def __repr__(self):
return "Enum(%s)" % `self.enum` return "Enum(%s)" % `self.enum`
def __str__(self): def __str__(self):
return string.strip(self.enum) return string.strip(self.enum)
def __aepack__(self): def __aepack__(self):
return pack(self.enum, typeEnumeration) return pack(self.enum, typeEnumeration)
def IsEnum(x): def IsEnum(x):
return isinstance(x, Enum) return isinstance(x, Enum)
def mkenum(enum): def mkenum(enum):
if IsEnum(enum): return enum if IsEnum(enum): return enum
return Enum(enum) return Enum(enum)
# Jack changed the way this is done # Jack changed the way this is done
class InsertionLoc: class InsertionLoc:
def __init__(self, of, pos): def __init__(self, of, pos):
self.of = of self.of = of
self.pos = pos self.pos = pos
def __repr__(self): def __repr__(self):
return "InsertionLoc(%s, %s)" % (`self.of`, `self.pos`) return "InsertionLoc(%s, %s)" % (`self.of`, `self.pos`)
def __aepack__(self): def __aepack__(self):
rec = {'kobj': self.of, 'kpos': self.pos} rec = {'kobj': self.of, 'kpos': self.pos}
return pack(rec, forcetype='insl') return pack(rec, forcetype='insl')
# Convenience functions for dsp: # Convenience functions for dsp:
def beginning(of): def beginning(of):
return InsertionLoc(of, Enum('bgng')) return InsertionLoc(of, Enum('bgng'))
def end(of): def end(of):
return InsertionLoc(of, Enum('end ')) return InsertionLoc(of, Enum('end '))
class Boolean: class Boolean:
"""An AE boolean value""" """An AE boolean value"""
def __init__(self, bool): def __init__(self, bool):
self.bool = (not not bool) self.bool = (not not bool)
def __repr__(self): def __repr__(self):
return "Boolean(%s)" % `self.bool` return "Boolean(%s)" % `self.bool`
def __str__(self): def __str__(self):
if self.bool: if self.bool:
return "True" return "True"
else: else:
return "False" return "False"
def __aepack__(self): def __aepack__(self):
return pack(struct.pack('b', self.bool), 'bool') return pack(struct.pack('b', self.bool), 'bool')
def IsBoolean(x): def IsBoolean(x):
return isinstance(x, Boolean) return isinstance(x, Boolean)
def mkboolean(bool): def mkboolean(bool):
if IsBoolean(bool): return bool if IsBoolean(bool): return bool
return Boolean(bool) return Boolean(bool)
class Type: class Type:
"""An AE 4-char typename object""" """An AE 4-char typename object"""
def __init__(self, type): def __init__(self, type):
self.type = "%-4.4s" % str(type) self.type = "%-4.4s" % str(type)
def __repr__(self): def __repr__(self):
return "Type(%s)" % `self.type` return "Type(%s)" % `self.type`
def __str__(self): def __str__(self):
return string.strip(self.type) return string.strip(self.type)
def __aepack__(self): def __aepack__(self):
return pack(self.type, typeType) return pack(self.type, typeType)
def IsType(x): def IsType(x):
return isinstance(x, Type) return isinstance(x, Type)
def mktype(type): def mktype(type):
if IsType(type): return type if IsType(type): return type
return Type(type) return Type(type)
class Keyword: class Keyword:
"""An AE 4-char keyword object""" """An AE 4-char keyword object"""
def __init__(self, keyword): def __init__(self, keyword):
self.keyword = "%-4.4s" % str(keyword) self.keyword = "%-4.4s" % str(keyword)
def __repr__(self): def __repr__(self):
return "Keyword(%s)" % `self.keyword` return "Keyword(%s)" % `self.keyword`
def __str__(self): def __str__(self):
return string.strip(self.keyword) return string.strip(self.keyword)
def __aepack__(self): def __aepack__(self):
return pack(self.keyword, typeKeyword) return pack(self.keyword, typeKeyword)
def IsKeyword(x): def IsKeyword(x):
return isinstance(x, Keyword) return isinstance(x, Keyword)
class Range: class Range:
"""An AE range object""" """An AE range object"""
def __init__(self, start, stop): def __init__(self, start, stop):
self.start = start self.start = start
self.stop = stop self.stop = stop
def __repr__(self): def __repr__(self):
return "Range(%s, %s)" % (`self.start`, `self.stop`) return "Range(%s, %s)" % (`self.start`, `self.stop`)
def __str__(self): def __str__(self):
return "%s thru %s" % (nice(self.start), nice(self.stop)) return "%s thru %s" % (nice(self.start), nice(self.stop))
def __aepack__(self): def __aepack__(self):
return pack({'star': self.start, 'stop': self.stop}, 'rang') return pack({'star': self.start, 'stop': self.stop}, 'rang')
def IsRange(x): def IsRange(x):
return isinstance(x, Range) return isinstance(x, Range)
class Comparison: class Comparison:
"""An AE Comparison""" """An AE Comparison"""
def __init__(self, obj1, relo, obj2): def __init__(self, obj1, relo, obj2):
self.obj1 = obj1 self.obj1 = obj1
self.relo = "%-4.4s" % str(relo) self.relo = "%-4.4s" % str(relo)
self.obj2 = obj2 self.obj2 = obj2
def __repr__(self): def __repr__(self):
return "Comparison(%s, %s, %s)" % (`self.obj1`, `self.relo`, `self.obj2`) return "Comparison(%s, %s, %s)" % (`self.obj1`, `self.relo`, `self.obj2`)
def __str__(self): def __str__(self):
return "%s %s %s" % (nice(self.obj1), string.strip(self.relo), nice(self.obj2)) return "%s %s %s" % (nice(self.obj1), string.strip(self.relo), nice(self.obj2))
def __aepack__(self): def __aepack__(self):
return pack({'obj1': self.obj1, return pack({'obj1': self.obj1,
'relo': mkenum(self.relo), 'relo': mkenum(self.relo),
'obj2': self.obj2}, 'obj2': self.obj2},
'cmpd') 'cmpd')
def IsComparison(x): def IsComparison(x):
return isinstance(x, Comparison) return isinstance(x, Comparison)
class NComparison(Comparison): class NComparison(Comparison):
# The class attribute 'relo' must be set in a subclass # The class attribute 'relo' must be set in a subclass
def __init__(self, obj1, obj2): def __init__(self, obj1, obj2):
Comparison.__init__(obj1, self.relo, obj2) Comparison.__init__(obj1, self.relo, obj2)
class Ordinal: class Ordinal:
"""An AE Ordinal""" """An AE Ordinal"""
def __init__(self, abso): def __init__(self, abso):
# self.obj1 = obj1 # self.obj1 = obj1
self.abso = "%-4.4s" % str(abso) self.abso = "%-4.4s" % str(abso)
def __repr__(self): def __repr__(self):
return "Ordinal(%s)" % (`self.abso`) return "Ordinal(%s)" % (`self.abso`)
def __str__(self): def __str__(self):
return "%s" % (string.strip(self.abso)) return "%s" % (string.strip(self.abso))
def __aepack__(self): def __aepack__(self):
return pack(self.abso, 'abso') return pack(self.abso, 'abso')
def IsOrdinal(x): def IsOrdinal(x):
return isinstance(x, Ordinal) return isinstance(x, Ordinal)
class NOrdinal(Ordinal): class NOrdinal(Ordinal):
# The class attribute 'abso' must be set in a subclass # The class attribute 'abso' must be set in a subclass
def __init__(self): def __init__(self):
Ordinal.__init__(self, self.abso) Ordinal.__init__(self, self.abso)
class Logical: class Logical:
"""An AE logical expression object""" """An AE logical expression object"""
def __init__(self, logc, term): def __init__(self, logc, term):
self.logc = "%-4.4s" % str(logc) self.logc = "%-4.4s" % str(logc)
self.term = term self.term = term
def __repr__(self): def __repr__(self):
return "Logical(%s, %s)" % (`self.logc`, `self.term`) return "Logical(%s, %s)" % (`self.logc`, `self.term`)
def __str__(self): def __str__(self):
if type(self.term) == ListType and len(self.term) == 2: if type(self.term) == ListType and len(self.term) == 2:
return "%s %s %s" % (nice(self.term[0]), return "%s %s %s" % (nice(self.term[0]),
string.strip(self.logc), string.strip(self.logc),
nice(self.term[1])) nice(self.term[1]))
else: else:
return "%s(%s)" % (string.strip(self.logc), nice(self.term)) return "%s(%s)" % (string.strip(self.logc), nice(self.term))
def __aepack__(self): def __aepack__(self):
return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi') return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi')
def IsLogical(x): def IsLogical(x):
return isinstance(x, Logical) return isinstance(x, Logical)
class StyledText: class StyledText:
"""An AE object respresenting text in a certain style""" """An AE object respresenting text in a certain style"""
def __init__(self, style, text): def __init__(self, style, text):
self.style = style self.style = style
self.text = text self.text = text
def __repr__(self): def __repr__(self):
return "StyledText(%s, %s)" % (`self.style`, `self.text`) return "StyledText(%s, %s)" % (`self.style`, `self.text`)
def __str__(self): def __str__(self):
return self.text return self.text
def __aepack__(self): def __aepack__(self):
return pack({'ksty': self.style, 'ktxt': self.text}, 'STXT') return pack({'ksty': self.style, 'ktxt': self.text}, 'STXT')
def IsStyledText(x): def IsStyledText(x):
return isinstance(x, StyledText) return isinstance(x, StyledText)
class AEText: class AEText:
"""An AE text object with style, script and language specified""" """An AE text object with style, script and language specified"""
def __init__(self, script, style, text): def __init__(self, script, style, text):
self.script = script self.script = script
self.style = style self.style = style
self.text = text self.text = text
def __repr__(self): def __repr__(self):
return "AEText(%s, %s, %s)" % (`self.script`, `self.style`, `self.text`) return "AEText(%s, %s, %s)" % (`self.script`, `self.style`, `self.text`)
def __str__(self): def __str__(self):
return self.text return self.text
def __aepack__(self): def __aepack__(self):
return pack({keyAEScriptTag: self.script, keyAEStyles: self.style, return pack({keyAEScriptTag: self.script, keyAEStyles: self.style,
keyAEText: self.text}, typeAEText) keyAEText: self.text}, typeAEText)
def IsAEText(x): def IsAEText(x):
return isinstance(x, AEText) return isinstance(x, AEText)
class IntlText: class IntlText:
"""A text object with script and language specified""" """A text object with script and language specified"""
def __init__(self, script, language, text): def __init__(self, script, language, text):
self.script = script self.script = script
self.language = language self.language = language
self.text = text self.text = text
def __repr__(self): def __repr__(self):
return "IntlText(%s, %s, %s)" % (`self.script`, `self.language`, `self.text`) return "IntlText(%s, %s, %s)" % (`self.script`, `self.language`, `self.text`)
def __str__(self): def __str__(self):
return self.text return self.text
def __aepack__(self): def __aepack__(self):
return pack(struct.pack('hh', self.script, self.language)+self.text, return pack(struct.pack('hh', self.script, self.language)+self.text,
typeIntlText) typeIntlText)
def IsIntlText(x): def IsIntlText(x):
return isinstance(x, IntlText) return isinstance(x, IntlText)
class IntlWritingCode: class IntlWritingCode:
"""An object representing script and language""" """An object representing script and language"""
def __init__(self, script, language): def __init__(self, script, language):
self.script = script self.script = script
self.language = language self.language = language
def __repr__(self): def __repr__(self):
return "IntlWritingCode(%s, %s)" % (`self.script`, `self.language`) return "IntlWritingCode(%s, %s)" % (`self.script`, `self.language`)
def __str__(self): def __str__(self):
return "script system %d, language %d"%(self.script, self.language) return "script system %d, language %d"%(self.script, self.language)
def __aepack__(self): def __aepack__(self):
return pack(struct.pack('hh', self.script, self.language), return pack(struct.pack('hh', self.script, self.language),
typeIntlWritingCode) typeIntlWritingCode)
def IsIntlWritingCode(x): def IsIntlWritingCode(x):
return isinstance(x, IntlWritingCode) return isinstance(x, IntlWritingCode)
class QDPoint: class QDPoint:
"""A point""" """A point"""
def __init__(self, v, h): def __init__(self, v, h):
self.v = v self.v = v
self.h = h self.h = h
def __repr__(self): def __repr__(self):
return "QDPoint(%s, %s)" % (`self.v`, `self.h`) return "QDPoint(%s, %s)" % (`self.v`, `self.h`)
def __str__(self): def __str__(self):
return "(%d, %d)"%(self.v, self.h) return "(%d, %d)"%(self.v, self.h)
def __aepack__(self): def __aepack__(self):
return pack(struct.pack('hh', self.v, self.h), return pack(struct.pack('hh', self.v, self.h),
typeQDPoint) typeQDPoint)
def IsQDPoint(x): def IsQDPoint(x):
return isinstance(x, QDPoint) return isinstance(x, QDPoint)
class QDRectangle: class QDRectangle:
"""A rectangle""" """A rectangle"""
def __init__(self, v0, h0, v1, h1): def __init__(self, v0, h0, v1, h1):
self.v0 = v0 self.v0 = v0
self.h0 = h0 self.h0 = h0
self.v1 = v1 self.v1 = v1
self.h1 = h1 self.h1 = h1
def __repr__(self): def __repr__(self):
return "QDRectangle(%s, %s, %s, %s)" % (`self.v0`, `self.h0`, return "QDRectangle(%s, %s, %s, %s)" % (`self.v0`, `self.h0`,
`self.v1`, `self.h1`) `self.v1`, `self.h1`)
def __str__(self): def __str__(self):
return "(%d, %d)-(%d, %d)"%(self.v0, self.h0, self.v1, self.h1) return "(%d, %d)-(%d, %d)"%(self.v0, self.h0, self.v1, self.h1)
def __aepack__(self): def __aepack__(self):
return pack(struct.pack('hhhh', self.v0, self.h0, self.v1, self.h1), return pack(struct.pack('hhhh', self.v0, self.h0, self.v1, self.h1),
typeQDRectangle) typeQDRectangle)
def IsQDRectangle(x): def IsQDRectangle(x):
return isinstance(x, QDRectangle) return isinstance(x, QDRectangle)
class RGBColor: class RGBColor:
"""An RGB color""" """An RGB color"""
def __init__(self, r, g, b): def __init__(self, r, g, b):
self.r = r self.r = r
self.g = g self.g = g
self.b = b self.b = b
def __repr__(self): def __repr__(self):
return "RGBColor(%s, %s, %s)" % (`self.r`, `self.g`, `self.b`) return "RGBColor(%s, %s, %s)" % (`self.r`, `self.g`, `self.b`)
def __str__(self): def __str__(self):
return "0x%x red, 0x%x green, 0x%x blue"% (self.r, self.g, self.b) return "0x%x red, 0x%x green, 0x%x blue"% (self.r, self.g, self.b)
def __aepack__(self): def __aepack__(self):
return pack(struct.pack('hhh', self.r, self.g, self.b), return pack(struct.pack('hhh', self.r, self.g, self.b),
typeRGBColor) typeRGBColor)
def IsRGBColor(x): def IsRGBColor(x):
return isinstance(x, RGBColor) return isinstance(x, RGBColor)
class ObjectSpecifier: class ObjectSpecifier:
"""A class for constructing and manipulation AE object specifiers in python. """A class for constructing and manipulation AE object specifiers in python.
An object specifier is actually a record with four fields: An object specifier is actually a record with four fields:
key type description key type description
--- ---- ----------- --- ---- -----------
'want' type 4-char class code of thing we want, 'want' type 4-char class code of thing we want,
e.g. word, paragraph or property e.g. word, paragraph or property
'form' enum how we specify which 'want' thing(s) we want, 'form' enum how we specify which 'want' thing(s) we want,
e.g. by index, by range, by name, or by property specifier e.g. by index, by range, by name, or by property specifier
'seld' any which thing(s) we want, 'seld' any which thing(s) we want,
e.g. its index, its name, or its property specifier e.g. its index, its name, or its property specifier
'from' object the object in which it is contained, 'from' object the object in which it is contained,
or null, meaning look for it in the application or null, meaning look for it in the application
Note that we don't call this class plain "Object", since that name Note that we don't call this class plain "Object", since that name
is likely to be used by the application. is likely to be used by the application.
""" """
def __init__(self, want, form, seld, fr = None): def __init__(self, want, form, seld, fr = None):
self.want = want self.want = want
self.form = form self.form = form
self.seld = seld self.seld = seld
self.fr = fr self.fr = fr
def __repr__(self): def __repr__(self):
s = "ObjectSpecifier(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`) s = "ObjectSpecifier(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`)
if self.fr: if self.fr:
s = s + ", %s)" % `self.fr` s = s + ", %s)" % `self.fr`
else: else:
s = s + ")" s = s + ")"
return s return s
def __aepack__(self): def __aepack__(self):
return pack({'want': mktype(self.want), return pack({'want': mktype(self.want),
'form': mkenum(self.form), 'form': mkenum(self.form),
'seld': self.seld, 'seld': self.seld,
'from': self.fr}, 'from': self.fr},
'obj ') 'obj ')
def IsObjectSpecifier(x): def IsObjectSpecifier(x):
return isinstance(x, ObjectSpecifier) return isinstance(x, ObjectSpecifier)
# Backwards compatability, sigh... # Backwards compatability, sigh...
class Property(ObjectSpecifier): class Property(ObjectSpecifier):
def __init__(self, which, fr = None, want='prop'): def __init__(self, which, fr = None, want='prop'):
ObjectSpecifier.__init__(self, want, 'prop', mktype(which), fr) ObjectSpecifier.__init__(self, want, 'prop', mktype(which), fr)
def __repr__(self): def __repr__(self):
if self.fr: if self.fr:
return "Property(%s, %s)" % (`self.seld.type`, `self.fr`) return "Property(%s, %s)" % (`self.seld.type`, `self.fr`)
else: else:
return "Property(%s)" % `self.seld.type` return "Property(%s)" % `self.seld.type`
def __str__(self): def __str__(self):
if self.fr: if self.fr:
return "Property %s of %s" % (str(self.seld), str(self.fr)) return "Property %s of %s" % (str(self.seld), str(self.fr))
else: else:
return "Property %s" % str(self.seld) return "Property %s" % str(self.seld)
class NProperty(ObjectSpecifier): class NProperty(ObjectSpecifier):
# Subclasses *must* self baseclass attributes: # Subclasses *must* self baseclass attributes:
# want is the type of this property # want is the type of this property
# which is the property name of this property # which is the property name of this property
def __init__(self, fr = None): def __init__(self, fr = None):
#try: #try:
# dummy = self.want # dummy = self.want
#except: #except:
# self.want = 'prop' # self.want = 'prop'
self.want = 'prop' self.want = 'prop'
ObjectSpecifier.__init__(self, self.want, 'prop', ObjectSpecifier.__init__(self, self.want, 'prop',
mktype(self.which), fr) mktype(self.which), fr)
def __repr__(self): def __repr__(self):
rv = "Property(%s"%`self.seld.type` rv = "Property(%s"%`self.seld.type`
if self.fr: if self.fr:
rv = rv + ", fr=%s" % `self.fr` rv = rv + ", fr=%s" % `self.fr`
if self.want != 'prop': if self.want != 'prop':
rv = rv + ", want=%s" % `self.want` rv = rv + ", want=%s" % `self.want`
return rv + ")" return rv + ")"
def __str__(self): def __str__(self):
if self.fr: if self.fr:
return "Property %s of %s" % (str(self.seld), str(self.fr)) return "Property %s of %s" % (str(self.seld), str(self.fr))
else: else:
return "Property %s" % str(self.seld) return "Property %s" % str(self.seld)
class SelectableItem(ObjectSpecifier): class SelectableItem(ObjectSpecifier):
def __init__(self, want, seld, fr = None): def __init__(self, want, seld, fr = None):
t = type(seld) t = type(seld)
if t == StringType: if t == StringType:
form = 'name' form = 'name'
elif IsRange(seld): elif IsRange(seld):
form = 'rang' form = 'rang'
elif IsComparison(seld) or IsLogical(seld): elif IsComparison(seld) or IsLogical(seld):
form = 'test' form = 'test'
elif t == TupleType: elif t == TupleType:
# Breakout: specify both form and seld in a tuple # Breakout: specify both form and seld in a tuple
# (if you want ID or rele or somesuch) # (if you want ID or rele or somesuch)
form, seld = seld form, seld = seld
else: else:
form = 'indx' form = 'indx'
ObjectSpecifier.__init__(self, want, form, seld, fr) ObjectSpecifier.__init__(self, want, form, seld, fr)
class ComponentItem(SelectableItem): class ComponentItem(SelectableItem):
# Derived classes *must* set the *class attribute* 'want' to some constant # Derived classes *must* set the *class attribute* 'want' to some constant
# Also, dictionaries _propdict and _elemdict must be set to map property # Also, dictionaries _propdict and _elemdict must be set to map property
# and element names to the correct classes # and element names to the correct classes
_propdict = {} _propdict = {}
_elemdict = {} _elemdict = {}
def __init__(self, which, fr = None): def __init__(self, which, fr = None):
SelectableItem.__init__(self, self.want, which, fr) SelectableItem.__init__(self, self.want, which, fr)
def __repr__(self): def __repr__(self):
if not self.fr: if not self.fr:
return "%s(%s)" % (self.__class__.__name__, `self.seld`) return "%s(%s)" % (self.__class__.__name__, `self.seld`)
return "%s(%s, %s)" % (self.__class__.__name__, `self.seld`, `self.fr`) return "%s(%s, %s)" % (self.__class__.__name__, `self.seld`, `self.fr`)
def __str__(self): def __str__(self):
seld = self.seld seld = self.seld
if type(seld) == StringType: if type(seld) == StringType:
ss = repr(seld) ss = repr(seld)
elif IsRange(seld): elif IsRange(seld):
start, stop = seld.start, seld.stop start, stop = seld.start, seld.stop
if type(start) == InstanceType == type(stop) and \ if type(start) == InstanceType == type(stop) and \
start.__class__ == self.__class__ == stop.__class__: start.__class__ == self.__class__ == stop.__class__:
ss = str(start.seld) + " thru " + str(stop.seld) ss = str(start.seld) + " thru " + str(stop.seld)
else: else:
ss = str(seld) ss = str(seld)
else: else:
ss = str(seld) ss = str(seld)
s = "%s %s" % (self.__class__.__name__, ss) s = "%s %s" % (self.__class__.__name__, ss)
if self.fr: s = s + " of %s" % str(self.fr) if self.fr: s = s + " of %s" % str(self.fr)
return s return s
def __getattr__(self, name): def __getattr__(self, name):
if self._elemdict.has_key(name): if self._elemdict.has_key(name):
cls = self._elemdict[name] cls = self._elemdict[name]
return DelayedComponentItem(cls, self) return DelayedComponentItem(cls, self)
if self._propdict.has_key(name): if self._propdict.has_key(name):
cls = self._propdict[name] cls = self._propdict[name]
return cls(self) return cls(self)
raise AttributeError, name raise AttributeError, name
class DelayedComponentItem: class DelayedComponentItem:
def __init__(self, compclass, fr): def __init__(self, compclass, fr):
self.compclass = compclass self.compclass = compclass
self.fr = fr self.fr = fr
def __call__(self, which): def __call__(self, which):
return self.compclass(which, self.fr) return self.compclass(which, self.fr)
def __repr__(self): def __repr__(self):
return "%s(???, %s)" % (self.__class__.__name__, `self.fr`) return "%s(???, %s)" % (self.__class__.__name__, `self.fr`)
def __str__(self): def __str__(self):
return "selector for element %s of %s"%(self.__class__.__name__, str(self.fr)) return "selector for element %s of %s"%(self.__class__.__name__, str(self.fr))
template = """ template = """
class %s(ComponentItem): want = '%s' class %s(ComponentItem): want = '%s'

View File

@ -24,77 +24,77 @@ AS_RESOURCEFORK=2
AS_IGNORE=(3,4,5,6,8,9,10,11,12,13,14,15) AS_IGNORE=(3,4,5,6,8,9,10,11,12,13,14,15)
def decode(input, output, resonly=0): def decode(input, output, resonly=0):
if type(input) == type(''): if type(input) == type(''):
input = open(input, 'rb') input = open(input, 'rb')
# Should we also test for FSSpecs or FSRefs? # Should we also test for FSSpecs or FSRefs?
header = input.read(AS_HEADER_LENGTH) header = input.read(AS_HEADER_LENGTH)
try: try:
magic, version, dummy, nentry = struct.unpack(AS_HEADER_FORMAT, header) magic, version, dummy, nentry = struct.unpack(AS_HEADER_FORMAT, header)
except ValueError, arg: except ValueError, arg:
raise Error, "Unpack header error: %s"%arg raise Error, "Unpack header error: %s"%arg
if verbose: if verbose:
print 'Magic: 0x%8.8x'%magic print 'Magic: 0x%8.8x'%magic
print 'Version: 0x%8.8x'%version print 'Version: 0x%8.8x'%version
print 'Entries: %d'%nentry print 'Entries: %d'%nentry
if magic != AS_MAGIC: if magic != AS_MAGIC:
raise Error, 'Unknown AppleSingle magic number 0x%8.8x'%magic raise Error, 'Unknown AppleSingle magic number 0x%8.8x'%magic
if version != AS_VERSION: if version != AS_VERSION:
raise Error, 'Unknown AppleSingle version number 0x%8.8x'%version raise Error, 'Unknown AppleSingle version number 0x%8.8x'%version
if nentry <= 0: if nentry <= 0:
raise Error, "AppleSingle file contains no forks" raise Error, "AppleSingle file contains no forks"
headers = [input.read(AS_ENTRY_LENGTH) for i in range(nentry)] headers = [input.read(AS_ENTRY_LENGTH) for i in range(nentry)]
didwork = 0 didwork = 0
for hdr in headers: for hdr in headers:
try: try:
id, offset, length = struct.unpack(AS_ENTRY_FORMAT, hdr) id, offset, length = struct.unpack(AS_ENTRY_FORMAT, hdr)
except ValueError, arg: except ValueError, arg:
raise Error, "Unpack entry error: %s"%arg raise Error, "Unpack entry error: %s"%arg
if verbose: if verbose:
print 'Fork %d, offset %d, length %d'%(id, offset, length) print 'Fork %d, offset %d, length %d'%(id, offset, length)
input.seek(offset) input.seek(offset)
if length == 0: if length == 0:
data = '' data = ''
else: else:
data = input.read(length) data = input.read(length)
if len(data) != length: if len(data) != length:
raise Error, 'Short read: expected %d bytes got %d'%(length, len(data)) raise Error, 'Short read: expected %d bytes got %d'%(length, len(data))
if id == AS_DATAFORK: if id == AS_DATAFORK:
if verbose: if verbose:
print ' (data fork)' print ' (data fork)'
if not resonly: if not resonly:
didwork = 1 didwork = 1
fp = open(output, 'wb') fp = open(output, 'wb')
fp.write(data) fp.write(data)
fp.close() fp.close()
elif id == AS_RESOURCEFORK: elif id == AS_RESOURCEFORK:
didwork = 1 didwork = 1
if verbose: if verbose:
print ' (resource fork)' print ' (resource fork)'
if resonly: if resonly:
fp = open(output, 'wb') fp = open(output, 'wb')
else: else:
fp = MacOS.openrf(output, 'wb') fp = MacOS.openrf(output, 'wb')
fp.write(data) fp.write(data)
fp.close() fp.close()
elif id in AS_IGNORE: elif id in AS_IGNORE:
if verbose: if verbose:
print ' (ignored)' print ' (ignored)'
else: else:
raise Error, 'Unknown fork type %d'%id raise Error, 'Unknown fork type %d'%id
if not didwork: if not didwork:
raise Error, 'No useful forks found' raise Error, 'No useful forks found'
def _test(): def _test():
if len(sys.argv) < 3 or sys.argv[1] == '-r' and len(sys.argv) != 4: if len(sys.argv) < 3 or sys.argv[1] == '-r' and len(sys.argv) != 4:
print 'Usage: applesingle.py [-r] applesinglefile decodedfile' print 'Usage: applesingle.py [-r] applesinglefile decodedfile'
sys.exit(1) sys.exit(1)
if sys.argv[1] == '-r': if sys.argv[1] == '-r':
resonly = 1 resonly = 1
del sys.argv[1] del sys.argv[1]
else: else:
resonly = 0 resonly = 0
decode(sys.argv[1], sys.argv[2], resonly=resonly) decode(sys.argv[1], sys.argv[2], resonly=resonly)
if __name__ == '__main__': if __name__ == '__main__':
_test() _test()

View File

@ -14,13 +14,13 @@ import marshal
# directory. # directory.
# #
if not sys.argv or sys.argv[0][:1] == '-': if not sys.argv or sys.argv[0][:1] == '-':
# Insert our (guessed) name. # Insert our (guessed) name.
_dir = os.path.split(sys.executable)[0] # removes "python" _dir = os.path.split(sys.executable)[0] # removes "python"
_dir = os.path.split(_dir)[0] # Removes "MacOS" _dir = os.path.split(_dir)[0] # Removes "MacOS"
_dir = os.path.join(_dir, 'Resources') _dir = os.path.join(_dir, 'Resources')
sys.argv.insert(0, '__rawmain__') sys.argv.insert(0, '__rawmain__')
else: else:
_dir = os.path.split(sys.argv[0])[0] _dir = os.path.split(sys.argv[0])[0]
# #
# Add the Resources directory to the path. This is where files installed # 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 # by BuildApplet.py with the --extra option show up, and if those files are
@ -36,28 +36,28 @@ argvemulator.ArgvCollector().mainloop()
# #
__file__ = os.path.join(_dir, '__main__.py') __file__ = os.path.join(_dir, '__main__.py')
if os.path.exists(__file__): if os.path.exists(__file__):
# #
# Setup something resembling a normal environment and go. # Setup something resembling a normal environment and go.
# #
sys.argv[0] = __file__ sys.argv[0] = __file__
del argvemulator, os, sys, _dir del argvemulator, os, sys, _dir
execfile(__file__) execfile(__file__)
else: else:
__file__ = os.path.join(_dir, '__main__.pyc') __file__ = os.path.join(_dir, '__main__.pyc')
if os.path.exists(__file__): if os.path.exists(__file__):
# #
# If we have only a .pyc file we read the code object from that # If we have only a .pyc file we read the code object from that
# #
sys.argv[0] = __file__ sys.argv[0] = __file__
_fp = open(__file__, 'rb') _fp = open(__file__, 'rb')
_fp.read(8) _fp.read(8)
__code__ = marshal.load(_fp) __code__ = marshal.load(_fp)
# #
# Again, we create an almost-normal environment (only __code__ is # Again, we create an almost-normal environment (only __code__ is
# funny) and go. # funny) and go.
# #
del argvemulator, os, sys, marshal, _dir, _fp del argvemulator, os, sys, marshal, _dir, _fp
exec __code__ exec __code__
else: else:
sys.stderr.write("%s: neither __main__.py nor __main__.pyc found\n"%sys.argv[0]) sys.stderr.write("%s: neither __main__.py nor __main__.pyc found\n"%sys.argv[0])
sys.exit(1) sys.exit(1)

View File

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

View File

@ -12,12 +12,12 @@ Error = "bgenlocations.Error"
# Where bgen is. For unix-Python bgen isn't installed, so you have to refer to # Where bgen is. For unix-Python bgen isn't installed, so you have to refer to
# the source tree here. # the source tree here.
if sys.platform == 'mac': if sys.platform == 'mac':
# For MacPython we know where it is # For MacPython we know where it is
def _pardir(p): return os.path.split(p)[0] def _pardir(p): return os.path.split(p)[0]
BGENDIR=os.path.join(sys.prefix, "Tools", "bgen", "bgen") BGENDIR=os.path.join(sys.prefix, "Tools", "bgen", "bgen")
else: else:
# for unix-Python we don't know, please set it yourself. # for unix-Python we don't know, please set it yourself.
BGENDIR="/Users/jack/src/python/Tools/bgen/bgen" BGENDIR="/Users/jack/src/python/Tools/bgen/bgen"
# #
# Where to find the Universal Header include files. If you have CodeWarrior # Where to find the Universal Header include files. If you have CodeWarrior
@ -26,9 +26,9 @@ else:
# end of lines, so don't worry about that. # end of lines, so don't worry about that.
# #
if sys.platform == 'mac': if sys.platform == 'mac':
_MWERKSDIR="Sap:Applications (Mac OS 9):Metrowerks CodeWarrior 7.0:Metrowerks CodeWarrior" _MWERKSDIR="Sap:Applications (Mac OS 9):Metrowerks CodeWarrior 7.0:Metrowerks CodeWarrior"
else: else:
_MWERKSDIR="/Volumes/Sap/Applications (Mac OS 9)/Metrowerks CodeWarrior 7.0/Metrowerks CodeWarrior/" _MWERKSDIR="/Volumes/Sap/Applications (Mac OS 9)/Metrowerks CodeWarrior 7.0/Metrowerks CodeWarrior/"
INCLUDEDIR=os.path.join(_MWERKSDIR, "MacOS Support", "Universal", "Interfaces", "CIncludes") INCLUDEDIR=os.path.join(_MWERKSDIR, "MacOS Support", "Universal", "Interfaces", "CIncludes")
# #
@ -37,25 +37,25 @@ INCLUDEDIR=os.path.join(_MWERKSDIR, "MacOS Support", "Universal", "Interfaces",
# your source directory, not your installed directory. # your source directory, not your installed directory.
# #
if sys.platform == 'mac': if sys.platform == 'mac':
TOOLBOXDIR=os.path.join(sys.prefix, "Lib", "plat-mac", "Carbon") TOOLBOXDIR=os.path.join(sys.prefix, "Lib", "plat-mac", "Carbon")
else: else:
TOOLBOXDIR="/Users/jack/src/python/Lib/plat-mac/Carbon" TOOLBOXDIR="/Users/jack/src/python/Lib/plat-mac/Carbon"
# Creator for C files: # Creator for C files:
CREATOR="CWIE" CREATOR="CWIE"
if not os.path.exists(BGENDIR): if not os.path.exists(BGENDIR):
raise Error, "Please fix bgenlocations.py, BGENDIR does not exist: %s" % BGENDIR raise Error, "Please fix bgenlocations.py, BGENDIR does not exist: %s" % BGENDIR
if not os.path.exists(INCLUDEDIR): if not os.path.exists(INCLUDEDIR):
raise Error, "Please fix bgenlocations.py, INCLUDEDIR does not exist: %s" % INCLUDEDIR raise Error, "Please fix bgenlocations.py, INCLUDEDIR does not exist: %s" % INCLUDEDIR
if not os.path.exists(TOOLBOXDIR): if not os.path.exists(TOOLBOXDIR):
raise Error, "Please fix bgenlocations.py, TOOLBOXDIR does not exist: %s" % 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 /. # Sigh, due to the way these are used make sure they end with : or /.
if BGENDIR[-1] != os.sep: if BGENDIR[-1] != os.sep:
BGENDIR = BGENDIR + os.sep BGENDIR = BGENDIR + os.sep
if INCLUDEDIR[-1] != os.sep: if INCLUDEDIR[-1] != os.sep:
INCLUDEDIR = INCLUDEDIR + os.sep INCLUDEDIR = INCLUDEDIR + os.sep
if TOOLBOXDIR[-1] != os.sep: if TOOLBOXDIR[-1] != os.sep:
TOOLBOXDIR = TOOLBOXDIR + os.sep TOOLBOXDIR = TOOLBOXDIR + os.sep

View File

@ -42,375 +42,375 @@ WRITE = 2
RESOURCE_FORK_NAME=Carbon.File.FSGetResourceForkName() RESOURCE_FORK_NAME=Carbon.File.FSGetResourceForkName()
def findtemplate(template=None): def findtemplate(template=None):
"""Locate the applet template along sys.path""" """Locate the applet template along sys.path"""
if MacOS.runtimemodel == 'macho': if MacOS.runtimemodel == 'macho':
return None return None
if not template: if not template:
template=TEMPLATE template=TEMPLATE
for p in sys.path: for p in sys.path:
file = os.path.join(p, template) file = os.path.join(p, template)
try: try:
file, d1, d2 = Carbon.File.FSResolveAliasFile(file, 1) file, d1, d2 = Carbon.File.FSResolveAliasFile(file, 1)
break break
except (Carbon.File.Error, ValueError): except (Carbon.File.Error, ValueError):
continue continue
else: else:
raise BuildError, "Template %s not found on sys.path" % `template` raise BuildError, "Template %s not found on sys.path" % `template`
file = file.as_pathname() file = file.as_pathname()
return file return file
def process(template, filename, destname, copy_codefragment=0, def process(template, filename, destname, copy_codefragment=0,
rsrcname=None, others=[], raw=0, progress="default"): rsrcname=None, others=[], raw=0, progress="default"):
if progress == "default": if progress == "default":
progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120) progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120)
progress.label("Compiling...") progress.label("Compiling...")
progress.inc(0) progress.inc(0)
# check for the script name being longer than 32 chars. This may trigger a bug # check for the script name being longer than 32 chars. This may trigger a bug
# on OSX that can destroy your sourcefile. # on OSX that can destroy your sourcefile.
if '#' in os.path.split(filename)[1]: if '#' in os.path.split(filename)[1]:
raise BuildError, "BuildApplet could destroy your sourcefile on OSX, please rename: %s" % filename raise BuildError, "BuildApplet could destroy your sourcefile on OSX, please rename: %s" % filename
# Read the source and compile it # Read the source and compile it
# (there's no point overwriting the destination if it has a syntax error) # (there's no point overwriting the destination if it has a syntax error)
fp = open(filename, 'rU') fp = open(filename, 'rU')
text = fp.read() text = fp.read()
fp.close() fp.close()
try: try:
code = compile(text + '\n', filename, "exec") code = compile(text + '\n', filename, "exec")
except SyntaxError, arg: except SyntaxError, arg:
raise BuildError, "Syntax error in script %s: %s" % (filename, arg) raise BuildError, "Syntax error in script %s: %s" % (filename, arg)
except EOFError: except EOFError:
raise BuildError, "End-of-file in script %s" % (filename,) raise BuildError, "End-of-file in script %s" % (filename,)
# Set the destination file name. Note that basename # Set the destination file name. Note that basename
# does contain the whole filepath, only a .py is stripped. # does contain the whole filepath, only a .py is stripped.
if string.lower(filename[-3:]) == ".py": if string.lower(filename[-3:]) == ".py":
basename = filename[:-3] basename = filename[:-3]
if MacOS.runtimemodel != 'macho' and not destname: if MacOS.runtimemodel != 'macho' and not destname:
destname = basename destname = basename
else: else:
basename = filename basename = filename
if not destname: if not destname:
if MacOS.runtimemodel == 'macho': if MacOS.runtimemodel == 'macho':
destname = basename + '.app' destname = basename + '.app'
else: else:
destname = basename + '.applet' destname = basename + '.applet'
if not rsrcname: if not rsrcname:
rsrcname = basename + '.rsrc' rsrcname = basename + '.rsrc'
# Try removing the output file. This fails in MachO, but it should # Try removing the output file. This fails in MachO, but it should
# do any harm. # do any harm.
try: try:
os.remove(destname) os.remove(destname)
except os.error: except os.error:
pass pass
process_common(template, progress, code, rsrcname, destname, 0, process_common(template, progress, code, rsrcname, destname, 0,
copy_codefragment, raw, others, filename) copy_codefragment, raw, others, filename)
def update(template, filename, output): def update(template, filename, output):
if MacOS.runtimemodel == 'macho': if MacOS.runtimemodel == 'macho':
raise BuildError, "No updating yet for MachO applets" raise BuildError, "No updating yet for MachO applets"
if progress: if progress:
progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120) progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120)
else: else:
progress = None progress = None
if not output: if not output:
output = filename + ' (updated)' output = filename + ' (updated)'
# Try removing the output file # Try removing the output file
try: try:
os.remove(output) os.remove(output)
except os.error: except os.error:
pass pass
process_common(template, progress, None, filename, output, 1, 1) process_common(template, progress, None, filename, output, 1, 1)
def process_common(template, progress, code, rsrcname, destname, is_update, def process_common(template, progress, code, rsrcname, destname, is_update,
copy_codefragment, raw=0, others=[], filename=None): copy_codefragment, raw=0, others=[], filename=None):
if MacOS.runtimemodel == 'macho': if MacOS.runtimemodel == 'macho':
return process_common_macho(template, progress, code, rsrcname, destname, return process_common_macho(template, progress, code, rsrcname, destname,
is_update, raw, others, filename) is_update, raw, others, filename)
if others: if others:
raise BuildError, "Extra files only allowed for MachoPython applets" raise BuildError, "Extra files only allowed for MachoPython applets"
# Create FSSpecs for the various files # Create FSSpecs for the various files
template_fsr, d1, d2 = Carbon.File.FSResolveAliasFile(template, 1) template_fsr, d1, d2 = Carbon.File.FSResolveAliasFile(template, 1)
template = template_fsr.as_pathname() template = template_fsr.as_pathname()
# Copy data (not resources, yet) from the template # Copy data (not resources, yet) from the template
if progress: if progress:
progress.label("Copy data fork...") progress.label("Copy data fork...")
progress.set(10) progress.set(10)
if copy_codefragment: if copy_codefragment:
tmpl = open(template, "rb") tmpl = open(template, "rb")
dest = open(destname, "wb") dest = open(destname, "wb")
data = tmpl.read() data = tmpl.read()
if data: if data:
dest.write(data) dest.write(data)
dest.close() dest.close()
tmpl.close() tmpl.close()
del dest del dest
del tmpl del tmpl
# Open the output resource fork # Open the output resource fork
if progress: if progress:
progress.label("Copy resources...") progress.label("Copy resources...")
progress.set(20) progress.set(20)
try: try:
output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE) output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
except MacOS.Error: except MacOS.Error:
destdir, destfile = os.path.split(destname) destdir, destfile = os.path.split(destname)
Res.FSCreateResourceFile(destdir, unicode(destfile), RESOURCE_FORK_NAME) Res.FSCreateResourceFile(destdir, unicode(destfile), RESOURCE_FORK_NAME)
output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE) output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
# Copy the resources from the target specific resource template, if any # Copy the resources from the target specific resource template, if any
typesfound, ownertype = [], None typesfound, ownertype = [], None
try: try:
input = Res.FSOpenResourceFile(rsrcname, RESOURCE_FORK_NAME, READ) input = Res.FSOpenResourceFile(rsrcname, RESOURCE_FORK_NAME, READ)
except (MacOS.Error, ValueError): except (MacOS.Error, ValueError):
pass pass
if progress: if progress:
progress.inc(50) progress.inc(50)
else: else:
if is_update: if is_update:
skip_oldfile = ['cfrg'] skip_oldfile = ['cfrg']
else: else:
skip_oldfile = [] skip_oldfile = []
typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress) typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress)
Res.CloseResFile(input) Res.CloseResFile(input)
# Check which resource-types we should not copy from the template # Check which resource-types we should not copy from the template
skiptypes = [] skiptypes = []
if 'vers' in typesfound: skiptypes.append('vers') if 'vers' in typesfound: skiptypes.append('vers')
if 'SIZE' in typesfound: skiptypes.append('SIZE') if 'SIZE' in typesfound: skiptypes.append('SIZE')
if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4',
'icl8', 'ics4', 'ics8', 'ICN#', 'ics#'] 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
if not copy_codefragment: if not copy_codefragment:
skiptypes.append('cfrg') skiptypes.append('cfrg')
## skipowner = (ownertype <> None) ## skipowner = (ownertype <> None)
# Copy the resources from the template # Copy the resources from the template
input = Res.FSOpenResourceFile(template, RESOURCE_FORK_NAME, READ) input = Res.FSOpenResourceFile(template, RESOURCE_FORK_NAME, READ)
dummy, tmplowner = copyres(input, output, skiptypes, 1, progress) dummy, tmplowner = copyres(input, output, skiptypes, 1, progress)
Res.CloseResFile(input) Res.CloseResFile(input)
## if ownertype == None: ## if ownertype == None:
## raise BuildError, "No owner resource found in either resource file or template" ## raise BuildError, "No owner resource found in either resource file or template"
# Make sure we're manipulating the output resource file now # Make sure we're manipulating the output resource file now
Res.UseResFile(output) Res.UseResFile(output)
if ownertype == None: if ownertype == None:
# No owner resource in the template. We have skipped the # No owner resource in the template. We have skipped the
# Python owner resource, so we have to add our own. The relevant # Python owner resource, so we have to add our own. The relevant
# bundle stuff is already included in the interpret/applet template. # bundle stuff is already included in the interpret/applet template.
newres = Res.Resource('\0') newres = Res.Resource('\0')
newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource") newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource")
ownertype = DEFAULT_APPLET_CREATOR ownertype = DEFAULT_APPLET_CREATOR
if code: if code:
# Delete any existing 'PYC ' resource named __main__ # Delete any existing 'PYC ' resource named __main__
try: try:
res = Res.Get1NamedResource(RESTYPE, RESNAME) res = Res.Get1NamedResource(RESTYPE, RESNAME)
res.RemoveResource() res.RemoveResource()
except Res.Error: except Res.Error:
pass pass
# Create the raw data for the resource from the code object # Create the raw data for the resource from the code object
if progress: if progress:
progress.label("Write PYC resource...") progress.label("Write PYC resource...")
progress.set(120) progress.set(120)
data = marshal.dumps(code) data = marshal.dumps(code)
del code del code
data = (MAGIC + '\0\0\0\0') + data data = (MAGIC + '\0\0\0\0') + data
# Create the resource and write it # Create the resource and write it
id = 0 id = 0
while id < 128: while id < 128:
id = Res.Unique1ID(RESTYPE) id = Res.Unique1ID(RESTYPE)
res = Res.Resource(data) res = Res.Resource(data)
res.AddResource(RESTYPE, id, RESNAME) res.AddResource(RESTYPE, id, RESNAME)
attrs = res.GetResAttrs() attrs = res.GetResAttrs()
attrs = attrs | 0x04 # set preload attrs = attrs | 0x04 # set preload
res.SetResAttrs(attrs) res.SetResAttrs(attrs)
res.WriteResource() res.WriteResource()
res.ReleaseResource() res.ReleaseResource()
# Close the output file # Close the output file
Res.CloseResFile(output) Res.CloseResFile(output)
# Now set the creator, type and bundle bit of the destination. # Now set the creator, type and bundle bit of the destination.
# Done with FSSpec's, FSRef FInfo isn't good enough yet (2.3a1+) # Done with FSSpec's, FSRef FInfo isn't good enough yet (2.3a1+)
dest_fss = Carbon.File.FSSpec(destname) dest_fss = Carbon.File.FSSpec(destname)
dest_finfo = dest_fss.FSpGetFInfo() dest_finfo = dest_fss.FSpGetFInfo()
dest_finfo.Creator = ownertype dest_finfo.Creator = ownertype
dest_finfo.Type = 'APPL' dest_finfo.Type = 'APPL'
dest_finfo.Flags = dest_finfo.Flags | Carbon.Files.kHasBundle | Carbon.Files.kIsShared dest_finfo.Flags = dest_finfo.Flags | Carbon.Files.kHasBundle | Carbon.Files.kIsShared
dest_finfo.Flags = dest_finfo.Flags & ~Carbon.Files.kHasBeenInited dest_finfo.Flags = dest_finfo.Flags & ~Carbon.Files.kHasBeenInited
dest_fss.FSpSetFInfo(dest_finfo) dest_fss.FSpSetFInfo(dest_finfo)
macostools.touched(destname) macostools.touched(destname)
if progress: if progress:
progress.label("Done.") progress.label("Done.")
progress.inc(0) progress.inc(0)
def process_common_macho(template, progress, code, rsrcname, destname, is_update, def process_common_macho(template, progress, code, rsrcname, destname, is_update,
raw=0, others=[], filename=None): raw=0, others=[], filename=None):
# Check that we have a filename # Check that we have a filename
if filename is None: if filename is None:
raise BuildError, "Need source filename on MacOSX" raise BuildError, "Need source filename on MacOSX"
# First make sure the name ends in ".app" # First make sure the name ends in ".app"
if destname[-4:] != '.app': if destname[-4:] != '.app':
destname = destname + '.app' destname = destname + '.app'
# Now deduce the short name # Now deduce the short name
destdir, shortname = os.path.split(destname) destdir, shortname = os.path.split(destname)
if shortname[-4:] == '.app': if shortname[-4:] == '.app':
# Strip the .app suffix # Strip the .app suffix
shortname = shortname[:-4] shortname = shortname[:-4]
# And deduce the .plist and .icns names # And deduce the .plist and .icns names
plistname = None plistname = None
icnsname = None icnsname = None
if rsrcname and rsrcname[-5:] == '.rsrc': if rsrcname and rsrcname[-5:] == '.rsrc':
tmp = rsrcname[:-5] tmp = rsrcname[:-5]
plistname = tmp + '.plist' plistname = tmp + '.plist'
if os.path.exists(plistname): if os.path.exists(plistname):
icnsname = tmp + '.icns' icnsname = tmp + '.icns'
if not os.path.exists(icnsname): if not os.path.exists(icnsname):
icnsname = None icnsname = None
else: else:
plistname = None plistname = None
if not os.path.exists(rsrcname): if not os.path.exists(rsrcname):
rsrcname = None rsrcname = None
if progress: if progress:
progress.label('Creating bundle...') progress.label('Creating bundle...')
import bundlebuilder import bundlebuilder
builder = bundlebuilder.AppBuilder(verbosity=0) builder = bundlebuilder.AppBuilder(verbosity=0)
builder.mainprogram = filename builder.mainprogram = filename
builder.builddir = destdir builder.builddir = destdir
builder.name = shortname builder.name = shortname
if rsrcname: if rsrcname:
realrsrcname = macresource.resource_pathname(rsrcname) realrsrcname = macresource.resource_pathname(rsrcname)
builder.files.append((realrsrcname, builder.files.append((realrsrcname,
os.path.join('Contents/Resources', os.path.basename(rsrcname)))) os.path.join('Contents/Resources', os.path.basename(rsrcname))))
for o in others: for o in others:
if type(o) == str: if type(o) == str:
builder.resources.append(o) builder.resources.append(o)
else: else:
builder.files.append(o) builder.files.append(o)
if plistname: if plistname:
import plistlib import plistlib
builder.plist = plistlib.Plist.fromFile(plistname) builder.plist = plistlib.Plist.fromFile(plistname)
if icnsname: if icnsname:
builder.iconfile = icnsname builder.iconfile = icnsname
if not raw: if not raw:
builder.argv_emulation = 1 builder.argv_emulation = 1
builder.setup() builder.setup()
builder.build() builder.build()
if progress: if progress:
progress.label('Done.') progress.label('Done.')
progress.inc(0) progress.inc(0)
## macostools.touched(dest_fss) ## macostools.touched(dest_fss)
# Copy resources between two resource file descriptors. # Copy resources between two resource file descriptors.
# skip a resource named '__main__' or (if skipowner is set) with ID zero. # skip a resource named '__main__' or (if skipowner is set) with ID zero.
# Also skip resources with a type listed in skiptypes. # Also skip resources with a type listed in skiptypes.
# #
def copyres(input, output, skiptypes, skipowner, progress=None): def copyres(input, output, skiptypes, skipowner, progress=None):
ctor = None ctor = None
alltypes = [] alltypes = []
Res.UseResFile(input) Res.UseResFile(input)
ntypes = Res.Count1Types() ntypes = Res.Count1Types()
progress_type_inc = 50/ntypes progress_type_inc = 50/ntypes
for itype in range(1, 1+ntypes): for itype in range(1, 1+ntypes):
type = Res.Get1IndType(itype) type = Res.Get1IndType(itype)
if type in skiptypes: if type in skiptypes:
continue continue
alltypes.append(type) alltypes.append(type)
nresources = Res.Count1Resources(type) nresources = Res.Count1Resources(type)
progress_cur_inc = progress_type_inc/nresources progress_cur_inc = progress_type_inc/nresources
for ires in range(1, 1+nresources): for ires in range(1, 1+nresources):
res = Res.Get1IndResource(type, ires) res = Res.Get1IndResource(type, ires)
id, type, name = res.GetResInfo() id, type, name = res.GetResInfo()
lcname = string.lower(name) lcname = string.lower(name)
if lcname == OWNERNAME and id == 0: if lcname == OWNERNAME and id == 0:
if skipowner: if skipowner:
continue # Skip this one continue # Skip this one
else: else:
ctor = type ctor = type
size = res.size size = res.size
attrs = res.GetResAttrs() attrs = res.GetResAttrs()
if progress: if progress:
progress.label("Copy %s %d %s"%(type, id, name)) progress.label("Copy %s %d %s"%(type, id, name))
progress.inc(progress_cur_inc) progress.inc(progress_cur_inc)
res.LoadResource() res.LoadResource()
res.DetachResource() res.DetachResource()
Res.UseResFile(output) Res.UseResFile(output)
try: try:
res2 = Res.Get1Resource(type, id) res2 = Res.Get1Resource(type, id)
except MacOS.Error: except MacOS.Error:
res2 = None res2 = None
if res2: if res2:
if progress: if progress:
progress.label("Overwrite %s %d %s"%(type, id, name)) progress.label("Overwrite %s %d %s"%(type, id, name))
progress.inc(0) progress.inc(0)
res2.RemoveResource() res2.RemoveResource()
res.AddResource(type, id, name) res.AddResource(type, id, name)
res.WriteResource() res.WriteResource()
attrs = attrs | res.GetResAttrs() attrs = attrs | res.GetResAttrs()
res.SetResAttrs(attrs) res.SetResAttrs(attrs)
Res.UseResFile(input) Res.UseResFile(input)
return alltypes, ctor return alltypes, ctor
def copyapptree(srctree, dsttree, exceptlist=[], progress=None): def copyapptree(srctree, dsttree, exceptlist=[], progress=None):
names = [] names = []
if os.path.exists(dsttree): if os.path.exists(dsttree):
shutil.rmtree(dsttree) shutil.rmtree(dsttree)
os.mkdir(dsttree) os.mkdir(dsttree)
todo = os.listdir(srctree) todo = os.listdir(srctree)
while todo: while todo:
this, todo = todo[0], todo[1:] this, todo = todo[0], todo[1:]
if this in exceptlist: if this in exceptlist:
continue continue
thispath = os.path.join(srctree, this) thispath = os.path.join(srctree, this)
if os.path.isdir(thispath): if os.path.isdir(thispath):
thiscontent = os.listdir(thispath) thiscontent = os.listdir(thispath)
for t in thiscontent: for t in thiscontent:
todo.append(os.path.join(this, t)) todo.append(os.path.join(this, t))
names.append(this) names.append(this)
for this in names: for this in names:
srcpath = os.path.join(srctree, this) srcpath = os.path.join(srctree, this)
dstpath = os.path.join(dsttree, this) dstpath = os.path.join(dsttree, this)
if os.path.isdir(srcpath): if os.path.isdir(srcpath):
os.mkdir(dstpath) os.mkdir(dstpath)
elif os.path.islink(srcpath): elif os.path.islink(srcpath):
endpoint = os.readlink(srcpath) endpoint = os.readlink(srcpath)
os.symlink(endpoint, dstpath) os.symlink(endpoint, dstpath)
else: else:
if progress: if progress:
progress.label('Copy '+this) progress.label('Copy '+this)
progress.inc(0) progress.inc(0)
shutil.copy2(srcpath, dstpath) shutil.copy2(srcpath, dstpath)
def writepycfile(codeobject, cfile): def writepycfile(codeobject, cfile):
import marshal import marshal
fc = open(cfile, 'wb') fc = open(cfile, 'wb')
fc.write('\0\0\0\0') # MAGIC placeholder, written later fc.write('\0\0\0\0') # MAGIC placeholder, written later
fc.write('\0\0\0\0') # Timestap placeholder, not needed fc.write('\0\0\0\0') # Timestap placeholder, not needed
marshal.dump(codeobject, fc) marshal.dump(codeobject, fc)
fc.flush() fc.flush()
fc.seek(0, 0) fc.seek(0, 0)
fc.write(MAGIC) fc.write(MAGIC)
fc.close() fc.close()

File diff suppressed because it is too large Load Diff

View File

@ -18,167 +18,167 @@ error = "cfm.error"
BUFSIZE = 0x80000 BUFSIZE = 0x80000
def mergecfmfiles(srclist, dst, architecture = 'fat'): def mergecfmfiles(srclist, dst, architecture = 'fat'):
"""Merge all files in srclist into a new file dst. """Merge all files in srclist into a new file dst.
If architecture is given, only code fragments of that type will be used: 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" "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic"
68k code, since it does not use code fragments to begin with. 68k code, since it does not use code fragments to begin with.
If architecture is None, all fragments will be used, enabling FAT binaries. If architecture is None, all fragments will be used, enabling FAT binaries.
""" """
srclist = list(srclist) srclist = list(srclist)
for i in range(len(srclist)): for i in range(len(srclist)):
srclist[i] = Carbon.File.pathname(srclist[i]) srclist[i] = Carbon.File.pathname(srclist[i])
dst = Carbon.File.pathname(dst) dst = Carbon.File.pathname(dst)
dstfile = open(dst, "wb") dstfile = open(dst, "wb")
rf = Res.FSpOpenResFile(dst, 3) rf = Res.FSpOpenResFile(dst, 3)
try: try:
dstcfrg = CfrgResource() dstcfrg = CfrgResource()
for src in srclist: for src in srclist:
srccfrg = CfrgResource(src) srccfrg = CfrgResource(src)
for frag in srccfrg.fragments: for frag in srccfrg.fragments:
if frag.architecture == 'pwpc' and architecture == 'm68k': if frag.architecture == 'pwpc' and architecture == 'm68k':
continue continue
if frag.architecture == 'm68k' and architecture == 'pwpc': if frag.architecture == 'm68k' and architecture == 'pwpc':
continue continue
dstcfrg.append(frag) dstcfrg.append(frag)
frag.copydata(dstfile) frag.copydata(dstfile)
cfrgres = Res.Resource(dstcfrg.build()) cfrgres = Res.Resource(dstcfrg.build())
Res.UseResFile(rf) Res.UseResFile(rf)
cfrgres.AddResource('cfrg', 0, "") cfrgres.AddResource('cfrg', 0, "")
finally: finally:
dstfile.close() dstfile.close()
rf = Res.CloseResFile(rf) rf = Res.CloseResFile(rf)
class CfrgResource: class CfrgResource:
def __init__(self, path = None): def __init__(self, path = None):
self.version = 1 self.version = 1
self.fragments = [] self.fragments = []
self.path = path self.path = path
if path is not None and os.path.exists(path): if path is not None and os.path.exists(path):
currentresref = Res.CurResFile() currentresref = Res.CurResFile()
resref = Res.FSpOpenResFile(path, 1) resref = Res.FSpOpenResFile(path, 1)
Res.UseResFile(resref) Res.UseResFile(resref)
try: try:
try: try:
data = Res.Get1Resource('cfrg', 0).data data = Res.Get1Resource('cfrg', 0).data
except Res.Error: except Res.Error:
raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback
finally: finally:
Res.CloseResFile(resref) Res.CloseResFile(resref)
Res.UseResFile(currentresref) Res.UseResFile(currentresref)
self.parse(data) self.parse(data)
if self.version <> 1: if self.version <> 1:
raise error, "unknown 'cfrg' resource format" raise error, "unknown 'cfrg' resource format"
def parse(self, data): def parse(self, data):
(res1, res2, self.version, (res1, res2, self.version,
res3, res4, res5, res6, res3, res4, res5, res6,
self.memberCount) = struct.unpack("8l", data[:32]) self.memberCount) = struct.unpack("8l", data[:32])
data = data[32:] data = data[32:]
while data: while data:
frag = FragmentDescriptor(self.path, data) frag = FragmentDescriptor(self.path, data)
data = data[frag.memberSize:] data = data[frag.memberSize:]
self.fragments.append(frag) self.fragments.append(frag)
def build(self): def build(self):
self.memberCount = len(self.fragments) self.memberCount = len(self.fragments)
data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount) data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
for frag in self.fragments: for frag in self.fragments:
data = data + frag.build() data = data + frag.build()
return data return data
def append(self, frag): def append(self, frag):
self.fragments.append(frag) self.fragments.append(frag)
class FragmentDescriptor: class FragmentDescriptor:
def __init__(self, path, data = None): def __init__(self, path, data = None):
self.path = path self.path = path
if data is not None: if data is not None:
self.parse(data) self.parse(data)
def parse(self, data): def parse(self, data):
self.architecture = data[:4] self.architecture = data[:4]
( self.updatelevel, ( self.updatelevel,
self.currentVersion, self.currentVersion,
self.oldDefVersion, self.oldDefVersion,
self.stacksize, self.stacksize,
self.applibdir, self.applibdir,
self.fragtype, self.fragtype,
self.where, self.where,
self.offset, self.offset,
self.length, self.length,
self.res1, self.res2, self.res1, self.res2,
self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42]) self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
pname = data[42:self.memberSize] pname = data[42:self.memberSize]
self.name = pname[1:1+ord(pname[0])] self.name = pname[1:1+ord(pname[0])]
def build(self): def build(self):
data = self.architecture data = self.architecture
data = data + struct.pack("4lhBB4l", data = data + struct.pack("4lhBB4l",
self.updatelevel, self.updatelevel,
self.currentVersion, self.currentVersion,
self.oldDefVersion, self.oldDefVersion,
self.stacksize, self.stacksize,
self.applibdir, self.applibdir,
self.fragtype, self.fragtype,
self.where, self.where,
self.offset, self.offset,
self.length, self.length,
self.res1, self.res2) self.res1, self.res2)
self.memberSize = len(data) + 2 + 1 + len(self.name) self.memberSize = len(data) + 2 + 1 + len(self.name)
# pad to 4 byte boundaries # pad to 4 byte boundaries
if self.memberSize % 4: if self.memberSize % 4:
self.memberSize = self.memberSize + 4 - (self.memberSize % 4) self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
data = data + struct.pack("hb", self.memberSize, len(self.name)) data = data + struct.pack("hb", self.memberSize, len(self.name))
data = data + self.name data = data + self.name
data = data + '\000' * (self.memberSize - len(data)) data = data + '\000' * (self.memberSize - len(data))
return data return data
def getfragment(self): def getfragment(self):
if self.where <> 1: if self.where <> 1:
raise error, "can't read fragment, unsupported location" raise error, "can't read fragment, unsupported location"
f = open(self.path, "rb") f = open(self.path, "rb")
f.seek(self.offset) f.seek(self.offset)
if self.length: if self.length:
frag = f.read(self.length) frag = f.read(self.length)
else: else:
frag = f.read() frag = f.read()
f.close() f.close()
return frag return frag
def copydata(self, outfile): def copydata(self, outfile):
if self.where <> 1: if self.where <> 1:
raise error, "can't read fragment, unsupported location" raise error, "can't read fragment, unsupported location"
infile = open(self.path, "rb") infile = open(self.path, "rb")
if self.length == 0: if self.length == 0:
infile.seek(0, 2) infile.seek(0, 2)
self.length = infile.tell() self.length = infile.tell()
# Position input file and record new offset from output file # Position input file and record new offset from output file
infile.seek(self.offset) infile.seek(self.offset)
# pad to 16 byte boundaries # pad to 16 byte boundaries
offset = outfile.tell() offset = outfile.tell()
if offset % 16: if offset % 16:
offset = offset + 16 - (offset % 16) offset = offset + 16 - (offset % 16)
outfile.seek(offset) outfile.seek(offset)
self.offset = offset self.offset = offset
l = self.length l = self.length
while l: while l:
if l > BUFSIZE: if l > BUFSIZE:
outfile.write(infile.read(BUFSIZE)) outfile.write(infile.read(BUFSIZE))
l = l - BUFSIZE l = l - BUFSIZE
else: else:
outfile.write(infile.read(l)) outfile.write(infile.read(l))
l = 0 l = 0
infile.close() infile.close()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,16 +11,16 @@ import macostools
error=icglue.error error=icglue.error
# From ictypes.h: # From ictypes.h:
icPrefNotFoundErr = -666 # preference not found (duh!) icPrefNotFoundErr = -666 # preference not found (duh!)
icPermErr = -667 # cannot set preference icPermErr = -667 # cannot set preference
icPrefDataErr = -668 # problem with preference data icPrefDataErr = -668 # problem with preference data
icInternalErr = -669 # hmm, this is not good icInternalErr = -669 # hmm, this is not good
icTruncatedErr = -670 # more data was present than was returned icTruncatedErr = -670 # more data was present than was returned
icNoMoreWritersErr = -671 # you cannot begin a write session because someone else is already doing it */ 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 icNothingToOverrideErr = -672 # no component for the override component to capture
icNoURLErr = -673 # no URL found icNoURLErr = -673 # no URL found
icConfigNotFoundErr = -674 # no configuration was found icConfigNotFoundErr = -674 # no configuration was found
icConfigInappropriateErr = -675 # incorrect manufacturer code icConfigInappropriateErr = -675 # incorrect manufacturer code
ICattr_no_change = -1 ICattr_no_change = -1
@ -30,240 +30,240 @@ icReadWritePerm = 2
# End of ictypes.h # End of ictypes.h
class ICOpaqueData: class ICOpaqueData:
"""An unparseable IC entry""" """An unparseable IC entry"""
def __init__(self, data): def __init__(self, data):
self.data = data self.data = data
def __repr__(self): def __repr__(self):
return "ICOpaqueData(%s)"%`self.data` return "ICOpaqueData(%s)"%`self.data`
_ICOpaqueDataType=type(ICOpaqueData('')) _ICOpaqueDataType=type(ICOpaqueData(''))
def _decode_default(data, key): def _decode_default(data, key):
if len(data) == 0: if len(data) == 0:
return data return data
if ord(data[0]) == len(data)-1: if ord(data[0]) == len(data)-1:
# Assume Pstring # Assume Pstring
return data[1:] return data[1:]
return ICOpaqueData(data) return ICOpaqueData(data)
def _decode_multistr(data, key): def _decode_multistr(data, key):
numstr = ord(data[0]) << 8 | ord(data[1]) numstr = ord(data[0]) << 8 | ord(data[1])
rv = [] rv = []
ptr = 2 ptr = 2
for i in range(numstr): for i in range(numstr):
strlen = ord(data[ptr]) strlen = ord(data[ptr])
str = data[ptr+1:ptr+strlen+1] str = data[ptr+1:ptr+strlen+1]
rv.append(str) rv.append(str)
ptr = ptr + strlen + 1 ptr = ptr + strlen + 1
return rv return rv
def _decode_fontrecord(data, key): def _decode_fontrecord(data, key):
size = ord(data[0]) << 8 | ord(data[1]) size = ord(data[0]) << 8 | ord(data[1])
face = ord(data[2]) face = ord(data[2])
namelen = ord(data[4]) namelen = ord(data[4])
return size, face, data[5:5+namelen] return size, face, data[5:5+namelen]
def _decode_boolean(data, key): def _decode_boolean(data, key):
return ord(data[0]) return ord(data[0])
def _decode_text(data, key): def _decode_text(data, key):
return data return data
def _decode_charset(data, key): def _decode_charset(data, key):
return data[:256], data[256:] return data[:256], data[256:]
def _decode_appspec(data, key): def _decode_appspec(data, key):
namelen = ord(data[4]) namelen = ord(data[4])
return data[0:4], data[5:5+namelen] return data[0:4], data[5:5+namelen]
def _code_default(data, key): def _code_default(data, key):
return chr(len(data)) + data return chr(len(data)) + data
def _code_multistr(data, key): def _code_multistr(data, key):
numstr = len(data) numstr = len(data)
rv = chr((numstr>>8) & 0xff) + chr(numstr & 0xff) rv = chr((numstr>>8) & 0xff) + chr(numstr & 0xff)
for i in data: for i in data:
rv = rv + _code_default(i) rv = rv + _code_default(i)
return rv return rv
def _code_fontrecord(data, key): def _code_fontrecord(data, key):
size, face, name = data size, face, name = data
return chr((size>>8) & 0xff) + chr(size & 0xff) + chr(face & 0xff) + \ return chr((size>>8) & 0xff) + chr(size & 0xff) + chr(face & 0xff) + \
chr(0) + _code_default(name) chr(0) + _code_default(name)
def _code_boolean(data, key): def _code_boolean(data, key):
print 'XXXX boolean:', `data` print 'XXXX boolean:', `data`
return chr(data) return chr(data)
def _code_text(data, key): def _code_text(data, key):
return data return data
def _code_charset(data, key): def _code_charset(data, key):
return data[0] + data[1] return data[0] + data[1]
def _code_appspec(data, key): def _code_appspec(data, key):
return data[0] + _code_default(data[1]) return data[0] + _code_default(data[1])
_decoder_table = { _decoder_table = {
"ArchieAll" : (_decode_multistr , _code_multistr), "ArchieAll" : (_decode_multistr , _code_multistr),
"UMichAll" : (_decode_multistr , _code_multistr), "UMichAll" : (_decode_multistr , _code_multistr),
"InfoMacAll" : (_decode_multistr , _code_multistr), "InfoMacAll" : (_decode_multistr , _code_multistr),
"ListFont" : (_decode_fontrecord , _code_fontrecord), "ListFont" : (_decode_fontrecord , _code_fontrecord),
"ScreenFont" : (_decode_fontrecord , _code_fontrecord), "ScreenFont" : (_decode_fontrecord , _code_fontrecord),
"PrinterFont" : (_decode_fontrecord , _code_fontrecord), "PrinterFont" : (_decode_fontrecord , _code_fontrecord),
# "DownloadFolder" : (_decode_filespec , _code_filespec), # "DownloadFolder" : (_decode_filespec , _code_filespec),
"Signature": (_decode_text , _code_text), "Signature": (_decode_text , _code_text),
"Plan" : (_decode_text , _code_text), "Plan" : (_decode_text , _code_text),
"MailHeaders" : (_decode_text , _code_text), "MailHeaders" : (_decode_text , _code_text),
"NewsHeaders" : (_decode_text , _code_text), "NewsHeaders" : (_decode_text , _code_text),
# "Mapping" # "Mapping"
"CharacterSet" : (_decode_charset , _code_charset), "CharacterSet" : (_decode_charset , _code_charset),
"Helper\245" : (_decode_appspec , _code_appspec), "Helper\245" : (_decode_appspec , _code_appspec),
# "Services" : (_decode_services, ????), # "Services" : (_decode_services, ????),
"NewMailFlashIcon" : (_decode_boolean , _code_boolean), "NewMailFlashIcon" : (_decode_boolean , _code_boolean),
"NewMailDialog" : (_decode_boolean , _code_boolean), "NewMailDialog" : (_decode_boolean , _code_boolean),
"NewMailPlaySound" : (_decode_boolean , _code_boolean), "NewMailPlaySound" : (_decode_boolean , _code_boolean),
# "WebBackgroundColor" : _decode_color, # "WebBackgroundColor" : _decode_color,
"NoProxyDomains" : (_decode_multistr , _code_multistr), "NoProxyDomains" : (_decode_multistr , _code_multistr),
"UseHTTPProxy" : (_decode_boolean , _code_boolean), "UseHTTPProxy" : (_decode_boolean , _code_boolean),
"UseGopherProxy": (_decode_boolean , _code_boolean), "UseGopherProxy": (_decode_boolean , _code_boolean),
"UseFTPProxy" : (_decode_boolean , _code_boolean), "UseFTPProxy" : (_decode_boolean , _code_boolean),
"UsePassiveFTP" : (_decode_boolean , _code_boolean), "UsePassiveFTP" : (_decode_boolean , _code_boolean),
} }
def _decode(data, key): def _decode(data, key):
if '\245' in key: if '\245' in key:
key2 = key[:string.index(key, '\245')+1] key2 = key[:string.index(key, '\245')+1]
else: else:
key2 = key key2 = key
if _decoder_table.has_key(key2): if _decoder_table.has_key(key2):
decoder = _decoder_table[key2][0] decoder = _decoder_table[key2][0]
else: else:
decoder = _decode_default decoder = _decode_default
return decoder(data, key) return decoder(data, key)
def _code(data, key): def _code(data, key):
if type(data) == _ICOpaqueDataType: if type(data) == _ICOpaqueDataType:
return data.data return data.data
if '\245' in key: if '\245' in key:
key2 = key[:string.index(key, '\245')+1] key2 = key[:string.index(key, '\245')+1]
else: else:
key2 = key key2 = key
if _decoder_table.has_key(key2): if _decoder_table.has_key(key2):
coder = _decoder_table[key2][1] coder = _decoder_table[key2][1]
else: else:
coder = _code_default coder = _code_default
return coder(data, key) return coder(data, key)
class IC: class IC:
def __init__(self, signature='Pyth', ic=None): def __init__(self, signature='Pyth', ic=None):
if ic: if ic:
self.ic = ic self.ic = ic
else: else:
self.ic = icglue.ICStart(signature) self.ic = icglue.ICStart(signature)
if hasattr(self.ic, 'ICFindConfigFile'): if hasattr(self.ic, 'ICFindConfigFile'):
self.ic.ICFindConfigFile() self.ic.ICFindConfigFile()
self.h = Res.Resource('') self.h = Res.Resource('')
def keys(self): def keys(self):
rv = [] rv = []
self.ic.ICBegin(icReadOnlyPerm) self.ic.ICBegin(icReadOnlyPerm)
num = self.ic.ICCountPref() num = self.ic.ICCountPref()
for i in range(num): for i in range(num):
rv.append(self.ic.ICGetIndPref(i+1)) rv.append(self.ic.ICGetIndPref(i+1))
self.ic.ICEnd() self.ic.ICEnd()
return rv return rv
def has_key(self, key): def has_key(self, key):
return self.__contains__(key) return self.__contains__(key)
def __contains__(self, key): def __contains__(self, key):
try: try:
dummy = self.ic.ICFindPrefHandle(key, self.h) dummy = self.ic.ICFindPrefHandle(key, self.h)
except icglue.error: except icglue.error:
return 0 return 0
return 1 return 1
def __getitem__(self, key): def __getitem__(self, key):
attr = self.ic.ICFindPrefHandle(key, self.h) attr = self.ic.ICFindPrefHandle(key, self.h)
return _decode(self.h.data, key) return _decode(self.h.data, key)
def __setitem__(self, key, value): def __setitem__(self, key, value):
value = _code(value, key) value = _code(value, key)
self.ic.ICSetPref(key, ICattr_no_change, value) self.ic.ICSetPref(key, ICattr_no_change, value)
def launchurl(self, url, hint=""): def launchurl(self, url, hint=""):
# Work around a bug in ICLaunchURL: file:/foo does # Work around a bug in ICLaunchURL: file:/foo does
# not work but file:///foo does. # not work but file:///foo does.
if url[:6] == 'file:/' and url[6] != '/': if url[:6] == 'file:/' and url[6] != '/':
url = 'file:///' + url[6:] url = 'file:///' + url[6:]
self.ic.ICLaunchURL(hint, url, 0, len(url)) self.ic.ICLaunchURL(hint, url, 0, len(url))
def parseurl(self, data, start=None, end=None, hint=""): def parseurl(self, data, start=None, end=None, hint=""):
if start == None: if start == None:
selStart = 0 selStart = 0
selEnd = len(data) selEnd = len(data)
else: else:
selStart = selEnd = start selStart = selEnd = start
if end != None: if end != None:
selEnd = end selEnd = end
selStart, selEnd = self.ic.ICParseURL(hint, data, selStart, selEnd, self.h) selStart, selEnd = self.ic.ICParseURL(hint, data, selStart, selEnd, self.h)
return self.h.data, selStart, selEnd return self.h.data, selStart, selEnd
def mapfile(self, file): def mapfile(self, file):
if type(file) != type(''): if type(file) != type(''):
file = file.as_tuple()[2] file = file.as_tuple()[2]
return self.ic.ICMapFilename(file) return self.ic.ICMapFilename(file)
def maptypecreator(self, type, creator, filename=""): def maptypecreator(self, type, creator, filename=""):
return self.ic.ICMapTypeCreator(type, creator, filename) return self.ic.ICMapTypeCreator(type, creator, filename)
def settypecreator(self, file): def settypecreator(self, file):
file = Carbon.File.pathname(file) file = Carbon.File.pathname(file)
record = self.mapfile(os.path.split(file)[1]) record = self.mapfile(os.path.split(file)[1])
MacOS.SetCreatorAndType(file, record[2], record[1]) MacOS.SetCreatorAndType(file, record[2], record[1])
macostools.touched(fss) macostools.touched(fss)
# Convenience routines # Convenience routines
_dft_ic = None _dft_ic = None
def launchurl(url, hint=""): def launchurl(url, hint=""):
global _dft_ic global _dft_ic
if _dft_ic == None: _dft_ic = IC() if _dft_ic == None: _dft_ic = IC()
return _dft_ic.launchurl(url, hint) return _dft_ic.launchurl(url, hint)
def parseurl(data, start=None, end=None, hint=""): def parseurl(data, start=None, end=None, hint=""):
global _dft_ic global _dft_ic
if _dft_ic == None: _dft_ic = IC() if _dft_ic == None: _dft_ic = IC()
return _dft_ic.parseurl(data, start, end, hint) return _dft_ic.parseurl(data, start, end, hint)
def mapfile(filename): def mapfile(filename):
global _dft_ic global _dft_ic
if _dft_ic == None: _dft_ic = IC() if _dft_ic == None: _dft_ic = IC()
return _dft_ic.mapfile(filename) return _dft_ic.mapfile(filename)
def maptypecreator(type, creator, filename=""): def maptypecreator(type, creator, filename=""):
global _dft_ic global _dft_ic
if _dft_ic == None: _dft_ic = IC() if _dft_ic == None: _dft_ic = IC()
return _dft_ic.maptypecreator(type, creator, filename) return _dft_ic.maptypecreator(type, creator, filename)
def settypecreator(file): def settypecreator(file):
global _dft_ic global _dft_ic
if _dft_ic == None: _dft_ic = IC() if _dft_ic == None: _dft_ic = IC()
return _dft_ic.settypecreator(file) return _dft_ic.settypecreator(file)
def _test(): def _test():
ic = IC() ic = IC()
for k in ic.keys(): for k in ic.keys():
try: try:
v = ic[k] v = ic[k]
except error: except error:
v = '????' v = '????'
print k, '\t', v print k, '\t', v
sys.exit(1) sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
_test() _test()

File diff suppressed because it is too large Load Diff

View File

@ -28,25 +28,25 @@ smAllScripts = -3
# Find the epoch conversion for file dates in a way that works on OS9 and OSX # Find the epoch conversion for file dates in a way that works on OS9 and OSX
import time import time
if time.gmtime(0)[0] == 1970: if time.gmtime(0)[0] == 1970:
_EPOCHCONVERT = -((1970-1904)*365 + 17) * (24*60*60) + 0x100000000L _EPOCHCONVERT = -((1970-1904)*365 + 17) * (24*60*60) + 0x100000000L
def _utc2time(utc): def _utc2time(utc):
t = utc[1] + _EPOCHCONVERT t = utc[1] + _EPOCHCONVERT
return int(t) return int(t)
def _time2utc(t): def _time2utc(t):
t = int(t) - _EPOCHCONVERT t = int(t) - _EPOCHCONVERT
if t < -0x7fffffff: if t < -0x7fffffff:
t = t + 0x10000000L t = t + 0x10000000L
return (0, int(t), 0) return (0, int(t), 0)
else: else:
def _utc2time(utc): def _utc2time(utc):
t = utc[1] t = utc[1]
if t < 0: if t < 0:
t = t + 0x100000000L t = t + 0x100000000L
return t return t
def _time2utc(t): def _time2utc(t):
if t > 0x7fffffff: if t > 0x7fffffff:
t = t - 0x100000000L t = t - 0x100000000L
return (0, int(t), 0) return (0, int(t), 0)
# The old name of the error object: # The old name of the error object:
error = Carbon.File.Error error = Carbon.File.Error
@ -56,60 +56,60 @@ error = Carbon.File.Error
# of the method names are subtly different. # of the method names are subtly different.
# #
class FSSpec(Carbon.File.FSSpec): class FSSpec(Carbon.File.FSSpec):
def as_fsref(self): def as_fsref(self):
return FSRef(self) return FSRef(self)
def NewAlias(self, src=None): def NewAlias(self, src=None):
return Alias(Carbon.File.NewAlias(src, self)) return Alias(Carbon.File.NewAlias(src, self))
def GetCreatorType(self): def GetCreatorType(self):
finfo = self.FSpGetFInfo() finfo = self.FSpGetFInfo()
return finfo.Creator, finfo.Type return finfo.Creator, finfo.Type
def SetCreatorType(self, ctor, tp): def SetCreatorType(self, ctor, tp):
finfo = self.FSpGetFInfo() finfo = self.FSpGetFInfo()
finfo.Creator = ctor finfo.Creator = ctor
finfo.Type = tp finfo.Type = tp
self.FSpSetFInfo(finfo) self.FSpSetFInfo(finfo)
def GetFInfo(self): def GetFInfo(self):
return self.FSpGetFInfo() return self.FSpGetFInfo()
def SetFInfo(self, info): def SetFInfo(self, info):
return self.FSpSetFInfo(info) return self.FSpSetFInfo(info)
def GetDates(self): def GetDates(self):
catInfoFlags = kFSCatInfoCreateDate|kFSCatInfoContentMod|kFSCatInfoBackupDate catInfoFlags = kFSCatInfoCreateDate|kFSCatInfoContentMod|kFSCatInfoBackupDate
catinfo, d1, d2, d3 = FSRef(self).FSGetCatalogInfo(catInfoFlags) catinfo, d1, d2, d3 = FSRef(self).FSGetCatalogInfo(catInfoFlags)
cdate = catinfo.createDate cdate = catinfo.createDate
mdate = catinfo.contentModDate mdate = catinfo.contentModDate
bdate = catinfo.backupDate bdate = catinfo.backupDate
return _utc2time(cdate), _utc2time(mdate), _utc2time(bdate) return _utc2time(cdate), _utc2time(mdate), _utc2time(bdate)
def SetDates(self, cdate, mdate, bdate): def SetDates(self, cdate, mdate, bdate):
catInfoFlags = kFSCatInfoCreateDate|kFSCatInfoContentMod|kFSCatInfoBackupDate catInfoFlags = kFSCatInfoCreateDate|kFSCatInfoContentMod|kFSCatInfoBackupDate
catinfo = Carbon.File.FSCatalogInfo( catinfo = Carbon.File.FSCatalogInfo(
createDate = _time2utc(cdate), createDate = _time2utc(cdate),
contentModDate = _time2utc(mdate), contentModDate = _time2utc(mdate),
backupDate = _time2utc(bdate)) backupDate = _time2utc(bdate))
FSRef(self).FSSetCatalogInfo(catInfoFlags, catinfo) FSRef(self).FSSetCatalogInfo(catInfoFlags, catinfo)
class FSRef(Carbon.File.FSRef): class FSRef(Carbon.File.FSRef):
def as_fsspec(self): def as_fsspec(self):
return FSSpec(self) return FSSpec(self)
class Alias(Carbon.File.Alias): class Alias(Carbon.File.Alias):
def GetInfo(self, index): def GetInfo(self, index):
return self.GetAliasInfo(index) return self.GetAliasInfo(index)
def Update(self, *args): def Update(self, *args):
pass # print "Alias.Update not yet implemented" pass # print "Alias.Update not yet implemented"
def Resolve(self, src=None): def Resolve(self, src=None):
fss, changed = self.ResolveAlias(src) fss, changed = self.ResolveAlias(src)
return FSSpec(fss), changed return FSSpec(fss), changed
from Carbon.File import FInfo from Carbon.File import FInfo
# Backward-compatible type names: # Backward-compatible type names:
@ -120,21 +120,21 @@ FInfoType = FInfo
# Global functions: # Global functions:
def ResolveAliasFile(fss, chain=1): def ResolveAliasFile(fss, chain=1):
fss, isdir, isalias = Carbon.File.ResolveAliasFile(fss, chain) fss, isdir, isalias = Carbon.File.ResolveAliasFile(fss, chain)
return FSSpec(fss), isdir, isalias return FSSpec(fss), isdir, isalias
def RawFSSpec(data): def RawFSSpec(data):
return FSSpec(rawdata=data) return FSSpec(rawdata=data)
def RawAlias(data): def RawAlias(data):
return Alias(rawdata=data) return Alias(rawdata=data)
def FindApplication(*args): def FindApplication(*args):
raise NotImplementedError, "FindApplication no longer implemented" raise NotImplementedError, "FindApplication no longer implemented"
def NewAliasMinimalFromFullPath(path): def NewAliasMinimalFromFullPath(path):
return Alias(Carbon.File.NewAliasMinimalFromFullPath(path, '', '')) return Alias(Carbon.File.NewAliasMinimalFromFullPath(path, '', ''))
# Another global function: # Another global function:
from Carbon.Folder import FindFolder from Carbon.Folder import FindFolder
@ -145,54 +145,54 @@ from Carbon.Folder import FindFolder
_curfolder = None _curfolder = None
def StandardGetFile(*typelist): def StandardGetFile(*typelist):
"""Ask for an input file, optionally specifying 4-char file types that are """Ask for an input file, optionally specifying 4-char file types that are
allowable""" allowable"""
return PromptGetFile('', *typelist) return PromptGetFile('', *typelist)
def PromptGetFile(prompt, *typelist): def PromptGetFile(prompt, *typelist):
"""Ask for an input file giving the user a prompt message. Optionally you can """Ask for an input file giving the user a prompt message. Optionally you can
specifying 4-char file types that are allowable""" specifying 4-char file types that are allowable"""
import EasyDialogs import EasyDialogs
warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen", warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
DeprecationWarning, stacklevel=2) DeprecationWarning, stacklevel=2)
if not typelist: if not typelist:
typelist = None typelist = None
fss = EasyDialogs.AskFileForOpen(message=prompt, wanted=FSSpec, fss = EasyDialogs.AskFileForOpen(message=prompt, wanted=FSSpec,
typeList=typelist, defaultLocation=_handleSetFolder()) typeList=typelist, defaultLocation=_handleSetFolder())
return fss, not fss is None return fss, not fss is None
def StandardPutFile(prompt, default=None): def StandardPutFile(prompt, default=None):
"""Ask the user for an output file, with a prompt. Optionally you cn supply a """Ask the user for an output file, with a prompt. Optionally you cn supply a
default output filename""" default output filename"""
import EasyDialogs import EasyDialogs
warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen", warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
DeprecationWarning, stacklevel=2) DeprecationWarning, stacklevel=2)
fss = EasyDialogs.AskFileForSave(wanted=FSSpec, message=prompt, fss = EasyDialogs.AskFileForSave(wanted=FSSpec, message=prompt,
savedFileName=default, defaultLocation=_handleSetFolder()) savedFileName=default, defaultLocation=_handleSetFolder())
return fss, not fss is None return fss, not fss is None
def SetFolder(folder): def SetFolder(folder):
global _curfolder global _curfolder
warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen", warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
DeprecationWarning, stacklevel=2) DeprecationWarning, stacklevel=2)
if _curfolder: if _curfolder:
rv = FSSpec(_curfolder) rv = FSSpec(_curfolder)
else: else:
rv = None rv = None
_curfolder = folder _curfolder = folder
return rv return rv
def _handleSetFolder(): def _handleSetFolder():
global _curfolder global _curfolder
rv = _curfolder rv = _curfolder
_curfolder = None _curfolder = None
return rv return rv
def GetDirectory(prompt=None): def GetDirectory(prompt=None):
"""Ask the user to select a folder. Optionally you can give a prompt.""" """Ask the user to select a folder. Optionally you can give a prompt."""
import EasyDialogs import EasyDialogs
warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen", warnings.warn("macfs.StandardGetFile and friends are deprecated, use EasyDialogs.AskFileForOpen",
DeprecationWarning, stacklevel=2) DeprecationWarning, stacklevel=2)
fss = EasyDialogs.AskFolder(message=prompt, wanted=FSSpec, fss = EasyDialogs.AskFolder(message=prompt, wanted=FSSpec,
defaultLocation=_handleSetFolder()) defaultLocation=_handleSetFolder())
return fss, not fss is None return fss, not fss is None

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -33,29 +33,29 @@ The <date> plist data has (limited) support through the Date class.
Generate Plist example: Generate Plist example:
pl = Plist( pl = Plist(
aString="Doodah", aString="Doodah",
aList=["A", "B", 12, 32.1, [1, 2, 3]], aList=["A", "B", 12, 32.1, [1, 2, 3]],
aFloat = 0.1, aFloat = 0.1,
anInt = 728, anInt = 728,
aDict=Dict( aDict=Dict(
anotherString="<hello & hi there!>", anotherString="<hello & hi there!>",
aUnicodeValue=u'M\xe4ssig, Ma\xdf', aUnicodeValue=u'M\xe4ssig, Ma\xdf',
aTrueValue=True, aTrueValue=True,
aFalseValue=False, aFalseValue=False,
), ),
someData = Data("<binary gunk>"), someData = Data("<binary gunk>"),
someMoreData = Data("<lots of binary gunk>" * 10), someMoreData = Data("<lots of binary gunk>" * 10),
aDate = Date(time.mktime(time.gmtime())), aDate = Date(time.mktime(time.gmtime())),
) )
# unicode keys are possible, but a little awkward to use: # unicode keys are possible, but a little awkward to use:
pl[u'\xc5benraa'] = "That was a unicode key." pl[u'\xc5benraa'] = "That was a unicode key."
pl.write(fileName) pl.write(fileName)
Parse Plist example: Parse Plist example:
pl = Plist.fromFile(pathOrFile) pl = Plist.fromFile(pathOrFile)
print pl.aKey print pl.aKey
""" """
@ -71,40 +71,40 @@ INDENT = "\t"
class DumbXMLWriter: class DumbXMLWriter:
def __init__(self, file): def __init__(self, file):
self.file = file self.file = file
self.stack = [] self.stack = []
self.indentLevel = 0 self.indentLevel = 0
def beginElement(self, element): def beginElement(self, element):
self.stack.append(element) self.stack.append(element)
self.writeln("<%s>" % element) self.writeln("<%s>" % element)
self.indentLevel += 1 self.indentLevel += 1
def endElement(self, element): def endElement(self, element):
assert self.indentLevel > 0 assert self.indentLevel > 0
assert self.stack.pop() == element assert self.stack.pop() == element
self.indentLevel -= 1 self.indentLevel -= 1
self.writeln("</%s>" % element) self.writeln("</%s>" % element)
def simpleElement(self, element, value=None): def simpleElement(self, element, value=None):
if value: if value:
value = _encode(value) value = _encode(value)
self.writeln("<%s>%s</%s>" % (element, value, element)) self.writeln("<%s>%s</%s>" % (element, value, element))
else: else:
self.writeln("<%s/>" % element) self.writeln("<%s/>" % element)
def writeln(self, line): def writeln(self, line):
if line: if line:
self.file.write(self.indentLevel * INDENT + line + "\n") self.file.write(self.indentLevel * INDENT + line + "\n")
else: else:
self.file.write("\n") self.file.write("\n")
def _encode(text): def _encode(text):
text = text.replace("&", "&amp;") text = text.replace("&", "&amp;")
text = text.replace("<", "&lt;") text = text.replace("<", "&lt;")
return text.encode("utf-8") return text.encode("utf-8")
PLISTHEADER = """\ PLISTHEADER = """\
@ -114,323 +114,323 @@ PLISTHEADER = """\
class PlistWriter(DumbXMLWriter): class PlistWriter(DumbXMLWriter):
def __init__(self, file): def __init__(self, file):
file.write(PLISTHEADER) file.write(PLISTHEADER)
DumbXMLWriter.__init__(self, file) DumbXMLWriter.__init__(self, file)
def writeValue(self, value): def writeValue(self, value):
if isinstance(value, (str, unicode)): if isinstance(value, (str, unicode)):
self.simpleElement("string", value) self.simpleElement("string", value)
elif isinstance(value, bool): elif isinstance(value, bool):
# must switch for bool before int, as bool is a # must switch for bool before int, as bool is a
# subclass of int... # subclass of int...
if value: if value:
self.simpleElement("true") self.simpleElement("true")
else: else:
self.simpleElement("false") self.simpleElement("false")
elif isinstance(value, int): elif isinstance(value, int):
self.simpleElement("integer", str(value)) self.simpleElement("integer", str(value))
elif isinstance(value, float): elif isinstance(value, float):
# should perhaps use repr() for better precision? # should perhaps use repr() for better precision?
self.simpleElement("real", str(value)) self.simpleElement("real", str(value))
elif isinstance(value, (dict, Dict)): elif isinstance(value, (dict, Dict)):
self.writeDict(value) self.writeDict(value)
elif isinstance(value, Data): elif isinstance(value, Data):
self.writeData(value) self.writeData(value)
elif isinstance(value, Date): elif isinstance(value, Date):
self.simpleElement("date", value.toString()) self.simpleElement("date", value.toString())
elif isinstance(value, (tuple, list)): elif isinstance(value, (tuple, list)):
self.writeArray(value) self.writeArray(value)
else: else:
assert 0, "unsuported type: %s" % type(value) assert 0, "unsuported type: %s" % type(value)
def writeData(self, data): def writeData(self, data):
self.beginElement("data") self.beginElement("data")
for line in data.asBase64().split("\n"): for line in data.asBase64().split("\n"):
if line: if line:
self.writeln(line) self.writeln(line)
self.endElement("data") self.endElement("data")
def writeDict(self, d): def writeDict(self, d):
self.beginElement("dict") self.beginElement("dict")
items = d.items() items = d.items()
items.sort() items.sort()
for key, value in items: for key, value in items:
assert isinstance(key, (str, unicode)), "keys must be strings" assert isinstance(key, (str, unicode)), "keys must be strings"
self.simpleElement("key", key) self.simpleElement("key", key)
self.writeValue(value) self.writeValue(value)
self.endElement("dict") self.endElement("dict")
def writeArray(self, array): def writeArray(self, array):
self.beginElement("array") self.beginElement("array")
for value in array: for value in array:
self.writeValue(value) self.writeValue(value)
self.endElement("array") self.endElement("array")
class Dict: class Dict:
"""Dict wrapper for convenient access of values through attributes.""" """Dict wrapper for convenient access of values through attributes."""
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
def __cmp__(self, other): def __cmp__(self, other):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return cmp(self.__dict__, other.__dict__) return cmp(self.__dict__, other.__dict__)
elif isinstance(other, dict): elif isinstance(other, dict):
return cmp(self.__dict__, other) return cmp(self.__dict__, other)
else: else:
return cmp(id(self), id(other)) return cmp(id(self), id(other))
def __str__(self): def __str__(self):
return "%s(**%s)" % (self.__class__.__name__, self.__dict__) return "%s(**%s)" % (self.__class__.__name__, self.__dict__)
__repr__ = __str__ __repr__ = __str__
def copy(self): def copy(self):
return self.__class__(**self.__dict__) return self.__class__(**self.__dict__)
def __getattr__(self, attr): def __getattr__(self, attr):
"""Delegate everything else to the dict object.""" """Delegate everything else to the dict object."""
return getattr(self.__dict__, attr) return getattr(self.__dict__, attr)
class Plist(Dict): class Plist(Dict):
"""The main Plist object. Basically a dict (the toplevel object """The main Plist object. Basically a dict (the toplevel object
of a plist is a dict) with two additional methods to read from of a plist is a dict) with two additional methods to read from
and write to files. and write to files.
""" """
def fromFile(cls, pathOrFile): def fromFile(cls, pathOrFile):
didOpen = 0 didOpen = 0
if not hasattr(pathOrFile, "write"): if not hasattr(pathOrFile, "write"):
pathOrFile = open(pathOrFile) pathOrFile = open(pathOrFile)
didOpen = 1 didOpen = 1
p = PlistParser() p = PlistParser()
plist = p.parse(pathOrFile) plist = p.parse(pathOrFile)
if didOpen: if didOpen:
pathOrFile.close() pathOrFile.close()
return plist return plist
fromFile = classmethod(fromFile) fromFile = classmethod(fromFile)
def write(self, pathOrFile): def write(self, pathOrFile):
if not hasattr(pathOrFile, "write"): if not hasattr(pathOrFile, "write"):
pathOrFile = open(pathOrFile, "w") pathOrFile = open(pathOrFile, "w")
didOpen = 1 didOpen = 1
else: else:
didOpen = 0 didOpen = 0
writer = PlistWriter(pathOrFile) writer = PlistWriter(pathOrFile)
writer.writeln("<plist version=\"1.0\">") writer.writeln("<plist version=\"1.0\">")
writer.writeDict(self.__dict__) writer.writeDict(self.__dict__)
writer.writeln("</plist>") writer.writeln("</plist>")
if didOpen: if didOpen:
pathOrFile.close() pathOrFile.close()
class Data: class Data:
"""Wrapper for binary data.""" """Wrapper for binary data."""
def __init__(self, data): def __init__(self, data):
self.data = data self.data = data
def fromBase64(cls, data): def fromBase64(cls, data):
import base64 import base64
return cls(base64.decodestring(data)) return cls(base64.decodestring(data))
fromBase64 = classmethod(fromBase64) fromBase64 = classmethod(fromBase64)
def asBase64(self): def asBase64(self):
import base64 import base64
return base64.encodestring(self.data) return base64.encodestring(self.data)
def __cmp__(self, other): def __cmp__(self, other):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return cmp(self.data, other.data) return cmp(self.data, other.data)
elif isinstance(other, str): elif isinstance(other, str):
return cmp(self.data, other) return cmp(self.data, other)
else: else:
return cmp(id(self), id(other)) return cmp(id(self), id(other))
def __repr__(self): def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.data)) return "%s(%s)" % (self.__class__.__name__, repr(self.data))
class Date: class Date:
"""Primitive date wrapper, uses time floats internally, is agnostic """Primitive date wrapper, uses time floats internally, is agnostic
about time zones. about time zones.
""" """
def __init__(self, date): def __init__(self, date):
if isinstance(date, str): if isinstance(date, str):
from xml.utils.iso8601 import parse from xml.utils.iso8601 import parse
date = parse(date) date = parse(date)
self.date = date self.date = date
def toString(self): def toString(self):
from xml.utils.iso8601 import tostring from xml.utils.iso8601 import tostring
return tostring(self.date) return tostring(self.date)
def __cmp__(self, other): def __cmp__(self, other):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return cmp(self.date, other.date) return cmp(self.date, other.date)
elif isinstance(other, (int, float)): elif isinstance(other, (int, float)):
return cmp(self.date, other) return cmp(self.date, other)
else: else:
return cmp(id(self), id(other)) return cmp(id(self), id(other))
def __repr__(self): def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.toString())) return "%s(%s)" % (self.__class__.__name__, repr(self.toString()))
class PlistParser: class PlistParser:
def __init__(self): def __init__(self):
self.stack = [] self.stack = []
self.currentKey = None self.currentKey = None
self.root = None self.root = None
def parse(self, file): def parse(self, file):
from xml.parsers.expat import ParserCreate from xml.parsers.expat import ParserCreate
parser = ParserCreate() parser = ParserCreate()
parser.StartElementHandler = self.handleBeginElement parser.StartElementHandler = self.handleBeginElement
parser.EndElementHandler = self.handleEndElement parser.EndElementHandler = self.handleEndElement
parser.CharacterDataHandler = self.handleData parser.CharacterDataHandler = self.handleData
parser.ParseFile(file) parser.ParseFile(file)
return self.root return self.root
def handleBeginElement(self, element, attrs): def handleBeginElement(self, element, attrs):
self.data = [] self.data = []
handler = getattr(self, "begin_" + element, None) handler = getattr(self, "begin_" + element, None)
if handler is not None: if handler is not None:
handler(attrs) handler(attrs)
def handleEndElement(self, element): def handleEndElement(self, element):
handler = getattr(self, "end_" + element, None) handler = getattr(self, "end_" + element, None)
if handler is not None: if handler is not None:
handler() handler()
def handleData(self, data): def handleData(self, data):
self.data.append(data) self.data.append(data)
def addObject(self, value): def addObject(self, value):
if self.currentKey is not None: if self.currentKey is not None:
self.stack[-1][self.currentKey] = value self.stack[-1][self.currentKey] = value
self.currentKey = None self.currentKey = None
elif not self.stack: elif not self.stack:
# this is the root object # this is the root object
assert self.root is value assert self.root is value
else: else:
self.stack[-1].append(value) self.stack[-1].append(value)
def getData(self): def getData(self):
data = "".join(self.data) data = "".join(self.data)
try: try:
data = data.encode("ascii") data = data.encode("ascii")
except UnicodeError: except UnicodeError:
pass pass
self.data = [] self.data = []
return data return data
# element handlers # element handlers
def begin_dict(self, attrs): def begin_dict(self, attrs):
if self.root is None: if self.root is None:
self.root = d = Plist() self.root = d = Plist()
else: else:
d = Dict() d = Dict()
self.addObject(d) self.addObject(d)
self.stack.append(d) self.stack.append(d)
def end_dict(self): def end_dict(self):
self.stack.pop() self.stack.pop()
def end_key(self): def end_key(self):
self.currentKey = self.getData() self.currentKey = self.getData()
def begin_array(self, attrs): def begin_array(self, attrs):
a = [] a = []
self.addObject(a) self.addObject(a)
self.stack.append(a) self.stack.append(a)
def end_array(self): def end_array(self):
self.stack.pop() self.stack.pop()
def end_true(self): def end_true(self):
self.addObject(True) self.addObject(True)
def end_false(self): def end_false(self):
self.addObject(False) self.addObject(False)
def end_integer(self): def end_integer(self):
self.addObject(int(self.getData())) self.addObject(int(self.getData()))
def end_real(self): def end_real(self):
self.addObject(float(self.getData())) self.addObject(float(self.getData()))
def end_string(self): def end_string(self):
self.addObject(self.getData()) self.addObject(self.getData())
def end_data(self): def end_data(self):
self.addObject(Data.fromBase64(self.getData())) self.addObject(Data.fromBase64(self.getData()))
def end_date(self): def end_date(self):
self.addObject(Date(self.getData())) self.addObject(Date(self.getData()))
# cruft to support booleans in Python <= 2.3 # cruft to support booleans in Python <= 2.3
import sys import sys
if sys.version_info[:2] < (2, 3): if sys.version_info[:2] < (2, 3):
# Python 2.2 and earlier: no booleans # Python 2.2 and earlier: no booleans
# Python 2.2.x: booleans are ints # Python 2.2.x: booleans are ints
class bool(int): class bool(int):
"""Imitation of the Python 2.3 bool object.""" """Imitation of the Python 2.3 bool object."""
def __new__(cls, value): def __new__(cls, value):
return int.__new__(cls, not not value) return int.__new__(cls, not not value)
def __repr__(self): def __repr__(self):
if self: if self:
return "True" return "True"
else: else:
return "False" return "False"
True = bool(1) True = bool(1)
False = bool(0) False = bool(0)
else: else:
# Bind the boolean builtins to local names # Bind the boolean builtins to local names
True = True True = True
False = False False = False
bool = bool bool = bool
if __name__ == "__main__": if __name__ == "__main__":
from StringIO import StringIO from StringIO import StringIO
import time import time
if len(sys.argv) == 1: if len(sys.argv) == 1:
pl = Plist( pl = Plist(
aString="Doodah", aString="Doodah",
aList=["A", "B", 12, 32.1, [1, 2, 3]], aList=["A", "B", 12, 32.1, [1, 2, 3]],
aFloat = 0.1, aFloat = 0.1,
anInt = 728, anInt = 728,
aDict=Dict( aDict=Dict(
anotherString="<hello & hi there!>", anotherString="<hello & hi there!>",
aUnicodeValue=u'M\xe4ssig, Ma\xdf', aUnicodeValue=u'M\xe4ssig, Ma\xdf',
aTrueValue=True, aTrueValue=True,
aFalseValue=False, aFalseValue=False,
), ),
someData = Data("<binary gunk>"), someData = Data("<binary gunk>"),
someMoreData = Data("<lots of binary gunk>" * 10), someMoreData = Data("<lots of binary gunk>" * 10),
aDate = Date(time.mktime(time.gmtime())), aDate = Date(time.mktime(time.gmtime())),
) )
elif len(sys.argv) == 2: elif len(sys.argv) == 2:
pl = Plist.fromFile(sys.argv[1]) pl = Plist.fromFile(sys.argv[1])
else: else:
print "Too many arguments: at most 1 plist file can be given." print "Too many arguments: at most 1 plist file can be given."
sys.exit(1) sys.exit(1)
# unicode keys are possible, but a little awkward to use: # unicode keys are possible, but a little awkward to use:
pl[u'\xc5benraa'] = "That was a unicode key." pl[u'\xc5benraa'] = "That was a unicode key."
f = StringIO() f = StringIO()
pl.write(f) pl.write(f)
xml = f.getvalue() xml = f.getvalue()
print xml print xml
f.seek(0) f.seek(0)
pl2 = Plist.fromFile(f) pl2 = Plist.fromFile(f)
assert pl == pl2 assert pl == pl2
f = StringIO() f = StringIO()
pl2.write(f) pl2.write(f)
assert xml == f.getvalue() assert xml == f.getvalue()
#print repr(pl2) #print repr(pl2)

View File

@ -13,280 +13,280 @@ from Carbon import Qdoffs
from Carbon import QDOffscreen from Carbon import QDOffscreen
from Carbon import Res from Carbon import Res
try: try:
import MediaDescr import MediaDescr
except ImportError: except ImportError:
def _audiodescr(data): def _audiodescr(data):
return None return None
else: else:
def _audiodescr(data): def _audiodescr(data):
return MediaDescr.SoundDescription.decode(data) return MediaDescr.SoundDescription.decode(data)
try: try:
from imgformat import macrgb from imgformat import macrgb
except ImportError: except ImportError:
macrgb = "Macintosh RGB format" macrgb = "Macintosh RGB format"
import os import os
# import audio.format # import audio.format
class VideoFormat: class VideoFormat:
def __init__(self, name, descr, width, height, format): def __init__(self, name, descr, width, height, format):
self.__name = name self.__name = name
self.__descr = descr self.__descr = descr
self.__width = width self.__width = width
self.__height = height self.__height = height
self.__format = format self.__format = format
def getname(self): def getname(self):
return self.__name return self.__name
def getdescr(self): def getdescr(self):
return self.__descr return self.__descr
def getsize(self): def getsize(self):
return self.__width, self.__height return self.__width, self.__height
def getformat(self): def getformat(self):
return self.__format return self.__format
class _Reader: class _Reader:
def __init__(self, path): def __init__(self, path):
fd = Qt.OpenMovieFile(path, 0) fd = Qt.OpenMovieFile(path, 0)
self.movie, d1, d2 = Qt.NewMovieFromFile(fd, 0, 0) self.movie, d1, d2 = Qt.NewMovieFromFile(fd, 0, 0)
self.movietimescale = self.movie.GetMovieTimeScale() self.movietimescale = self.movie.GetMovieTimeScale()
try: try:
self.audiotrack = self.movie.GetMovieIndTrackType(1, self.audiotrack = self.movie.GetMovieIndTrackType(1,
QuickTime.AudioMediaCharacteristic, QuickTime.movieTrackCharacteristic) QuickTime.AudioMediaCharacteristic, QuickTime.movieTrackCharacteristic)
self.audiomedia = self.audiotrack.GetTrackMedia() self.audiomedia = self.audiotrack.GetTrackMedia()
except Qt.Error: except Qt.Error:
self.audiotrack = self.audiomedia = None self.audiotrack = self.audiomedia = None
self.audiodescr = {} self.audiodescr = {}
else: else:
handle = Res.Handle('') handle = Res.Handle('')
n = self.audiomedia.GetMediaSampleDescriptionCount() n = self.audiomedia.GetMediaSampleDescriptionCount()
self.audiomedia.GetMediaSampleDescription(1, handle) self.audiomedia.GetMediaSampleDescription(1, handle)
self.audiodescr = _audiodescr(handle.data) self.audiodescr = _audiodescr(handle.data)
self.audiotimescale = self.audiomedia.GetMediaTimeScale() self.audiotimescale = self.audiomedia.GetMediaTimeScale()
del handle del handle
try: try:
self.videotrack = self.movie.GetMovieIndTrackType(1, self.videotrack = self.movie.GetMovieIndTrackType(1,
QuickTime.VisualMediaCharacteristic, QuickTime.movieTrackCharacteristic) QuickTime.VisualMediaCharacteristic, QuickTime.movieTrackCharacteristic)
self.videomedia = self.videotrack.GetTrackMedia() self.videomedia = self.videotrack.GetTrackMedia()
except Qt.Error: except Qt.Error:
self.videotrack = self.videomedia = self.videotimescale = None self.videotrack = self.videomedia = self.videotimescale = None
if self.videotrack: if self.videotrack:
self.videotimescale = self.videomedia.GetMediaTimeScale() self.videotimescale = self.videomedia.GetMediaTimeScale()
x0, y0, x1, y1 = self.movie.GetMovieBox() x0, y0, x1, y1 = self.movie.GetMovieBox()
self.videodescr = {'width':(x1-x0), 'height':(y1-y0)} self.videodescr = {'width':(x1-x0), 'height':(y1-y0)}
self._initgworld() self._initgworld()
self.videocurtime = None self.videocurtime = None
self.audiocurtime = None self.audiocurtime = None
def __del__(self): def __del__(self):
self.audiomedia = None self.audiomedia = None
self.audiotrack = None self.audiotrack = None
self.videomedia = None self.videomedia = None
self.videotrack = None self.videotrack = None
self.movie = None self.movie = None
def _initgworld(self): def _initgworld(self):
old_port, old_dev = Qdoffs.GetGWorld() old_port, old_dev = Qdoffs.GetGWorld()
try: try:
movie_w = self.videodescr['width'] movie_w = self.videodescr['width']
movie_h = self.videodescr['height'] movie_h = self.videodescr['height']
movie_rect = (0, 0, movie_w, movie_h) movie_rect = (0, 0, movie_w, movie_h)
self.gworld = Qdoffs.NewGWorld(32, movie_rect, None, None, QDOffscreen.keepLocal) self.gworld = Qdoffs.NewGWorld(32, movie_rect, None, None, QDOffscreen.keepLocal)
self.pixmap = self.gworld.GetGWorldPixMap() self.pixmap = self.gworld.GetGWorldPixMap()
Qdoffs.LockPixels(self.pixmap) Qdoffs.LockPixels(self.pixmap)
Qdoffs.SetGWorld(self.gworld.as_GrafPtr(), None) Qdoffs.SetGWorld(self.gworld.as_GrafPtr(), None)
Qd.EraseRect(movie_rect) Qd.EraseRect(movie_rect)
self.movie.SetMovieGWorld(self.gworld.as_GrafPtr(), None) self.movie.SetMovieGWorld(self.gworld.as_GrafPtr(), None)
self.movie.SetMovieBox(movie_rect) self.movie.SetMovieBox(movie_rect)
self.movie.SetMovieActive(1) self.movie.SetMovieActive(1)
self.movie.MoviesTask(0) self.movie.MoviesTask(0)
self.movie.SetMoviePlayHints(QuickTime.hintsHighQuality, QuickTime.hintsHighQuality) self.movie.SetMoviePlayHints(QuickTime.hintsHighQuality, QuickTime.hintsHighQuality)
# XXXX framerate # XXXX framerate
finally: finally:
Qdoffs.SetGWorld(old_port, old_dev) Qdoffs.SetGWorld(old_port, old_dev)
def _gettrackduration_ms(self, track): def _gettrackduration_ms(self, track):
tracktime = track.GetTrackDuration() tracktime = track.GetTrackDuration()
return self._movietime_to_ms(tracktime) return self._movietime_to_ms(tracktime)
def _movietime_to_ms(self, time): def _movietime_to_ms(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.movietimescale, None), 1000) value, d1, d2 = Qt.ConvertTimeScale((time, self.movietimescale, None), 1000)
return value return value
def _videotime_to_ms(self, time): def _videotime_to_ms(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), 1000) value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), 1000)
return value return value
def _audiotime_to_ms(self, time): def _audiotime_to_ms(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.audiotimescale, None), 1000) value, d1, d2 = Qt.ConvertTimeScale((time, self.audiotimescale, None), 1000)
return value return value
def _videotime_to_movietime(self, time): def _videotime_to_movietime(self, time):
value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None), value, d1, d2 = Qt.ConvertTimeScale((time, self.videotimescale, None),
self.movietimescale) self.movietimescale)
return value return value
def HasAudio(self): def HasAudio(self):
return not self.audiotrack is None return not self.audiotrack is None
def HasVideo(self): def HasVideo(self):
return not self.videotrack is None return not self.videotrack is None
def GetAudioDuration(self): def GetAudioDuration(self):
if not self.audiotrack: if not self.audiotrack:
return 0 return 0
return self._gettrackduration_ms(self.audiotrack) return self._gettrackduration_ms(self.audiotrack)
def GetVideoDuration(self): def GetVideoDuration(self):
if not self.videotrack: if not self.videotrack:
return 0 return 0
return self._gettrackduration_ms(self.videotrack) return self._gettrackduration_ms(self.videotrack)
def GetAudioFormat(self): def GetAudioFormat(self):
if not self.audiodescr: if not self.audiodescr:
return None, None, None, None, None return None, None, None, None, None
bps = self.audiodescr['sampleSize'] bps = self.audiodescr['sampleSize']
nch = self.audiodescr['numChannels'] nch = self.audiodescr['numChannels']
if nch == 1: if nch == 1:
channels = ['mono'] channels = ['mono']
elif nch == 2: elif nch == 2:
channels = ['left', 'right'] channels = ['left', 'right']
else: else:
channels = map(lambda x: str(x+1), range(nch)) channels = map(lambda x: str(x+1), range(nch))
if bps % 8: if bps % 8:
# Funny bits-per sample. We pretend not to understand # Funny bits-per sample. We pretend not to understand
blocksize = 0 blocksize = 0
fpb = 0 fpb = 0
else: else:
# QuickTime is easy (for as far as we support it): samples are always a whole # 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. # number of bytes, so frames are nchannels*samplesize, and there's one frame per block.
blocksize = (bps/8)*nch blocksize = (bps/8)*nch
fpb = 1 fpb = 1
if self.audiodescr['dataFormat'] == 'raw ': if self.audiodescr['dataFormat'] == 'raw ':
encoding = 'linear-excess' encoding = 'linear-excess'
elif self.audiodescr['dataFormat'] == 'twos': elif self.audiodescr['dataFormat'] == 'twos':
encoding = 'linear-signed' encoding = 'linear-signed'
else: else:
encoding = 'quicktime-coding-%s'%self.audiodescr['dataFormat'] encoding = 'quicktime-coding-%s'%self.audiodescr['dataFormat']
## return audio.format.AudioFormatLinear('quicktime_audio', 'QuickTime Audio Format', ## return audio.format.AudioFormatLinear('quicktime_audio', 'QuickTime Audio Format',
## channels, encoding, blocksize=blocksize, fpb=fpb, bps=bps) ## channels, encoding, blocksize=blocksize, fpb=fpb, bps=bps)
return channels, encoding, blocksize, fpb, bps return channels, encoding, blocksize, fpb, bps
def GetAudioFrameRate(self): def GetAudioFrameRate(self):
if not self.audiodescr: if not self.audiodescr:
return None return None
return int(self.audiodescr['sampleRate']) return int(self.audiodescr['sampleRate'])
def GetVideoFormat(self): def GetVideoFormat(self):
width = self.videodescr['width'] width = self.videodescr['width']
height = self.videodescr['height'] height = self.videodescr['height']
return VideoFormat('dummy_format', 'Dummy Video Format', width, height, macrgb) return VideoFormat('dummy_format', 'Dummy Video Format', width, height, macrgb)
def GetVideoFrameRate(self): def GetVideoFrameRate(self):
tv = self.videocurtime tv = self.videocurtime
if tv == None: if tv == None:
tv = 0 tv = 0
flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
tv, dur = self.videomedia.GetMediaNextInterestingTime(flags, tv, 1.0) tv, dur = self.videomedia.GetMediaNextInterestingTime(flags, tv, 1.0)
dur = self._videotime_to_ms(dur) dur = self._videotime_to_ms(dur)
return int((1000.0/dur)+0.5) return int((1000.0/dur)+0.5)
def ReadAudio(self, nframes, time=None): def ReadAudio(self, nframes, time=None):
if not time is None: if not time is None:
self.audiocurtime = time self.audiocurtime = time
flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK flags = QuickTime.nextTimeStep|QuickTime.nextTimeEdgeOK
if self.audiocurtime == None: if self.audiocurtime == None:
self.audiocurtime = 0 self.audiocurtime = 0
tv = self.audiomedia.GetMediaNextInterestingTimeOnly(flags, self.audiocurtime, 1.0) tv = self.audiomedia.GetMediaNextInterestingTimeOnly(flags, self.audiocurtime, 1.0)
if tv < 0 or (self.audiocurtime and tv < self.audiocurtime): if tv < 0 or (self.audiocurtime and tv < self.audiocurtime):
return self._audiotime_to_ms(self.audiocurtime), None return self._audiotime_to_ms(self.audiocurtime), None
h = Res.Handle('') h = Res.Handle('')
desc_h = Res.Handle('') desc_h = Res.Handle('')
size, actualtime, sampleduration, desc_index, actualcount, flags = \ size, actualtime, sampleduration, desc_index, actualcount, flags = \
self.audiomedia.GetMediaSample(h, 0, tv, desc_h, nframes) self.audiomedia.GetMediaSample(h, 0, tv, desc_h, nframes)
self.audiocurtime = actualtime + actualcount*sampleduration self.audiocurtime = actualtime + actualcount*sampleduration
return self._audiotime_to_ms(actualtime), h.data return self._audiotime_to_ms(actualtime), h.data
def ReadVideo(self, time=None): def ReadVideo(self, time=None):
if not time is None: if not time is None:
self.videocurtime = time self.videocurtime = time
flags = QuickTime.nextTimeStep flags = QuickTime.nextTimeStep
if self.videocurtime == None: if self.videocurtime == None:
flags = flags | QuickTime.nextTimeEdgeOK flags = flags | QuickTime.nextTimeEdgeOK
self.videocurtime = 0 self.videocurtime = 0
tv = self.videomedia.GetMediaNextInterestingTimeOnly(flags, self.videocurtime, 1.0) tv = self.videomedia.GetMediaNextInterestingTimeOnly(flags, self.videocurtime, 1.0)
if tv < 0 or (self.videocurtime and tv <= self.videocurtime): if tv < 0 or (self.videocurtime and tv <= self.videocurtime):
return self._videotime_to_ms(self.videocurtime), None return self._videotime_to_ms(self.videocurtime), None
self.videocurtime = tv self.videocurtime = tv
moviecurtime = self._videotime_to_movietime(self.videocurtime) moviecurtime = self._videotime_to_movietime(self.videocurtime)
self.movie.SetMovieTimeValue(moviecurtime) self.movie.SetMovieTimeValue(moviecurtime)
self.movie.MoviesTask(0) self.movie.MoviesTask(0)
return self._videotime_to_ms(self.videocurtime), self._getpixmapcontent() return self._videotime_to_ms(self.videocurtime), self._getpixmapcontent()
def _getpixmapcontent(self): def _getpixmapcontent(self):
"""Shuffle the offscreen PixMap data, because it may have funny stride values""" """Shuffle the offscreen PixMap data, because it may have funny stride values"""
rowbytes = Qdoffs.GetPixRowBytes(self.pixmap) rowbytes = Qdoffs.GetPixRowBytes(self.pixmap)
width = self.videodescr['width'] width = self.videodescr['width']
height = self.videodescr['height'] height = self.videodescr['height']
start = 0 start = 0
rv = '' rv = ''
for i in range(height): for i in range(height):
nextline = Qdoffs.GetPixMapBytes(self.pixmap, start, width*4) nextline = Qdoffs.GetPixMapBytes(self.pixmap, start, width*4)
start = start + rowbytes start = start + rowbytes
rv = rv + nextline rv = rv + nextline
return rv return rv
def reader(url): def reader(url):
try: try:
rdr = _Reader(url) rdr = _Reader(url)
except IOError: except IOError:
return None return None
return rdr return rdr
def _test(): def _test():
import EasyDialogs import EasyDialogs
try: try:
import img import img
except ImportError: except ImportError:
img = None img = None
import MacOS import MacOS
Qt.EnterMovies() Qt.EnterMovies()
path = EasyDialogs.AskFileForOpen(message='Video to convert') path = EasyDialogs.AskFileForOpen(message='Video to convert')
if not path: sys.exit(0) if not path: sys.exit(0)
rdr = reader(path) rdr = reader(path)
if not rdr: if not rdr:
sys.exit(1) sys.exit(1)
dstdir = EasyDialogs.AskFileForSave(message='Name for output folder') dstdir = EasyDialogs.AskFileForSave(message='Name for output folder')
if not dstdir: sys.exit(0) if not dstdir: sys.exit(0)
num = 0 num = 0
os.mkdir(dstdir) os.mkdir(dstdir)
videofmt = rdr.GetVideoFormat() videofmt = rdr.GetVideoFormat()
imgfmt = videofmt.getformat() imgfmt = videofmt.getformat()
imgw, imgh = videofmt.getsize() imgw, imgh = videofmt.getsize()
timestamp, data = rdr.ReadVideo() timestamp, data = rdr.ReadVideo()
while data: while data:
fname = 'frame%04.4d.jpg'%num fname = 'frame%04.4d.jpg'%num
num = num+1 num = num+1
pname = os.path.join(dstdir, fname) pname = os.path.join(dstdir, fname)
if not img: print 'Not', if not img: print 'Not',
print 'Writing %s, size %dx%d, %d bytes'%(fname, imgw, imgh, len(data)) print 'Writing %s, size %dx%d, %d bytes'%(fname, imgw, imgh, len(data))
if img: if img:
wrt = img.writer(imgfmt, pname) wrt = img.writer(imgfmt, pname)
wrt.width = imgw wrt.width = imgw
wrt.height = imgh wrt.height = imgh
wrt.write(data) wrt.write(data)
timestamp, data = rdr.ReadVideo() timestamp, data = rdr.ReadVideo()
MacOS.SetCreatorAndType(pname, 'ogle', 'JPEG') MacOS.SetCreatorAndType(pname, 'ogle', 'JPEG')
if num > 20: if num > 20:
print 'stopping at 20 frames so your disk does not fill up:-)' print 'stopping at 20 frames so your disk does not fill up:-)'
break break
print 'Total frames:', num print 'Total frames:', num
if __name__ == '__main__': if __name__ == '__main__':
_test() _test()
sys.exit(1) sys.exit(1)