symbian-qemu-0.9.1-12/python-2.6.1/PC/bdist_wininst/extract.c
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/python-2.6.1/PC/bdist_wininst/extract.c	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,321 @@
+/*
+  IMPORTANT NOTE: IF THIS FILE IS CHANGED, WININST-6.EXE MUST BE RECOMPILED
+  WITH THE MSVC6 WININST.DSW WORKSPACE FILE MANUALLY, AND WININST-7.1.EXE MUST
+  BE RECOMPILED WITH THE MSVC 2003.NET WININST-7.1.VCPROJ FILE MANUALLY.
+
+  IF CHANGES TO THIS FILE ARE CHECKED INTO PYTHON CVS, THE RECOMPILED BINARIES
+  MUST BE CHECKED IN AS WELL!
+*/
+
+#include <windows.h>
+
+#include "zlib.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "archive.h"
+
+/* Convert unix-path to dos-path */
+static void normpath(char *path)
+{
+	while (path && *path) {
+		if (*path == '/')
+			*path = '\\';
+		++path;
+	}
+}
+
+BOOL ensure_directory(char *pathname, char *new_part, NOTIFYPROC notify)
+{
+	while (new_part && *new_part && (new_part = strchr(new_part, '\\'))) {
+		DWORD attr;
+		*new_part = '\0';
+		attr = GetFileAttributes(pathname);
+		if (attr == -1) {
+			/* nothing found */
+			if (!CreateDirectory(pathname, NULL) && notify)
+				notify(SYSTEM_ERROR,
+				       "CreateDirectory (%s)", pathname);
+			else
+				notify(DIR_CREATED, pathname);
+		}
+		if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+			;
+		} else {
+			SetLastError(183);
+			if (notify)
+				notify(SYSTEM_ERROR,
+				       "CreateDirectory (%s)", pathname);
+		}
+		*new_part = '\\';
+		++new_part;
+	}
+	return TRUE;
+}
+
+/* XXX Should better explicitely specify
+ * uncomp_size and file_times instead of pfhdr!
+ */
+char *map_new_file(DWORD flags, char *filename,
+		   char *pathname_part, int size,
+		   WORD wFatDate, WORD wFatTime,
+		   NOTIFYPROC notify)
+{
+	HANDLE hFile, hFileMapping;
+	char *dst;
+	FILETIME ft;
+
+  try_again:
+	if (!flags)
+		flags = CREATE_NEW;
+	hFile = CreateFile(filename,
+			   GENERIC_WRITE | GENERIC_READ,
+			   0, NULL,
+			   flags,
+			   FILE_ATTRIBUTE_NORMAL, NULL);
+	if (hFile == INVALID_HANDLE_VALUE) {
+		DWORD x = GetLastError();
+		switch (x) {
+		case ERROR_FILE_EXISTS:
+			if (notify && notify(CAN_OVERWRITE, filename))
+				hFile = CreateFile(filename,
+						   GENERIC_WRITE|GENERIC_READ,
+						   0, NULL,
+						   CREATE_ALWAYS,
+						   FILE_ATTRIBUTE_NORMAL,
+						   NULL);
+			else {
+				if (notify)
+					notify(FILE_OVERWRITTEN, filename);
+				return NULL;
+			}
+			break;
+		case ERROR_PATH_NOT_FOUND:
+			if (ensure_directory(filename, pathname_part, notify))
+				goto try_again;
+			else
+				return FALSE;
+			break;
+		default:
+			SetLastError(x);
+			break;
+		}
+	}
+	if (hFile == INVALID_HANDLE_VALUE) {
+		if (notify)
+			notify (SYSTEM_ERROR, "CreateFile (%s)", filename);
+		return NULL;
+	}
+
+	if (notify)
+		notify(FILE_CREATED, filename);
+
+	DosDateTimeToFileTime(wFatDate, wFatTime, &ft);
+	SetFileTime(hFile, &ft, &ft, &ft);
+
+
+	if (size == 0) {
+		/* We cannot map a zero-length file (Also it makes
+		   no sense */
+		CloseHandle(hFile);
+		return NULL;
+	}
+
+	hFileMapping = CreateFileMapping(hFile,
+					 NULL, PAGE_READWRITE, 0, size, NULL);
+
+	CloseHandle(hFile);
+
+	if (hFileMapping == INVALID_HANDLE_VALUE) {
+		if (notify)
+			notify(SYSTEM_ERROR,
+			       "CreateFileMapping (%s)", filename);
+		return NULL;
+	}
+
+	dst = MapViewOfFile(hFileMapping,
+			    FILE_MAP_WRITE, 0, 0, 0);
+
+	CloseHandle(hFileMapping);
+
+	if (!dst) {
+		if (notify)
+			notify(SYSTEM_ERROR, "MapViewOfFile (%s)", filename);
+		return NULL;
+	}
+	return dst;
+}
+
+
+BOOL
+extract_file(char *dst, char *src, int method, int comp_size,
+	     int uncomp_size, NOTIFYPROC notify)
+{
+	z_stream zstream;
+	int result;
+
+	if (method == Z_DEFLATED) {
+		int x;
+		memset(&zstream, 0, sizeof(zstream));
+		zstream.next_in = src;
+		zstream.avail_in = comp_size+1;
+		zstream.next_out = dst;
+		zstream.avail_out = uncomp_size;
+
+/* Apparently an undocumented feature of zlib: Set windowsize
+   to negative values to supress the gzip header and be compatible with
+   zip! */
+		result = TRUE;
+		if (Z_OK != (x = inflateInit2(&zstream, -15))) {
+			if (notify)
+				notify(ZLIB_ERROR,
+				       "inflateInit2 returns %d", x);
+			result = FALSE;
+			goto cleanup;
+		}
+		if (Z_STREAM_END != (x = inflate(&zstream, Z_FINISH))) {
+			if (notify)
+				notify(ZLIB_ERROR,
+				       "inflate returns %d", x);
+			result = FALSE;
+		}
+	  cleanup:
+		if (Z_OK != (x = inflateEnd(&zstream))) {
+			if (notify)
+				notify (ZLIB_ERROR,
+					"inflateEnd returns %d", x);
+			result = FALSE;
+		}
+	} else if (method == 0) {
+		memcpy(dst, src, uncomp_size);
+		result = TRUE;
+	} else
+		result = FALSE;
+	UnmapViewOfFile(dst);
+	return result;
+}
+
+/* Open a zip-compatible archive and extract all files
+ * into the specified directory (which is assumed to exist)
+ */
+BOOL
+unzip_archive(SCHEME *scheme, char *dirname, char *data, DWORD size,
+	      NOTIFYPROC notify)
+{
+	int n;
+	char pathname[MAX_PATH];
+	char *new_part;
+
+	/* read the end of central directory record */
+	struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
+						       (struct eof_cdir)];
+
+	int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
+		pe->ofsCDir;
+
+	/* set position to start of central directory */
+	int pos = arc_start + pe->ofsCDir;
+
+	/* make sure this is a zip file */
+	if (pe->tag != 0x06054b50)
+		return FALSE;
+    
+	/* Loop through the central directory, reading all entries */
+	for (n = 0; n < pe->nTotalCDir; ++n) {
+		int i;
+		char *fname;
+		char *pcomp;
+		char *dst;
+		struct cdir *pcdir;
+		struct fhdr *pfhdr;
+
+		pcdir = (struct cdir *)&data[pos];
+		pfhdr = (struct fhdr *)&data[pcdir->ofs_local_header +
+					     arc_start];
+
+		if (pcdir->tag != 0x02014b50)
+			return FALSE;
+		if (pfhdr->tag != 0x04034b50)
+			return FALSE;
+		pos += sizeof(struct cdir);
+		fname = (char *)&data[pos]; /* This is not null terminated! */
+		pos += pcdir->fname_length + pcdir->extra_length +
+			pcdir->comment_length;
+
+		pcomp = &data[pcdir->ofs_local_header
+			      + sizeof(struct fhdr)
+			      + arc_start
+			      + pfhdr->fname_length
+			      + pfhdr->extra_length];
+
+		/* dirname is the Python home directory (prefix) */
+		strcpy(pathname, dirname);
+		if (pathname[strlen(pathname)-1] != '\\')
+			strcat(pathname, "\\");
+		new_part = &pathname[lstrlen(pathname)];
+		/* we must now match the first part of the pathname
+		 * in the archive to a component in the installation
+		 * scheme (PURELIB, PLATLIB, HEADERS, SCRIPTS, or DATA)
+		 * and replace this part by the one in the scheme to use
+		 */
+		for (i = 0; scheme[i].name; ++i) {
+			if (0 == strnicmp(scheme[i].name, fname,
+					  strlen(scheme[i].name))) {
+				char *rest;
+				int len;
+				
+				/* length of the replaced part */
+				int namelen = strlen(scheme[i].name);
+				
+				strcat(pathname, scheme[i].prefix);
+				
+				rest = fname + namelen;
+				len = pfhdr->fname_length - namelen;
+				
+				if ((pathname[strlen(pathname)-1] != '\\')
+				    && (pathname[strlen(pathname)-1] != '/'))
+					strcat(pathname, "\\");
+				/* Now that pathname ends with a separator,
+				 * we must make sure rest does not start with
+				 * an additional one.
+				 */
+				if ((rest[0] == '\\') || (rest[0] == '/')) {
+					++rest;
+					--len;
+				}
+
+				strncat(pathname, rest, len);
+				goto Done;
+			}
+		}
+		/* no prefix to replace found, go unchanged */
+		strncat(pathname, fname, pfhdr->fname_length);
+	  Done:
+		normpath(pathname);
+		if (pathname[strlen(pathname)-1] != '\\') {
+			/*
+			 * The local file header (pfhdr) does not always
+			 * contain the compressed and uncompressed sizes of
+			 * the data depending on bit 3 of the flags field.  So
+			 * it seems better to use the data from the central
+			 * directory (pcdir).
+			 */
+			dst = map_new_file(0, pathname, new_part,
+					   pcdir->uncomp_size,
+					   pcdir->last_mod_file_date,
+					   pcdir->last_mod_file_time, notify);
+			if (dst) {
+				if (!extract_file(dst, pcomp, pfhdr->method,
+						  pcdir->comp_size,
+						  pcdir->uncomp_size,
+						  notify))
+					return FALSE;
+			} /* else ??? */
+		}
+		if (notify)
+			notify(NUM_FILES, new_part, (int)pe->nTotalCDir,
+			       (int)n+1);
+	}
+	return TRUE;
+}