Commit 354e3d90 authored by Thomas Heller's avatar Thomas Heller

Change the zipimport implementation to accept files containing

arbitrary bytes before the actual zip compatible archive.  Zipfiles
containing comments at the end of the file are still not supported.

Add a testcase to test_zipimport, and update NEWS.

This closes sf #775637 and sf #669036.
parent fac083d1
...@@ -49,7 +49,7 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): ...@@ -49,7 +49,7 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
zipimport._zip_directory_cache.clear() zipimport._zip_directory_cache.clear()
ImportHooksBaseTestCase.setUp(self) ImportHooksBaseTestCase.setUp(self)
def doTest(self, expected_ext, files, *modules): def doTest(self, expected_ext, files, *modules, **kw):
z = ZipFile(TEMP_ZIP, "w") z = ZipFile(TEMP_ZIP, "w")
try: try:
for name, (mtime, data) in files.items(): for name, (mtime, data) in files.items():
...@@ -57,6 +57,19 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): ...@@ -57,6 +57,19 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
zinfo.compress_type = self.compression zinfo.compress_type = self.compression
z.writestr(zinfo, data) z.writestr(zinfo, data)
z.close() z.close()
stuff = kw.get("stuff", None)
if stuff is not None:
# Prepend 'stuff' to the start of the zipfile
f = open(TEMP_ZIP, "rb")
data = f.read()
f.close()
f = open(TEMP_ZIP, "wb")
f.write(stuff)
f.write(data)
f.close()
sys.path.insert(0, TEMP_ZIP) sys.path.insert(0, TEMP_ZIP)
mod = __import__(".".join(modules), globals(), locals(), mod = __import__(".".join(modules), globals(), locals(),
...@@ -181,6 +194,12 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): ...@@ -181,6 +194,12 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
"some.data": (NOW, "some data")} "some.data": (NOW, "some data")}
self.doTest(pyc_ext, files, TESTMOD) self.doTest(pyc_ext, files, TESTMOD)
def testImport_WithStuff(self):
# try importing from a zipfile which contains additional
# stuff at the beginning of the file
files = {TESTMOD + ".py": (NOW, test_src)}
self.doTest(".py", files, TESTMOD,
stuff="Some Stuff"*31)
class CompressedZipImportTestCase(UncompressedZipImportTestCase): class CompressedZipImportTestCase(UncompressedZipImportTestCase):
compression = ZIP_DEFLATED compression = ZIP_DEFLATED
......
...@@ -12,6 +12,10 @@ What's New in Python 2.3 release candidate 2? ...@@ -12,6 +12,10 @@ What's New in Python 2.3 release candidate 2?
Core and builtins Core and builtins
----------------- -----------------
- It is now possible to import from zipfiles containing additional
data bytes before the zip compatible archive. Zipfiles containing a
comment at the end are still unsupported.
Extension modules Extension modules
----------------- -----------------
......
...@@ -655,11 +655,12 @@ read_directory(char *archive) ...@@ -655,11 +655,12 @@ read_directory(char *archive)
PyObject *files = NULL; PyObject *files = NULL;
FILE *fp; FILE *fp;
long compress, crc, data_size, file_size, file_offset, date, time; long compress, crc, data_size, file_size, file_offset, date, time;
long header_offset, name_size, header_size; long header_offset, name_size, header_size, header_position;
long i, l, length, count; long i, l, length, count;
char path[MAXPATHLEN + 5]; char path[MAXPATHLEN + 5];
char name[MAXPATHLEN + 5]; char name[MAXPATHLEN + 5];
char *p, endof_central_dir[22]; char *p, endof_central_dir[22];
long arc_offset; /* offset from beginning of file to start of zip-archive */
if (strlen(archive) > MAXPATHLEN) { if (strlen(archive) > MAXPATHLEN) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
...@@ -675,6 +676,7 @@ read_directory(char *archive) ...@@ -675,6 +676,7 @@ read_directory(char *archive)
return NULL; return NULL;
} }
fseek(fp, -22, SEEK_END); fseek(fp, -22, SEEK_END);
header_position = ftell(fp);
if (fread(endof_central_dir, 1, 22, fp) != 22) { if (fread(endof_central_dir, 1, 22, fp) != 22) {
fclose(fp); fclose(fp);
PyErr_Format(ZipImportError, "can't read Zip file: " PyErr_Format(ZipImportError, "can't read Zip file: "
...@@ -689,7 +691,10 @@ read_directory(char *archive) ...@@ -689,7 +691,10 @@ read_directory(char *archive)
return NULL; return NULL;
} }
header_size = get_long((unsigned char *)endof_central_dir + 12);
header_offset = get_long((unsigned char *)endof_central_dir + 16); header_offset = get_long((unsigned char *)endof_central_dir + 16);
arc_offset = header_position - header_offset - header_size;
header_offset += arc_offset;
files = PyDict_New(); files = PyDict_New();
if (files == NULL) if (files == NULL)
...@@ -720,7 +725,7 @@ read_directory(char *archive) ...@@ -720,7 +725,7 @@ read_directory(char *archive)
PyMarshal_ReadShortFromFile(fp) + PyMarshal_ReadShortFromFile(fp) +
PyMarshal_ReadShortFromFile(fp); PyMarshal_ReadShortFromFile(fp);
fseek(fp, header_offset + 42, 0); fseek(fp, header_offset + 42, 0);
file_offset = PyMarshal_ReadLongFromFile(fp); file_offset = PyMarshal_ReadLongFromFile(fp) + arc_offset;
if (name_size > MAXPATHLEN) if (name_size > MAXPATHLEN)
name_size = MAXPATHLEN; name_size = MAXPATHLEN;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment