1 /***********************************************************
2 Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
33 #include "pythonresources.h"
37 #include <Resources.h>
39 #include <OSUtils.h> /* for Set(Current)A5 */
40 #include <StandardFile.h>
44 #include <Processes.h>
47 #include <TextUtils.h>
49 #include <CodeFragments.h>
52 #include "TFileSpec.h" /* for Path2FSSpec() */
55 typedef void (*dl_funcptr
)();
56 #define FUNCNAME_PATTERN "init%.200s"
59 ** findnamedresource - Common code for the various *ResourceModule functions.
60 ** Check whether a file contains a resource of the correct name and type, and
61 ** optionally return the value in it.
79 ** If we have interning find_module takes care of interning all
80 ** sys.path components. We then keep a record of all sys.path
81 ** components for which GetFInfo has failed (usually because the
82 ** component in question is a folder), and we don't try opening these
83 ** as resource files again.
85 #define MAXPATHCOMPONENTS 32
86 static PyStringObject
*not_a_file
[MAXPATHCOMPONENTS
];
87 static int max_not_a_file
= 0;
90 if (obj
&& obj
->ob_sinterned
) {
91 for( i
=0; i
< max_not_a_file
; i
++ )
92 if ( obj
== not_a_file
[i
] )
95 #endif /* INTERN_STRINGS */
97 if ( strcmp(filename
, PyMac_ApplicationPath
) == 0 ) {
99 ** Special case: the application itself. Use a shortcut to
100 ** forestall opening and closing the application numerous times
101 ** (which is dead slow when running from CDROM)
103 oldrh
= CurResFile();
104 UseResFile(PyMac_AppRefNum
);
108 if ( Path2FSSpec(filename
, &fss
) != noErr
||
110 if ( FSMakeFSSpec(0, 0, Pstring(filename
), &fss
) != noErr
||
112 FSpGetFInfo(&fss
, &finfo
) != noErr
) {
113 #ifdef INTERN_STRINGS
114 if ( obj
&& max_not_a_file
< MAXPATHCOMPONENTS
&& obj
->ob_sinterned
)
115 not_a_file
[max_not_a_file
++] = obj
;
116 #endif /* INTERN_STRINGS */
117 /* doesn't exist or is folder */
120 oldrh
= CurResFile();
121 filerh
= FSpOpenResFile(&fss
, fsRdPerm
);
126 if ( dataptr
== NULL
)
128 h
= Get1NamedResource(restype
, Pstring(module
));
131 if ( ok
&& dataptr
!= NULL
) {
133 /* XXXX Unsafe if resource not correctly formatted! */
135 /* for cfm68k we take the second pstring */
136 *dataptr
= *((*h
)+(**h
)+1);
137 memcpy(dataptr
+1, (*h
)+(**h
)+2, (int)*dataptr
);
139 /* for ppc we take the first pstring */
141 memcpy(dataptr
+1, (*h
)+1, (int)*dataptr
);
146 CloseResFile(filerh
);
152 ** Returns true if the argument has a resource fork, and it contains
153 ** a 'PYC ' resource of the correct name
156 PyMac_FindResourceModule(obj
, module
, filename
)
163 ok
= findnamedresource(obj
, module
, filename
, 'PYC ', (StringPtr
)0);
168 ** Returns true if the argument has a resource fork, and it contains
169 ** a 'PYD ' resource of the correct name
172 PyMac_FindCodeResourceModule(obj
, module
, filename
)
179 ok
= findnamedresource(obj
, module
, filename
, 'PYD ', (StringPtr
)0);
185 ** Load the specified module from a code resource
188 PyMac_LoadCodeResourceModule(name
, pathname
)
194 char *lastdot
, *shortname
, *packagecontext
;
197 CFragConnectionID connID
;
203 CFragSymbolClass
class;
205 if ((m
= _PyImport_FindExtension(name
, name
)) != NULL
) {
209 lastdot
= strrchr(name
, '.');
210 if (lastdot
== NULL
) {
211 packagecontext
= NULL
;
215 packagecontext
= name
;
216 shortname
= lastdot
+1;
218 sprintf(funcname
, FUNCNAME_PATTERN
, shortname
);
219 if( !findnamedresource((PyStringObject
*)0, shortname
, pathname
, 'PYD ', fragmentname
)) {
220 PyErr_SetString(PyExc_ImportError
, "PYD resource not found");
225 (or return the connID if it is already loaded */
226 err
= GetSharedLibrary(fragmentname
, kCompiledCFragArch
,
227 kLoadCFrag
, &connID
, &mainAddr
,
230 sprintf(buf
, "%.*s: %.200s",
231 errMessage
[0], errMessage
+1,
232 PyMac_StrError(err
));
233 PyErr_SetString(PyExc_ImportError
, buf
);
236 /* Locate the address of the correct init function */
237 err
= FindSymbol(connID
, Pstring(funcname
), &symAddr
, &class);
239 sprintf(buf
, "%s: %.200s",
240 funcname
, PyMac_StrError(err
));
241 PyErr_SetString(PyExc_ImportError
, buf
);
244 p
= (dl_funcptr
)symAddr
;
246 PyErr_Format(PyExc_ImportError
,
247 "dynamic module does not define init function (%.200s)",
251 _Py_PackageContext
= packagecontext
;
253 _Py_PackageContext
= NULL
;
254 if (PyErr_Occurred())
256 if (_PyImport_FixupExtension(name
, name
) == NULL
)
259 m
= PyDict_GetItemString(PyImport_GetModuleDict(), name
);
261 PyErr_SetString(PyExc_SystemError
,
262 "dynamic module not initialized properly");
266 /* Remember the filename as the __file__ attribute */
267 d
= PyModule_GetDict(m
);
268 s
= PyString_FromString(pathname
);
269 if (s
== NULL
|| PyDict_SetItemString(d
, "__file__", s
) != 0)
270 PyErr_Clear(); /* Not important enough to report */
274 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
275 name
, fragmentname
, pathname
);
281 ** Load the specified module from a resource
284 PyMac_LoadResourceModule(module
, filename
)
296 if ( strcmp(filename
, PyMac_ApplicationPath
) == 0 ) {
298 ** Special case: the application itself. Use a shortcut to
299 ** forestall opening and closing the application numerous times
300 ** (which is dead slow when running from CDROM)
302 oldrh
= CurResFile();
303 UseResFile(PyMac_AppRefNum
);
307 if ( (err
=Path2FSSpec(filename
, &fss
)) != noErr
||
308 FSpGetFInfo(&fss
, &finfo
) != noErr
)
310 if ( (err
=FSMakeFSSpec(0, 0, Pstring(filename
), &fss
)) != noErr
)
313 if ( (err
=FSpGetFInfo(&fss
, &finfo
)) != noErr
)
315 oldrh
= CurResFile();
316 filerh
= FSpOpenResFile(&fss
, fsRdPerm
);
317 if ( filerh
== -1 ) {
323 h
= Get1NamedResource('PYC ', Pstring(module
));
330 ** XXXX The next few lines are intimately tied to the format of pyc
331 ** files. I'm not sure whether this code should be here or in import.c -- Jack
333 size
= GetHandleSize(h
);
335 PyErr_SetString(PyExc_ImportError
, "Resource too small");
338 num
= (*h
)[0] & 0xff;
339 num
= num
| (((*h
)[1] & 0xff) << 8);
340 num
= num
| (((*h
)[2] & 0xff) << 16);
341 num
= num
| (((*h
)[3] & 0xff) << 24);
342 if ( num
!= PyImport_GetMagicNumber() ) {
343 PyErr_SetString(PyExc_ImportError
, "Bad MAGIC in resource");
346 co
= PyMarshal_ReadObjectFromString((*h
)+8, size
-8);
348 ** Normally, byte 4-7 are the time stamp, but that is not used
349 ** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
350 ** that it is a package rather than an ordinary module.
351 ** See also py_resource.py. (jvr)
353 if ((*h
)[4] & 0xff) {
355 /* Set __path__ to the package name */
359 m
= PyImport_AddModule(module
);
364 d
= PyModule_GetDict(m
);
365 s
= PyString_InternFromString(module
);
370 err
= PyDict_SetItemString(d
, "__path__", s
);
382 CloseResFile(filerh
);
387 m
= PyImport_ExecCodeModuleEx(module
, co
, "<pyc resource>");
393 PySys_WriteStderr("import %s # pyc resource from %s\n",
400 sprintf(buf
, "%s: %s", filename
, PyMac_StrError(err
));
401 PyErr_SetString(PyExc_ImportError
, buf
);
407 ** Look for a module in a single folder. Upon entry buf and len
408 ** point to the folder to search, upon exit they refer to the full
409 ** pathname of the module found (if any).
412 PyMac_FindModuleExtension(char *buf
, size_t *lenp
, char *module
)
414 struct filedescr
*fdp
;
415 unsigned char fnbuf
[64];
416 int modnamelen
= strlen(module
);
425 ** Copy the module name to the buffer (already :-terminated)
426 ** We also copy the first suffix, if this matches immedeately we're
427 ** lucky and return immedeately.
429 if ( !_PyImport_Filetab
[0].suffix
)
434 strcpy(buf
+*lenp
, module
);
435 strcpy(buf
+*lenp
+modnamelen
, _PyImport_Filetab
[0].suffix
);
437 strcpy(buf
+*lenp
, _PyImport_Filetab
[0].suffix
);
440 if ( Path2FSSpec(buf
, &fss
) == noErr
&&
441 FSpGetFInfo(&fss
, &finfo
) == noErr
)
442 return _PyImport_Filetab
;
444 if ( FSMakeFSSpec(0, 0, Pstring(buf
), &fss
) == noErr
)
445 return _PyImport_Filetab
;
448 ** We cannot check for fnfErr (unfortunately), it can mean either that
449 ** the file doesn't exist (fine, we try others) or the path leading to it.
451 refnum
= fss
.vRefNum
;
453 if ( refnum
== 0 || dirid
== 0 ) /* Fail on nonexistent dir */
456 ** We now have the folder parameters. Setup the field for the filename
458 if ( modnamelen
> 54 ) return 0; /* Leave room for extension */
459 strcpy((char *)fnbuf
+1, module
);
461 for( fdp
= _PyImport_Filetab
+1; fdp
->suffix
; fdp
++ ) {
462 strcpy((char *)fnbuf
+1+modnamelen
, fdp
->suffix
);
463 fnbuf
[0] = strlen((char *)fnbuf
+1);
464 if (Py_VerboseFlag
> 1)
465 PySys_WriteStderr("# trying %s%s\n", buf
, fdp
->suffix
);
466 if ( FSMakeFSSpec(refnum
, dirid
, fnbuf
, &fss
) == noErr
) {
469 strcpy(buf
+*lenp
+modnamelen
, fdp
->suffix
);
471 strcpy(buf
+*lenp
, fdp
->suffix
);