blob: b47a6940f507cd255801d2446f8cbd4bf9bcc071 [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>
38#if 0
39#include <OSUtils.h> /* for Set(Current)A5 */
40#include <StandardFile.h>
41#include <Memory.h>
42#include <Windows.h>
43#include <Traps.h>
44#include <Processes.h>
45#include <Fonts.h>
46#include <Menus.h>
47#include <TextUtils.h>
48#endif
49#include <CodeFragments.h>
Jack Jansenb45032e2001-05-22 14:13:02 +000050#include <StringCompare.h>
Jack Jansen1e2260f1998-07-13 13:37:12 +000051
Jack Jansen2d1306b2000-04-07 09:10:49 +000052#ifdef USE_GUSI1
Jack Jansen48a9c361998-09-07 11:36:17 +000053#include "TFileSpec.h" /* for Path2FSSpec() */
54#endif
55
Jack Jansen1e2260f1998-07-13 13:37:12 +000056typedef void (*dl_funcptr)();
57#define FUNCNAME_PATTERN "init%.200s"
58
Jack Jansenb45032e2001-05-22 14:13:02 +000059static int
60fssequal(FSSpec *fs1, FSSpec *fs2)
61{
62 if ( fs1->vRefNum != fs2->vRefNum || fs1->parID != fs2->parID )
63 return 0;
64 return EqualString(fs1->name, fs2->name, false, true);
65}
Jack Jansen1e2260f1998-07-13 13:37:12 +000066/*
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.
70*/
71static int
72findnamedresource(
73 PyStringObject *obj,
74 char *module,
75 char *filename,
76 OSType restype,
77 StringPtr dataptr)
78{
79 FSSpec fss;
80 FInfo finfo;
81 short oldrh, filerh;
82 int ok;
83 Handle h;
84
85#ifdef INTERN_STRINGS
86 /*
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.
92 */
93#define MAXPATHCOMPONENTS 32
94 static PyStringObject *not_a_file[MAXPATHCOMPONENTS];
95 static int max_not_a_file = 0;
96 int i;
97
98 if (obj && obj->ob_sinterned ) {
99 for( i=0; i< max_not_a_file; i++ )
100 if ( obj == not_a_file[i] )
101 return 0;
102 }
103#endif /* INTERN_STRINGS */
Jack Jansenb45032e2001-05-22 14:13:02 +0000104#ifdef USE_GUSI1
105 if ( Path2FSSpec(filename, &fss) != noErr ) {
106#else
107 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr ) {
108#endif
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 */
114 return 0;
115 }
116 if ( fssequal(&fss, &PyMac_ApplicationFSSpec) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000117 /*
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)
121 */
122 oldrh = CurResFile();
123 UseResFile(PyMac_AppRefNum);
124 filerh = -1;
125 } else {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000126#ifdef INTERN_STRINGS
Jack Jansenb45032e2001-05-22 14:13:02 +0000127 if ( FSpGetFInfo(&fss, &finfo) != noErr ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000128 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned )
129 not_a_file[max_not_a_file++] = obj;
Jack Jansenb45032e2001-05-22 14:13:02 +0000130 /* doesn't exist or is folder */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000131 return 0;
132 }
Jack Jansenb45032e2001-05-22 14:13:02 +0000133#endif /* INTERN_STRINGS */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000134 oldrh = CurResFile();
135 filerh = FSpOpenResFile(&fss, fsRdPerm);
136 if ( filerh == -1 )
137 return 0;
138 UseResFile(filerh);
139 }
140 if ( dataptr == NULL )
141 SetResLoad(0);
142 h = Get1NamedResource(restype, Pstring(module));
143 SetResLoad(1);
144 ok = (h != NULL);
145 if ( ok && dataptr != NULL ) {
146 HLock(h);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000147 /* XXXX Unsafe if resource not correctly formatted! */
148#ifdef __CFM68K__
149 /* for cfm68k we take the second pstring */
150 *dataptr = *((*h)+(**h)+1);
151 memcpy(dataptr+1, (*h)+(**h)+2, (int)*dataptr);
152#else
153 /* for ppc we take the first pstring */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000154 *dataptr = **h;
155 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000156#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000157 HUnlock(h);
158 }
159 if ( filerh != -1 )
160 CloseResFile(filerh);
161 UseResFile(oldrh);
162 return ok;
163}
164
165/*
166** Returns true if the argument has a resource fork, and it contains
167** a 'PYC ' resource of the correct name
168*/
169int
170PyMac_FindResourceModule(obj, module, filename)
171PyStringObject *obj;
172char *module;
173char *filename;
174{
175 int ok;
176
177 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
178 return ok;
179}
180
181/*
182** Returns true if the argument has a resource fork, and it contains
183** a 'PYD ' resource of the correct name
184*/
185int
186PyMac_FindCodeResourceModule(obj, module, filename)
187PyStringObject *obj;
188char *module;
189char *filename;
190{
191 int ok;
192
193 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
194 return ok;
195}
196
197
198/*
199** Load the specified module from a code resource
200*/
201PyObject *
202PyMac_LoadCodeResourceModule(name, pathname)
203 char *name;
204 char *pathname;
205{
Jack Jansen017e0ff1998-07-31 09:34:47 +0000206 PyObject *m, *d, *s;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000207 char funcname[258];
208 char *lastdot, *shortname, *packagecontext;
209 dl_funcptr p = NULL;
210 Str255 fragmentname;
211 CFragConnectionID connID;
212 Ptr mainAddr;
213 Str255 errMessage;
214 OSErr err;
215 char buf[512];
216 Ptr symAddr;
217 CFragSymbolClass class;
218
219 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
220 Py_INCREF(m);
221 return m;
222 }
223 lastdot = strrchr(name, '.');
224 if (lastdot == NULL) {
225 packagecontext = NULL;
226 shortname = name;
227 }
228 else {
229 packagecontext = name;
230 shortname = lastdot+1;
231 }
232 sprintf(funcname, FUNCNAME_PATTERN, shortname);
Just van Rossum0297dca2001-06-26 06:54:33 +0000233 if( !findnamedresource((PyStringObject *)0, name, pathname, 'PYD ', fragmentname)) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000234 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
235 return NULL;
236 }
237
238 /* Load the fragment
239 (or return the connID if it is already loaded */
240 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
241 kLoadCFrag, &connID, &mainAddr,
242 errMessage);
243 if ( err ) {
244 sprintf(buf, "%.*s: %.200s",
245 errMessage[0], errMessage+1,
246 PyMac_StrError(err));
247 PyErr_SetString(PyExc_ImportError, buf);
248 return NULL;
249 }
250 /* Locate the address of the correct init function */
251 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
252 if ( err ) {
253 sprintf(buf, "%s: %.200s",
254 funcname, PyMac_StrError(err));
255 PyErr_SetString(PyExc_ImportError, buf);
256 return NULL;
257 }
258 p = (dl_funcptr)symAddr;
259 if (p == NULL) {
260 PyErr_Format(PyExc_ImportError,
261 "dynamic module does not define init function (%.200s)",
262 funcname);
263 return NULL;
264 }
265 _Py_PackageContext = packagecontext;
266 (*p)();
267 _Py_PackageContext = NULL;
268 if (PyErr_Occurred())
269 return NULL;
270 if (_PyImport_FixupExtension(name, name) == NULL)
271 return NULL;
272
273 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
274 if (m == NULL) {
275 PyErr_SetString(PyExc_SystemError,
276 "dynamic module not initialized properly");
277 return NULL;
278 }
Jack Jansen017e0ff1998-07-31 09:34:47 +0000279#if 1
Jack Jansen1e2260f1998-07-13 13:37:12 +0000280 /* Remember the filename as the __file__ attribute */
281 d = PyModule_GetDict(m);
282 s = PyString_FromString(pathname);
283 if (s == NULL || PyDict_SetItemString(d, "__file__", s) != 0)
284 PyErr_Clear(); /* Not important enough to report */
285 Py_XDECREF(s);
286#endif
287 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000288 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000289 name, fragmentname, pathname);
290 Py_INCREF(m);
291 return m;
292}
293
294/*
295** Load the specified module from a resource
296*/
297PyObject *
298PyMac_LoadResourceModule(module, filename)
299char *module;
300char *filename;
301{
302 FSSpec fss;
303 FInfo finfo;
304 short oldrh, filerh;
305 Handle h;
306 OSErr err;
307 PyObject *m, *co;
308 long num, size;
309
Jack Jansenb45032e2001-05-22 14:13:02 +0000310#ifdef USE_GUSI1
311 if ( (err=Path2FSSpec(filename, &fss)) != noErr ||
312 FSpGetFInfo(&fss, &finfo) != noErr )
313#else
314 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
315#endif
316 goto error;
317 if ( fssequal(&fss, &PyMac_ApplicationFSSpec) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000318 /*
319 ** Special case: the application itself. Use a shortcut to
320 ** forestall opening and closing the application numerous times
321 ** (which is dead slow when running from CDROM)
322 */
323 oldrh = CurResFile();
324 UseResFile(PyMac_AppRefNum);
325 filerh = -1;
326 } else {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000327 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
328 goto error;
329 oldrh = CurResFile();
330 filerh = FSpOpenResFile(&fss, fsRdPerm);
331 if ( filerh == -1 ) {
332 err = ResError();
333 goto error;
334 }
335 UseResFile(filerh);
336 }
337 h = Get1NamedResource('PYC ', Pstring(module));
338 if ( h == NULL ) {
339 err = ResError();
340 goto error;
341 }
342 HLock(h);
343 /*
344 ** XXXX The next few lines are intimately tied to the format of pyc
345 ** files. I'm not sure whether this code should be here or in import.c -- Jack
346 */
347 size = GetHandleSize(h);
348 if ( size < 8 ) {
349 PyErr_SetString(PyExc_ImportError, "Resource too small");
350 co = NULL;
351 } else {
352 num = (*h)[0] & 0xff;
353 num = num | (((*h)[1] & 0xff) << 8);
354 num = num | (((*h)[2] & 0xff) << 16);
355 num = num | (((*h)[3] & 0xff) << 24);
356 if ( num != PyImport_GetMagicNumber() ) {
357 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
358 co = NULL;
359 } else {
360 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
Jack Jansenb93f5211998-08-18 12:23:11 +0000361 /*
362 ** Normally, byte 4-7 are the time stamp, but that is not used
363 ** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
364 ** that it is a package rather than an ordinary module.
365 ** See also py_resource.py. (jvr)
366 */
367 if ((*h)[4] & 0xff) {
368 /* it's a package */
369 /* Set __path__ to the package name */
370 PyObject *d, *s;
371 int err;
372
373 m = PyImport_AddModule(module);
374 if (m == NULL) {
375 co = NULL;
376 goto packageerror;
377 }
378 d = PyModule_GetDict(m);
379 s = PyString_InternFromString(module);
380 if (s == NULL) {
381 co = NULL;
382 goto packageerror;
383 }
384 err = PyDict_SetItemString(d, "__path__", s);
385 Py_DECREF(s);
386 if (err != 0) {
387 co = NULL;
388 goto packageerror;
389 }
390 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000391 }
392 }
Jack Jansenb93f5211998-08-18 12:23:11 +0000393packageerror:
Jack Jansen1e2260f1998-07-13 13:37:12 +0000394 HUnlock(h);
395 if ( filerh != -1 )
396 CloseResFile(filerh);
Jack Jansenadd8b242001-02-21 15:48:19 +0000397 else
398 ReleaseResource(h);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000399 UseResFile(oldrh);
400 if ( co ) {
Jack Jansenb93f5211998-08-18 12:23:11 +0000401 m = PyImport_ExecCodeModuleEx(module, co, "<pyc resource>");
Jack Jansen1e2260f1998-07-13 13:37:12 +0000402 Py_DECREF(co);
403 } else {
404 m = NULL;
405 }
406 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000407 PySys_WriteStderr("import %s # pyc resource from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000408 module, filename);
409 return m;
410error:
411 {
412 char buf[512];
413
414 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
415 PyErr_SetString(PyExc_ImportError, buf);
416 return NULL;
417 }
418}
419
420/*
421** Look for a module in a single folder. Upon entry buf and len
422** point to the folder to search, upon exit they refer to the full
423** pathname of the module found (if any).
424*/
425struct filedescr *
Jack Jansenfe38d292000-07-03 23:53:40 +0000426PyMac_FindModuleExtension(char *buf, size_t *lenp, char *module)
Jack Jansen1e2260f1998-07-13 13:37:12 +0000427{
428 struct filedescr *fdp;
429 unsigned char fnbuf[64];
430 int modnamelen = strlen(module);
431 FSSpec fss;
Jack Jansen9ae898b2000-07-11 21:16:03 +0000432#ifdef USE_GUSI1
Jack Jansen48a9c361998-09-07 11:36:17 +0000433 FInfo finfo;
Jack Jansen9ae898b2000-07-11 21:16:03 +0000434#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000435 short refnum;
436 long dirid;
437
438 /*
439 ** Copy the module name to the buffer (already :-terminated)
440 ** We also copy the first suffix, if this matches immedeately we're
441 ** lucky and return immedeately.
442 */
443 if ( !_PyImport_Filetab[0].suffix )
444 return 0;
445
446#if 0
447 /* Pre 1.5a4 */
448 strcpy(buf+*lenp, module);
449 strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix);
450#else
451 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
452#endif
Jack Jansen2d1306b2000-04-07 09:10:49 +0000453#ifdef USE_GUSI1
Jack Jansen48a9c361998-09-07 11:36:17 +0000454 if ( Path2FSSpec(buf, &fss) == noErr &&
455 FSpGetFInfo(&fss, &finfo) == noErr)
456 return _PyImport_Filetab;
457#else
Jack Jansen1e2260f1998-07-13 13:37:12 +0000458 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
459 return _PyImport_Filetab;
Jack Jansen48a9c361998-09-07 11:36:17 +0000460#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000461 /*
462 ** We cannot check for fnfErr (unfortunately), it can mean either that
463 ** the file doesn't exist (fine, we try others) or the path leading to it.
464 */
465 refnum = fss.vRefNum;
466 dirid = fss.parID;
467 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
468 return 0;
469 /*
470 ** We now have the folder parameters. Setup the field for the filename
471 */
472 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
473 strcpy((char *)fnbuf+1, module);
474
475 for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
476 strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
477 fnbuf[0] = strlen((char *)fnbuf+1);
478 if (Py_VerboseFlag > 1)
Jack Jansendeff89c1998-10-12 20:53:15 +0000479 PySys_WriteStderr("# trying %s%s\n", buf, fdp->suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000480 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
481 /* Found it. */
482#if 0
483 strcpy(buf+*lenp+modnamelen, fdp->suffix);
484#else
485 strcpy(buf+*lenp, fdp->suffix);
486#endif
487 *lenp = strlen(buf);
488 return fdp;
489 }
490 }
491 return 0;
492}