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>
50 #include <StringCompare.h>
53 #include "TFileSpec.h" /* for Path2FSSpec() */
56 typedef void (*dl_funcptr
)();
57 #define FUNCNAME_PATTERN "init%.200s"
60 fssequal(FSSpec
*fs1
, FSSpec
*fs2
)
62 if ( fs1
->vRefNum
!= fs2
->vRefNum
|| fs1
->parID
!= fs2
->parID
)
64 return EqualString(fs1
->name
, fs2
->name
, false, true);
67 ** findnamedresource - Common code for the various *ResourceModule functions.
68 ** Check whether a file contains a resource of the correct name and type, and
69 ** optionally return the value in it.
87 ** If we have interning find_module takes care of interning all
88 ** sys.path components. We then keep a record of all sys.path
89 ** components for which GetFInfo has failed (usually because the
90 ** component in question is a folder), and we don't try opening these
91 ** as resource files again.
93 #define MAXPATHCOMPONENTS 32
94 static PyStringObject
*not_a_file
[MAXPATHCOMPONENTS
];
95 static int max_not_a_file
= 0;
98 if (obj
&& obj
->ob_sinterned
) {
99 for( i
=0; i
< max_not_a_file
; i
++ )
100 if ( obj
== not_a_file
[i
] )
103 #endif /* INTERN_STRINGS */
105 if ( Path2FSSpec(filename
, &fss
) != noErr
) {
107 if ( FSMakeFSSpec(0, 0, Pstring(filename
), &fss
) != noErr
) {
109 #ifdef INTERN_STRINGS
110 if ( obj
&& max_not_a_file
< MAXPATHCOMPONENTS
&& obj
->ob_sinterned
)
111 not_a_file
[max_not_a_file
++] = obj
;
112 #endif /* INTERN_STRINGS */
113 /* doesn't exist or is folder */
116 if ( fssequal(&fss
, &PyMac_ApplicationFSSpec
) ) {
118 ** Special case: the application itself. Use a shortcut to
119 ** forestall opening and closing the application numerous times
120 ** (which is dead slow when running from CDROM)
122 oldrh
= CurResFile();
123 UseResFile(PyMac_AppRefNum
);
126 #ifdef INTERN_STRINGS
127 if ( FSpGetFInfo(&fss
, &finfo
) != noErr
) {
128 if ( obj
&& max_not_a_file
< MAXPATHCOMPONENTS
&& obj
->ob_sinterned
)
129 not_a_file
[max_not_a_file
++] = obj
;
130 /* doesn't exist or is folder */
133 #endif /* INTERN_STRINGS */
134 oldrh
= CurResFile();
135 filerh
= FSpOpenResFile(&fss
, fsRdPerm
);
140 if ( dataptr
== NULL
)
142 h
= Get1NamedResource(restype
, Pstring(module
));
145 if ( ok
&& dataptr
!= NULL
) {
147 /* XXXX Unsafe if resource not correctly formatted! */
148 /* for ppc we take the first pstring */
150 memcpy(dataptr
+1, (*h
)+1, (int)*dataptr
);
154 CloseResFile(filerh
);
160 ** Returns true if the argument has a resource fork, and it contains
161 ** a 'PYC ' resource of the correct name
164 PyMac_FindResourceModule(obj
, module
, filename
)
171 ok
= findnamedresource(obj
, module
, filename
, 'PYC ', (StringPtr
)0);
176 ** Returns true if the argument has a resource fork, and it contains
177 ** a 'PYD ' resource of the correct name
180 PyMac_FindCodeResourceModule(obj
, module
, filename
)
187 ok
= findnamedresource(obj
, module
, filename
, 'PYD ', (StringPtr
)0);
193 ** Load the specified module from a code resource
196 PyMac_LoadCodeResourceModule(name
, pathname
)
202 char *lastdot
, *shortname
, *packagecontext
;
205 CFragConnectionID connID
;
211 CFragSymbolClass
class;
213 if ((m
= _PyImport_FindExtension(name
, name
)) != NULL
) {
217 lastdot
= strrchr(name
, '.');
218 if (lastdot
== NULL
) {
219 packagecontext
= NULL
;
223 packagecontext
= name
;
224 shortname
= lastdot
+1;
226 PyOS_snprintf(funcname
, sizeof(funcname
), FUNCNAME_PATTERN
, shortname
);
227 if( !findnamedresource((PyStringObject
*)0, name
, pathname
, 'PYD ', fragmentname
)) {
228 PyErr_SetString(PyExc_ImportError
, "PYD resource not found");
233 (or return the connID if it is already loaded */
234 err
= GetSharedLibrary(fragmentname
, kCompiledCFragArch
,
235 kLoadCFrag
, &connID
, &mainAddr
,
238 PyOS_snprintf(buf
, sizeof(buf
), "%.*s: %.200s",
239 errMessage
[0], errMessage
+1,
240 PyMac_StrError(err
));
241 PyErr_SetString(PyExc_ImportError
, buf
);
244 /* Locate the address of the correct init function */
245 err
= FindSymbol(connID
, Pstring(funcname
), &symAddr
, &class);
247 PyOS_snprintf(buf
, sizeof(buf
), "%s: %.200s",
248 funcname
, PyMac_StrError(err
));
249 PyErr_SetString(PyExc_ImportError
, buf
);
252 p
= (dl_funcptr
)symAddr
;
254 PyErr_Format(PyExc_ImportError
,
255 "dynamic module does not define init function (%.200s)",
259 _Py_PackageContext
= packagecontext
;
261 _Py_PackageContext
= NULL
;
262 if (PyErr_Occurred())
264 if (_PyImport_FixupExtension(name
, name
) == NULL
)
267 m
= PyDict_GetItemString(PyImport_GetModuleDict(), name
);
269 PyErr_SetString(PyExc_SystemError
,
270 "dynamic module not initialized properly");
274 /* Remember the filename as the __file__ attribute */
275 d
= PyModule_GetDict(m
);
276 s
= PyString_FromString(pathname
);
277 if (s
== NULL
|| PyDict_SetItemString(d
, "__file__", s
) != 0)
278 PyErr_Clear(); /* Not important enough to report */
282 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
283 name
, fragmentname
, pathname
);
289 ** Load the specified module from a resource
292 PyMac_LoadResourceModule(module
, filename
)
305 if ( (err
=Path2FSSpec(filename
, &fss
)) != noErr
||
306 FSpGetFInfo(&fss
, &finfo
) != noErr
)
308 if ( (err
=FSMakeFSSpec(0, 0, Pstring(filename
), &fss
)) != noErr
)
311 if ( fssequal(&fss
, &PyMac_ApplicationFSSpec
) ) {
313 ** Special case: the application itself. Use a shortcut to
314 ** forestall opening and closing the application numerous times
315 ** (which is dead slow when running from CDROM)
317 oldrh
= CurResFile();
318 UseResFile(PyMac_AppRefNum
);
321 if ( (err
=FSpGetFInfo(&fss
, &finfo
)) != noErr
)
323 oldrh
= CurResFile();
324 filerh
= FSpOpenResFile(&fss
, fsRdPerm
);
325 if ( filerh
== -1 ) {
331 h
= Get1NamedResource('PYC ', Pstring(module
));
338 ** XXXX The next few lines are intimately tied to the format of pyc
339 ** files. I'm not sure whether this code should be here or in import.c -- Jack
341 size
= GetHandleSize(h
);
343 PyErr_SetString(PyExc_ImportError
, "Resource too small");
346 num
= (*h
)[0] & 0xff;
347 num
= num
| (((*h
)[1] & 0xff) << 8);
348 num
= num
| (((*h
)[2] & 0xff) << 16);
349 num
= num
| (((*h
)[3] & 0xff) << 24);
350 if ( num
!= PyImport_GetMagicNumber() ) {
351 PyErr_SetString(PyExc_ImportError
, "Bad MAGIC in resource");
354 co
= PyMarshal_ReadObjectFromString((*h
)+8, size
-8);
356 ** Normally, byte 4-7 are the time stamp, but that is not used
357 ** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
358 ** that it is a package rather than an ordinary module.
359 ** See also py_resource.py. (jvr)
361 if ((*h
)[4] & 0xff) {
363 /* Set __path__ to the package name */
367 m
= PyImport_AddModule(module
);
372 d
= PyModule_GetDict(m
);
373 s
= PyString_InternFromString(module
);
378 err
= PyDict_SetItemString(d
, "__path__", s
);
390 CloseResFile(filerh
);
395 m
= PyImport_ExecCodeModuleEx(module
, co
, "<pyc resource>");
401 PySys_WriteStderr("import %s # pyc resource from %s\n",
408 PyOS_snprintf(buf
, sizeof(buf
), "%s: %s", filename
, PyMac_StrError(err
));
409 PyErr_SetString(PyExc_ImportError
, buf
);
415 ** Look for a module in a single folder. Upon entry buf and len
416 ** point to the folder to search, upon exit they refer to the full
417 ** pathname of the module found (if any).
420 PyMac_FindModuleExtension(char *buf
, size_t *lenp
, char *module
)
422 struct filedescr
*fdp
;
423 unsigned char fnbuf
[64];
424 int modnamelen
= strlen(module
);
433 ** Copy the module name to the buffer (already :-terminated)
434 ** We also copy the first suffix, if this matches immedeately we're
435 ** lucky and return immedeately.
437 if ( !_PyImport_Filetab
[0].suffix
)
440 strcpy(buf
+*lenp
, _PyImport_Filetab
[0].suffix
);
442 if ( Path2FSSpec(buf
, &fss
) == noErr
&&
443 FSpGetFInfo(&fss
, &finfo
) == noErr
)
444 return _PyImport_Filetab
;
446 if ( FSMakeFSSpec(0, 0, Pstring(buf
), &fss
) == noErr
)
447 return _PyImport_Filetab
;
450 ** We cannot check for fnfErr (unfortunately), it can mean either that
451 ** the file doesn't exist (fine, we try others) or the path leading to it.
453 refnum
= fss
.vRefNum
;
455 if ( refnum
== 0 || dirid
== 0 ) /* Fail on nonexistent dir */
458 ** We now have the folder parameters. Setup the field for the filename
460 if ( modnamelen
> 54 ) return 0; /* Leave room for extension */
461 strcpy((char *)fnbuf
+1, module
);
464 for( fdp
= _PyImport_Filetab
+1; fdp
->suffix
; fdp
++ ) {
465 strcpy((char *)fnbuf
+1+modnamelen
, fdp
->suffix
);
466 fnbuf
[0] = strlen((char *)fnbuf
+1);
467 if (Py_VerboseFlag
> 1)
468 PySys_WriteStderr("# trying %s%s\n", buf
, fdp
->suffix
);
469 if ( FSMakeFSSpec(refnum
, dirid
, fnbuf
, &fss
) == noErr
) {
471 strcpy(buf
+*lenp
, fdp
->suffix
);