srcanamdw/codescanner/pyinstaller/source/common/launch.c
changeset 1 22878952f6e2
equal deleted inserted replaced
0:509e4801c378 1:22878952f6e2
       
     1 /*
       
     2  * Launch a python module from an archive.   
       
     3  * Copyright (C) 2005, Giovanni Bajo
       
     4  * Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.
       
     5  *
       
     6  * This program is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU General Public License
       
     8  * as published by the Free Software Foundation; either version 2
       
     9  * of the License, or (at your option) any later version.
       
    10  *
       
    11  * In addition to the permissions in the GNU General Public License, the
       
    12  * authors give you unlimited permission to link or embed the compiled
       
    13  * version of this file into combinations with other programs, and to
       
    14  * distribute those combinations without any restriction coming from the
       
    15  * use of this file. (The General Public License restrictions do apply in
       
    16  * other respects; for example, they cover modification of the file, and
       
    17  * distribution when not linked into a combine executable.)
       
    18  *
       
    19  * This program is distributed in the hope that it will be useful,
       
    20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    22  * GNU General Public License for more details.
       
    23  *
       
    24  * You should have received a copy of the GNU General Public License
       
    25  * along with this program; if not, write to the Free Software
       
    26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
       
    27  */
       
    28 #include <stdio.h>
       
    29 #ifdef WIN32
       
    30  #include <windows.h>
       
    31  #include <direct.h>
       
    32  #include <process.h>
       
    33  #include <io.h>
       
    34 #else
       
    35  #include <unistd.h>
       
    36  #include <fcntl.h>
       
    37  #include <dirent.h>
       
    38 #endif
       
    39 #include <stdio.h>
       
    40 #include <sys/types.h>
       
    41 #include <sys/stat.h>
       
    42 #include "launch.h"
       
    43 #ifndef NOZLIB
       
    44 #include "zlib.h"
       
    45 #endif
       
    46 #ifdef WIN32
       
    47 /*
       
    48  * Python Entry point declarations (see macros in launch.h).
       
    49  */
       
    50 DECLVAR(Py_NoSiteFlag);
       
    51 DECLVAR(Py_OptimizeFlag);
       
    52 DECLVAR(Py_VerboseFlag);
       
    53 DECLPROC(Py_Initialize);
       
    54 DECLPROC(Py_Finalize);
       
    55 DECLPROC(Py_CompileString);
       
    56 DECLPROC(PyImport_ExecCodeModule);
       
    57 DECLPROC(PyRun_SimpleString);
       
    58 DECLPROC(PySys_SetArgv);
       
    59 DECLPROC(Py_SetProgramName);
       
    60 DECLPROC(PyImport_ImportModule);
       
    61 DECLPROC(PyImport_AddModule);
       
    62 DECLPROC(PyObject_SetAttrString);
       
    63 DECLPROC(PyList_New);
       
    64 DECLPROC(PyList_Append);
       
    65 DECLPROC(Py_BuildValue);
       
    66 DECLPROC(PyFile_FromString);
       
    67 DECLPROC(PyString_FromStringAndSize);
       
    68 DECLPROC(PyObject_CallFunction);
       
    69 DECLPROC(PyModule_GetDict);
       
    70 DECLPROC(PyDict_GetItemString);
       
    71 DECLPROC(PyErr_Clear);
       
    72 DECLPROC(PyErr_Occurred);
       
    73 DECLPROC(PyErr_Print);
       
    74 DECLPROC(PyObject_CallObject);
       
    75 DECLPROC(PyObject_CallMethod);
       
    76 DECLPROC(PySys_AddWarnOption);
       
    77 DECLPROC(PyEval_InitThreads);
       
    78 DECLPROC(PyEval_AcquireThread);
       
    79 DECLPROC(PyEval_ReleaseThread);
       
    80 DECLPROC(PyEval_AcquireLock);
       
    81 DECLPROC(PyEval_ReleaseLock);
       
    82 DECLPROC(PyThreadState_Swap);
       
    83 DECLPROC(PyThreadState_New);
       
    84 DECLPROC(PyThreadState_Clear);
       
    85 DECLPROC(PyThreadState_Delete);
       
    86 DECLPROC(PyInterpreterState_New);
       
    87 DECLPROC(Py_NewInterpreter);
       
    88 DECLPROC(Py_EndInterpreter);
       
    89 DECLPROC(PyInt_AsLong);
       
    90 DECLPROC(PySys_SetObject);
       
    91 #endif
       
    92 
       
    93 #ifdef WIN32
       
    94 #define PATHSEP ";"
       
    95 #define SEP "/"
       
    96 #else
       
    97 #define PATHSEP ":"
       
    98 #define SEP "/"
       
    99 #endif
       
   100 
       
   101 /* File Local Variables (all start with f_) */
       
   102 static char f_archivename[_MAX_PATH+1];
       
   103 static char f_homepath[_MAX_PATH+1];
       
   104 static char f_temppath[_MAX_PATH+1] = { '\0' };
       
   105 #ifdef WIN32
       
   106 static char f_temppathraw[MAX_PATH+1];
       
   107 static char f_homepathraw[_MAX_PATH+1];
       
   108 #endif
       
   109 static char *f_workpath = NULL;
       
   110 static FILE *f_fp;
       
   111 static int f_pkgstart;
       
   112 static TOC *f_tocbuff = NULL;
       
   113 static TOC *f_tocend = NULL;
       
   114 static COOKIE f_cookie;
       
   115 
       
   116 unsigned char *extract(TOC *ptoc);
       
   117 
       
   118 /*
       
   119  * The functions in this file defined in reverse order so that forward 
       
   120  * declarations are not necessary.
       
   121  */
       
   122 
       
   123 int testTempPath(char *buff)
       
   124 {
       
   125 	char base[16];
       
   126 	int n;
       
   127 
       
   128 	n = strlen(buff);
       
   129 	if ( buff[n-1] == '/' || buff[n-1] == '\\' )
       
   130 		sprintf(base, "_MEI%d", getpid());
       
   131 	else
       
   132 		sprintf(base, "%s_MEI%d", SEP, getpid());
       
   133 	strcat(buff, base);
       
   134 #ifdef WIN32
       
   135 	if (mkdir(buff) == 0) {
       
   136 #else
       
   137 	if (mkdir(buff, 0700) == 0) {
       
   138 #endif
       
   139 		strcat(buff, SEP);
       
   140 		return 1;
       
   141 	}
       
   142 	return 0;
       
   143 }
       
   144 
       
   145 void getTempPath(char *buff)
       
   146 {
       
   147 #ifdef WIN32
       
   148 	GetTempPath(MAX_PATH, buff);
       
   149 	testTempPath(buff);
       
   150 #else
       
   151 	static const char *envname[] = {
       
   152 		"TMPDIR", "TEMP", "TMP", 0
       
   153 	};
       
   154 	static const char *dirname[] = {
       
   155 		"/tmp", "/var/tmp", "/usr/tmp", 0
       
   156 	};
       
   157 	int i;
       
   158 	char *p;
       
   159 	for ( i=0; envname[i]; i++ ) {
       
   160 		p = getenv(envname[i]);
       
   161 		if (p) {
       
   162 			strcpy(buff, p);
       
   163 			if (testTempPath(buff))
       
   164 				return;
       
   165 		}
       
   166 	}
       
   167 	for ( i=0; dirname[i]; i++ ) {
       
   168 		strcpy(buff, dirname[i]);
       
   169 		if (testTempPath(buff))
       
   170 			return;
       
   171 	}
       
   172 	buff[0] = '\0';
       
   173 #endif
       
   174 }
       
   175 /*
       
   176  * Set up paths required by rest of this module
       
   177  * Sets f_archivename, f_homepath
       
   178  */
       
   179 int setPaths(char const * archivePath, char const * archiveName)
       
   180 {
       
   181 #ifdef WIN32
       
   182 	char *p;
       
   183 #endif
       
   184 	/* Get the archive Path */
       
   185 	strcpy(f_archivename, archivePath);
       
   186 	strcat(f_archivename, archiveName);
       
   187 
       
   188 	/* Set homepath to where the archive is */
       
   189 	strcpy(f_homepath, archivePath);
       
   190 #ifdef WIN32
       
   191 	strcpy(f_homepathraw, archivePath);
       
   192 	for ( p = f_homepath; *p; p++ )
       
   193 		if (*p == '\\')
       
   194 			*p = '/';
       
   195 #endif
       
   196 
       
   197 	return 0;
       
   198 }
       
   199 
       
   200 
       
   201 /* 
       
   202  * Open the archive
       
   203  * Sets f_archiveFile, f_pkgstart, f_tocbuff and f_cookie.
       
   204  */
       
   205 int openArchive()
       
   206 {
       
   207 	int filelen;
       
   208 
       
   209 	/* Physically open the file */
       
   210 	f_fp = fopen(f_archivename, "rb");
       
   211 	if (f_fp == NULL) {
       
   212 		VS("Cannot open archive: ");
       
   213 		VS(f_archivename);
       
   214 		VS("\n");
       
   215 		return -1;
       
   216 	}
       
   217 
       
   218 	/* Seek to the Cookie at the end of the file. */
       
   219 	fseek(f_fp, 0, SEEK_END);
       
   220 	filelen = ftell(f_fp);
       
   221 	if (fseek(f_fp, -(int)sizeof(COOKIE), SEEK_END)) 
       
   222 	{
       
   223 		VS(f_archivename);
       
   224 		VS(" appears to be an invalid archive\n");
       
   225 		return -1;
       
   226 	}
       
   227 
       
   228 	/* Read the Cookie, and check its MAGIC bytes */
       
   229 	fread(&f_cookie, sizeof(COOKIE), 1, f_fp);
       
   230 	if (strncmp(f_cookie.magic, MAGIC, strlen(MAGIC))) 
       
   231 	{
       
   232 		VS(f_archivename);
       
   233 		VS(" has bad magic!\n");
       
   234 		return -1;
       
   235 	}
       
   236 
       
   237 	/* From the cookie, calculate the archive start */
       
   238 	f_pkgstart = filelen - ntohl(f_cookie.len);
       
   239 
       
   240 	/* Read in in the table of contents */
       
   241 	fseek(f_fp, f_pkgstart + ntohl(f_cookie.TOC), SEEK_SET);
       
   242 	f_tocbuff = (TOC *) malloc(ntohl(f_cookie.TOClen));
       
   243 	if (f_tocbuff == NULL) 
       
   244 	{
       
   245 		FATALERROR("Could not allocate buffer for TOC.");
       
   246 		return -1;
       
   247 	}
       
   248 	fread(f_tocbuff, ntohl(f_cookie.TOClen), 1, f_fp);
       
   249 	f_tocend = (TOC *) (((char *)f_tocbuff) + ntohl(f_cookie.TOClen));
       
   250 
       
   251 	/* Check input file is still ok (should be). */
       
   252 	if (ferror(f_fp))
       
   253 	{
       
   254 		FATALERROR("Error on file");
       
   255 		return -1;
       
   256 	}
       
   257 	return 0;
       
   258 }
       
   259 #ifdef WIN32
       
   260 int mapNames(HMODULE dll)
       
   261 {
       
   262     /* Get all of the entry points that we are interested in */
       
   263 	GETVAR(dll, Py_NoSiteFlag);
       
   264 	GETVAR(dll, Py_OptimizeFlag);
       
   265 	GETVAR(dll, Py_VerboseFlag);
       
   266 	GETPROC(dll, Py_Initialize);
       
   267 	GETPROC(dll, Py_Finalize);
       
   268 	GETPROC(dll, Py_CompileString);
       
   269 	GETPROC(dll, PyImport_ExecCodeModule);
       
   270 	GETPROC(dll, PyRun_SimpleString);
       
   271 	GETPROC(dll, PySys_SetArgv);
       
   272 	GETPROC(dll, Py_SetProgramName);
       
   273 	GETPROC(dll, PyImport_ImportModule);
       
   274 	GETPROC(dll, PyImport_AddModule);
       
   275 	GETPROC(dll, PyObject_SetAttrString);
       
   276 	GETPROC(dll, PyList_New);
       
   277 	GETPROC(dll, PyList_Append);
       
   278 	GETPROC(dll, Py_BuildValue);
       
   279 	GETPROC(dll, PyFile_FromString);
       
   280 	GETPROC(dll, PyString_FromStringAndSize);
       
   281 	GETPROC(dll, PyObject_CallFunction);
       
   282 	GETPROC(dll, PyModule_GetDict);
       
   283 	GETPROC(dll, PyDict_GetItemString);
       
   284 	GETPROC(dll, PyErr_Clear);
       
   285 	GETPROC(dll, PyErr_Occurred);
       
   286 	GETPROC(dll, PyErr_Print);
       
   287 	GETPROC(dll, PyObject_CallObject);
       
   288 	GETPROC(dll, PyObject_CallMethod);
       
   289 	if (ntohl(f_cookie.pyvers) >= 21) {
       
   290 		GETPROC(dll, PySys_AddWarnOption);
       
   291 	}
       
   292 	GETPROC(dll, PyEval_InitThreads);
       
   293 	GETPROC(dll, PyEval_AcquireThread);
       
   294 	GETPROC(dll, PyEval_ReleaseThread);
       
   295 	GETPROC(dll, PyEval_AcquireLock);
       
   296 	GETPROC(dll, PyEval_ReleaseLock);
       
   297 	GETPROC(dll, PyThreadState_Swap);
       
   298 	GETPROC(dll, PyThreadState_New);
       
   299 	GETPROC(dll, PyThreadState_Clear);
       
   300 	GETPROC(dll, PyThreadState_Delete);
       
   301 	GETPROC(dll, PyInterpreterState_New);
       
   302 	GETPROC(dll, Py_NewInterpreter);
       
   303 	GETPROC(dll, Py_EndInterpreter);
       
   304 	GETPROC(dll, PyErr_Print);
       
   305 	GETPROC(dll, PyInt_AsLong);
       
   306 	GETPROC(dll, PySys_SetObject);
       
   307 	return 0;
       
   308 }
       
   309 #endif
       
   310 /*
       
   311  * Load the Python DLL, and get all of the necessary entry points
       
   312  * Windows only (dynamic load)
       
   313  */
       
   314 int loadPython()
       
   315 {
       
   316 #ifdef WIN32
       
   317 	HINSTANCE dll;
       
   318 	char dllpath[_MAX_PATH + 1];
       
   319 
       
   320 	/* Determine the path */
       
   321 	sprintf(dllpath, "%spython%02d.dll", f_homepathraw, ntohl(f_cookie.pyvers));
       
   322 
       
   323 	/* Load the DLL */
       
   324 	dll = LoadLibraryEx(dllpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);  
       
   325 	if (dll) {
       
   326 		VS(dllpath);
       
   327 		VS("\n");
       
   328 	}
       
   329 	else {
       
   330 		sprintf(dllpath, "%spython%02d.dll", f_temppathraw, ntohl(f_cookie.pyvers));
       
   331 		dll = LoadLibraryEx(dllpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
       
   332 		if (dll) {
       
   333 			VS(dllpath); 
       
   334 			VS("\n");
       
   335 		}
       
   336 	}
       
   337 	if (dll == 0) {
       
   338 		FATALERROR("Error loading Python DLL: ");
       
   339 		FATALERROR(dllpath);
       
   340 		FATALERROR("\n");
       
   341 		return -1;
       
   342 	}
       
   343 
       
   344 	mapNames(dll);
       
   345 #endif
       
   346 
       
   347 	return 0;
       
   348 }
       
   349 #ifdef WIN32
       
   350 /*
       
   351  * use this from a dll instead of loadPython()
       
   352  * it will attach to an existing pythonXX.dll,
       
   353  * or load one if needed.
       
   354  */
       
   355 int attachPython(int *loadedNew)
       
   356 {
       
   357 	HMODULE dll;
       
   358 	char nm[_MAX_PATH + 1];
       
   359 
       
   360 	/* Get python's name */
       
   361 	sprintf(nm, "python%02d.dll", ntohl(f_cookie.pyvers));
       
   362 
       
   363 	/* See if it's loaded */
       
   364 	dll = GetModuleHandle(nm);  
       
   365 	if (dll == 0) {
       
   366 		*loadedNew = 1;
       
   367 		return loadPython();
       
   368 	}
       
   369 	mapNames(dll);
       
   370 	*loadedNew = 0;
       
   371 	return 0;
       
   372 }
       
   373 #endif
       
   374 
       
   375 /*
       
   376  * Return pointer to next toc entry.
       
   377  */
       
   378 TOC *incrementTocPtr(TOC* ptoc)
       
   379 {
       
   380 	TOC *result = (TOC*)((char *)ptoc + ntohl(ptoc->structlen));
       
   381 	if (result < f_tocbuff) {
       
   382 		FATALERROR("Cannot read Table of Contents.\n");
       
   383 		return f_tocend;
       
   384 	}
       
   385 	return result;
       
   386 }
       
   387 /*
       
   388  * external API for iterating TOCs
       
   389  */
       
   390 TOC *getFirstTocEntry(void)
       
   391 {
       
   392 	return f_tocbuff;
       
   393 }
       
   394 TOC *getNextTocEntry(TOC *entry)
       
   395 {
       
   396 	TOC *rslt = (TOC*)((char *)entry + ntohl(entry->structlen));
       
   397 	if (rslt >= f_tocend)
       
   398 		return NULL;
       
   399 	return rslt;
       
   400 }
       
   401 /*
       
   402  * A toc entry of type 'o' holds runtime options
       
   403  * toc->name is the arg
       
   404  * this is so you can freeze in command line args to Python
       
   405  */
       
   406 int setRuntimeOptions(void)
       
   407 {
       
   408 	int unbuffered = 0;
       
   409 	TOC *ptoc = f_tocbuff;
       
   410 	while (ptoc < f_tocend) {
       
   411 		if (ptoc->typcd == 'o') {
       
   412 			VS(ptoc->name);
       
   413 			VS("\n");
       
   414 			switch (ptoc->name[0]) {
       
   415 			case 'v':
       
   416 #if defined  WIN32 
       
   417 				*Py_VerboseFlag = 1;
       
   418 #else
       
   419 				Py_VerboseFlag = 1;
       
   420 #endif
       
   421 			break;
       
   422 			case 'u':
       
   423 				unbuffered = 1;
       
   424 			break;
       
   425 #ifdef HAVE_WARNINGS
       
   426 			case 'W':
       
   427 				if (ntohl(f_cookie.pyvers) >= 21) {
       
   428 					PySys_AddWarnOption(&ptoc->name[2]);
       
   429 				}
       
   430 			break;
       
   431 #endif
       
   432 			case 's':
       
   433 #if defined  WIN32 
       
   434 				*Py_NoSiteFlag = 0;
       
   435 #else
       
   436 				Py_NoSiteFlag = 0;
       
   437 #endif
       
   438 			break;
       
   439 			case 'O':
       
   440 #if defined  WIN32 
       
   441 				*Py_OptimizeFlag = 1;
       
   442 #else
       
   443 				Py_OptimizeFlag = 1;
       
   444 #endif
       
   445 			break;
       
   446 			}
       
   447 		}
       
   448 		ptoc = incrementTocPtr(ptoc);
       
   449 	}
       
   450 	if (unbuffered) {
       
   451 #ifdef WIN32
       
   452 		_setmode(fileno(stdin), O_BINARY);
       
   453 		_setmode(fileno(stdout), O_BINARY);
       
   454 #else
       
   455 		fflush(stdout);
       
   456 		fflush(stderr);
       
   457 #ifdef HAVE_SETVBUF
       
   458 		setvbuf(stdin, (char *)NULL, _IONBF, 0);
       
   459 		setvbuf(stdout, (char *)NULL, _IONBF, 0);
       
   460 		setvbuf(stderr, (char *)NULL, _IONBF, 0);
       
   461 #else
       
   462 		setbuf(stdin, (char *)NULL);
       
   463 		setbuf(stdout, (char *)NULL);
       
   464 		setbuf(stderr, (char *)NULL);
       
   465 #endif
       
   466 #endif
       
   467 	}
       
   468 	return 0;
       
   469 }
       
   470 /*
       
   471  * Start python - return 0 on success
       
   472  */
       
   473 int startPython(int argc, char *argv[])
       
   474 {
       
   475     /* Set PYTHONPATH so dynamic libs will load */
       
   476 	static char pypath[2*_MAX_PATH + 14];
       
   477 	int pathlen = 1;
       
   478 	int i;
       
   479 	char cmd[_MAX_PATH+1+80];
       
   480 	char tmp[_MAX_PATH+1];
       
   481 	PyObject *py_argv;
       
   482 	PyObject *val;
       
   483 	PyObject *sys;
       
   484 
       
   485 	VS("Manipulating evironment\n");
       
   486 	if (f_workpath && (strcmp(f_workpath, f_homepath) != 0)) {
       
   487 		strcpy(pypath, "PYTHONPATH=");
       
   488 		strcat(pypath, f_workpath);
       
   489 		pypath[strlen(pypath)-1] = '\0';
       
   490 		strcat(pypath, PATHSEP);
       
   491 		strcat(pypath, f_homepath);
       
   492 		pathlen = 2;
       
   493 	}
       
   494 	else {
       
   495 		/* never extracted anything, or extracted to homepath - homepath will do */
       
   496 		strcpy(pypath, "PYTHONPATH=");
       
   497 		strcat(pypath, f_homepath);
       
   498 	}
       
   499 	/* don't chop off SEP if root directory */
       
   500 #ifdef WIN32
       
   501 	if (strlen(pypath) > 14)
       
   502 #else
       
   503 	if (strlen(pypath) > 12)
       
   504 #endif
       
   505 		pypath[strlen(pypath)-1] = '\0';
       
   506 
       
   507 	putenv(pypath);
       
   508 	VS(pypath); 
       
   509 	VS("\n");
       
   510 	/* Clear out PYTHONHOME to avoid clashing with any installation */
       
   511 #ifdef WIN32
       
   512 	putenv("PYTHONHOME=");
       
   513 #endif
       
   514 
       
   515 	/* Start python. */
       
   516 	/* VS("Loading python\n"); */
       
   517 #if defined  WIN32 
       
   518 	*Py_NoSiteFlag = 1;	/* maybe changed to 0 by setRuntimeOptions() */
       
   519 #else
       
   520 	Py_NoSiteFlag = 1;
       
   521 #endif
       
   522 	setRuntimeOptions();
       
   523 #ifdef WIN32
       
   524 	Py_SetProgramName(f_archivename); /*XXX*/
       
   525 #endif
       
   526 	Py_Initialize();
       
   527 
       
   528 	/* Set sys.path */
       
   529 	/* VS("Manipulating Python's sys.path\n"); */
       
   530 	strcpy(tmp, f_homepath);
       
   531 	tmp[strlen(tmp)-1] = '\0';
       
   532 	PyRun_SimpleString("import sys\n");
       
   533 	PyRun_SimpleString("while sys.path:\n del sys.path[0]\n");
       
   534 	sprintf(cmd, "sys.path.append('%s')", tmp);
       
   535 	PyRun_SimpleString (cmd);
       
   536 	if (pathlen == 2) {
       
   537 		strcpy(tmp, f_workpath);
       
   538 		tmp[strlen(tmp)-1] = '\0';
       
   539 		sprintf(cmd, "sys.path.insert(0, '%s')", tmp);
       
   540 		PyRun_SimpleString(cmd);
       
   541 	}
       
   542 
       
   543 	/* Set argv[0] to be the archiveName */
       
   544 	py_argv = PyList_New(0);
       
   545 	val = Py_BuildValue("s", f_archivename);
       
   546 	PyList_Append(py_argv, val);
       
   547 	for (i = 1; i < argc; ++i) {
       
   548 		val = Py_BuildValue ("s", argv[i]);
       
   549 		PyList_Append (py_argv, val);
       
   550 	}
       
   551 	sys = PyImport_ImportModule("sys");
       
   552 	/* VS("Setting sys.argv\n"); */
       
   553 	PyObject_SetAttrString(sys, "argv", py_argv);
       
   554 
       
   555 	/* Check for a python error */
       
   556 	if (PyErr_Occurred())
       
   557 	{
       
   558 		FATALERROR("Error detected starting Python VM.");
       
   559 		return -1;
       
   560 	}
       
   561 
       
   562 	return 0;
       
   563 }
       
   564 
       
   565 /*
       
   566  * Import modules embedded in the archive - return 0 on success
       
   567  */
       
   568 int importModules()
       
   569 {
       
   570 	PyObject *marshal;
       
   571 	PyObject *marshaldict;
       
   572 	PyObject *loadfunc;
       
   573 	PyObject *pyfile;
       
   574 	TOC *ptoc;
       
   575 	PyObject *co;
       
   576 	PyObject *mod;
       
   577 	PyObject *res;
       
   578 	char buf[32];
       
   579 
       
   580 	VS("importing modules from CArchive\n"); 
       
   581 
       
   582 	/* Get the Python function marshall.load
       
   583 		* Here we collect some reference to PyObject that we don't dereference
       
   584 		* Doesn't matter because the objects won't be going away anyway.
       
   585 		*/
       
   586 	marshal = PyImport_ImportModule("marshal");
       
   587 	marshaldict = PyModule_GetDict(marshal);
       
   588 	loadfunc = PyDict_GetItemString(marshaldict, "loads");
       
   589 
       
   590 	/* Iterate through toc looking for module entries (type 'm')
       
   591 		* this is normally just bootstrap stuff (archive and iu)
       
   592 		*/
       
   593 	ptoc = f_tocbuff;
       
   594 	while (ptoc < f_tocend) {
       
   595 		if (ptoc->typcd == 'm' || ptoc->typcd == 'M') 
       
   596 		{
       
   597 			unsigned char *modbuf = extract(ptoc);
       
   598 
       
   599 			/* .pyc/.pyo files have 8 bytes header. Skip it and get a Python
       
   600 			 * string directly pointing at the marshalled code.
       
   601 			 */
       
   602 			PyObject *mods = PyString_FromStringAndSize(modbuf + 8,
       
   603 				ntohl(ptoc->ulen) - 8);
       
   604             
       
   605 			VS(ptoc->name);
       
   606 			VS("\n");
       
   607 			
       
   608 			co = PyObject_CallFunction(loadfunc, "O", mods);
       
   609 			mod = PyImport_ExecCodeModule(ptoc->name, co);
       
   610 
       
   611 			/* Check for errors in loading */
       
   612 			if (mod == NULL) {
       
   613 				FATALERROR("mod is NULL - ");
       
   614 				FATALERROR(ptoc->name);
       
   615 			}
       
   616 			if (PyErr_Occurred())
       
   617 			{
       
   618 				PyErr_Print();
       
   619 				PyErr_Clear();
       
   620 			}
       
   621 
       
   622 			Py_DECREF(mods);
       
   623 			free(modbuf);
       
   624 		}
       
   625 		ptoc = incrementTocPtr(ptoc); 
       
   626 	}
       
   627 
       
   628 	return 0;
       
   629 }
       
   630 
       
   631 
       
   632 /* Install a zlib from a toc entry
       
   633  * Return non zero on failure
       
   634  */
       
   635 int installZlib(TOC *ptoc)
       
   636 {
       
   637 	int rc;
       
   638 	int zlibpos = f_pkgstart + ntohl(ptoc->pos);
       
   639 	char *tmpl = "sys.path.append(r\"%s?%d\")\n";
       
   640 	char *cmd = (char *) malloc(strlen(tmpl) + strlen(f_archivename) + 32);
       
   641 	sprintf(cmd, tmpl, f_archivename, zlibpos);
       
   642 	//VS(cmd);
       
   643 	rc = PyRun_SimpleString(cmd);
       
   644 	if (rc != 0)
       
   645 	{
       
   646 		FATALERROR("Error in command.");
       
   647 		FATALERROR(cmd);
       
   648 		free(cmd);
       
   649 		return -1;
       
   650 	}
       
   651 
       
   652 	free(cmd);
       
   653 	return 0;
       
   654 }
       
   655 
       
   656 
       
   657 /*
       
   658  * Install zlibs 
       
   659  * Return non zero on failure
       
   660  */
       
   661 int installZlibs()
       
   662 {
       
   663 	TOC * ptoc;
       
   664 	VS("Installing import hooks\n");
       
   665 
       
   666 	/* Iterate through toc looking for zlibs (type 'z') */
       
   667 	ptoc = f_tocbuff;
       
   668 	while (ptoc < f_tocend) {
       
   669 		if (ptoc->typcd == 'z') 
       
   670 		{
       
   671 			VS(ptoc->name);
       
   672 			VS("\n");
       
   673 			installZlib(ptoc);
       
   674 		}
       
   675 
       
   676 		ptoc = incrementTocPtr(ptoc); 
       
   677 	}
       
   678 	return 0;
       
   679 }
       
   680 
       
   681 #ifndef NOZLIB
       
   682 /* decompress data in buff, described by ptoc
       
   683  * return in malloc'ed buffer (needs to be freed)
       
   684  */
       
   685 unsigned char *decompress(unsigned char * buff, TOC *ptoc)
       
   686 {
       
   687 	const char *ver;
       
   688 	unsigned char *out;
       
   689 	z_stream zstream;
       
   690 	int rc;
       
   691 	char msg[400];
       
   692 
       
   693 	ver = (zlibVersion)();
       
   694 	out = (unsigned char *)malloc(ntohl(ptoc->ulen));
       
   695 	if (out == NULL) {
       
   696 		OTHERERROR("Error allocating decompression buffer\n");
       
   697 		return NULL;
       
   698 	}
       
   699 
       
   700 	zstream.zalloc = NULL;
       
   701 	zstream.zfree = NULL;
       
   702 	zstream.opaque = NULL;
       
   703 	zstream.next_in = buff;
       
   704 	zstream.avail_in = ntohl(ptoc->len);
       
   705 	zstream.next_out = out;
       
   706 	zstream.avail_out = ntohl(ptoc->ulen);
       
   707 	rc = inflateInit(&zstream);
       
   708 	if (rc >= 0) {
       
   709 		rc = (inflate)(&zstream, Z_FINISH);
       
   710 		if (rc >= 0) {
       
   711 			rc = (inflateEnd)(&zstream);
       
   712 		}
       
   713 		else {
       
   714 			sprintf(msg, "Error %d from inflate: %s\n", rc, zstream.msg);
       
   715 			OTHERERROR(msg);
       
   716 			return NULL;
       
   717 		}
       
   718 	}
       
   719 	else {
       
   720 		sprintf(msg, "Error %d from inflateInit: %s\n", rc, zstream.msg);
       
   721 		OTHERERROR(msg);
       
   722 		return NULL;
       
   723 	}	
       
   724 	return out;
       
   725 }
       
   726 #endif
       
   727 /* 
       
   728  * extract an archive entry
       
   729  * returns pointer to the data (must be freed)
       
   730  */
       
   731 unsigned char *extract(TOC *ptoc)
       
   732 {
       
   733 	unsigned char *data;
       
   734 	unsigned char *tmp;
       
   735 	char msg[400];
       
   736 
       
   737 	sprintf( msg, " extracting %1.20s (%d, %c)\n", ptoc->name, ptoc->cflag, ptoc->typcd);
       
   738 	//VS(msg);
       
   739 	fseek(f_fp, f_pkgstart + ntohl(ptoc->pos), SEEK_SET);
       
   740 	data = (unsigned char *)malloc(ntohl(ptoc->len));
       
   741 	if (data == NULL) {
       
   742 		OTHERERROR("Could not allocate read buffer\n");
       
   743 		return NULL;
       
   744 	}
       
   745 	fread(data, ntohl(ptoc->len), 1, f_fp);
       
   746 	if (ptoc->cflag == '\1') {
       
   747 #ifndef NOZLIB
       
   748 		tmp = decompress(data, ptoc);
       
   749 		free(data);
       
   750 		data = tmp;
       
   751 		if (data == NULL) {
       
   752 			sprintf(msg, "Error decompressing %s\n", ptoc->name);
       
   753 			OTHERERROR(msg);
       
   754 			return NULL;
       
   755 		}
       
   756 #else
       
   757 		FATALERROR("No ZLIB support but archive uses compression\n");
       
   758 		return NULL;
       
   759 #endif
       
   760 	}
       
   761 	return data;
       
   762 }
       
   763 /*
       
   764  * helper for extract2fs
       
   765  * which may try multiple places
       
   766  */
       
   767 FILE *openTarget(char *path, char*name)
       
   768 {
       
   769 	struct stat sbuf;
       
   770 	char fnm[_MAX_PATH+1];
       
   771 	strcpy(fnm, path);
       
   772 	strcat(fnm, name);
       
   773 	if (stat(fnm, &sbuf) == -1) {
       
   774 		VS(fnm);
       
   775 		VS("\n");
       
   776 		return fopen(fnm, "wb");
       
   777 	}
       
   778 	return NULL;
       
   779 }
       
   780 /*
       
   781  * extract from the archive
       
   782  * and copy to the filesystem 
       
   783  * relative to the directory the archive's in
       
   784  */
       
   785 int extract2fs(TOC *ptoc)
       
   786 {
       
   787 #ifdef WIN32
       
   788 	char *p;
       
   789 #endif
       
   790 	FILE *out;
       
   791 	unsigned char *data = extract(ptoc);
       
   792 
       
   793 	if (!f_workpath) {
       
   794 		getTempPath(f_temppath);
       
   795 #ifdef WIN32
       
   796 		strcpy(f_temppathraw, f_temppath);
       
   797 		for ( p=f_temppath; *p; p++ )
       
   798 			if (*p == '\\')
       
   799 				*p = '/';
       
   800 #endif
       
   801 		f_workpath = f_temppath;
       
   802 	}
       
   803 	out = openTarget(f_workpath, ptoc->name);
       
   804 
       
   805 	if (out == NULL)  {
       
   806 		FATALERROR(ptoc->name);
       
   807 		FATALERROR(" could not be extracted!\n");
       
   808 	}
       
   809 	else {
       
   810 		fwrite(data, ntohl(ptoc->ulen), 1, out);
       
   811 #ifndef WIN32
       
   812 		fchmod(fileno(out), S_IRUSR | S_IWUSR | S_IXUSR);
       
   813 #endif
       
   814 		fclose(out);
       
   815 	}
       
   816 	free(data);
       
   817 	return 0;
       
   818 }
       
   819 /*
       
   820  * extract all binaries (type 'b') to the filesystem
       
   821  */
       
   822 int extractBinaries(char **workpath)
       
   823 {
       
   824 	TOC * ptoc = f_tocbuff;
       
   825 	workpath[0] = '\0';
       
   826 	VS("Extracting binaries\n");
       
   827 	while (ptoc < f_tocend) {
       
   828 		if (ptoc->typcd == 'b') 
       
   829 		if (extract2fs(ptoc))
       
   830 		return -1;
       
   831 		ptoc = incrementTocPtr(ptoc); 
       
   832 	}
       
   833 	*workpath = f_workpath;
       
   834 	return 0;
       
   835 }
       
   836 /* 
       
   837  * Run scripts
       
   838  * Return non zero on failure
       
   839  */
       
   840 int runScripts()
       
   841 {
       
   842 	unsigned char *data;
       
   843 	int rc = 0;
       
   844 	TOC * ptoc = f_tocbuff;
       
   845 	char msg[400];
       
   846 	VS("Running scripts\n");
       
   847 
       
   848 	/* Iterate through toc looking for scripts (type 's') */
       
   849 	while (ptoc < f_tocend) {
       
   850 		if (ptoc->typcd == 's') {
       
   851 			/* Get data out of the archive.  */
       
   852 			data = extract(ptoc);
       
   853 			/* Run it */
       
   854 			rc = PyRun_SimpleString(data);
       
   855 			/* log errors and abort */
       
   856 			if (rc != 0) {
       
   857 				sprintf(msg, " RC: %d from %s\n", rc, ptoc->name);
       
   858 				VS(msg);
       
   859 				return rc;
       
   860 			}
       
   861 			free(data);
       
   862 		}
       
   863 
       
   864 		ptoc = incrementTocPtr(ptoc); 
       
   865 	}
       
   866 	return 0;
       
   867 }
       
   868 
       
   869 /* 
       
   870  * call a simple "int func(void)" entry point.  Assumes such a function
       
   871  * exists in the main namespace.
       
   872  * Return non zero on failure, with -2 if the specific error is
       
   873  * that the function does not exist in the namespace.
       
   874  */
       
   875 int callSimpleEntryPoint(char *name, int *presult)
       
   876 {
       
   877 	int rc = -1;
       
   878 	/* Objects with no ref. */
       
   879 	PyObject *mod, *dict;
       
   880 	/* Objects with refs to kill. */
       
   881 	PyObject *func = NULL, *pyresult = NULL;
       
   882 
       
   883 	mod = PyImport_AddModule("__main__"); /* NO ref added */
       
   884 	if (!mod) {
       
   885 		VS("No __main__\n");
       
   886 		goto done;
       
   887 	}
       
   888 	dict = PyModule_GetDict(mod); /* NO ref added */
       
   889 	if (!mod) {
       
   890 		VS("No __dict__\n");
       
   891 		goto done;
       
   892 	}
       
   893 	func = PyDict_GetItemString(dict, name);
       
   894 	if (func == NULL) { /* should explicitly check KeyError */
       
   895 		VS("CallSimpleEntryPoint can't find the function name\n");
       
   896 		rc = -2;
       
   897 		goto done;
       
   898 	}
       
   899 	pyresult = PyObject_CallFunction(func, "");
       
   900 	if (pyresult==NULL) goto done;
       
   901 	PyErr_Clear();
       
   902 	*presult = PyInt_AsLong(pyresult);
       
   903 	rc = PyErr_Occurred() ? -1 : 0;
       
   904 	VS( rc ? "Finished with failure\n" : "Finished OK\n");
       
   905 	// all done!
       
   906 done:
       
   907 	Py_XDECREF(func);
       
   908 	Py_XDECREF(pyresult);
       
   909 	/* can't leave Python error set, else it may
       
   910 	   cause failures in later async code */
       
   911 	if (rc)
       
   912 		/* But we will print them 'cos they may be useful */
       
   913 		PyErr_Print();
       
   914 	PyErr_Clear();
       
   915 	return rc;
       
   916 }
       
   917 
       
   918 /*
       
   919  * Launch an archive with the given fully-qualified path name
       
   920  * No command line, no extracting of binaries
       
   921  * Designed for embedding situations.
       
   922  */
       
   923 int launchembedded(char const * archivePath, char  const * archiveName)
       
   924 {
       
   925 	char pathnm[_MAX_PATH];
       
   926 
       
   927 	VS("START\n");
       
   928 	strcpy(pathnm, archivePath);
       
   929 	strcat(pathnm, archiveName);
       
   930 	/* Set up paths */
       
   931 	if (setPaths(archivePath, archiveName))
       
   932 		return -1;
       
   933 	VS("Got Paths\n");
       
   934 	/* Open the archive */
       
   935 	if (openArchive())
       
   936 		return -1;
       
   937 	VS("Opened Archive\n");
       
   938 	/* Load Python DLL */
       
   939 	if (loadPython())
       
   940 		return -1;
       
   941 
       
   942 	/* Start Python with silly command line */
       
   943 	if (startPython(1, (char**)&pathnm))
       
   944 		return -1;
       
   945 	VS("Started Python\n");
       
   946 
       
   947 	/* a signal to scripts */
       
   948 	PyRun_SimpleString("import sys;sys.frozen='dll'\n");
       
   949 	VS("set sys.frozen\n");
       
   950 	/* Import modules from archive - this is to bootstrap */
       
   951 	if (importModules())
       
   952 		return -1;
       
   953 	VS("Imported Modules\n");
       
   954 	/* Install zlibs - now import hooks are in place */
       
   955 	if (installZlibs())
       
   956 		return -1;
       
   957 	VS("Installed Zlibs\n");
       
   958 	/* Run scripts */
       
   959 	if (runScripts())
       
   960 		return -1;
       
   961 	VS("All scripts run\n");
       
   962 	if (PyErr_Occurred()) {
       
   963 		// PyErr_Print();
       
   964 		//PyErr_Clear();
       
   965 		VS("Some error occurred\n");
       
   966 	}
       
   967 	VS("OK.\n");
       
   968 
       
   969 	return 0;
       
   970 }
       
   971 
       
   972 /* for finer grained control */
       
   973 /*
       
   974  * initialize (this always needs to be done)
       
   975  */
       
   976 int init(char const * archivePath, char  const * archiveName, char const * workpath)
       
   977 {
       
   978 	char *p;
       
   979 
       
   980 	if (workpath) {
       
   981 		f_workpath = (char *)workpath;
       
   982 #ifdef WIN32
       
   983 		strcpy(f_temppathraw, f_workpath);
       
   984 		for ( p = f_temppathraw; *p; p++ )
       
   985 			if (*p == '/')
       
   986 				*p = '\\';
       
   987 #endif
       
   988 	}
       
   989 
       
   990 	/* Set up paths */
       
   991 	if (setPaths(archivePath, archiveName))
       
   992 		return -1;
       
   993 
       
   994 	/* Open the archive */
       
   995 	if (openArchive())
       
   996 		return -1;
       
   997 
       
   998 	return 0;
       
   999 }
       
  1000 /* once init'ed, you might want to extractBinaries()
       
  1001  * If you do, what comes after is very platform specific.
       
  1002  * Once you've taken care of the platform specific details,
       
  1003  * or if there are no binaries to extract, you go on
       
  1004  * to doIt(), which is the important part
       
  1005  */
       
  1006 int doIt(int argc, char *argv[]) 
       
  1007 {
       
  1008 	int rc = 0;
       
  1009 	/* Load Python DLL */
       
  1010 	if (loadPython())
       
  1011 		return -1;
       
  1012 
       
  1013 	/* Start Python. */
       
  1014 	if (startPython(argc, argv))
       
  1015 		return -1;
       
  1016 
       
  1017 	/* Import modules from archive - bootstrap */
       
  1018 	if (importModules())
       
  1019 		return -1;
       
  1020 
       
  1021 	/* Install zlibs  - now all hooks in place */
       
  1022 	if (installZlibs())
       
  1023 		return -1;
       
  1024 
       
  1025 	/* Run scripts */
       
  1026 	rc = runScripts();
       
  1027 
       
  1028 	VS("OK.\n");
       
  1029 
       
  1030 	return rc;
       
  1031 }
       
  1032 void clear(const char *dir);
       
  1033 #ifdef WIN32
       
  1034 void removeOne(char *fnm, int pos, struct _finddata_t finfo)
       
  1035 {
       
  1036 	if ( strcmp(finfo.name, ".")==0  || strcmp(finfo.name, "..") == 0 )
       
  1037 		return;
       
  1038 	fnm[pos] = '\0';
       
  1039 	strcat(fnm, finfo.name);
       
  1040 	if ( finfo.attrib & _A_SUBDIR )
       
  1041 		clear(fnm);
       
  1042 	else 
       
  1043 		remove(fnm);
       
  1044 }
       
  1045 void clear(const char *dir) 
       
  1046 {
       
  1047 	char fnm[_MAX_PATH+1];
       
  1048 	struct _finddata_t finfo;
       
  1049 	long h;
       
  1050 	int dirnmlen;
       
  1051 	strcpy(fnm, dir);
       
  1052 	dirnmlen = strlen(fnm);
       
  1053 	if ( fnm[dirnmlen-1] != '/' && fnm[dirnmlen-1] != '\\' ) {
       
  1054 		strcat(fnm, "\\");
       
  1055 		dirnmlen++;
       
  1056 	}
       
  1057 	strcat(fnm, "*");
       
  1058 	h = _findfirst(fnm, &finfo);
       
  1059 	if (h != -1) {
       
  1060 		removeOne(fnm, dirnmlen, finfo);
       
  1061 		while ( _findnext(h, &finfo) == 0 ) 
       
  1062 			removeOne(fnm, dirnmlen, finfo);
       
  1063 		_findclose(h);
       
  1064 	}
       
  1065 	rmdir(dir);
       
  1066 }
       
  1067 #else
       
  1068 void removeOne(char *pnm, int pos, const char *fnm)
       
  1069 {
       
  1070 	struct stat sbuf;
       
  1071 	if ( strcmp(fnm, ".")==0  || strcmp(fnm, "..") == 0 )
       
  1072 		return;
       
  1073 	pnm[pos] = '\0';
       
  1074 	strcat(pnm, fnm);
       
  1075 	if ( stat(pnm, &sbuf) == 0 ) {
       
  1076 		if ( S_ISDIR(sbuf.st_mode) )
       
  1077 			clear(pnm);
       
  1078 		else 
       
  1079 			unlink(pnm);
       
  1080 	}
       
  1081 }
       
  1082 void clear(const char *dir) 
       
  1083 {
       
  1084 	char fnm[_MAX_PATH+1];
       
  1085 	DIR *ds;
       
  1086 	struct dirent *finfo;
       
  1087 	int dirnmlen;
       
  1088 
       
  1089 	strcpy(fnm, dir);
       
  1090 	dirnmlen = strlen(fnm);
       
  1091 	if ( fnm[dirnmlen-1] != '/' ) {
       
  1092 		strcat(fnm, "/");
       
  1093 		dirnmlen++;
       
  1094 	}
       
  1095 	ds = opendir(dir);
       
  1096 	finfo = readdir(ds);
       
  1097 	while (finfo) {
       
  1098 		removeOne(fnm, dirnmlen, finfo->d_name);
       
  1099 		finfo = readdir(ds);
       
  1100 	}
       
  1101 	closedir(ds);
       
  1102 	rmdir(dir);
       
  1103 }
       
  1104 #endif
       
  1105 
       
  1106 /*
       
  1107  * If binaries were extracted, this should be called
       
  1108  * to remove them
       
  1109  */
       
  1110 void cleanUp()
       
  1111 {
       
  1112 	if (f_temppath[0])
       
  1113 		clear(f_temppath);
       
  1114 }
       
  1115 /*
       
  1116  * Helpers for embedders
       
  1117  */
       
  1118 int getPyVersion(void)
       
  1119 {
       
  1120 	return ntohl(f_cookie.pyvers);
       
  1121 }
       
  1122 void finalizePython(void)
       
  1123 {
       
  1124 	Py_Finalize();
       
  1125 }
       
  1126