blob: cc562f113ba5c14aceceaa4b7346f8ac01b9d044 [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>
Jack Jansen1e2260f1998-07-13 13:37:12 +000038#include <CodeFragments.h>
Jack Jansenb45032e2001-05-22 14:13:02 +000039#include <StringCompare.h>
Jack Jansen1e2260f1998-07-13 13:37:12 +000040
41typedef void (*dl_funcptr)();
42#define FUNCNAME_PATTERN "init%.200s"
43
Jack Jansenb45032e2001-05-22 14:13:02 +000044static int
45fssequal(FSSpec *fs1, FSSpec *fs2)
46{
47 if ( fs1->vRefNum != fs2->vRefNum || fs1->parID != fs2->parID )
48 return 0;
49 return EqualString(fs1->name, fs2->name, false, true);
50}
Jack Jansen1e2260f1998-07-13 13:37:12 +000051/*
52** findnamedresource - Common code for the various *ResourceModule functions.
53** Check whether a file contains a resource of the correct name and type, and
54** optionally return the value in it.
55*/
56static int
57findnamedresource(
58 PyStringObject *obj,
59 char *module,
60 char *filename,
61 OSType restype,
62 StringPtr dataptr)
63{
64 FSSpec fss;
65 FInfo finfo;
66 short oldrh, filerh;
67 int ok;
68 Handle h;
69
Jack Jansen1e2260f1998-07-13 13:37:12 +000070 /*
71 ** If we have interning find_module takes care of interning all
72 ** sys.path components. We then keep a record of all sys.path
73 ** components for which GetFInfo has failed (usually because the
74 ** component in question is a folder), and we don't try opening these
75 ** as resource files again.
76 */
77#define MAXPATHCOMPONENTS 32
78 static PyStringObject *not_a_file[MAXPATHCOMPONENTS];
79 static int max_not_a_file = 0;
80 int i;
81
82 if (obj && obj->ob_sinterned ) {
83 for( i=0; i< max_not_a_file; i++ )
84 if ( obj == not_a_file[i] )
85 return 0;
86 }
Jack Jansenb45032e2001-05-22 14:13:02 +000087 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr ) {
Jack Jansenb45032e2001-05-22 14:13:02 +000088 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned )
89 not_a_file[max_not_a_file++] = obj;
Jack Jansenb45032e2001-05-22 14:13:02 +000090 /* doesn't exist or is folder */
91 return 0;
92 }
93 if ( fssequal(&fss, &PyMac_ApplicationFSSpec) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +000094 /*
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 {
Jack Jansenb45032e2001-05-22 14:13:02 +0000103 if ( FSpGetFInfo(&fss, &finfo) != noErr ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000104 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned )
105 not_a_file[max_not_a_file++] = obj;
Jack Jansenb45032e2001-05-22 14:13:02 +0000106 /* doesn't exist or is folder */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000107 return 0;
108 }
109 oldrh = CurResFile();
110 filerh = FSpOpenResFile(&fss, fsRdPerm);
111 if ( filerh == -1 )
112 return 0;
113 UseResFile(filerh);
114 }
115 if ( dataptr == NULL )
116 SetResLoad(0);
117 h = Get1NamedResource(restype, Pstring(module));
118 SetResLoad(1);
119 ok = (h != NULL);
120 if ( ok && dataptr != NULL ) {
121 HLock(h);
Jack Jansen017e0ff1998-07-31 09:34:47 +0000122 /* XXXX Unsafe if resource not correctly formatted! */
Jack Jansen017e0ff1998-07-31 09:34:47 +0000123 /* for ppc we take the first pstring */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000124 *dataptr = **h;
125 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
126 HUnlock(h);
127 }
128 if ( filerh != -1 )
129 CloseResFile(filerh);
130 UseResFile(oldrh);
131 return ok;
132}
133
134/*
135** Returns true if the argument has a resource fork, and it contains
136** a 'PYC ' resource of the correct name
137*/
138int
139PyMac_FindResourceModule(obj, module, filename)
140PyStringObject *obj;
141char *module;
142char *filename;
143{
144 int ok;
145
146 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
147 return ok;
148}
149
150/*
151** Returns true if the argument has a resource fork, and it contains
152** a 'PYD ' resource of the correct name
153*/
154int
155PyMac_FindCodeResourceModule(obj, module, filename)
156PyStringObject *obj;
157char *module;
158char *filename;
159{
160 int ok;
161
162 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
163 return ok;
164}
165
166
167/*
168** Load the specified module from a code resource
169*/
170PyObject *
171PyMac_LoadCodeResourceModule(name, pathname)
172 char *name;
173 char *pathname;
174{
Jack Jansen017e0ff1998-07-31 09:34:47 +0000175 PyObject *m, *d, *s;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000176 char funcname[258];
177 char *lastdot, *shortname, *packagecontext;
178 dl_funcptr p = NULL;
179 Str255 fragmentname;
180 CFragConnectionID connID;
181 Ptr mainAddr;
182 Str255 errMessage;
183 OSErr err;
184 char buf[512];
185 Ptr symAddr;
186 CFragSymbolClass class;
187
188 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
189 Py_INCREF(m);
190 return m;
191 }
192 lastdot = strrchr(name, '.');
193 if (lastdot == NULL) {
194 packagecontext = NULL;
195 shortname = name;
196 }
197 else {
198 packagecontext = name;
199 shortname = lastdot+1;
200 }
Jack Jansen101de912001-12-05 23:27:58 +0000201 PyOS_snprintf(funcname, sizeof(funcname), FUNCNAME_PATTERN, shortname);
Just van Rossum0297dca2001-06-26 06:54:33 +0000202 if( !findnamedresource((PyStringObject *)0, name, pathname, 'PYD ', fragmentname)) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000203 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
204 return NULL;
205 }
206
207 /* Load the fragment
208 (or return the connID if it is already loaded */
209 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
210 kLoadCFrag, &connID, &mainAddr,
211 errMessage);
212 if ( err ) {
Jack Jansen101de912001-12-05 23:27:58 +0000213 PyOS_snprintf(buf, sizeof(buf), "%.*s: %.200s",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000214 errMessage[0], errMessage+1,
215 PyMac_StrError(err));
216 PyErr_SetString(PyExc_ImportError, buf);
217 return NULL;
218 }
219 /* Locate the address of the correct init function */
220 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
221 if ( err ) {
Jack Jansen101de912001-12-05 23:27:58 +0000222 PyOS_snprintf(buf, sizeof(buf), "%s: %.200s",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000223 funcname, PyMac_StrError(err));
224 PyErr_SetString(PyExc_ImportError, buf);
225 return NULL;
226 }
227 p = (dl_funcptr)symAddr;
228 if (p == NULL) {
229 PyErr_Format(PyExc_ImportError,
230 "dynamic module does not define init function (%.200s)",
231 funcname);
232 return NULL;
233 }
234 _Py_PackageContext = packagecontext;
235 (*p)();
236 _Py_PackageContext = NULL;
237 if (PyErr_Occurred())
238 return NULL;
239 if (_PyImport_FixupExtension(name, name) == NULL)
240 return NULL;
241
242 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
243 if (m == NULL) {
244 PyErr_SetString(PyExc_SystemError,
245 "dynamic module not initialized properly");
246 return NULL;
247 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000248 /* Remember the filename as the __file__ attribute */
249 d = PyModule_GetDict(m);
250 s = PyString_FromString(pathname);
251 if (s == NULL || PyDict_SetItemString(d, "__file__", s) != 0)
252 PyErr_Clear(); /* Not important enough to report */
253 Py_XDECREF(s);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000254 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000255 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000256 name, fragmentname, pathname);
257 Py_INCREF(m);
258 return m;
259}
260
261/*
262** Load the specified module from a resource
263*/
264PyObject *
265PyMac_LoadResourceModule(module, filename)
266char *module;
267char *filename;
268{
269 FSSpec fss;
270 FInfo finfo;
271 short oldrh, filerh;
272 Handle h;
273 OSErr err;
274 PyObject *m, *co;
275 long num, size;
276
Jack Jansenb45032e2001-05-22 14:13:02 +0000277 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
Jack Jansenb45032e2001-05-22 14:13:02 +0000278 goto error;
279 if ( fssequal(&fss, &PyMac_ApplicationFSSpec) ) {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000280 /*
281 ** Special case: the application itself. Use a shortcut to
282 ** forestall opening and closing the application numerous times
283 ** (which is dead slow when running from CDROM)
284 */
285 oldrh = CurResFile();
286 UseResFile(PyMac_AppRefNum);
287 filerh = -1;
288 } else {
Jack Jansen1e2260f1998-07-13 13:37:12 +0000289 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
290 goto error;
291 oldrh = CurResFile();
292 filerh = FSpOpenResFile(&fss, fsRdPerm);
293 if ( filerh == -1 ) {
294 err = ResError();
295 goto error;
296 }
297 UseResFile(filerh);
298 }
299 h = Get1NamedResource('PYC ', Pstring(module));
300 if ( h == NULL ) {
301 err = ResError();
302 goto error;
303 }
304 HLock(h);
305 /*
306 ** XXXX The next few lines are intimately tied to the format of pyc
307 ** files. I'm not sure whether this code should be here or in import.c -- Jack
308 */
309 size = GetHandleSize(h);
310 if ( size < 8 ) {
311 PyErr_SetString(PyExc_ImportError, "Resource too small");
312 co = NULL;
313 } else {
314 num = (*h)[0] & 0xff;
315 num = num | (((*h)[1] & 0xff) << 8);
316 num = num | (((*h)[2] & 0xff) << 16);
317 num = num | (((*h)[3] & 0xff) << 24);
318 if ( num != PyImport_GetMagicNumber() ) {
319 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
320 co = NULL;
321 } else {
322 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
Jack Jansenb93f5211998-08-18 12:23:11 +0000323 /*
324 ** Normally, byte 4-7 are the time stamp, but that is not used
325 ** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
326 ** that it is a package rather than an ordinary module.
327 ** See also py_resource.py. (jvr)
328 */
329 if ((*h)[4] & 0xff) {
330 /* it's a package */
331 /* Set __path__ to the package name */
332 PyObject *d, *s;
333 int err;
334
335 m = PyImport_AddModule(module);
336 if (m == NULL) {
337 co = NULL;
338 goto packageerror;
339 }
340 d = PyModule_GetDict(m);
341 s = PyString_InternFromString(module);
342 if (s == NULL) {
343 co = NULL;
344 goto packageerror;
345 }
346 err = PyDict_SetItemString(d, "__path__", s);
347 Py_DECREF(s);
348 if (err != 0) {
349 co = NULL;
350 goto packageerror;
351 }
352 }
Jack Jansen1e2260f1998-07-13 13:37:12 +0000353 }
354 }
Jack Jansenb93f5211998-08-18 12:23:11 +0000355packageerror:
Jack Jansen1e2260f1998-07-13 13:37:12 +0000356 HUnlock(h);
357 if ( filerh != -1 )
358 CloseResFile(filerh);
Jack Jansenadd8b242001-02-21 15:48:19 +0000359 else
360 ReleaseResource(h);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000361 UseResFile(oldrh);
362 if ( co ) {
Jack Jansenb93f5211998-08-18 12:23:11 +0000363 m = PyImport_ExecCodeModuleEx(module, co, "<pyc resource>");
Jack Jansen1e2260f1998-07-13 13:37:12 +0000364 Py_DECREF(co);
365 } else {
366 m = NULL;
367 }
368 if (Py_VerboseFlag)
Jack Jansendeff89c1998-10-12 20:53:15 +0000369 PySys_WriteStderr("import %s # pyc resource from %s\n",
Jack Jansen1e2260f1998-07-13 13:37:12 +0000370 module, filename);
371 return m;
372error:
373 {
374 char buf[512];
375
Jack Jansen101de912001-12-05 23:27:58 +0000376 PyOS_snprintf(buf, sizeof(buf), "%s: %s", filename, PyMac_StrError(err));
Jack Jansen1e2260f1998-07-13 13:37:12 +0000377 PyErr_SetString(PyExc_ImportError, buf);
378 return NULL;
379 }
380}
381
382/*
383** Look for a module in a single folder. Upon entry buf and len
384** point to the folder to search, upon exit they refer to the full
385** pathname of the module found (if any).
386*/
387struct filedescr *
Jack Jansenfe38d292000-07-03 23:53:40 +0000388PyMac_FindModuleExtension(char *buf, size_t *lenp, char *module)
Jack Jansen1e2260f1998-07-13 13:37:12 +0000389{
390 struct filedescr *fdp;
391 unsigned char fnbuf[64];
392 int modnamelen = strlen(module);
393 FSSpec fss;
394 short refnum;
395 long dirid;
396
397 /*
398 ** Copy the module name to the buffer (already :-terminated)
399 ** We also copy the first suffix, if this matches immedeately we're
400 ** lucky and return immedeately.
401 */
402 if ( !_PyImport_Filetab[0].suffix )
403 return 0;
404
Jack Jansen1e2260f1998-07-13 13:37:12 +0000405 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000406 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
407 return _PyImport_Filetab;
Jack Jansen1e2260f1998-07-13 13:37:12 +0000408 /*
409 ** We cannot check for fnfErr (unfortunately), it can mean either that
410 ** the file doesn't exist (fine, we try others) or the path leading to it.
411 */
412 refnum = fss.vRefNum;
413 dirid = fss.parID;
414 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
415 return 0;
416 /*
417 ** We now have the folder parameters. Setup the field for the filename
418 */
419 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
420 strcpy((char *)fnbuf+1, module);
Jack Jansen80c85d82001-11-05 14:36:32 +0000421 buf[*lenp] = '\0';
Jack Jansen1e2260f1998-07-13 13:37:12 +0000422
423 for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
424 strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
425 fnbuf[0] = strlen((char *)fnbuf+1);
426 if (Py_VerboseFlag > 1)
Jack Jansendeff89c1998-10-12 20:53:15 +0000427 PySys_WriteStderr("# trying %s%s\n", buf, fdp->suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000428 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
429 /* Found it. */
Jack Jansen1e2260f1998-07-13 13:37:12 +0000430 strcpy(buf+*lenp, fdp->suffix);
Jack Jansen1e2260f1998-07-13 13:37:12 +0000431 return fdp;
432 }
433 }
434 return 0;
435}