mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			474 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			474 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***********************************************************
 | |
| Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
 | |
| The Netherlands.
 | |
| 
 | |
|                         All Rights Reserved
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software and its 
 | |
| documentation for any purpose and without fee is hereby granted, 
 | |
| provided that the above copyright notice appear in all copies and that
 | |
| both that copyright notice and this permission notice appear in 
 | |
| supporting documentation, and that the names of Stichting Mathematisch
 | |
| Centrum or CWI not be used in advertising or publicity pertaining to
 | |
| distribution of the software without specific, written prior permission.
 | |
| 
 | |
| STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
 | |
| THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | |
| FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
 | |
| FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 | |
| OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
| ******************************************************************/
 | |
| 
 | |
| 
 | |
| #include "Python.h"
 | |
| 
 | |
| #include "macglue.h"
 | |
| #include "marshal.h"
 | |
| #include "import.h"
 | |
| #include "importdl.h"
 | |
| 
 | |
| #include "pythonresources.h"
 | |
| 
 | |
| #include <Types.h>
 | |
| #include <Files.h>
 | |
| #include <Resources.h>
 | |
| #if 0
 | |
| #include <OSUtils.h> /* for Set(Current)A5 */
 | |
| #include <StandardFile.h>
 | |
| #include <Memory.h>
 | |
| #include <Windows.h>
 | |
| #include <Traps.h>
 | |
| #include <Processes.h>
 | |
| #include <Fonts.h>
 | |
| #include <Menus.h>
 | |
| #include <TextUtils.h>
 | |
| #endif
 | |
| #include <CodeFragments.h>
 | |
| 
 | |
| #ifdef USE_GUSI
 | |
| #include "TFileSpec.h"	/* for Path2FSSpec() */
 | |
| #endif
 | |
| 
 | |
| typedef void (*dl_funcptr)();
 | |
| #define FUNCNAME_PATTERN "init%.200s"
 | |
| 
 | |
| /*
 | |
| ** findnamedresource - Common code for the various *ResourceModule functions.
 | |
| ** Check whether a file contains a resource of the correct name and type, and
 | |
| ** optionally return the value in it.
 | |
| */
 | |
| static int
 | |
| findnamedresource(
 | |
| 	PyStringObject *obj, 
 | |
| 	char *module, 
 | |
| 	char *filename, 
 | |
| 	OSType restype, 
 | |
| 	StringPtr dataptr)
 | |
| {
 | |
| 	FSSpec fss;
 | |
| 	FInfo finfo;
 | |
| 	short oldrh, filerh;
 | |
| 	int ok;
 | |
| 	Handle h;
 | |
| 
 | |
| #ifdef INTERN_STRINGS
 | |
| 	/*
 | |
| 	** If we have interning find_module takes care of interning all
 | |
| 	** sys.path components. We then keep a record of all sys.path
 | |
| 	** components for which GetFInfo has failed (usually because the
 | |
| 	** component in question is a folder), and we don't try opening these
 | |
| 	** as resource files again.
 | |
| 	*/
 | |
| #define MAXPATHCOMPONENTS 32
 | |
| 	static PyStringObject *not_a_file[MAXPATHCOMPONENTS];
 | |
| 	static int max_not_a_file = 0;
 | |
| 	int i;
 | |
| 		
 | |
| 	if (obj && obj->ob_sinterned ) {
 | |
| 		for( i=0; i< max_not_a_file; i++ )
 | |
| 			if ( obj == not_a_file[i] )
 | |
| 				return 0;
 | |
| 	}
 | |
| #endif /* INTERN_STRINGS */
 | |
| 
 | |
| 	if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
 | |
| 		/*
 | |
| 		** Special case: the application itself. Use a shortcut to
 | |
| 		** forestall opening and closing the application numerous times
 | |
| 		** (which is dead slow when running from CDROM)
 | |
| 		*/
 | |
| 		oldrh = CurResFile();
 | |
| 		UseResFile(PyMac_AppRefNum);
 | |
| 		filerh = -1;
 | |
| 	} else {
 | |
| #ifdef USE_GUSI
 | |
| 		if ( Path2FSSpec(filename, &fss) != noErr ||
 | |
| #else
 | |
| 		if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr ||
 | |
| #endif
 | |
| 		     FSpGetFInfo(&fss, &finfo) != noErr ) {
 | |
| #ifdef INTERN_STRINGS
 | |
| 			if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned )
 | |
| 				not_a_file[max_not_a_file++] = obj;
 | |
| #endif /* INTERN_STRINGS */
 | |
| 		     	/* doesn't exist or is folder */
 | |
| 			return 0;
 | |
| 		}			
 | |
| 		oldrh = CurResFile();
 | |
| 		filerh = FSpOpenResFile(&fss, fsRdPerm);
 | |
| 		if ( filerh == -1 )
 | |
| 			return 0;
 | |
| 		UseResFile(filerh);
 | |
| 	}
 | |
| 	if ( dataptr == NULL )
 | |
| 		SetResLoad(0);
 | |
| 	h = Get1NamedResource(restype, Pstring(module));
 | |
| 	SetResLoad(1);
 | |
| 	ok = (h != NULL);
 | |
| 	if ( ok && dataptr != NULL ) {
 | |
| 		HLock(h);
 | |
| 		/* XXXX Unsafe if resource not correctly formatted! */
 | |
| #ifdef __CFM68K__
 | |
| 		/* for cfm68k we take the second pstring */
 | |
| 		*dataptr = *((*h)+(**h)+1);
 | |
| 		memcpy(dataptr+1, (*h)+(**h)+2, (int)*dataptr);
 | |
| #else
 | |
| 		/* for ppc we take the first pstring */
 | |
| 		*dataptr = **h;
 | |
| 		memcpy(dataptr+1, (*h)+1, (int)*dataptr);
 | |
| #endif
 | |
| 		HUnlock(h);
 | |
| 	}
 | |
| 	if ( filerh != -1 )
 | |
| 		CloseResFile(filerh);
 | |
| 	UseResFile(oldrh);
 | |
| 	return ok;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Returns true if the argument has a resource fork, and it contains
 | |
| ** a 'PYC ' resource of the correct name
 | |
| */
 | |
| int
 | |
| PyMac_FindResourceModule(obj, module, filename)
 | |
| PyStringObject *obj;
 | |
| char *module;
 | |
| char *filename;
 | |
