blob: ce6b49eb3c6188c19d16564f036f952711b16ea5 [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);
125 *dataptr = **h;
126 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
127 HUnlock(h);
128 }
129 if ( filerh != -1 )
130 CloseResFile(filerh);
131 UseResFile(oldrh);
132 return ok;
133}
134
135/*
136** Returns true if the argument has a resource fork, and it contains
137** a 'PYC ' resource of the correct name
138*/
139int
140PyMac_FindResourceModule(obj, module, filename)
141PyStringObject *obj;
142char *module;
143char *filename;
144{
145 int ok;
146
147 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
148 return ok;
149}
150
151/*
152** Returns true if the argument has a resource fork, and it contains
153** a 'PYD ' resource of the correct name
154*/
155int
156PyMac_FindCodeResourceModule(obj, module, filename)
157PyStringObject *obj;
158char *module;
159char *filename;
160{
161 int ok;
162
163 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
164 return ok;
165}
166
167
168/*
169** Load the specified module from a code resource
170*/
171PyObject *
172PyMac_LoadCodeResourceModule(name, pathname)
173 char *name;
174 char *pathname;
175{
176 PyObject *m;
177 char funcname[258];
178 char *lastdot, *shortname, *packagecontext;
179 dl_funcptr p = NULL;
180 Str255 fragmentname;
181 CFragConnectionID connID;
182 Ptr mainAddr;
183 Str255 errMessage;
184 OSErr err;
185 char buf[512];
186 Ptr symAddr;
187 CFragSymbolClass class;
188
189 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
190 Py_INCREF(m);
191 return m;
192 }
193 lastdot = strrchr(name, '.');
194 if (lastdot == NULL) {
195 packagecontext = NULL;
196 shortname = name;
197 }
198 else {
199 packagecontext = name;
200 shortname = lastdot+1;
201 }
202 sprintf(funcname, FUNCNAME_PATTERN, shortname);
203 if( !findnamedresource((PyStringObject *)0, shortname, pathname, 'PYD ', fragmentname)) {
204 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
205 return NULL;
206 }
207
208 /* Load the fragment
209 (or return the connID if it is already loaded */
210 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
211 kLoadCFrag, &connID, &mainAddr,
212 errMessage);
213 if ( err ) {
214 sprintf(buf, "%.*s: %.200s",
215 errMessage[0], errMessage+1,
216 PyMac_StrError(err));
217 PyErr_SetString(PyExc_ImportError, buf);
218 return NULL;
219 }
220 /* Locate the address of the correct init function */
221 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
222 if ( err ) {
223 sprintf(buf, "%s: %.200s",
224 funcname, PyMac_StrError(err));
225 PyErr_SetString(PyExc_ImportError, buf);
226 return NULL;
227 }
228 p = (dl_funcptr)symAddr;
229 if (p == NULL) {
230 PyErr_Format(PyExc_ImportError,
231 "dynamic module does not define init function (%.200s)",
232 funcname);
233 return NULL;
234 }
235 _Py_PackageContext = packagecontext;
236 (*p)();
237 _Py_PackageContext = NULL;
238 if (PyErr_Occurred())
239 return NULL;
240 if (_PyImport_FixupExtension(name, name) == NULL)
241 return NULL;
242
243 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
244 if (m == NULL) {
245 PyErr_SetString(PyExc_SystemError,
246 "dynamic module not initialized properly");
247 return NULL;
248 }
249#if 0
250 /* Remember the filename as the __file__ attribute */
251 d = PyModule_GetDict(m);
252 s = PyString_FromString(pathname);
253 if (s == NULL || PyDict_SetItemString(d, "__file__", s) != 0)
254 PyErr_Clear(); /* Not important enough to report */
255 Py_XDECREF(s);
256#endif
257 if (Py_VerboseFlag)
258 fprintf(stderr,
259 "import %s # pyd fragment %#s loaded from %s\n",
260 name, fragmentname, pathname);
261 Py_INCREF(m);
262 return m;
263}
264
265/*
266** Load the specified module from a resource
267*/
268PyObject *
269PyMac_LoadResourceModule(module, filename)
270char *module;
271char *filename;
272{
273 FSSpec fss;
274 FInfo finfo;
275 short oldrh, filerh;
276 Handle h;
277 OSErr err;
278 PyObject *m, *co;
279 long num, size;
280
281 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
282 /*
283 ** Special case: the application itself. Use a shortcut to
284 ** forestall opening and closing the application numerous times
285 ** (which is dead slow when running from CDROM)
286 */
287 oldrh = CurResFile();
288 UseResFile(PyMac_AppRefNum);
289 filerh = -1;
290 } else {
291 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
292 goto error;
293 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
294 goto error;
295 oldrh = CurResFile();
296 filerh = FSpOpenResFile(&fss, fsRdPerm);
297 if ( filerh == -1 ) {
298 err = ResError();
299 goto error;
300 }
301 UseResFile(filerh);
302 }
303 h = Get1NamedResource('PYC ', Pstring(module));
304 if ( h == NULL ) {
305 err = ResError();
306 goto error;
307 }
308 HLock(h);
309 /*
310 ** XXXX The next few lines are intimately tied to the format of pyc
311 ** files. I'm not sure whether this code should be here or in import.c -- Jack
312 */
313 size = GetHandleSize(h);
314 if ( size < 8 ) {
315 PyErr_SetString(PyExc_ImportError, "Resource too small");
316 co = NULL;
317 } else {
318 num = (*h)[0] & 0xff;
319 num = num | (((*h)[1] & 0xff) << 8);
320 num = num | (((*h)[2] & 0xff) << 16);
321 num = num | (((*h)[3] & 0xff) << 24);
322 if ( num != PyImport_GetMagicNumber() ) {
323 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
324 co = NULL;
325 } else {
326 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
327 }
328 }
329 HUnlock(h);
330 if ( filerh != -1 )
331 CloseResFile(filerh);
332 UseResFile(oldrh);
333 if ( co ) {
334 m = PyImport_ExecCodeModule(module, co);
335 Py_DECREF(co);
336 } else {
337 m = NULL;
338 }
339 if (Py_VerboseFlag)
340 fprintf(stderr, "import %s # pyc resource from %s\n",
341 module, filename);
342 return m;
343error:
344 {
345 char buf[512];
346
347 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
348 PyErr_SetString(PyExc_ImportError, buf);
349 return NULL;
350 }
351}
352
353/*
354** Look for a module in a single folder. Upon entry buf and len
355** point to the folder to search, upon exit they refer to the full
356** pathname of the module found (if any).
357*/
358struct filedescr *
359PyMac_FindModuleExtension(char *buf, int *lenp, char *module)
360{
361 struct filedescr *fdp;
362 unsigned char fnbuf[64];
363 int modnamelen = strlen(module);
364 FSSpec fss;
365 short refnum;
366 long dirid;
367
368 /*
369 ** Copy the module name to the buffer (already :-terminated)
370 ** We also copy the first suffix, if this matches immedeately we're
371 ** lucky and return immedeately.
372 */
373 if ( !_PyImport_Filetab[0].suffix )
374 return 0;
375
376#if 0
377 /* Pre 1.5a4 */
378 strcpy(buf+*lenp, module);
379 strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix);
380#else
381 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
382#endif
383 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
384 return _PyImport_Filetab;
385 /*
386 ** We cannot check for fnfErr (unfortunately), it can mean either that
387 ** the file doesn't exist (fine, we try others) or the path leading to it.
388 */
389 refnum = fss.vRefNum;
390 dirid = fss.parID;
391 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
392 return 0;
393 /*
394 ** We now have the folder parameters. Setup the field for the filename
395 */
396 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
397 strcpy((char *)fnbuf+1, module);
398
399 for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
400 strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
401 fnbuf[0] = strlen((char *)fnbuf+1);
402 if (Py_VerboseFlag > 1)
403 fprintf(stderr, "# trying %s%s\n", buf, fdp->suffix);
404 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
405 /* Found it. */
406#if 0
407 strcpy(buf+*lenp+modnamelen, fdp->suffix);
408#else
409 strcpy(buf+*lenp, fdp->suffix);
410#endif
411 *lenp = strlen(buf);
412 return fdp;
413 }
414 }
415 return 0;
416}