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>
38 #include <CodeFragments.h>
39 #include <StringCompare.h>
41 typedef void (*dl_funcptr
)();
42 #define FUNCNAME_PATTERN "init%.200s"
45 fssequal(FSSpec
*fs1
, FSSpec
*fs2
)
47 if ( fs1
->vRefNum
!= fs2
->vRefNum
|| fs1
->parID
!= fs2
->parID
)
49 return EqualString(fs1
->name
, fs2
->name
, false, true);
52 ** findnamedresource - Common code for the various *ResourceModule functions.
53 ** Check whether a file contains a resource of the correct name and type, and
54 ** optionally return the value in it.
71 ** Find_module takes care of interning all
72 ** sys.path components. We then keep a record of all sys.path
73 ** components for which GetFInfo has failed (usually because the
74 ** component in question is a folder), and we don't try opening these
75 ** as resource files again.
77 #define MAXPATHCOMPONENTS 32
78 static PyStringObject
*not_a_file
[MAXPATHCOMPONENTS
];
79 static int max_not_a_file
= 0;
82 if (obj
&& PyString_Check(obj
) && PyString_CHECK_INTERNED(obj
) ) {
83 for( i
=0; i
< max_not_a_file
; i
++ )
84 if ( obj
== not_a_file
[i
] )
87 if ( FSMakeFSSpec(0, 0, Pstring(filename
), &fss
) != noErr
) {
88 /* doesn't exist or is folder */
89 if ( obj
&& max_not_a_file
< MAXPATHCOMPONENTS
&& PyString_Check(obj
) && PyString_CHECK_INTERNED(obj
) ) {
91 not_a_file
[max_not_a_file
++] = obj
;
92 if (Py_VerboseFlag
> 1)
93 PySys_WriteStderr("# %s is not a file\n", filename
);
97 if ( fssequal(&fss
, &PyMac_ApplicationFSSpec
) ) {
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
);
107 if ( FSpGetFInfo(&fss
, &finfo
) != noErr
) {
108 /* doesn't exist or is folder */
109 if ( obj
&& max_not_a_file
< MAXPATHCOMPONENTS
&& PyString_Check(obj
) && PyString_CHECK_INTERNED(obj
) ) {
111 not_a_file
[max_not_a_file
++] = obj
;
112 if (Py_VerboseFlag
> 1)
113 PySys_WriteStderr("# %s is not a file\n", filename
);
117 oldrh
= CurResFile();
118 filerh
= FSpOpenResFile(&fss
, fsRdPerm
);
123 if ( dataptr
== NULL
)
125 if (Py_VerboseFlag
> 1)
126 PySys_WriteStderr("# Look for ('PYC ', %s) in %s\n", module
, filename
);
127 h
= Get1NamedResource(restype
, Pstring(module
));
130 if ( ok
&& dataptr
!= NULL
) {
132 /* XXXX Unsafe if resource not correctly formatted! */
133 /* for ppc we take the first pstring */
135 memcpy(dataptr
+1, (*h
)+1, (int)*dataptr
);
139 CloseResFile(filerh
);
145 ** Returns true if the argument has a resource fork, and it contains
146 ** a 'PYC ' resource of the correct name
149 PyMac_FindResourceModule(obj
, module
, filename
)
156 ok
= findnamedresource(obj
, module
, filename
, 'PYC ', (StringPtr
)0);
161 ** Returns true if the argument has a resource fork, and it contains
162 ** a 'PYD ' resource of the correct name
165 PyMac_FindCodeResourceModule(obj
, module
, filename
)
172 ok
= findnamedresource(obj
, module
, filename
, 'PYD ', (StringPtr
)0);
178 ** Load the specified module from a code resource
181 PyMac_LoadCodeResourceModule(name
, pathname
)
187 char *lastdot
, *shortname
, *packagecontext
;
190 CFragConnectionID connID
;
196 CFragSymbolClass
class;
198 if ((m
= _PyImport_FindExtension(name
, name
)) != NULL
) {
202 lastdot
= strrchr(name
, '.');
203 if (lastdot
== NULL
) {
204 packagecontext
= NULL
;
208 packagecontext
= name
;
209 shortname
= lastdot
+1;
211 PyOS_snprintf(funcname
, sizeof(funcname
), FUNCNAME_PATTERN
, shortname
);
212 if( !findnamedresource((PyStringObject
*)0, name
, pathname
, 'PYD ', fragmentname
)) {
213 PyErr_SetString(PyExc_ImportError
, "PYD resource not found");
218 (or return the connID if it is already loaded */
219 err
= GetSharedLibrary(fragmentname
, kCompiledCFragArch
,
220 kLoadCFrag
, &connID
, &mainAddr
,
223 PyOS_snprintf(buf
, sizeof(buf
), "%.*s: %.200s",
224 errMessage
[0], errMessage
+1,
225 PyMac_StrError(err
));
226 PyErr_SetString(PyExc_ImportError
, buf
);
229 /* Locate the address of the correct init function */
230 err
= FindSymbol(connID
, Pstring(funcname
), &symAddr
, &class);
232 PyOS_snprintf(buf
, sizeof(buf
), "%s: %.200s",
233 funcname
, PyMac_StrError(err
));
234 PyErr_SetString(PyExc_ImportError
, buf
);
237 p
= (dl_funcptr
)symAddr
;
239 PyErr_Format(PyExc_ImportError
,
240 "dynamic module does not define init function (%.200s)",
244 _Py_PackageContext
= packagecontext
;
246 _Py_PackageContext
= NULL
;
247 if (PyErr_Occurred())
249 if (_PyImport_FixupExtension(name
, name
) == NULL
)
252 m
= PyDict_GetItemString(PyImport_GetModuleDict(), name
);
254 PyErr_SetString(PyExc_SystemError
,
255 "dynamic module not initialized properly");
258 /* Remember the filename as the __file__ attribute */
259 d
= PyModule_GetDict(m
);
260 s
= PyString_FromString(pathname
);
261 if (s
== NULL
|| PyDict_SetItemString(d
, "__file__", s
) != 0)
262 PyErr_Clear(); /* Not important enough to report */
265 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
266 name
, fragmentname
, pathname
);
272 ** Load the specified module from a resource
275 PyMac_LoadResourceModule(module
, filename
)
287 if ( (err
=FSMakeFSSpec(0, 0, Pstring(filename
), &fss
)) != noErr
)
289 if ( fssequal(&fss
, &PyMac_ApplicationFSSpec
) ) {
291 ** Special case: the application itself. Use a shortcut to
292 ** forestall opening and closing the application numerous times
293 ** (which is dead slow when running from CDROM)
295 oldrh
= CurResFile();
296 UseResFile(PyMac_AppRefNum
);
299 if ( (err
=FSpGetFInfo(&fss
, &finfo
)) != noErr
)
301 oldrh
= CurResFile();
302 filerh
= FSpOpenResFile(&fss
, fsRdPerm
);
303 if ( filerh
== -1 ) {
309 h
= Get1NamedResource('PYC ', Pstring(module
));
316 ** XXXX The next few lines are intimately tied to the format of pyc
317 ** files. I'm not sure whether this code should be here or in import.c -- Jack
319 size
= GetHandleSize(h
);
321 PyErr_SetString(PyExc_ImportError
, "Resource too small");
324 num
= (*h
)[0] & 0xff;
325 num
= num
| (((*h
)[1] & 0xff) << 8);
326 num
= num
| (((*h
)[2] & 0xff) << 16);
327 num
= num
| (((*h
)[3] & 0xff) << 24);
328 if ( num
!= PyImport_GetMagicNumber() ) {
329 PyErr_SetString(PyExc_ImportError
, "Bad MAGIC in resource");
332 co
= PyMarshal_ReadObjectFromString((*h
)+8, size
-8);
334 ** Normally, byte 4-7 are the time stamp, but that is not used
335 ** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
336 ** that it is a package rather than an ordinary module.
337 ** See also py_resource.py. (jvr)
339 if ((*h
)[4] & 0xff) {
341 /* Set __path__ to the package name */
345 m
= PyImport_AddModule(module
);
350 d
= PyModule_GetDict(m
);
351 s
= PyString_InternFromString(module
);
356 err
= PyDict_SetItemString(d
, "__path__", s
);
368 CloseResFile(filerh
);
373 m
= PyImport_ExecCodeModuleEx(module
, co
, "<pyc resource>");
379 PySys_WriteStderr("import %s # pyc resource from %s\n",
386 PyOS_snprintf(buf
, sizeof(buf
), "%s: %s", filename
, PyMac_StrError(err
));
387 PyErr_SetString(PyExc_ImportError
, buf
);
393 ** Look for a module in a single folder. Upon entry buf and len
394 ** point to the folder to search, upon exit they refer to the full
395 ** pathname of the module found (if any).
398 PyMac_FindModuleExtension(char *buf
, size_t *lenp
, char *module
)
400 struct filedescr
*fdp
;
401 unsigned char fnbuf
[64];
402 int modnamelen
= strlen(module
);
408 ** Copy the module name to the buffer (already :-terminated)
409 ** We also copy the first suffix, if this matches immedeately we're
410 ** lucky and return immedeately.
412 if ( !_PyImport_Filetab
[0].suffix
)
415 strcpy(buf
+*lenp
, _PyImport_Filetab
[0].suffix
);
416 if ( FSMakeFSSpec(0, 0, Pstring(buf
), &fss
) == noErr
)
417 return _PyImport_Filetab
;
419 ** We cannot check for fnfErr (unfortunately), it can mean either that
420 ** the file doesn't exist (fine, we try others) or the path leading to it.
422 refnum
= fss
.vRefNum
;
424 if ( refnum
== 0 || dirid
== 0 ) /* Fail on nonexistent dir */
427 ** We now have the folder parameters. Setup the field for the filename
429 if ( modnamelen
> 54 ) return 0; /* Leave room for extension */
430 strcpy((char *)fnbuf
+1, module
);
433 for( fdp
= _PyImport_Filetab
+1; fdp
->suffix
; fdp
++ ) {
434 strcpy((char *)fnbuf
+1+modnamelen
, fdp
->suffix
);
435 fnbuf
[0] = strlen((char *)fnbuf
+1);
436 if (Py_VerboseFlag
> 1)
437 PySys_WriteStderr("# trying %s%s\n", buf
, fdp
->suffix
);
438 if ( FSMakeFSSpec(refnum
, dirid
, fnbuf
, &fss
) == noErr
) {
440 strcpy(buf
+*lenp
, fdp
->suffix
);