[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