blob: 16eed00f4980ef97b96f2b1ef5910582472bac11 [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):
13 """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
Jack Jansena5d7da52001-08-27 21:37:45 +000017 where modname was loaded from, or otherwise across sys.path.
18
19 Returns the refno of the resource file opened (or None)"""
Jack Jansende3226f2001-08-27 21:21:07 +000020
21 if modname is None and filename is None:
22 raise ArgumentError, "Either filename or modname argument (or both) must be given"
23
24 if type(resid) is type(1):
25 try:
26 h = Res.GetResource(restype, resid)
27 except Res.Error:
28 pass
29 else:
Jack Jansena5d7da52001-08-27 21:37:45 +000030 return None
Jack Jansende3226f2001-08-27 21:21:07 +000031 else:
32 try:
33 h = Res.GetNamedResource(restype, resid)
34 except Res.Error:
35 pass
36 else:
Jack Jansena5d7da52001-08-27 21:37:45 +000037 return None
Jack Jansende3226f2001-08-27 21:21:07 +000038
39 # 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'
45
46 # 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__'):
Just van Rossum077c5822003-01-06 11:15:05 +000054 searchdirs = [os.path.dirname(mod.__file__)]
55 searchdirs.extend(sys.path)
Jack Jansende3226f2001-08-27 21:21:07 +000056
57 # 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
64
Jack Jansen562baab2002-03-21 22:38:32 +000065 refno = open_pathname(pathname)
66
67 # 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
73
Jack Jansenccd8e8d2002-08-09 13:44:03 +000074def open_pathname(pathname, verbose=0):
Jack Jansen562baab2002-03-21 22:38:32 +000075 """Open a resource file given by pathname, possibly decoding an
76 AppleSingle file"""
Jack Jansen32d1a3b2002-01-13 23:18:00 +000077 try:
78 refno = Res.FSpOpenResFile(pathname, 1)
79 except Res.Error, arg:
80 if arg[0] in (-37, -39):
Jack Jansen5053b702002-03-29 14:29:35 +000081 # 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:
Jack Jansen32d1a3b2002-01-13 23:18:00 +000085 refno = Res.FSOpenResourceFile(pathname, u'', 1)
Jack Jansen5053b702002-03-29 14:29:35 +000086 except Res.Error, arg:
87 if arg[0] != -199:
88 # -199 is "bad resource map"
89 raise
Jack Jansen32d1a3b2002-01-13 23:18:00 +000090 else:
Jack Jansen5053b702002-03-29 14:29:35 +000091 return refno
92 # Finally try decoding an AppleSingle file
Jack Jansenccd8e8d2002-08-09 13:44:03 +000093 pathname = _decode(pathname, verbose=verbose)
Jack Jansen5053b702002-03-29 14:29:35 +000094 refno = Res.FSOpenResourceFile(pathname, u'', 1)
Jack Jansend21c9f42002-03-29 21:17:57 +000095 else:
96 raise
Jack Jansen32d1a3b2002-01-13 23:18:00 +000097 return refno
98
Jack Jansendde800e2002-11-07 23:07:05 +000099def open_error_resource():
100 """Open the resource file containing the error code to error message
101 mapping."""
102 need('Estr', 1, filename="errors.rsrc", modname=__name__)
103
Jack Jansen946c1942003-02-17 16:47:12 +0000104def _decode(pathname, verbose=0, newpathname=None):
Jack Jansen32d1a3b2002-01-13 23:18:00 +0000105 # Decode an AppleSingle resource file, return the new pathname.
Jack Jansen946c1942003-02-17 16:47:12 +0000106 if not newpathname:
107 newpathname = pathname + '.df.rsrc'
108 if os.path.exists(newpathname) and \
Jack Jansenccd8e8d2002-08-09 13:44:03 +0000109 os.stat(newpathname).st_mtime >= os.stat(pathname).st_mtime:
Jack Jansen946c1942003-02-17 16:47:12 +0000110 return newpathname
Jack Jansenccd8e8d2002-08-09 13:44:03 +0000111 if verbose:
112 print 'Decoding', pathname
Jack Jansen32d1a3b2002-01-13 23:18:00 +0000113 import applesingle
114 applesingle.decode(pathname, newpathname, resonly=1)
115 return newpathname
116
Jack Jansen946c1942003-02-17 16:47:12 +0000117def install(src, dst, mkdirs=0):
118 """Copy a resource file. The result will always be a datafork-based
119 resource file, whether the source is datafork-based, resource-fork
120 based or AppleSingle-encoded."""
121 if mkdirs:
122 macostools.mkdirs(os.path.split(dst)[0])
123 try:
124 refno = Res.FSOpenResourceFile(src, u'', 1)
125 except Res.Error, arg:
126 if arg[0] != -199:
127 # -199 is "bad resource map"
128 raise
129 else:
130 # Resource-fork based. Simply copy.
131 Res.CloseResFile(refno)
132 macostools.copy(src, dst)
133
134 try:
135 refno = Res.FSpOpenResFile(src, 1)
136 except Res.Error, arg:
137 if not arg[0] in (-37, -39):
138 raise
139 else:
140 Res.CloseResFile(refno)
141 BUFSIZ=0x80000 # Copy in 0.5Mb chunks
142 ifp = MacOS.openrf(src, '*rb')
143 ofp = open(dst, 'wb')
144 d = ifp.read(BUFSIZ)
145 while d:
146 ofp.write(d)
147 d = ifp.read(BUFSIZ)
148 ifp.close()
149 ofp.close()
150
151 _decode(src, newpathname=dst)