blob: f68ecdc8a8bc395a45496134cc8007679660e4a7 [file] [log] [blame]
Jack Jansende3226f2001-08-27 21:21:07 +00001"""macresource - Locate and open the resources needed for a script."""
2
3from Carbon import Res
4import os
5import sys
Jack Jansen946c1942003-02-17 16:47:12 +00006import MacOS
7import macostools
Jack Jansende3226f2001-08-27 21:21:07 +00008
9class ArgumentError(TypeError): pass
10class ResourceFileNotFoundError(ImportError): pass
11
12def need(restype, resid, filename=None, modname=None):
Jack Jansen0ae32202003-04-09 13:25:43 +000013 """Open a resource file, if needed. restype and resid
14 are required parameters, and identify the resource for which to test. If it
15 is available we are done. If it is not available we look for a file filename
16 (default: modname with .rsrc appended) either in the same folder as
17 where modname was loaded from, or otherwise across sys.path.
Tim Peters182b5ac2004-07-18 06:16:08 +000018
Jack Jansen0ae32202003-04-09 13:25:43 +000019 Returns the refno of the resource file opened (or None)"""
Jack Jansende3226f2001-08-27 21:21:07 +000020
Jack Jansen0ae32202003-04-09 13:25:43 +000021 if modname is None and filename is None:
22 raise ArgumentError, "Either filename or modname argument (or both) must be given"
Tim Peters182b5ac2004-07-18 06:16:08 +000023
Jack Jansen0ae32202003-04-09 13:25:43 +000024 if type(resid) is type(1):
25 try:
26 h = Res.GetResource(restype, resid)
27 except Res.Error:
28 pass
29 else:
30 return None
31 else:
32 try:
33 h = Res.GetNamedResource(restype, resid)
34 except Res.Error:
35 pass
36 else:
37 return None
Tim Peters182b5ac2004-07-18 06:16:08 +000038
Jack Jansen0ae32202003-04-09 13:25:43 +000039 # Construct a filename if we don't have one
40 if not filename:
41 if '.' in modname:
42 filename = modname.split('.')[-1] + '.rsrc'
43 else:
44 filename = modname + '.rsrc'
Tim Peters182b5ac2004-07-18 06:16:08 +000045
Jack Jansen0ae32202003-04-09 13:25:43 +000046 # Now create a list of folders to search
47 searchdirs = []
48 if modname == '__main__':
49 # If we're main we look in the current directory
50 searchdirs = [os.curdir]
51 if sys.modules.has_key(modname):
52 mod = sys.modules[modname]
53 if hasattr(mod, '__file__'):
54 searchdirs = [os.path.dirname(mod.__file__)]
55 searchdirs.extend(sys.path)
Tim Peters182b5ac2004-07-18 06:16:08 +000056
Jack Jansen0ae32202003-04-09 13:25:43 +000057 # And look for the file
58 for dir in searchdirs:
59 pathname = os.path.join(dir, filename)
60 if os.path.exists(pathname):
61 break
62 else:
63 raise ResourceFileNotFoundError, filename
Tim Peters182b5ac2004-07-18 06:16:08 +000064
Jack Jansen0ae32202003-04-09 13:25:43 +000065 refno = open_pathname(pathname)
Tim Peters182b5ac2004-07-18 06:16:08 +000066
Jack Jansen0ae32202003-04-09 13:25:43 +000067 # And check that the resource exists now
68 if type(resid) is type(1):
69 h = Res.GetResource(restype, resid)
70 else:
71 h = Res.GetNamedResource(restype, resid)
72 return refno
Tim Peters182b5ac2004-07-18 06:16:08 +000073
Jack Jansenccd8e8d2002-08-09 13:44:03 +000074def open_pathname(pathname, verbose=0):
Jack Jansen0ae32202003-04-09 13:25:43 +000075 """Open a resource file given by pathname, possibly decoding an
76 AppleSingle file"""
77 try:
78 refno = Res.FSpOpenResFile(pathname, 1)
79 except Res.Error, arg:
80 if arg[0] in (-37, -39):
81 # No resource fork. We may be on OSX, and this may be either
82 # a data-fork based resource file or a AppleSingle file
83 # from the CVS repository.
84 try:
85 refno = Res.FSOpenResourceFile(pathname, u'', 1)
86 except Res.Error, arg:
87 if arg[0] != -199:
88 # -199 is "bad resource map"
89 raise
90 else:
91 return refno
92 # Finally try decoding an AppleSingle file
93 pathname = _decode(pathname, verbose=verbose)
94 refno = Res.FSOpenResourceFile(pathname, u'', 1)
95 else:
96 raise
97 return refno
Tim Peters182b5ac2004-07-18 06:16:08 +000098
Jack Jansencba861e2003-02-25 23:02:03 +000099def resource_pathname(pathname, verbose=0):
Jack Jansen0ae32202003-04-09 13:25:43 +0000100 """Return the pathname for a resource file (either DF or RF based).
101 If the pathname given already refers to such a file simply return it,
102 otherwise first decode it."""
103 try:
104 refno = Res.FSpOpenResFile(pathname, 1)
105 Res.CloseResFile(refno)
106 except Res.Error, arg:
107 if arg[0] in (-37, -39):
108 # No resource fork. We may be on OSX, and this may be either
109 # a data-fork based resource file or a AppleSingle file
110 # from the CVS repository.
111 try:
112 refno = Res.FSOpenResourceFile(pathname, u'', 1)
113 except Res.Error, arg:
114 if arg[0] != -199:
115 # -199 is "bad resource map"
116 raise
117 else:
118 return refno
119 # Finally try decoding an AppleSingle file
120 pathname = _decode(pathname, verbose=verbose)
121 else:
122 raise
123 return pathname
Tim Peters182b5ac2004-07-18 06:16:08 +0000124
Jack Jansendde800e2002-11-07 23:07:05 +0000125def open_error_resource():
Jack Jansen0ae32202003-04-09 13:25:43 +0000126 """Open the resource file containing the error code to error message
127 mapping."""
128 need('Estr', 1, filename="errors.rsrc", modname=__name__)
Tim Peters182b5ac2004-07-18 06:16:08 +0000129
Jack Jansencba861e2003-02-25 23:02:03 +0000130def _decode(pathname, verbose=0):
Jack Jansen0ae32202003-04-09 13:25:43 +0000131 # Decode an AppleSingle resource file, return the new pathname.
132 newpathname = pathname + '.df.rsrc'
133 if os.path.exists(newpathname) and \
134 os.stat(newpathname).st_mtime >= os.stat(pathname).st_mtime:
135 return newpathname
136 if hasattr(os, 'access') and not \
137 os.access(os.path.dirname(pathname), os.W_OK|os.X_OK):
138 # The destination directory isn't writeable. Create the file in
139 # a temporary directory
140 import tempfile
141 fd, newpathname = tempfile.mkstemp(".rsrc")
142 if verbose:
143 print 'Decoding', pathname, 'to', newpathname
144 import applesingle
145 applesingle.decode(pathname, newpathname, resonly=1)
146 return newpathname