blob: e6c432b5d55a9ce8e3a9cfec333c51867dcaa756 [file] [log] [blame]
Jack Jansen1e2260f1998-07-13 13:37:12 +00001/***********************************************************
2Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25
26#include "Python.h"
27
28#include "macglue.h"
29#include "marshal.h"
30#include "import.h"
31#include "importdl.h"
32
33#include "pythonresources.h"
34
35#include <Types.h>
36#include <Files.h>
37#include <Resources.h>
Jack Jansen1e2260f1998-07-13 13:37:12 +000038#include <CodeFragments.h>
Jack Jansenb45032e2001-05-22 14:13:02 +000039#include <StringCompare.h>
Jack Jansen1e2260f1998-07-13 13:37:12 +000040
41typedef void (*dl_funcptr)();
42#define FUNCNAME_PATTERN "init%.200s"
43
Jack Jansenb45032e2001-05-22 14:13:02 +000044static int
45fssequal(FSSpec *fs1, FSSpec *fs2)
46{
47 if ( fs1->vRefNum != fs2->vRefNum || fs1->parID != fs2->parID )
48 return 0;
49 return EqualString(fs1->name, fs2->name, false, true);
50}
Jack Jansen1e2260f1998-07-13 13:37:12 +000051/*
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.
55*/
56static int
57findnamedresource(
58 PyStringObject *obj,
59 char *module,
60 char *filename,
61 OSType restype,
62 StringPtr dataptr)
63{
64 FSSpec fss;
65 FInfo finfo;
66 short oldrh, filerh;
67 int ok;
68 Handle h;
69
Jack Jansen1e2260f1998-07-13 13:37:12 +000070 /*
Jack Jansen603e76e2002-07-22 12:35:22 +000071 ** Find_module takes care of interning all
Jack Jansen1e2260f1998-07-13 13:37:12 +000072 ** 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.
76 */
77#define MAXPATHCOMPONENTS 32
78 static PyStringObject *not_a_file[MAXPATHCOMPONENTS];
79 static int max_not_a_file = 0;
80 int i;
81
Jack Jansen82a9b602002-09-06 20:42:27 +000082 if (obj && PyString_Check(obj) && PyString_CHECK_INTERNED(obj) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +000083 for( i=0; i< max_not_a_file; i++ )
84 if ( obj == not_a_file[i] )
85 return 0;
86 }
Jack Jansenb45032e2001-05-22 14:13:02 +000087 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr ) {
Jack Jansen603e76e2002-07-22 12:35:22 +000088 /* doesn't exist or is folder */
Jack Jansen82a9b602002-09-06 20:42:27 +000089 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && PyString_Check(obj) && PyString_CHECK_INTERNED(obj) ) {
Jack Jansen603e76e2002-07-22 12:35:22 +000090 Py_INCREF(obj);
Jack Jansenb45032e2001-05-22 14:13:02 +000091 not_a_file[max_not_a_file++] = obj;
Jack Jansen603e76e2002-07-22 12:35:22 +000092 if (Py_VerboseFlag > 1)
93 PySys_WriteStderr("# %s is not a file\n", filename);
94 }
Jack Jansenb45032e2001-05-22 14:13:02 +000095 return 0;
96 }
97 if ( fssequal(&fss, &PyMac_ApplicationFSSpec) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +000098 /*
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)
102 */
103 oldrh = CurResFile();
104 UseResFile(PyMac_AppRefNum);
105 filerh = -1;
106 } else {
Jack Jansen603e76e2002-07-22 12:35:22 +0000107 if ( FSpGetFInfo(&fss, &finfo) != noErr ) {
108 /* doesn't exist or is folder */
Jack Jansen82a9b602002-09-06 20:42:27 +0000109 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && PyString_Check(obj) && PyString_CHECK_INTERNED(obj) ) {
Jack Jansen603e76e2002-07-22 12:35:22 +0000110 Py_INCREF(obj);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000111 not_a_file[max_not_a_file++] = obj;
Jack Jansen603e76e2002-07-22 12:35:22 +0000112 if (Py_VerboseFlag > 1)
113 PySys_WriteStderr("# %s is not a file\n", filename);
114 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000115 return 0;
116 }
117 oldrh = CurResFile();
118 filerh = FSpOpenResFile(&fss, fsRdPerm);
119 if ( filerh == -1 )
120 return 0;
121 UseResFile(filerh);
122 }
123 if ( dataptr == NULL )
124 SetResLoad(0);
Jack Jansen603e76e2002-07-22 12:35:22 +0000125 if (Py_VerboseFlag > 1)
126 PySys_WriteStderr("# Look for ('PYC ', %s) in %s\n", module, filename);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000127 h = Get1NamedResource(restype, Pstring(module));
128 SetResLoad(1);
129 ok = (h != NULL);
130 if ( ok && dataptr != NULL ) {
131 HLock(h);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000132 /* XXXX Unsafe if resource not correctly formatted! */
Jack Jansen017e0ff1998-07-31 09:34:47 +0000133 /* for ppc we take the first pstring */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000134 *dataptr = **h;
135 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
136 HUnlock(h);
137 }
138 if ( filerh != -1 )
139 CloseResFile(filerh);
140 UseResFile(oldrh);
141 return ok;
142}
143
144/*
145** Returns true if the argument has a resource fork, and it contains
146** a 'PYC ' resource of the correct name
147*/
148int
149PyMac_FindResourceModule(obj, module, filename)
150PyStringObject *obj;
151char *module;
152char *filename;
153{
154 int ok;
155
156 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
157 return ok;
158}
159
160/*
161** Returns true if the argument has a resource fork, and it contains
162** a 'PYD ' resource of the correct name
163*/
164int
165PyMac_FindCodeResourceModule(obj, module, filename)
166PyStringObject *obj;
167char *module;
168char *filename;
169{
170 int ok;
171
172 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
173 return ok;
174}
175
176
177/*
178** Load the specified module from a code resource
179*/
180PyObject *
181PyMac_LoadCodeResourceModule(name, pathname)
182 char *name;
183 char *pathname;
184{
Jack Jansen017e0ff1998-07-31 09:34:47 +0000185 PyObject *m, *d, *s;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000186 char funcname[258];
187 char *lastdot, *shortname, *packagecontext;
188 dl_funcptr p = NULL;
189 Str255 fragmentname;
190 CFragConnectionID connID;
191 Ptr mainAddr;
192 Str255 errMessage;
193 OSErr err;
194 char buf[512];
195 Ptr symAddr;
196 CFragSymbolClass class;
197
198 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
199 Py_INCREF(m);
200 return m;
201 }
202 lastdot = strrchr(name, '.');
203 if (lastdot == NULL) {
204 packagecontext = NULL;
205 shortname = name;
206 }
207 else {
208 packagecontext = name;
209 shortname = lastdot+1;
210 }
Jack Jansen101de912001-12-05 23:27:58 +0000211 PyOS_snprintf(funcname, sizeof(funcname), FUNCNAME_PATTERN, shortname);
Just van Rossum0297dca2001-06-26 06:54:33 +0000212 if( !findnamedresource((PyStringObject *)0, name, pathname, 'PYD ', fragmentname)) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000213 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
214 return NULL;
215 }
216
217 /* Load the fragment
218 (or return the connID if it is already loaded */
219 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
220 kLoadCFrag, &connID, &mainAddr,
221 errMessage);
222 if ( err ) {
Jack Jansen101de912001-12-05 23:27:58 +0000223 PyOS_snprintf(buf, sizeof(buf), "%.*s: %.200s",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000224 errMessage[0], errMessage+1,
225 PyMac_StrError(err));
226 PyErr_SetString(PyExc_ImportError, buf);
227 return NULL;
228 }
229 /* Locate the address of the correct init function */
230 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
231 if ( err ) {
Jack Jansen101de912001-12-05 23:27:58 +0000232 PyOS_snprintf(buf, sizeof(buf), "%s: %.200s",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000233 funcname, PyMac_StrError(err));
234 PyErr_SetString(PyExc_ImportError, buf);
235 return NULL;
236 }
237 p = (dl_funcptr)symAddr;
238 if (p == NULL) {
239 PyErr_Format(PyExc_ImportError,
240 "dynamic module does not define init function (%.200s)",
241 funcname);
242 return NULL;
243 }
244 _Py_PackageContext = packagecontext;
245 (*p)();
246 _Py_PackageContext = NULL;
247 if (PyErr_Occurred())
248 return NULL;
249 if (_PyImport_FixupExtension(name, name) == NULL)
250 return NULL;
251
252 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
253 if (m == NULL) {
254 PyErr_SetString(PyExc_SystemError,
255 "dynamic module not initialized properly");
256 return NULL;
257 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000258 /* 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 */
263 Py_XDECREF(s);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000264 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000265 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000266 name, fragmentname, pathname);
267 Py_INCREF(m);
268 return m;
269}
270
271/*
272** Load the specified module from a resource
273*/
274PyObject *
275PyMac_LoadResourceModule(module, filename)
276char *module;
277char *filename;
278{
279 FSSpec fss;
280 FInfo finfo;
281 short oldrh, filerh;
282 Handle h;
283 OSErr err;
284 PyObject *m, *co;
285 long num, size;
286
Jack Jansenb45032e2001-05-22 14:13:02 +0000287 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
Jack Jansenb45032e2001-05-22 14:13:02 +0000288 goto error;
289 if ( fssequal(&fss, &PyMac_ApplicationFSSpec) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000290 /*
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)
294 */
295 oldrh = CurResFile();
296 UseResFile(PyMac_AppRefNum);
297 filerh = -1;
298 } else {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000299 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
300 goto error;
301 oldrh = CurResFile();
302 filerh = FSpOpenResFile(&fss, fsRdPerm);
303 if ( filerh == -1 ) {
304 err = ResError();
305 goto error;
306 }
307 UseResFile(filerh);
308 }
309 h = Get1NamedResource('PYC ', Pstring(module));
310 if ( h == NULL ) {
311 err = ResError();
312 goto error;
313 }
314 HLock(h);
315 /*
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
318 */
319 size = GetHandleSize(h);
320 if ( size < 8 ) {
321 PyErr_SetString(PyExc_ImportError, "Resource too small");
322 co = NULL;
323 } else {
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");
330 co = NULL;
331 } else {
332 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
Jack Jansenb93f5211998-08-18 12:23:11 +0000333 /*
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)
338 */
339 if ((*h)[4] & 0xff) {
340 /* it's a package */
341 /* Set __path__ to the package name */
342 PyObject *d, *s;
343 int err;
344
345 m = PyImport_AddModule(module);
346 if (m == NULL) {
347 co = NULL;
348 goto packageerror;
349 }
350 d = PyModule_GetDict(m);
351 s = PyString_InternFromString(module);
352 if (s == NULL) {
353 co = NULL;
354 goto packageerror;
355 }
356 err = PyDict_SetItemString(d, "__path__", s);
357 Py_DECREF(s);
358 if (err != 0) {
359 co = NULL;
360 goto packageerror;
361 }
362 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000363 }
364 }
Jack Jansenb93f5211998-08-18 12:23:11 +0000365packageerror:
Jack Jansen1e2260f1998-07-13 13:37:12 +0000366 HUnlock(h);
367 if ( filerh != -1 )
368 CloseResFile(filerh);
Jack Jansenadd8b242001-02-21 15:48:19 +0000369 else
370 ReleaseResource(h);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000371 UseResFile(oldrh);
372 if ( co ) {
Jack Jansenb93f5211998-08-18 12:23:11 +0000373 m = PyImport_ExecCodeModuleEx(module, co, "<pyc resource>");
Jack Jansen1e2260f1998-07-13 13:37:12 +0000374 Py_DECREF(co);
375 } else {
376 m = NULL;
377 }
378 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000379 PySys_WriteStderr("import %s # pyc resource from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000380 module, filename);
381 return m;
382error:
383 {
384 char buf[512];
385
Jack Jansen101de912001-12-05 23:27:58 +0000386 PyOS_snprintf(buf, sizeof(buf), "%s: %s", filename, PyMac_StrError(err));
Jack Jansen1e2260f1998-07-13 13:37:12 +0000387 PyErr_SetString(PyExc_ImportError, buf);
388 return NULL;
389 }
390}
391
392/*
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).
396*/
397struct filedescr *
Jack Jansenfe38d292000-07-03 23:53:40 +0000398PyMac_FindModuleExtension(char *buf, size_t *lenp, char *module)
Jack Jansen1e2260f1998-07-13 13:37:12 +0000399{
400 struct filedescr *fdp;
401 unsigned char fnbuf[64];
402 int modnamelen = strlen(module);
403 FSSpec fss;
404 short refnum;
405 long dirid;
406
407 /*
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.
411 */
412 if ( !_PyImport_Filetab[0].suffix )
413 return 0;
414
Jack Jansen1e2260f1998-07-13 13:37:12 +0000415 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000416 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
417 return _PyImport_Filetab;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000418 /*
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.
421 */
422 refnum = fss.vRefNum;
423 dirid = fss.parID;
424 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
425 return 0;
426 /*
427 ** We now have the folder parameters. Setup the field for the filename
428 */
429 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
430 strcpy((char *)fnbuf+1, module);
Jack Jansen80c85d82001-11-05 14:36:32 +0000431 buf[*lenp] = '\0';
Jack Jansen1e2260f1998-07-13 13:37:12 +0000432
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)
Jack Jansendeff89c1998-10-12 20:53:15 +0000437 PySys_WriteStderr("# trying %s%s\n", buf, fdp->suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000438 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
439 /* Found it. */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000440 strcpy(buf+*lenp, fdp->suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000441 return fdp;
442 }
443 }
444 return 0;
445}