blob: 82d64385950676f75af214abebd710d29120db97 [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! */
Jack Jansen017e0ff1998-07-31 09:34:47 +0000148 /* for ppc we take the first pstring */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000149 *dataptr = **h;
150 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
151 HUnlock(h);
152 }
153 if ( filerh != -1 )
154 CloseResFile(filerh);
155 UseResFile(oldrh);
156 return ok;
157}
158
159/*
160** Returns true if the argument has a resource fork, and it contains
161** a 'PYC ' resource of the correct name
162*/
163int
164PyMac_FindResourceModule(obj, module, filename)
165PyStringObject *obj;
166char *module;
167char *filename;
168{
169 int ok;
170
171 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
172 return ok;
173}
174
175/*
176** Returns true if the argument has a resource fork, and it contains
177** a 'PYD ' resource of the correct name
178*/
179int
180PyMac_FindCodeResourceModule(obj, module, filename)
181PyStringObject *obj;
182char *module;
183char *filename;
184{
185 int ok;
186
187 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
188 return ok;
189}
190
191
192/*
193** Load the specified module from a code resource
194*/
195PyObject *
196PyMac_LoadCodeResourceModule(name, pathname)
197 char *name;
198 char *pathname;
199{
Jack Jansen017e0ff1998-07-31 09:34:47 +0000200 PyObject *m, *d, *s;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000201 char funcname[258];
202 char *lastdot, *shortname, *packagecontext;
203 dl_funcptr p = NULL;
204 Str255 fragmentname;
205 CFragConnectionID connID;
206 Ptr mainAddr;
207 Str255 errMessage;
208 OSErr err;
209 char buf[512];
210 Ptr symAddr;
211 CFragSymbolClass class;
212
213 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
214 Py_INCREF(m);
215 return m;
216 }
217 lastdot = strrchr(name, '.');
218 if (lastdot == NULL) {
219 packagecontext = NULL;
220 shortname = name;
221 }
222 else {
223 packagecontext = name;
224 shortname = lastdot+1;
225 }
226 sprintf(funcname, FUNCNAME_PATTERN, shortname);
Just van Rossum0297dca2001-06-26 06:54:33 +0000227 if( !findnamedresource((PyStringObject *)0, name, pathname, 'PYD ', fragmentname)) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000228 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
229 return NULL;
230 }
231
232 /* Load the fragment
233 (or return the connID if it is already loaded */
234 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
235 kLoadCFrag, &connID, &mainAddr,
236 errMessage);
237 if ( err ) {
238 sprintf(buf, "%.*s: %.200s",
239 errMessage[0], errMessage+1,
240 PyMac_StrError(err));
241 PyErr_SetString(PyExc_ImportError, buf);
242 return NULL;
243 }
244 /* Locate the address of the correct init function */
245 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
246 if ( err ) {
247 sprintf(buf, "%s: %.200s",
248 funcname, PyMac_StrError(err));
249 PyErr_SetString(PyExc_ImportError, buf);
250 return NULL;
251 }
252 p = (dl_funcptr)symAddr;
253 if (p == NULL) {
254 PyErr_Format(PyExc_ImportError,
255 "dynamic module does not define init function (%.200s)",
256 funcname);
257 return NULL;
258 }
259 _Py_PackageContext = packagecontext;
260 (*p)();
261 _Py_PackageContext = NULL;
262 if (PyErr_Occurred())
263 return NULL;
264 if (_PyImport_FixupExtension(name, name) == NULL)
265 return NULL;
266
267 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
268 if (m == NULL) {
269 PyErr_SetString(PyExc_SystemError,
270 "dynamic module not initialized properly");
271 return NULL;
272 }
Jack Jansen017e0ff1998-07-31 09:34:47 +0000273#if 1
Jack Jansen1e2260f1998-07-13 13:37:12 +0000274 /* 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 */
279 Py_XDECREF(s);
280#endif
281 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000282 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000283 name, fragmentname, pathname);
284 Py_INCREF(m);
285 return m;
286}
287
288/*
289** Load the specified module from a resource
290*/
291PyObject *
292PyMac_LoadResourceModule(module, filename)
293char *module;
294char *filename;
295{
296 FSSpec fss;
297 FInfo finfo;
298 short oldrh, filerh;
299 Handle h;
300 OSErr err;
301 PyObject *m, *co;
302 long num, size;
303
Jack Jansenb45032e2001-05-22 14:13:02 +0000304#ifdef USE_GUSI1
305 if ( (err=Path2FSSpec(filename, &fss)) != noErr ||
306 FSpGetFInfo(&fss, &finfo) != noErr )
307#else
308 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
309#endif
310 goto error;
311 if ( fssequal(&fss, &PyMac_ApplicationFSSpec) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000312 /*
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)
316 */
317 oldrh = CurResFile();
318 UseResFile(PyMac_AppRefNum);
319 filerh = -1;
320 } else {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000321 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
322 goto error;
323 oldrh = CurResFile();
324 filerh = FSpOpenResFile(&fss, fsRdPerm);
325 if ( filerh == -1 ) {
326 err = ResError();
327 goto error;
328 }
329 UseResFile(filerh);
330 }
331 h = Get1NamedResource('PYC ', Pstring(module));
332 if ( h == NULL ) {
333 err = ResError();
334 goto error;
335 }
336 HLock(h);
337 /*
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
340 */
341 size = GetHandleSize(h);
342 if ( size < 8 ) {
343 PyErr_SetString(PyExc_ImportError, "Resource too small");
344 co = NULL;
345 } else {
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");
352 co = NULL;
353 } else {
354 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
Jack Jansenb93f5211998-08-18 12:23:11 +0000355 /*
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)
360 */
361 if ((*h)[4] & 0xff) {
362 /* it's a package */
363 /* Set __path__ to the package name */
364 PyObject *d, *s;
365 int err;
366
367 m = PyImport_AddModule(module);
368 if (m == NULL) {
369 co = NULL;
370 goto packageerror;
371 }
372 d = PyModule_GetDict(m);
373 s = PyString_InternFromString(module);
374 if (s == NULL) {
375 co = NULL;
376 goto packageerror;
377 }
378 err = PyDict_SetItemString(d, "__path__", s);
379 Py_DECREF(s);
380 if (err != 0) {
381 co = NULL;
382 goto packageerror;
383 }
384 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000385 }
386 }
Jack Jansenb93f5211998-08-18 12:23:11 +0000387packageerror:
Jack Jansen1e2260f1998-07-13 13:37:12 +0000388 HUnlock(h);
389 if ( filerh != -1 )
390 CloseResFile(filerh);
Jack Jansenadd8b242001-02-21 15:48:19 +0000391 else
392 ReleaseResource(h);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000393 UseResFile(oldrh);
394 if ( co ) {
Jack Jansenb93f5211998-08-18 12:23:11 +0000395 m = PyImport_ExecCodeModuleEx(module, co, "<pyc resource>");
Jack Jansen1e2260f1998-07-13 13:37:12 +0000396 Py_DECREF(co);
397 } else {
398 m = NULL;
399 }
400 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000401 PySys_WriteStderr("import %s # pyc resource from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000402 module, filename);
403 return m;
404error:
405 {
406 char buf[512];
407
408 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
409 PyErr_SetString(PyExc_ImportError, buf);
410 return NULL;
411 }
412}
413
414/*
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).
418*/
419struct filedescr *
Jack Jansenfe38d292000-07-03 23:53:40 +0000420PyMac_FindModuleExtension(char *buf, size_t *lenp, char *module)
Jack Jansen1e2260f1998-07-13 13:37:12 +0000421{
422 struct filedescr *fdp;
423 unsigned char fnbuf[64];
424 int modnamelen = strlen(module);
425 FSSpec fss;
Jack Jansen9ae898b2000-07-11 21:16:03 +0000426#ifdef USE_GUSI1
Jack Jansen48a9c361998-09-07 11:36:17 +0000427 FInfo finfo;
Jack Jansen9ae898b2000-07-11 21:16:03 +0000428#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000429 short refnum;
430 long dirid;
431
432 /*
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.
436 */
437 if ( !_PyImport_Filetab[0].suffix )
438 return 0;
439
440#if 0
441 /* Pre 1.5a4 */
442 strcpy(buf+*lenp, module);
443 strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix);
444#else
445 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
446#endif
Jack Jansen2d1306b2000-04-07 09:10:49 +0000447#ifdef USE_GUSI1
Jack Jansen48a9c361998-09-07 11:36:17 +0000448 if ( Path2FSSpec(buf, &fss) == noErr &&
449 FSpGetFInfo(&fss, &finfo) == noErr)
450 return _PyImport_Filetab;
451#else
Jack Jansen1e2260f1998-07-13 13:37:12 +0000452 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
453 return _PyImport_Filetab;
Jack Jansen48a9c361998-09-07 11:36:17 +0000454#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000455 /*
456 ** We cannot check for fnfErr (unfortunately), it can mean either that
457 ** the file doesn't exist (fine, we try others) or the path leading to it.
458 */
459 refnum = fss.vRefNum;
460 dirid = fss.parID;
461 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
462 return 0;
463 /*
464 ** We now have the folder parameters. Setup the field for the filename
465 */
466 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
467 strcpy((char *)fnbuf+1, module);
468
469 for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
470 strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
471 fnbuf[0] = strlen((char *)fnbuf+1);
472 if (Py_VerboseFlag > 1)
Jack Jansendeff89c1998-10-12 20:53:15 +0000473 PySys_WriteStderr("# trying %s%s\n", buf, fdp->suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000474 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
475 /* Found it. */
476#if 0
477 strcpy(buf+*lenp+modnamelen, fdp->suffix);
478#else
479 strcpy(buf+*lenp, fdp->suffix);
480#endif
481 *lenp = strlen(buf);
482 return fdp;
483 }
484 }
485 return 0;
486}