blob: 627f828a10f50518e9a962cd4c2e3e525cd987dc [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>
50
Jack Jansen48a9c361998-09-07 11:36:17 +000051#ifdef USE_GUSI
52#include "TFileSpec.h" /* for Path2FSSpec() */
53#endif
54
Jack Jansen1e2260f1998-07-13 13:37:12 +000055typedef void (*dl_funcptr)();
56#define FUNCNAME_PATTERN "init%.200s"
57
58/*
59** findnamedresource - Common code for the various *ResourceModule functions.
60** Check whether a file contains a resource of the correct name and type, and
61** optionally return the value in it.
62*/
63static int
64findnamedresource(
65 PyStringObject *obj,
66 char *module,
67 char *filename,
68 OSType restype,
69 StringPtr dataptr)
70{
71 FSSpec fss;
72 FInfo finfo;
73 short oldrh, filerh;
74 int ok;
75 Handle h;
76
77#ifdef INTERN_STRINGS
78 /*
79 ** If we have interning find_module takes care of interning all
80 ** sys.path components. We then keep a record of all sys.path
81 ** components for which GetFInfo has failed (usually because the
82 ** component in question is a folder), and we don't try opening these
83 ** as resource files again.
84 */
85#define MAXPATHCOMPONENTS 32
86 static PyStringObject *not_a_file[MAXPATHCOMPONENTS];
87 static int max_not_a_file = 0;
88 int i;
89
90 if (obj && obj->ob_sinterned ) {
91 for( i=0; i< max_not_a_file; i++ )
92 if ( obj == not_a_file[i] )
93 return 0;
94 }
95#endif /* INTERN_STRINGS */
96
97 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
98 /*
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 Jansen48a9c361998-09-07 11:36:17 +0000107#ifdef USE_GUSI
108 if ( Path2FSSpec(filename, &fss) != noErr ||
109#else
Jack Jansen1e2260f1998-07-13 13:37:12 +0000110 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr ||
Jack Jansen48a9c361998-09-07 11:36:17 +0000111#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000112 FSpGetFInfo(&fss, &finfo) != noErr ) {
113#ifdef INTERN_STRINGS
114 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned )
115 not_a_file[max_not_a_file++] = obj;
116#endif /* INTERN_STRINGS */
117 /* doesn't exist or is folder */
118 return 0;
119 }
120 oldrh = CurResFile();
121 filerh = FSpOpenResFile(&fss, fsRdPerm);
122 if ( filerh == -1 )
123 return 0;
124 UseResFile(filerh);
125 }
126 if ( dataptr == NULL )
127 SetResLoad(0);
128 h = Get1NamedResource(restype, Pstring(module));
129 SetResLoad(1);
130 ok = (h != NULL);
131 if ( ok && dataptr != NULL ) {
132 HLock(h);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000133 /* XXXX Unsafe if resource not correctly formatted! */
134#ifdef __CFM68K__
135 /* for cfm68k we take the second pstring */
136 *dataptr = *((*h)+(**h)+1);
137 memcpy(dataptr+1, (*h)+(**h)+2, (int)*dataptr);
138#else
139 /* for ppc we take the first pstring */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000140 *dataptr = **h;
141 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000142#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000143 HUnlock(h);
144 }
145 if ( filerh != -1 )
146 CloseResFile(filerh);
147 UseResFile(oldrh);
148 return ok;
149}
150
151/*
152** Returns true if the argument has a resource fork, and it contains
153** a 'PYC ' resource of the correct name
154*/
155int
156PyMac_FindResourceModule(obj, module, filename)
157PyStringObject *obj;
158char *module;
159char *filename;
160{
161 int ok;
162
163 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
164 return ok;
165}
166
167/*
168** Returns true if the argument has a resource fork, and it contains
169** a 'PYD ' resource of the correct name
170*/
171int
172PyMac_FindCodeResourceModule(obj, module, filename)
173PyStringObject *obj;
174char *module;
175char *filename;
176{
177 int ok;
178
179 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
180 return ok;
181}
182
183
184/*
185** Load the specified module from a code resource
186*/
187PyObject *
188PyMac_LoadCodeResourceModule(name, pathname)
189 char *name;
190 char *pathname;
191{
Jack Jansen017e0ff1998-07-31 09:34:47 +0000192 PyObject *m, *d, *s;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000193 char funcname[258];
194 char *lastdot, *shortname, *packagecontext;
195 dl_funcptr p = NULL;
196 Str255 fragmentname;
197 CFragConnectionID connID;
198 Ptr mainAddr;
199 Str255 errMessage;
200 OSErr err;
201 char buf[512];
202 Ptr symAddr;
203 CFragSymbolClass class;
204
205 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
206 Py_INCREF(m);
207 return m;
208 }
209 lastdot = strrchr(name, '.');
210 if (lastdot == NULL) {
211 packagecontext = NULL;
212 shortname = name;
213 }
214 else {
215 packagecontext = name;
216 shortname = lastdot+1;
217 }
218 sprintf(funcname, FUNCNAME_PATTERN, shortname);
219 if( !findnamedresource((PyStringObject *)0, shortname, pathname, 'PYD ', fragmentname)) {
220 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
221 return NULL;
222 }
223
224 /* Load the fragment
225 (or return the connID if it is already loaded */
226 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
227 kLoadCFrag, &connID, &mainAddr,
228 errMessage);
229 if ( err ) {
230 sprintf(buf, "%.*s: %.200s",
231 errMessage[0], errMessage+1,
232 PyMac_StrError(err));
233 PyErr_SetString(PyExc_ImportError, buf);
234 return NULL;
235 }
236 /* Locate the address of the correct init function */
237 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
238 if ( err ) {
239 sprintf(buf, "%s: %.200s",
240 funcname, PyMac_StrError(err));
241 PyErr_SetString(PyExc_ImportError, buf);
242 return NULL;
243 }
244 p = (dl_funcptr)symAddr;
245 if (p == NULL) {
246 PyErr_Format(PyExc_ImportError,
247 "dynamic module does not define init function (%.200s)",
248 funcname);
249 return NULL;
250 }
251 _Py_PackageContext = packagecontext;
252 (*p)();
253 _Py_PackageContext = NULL;
254 if (PyErr_Occurred())
255 return NULL;
256 if (_PyImport_FixupExtension(name, name) == NULL)
257 return NULL;
258
259 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
260 if (m == NULL) {
261 PyErr_SetString(PyExc_SystemError,
262 "dynamic module not initialized properly");
263 return NULL;
264 }
Jack Jansen017e0ff1998-07-31 09:34:47 +0000265#if 1
Jack Jansen1e2260f1998-07-13 13:37:12 +0000266 /* Remember the filename as the __file__ attribute */
267 d = PyModule_GetDict(m);
268 s = PyString_FromString(pathname);
269 if (s == NULL || PyDict_SetItemString(d, "__file__", s) != 0)
270 PyErr_Clear(); /* Not important enough to report */
271 Py_XDECREF(s);
272#endif
273 if (Py_VerboseFlag)
274 fprintf(stderr,
275 "import %s # pyd fragment %#s loaded from %s\n",
276 name, fragmentname, pathname);
277 Py_INCREF(m);
278 return m;
279}
280
281/*
282** Load the specified module from a resource
283*/
284PyObject *
285PyMac_LoadResourceModule(module, filename)
286char *module;
287char *filename;
288{
289 FSSpec fss;
290 FInfo finfo;
291 short oldrh, filerh;
292 Handle h;
293 OSErr err;
294 PyObject *m, *co;
295 long num, size;
296
297 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
298 /*
299 ** Special case: the application itself. Use a shortcut to
300 ** forestall opening and closing the application numerous times
301 ** (which is dead slow when running from CDROM)
302 */
303 oldrh = CurResFile();
304 UseResFile(PyMac_AppRefNum);
305 filerh = -1;
306 } else {
Jack Jansen48a9c361998-09-07 11:36:17 +0000307#ifdef USE_GUSI
308 if ( (err=Path2FSSpec(filename, &fss)) != noErr ||
309 FSpGetFInfo(&fss, &finfo) != noErr )
310#else
Jack Jansen1e2260f1998-07-13 13:37:12 +0000311 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
Jack Jansen48a9c361998-09-07 11:36:17 +0000312#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000313 goto error;
314 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
315 goto error;
316 oldrh = CurResFile();
317 filerh = FSpOpenResFile(&fss, fsRdPerm);
318 if ( filerh == -1 ) {
319 err = ResError();
320 goto error;
321 }
322 UseResFile(filerh);
323 }
324 h = Get1NamedResource('PYC ', Pstring(module));
325 if ( h == NULL ) {
326 err = ResError();
327 goto error;
328 }
329 HLock(h);
330 /*
331 ** XXXX The next few lines are intimately tied to the format of pyc
332 ** files. I'm not sure whether this code should be here or in import.c -- Jack
333 */
334 size = GetHandleSize(h);
335 if ( size < 8 ) {
336 PyErr_SetString(PyExc_ImportError, "Resource too small");
337 co = NULL;
338 } else {
339 num = (*h)[0] & 0xff;
340 num = num | (((*h)[1] & 0xff) << 8);
341 num = num | (((*h)[2] & 0xff) << 16);
342 num = num | (((*h)[3] & 0xff) << 24);
343 if ( num != PyImport_GetMagicNumber() ) {
344 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
345 co = NULL;
346 } else {
347 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
Jack Jansenb93f5211998-08-18 12:23:11 +0000348 /*
349 ** Normally, byte 4-7 are the time stamp, but that is not used
350 ** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
351 ** that it is a package rather than an ordinary module.
352 ** See also py_resource.py. (jvr)
353 */
354 if ((*h)[4] & 0xff) {
355 /* it's a package */
356 /* Set __path__ to the package name */
357 PyObject *d, *s;
358 int err;
359
360 m = PyImport_AddModule(module);
361 if (m == NULL) {
362 co = NULL;
363 goto packageerror;
364 }
365 d = PyModule_GetDict(m);
366 s = PyString_InternFromString(module);
367 if (s == NULL) {
368 co = NULL;
369 goto packageerror;
370 }
371 err = PyDict_SetItemString(d, "__path__", s);
372 Py_DECREF(s);
373 if (err != 0) {
374 co = NULL;
375 goto packageerror;
376 }
377 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000378 }
379 }
Jack Jansenb93f5211998-08-18 12:23:11 +0000380packageerror:
Jack Jansen1e2260f1998-07-13 13:37:12 +0000381 HUnlock(h);
382 if ( filerh != -1 )
383 CloseResFile(filerh);
384 UseResFile(oldrh);
385 if ( co ) {
Jack Jansenb93f5211998-08-18 12:23:11 +0000386 m = PyImport_ExecCodeModuleEx(module, co, "<pyc resource>");
Jack Jansen1e2260f1998-07-13 13:37:12 +0000387 Py_DECREF(co);
388 } else {
389 m = NULL;
390 }
391 if (Py_VerboseFlag)
392 fprintf(stderr, "import %s # pyc resource from %s\n",
393 module, filename);
394 return m;
395error:
396 {
397 char buf[512];
398
399 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
400 PyErr_SetString(PyExc_ImportError, buf);
401 return NULL;
402 }
403}
404
405/*
406** Look for a module in a single folder. Upon entry buf and len
407** point to the folder to search, upon exit they refer to the full
408** pathname of the module found (if any).
409*/
410struct filedescr *
411PyMac_FindModuleExtension(char *buf, int *lenp, char *module)
412{
413 struct filedescr *fdp;
414 unsigned char fnbuf[64];
415 int modnamelen = strlen(module);
416 FSSpec fss;
Jack Jansen48a9c361998-09-07 11:36:17 +0000417 FInfo finfo;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000418 short refnum;
419 long dirid;
420
421 /*
422 ** Copy the module name to the buffer (already :-terminated)
423 ** We also copy the first suffix, if this matches immedeately we're
424 ** lucky and return immedeately.
425 */
426 if ( !_PyImport_Filetab[0].suffix )
427 return 0;
428
429#if 0
430 /* Pre 1.5a4 */
431 strcpy(buf+*lenp, module);
432 strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix);
433#else
434 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
435#endif
Jack Jansen48a9c361998-09-07 11:36:17 +0000436#ifdef USE_GUSI
437 if ( Path2FSSpec(buf, &fss) == noErr &&
438 FSpGetFInfo(&fss, &finfo) == noErr)
439 return _PyImport_Filetab;
440#else
Jack Jansen1e2260f1998-07-13 13:37:12 +0000441 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
442 return _PyImport_Filetab;
Jack Jansen48a9c361998-09-07 11:36:17 +0000443#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000444 /*
445 ** We cannot check for fnfErr (unfortunately), it can mean either that
446 ** the file doesn't exist (fine, we try others) or the path leading to it.
447 */
448 refnum = fss.vRefNum;
449 dirid = fss.parID;
450 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
451 return 0;
452 /*
453 ** We now have the folder parameters. Setup the field for the filename
454 */
455 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
456 strcpy((char *)fnbuf+1, module);
457
458 for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
459 strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
460 fnbuf[0] = strlen((char *)fnbuf+1);
461 if (Py_VerboseFlag > 1)
462 fprintf(stderr, "# trying %s%s\n", buf, fdp->suffix);
463 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
464 /* Found it. */
465#if 0
466 strcpy(buf+*lenp+modnamelen, fdp->suffix);
467#else
468 strcpy(buf+*lenp, fdp->suffix);
469#endif
470 *lenp = strlen(buf);
471 return fdp;
472 }
473 }
474 return 0;
475}