macresource.py 4.99 KB
Newer Older
1 2 3 4 5
"""macresource - Locate and open the resources needed for a script."""

from Carbon import Res
import os
import sys
6 7
import MacOS
import macostools
8 9 10 11 12

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

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

Jack Jansen's avatar
Jack Jansen committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    if modname is None and filename is None:
        raise ArgumentError, "Either filename or modname argument (or both) must be given"
    
    if type(resid) is type(1):
        try:
            h = Res.GetResource(restype, resid)
        except Res.Error:
            pass
        else:
            return None
    else:
        try:
            h = Res.GetNamedResource(restype, resid)
        except Res.Error:
            pass
        else:
            return None
            
    # Construct a filename if we don't have one
    if not filename:
        if '.' in modname:
            filename = modname.split('.')[-1] + '.rsrc'
        else:
            filename = modname + '.rsrc'
    
    # Now create a list of folders to search
    searchdirs = []
    if modname == '__main__':
        # If we're main we look in the current directory
        searchdirs = [os.curdir]
    if sys.modules.has_key(modname):
        mod = sys.modules[modname]
        if hasattr(mod, '__file__'):
            searchdirs = [os.path.dirname(mod.__file__)]
    searchdirs.extend(sys.path)
    
    # And look for the file
    for dir in searchdirs:
        pathname = os.path.join(dir, filename)
        if os.path.exists(pathname):
            break
    else:
        raise ResourceFileNotFoundError, filename
    
    refno = open_pathname(pathname)
    
    # And check that the resource exists now
    if type(resid) is type(1):
        h = Res.GetResource(restype, resid)
    else:
        h = Res.GetNamedResource(restype, resid)
    return refno
    
74
def open_pathname(pathname, verbose=0):
Jack Jansen's avatar
Jack Jansen committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    """Open a resource file given by pathname, possibly decoding an
    AppleSingle file"""
    try:
        refno = Res.FSpOpenResFile(pathname, 1)
    except Res.Error, arg:
        if arg[0] in (-37, -39):
            # No resource fork. We may be on OSX, and this may be either
            # a data-fork based resource file or a AppleSingle file
            # from the CVS repository.
            try:
                refno = Res.FSOpenResourceFile(pathname, u'', 1)
            except Res.Error, arg:
                if arg[0] != -199:
                    # -199 is "bad resource map"
                    raise
            else:
                return refno
            # Finally try decoding an AppleSingle file
            pathname = _decode(pathname, verbose=verbose)
            refno = Res.FSOpenResourceFile(pathname, u'', 1)
        else:
            raise
    return refno
    
99
def resource_pathname(pathname, verbose=0):
Jack Jansen's avatar
Jack Jansen committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    """Return the pathname for a resource file (either DF or RF based).
    If the pathname given already refers to such a file simply return it,
    otherwise first decode it."""
    try:
        refno = Res.FSpOpenResFile(pathname, 1)
        Res.CloseResFile(refno)
    except Res.Error, arg:
        if arg[0] in (-37, -39):
            # No resource fork. We may be on OSX, and this may be either
            # a data-fork based resource file or a AppleSingle file
            # from the CVS repository.
            try:
                refno = Res.FSOpenResourceFile(pathname, u'', 1)
            except Res.Error, arg:
                if arg[0] != -199:
                    # -199 is "bad resource map"
                    raise
            else:
                return refno
            # Finally try decoding an AppleSingle file
            pathname = _decode(pathname, verbose=verbose)
        else:
            raise
    return pathname
    
125
def open_error_resource():
Jack Jansen's avatar
Jack Jansen committed
126 127 128 129
    """Open the resource file containing the error code to error message
    mapping."""
    need('Estr', 1, filename="errors.rsrc", modname=__name__)
    
130
def _decode(pathname, verbose=0):
Jack Jansen's avatar
Jack Jansen committed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    # Decode an AppleSingle resource file, return the new pathname.
    newpathname = pathname + '.df.rsrc'
    if os.path.exists(newpathname) and \
        os.stat(newpathname).st_mtime >= os.stat(pathname).st_mtime:
        return newpathname
    if hasattr(os, 'access') and not \
        os.access(os.path.dirname(pathname), os.W_OK|os.X_OK):
        # The destination directory isn't writeable. Create the file in
        # a temporary directory
        import tempfile
        fd, newpathname = tempfile.mkstemp(".rsrc")
    if verbose:
        print 'Decoding', pathname, 'to', newpathname
    import applesingle
    applesingle.decode(pathname, newpathname, resonly=1)
    return newpathname