[Pythonmac-SIG] obtaining versions of application bundles
brad.allen at omsdal.com
brad.allen at omsdal.com
Fri Oct 22 22:40:58 CEST 2004
> Yeah, Carbon is annoying.. It would look something like this:
Well, I don't know if this will be useful to you, but I did get permission
to publicly post code from our project. Below is Walker's VersionResource
module. This approach reads from the 'vers' resource, not the 'plst'
resource. The 'plst' resource is easier to parse, I guess. Can we expect it
to be present in every CFM app?
# File: VersionResource.py
#
# Contains: Class that exposes the information stored in Mac OS
Classic
# version resources.
#
# Version: Technology: Python 2.2
# Group: sequence
# Tag: $Name: $ <== explicit checkout
#
# $Author: walker $ <== last changed by
# $Date$
# $Revision$
# $Source$
#
# Copyright: 2004 by Omnicom Management Services, all rights reserved
"""Class that exposes the information stored in Mac OS Classic
version resources.
"""
from Carbon import File as F # File Manager
from Carbon import Files as Fs # File Manager constants
from Carbon import Res as R # Resource Manager
#fPath = 'Documents/test_resource'
def getVersionResourceData(fPath):
"""
Given a file path, return the binary data for the pair of version
resources.
For historical reasons, a Mac OS Classic file with version info will
contain two version resources. Both resources have resource type
'vers'.
One has an ID of 1 and the other has an ID of 2. Normally, the
contents of
the two resources are identical up to the string data. In resource 1,
the
string data contains the short and long versions as strings. (The
long
string usually contains a copyright.) In resource 2, the string data
contains information about the set that contains this file. Older
files may
not contain the second resource. Some files may contain identical
resources.
<http://developer.apple.com/documentation/mac/Toolbox/Toolbox-454.html>
The result is a pair (tuple) of strings or None if the file doesn't
contain
the matching resource. In most cases, this tuple is sufficient to
compare
the version info between two files with version resources.
Will throw exceptions if the file doesn't exist or doesn't contain a
resource
fork.
"""
spec = F.FSSpec(fPath)
num = R.FSpOpenResFile(spec, Fs.fsRdPerm) # file reference number
assert R.CurResFile() == num
try:
h1 = R.Get1IndResource('vers', 1)
result1 = h1.data[:] # make a copy
del(h1)
except:
result1 = None
try:
h2 = R.Get1IndResource('vers', 2)
result2 = h2.data[:] # make a copy
del(h2)
except:
result2 = None
R.CloseResFile(num)
return (result1, result2)
def bcd2Decimal(char):
"""
Given a char of a single byte of binary data, convert from BCD.
BCD is binary coded decimal -- where you 'spell out' a decimal
number using hex digits. Four bits --> one decimal digit.
"""
bcd = ord(char)
high = bcd / 16
low = bcd % 16
return high * 10 + low
class VersResource(object):
"""
A parsed form of the raw vers resource data.
A vers resource has the following format (see TechNote 1132
<http://developer.apple.com/technotes/tn/tn1132.html>):
type 'vers' {
hex byte; /* Major revision in BCD*/
hex byte; /* Minor revision in BCD*/
hex byte development = 0x20, /* Release stage */
alpha = 0x40,
beta = 0x60,
final = 0x80, /* or */ release = 0x80;
hex byte; /* Non-final release # */
integer; /* Region code */
pstring; /* Short version number */
pstring; /* Long version number */
};
"""
__slots__ = 'major', 'minor', 'stage', 'buildNum', 'regionCode', \
'shortStr', 'longStr', 'raw'
def __init__(self, rawData):
self.major = bcd2Decimal(rawData[0])
self.minor = bcd2Decimal(rawData[1])
self.stage = ord(rawData[2]) / 32 # final --> 4, beta -->
3, etc.
self.buildNum = ord(rawData[3]) # == 0 for released products
self.regionCode = ord(rawData[4]) * 256 + ord(rawData[5])
len1 = ord(rawData[6])
self.shortStr = rawData[7:7+len1]
len2 = ord(rawData[7+len1])
self.longStr = rawData[8+len1:8+len1+len2]
self.raw = rawData
def __eq__(self, other):
return (self.raw == other.raw)
def __str__(self):
if self.stage == 1:
stage = 'd'
elif self.stage == 2:
stage = 'a'
elif self.stage == 3:
stage = 'b'
else:
stage = ''
if self.buildNum > 0:
build = str(self.buildNum)
else:
build = ''
return '%d.%d%s%s; %s; %s' % \
(self.major, self.minor, stage, build, self.shortStr,
self.longStr)
def getVersionResourceStrings(fPath):
"""
Given a file path, return the parsed data for the pair of version
resources.
For historical reasons, a Mac OS Classic file with version info will
contain two version resources. Both resources have resource type
'vers'.
One has an ID of 1 and the other has an ID of 2. Normally, the
contents of
the two resources are identical up to the string data. In resource 1,
the
string data contains the short and long versions as strings. (The
long
string usually contains a copyright.) In resource 2, the string data
contains information about the set that contains this file. Older
files may
not contain the second resource. Some files may contain identical
resources.
<http://developer.apple.com/documentation/mac/Toolbox/Toolbox-454.html>
The result is a pair (tuple) of strings or None if the file doesn't
contain
the matching resource.
Will throw exceptions if the file doesn't exist or doesn't contain a
resource
fork.
"""
data1, data2 = getVersionResourceData(fPath)
if data1 is None:
str1 = None
else:
v1 = VersResource(data1)
str1 = str(v1)
if data2 is None:
str2 = None
else:
v2 = VersResource(data2)
str2 = str(v2)
return (str1, str2)
# Change Record
#
# $Log$
More information about the Pythonmac-SIG
mailing list