blob: cf9254378eac66928372e57f023fb4dbb3b72800 [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
51typedef void (*dl_funcptr)();
52#define FUNCNAME_PATTERN "init%.200s"
53
54/*
55** findnamedresource - Common code for the various *ResourceModule functions.
56** Check whether a file contains a resource of the correct name and type, and
57** optionally return the value in it.
58*/
59static int
60findnamedresource(
61 PyStringObject *obj,
62 char *module,
63 char *filename,
64 OSType restype,
65 StringPtr dataptr)
66{
67 FSSpec fss;
68 FInfo finfo;
69 short oldrh, filerh;
70 int ok;
71 Handle h;
72
73#ifdef INTERN_STRINGS
74 /*
75 ** If we have interning find_module takes care of interning all
76 ** sys.path components. We then keep a record of all sys.path
77 ** components for which GetFInfo has failed (usually because the
78 ** component in question is a folder), and we don't try opening these
79 ** as resource files again.
80 */
81#define MAXPATHCOMPONENTS 32
82 static PyStringObject *not_a_file[MAXPATHCOMPONENTS];
83 static int max_not_a_file = 0;
84 int i;
85
86 if (obj && obj->ob_sinterned ) {
87 for( i=0; i< max_not_a_file; i++ )
88 if ( obj == not_a_file[i] )
89 return 0;
90 }
91#endif /* INTERN_STRINGS */
92
93 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
94 /*
95 ** Special case: the application itself. Use a shortcut to
96 ** forestall opening and closing the application numerous times
97 ** (which is dead slow when running from CDROM)
98 */
99 oldrh = CurResFile();
100 UseResFile(PyMac_AppRefNum);
101 filerh = -1;
102 } else {
103 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr ||
104 FSpGetFInfo(&fss, &finfo) != noErr ) {
105#ifdef INTERN_STRINGS
106 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned )
107 not_a_file[max_not_a_file++] = obj;
108#endif /* INTERN_STRINGS */
109 /* doesn't exist or is folder */
110 return 0;
111 }
112 oldrh = CurResFile();
113 filerh = FSpOpenResFile(&fss, fsRdPerm);
114 if ( filerh == -1 )
115 return 0;
116 UseResFile(filerh);
117 }
118 if ( dataptr == NULL )
119 SetResLoad(0);
120 h = Get1NamedResource(restype, Pstring(module));
121 SetResLoad(1);
122 ok = (h != NULL);
123 if ( ok && dataptr != NULL ) {
124 HLock(h);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000125 /* XXXX Unsafe if resource not correctly formatted! */
126#ifdef __CFM68K__
127 /* for cfm68k we take the second pstring */
128 *dataptr = *((*h)+(**h)+1);
129 memcpy(dataptr+1, (*h)+(**h)+2, (int)*dataptr);
130#else
131 /* for ppc we take the first pstring */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000132 *dataptr = **h;
133 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000134#endif
Jack Jansen1e2260f1998-07-13 13:37:12 +0000135 HUnlock(h);
136 }
137 if ( filerh != -1 )
138 CloseResFile(filerh);
139 UseResFile(oldrh);
140 return ok;
141}
142
143/*
144** Returns true if the argument has a resource fork, and it contains
145** a 'PYC ' resource of the correct name
146*/
147int
148PyMac_FindResourceModule(obj, module, filename)
149PyStringObject *obj;
150char *module;
151char *filename;
152{
153 int ok;
154
155 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
156 return ok;
157}
158
159/*
160** Returns true if the argument has a resource fork, and it contains
161** a 'PYD ' resource of the correct name
162*/
163int
164PyMac_FindCodeResourceModule(obj, module, filename)
165PyStringObject *obj;
166char *module;
167char *filename;
168{
169 int ok;
170
171 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
172 return ok;
173}
174
175
176/*
177** Load the specified module from a code resource
178*/
179PyObject *
180PyMac_LoadCodeResourceModule(name, pathname)
181 char *name;
182 char *pathname;
183{
Jack Jansen017e0ff1998-07-31 09:34:47 +0000184 PyObject *m, *d, *s;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000185 char funcname[258];
186 char *lastdot, *shortname, *packagecontext;
187 dl_funcptr p = NULL;
188 Str255 fragmentname;
189 CFragConnectionID connID;
190 Ptr mainAddr;
191 Str255 errMessage;
192 OSErr err;
193 char buf[512];
194 Ptr symAddr;
195 CFragSymbolClass class;
196
197 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
198 Py_INCREF(m);
199 return m;
200 }
201 lastdot = strrchr(name, '.');
202 if (lastdot == NULL) {
203 packagecontext = NULL;
204 shortname = name;
205 }
206 else {
207 packagecontext = name;
208 shortname = lastdot+1;
209 }
210 sprintf(funcname, FUNCNAME_PATTERN, shortname);
211 if( !findnamedresource((PyStringObject *)0, shortname, pathname, 'PYD ', fragmentname)) {
212 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
213 return NULL;
214 }
215
216 /* Load the fragment
217 (or return the connID if it is already loaded */
218 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
219 kLoadCFrag, &connID, &mainAddr,
220 errMessage);
221 if ( err ) {
222 sprintf(buf, "%.*s: %.200s",
223 errMessage[0], errMessage+1,
224 PyMac_StrError(err));
225 PyErr_SetString(PyExc_ImportError, buf);
226 return NULL;
227 }
228 /* Locate the address of the correct init function */
229 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
230 if ( err ) {
231 sprintf(buf, "%s: %.200s",
232 funcname, PyMac_StrError(err));
233 PyErr_SetString(PyExc_ImportError, buf);
234 return NULL;
235 }
236 p = (dl_funcptr)symAddr;
237 if (p == NULL) {
238 PyErr_Format(PyExc_ImportError,
239 "dynamic module does not define init function (%.200s)",
240 funcname);
241 return NULL;
242 }
243 _Py_PackageContext = packagecontext;
244 (*p)();
245 _Py_PackageContext = NULL;
246 if (PyErr_Occurred())
247 return NULL;
248 if (_PyImport_FixupExtension(name, name) == NULL)
249 return NULL;
250
251 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
252 if (m == NULL) {
253 PyErr_SetString(PyExc_SystemError,
254 "dynamic module not initialized properly");
255 return NULL;
256 }
Jack Jansen017e0ff1998-07-31 09:34:47 +0000257#if 1
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);
264#endif
265 if (Py_VerboseFlag)
266 fprintf(stderr,
267 "import %s # pyd fragment %#s loaded from %s\n",
268 name, fragmentname, pathname);
269 Py_INCREF(m);
270 return m;
271}
272
273/*
274** Load the specified module from a resource
275*/
276PyObject *
277PyMac_LoadResourceModule(module, filename)
278char *module;
279char *filename;
280{
281 FSSpec fss;
282 FInfo finfo;
283 short oldrh, filerh;
284 Handle h;
285 OSErr err;
286 PyObject *m, *co;
287 long num, size;
288
289 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
290 /*
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 {
299 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
300 goto error;
301 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
302 goto error;
303 oldrh = CurResFile();
304 filerh = FSpOpenResFile(&fss, fsRdPerm);
305 if ( filerh == -1 ) {
306 err = ResError();
307 goto error;
308 }
309 UseResFile(filerh);
310 }
311 h = Get1NamedResource('PYC ', Pstring(module));
312 if ( h == NULL ) {
313 err = ResError();
314 goto error;
315 }
316 HLock(h);
317 /*
318 ** XXXX The next few lines are intimately tied to the format of pyc
319 ** files. I'm not sure whether this code should be here or in import.c -- Jack
320 */
321 size = GetHandleSize(h);
322 if ( size < 8 ) {
323 PyErr_SetString(PyExc_ImportError, "Resource too small");
324 co = NULL;
325 } else {
326 num = (*h)[0] & 0xff;
327 num = num | (((*h)[1] & 0xff) << 8);
328 num = num | (((*h)[2] & 0xff) << 16);
329 num = num | (((*h)[3] & 0xff) << 24);
330 if ( num != PyImport_GetMagicNumber() ) {
331 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
332 co = NULL;
333 } else {
334 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
335 }
336 }
337 HUnlock(h);
338 if ( filerh != -1 )
339 CloseResFile(filerh);
340 UseResFile(oldrh);
341 if ( co ) {
342 m = PyImport_ExecCodeModule(module, co);
343 Py_DECREF(co);
344 } else {
345 m = NULL;
346 }
347 if (Py_VerboseFlag)
348 fprintf(stderr, "import %s # pyc resource from %s\n",
349 module, filename);
350 return m;
351error:
352 {
353 char buf[512];
354
355 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
356 PyErr_SetString(PyExc_ImportError, buf);
357 return NULL;
358 }
359}
360
361/*
362** Look for a module in a single folder. Upon entry buf and len
363** point to the folder to search, upon exit they refer to the full
364** pathname of the module found (if any).
365*/
366struct filedescr *
367PyMac_FindModuleExtension(char *buf, int *lenp, char *module)
368{
369 struct filedescr *fdp;
370 unsigned char fnbuf[64];
371 int modnamelen = strlen(module);
372 FSSpec fss;
373 short refnum;
374 long dirid;
375
376 /*
377 ** Copy the module name to the buffer (already :-terminated)
378 ** We also copy the first suffix, if this matches immedeately we're
379 ** lucky and return immedeately.
380 */
381 if ( !_PyImport_Filetab[0].suffix )
382 return 0;
383
384#if 0
385 /* Pre 1.5a4 */
386 strcpy(buf+*lenp, module);
387 strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix);
388#else
389 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
390#endif
391 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
392 return _PyImport_Filetab;
393 /*
394 ** We cannot check for fnfErr (unfortunately), it can mean either that
395 ** the file doesn't exist (fine, we try others) or the path leading to it.
396 */
397 refnum = fss.vRefNum;
398 dirid = fss.parID;
399 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
400 return 0;
401 /*
402 ** We now have the folder parameters. Setup the field for the filename
403 */
404 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
405 strcpy((char *)fnbuf+1, module);
406
407 for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
408 strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
409 fnbuf[0] = strlen((char *)fnbuf+1);
410 if (Py_VerboseFlag > 1)
411 fprintf(stderr, "# trying %s%s\n", buf, fdp->suffix);
412 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
413 /* Found it. */
414#if 0
415 strcpy(buf+*lenp+modnamelen, fdp->suffix);
416#else
417 strcpy(buf+*lenp, fdp->suffix);
418#endif
419 *lenp = strlen(buf);
420 return fdp;
421 }
422 }
423 return 0;
424}