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.
This commit is contained in:
parent
fac083d14a
commit
354e3d90d3
|
@ -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):
|
||||||
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):
|
||||||
"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?
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue