Ejemplo n.º 1
0
	def packlong(self, val):
		if (-2**31) <= val < (2**31): # pack as typeSInt32 if possible (non-lossy)
			return newdesc(kae.typeSInt32, struct.pack('i', val))
		elif (-2**63) <= val < (2**63): # else pack as typeSInt64 if possible (non-lossy)
			return newdesc(kae.typeSInt64, struct.pack('q', val))
		else: # else pack as typeFloat (lossy)
			return self.pack(float(val))
Ejemplo n.º 2
0
	def packlong(self, val):
		if (-2**31) <= val < (2**31): # pack as typeSInt32 if possible (non-lossy)
			return newdesc(kae.typeSInt32, struct.pack('i', val))
		elif (-2**63) <= val < (2**63): # else pack as typeSInt64 if possible (non-lossy)
			return newdesc(kae.typeSInt64, struct.pack('q', val))
		else: # else pack as typeFloat (lossy)
			return self.pack(float(val))
Ejemplo n.º 3
0
 def makewithurl(klass, url):
     """Make File object from file URL."""
     obj = klass(_kNoPath)
     obj._desc = newdesc(kae.typeFileURL, url)
     obj._url = url
     obj._path = converturltopath(url, kCFURLPOSIXPathStyle)
     return obj
Ejemplo n.º 4
0
	def makewithurl(klass, url):
		"""Make File object from file URL."""
		obj = klass(_kNoPath)
		obj._desc = newdesc(kae.typeFileURL, url)
		obj._url = url
		obj._path = converturltopath(url, kCFURLPOSIXPathStyle)
		return obj
Ejemplo n.º 5
0
def processexistsforurl(url):
	"""Does an application process specified by the given eppc:// URL exist?
		Note: this will send a 'launch' Apple event to the target application.
	"""
	if ':' not in url: # workaround: process will crash if no colon in URL (OS bug)
		raise ValueError("Invalid url: %r" % url)
	return processexistsfordesc(ae.newdesc(kae.typeApplicationURL, url))
Ejemplo n.º 6
0
def processexistsforurl(url):
    """Does an application process specified by the given eppc:// URL exist?
		Note: this will send a 'launch' Apple event to the target application.
	"""
    if ':' not in url:  # workaround: process will crash if no colon in URL (OS bug)
        raise ValueError("Invalid url: %r" % url)
    return processexistsfordesc(ae.newdesc(kae.typeApplicationURL, url))
Ejemplo n.º 7
0
def remoteapp(url):
	"""Make an AEAddressDesc identifying a running application on another machine.
		url : string -- URL for remote application, e.g. 'eppc://*****:*****@0.0.0.1/TextEdit'
		Result : AEAddressDesc
	"""
	if ':' not in url: # workaround: process will crash if no colon in URL (OS bug)
		raise ValueError("Invalid url: %r" % url)
	return ae.newdesc(kae.typeApplicationURL, url)
Ejemplo n.º 8
0
	def __init__(self, path):
		"""Make File object from POSIX path."""
		if path is not _kNoPath:
			if not isinstance(path, unicode):
				path = unicode(path)
			self._path = abspath(path)
			self._url = convertpathtourl(self._path, kCFURLPOSIXPathStyle)
			self._desc = newdesc(kae.typeFileURL, self._url)
Ejemplo n.º 9
0
def remoteapp(url):
    """Make an AEAddressDesc identifying a running application on another machine.
		url : string -- URL for remote application, e.g. 'eppc://*****:*****@0.0.0.1/TextEdit'
		Result : AEAddressDesc
	"""
    if ':' not in url:  # workaround: process will crash if no colon in URL (OS bug)
        raise ValueError("Invalid url: %r" % url)
    return ae.newdesc(kae.typeApplicationURL, url)
Ejemplo n.º 10
0
 def __init__(self, path):
     """Make File object from POSIX path."""
     if path is not _kNoPath:
         if not isinstance(path, unicode):
             path = unicode(path)
         self._path = abspath(path)
         self._url = convertpathtourl(self._path, kCFURLPOSIXPathStyle)
         self._desc = newdesc(kae.typeFileURL, self._url)
Ejemplo n.º 11
0
	def packunicodetext(self, val):
		# Note: optional BOM is omitted as this causes problems with stupid apps like iTunes 7 that don't
		# handle BOMs correctly; note: while typeUnicodeText is not recommended as of OS 10.4, it's still
		# being used rather than typeUTF8Text or typeUTF16ExternalRepresentation to provide compatibility
		#with not-so-well-designed applications that may have problems with these newer types.
		data = val.encode(nativeutf16encoding)
		if data.startswith(BOM_UTF16_LE) or data.startswith(BOM_UTF16_BE):
			data = data[2:]
		return newdesc(kae.typeUnicodeText, data)
Ejemplo n.º 12
0
	def packunicodetext(self, val):
		# Note: optional BOM is omitted as this causes problems with stupid apps like iTunes 7 that don't
		# handle BOMs correctly; note: while typeUnicodeText is not recommended as of OS 10.4, it's still
		# being used rather than typeUTF8Text or typeUTF16ExternalRepresentation to provide compatibility
		#with not-so-well-designed applications that may have problems with these newer types.
		data = val.encode(nativeutf16encoding)
		if data.startswith(BOM_UTF16_LE) or data.startswith(BOM_UTF16_BE):
			data = data[2:]
		return newdesc(kae.typeUnicodeText, data)
Ejemplo n.º 13
0
	def __init__(self, path):
		"""Make Alias object from POSIX path."""
		if path is _kNoPath:
			self._desc = None
		else:
			urldesc = newdesc(kae.typeFileURL, 
					convertpathtourl(abspath(path), kCFURLPOSIXPathStyle))
			try:
				self._desc = urldesc.coerce(kae.typeAlias)
			except MacOSError, err:
				if err.args[0] == -1700:
					raise ValueError("Can't make mactypes.Alias as file doesn't exist: %r" % path)
				else:
					raise
Ejemplo n.º 14
0
 def __init__(self, path):
     """Make Alias object from POSIX path."""
     if path is _kNoPath:
         self._desc = None
     else:
         urldesc = newdesc(
             kae.typeFileURL,
             convertpathtourl(abspath(path), kCFURLPOSIXPathStyle))
         try:
             self._desc = urldesc.coerce(kae.typeAlias)
         except MacOSError, err:
             if err.args[0] == -1700:
                 raise ValueError(
                     "Can't make mactypes.Alias as file doesn't exist: %r" %
                     path)
             else:
                 raise
Ejemplo n.º 15
0
def localappbypid(pid):
	"""Make an AEAddressDesc identifying a local process.
		pid : integer -- Unix process id
		Result : AEAddressDesc
	"""
	return ae.newdesc(kae.typeKernelProcessID, struct.pack('i', pid))
Ejemplo n.º 16
0
kLSLaunchDontAddToRecents = 0x00000100
kLSLaunchDontSwitch = 0x00000200
kLSLaunchNoParams = 0x00000800
kLSLaunchAsync = 0x00010000
kLSLaunchStartClassic = 0x00020000
kLSLaunchInClassic = 0x00040000
kLSLaunchNewInstance = 0x00080000
kLSLaunchAndHide = 0x00100000
kLSLaunchAndHideOthers = 0x00200000
kLSLaunchHasUntrustedContents = 0x00400000


_kNoProcess = 0
_kCurrentProcess = 2

_nulladdressdesc = ae.newdesc(kae.typeProcessSerialNumber, struct.pack('II', 0, _kNoProcess)) # ae.newappleevent complains if you pass None as address, so we give it one to throw away

_launchevent = Event(_nulladdressdesc, 'ascrnoop').AEM_event
_runevent = Event(_nulladdressdesc, 'aevtoapp').AEM_event

#######

def _launchapplication(path, event, newinstance=False, hide=False):
	flags = kLSLaunchNoParams | kLSLaunchStartClassic | kLSLaunchDontSwitch
	if newinstance:
		flags |= kLSLaunchNewInstance
	if hide:
		flags |= kLSLaunchAndHide
	try:
		return ae.launchapplication(path, event, flags)
	except ae.MacOSError, err:
Ejemplo n.º 17
0
	def packkey(self, val): 
		return newdesc(kae.typeKeyword, fourcharcode(val.code))
Ejemplo n.º 18
0
def localappbypid(pid):
    """Make an AEAddressDesc identifying a local process.
		pid : integer -- Unix process id
		Result : AEAddressDesc
	"""
    return ae.newdesc(kae.typeKernelProcessID, struct.pack('i', pid))
Ejemplo n.º 19
0
	def packfloat(self, val):
		return newdesc(kae.typeFloat, struct.pack('d', val))
Ejemplo n.º 20
0
	def _defaultpacker(self, units, code): 
		return newdesc(code, struct.pack('d', units.value))
Ejemplo n.º 21
0
	def packprop(self, val): 
		return newdesc(kae.typeProperty, fourcharcode(val.code))
Ejemplo n.º 22
0
 def makewithurl(klass, url):
     """Make File object from file URL."""
     obj = klass(_kNoPath)
     obj._desc = newdesc(kae.typeFileURL, url).coerce(kae.typeAlias)
     return obj
Ejemplo n.º 23
0
 def desc(self):
     if self._desc is None:
         self._desc = newdesc(kae.typeFileURL, self.url)
     return self._desc
Ejemplo n.º 24
0
	def packabsoluteordinal(code): 
		return ae.newdesc(kae.typeAbsoluteOrdinal, code[::-1])
Ejemplo n.º 25
0
class ObjectBeingExamined(ReferenceRoot):
	"""Form: its
		Reference base; represents an element to be tested. Used to construct by-filter references.
	"""
	_kName = 'its'
	_kType = ae.newdesc(kae.typeObjectBeingExamined, '')
Ejemplo n.º 26
0
    'remoteapp', 'CantLaunchApplicationError'
]

######################################################################
# PRIVATE
######################################################################

_kLaunchContinue = 0x4000
_kLaunchNoFileFlags = 0x0800
_kLaunchDontSwitch = 0x0200

_kNoProcess = 0
_kCurrentProcess = 2

_nulladdressdesc = ae.newdesc(
    kae.typeProcessSerialNumber, struct.pack('LL', 0, _kNoProcess)
)  # ae.newappleevent complains if you pass None as address, so we give it one to throw away

_launchevent = Event(_nulladdressdesc, 'ascrnoop').AEM_event
_runevent = Event(_nulladdressdesc, 'aevtoapp').AEM_event

#######


def _launchapplication(path, event):
    try:
        return ae.launchapplication(
            path, event,
            _kLaunchContinue + _kLaunchNoFileFlags + _kLaunchDontSwitch)
    except ae.MacOSError, err:
        raise CantLaunchApplicationError(err.args[0], path)
Ejemplo n.º 27
0
class CurrentContainer(ReferenceRoot):
	"""Form: con
		Reference base; represents elements' container object. Used to construct by-range references.
	"""
	_kName = 'con'
	_kType = ae.newdesc(kae.typeCurrentContainer, '')
Ejemplo n.º 28
0
	def packenum(self, val): 
		return newdesc(kae.typeEnumeration, fourcharcode(val.code))
Ejemplo n.º 29
0
class Codecs(object):
	"""Convert between Python and Apple event data types.
	Clients may add additional encoders/decoders and/or subclass to suit their needs.
	"""
	
	# Constants
	
	kNullDesc = newdesc(kae.typeNull, '')
	kMacEpoch = datetime.datetime(1904, 1, 1) # used in packing datetime objects as AEDesc typeLongDateTime
	kMacEpochT = time.mktime(kMacEpoch.timetuple())
	kShortMacEpoch = kMacEpoch.date() # used in packing date objects as AEDesc typeLongDateTime

	kTrueDesc = newdesc(kae.typeTrue, '')
	kFalseDesc = newdesc(kae.typeFalse, '')
	
	#######
	# tables to map AE codes to aem method names
	
	kInsertionLocSelectors = {
			fourcharcode(kae.kAEBefore): 'before', 
			fourcharcode(kae.kAEAfter): 'after', 
			fourcharcode(kae.kAEBeginning): 'beginning', 
			fourcharcode(kae.kAEEnd): 'end'
	}
	
	kTypeCompDescriptorOperators = {
			fourcharcode(kae.kAEGreaterThan): 'gt',
			fourcharcode(kae.kAEGreaterThanEquals): 'ge',
			fourcharcode(kae.kAEEquals): 'eq',
			fourcharcode(kae.kAELessThan): 'lt',
			fourcharcode(kae.kAELessThanEquals): 'le',
			fourcharcode(kae.kAEBeginsWith): 'beginswith',
			fourcharcode(kae.kAEEndsWith): 'endswith',
			fourcharcode(kae.kAEContains): 'contains'
	}
	
	kTypeLogicalDescriptorOperators = {
			fourcharcode(kae.kAEAND): 'AND',
			fourcharcode(kae.kAEOR): 'OR',
			fourcharcode(kae.kAENOT): 'NOT'
	}
	
	
	###################################
	
	
	def __init__(self):
		# Clients may add/remove/replace encoder and decoder items:
		self.encoders = {
				AEDesc: self.packdesc,
				type(None): self.packnone,
				bool: self.packbool,
				int: self.packint,
				long: self.packlong,
				float: self.packfloat,
				
				str: self.packstr,
				unicode: self.packunicodetext, 
				
				list: self.packlist,
				tuple: self.packlist,
				dict: self.packdict,
				datetime.date: self.packdate,
				datetime.datetime: self.packdatetime,
				datetime.time: self.packtime,
				time.struct_time: self.packstructtime,
				
				mactypes.Alias: self.packalias,
				mactypes.File: self.packfile,
				
				AEType: self.packtype,
				AEEnum: self.packenum,
				AEProp: self.packprop,
				AEKey: self.packkey,
		}
		
		self. decoders = {
				kae.typeNull: self.unpacknull,
				kae.typeBoolean: self.unpackboolean,
				kae.typeFalse: self.unpackfalse,
				kae.typeTrue: self.unpacktrue,
				kae.typeSInt16: self.unpacksint16,
				kae.typeUInt16: self.unpackuint16,
				kae.typeSInt32: self.unpacksint32,
				kae.typeUInt32: self.unpackuint32,
				kae.typeSInt64: self.unpacksint64,
				kae.typeUInt64: self.unpackuint64,
				kae.typeIEEE32BitFloatingPoint: self.unpackfloat32,
				kae.typeIEEE64BitFloatingPoint: self.unpackfloat64,
				kae.type128BitFloatingPoint: self.unpackfloat128,
				
				kae.typeChar: self.unpackchar,
				kae.typeIntlText: self.unpackintltext,
				kae.typeUTF8Text: self.unpackutf8text,
				kae.typeUTF16ExternalRepresentation: self.unpackutf16externalrepresentation,
				kae.typeStyledText: self.unpackstyledtext,
				kae.typeUnicodeText: self.unpackunicodetext,
				
				kae.typeLongDateTime: self.unpacklongdatetime,
				kae.typeAEList: self.unpackaelist,
				kae.typeAERecord: self.unpackaerecord,
				kae.typeVersion: self.unpackversion,
				
				kae.typeAlias: self.unpackalias,
				kae.typeFSS: self.unpackfss,
				kae.typeFSRef: self.unpackfsref,
				kae.typeFileURL: self.unpackfileurl,
				
				kae.typeQDPoint: self.unpackqdpoint,
				kae.typeQDRectangle: self.unpackqdrect, 
				kae.typeRGBColor: self.unpackrgbcolor,
				
				kae.typeType: self.unpacktype,
				kae.typeEnumeration: self.unpackenumeration,
				kae.typeProperty: self.unpackproperty,
				kae.typeKeyword: self.unpackkeyword,
				
				kae.typeInsertionLoc: self.unpackinsertionloc,
				kae.typeObjectSpecifier: self.unpackobjectspecifier,
				kae.typeAbsoluteOrdinal: self.unpackabsoluteordinal,
				kae.typeCompDescriptor: self.unpackcompdescriptor,
				kae.typeLogicalDescriptor: self.unpacklogicaldescriptor,
				kae.typeRangeDescriptor: self.unpackrangedescriptor,
				
				kae.typeCurrentContainer: lambda desc: self.con,
				kae.typeObjectBeingExamined: lambda desc: self.its,
		}

		self._unittypecodecs = UnitTypeCodecs()
	
	
	###################################
	# compatibility options
	
	def addunittypes(self, typedefs):
		"""Register custom unit type definitions with this Codecs instance
			e.g. Adobe apps define additional unit types (ciceros, pixels, etc.)
		"""
		self._unittypecodecs.addtypes(typedefs)
	
	def dontcacheunpackedspecifiers(self):
		""" When unpacking object specifiers, unlike AppleScript, appscript caches
			the original AEDesc for efficiency, allowing the resulting reference to
			be re-packed much more quickly. Occasionally this causes compatibility
			problems with applications that returned subtly malformed specifiers.
			To force a Codecs object to fully unpack and repack object specifiers,
			call its dontcacheunpackedspecifiers method.
		"""
		self.unpackobjectspecifier = self.fullyunpackobjectspecifier
	
	
	###################################
	
	def packunknown(self, data):
		"""Clients may override this to provide additional packers."""
		raise TypeError("Can't pack data into an AEDesc (unsupported type): %r" % data)
	
	def unpackunknown(self, desc):
		"""Clients may override this to provide additional unpackers."""
		if desc.isrecord():
			rec = desc.coerce('reco')
			rec.setparam('pcls', self.pack(AEType(desc.type)))
			decoder = self.decoders.get('reco')
			if decoder:
				return decoder(rec)
			else:
				return rec
		else:
			return desc
	
	##
	
	def pack(self, data):
		"""Pack Python data.
			data : anything -- a Python value
			Result : aem.ae.AEDesc -- an Apple event descriptor, or error if no encoder exists for this type of data
		"""
		if isinstance(data, aemreference.Query):
			return data.AEM_packself(self)
		else:
			try:
				return self.encoders[data.__class__](data) # quick lookup by type/class
			except (KeyError, AttributeError):
				for type, encoder in self.encoders.items(): # slower but more thorough lookup that can handle subtypes/subclasses
					if isinstance(data, type):
						return encoder(data)
				didpack, desc = self._unittypecodecs.pack(data)
				if didpack:
					return desc
				else:
					self.packunknown(data)
	
	def unpack(self, desc):
		"""Unpack an Apple event descriptor.
			desc : aem.ae.AEDesc -- an Apple event descriptor
			Result : anything -- a Python value, or the AEDesc object if no decoder is found
		"""
		decoder = self.decoders.get(desc.type)
		if decoder:
			return decoder(desc)
		else:
			didunpack, val = self._unittypecodecs.unpack(desc)
			if didunpack:
				return val
			else:
				return self.unpackunknown(desc)
	
	
	###################################
	
	def packdesc(self, val):
		return val
	
	def packnone(self, val):
		return self.kNullDesc
	
	def packbool(self, val):
		return val and self.kTrueDesc or self.kFalseDesc
	
	def packlong(self, val):
		if (-2**31) <= val < (2**31): # pack as typeSInt32 if possible (non-lossy)
			return newdesc(kae.typeSInt32, struct.pack('i', val))
		elif (-2**63) <= val < (2**63): # else pack as typeSInt64 if possible (non-lossy)
			return newdesc(kae.typeSInt64, struct.pack('q', val))
		else: # else pack as typeFloat (lossy)
			return self.pack(float(val))
	
	packint = packlong # note: Python int = C long, so may need to pack as typeSInt64 on 64-bit
	
	def packfloat(self, val):
		return newdesc(kae.typeFloat, struct.pack('d', val))
	
	##
	
	def packunicodetext(self, val):
		# Note: optional BOM is omitted as this causes problems with stupid apps like iTunes 7 that don't
		# handle BOMs correctly; note: while typeUnicodeText is not recommended as of OS 10.4, it's still
		# being used rather than typeUTF8Text or typeUTF16ExternalRepresentation to provide compatibility
		#with not-so-well-designed applications that may have problems with these newer types.
		data = val.encode(nativeutf16encoding)
		if data.startswith(BOM_UTF16_LE) or data.startswith(BOM_UTF16_BE):
			data = data[2:]
		return newdesc(kae.typeUnicodeText, data)
	
	def packstr(self, val):
		return newdesc(kae.typeChar, val)
	
	##
	
	def packdate(self, val):
		delta = val - self.kShortMacEpoch
		sec = delta.days * 3600 * 24 + delta.seconds
		return newdesc(kae.typeLongDateTime, struct.pack('q', sec))
	
	def packdatetime(self, val):
		delta = val - self.kMacEpoch
		sec = delta.days * 3600 * 24 + delta.seconds
		return newdesc(kae.typeLongDateTime, struct.pack('q', sec))
	
	def packtime(self, val):
		return self.packdatetime(datetime.datetime.combine(datetime.date.today(), val))
	
	def packstructtime(self, val):
		sec = int(time.mktime(val) - self.kMacEpochT)
		return newdesc(kae.typeLongDateTime, struct.pack('q', sec))
	
	def packalias(self, val):
		return val.desc
	packfile = packalias
	
	##
	
	def packlist(self, val):
		lst = newlist()
		for item in val:
			lst.setitem(0, self.pack(item))
		return lst
	
	def packdict(self, val):
		record = newrecord()
		usrf = None
		for key, value in val.items():
			if isinstance(key, (AEType, AEProp)):
				if key.code == 'pcls': # AS packs records that contain a 'class' property by coercing the packed record to that type at the end
					try:
						record = record.coerce(value.code)
					except:
						record.setparam(key.code, self.pack(value))
				else:
					record.setparam(key.code, self.pack(value))
			else:
				if not usrf:
					usrf = newlist()
				usrf.setitem(0, self.pack(key))
				usrf.setitem(0, self.pack(value))
		if usrf:
			record.setparam('usrf', usrf)
		return record
	
	##
	
	def packtype(self, val):
		return newdesc(kae.typeType, fourcharcode(val.code))
	
	def packenum(self, val): 
		return newdesc(kae.typeEnumeration, fourcharcode(val.code))
	
	def packprop(self, val): 
		return newdesc(kae.typeProperty, fourcharcode(val.code))
	
	def packkey(self, val): 
		return newdesc(kae.typeKeyword, fourcharcode(val.code))

	
	###################################
	# unpack
	
	def unpacknull(self, desc):
		return None
	
	def unpackboolean(self, desc):
		return desc.data != '\x00'
	
	def unpacktrue(self, desc):
		return True
	
	def unpackfalse(self, desc):
		return False
	
	def unpacksint16(self, desc):
		return struct.unpack('h', desc.data)[0]
	
	def unpackuint16(self, desc):
		return struct.unpack('H', desc.data)[0]
	
	def unpacksint32(self, desc):
		return struct.unpack('i', desc.data)[0]
	
	def unpackuint32(self, desc):
		return struct.unpack('I', desc.data)[0]
	
	def unpacksint64(self, desc):
		return struct.unpack('q', desc.data)[0]
	
	def unpackuint64(self, desc):
		return struct.unpack('Q', desc.data)[0]
	
	def unpackfloat32(self, desc):
		return struct.unpack('f', desc.data)[0]
	
	def unpackfloat64(self, desc):
		return struct.unpack('d', desc.data)[0]
	
	def unpackfloat128(self, desc):
		return struct.unpack('d', desc.coerce(kae.typeIEEE64BitFloatingPoint).data)[0]

	##
	
	def unpackchar(self, desc):
		return desc.data
	
	def unpackintltext(self, desc):
		return self.unpackunicodetext(desc.coerce(kae.typeUnicodeText))
	
	def unpackutf8text(self, desc):
		return unicode(desc.data, 'utf8')
	
	def unpackstyledtext(self, desc):
		return self.unpackunicodetext(desc.coerce(kae.typeUnicodeText))
	
	def unpackunicodetext(self, desc):
		# typeUnicodeText = native endian UTF16 with optional BOM
		data = desc.data
		if data.startswith(BOM_UTF16_BE):
			return unicode(data, 'UTF-16BE')
		elif data.startswith(BOM_UTF16_LE):
			return unicode(data, 'UTF-16LE')
		else:
			return unicode(data, nativeutf16encoding)
	
	def unpackutf16externalrepresentation(self, desc): 
		# type UTF16ExternalRepresentation = big-endian UTF16 with optional byte-order-mark 
		# OR little-endian UTF16 with required byte-order-mark
		if desc.data.startswith(BOM_UTF16_LE):
			return unicode(desc.data, 'UTF-16LE')
		else:
			return unicode(desc.data, 'UTF-16BE')
	
	##
	
	def unpacklongdatetime(self, desc):
		return self.kMacEpoch + datetime.timedelta(seconds=struct.unpack('q', desc.data)[0])
	
	def unpackqdpoint(self, desc): 
		x, y = struct.unpack('hh', desc.data)
		return (y, x)
	
	def unpackqdrect(self, desc):
		x1, y1, x2, y2 = struct.unpack('hhhh', desc.data)
		return (y1, x1, y2, x2)
	
	def unpackrgbcolor(self, desc):
		return struct.unpack('HHH', desc.data)
	
	def unpackversion(self, desc):
		# Cocoa apps use unicode strings for version numbers, so return as string for consistency
		try:
			return self.unpack(desc.coerce(kae.typeUnicodeText)) # supported in 10.4+
		except:
			return '%i.%i.%i' % ((ord(desc.data[0]),) + divmod(ord(desc.data[1]), 16)) # note: always big-endian
	
	##
	
	def unpackalias(self, desc):
		return mactypes.Alias.makewithdesc(desc)
		
	def unpackfileurl(self, desc):
		return mactypes.File.makewithdesc(desc)
	unpackfsref = unpackfss = unpackfileurl
	
	##
	
	def unpackaelist(self, desc):
		# Unpack list and its values.
		return [self.unpack(desc.getitem(i + 1, kae.typeWildCard)[1]) for i in range(desc.count())]
	
	def unpackaerecord(self, desc):
		# Unpack record to dict, converting keys from 4-letter codes to AEType instances and unpacking values.
		dct = {}
		for i in range(desc.count()):
			key, value = desc.getitem(i + 1, kae.typeWildCard)
			if key == 'usrf':
				lst = self.unpackaelist(value)
				for i in range(0, len(lst), 2):
					dct[lst[i]] = lst[i+1]
			else:
				dct[AEType(key)] = self.unpack(value)
		return dct

	##
	
	def unpacktype(self, desc):
		return AEType(fourcharcode(desc.data))
	
	def unpackenumeration(self, desc):
		return AEEnum(fourcharcode(desc.data))
	
	def unpackproperty(self, desc):
		return AEProp(fourcharcode(desc.data))
	
	def unpackkeyword(self, desc):
		return AEKey(fourcharcode(desc.data))
					
	##
	
	def fullyunpackobjectspecifier(self, desc):
		# This function performs a full recursive unpacking of object specifiers, reconstructing an 'app'/'con'/'its' based aem reference from the ground up.
		want = self.unpack(desc.getparam(kae.keyAEDesiredClass, kae.typeType)).code # 4-letter code indicating element class
		keyform = self.unpack(desc.getparam(kae.keyAEKeyForm, kae.typeEnumeration)).code # 4-letter code indicating Specifier type
		key = self.unpack(desc.getparam(kae.keyAEKeyData, kae.typeWildCard)) # value indicating which object(s) to select
		ref = self.unpack(desc.getparam(kae.keyAEContainer, kae.typeWildCard)) # recursively unpack container structure
		if not isinstance(ref, aemreference.Query):
			if ref is None:
				ref = self.app
			else:
				ref = self.customroot(ref)
		# print(want, keyform, key, ref) # DEBUG
		if keyform == kae.formPropertyID: # property specifier
			return ref.property(key.code)
		elif keyform == 'usrp': # user-defined property specifier
			return ref.userproperty(key)
		elif keyform == kae.formRelativePosition: # relative element specifier
			if key.code == kae.kAEPrevious:
				return ref.previous(want)
			elif key.code == kae.kAENext:
				return ref.next(want)
			else:
				raise ValueError("Bad relative position selector: %r" % want)
		else: # other element(s) specifier
			ref = ref.elements(want)
			if keyform == kae.formName:
				return ref.byname(key)
			elif keyform == kae.formAbsolutePosition:
				if isinstance(key, _Ordinal):
					if key.code == kae.kAEAll:
						return ref
					else:
						return getattr(ref, {kae.kAEFirst: 'first', kae.kAELast: 'last', kae.kAEMiddle: 'middle', kae.kAEAny: 'any'}[key.code])
				else:
					return ref.byindex(key)
			elif keyform == kae.formUniqueID:
				return ref.byid(key)
			elif keyform == kae.formRange:
				return ref.byrange(*key.range)
			elif keyform == kae.formTest:
				return ref.byfilter(key)
		raise TypeError
	
	
	def unpackobjectspecifier(self, desc):
		# This function performance-optimises the unpacking of some object specifiers by only doing a shallow unpack where only the topmost descriptor is unpacked.
		# The container AEDesc is retained as-is, allowing a full recursive unpack to be performed later on only if needed (e.g. if the __repr__ method is called).
		# For simplicity, only the commonly encountered forms are optimised this way; forms that are rarely returned by applications (e.g. typeRange) are always fully unpacked.
		keyform = self.unpack(desc.getparam(kae.keyAEKeyForm, kae.typeEnumeration)).code
		if keyform in [kae.formPropertyID, kae.formAbsolutePosition, kae.formName, kae.formUniqueID]:
			want = self.unpack(desc.getparam(kae.keyAEDesiredClass, kae.typeType)).code # 4-letter code indicating element class
			key = self.unpack(desc.getparam(kae.keyAEKeyData, kae.typeWildCard)) # value indicating which object(s) to select
			container = aemreference.DeferredSpecifier(desc.getparam(kae.keyAEContainer, kae.typeWildCard), self)
			if keyform == kae.formPropertyID:
				ref = aemreference.Property(want, container, key.code)
			elif keyform == kae.formAbsolutePosition:
				if isinstance(key, _Ordinal):
					if key.code == kae.kAEAll:
						ref = aemreference.AllElements(want, container)
					else:
						keyname = {kae.kAEFirst: 'first', kae.kAELast: 'last', kae.kAEMiddle: 'middle', kae.kAEAny: 'any'}[key.code]
						ref = aemreference.ElementByOrdinal(want, aemreference.UnkeyedElements(want, container), key, keyname)
				else:
					ref = aemreference.ElementByIndex(want, aemreference.UnkeyedElements(want, container), key)
			elif keyform == kae.formName:
				ref = aemreference.ElementByName(want, aemreference.UnkeyedElements(want, container), key)
			elif keyform == kae.formUniqueID:
				ref = aemreference.ElementByID(want, aemreference.UnkeyedElements(want, container), key)
			ref.AEM_packself = lambda codecs:desc
			return ref
		else: # do full unpack of more complex, rarely returned reference forms
			return self.fullyunpackobjectspecifier(desc)
	
	
	def unpackinsertionloc(self, desc):
		return getattr(self.fullyunpackobjectspecifier(desc.getparam(kae.keyAEObject, kae.typeWildCard)), 
				self.kInsertionLocSelectors[desc.getparam(kae.keyAEPosition, kae.typeEnumeration).data])
	
	
	def unpackcompdescriptor(self, desc):
		operator = self.kTypeCompDescriptorOperators[desc.getparam(kae.keyAECompOperator, kae.typeEnumeration).data]
		op1 = self.unpack(desc.getparam(kae.keyAEObject1, kae.typeWildCard))
		op2 = self.unpack(desc.getparam(kae.keyAEObject2, kae.typeWildCard))
		if operator == 'contains':
			if isinstance(op1, aemreference.Query) and op1.AEM_root() == aemreference.its:
				return op1.contains(op2)
			else:
				return op2.isin(op1)
		return getattr(op1, operator)(op2)
	
	
	def unpacklogicaldescriptor(self, desc):
		operator = self.kTypeLogicalDescriptorOperators[desc.getparam(kae.keyAELogicalOperator, kae.typeEnumeration).data]
		operands = self.unpack(desc.getparam(kae.keyAELogicalTerms, kae.typeAEList))
		return operator == 'NOT' and operands[0].NOT or getattr(operands[0], operator)(*operands[1:])
	
	def unpackrangedescriptor(self, desc):
		return _Range([self.unpack(desc.getparam(kae.keyAERangeStart, kae.typeWildCard)), 
				self.unpack(desc.getparam(kae.keyAERangeStop, kae.typeWildCard))])
	
	
	def unpackabsoluteordinal(self, desc):
		return _Ordinal(fourcharcode(desc.data))
	
	##
	
	app = aemreference.app
	con = aemreference.con
	its = aemreference.its
	customroot = aemreference.customroot
Ejemplo n.º 30
0
	def packkey(self, val): 
		return newdesc(kae.typeKeyword, fourcharcode(val.code))
Ejemplo n.º 31
0
	def packstr(self, val):
		return newdesc(kae.typeChar, val)
Ejemplo n.º 32
0
	def packstructtime(self, val):
		sec = int(time.mktime(val) - self.kMacEpochT)
		return newdesc(kae.typeLongDateTime, struct.pack('q', sec))
Ejemplo n.º 33
0
	def packenum(self, val): 
		return newdesc(kae.typeEnumeration, fourcharcode(val.code))
Ejemplo n.º 34
0
	def packtype(code):
		return ae.newdesc(kae.typeType, code[::-1])
Ejemplo n.º 35
0
	def packenum(code):
		return ae.newdesc(kae.typeEnumeration, code[::-1])
Ejemplo n.º 36
0
	def packdatetime(self, val):
		delta = val - self.kMacEpoch
		sec = delta.days * 3600 * 24 + delta.seconds
		return newdesc(kae.typeLongDateTime, struct.pack('q', sec))
Ejemplo n.º 37
0
	def packfloat(self, val):
		return newdesc(kae.typeFloat, struct.pack('d', val))
Ejemplo n.º 38
0
	def packtype(self, val):
		return newdesc(kae.typeType, fourcharcode(val.code))
Ejemplo n.º 39
0
	def makewithurl(klass, url):
		"""Make File object from file URL."""
		obj = klass(_kNoPath)
		obj._desc = newdesc(kae.typeFileURL, url).coerce(kae.typeAlias)
		return obj
Ejemplo n.º 40
0
	def packprop(self, val): 
		return newdesc(kae.typeProperty, fourcharcode(val.code))
Ejemplo n.º 41
0
	def packstr(self, val):
		return newdesc(kae.typeChar, val)
Ejemplo n.º 42
0
	def _defaultpacker(self, units, code): 
		return newdesc(code, struct.pack('d', units.value))
Ejemplo n.º 43
0
	def packdatetime(self, val):
		delta = val - self.kMacEpoch
		sec = delta.days * 3600 * 24 + delta.seconds
		return newdesc(kae.typeLongDateTime, struct.pack('q', sec))
Ejemplo n.º 44
0
	def desc(self):
		if self._desc is None:
			self._desc = newdesc(kae.typeFileURL, self.url)
		return self._desc
Ejemplo n.º 45
0
	def packstructtime(self, val):
		sec = int(time.mktime(val) - self.kMacEpochT)
		return newdesc(kae.typeLongDateTime, struct.pack('q', sec))
Ejemplo n.º 46
0
	def packtype(self, val):
		return newdesc(kae.typeType, fourcharcode(val.code))
Ejemplo n.º 47
0
class ApplicationRoot(ReferenceRoot):
	"""Form: app
		Reference base; represents an application's application object. Used to construct full references.
	"""
	_kName = 'app'
	_kType = ae.newdesc(kae.typeNull, '')