| Jack Jansen | de3226f | 2001-08-27 21:21:07 +0000 | [diff] [blame] | 1 | """macresource - Locate and open the resources needed for a script.""" | 
 | 2 |  | 
 | 3 | from Carbon import Res | 
 | 4 | import os | 
 | 5 | import sys | 
| Jack Jansen | 946c194 | 2003-02-17 16:47:12 +0000 | [diff] [blame] | 6 | import MacOS | 
 | 7 | import macostools | 
| Jack Jansen | de3226f | 2001-08-27 21:21:07 +0000 | [diff] [blame] | 8 |  | 
 | 9 | class ArgumentError(TypeError): pass | 
 | 10 | class ResourceFileNotFoundError(ImportError): pass | 
 | 11 |  | 
 | 12 | def need(restype, resid, filename=None, modname=None): | 
| Jack Jansen | 0ae3220 | 2003-04-09 13:25:43 +0000 | [diff] [blame] | 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 | 
 | 17 |     where modname was loaded from, or otherwise across sys.path. | 
 | 18 |      | 
 | 19 |     Returns the refno of the resource file opened (or None)""" | 
| Jack Jansen | de3226f | 2001-08-27 21:21:07 +0000 | [diff] [blame] | 20 |  | 
| Jack Jansen | 0ae3220 | 2003-04-09 13:25:43 +0000 | [diff] [blame] | 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: | 
 | 30 |             return None | 
 | 31 |     else: | 
 | 32 |         try: | 
 | 33 |             h = Res.GetNamedResource(restype, resid) | 
 | 34 |         except Res.Error: | 
 | 35 |             pass | 
 | 36 |         else: | 
 | 37 |             return None | 
 | 38 |              | 
 | 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__'): | 
 | 54 |             searchdirs = [os.path.dirname(mod.__file__)] | 
 | 55 |     searchdirs.extend(sys.path) | 
 | 56 |      | 
 | 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 |      | 
 | 65 |     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 Jansen | ccd8e8d | 2002-08-09 13:44:03 +0000 | [diff] [blame] | 74 | def open_pathname(pathname, verbose=0): | 
| Jack Jansen | 0ae3220 | 2003-04-09 13:25:43 +0000 | [diff] [blame] | 75 |     """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 | 
 | 98 |      | 
| Jack Jansen | cba861e | 2003-02-25 23:02:03 +0000 | [diff] [blame] | 99 | def resource_pathname(pathname, verbose=0): | 
| Jack Jansen | 0ae3220 | 2003-04-09 13:25:43 +0000 | [diff] [blame] | 100 |     """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 | 
 | 124 |      | 
| Jack Jansen | dde800e | 2002-11-07 23:07:05 +0000 | [diff] [blame] | 125 | def open_error_resource(): | 
| Jack Jansen | 0ae3220 | 2003-04-09 13:25:43 +0000 | [diff] [blame] | 126 |     """Open the resource file containing the error code to error message | 
 | 127 |     mapping.""" | 
 | 128 |     need('Estr', 1, filename="errors.rsrc", modname=__name__) | 
 | 129 |      | 
| Jack Jansen | cba861e | 2003-02-25 23:02:03 +0000 | [diff] [blame] | 130 | def _decode(pathname, verbose=0): | 
| Jack Jansen | 0ae3220 | 2003-04-09 13:25:43 +0000 | [diff] [blame] | 131 |     # 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 |