| {
 | |
| 	int ok;
 | |
| 	
 | |
| 	ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
 | |
| 	return ok;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Returns true if the argument has a resource fork, and it contains
 | |
| ** a 'PYD ' resource of the correct name
 | |
| */
 | |
| int
 | |
| PyMac_FindCodeResourceModule(obj, module, filename)
 | |
| PyStringObject *obj;
 | |
| char *module;
 | |
| char *filename;
 | |
| {
 | |
| 	int ok;
 | |
| 	
 | |
| 	ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
 | |
| 	return ok;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Load the specified module from a code resource
 | |
| */
 | |
| PyObject *
 | |
| PyMac_LoadCodeResourceModule(name, pathname)
 | |
| 	char *name;
 | |
| 	char *pathname;
 | |
| {
 | |
| 	PyObject *m, *d, *s;
 | |
| 	char funcname[258];
 | |
| 	char *lastdot, *shortname, *packagecontext;
 | |
| 	dl_funcptr p = NULL;
 | |
| 	Str255 fragmentname;
 | |
| 	CFragConnectionID connID;
 | |
| 	Ptr mainAddr;
 | |
| 	Str255 errMessage;
 | |
| 	OSErr err;
 | |
| 	char buf[512];
 | |
| 	Ptr symAddr;
 | |
| 	CFragSymbolClass class;
 | |
| 
 | |
| 	if ((m = _PyImport_FindExtension(name, name)) != NULL) {
 | |
| 		Py_INCREF(m);
 | |
| 		return m;
 | |
| 	}
 | |
| 	lastdot = strrchr(name, '.');
 | |
| 	if (lastdot == NULL) {
 | |
| 		packagecontext = NULL;
 | |
| 		shortname = name;
 | |
| 	}
 | |
| 	else {
 | |
| 		packagecontext = name;
 | |
| 		shortname = lastdot+1;
 | |
| 	}
 | |
| 	sprintf(funcname, FUNCNAME_PATTERN, shortname);
 | |
| 	if( !findnamedresource((PyStringObject *)0, shortname, pathname, 'PYD ', fragmentname)) {
 | |
| 		PyErr_SetString(PyExc_ImportError, "PYD resource not found");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	
 | |
| 	/* Load the fragment
 | |
| 	   (or return the connID if it is already loaded */
 | |
| 	err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
 | |
| 			      kLoadCFrag, &connID, &mainAddr,
 | |
| 			      errMessage);
 | |
| 	if ( err ) {
 | |
| 		sprintf(buf, "%.*s: %.200s",
 | |
| 			errMessage[0], errMessage+1,
 | |
| 			PyMac_StrError(err));
 | |
| 		PyErr_SetString(PyExc_ImportError, buf);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	/* Locate the address of the correct init function */
 | |
| 	err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
 | |
| 	if ( err ) {
 | |
| 		sprintf(buf, "%s: %.200s",
 | |
| 			funcname, PyMac_StrError(err));
 | |
| 		PyErr_SetString(PyExc_ImportError, buf);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	p = (dl_funcptr)symAddr;
 | |
| 	if (p == NULL) {
 | |
| 		PyErr_Format(PyExc_ImportError,
 | |
| 		   "dynamic module does not define init function (%.200s)",
 | |
| 			     funcname);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	_Py_PackageContext = packagecontext;
 | |
| 	(*p)();
 | |
| 	_Py_PackageContext = NULL;
 | |
| 	if (PyErr_Occurred())
 | |
| 		return NULL;
 | |
| 	if (_PyImport_FixupExtension(name, name) == NULL)
 | |
| 		return NULL;
 | |
| 
 | |
| 	m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
 | |
| 	if (m == NULL) {
 | |
| 		PyErr_SetString(PyExc_SystemError,
 | |
| 				"dynamic module not initialized properly");
 | |
| 		return NULL;
 | |
| 	}
 | |
| #if 1
 | |
| 	/* Remember the filename as the __file__ attribute */
 | |
| 	d = PyModule_GetDict(m);
 | |
| 	s = PyString_FromString(pathname);
 | |
| 	if (s == NULL || PyDict_SetItemString(d, "__file__", s) != 0)
 | |
| 		PyErr_Clear(); /* Not important enough to report */
 | |
| 	Py_XDECREF(s);
 | |
| #endif
 | |
| 	if (Py_VerboseFlag)
 | |
| 		PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
 | |
| 			name, fragmentname, pathname);
 | |
| 	Py_INCREF(m);
 | |
| 	return m;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Load the specified module from a resource
 | |
| */
 | |
| PyObject *
 | |
| PyMac_LoadResourceModule(module, filename)
 | |
| char *module;
 | |
| char *filename;
 | |
| {
 | |
| 	FSSpec fss;
 | |
| 	FInfo finfo;
 | |
| 	short oldrh, filerh;
 | |
| 	Handle h;
 | |
| 	OSErr err;
 | |
| 	PyObject *m, *co;
 | |
| 	long num, size;
 | |
| 	
 | |
| 	if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
 | |
| 		/*
 | |
| 		** Special case: the application itself. Use a shortcut to
 | |
| 		** forestall opening and closing the application numerous times
 | |
| 		** (which is dead slow when running from CDROM)
 | |
| 		*/
 | |
| 		oldrh = CurResFile();
 | |
| 		UseResFile(PyMac_AppRefNum);
 | |
| 		filerh = -1;
 | |
| 	} else {
 | |
| #ifdef USE_GUSI
 | |
| 		if ( (err=Path2FSSpec(filename, &fss)) != noErr ||
 | |
| 		     FSpGetFInfo(&fss, &finfo) != noErr )
 | |
| #else
 | |
| 		if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
 | |
| #endif
 | |
| 			goto error;
 | |
| 		if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
 | |
| 			goto error;
 | |
| 		oldrh = CurResFile();
 | |
| 		filerh = FSpOpenResFile(&fss, fsRdPerm);
 | |
| 		if ( filerh == -1 ) {
 | |
| 			err = ResError();
 | |
| 			goto error;
 | |
| 		}
 | |
| 		UseResFile(filerh);
 | |
| 	}
 | |
| 	h = Get1NamedResource('PYC ', Pstring(module));
 | |
| 	if ( h == NULL ) {
 | |
| 		err = ResError();
 | |
| 		goto error;
 | |
| 	}
 | |
| 	HLock(h);
 | |
| 	/*
 | |
| 	** XXXX The next few lines are intimately tied to the format of pyc
 | |
| 	** files. I'm not sure whether this code should be here or in import.c -- Jack
 | |
| 	*/
 | |
| 	size = GetHandleSize(h);
 | |
| 	if ( size < 8 ) {
 | |
| 		PyErr_SetString(PyExc_ImportError, "Resource too small");
 | |
| 		co = NULL;
 | |
| 	} else {
 | |
| 		num = (*h)[0] & 0xff;
 | |
| 		num = num | (((*h)[1] & 0xff) << 8);
 | |
| 		num = num | (((*h)[2] & 0xff) << 16);
 | |
| 		num = num | (((*h)[3] & 0xff) << 24);
 | |
| 		if ( num != PyImport_GetMagicNumber() ) {
 | |
| 			PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
 | |
| 			co = NULL;
 | |
| 		} else {
 | |
| 			co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
 | |
| 			/*
 | |
| 			** Normally, byte 4-7 are the time stamp, but that is not used
 | |
| 			** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
 | |
| 			** that it is a package rather than an ordinary module. 
 | |
| 			** See also py_resource.py. (jvr)
 | |
| 			*/
 | |
| 			if ((*h)[4] & 0xff) {
 | |
| 				/* it's a package */
 | |
| 				/* Set __path__ to the package name */
 | |
| 				PyObject *d, *s;
 | |
| 				int err;
 | |
| 				
 | |
| 				m = PyImport_AddModule(module);
 | |
| 				if (m == NULL) {
 | |
| 					co = NULL;
 | |
| 					goto packageerror;
 | |
| 				}
 | |
| 				d = PyModule_GetDict(m);
 | |
| 				s = PyString_InternFromString(module);
 | |
| 				if (s == NULL) {
 | |
| 					co = NULL;
 | |
| 					goto packageerror;
 | |
| 				}
 | |
| 				err = PyDict_SetItemString(d, "__path__", s);
 | |
| 				Py_DECREF(s);
 | |
| 				if (err != 0) {
 | |
| 					co = NULL;
 | |
| 					goto packageerror;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| packageerror:
 | |
| 	HUnlock(h);
 | |
| 	if ( filerh != -1 )
 | |
| 		CloseResFile(filerh);
 | |
| 	UseResFile(oldrh);
 | |
| 	if ( co ) {
 | |
| 		m = PyImport_ExecCodeModuleEx(module, co, "<pyc resource>");
 | |
| 		Py_DECREF(co);
 | |
| 	} else {
 | |
| 		m = NULL;
 | |
| 	}
 | |
| 	if (Py_VerboseFlag)
 | |
| 		PySys_WriteStderr("import %s # pyc resource from %s\n",
 | |
| 			module, filename);
 | |
| 	return m;
 | |
| error:
 | |
| 	{
 | |
| 		char buf[512];
 | |
| 		
 | |
| 		sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
 | |
| 		PyErr_SetString(PyExc_ImportError, buf);
 | |
| 		return NULL;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Look for a module in a single folder. Upon entry buf and len
 | |
| ** point to the folder to search, upon exit they refer to the full
 | |
| ** pathname of the module found (if any).
 | |
| */
 | |
| struct filedescr *
 | |
| PyMac_FindModuleExtension(char *buf, int *lenp, char *module)
 | |
| {
 | |
| 	struct filedescr *fdp;
 | |
| 	unsigned char fnbuf[64];
 | |
| 	int modnamelen = strlen(module);
 | |
| 	FSSpec fss;
 | |
| 	FInfo finfo;
 | |
| 	short refnum;
 | |
| 	long dirid;
 | |
| 	
 | |
| 	/*
 | |
| 	** Copy the module name to the buffer (already :-terminated)
 | |
| 	** We also copy the first suffix, if this matches immedeately we're
 | |
| 	** lucky and return immedeately.
 | |
| 	*/
 | |
| 	if ( !_PyImport_Filetab[0].suffix )
 | |
| 		return 0;
 | |
| 		
 | |
| #if 0
 | |
| 	/* Pre 1.5a4 */
 | |
| 	strcpy(buf+*lenp, module);
 | |
| 	strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix);
 | |
| #else
 | |
| 	strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
 | |
| #endif
 | |
| #ifdef USE_GUSI
 | |
| 	if ( Path2FSSpec(buf, &fss) == noErr && 
 | |
| 			FSpGetFInfo(&fss, &finfo) == noErr)
 | |
| 		return _PyImport_Filetab;
 | |
| #else
 | |
| 	if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
 | |
| 		return _PyImport_Filetab;
 | |
| #endif
 | |
| 	/*
 | |
| 	** We cannot check for fnfErr (unfortunately), it can mean either that
 | |
| 	** the file doesn't exist (fine, we try others) or the path leading to it.
 | |
| 	*/
 | |
| 	refnum = fss.vRefNum;
 | |
| 	dirid = fss.parID;
 | |
| 	if ( refnum == 0 || dirid == 0 )	/* Fail on nonexistent dir */
 | |
| 		return 0;
 | |
| 	/*
 | |
| 	** We now have the folder parameters. Setup the field for the filename
 | |
| 	*/
 | |
| 	if ( modnamelen > 54 ) return 0;	/* Leave room for extension */
 | |
| 	strcpy((char *)fnbuf+1, module);
 | |
| 	
 | |
| 	for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
 | |
| 		strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
 | |
| 		fnbuf[0] = strlen((char *)fnbuf+1);
 | |
| 		if (Py_VerboseFlag > 1)
 | |
| 			PySys_WriteStderr("# trying %s%s\n", buf, fdp->suffix);
 | |
| 		if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
 | |
| 			/* Found it. */
 | |
| #if 0
 | |
| 			strcpy(buf+*lenp+modnamelen, fdp->suffix);
 | |
| #else
 | |
| 			strcpy(buf+*lenp, fdp->suffix);
 | |
| #endif
 | |
| 			*lenp = strlen(buf);
 | |
| 			return fdp;
 | |
| 		}
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | 
