Remove tuple parameter unpacking in aifc to silence warnings under -3.
[python.git] / Modules / zipimport.c
blobd3cd4ad61a753b532f7c4a8b263de84c09e3e0cd
1 #include "Python.h"
2 #include "structmember.h"
3 #include "osdefs.h"
4 #include "marshal.h"
5 #include <time.h>
8 #define IS_SOURCE 0x0
9 #define IS_BYTECODE 0x1
10 #define IS_PACKAGE 0x2
12 struct st_zip_searchorder {
13 char suffix[14];
14 int type;
17 /* zip_searchorder defines how we search for a module in the Zip
18 archive: we first search for a package __init__, then for
19 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
20 are swapped by initzipimport() if we run in optimized mode. Also,
21 '/' is replaced by SEP there. */
22 static struct st_zip_searchorder zip_searchorder[] = {
23 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
24 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
25 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
26 {".pyc", IS_BYTECODE},
27 {".pyo", IS_BYTECODE},
28 {".py", IS_SOURCE},
29 {"", 0}
32 /* zipimporter object definition and support */
34 typedef struct _zipimporter ZipImporter;
36 struct _zipimporter {
37 PyObject_HEAD
38 PyObject *archive; /* pathname of the Zip archive */
39 PyObject *prefix; /* file prefix: "a/sub/directory/" */
40 PyObject *files; /* dict with file info {path: toc_entry} */
43 static PyObject *ZipImportError;
44 static PyObject *zip_directory_cache = NULL;
46 /* forward decls */
47 static PyObject *read_directory(char *archive);
48 static PyObject *get_data(char *archive, PyObject *toc_entry);
49 static PyObject *get_module_code(ZipImporter *self, char *fullname,
50 int *p_ispackage, char **p_modpath);
53 #define ZipImporter_Check(op) PyObject_TypeCheck(op, &ZipImporter_Type)
56 /* zipimporter.__init__
57 Split the "subdirectory" from the Zip archive path, lookup a matching
58 entry in sys.path_importer_cache, fetch the file directory from there
59 if found, or else read it from the archive. */
60 static int
61 zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds)
63 char *path, *p, *prefix, buf[MAXPATHLEN+2];
64 size_t len;
66 if (!_PyArg_NoKeywords("zipimporter()", kwds))
67 return -1;
69 if (!PyArg_ParseTuple(args, "s:zipimporter",
70 &path))
71 return -1;
73 len = strlen(path);
74 if (len == 0) {
75 PyErr_SetString(ZipImportError, "archive path is empty");
76 return -1;
78 if (len >= MAXPATHLEN) {
79 PyErr_SetString(ZipImportError,
80 "archive path too long");
81 return -1;
83 strcpy(buf, path);
85 #ifdef ALTSEP
86 for (p = buf; *p; p++) {
87 if (*p == ALTSEP)
88 *p = SEP;
90 #endif
92 path = NULL;
93 prefix = NULL;
94 for (;;) {
95 #ifndef RISCOS
96 struct stat statbuf;
97 int rv;
99 rv = stat(buf, &statbuf);
100 if (rv == 0) {
101 /* it exists */
102 if (S_ISREG(statbuf.st_mode))
103 /* it's a file */
104 path = buf;
105 break;
107 #else
108 if (object_exists(buf)) {
109 /* it exists */
110 if (isfile(buf))
111 /* it's a file */
112 path = buf;
113 break;
115 #endif
116 /* back up one path element */
117 p = strrchr(buf, SEP);
118 if (prefix != NULL)
119 *prefix = SEP;
120 if (p == NULL)
121 break;
122 *p = '\0';
123 prefix = p;
125 if (path != NULL) {
126 PyObject *files;
127 files = PyDict_GetItemString(zip_directory_cache, path);
128 if (files == NULL) {
129 files = read_directory(buf);
130 if (files == NULL)
131 return -1;
132 if (PyDict_SetItemString(zip_directory_cache, path,
133 files) != 0)
134 return -1;
136 else
137 Py_INCREF(files);
138 self->files = files;
140 else {
141 PyErr_SetString(ZipImportError, "not a Zip file");
142 return -1;
145 if (prefix == NULL)
146 prefix = "";
147 else {
148 prefix++;
149 len = strlen(prefix);
150 if (prefix[len-1] != SEP) {
151 /* add trailing SEP */
152 prefix[len] = SEP;
153 prefix[len + 1] = '\0';
157 self->archive = PyString_FromString(buf);
158 if (self->archive == NULL)
159 return -1;
161 self->prefix = PyString_FromString(prefix);
162 if (self->prefix == NULL)
163 return -1;
165 return 0;
168 /* GC support. */
169 static int
170 zipimporter_traverse(PyObject *obj, visitproc visit, void *arg)
172 ZipImporter *self = (ZipImporter *)obj;
173 Py_VISIT(self->files);
174 return 0;
177 static void
178 zipimporter_dealloc(ZipImporter *self)
180 PyObject_GC_UnTrack(self);
181 Py_XDECREF(self->archive);
182 Py_XDECREF(self->prefix);
183 Py_XDECREF(self->files);
184 Py_TYPE(self)->tp_free((PyObject *)self);
187 static PyObject *
188 zipimporter_repr(ZipImporter *self)
190 char buf[500];
191 char *archive = "???";
192 char *prefix = "";
194 if (self->archive != NULL && PyString_Check(self->archive))
195 archive = PyString_AsString(self->archive);
196 if (self->prefix != NULL && PyString_Check(self->prefix))
197 prefix = PyString_AsString(self->prefix);
198 if (prefix != NULL && *prefix)
199 PyOS_snprintf(buf, sizeof(buf),
200 "<zipimporter object \"%.300s%c%.150s\">",
201 archive, SEP, prefix);
202 else
203 PyOS_snprintf(buf, sizeof(buf),
204 "<zipimporter object \"%.300s\">",
205 archive);
206 return PyString_FromString(buf);
209 /* return fullname.split(".")[-1] */
210 static char *
211 get_subname(char *fullname)
213 char *subname = strrchr(fullname, '.');
214 if (subname == NULL)
215 subname = fullname;
216 else
217 subname++;
218 return subname;
221 /* Given a (sub)modulename, write the potential file path in the
222 archive (without extension) to the path buffer. Return the
223 length of the resulting string. */
224 static int
225 make_filename(char *prefix, char *name, char *path)
227 size_t len;
228 char *p;
230 len = strlen(prefix);
232 /* self.prefix + name [+ SEP + "__init__"] + ".py[co]" */
233 if (len + strlen(name) + 13 >= MAXPATHLEN) {
234 PyErr_SetString(ZipImportError, "path too long");
235 return -1;
238 strcpy(path, prefix);
239 strcpy(path + len, name);
240 for (p = path + len; *p; p++) {
241 if (*p == '.')
242 *p = SEP;
244 len += strlen(name);
245 assert(len < INT_MAX);
246 return (int)len;
249 enum zi_module_info {
250 MI_ERROR,
251 MI_NOT_FOUND,
252 MI_MODULE,
253 MI_PACKAGE
256 /* Return some information about a module. */
257 static enum zi_module_info
258 get_module_info(ZipImporter *self, char *fullname)
260 char *subname, path[MAXPATHLEN + 1];
261 int len;
262 struct st_zip_searchorder *zso;
264 subname = get_subname(fullname);
266 len = make_filename(PyString_AsString(self->prefix), subname, path);
267 if (len < 0)
268 return MI_ERROR;
270 for (zso = zip_searchorder; *zso->suffix; zso++) {
271 strcpy(path + len, zso->suffix);
272 if (PyDict_GetItemString(self->files, path) != NULL) {
273 if (zso->type & IS_PACKAGE)
274 return MI_PACKAGE;
275 else
276 return MI_MODULE;
279 return MI_NOT_FOUND;
282 /* Check whether we can satisfy the import of the module named by
283 'fullname'. Return self if we can, None if we can't. */
284 static PyObject *
285 zipimporter_find_module(PyObject *obj, PyObject *args)
287 ZipImporter *self = (ZipImporter *)obj;
288 PyObject *path = NULL;
289 char *fullname;
290 enum zi_module_info mi;
292 if (!PyArg_ParseTuple(args, "s|O:zipimporter.find_module",
293 &fullname, &path))
294 return NULL;
296 mi = get_module_info(self, fullname);
297 if (mi == MI_ERROR)
298 return NULL;
299 if (mi == MI_NOT_FOUND) {
300 Py_INCREF(Py_None);
301 return Py_None;
303 Py_INCREF(self);
304 return (PyObject *)self;
307 /* Load and return the module named by 'fullname'. */
308 static PyObject *
309 zipimporter_load_module(PyObject *obj, PyObject *args)
311 ZipImporter *self = (ZipImporter *)obj;
312 PyObject *code, *mod, *dict;
313 char *fullname, *modpath;
314 int ispackage;
316 if (!PyArg_ParseTuple(args, "s:zipimporter.load_module",
317 &fullname))
318 return NULL;
320 code = get_module_code(self, fullname, &ispackage, &modpath);
321 if (code == NULL)
322 return NULL;
324 mod = PyImport_AddModule(fullname);
325 if (mod == NULL) {
326 Py_DECREF(code);
327 return NULL;
329 dict = PyModule_GetDict(mod);
331 /* mod.__loader__ = self */
332 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0)
333 goto error;
335 if (ispackage) {
336 /* add __path__ to the module *before* the code gets
337 executed */
338 PyObject *pkgpath, *fullpath;
339 char *prefix = PyString_AsString(self->prefix);
340 char *subname = get_subname(fullname);
341 int err;
343 fullpath = PyString_FromFormat("%s%c%s%s",
344 PyString_AsString(self->archive),
345 SEP,
346 *prefix ? prefix : "",
347 subname);
348 if (fullpath == NULL)
349 goto error;
351 pkgpath = Py_BuildValue("[O]", fullpath);
352 Py_DECREF(fullpath);
353 if (pkgpath == NULL)
354 goto error;
355 err = PyDict_SetItemString(dict, "__path__", pkgpath);
356 Py_DECREF(pkgpath);
357 if (err != 0)
358 goto error;
360 mod = PyImport_ExecCodeModuleEx(fullname, code, modpath);
361 Py_DECREF(code);
362 if (Py_VerboseFlag)
363 PySys_WriteStderr("import %s # loaded from Zip %s\n",
364 fullname, modpath);
365 return mod;
366 error:
367 Py_DECREF(code);
368 Py_DECREF(mod);
369 return NULL;
372 /* Return a bool signifying whether the module is a package or not. */
373 static PyObject *
374 zipimporter_is_package(PyObject *obj, PyObject *args)
376 ZipImporter *self = (ZipImporter *)obj;
377 char *fullname;
378 enum zi_module_info mi;
380 if (!PyArg_ParseTuple(args, "s:zipimporter.is_package",
381 &fullname))
382 return NULL;
384 mi = get_module_info(self, fullname);
385 if (mi == MI_ERROR)
386 return NULL;
387 if (mi == MI_NOT_FOUND) {
388 PyErr_Format(ZipImportError, "can't find module '%.200s'",
389 fullname);
390 return NULL;
392 return PyBool_FromLong(mi == MI_PACKAGE);
395 static PyObject *
396 zipimporter_get_data(PyObject *obj, PyObject *args)
398 ZipImporter *self = (ZipImporter *)obj;
399 char *path;
400 #ifdef ALTSEP
401 char *p, buf[MAXPATHLEN + 1];
402 #endif
403 PyObject *toc_entry;
404 Py_ssize_t len;
406 if (!PyArg_ParseTuple(args, "s:zipimporter.get_data", &path))
407 return NULL;
409 #ifdef ALTSEP
410 if (strlen(path) >= MAXPATHLEN) {
411 PyErr_SetString(ZipImportError, "path too long");
412 return NULL;
414 strcpy(buf, path);
415 for (p = buf; *p; p++) {
416 if (*p == ALTSEP)
417 *p = SEP;
419 path = buf;
420 #endif
421 len = PyString_Size(self->archive);
422 if ((size_t)len < strlen(path) &&
423 strncmp(path, PyString_AsString(self->archive), len) == 0 &&
424 path[len] == SEP) {
425 path = path + len + 1;
428 toc_entry = PyDict_GetItemString(self->files, path);
429 if (toc_entry == NULL) {
430 PyErr_SetFromErrnoWithFilename(PyExc_IOError, path);
431 return NULL;
433 return get_data(PyString_AsString(self->archive), toc_entry);
436 static PyObject *
437 zipimporter_get_code(PyObject *obj, PyObject *args)
439 ZipImporter *self = (ZipImporter *)obj;
440 char *fullname;
442 if (!PyArg_ParseTuple(args, "s:zipimporter.get_code", &fullname))
443 return NULL;
445 return get_module_code(self, fullname, NULL, NULL);
448 static PyObject *
449 zipimporter_get_source(PyObject *obj, PyObject *args)
451 ZipImporter *self = (ZipImporter *)obj;
452 PyObject *toc_entry;
453 char *fullname, *subname, path[MAXPATHLEN+1];
454 int len;
455 enum zi_module_info mi;
457 if (!PyArg_ParseTuple(args, "s:zipimporter.get_source", &fullname))
458 return NULL;
460 mi = get_module_info(self, fullname);
461 if (mi == MI_ERROR)
462 return NULL;
463 if (mi == MI_NOT_FOUND) {
464 PyErr_Format(ZipImportError, "can't find module '%.200s'",
465 fullname);
466 return NULL;
468 subname = get_subname(fullname);
470 len = make_filename(PyString_AsString(self->prefix), subname, path);
471 if (len < 0)
472 return NULL;
474 if (mi == MI_PACKAGE) {
475 path[len] = SEP;
476 strcpy(path + len + 1, "__init__.py");
478 else
479 strcpy(path + len, ".py");
481 toc_entry = PyDict_GetItemString(self->files, path);
482 if (toc_entry != NULL)
483 return get_data(PyString_AsString(self->archive), toc_entry);
485 /* we have the module, but no source */
486 Py_INCREF(Py_None);
487 return Py_None;
490 PyDoc_STRVAR(doc_find_module,
491 "find_module(fullname, path=None) -> self or None.\n\
493 Search for a module specified by 'fullname'. 'fullname' must be the\n\
494 fully qualified (dotted) module name. It returns the zipimporter\n\
495 instance itself if the module was found, or None if it wasn't.\n\
496 The optional 'path' argument is ignored -- it's there for compatibility\n\
497 with the importer protocol.");
499 PyDoc_STRVAR(doc_load_module,
500 "load_module(fullname) -> module.\n\
502 Load the module specified by 'fullname'. 'fullname' must be the\n\
503 fully qualified (dotted) module name. It returns the imported\n\
504 module, or raises ZipImportError if it wasn't found.");
506 PyDoc_STRVAR(doc_get_data,
507 "get_data(pathname) -> string with file data.\n\
509 Return the data associated with 'pathname'. Raise IOError if\n\
510 the file wasn't found.");
512 PyDoc_STRVAR(doc_is_package,
513 "is_package(fullname) -> bool.\n\
515 Return True if the module specified by fullname is a package.\n\
516 Raise ZipImportError is the module couldn't be found.");
518 PyDoc_STRVAR(doc_get_code,
519 "get_code(fullname) -> code object.\n\
521 Return the code object for the specified module. Raise ZipImportError\n\
522 is the module couldn't be found.");
524 PyDoc_STRVAR(doc_get_source,
525 "get_source(fullname) -> source string.\n\
527 Return the source code for the specified module. Raise ZipImportError\n\
528 is the module couldn't be found, return None if the archive does\n\
529 contain the module, but has no source for it.");
531 static PyMethodDef zipimporter_methods[] = {
532 {"find_module", zipimporter_find_module, METH_VARARGS,
533 doc_find_module},
534 {"load_module", zipimporter_load_module, METH_VARARGS,
535 doc_load_module},
536 {"get_data", zipimporter_get_data, METH_VARARGS,
537 doc_get_data},
538 {"get_code", zipimporter_get_code, METH_VARARGS,
539 doc_get_code},
540 {"get_source", zipimporter_get_source, METH_VARARGS,
541 doc_get_source},
542 {"is_package", zipimporter_is_package, METH_VARARGS,
543 doc_is_package},
544 {NULL, NULL} /* sentinel */
547 static PyMemberDef zipimporter_members[] = {
548 {"archive", T_OBJECT, offsetof(ZipImporter, archive), READONLY},
549 {"prefix", T_OBJECT, offsetof(ZipImporter, prefix), READONLY},
550 {"_files", T_OBJECT, offsetof(ZipImporter, files), READONLY},
551 {NULL}
554 PyDoc_STRVAR(zipimporter_doc,
555 "zipimporter(archivepath) -> zipimporter object\n\
557 Create a new zipimporter instance. 'archivepath' must be a path to\n\
558 a zipfile, or to a specific path inside a zipfile. For example, it can be\n\
559 '/tmp/myimport.zip', or '/tmp/myimport.zip/mydirectory', if mydirectory is a\n\
560 valid directory inside the archive.\n\
562 'ZipImportError is raised if 'archivepath' doesn't point to a valid Zip\n\
563 archive.\n\
565 The 'archive' attribute of zipimporter objects contains the name of the\n\
566 zipfile targeted.");
568 #define DEFERRED_ADDRESS(ADDR) 0
570 static PyTypeObject ZipImporter_Type = {
571 PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
572 "zipimport.zipimporter",
573 sizeof(ZipImporter),
574 0, /* tp_itemsize */
575 (destructor)zipimporter_dealloc, /* tp_dealloc */
576 0, /* tp_print */
577 0, /* tp_getattr */
578 0, /* tp_setattr */
579 0, /* tp_compare */
580 (reprfunc)zipimporter_repr, /* tp_repr */
581 0, /* tp_as_number */
582 0, /* tp_as_sequence */
583 0, /* tp_as_mapping */
584 0, /* tp_hash */
585 0, /* tp_call */
586 0, /* tp_str */
587 PyObject_GenericGetAttr, /* tp_getattro */
588 0, /* tp_setattro */
589 0, /* tp_as_buffer */
590 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
591 Py_TPFLAGS_HAVE_GC, /* tp_flags */
592 zipimporter_doc, /* tp_doc */
593 zipimporter_traverse, /* tp_traverse */
594 0, /* tp_clear */
595 0, /* tp_richcompare */
596 0, /* tp_weaklistoffset */
597 0, /* tp_iter */
598 0, /* tp_iternext */
599 zipimporter_methods, /* tp_methods */
600 zipimporter_members, /* tp_members */
601 0, /* tp_getset */
602 0, /* tp_base */
603 0, /* tp_dict */
604 0, /* tp_descr_get */
605 0, /* tp_descr_set */
606 0, /* tp_dictoffset */
607 (initproc)zipimporter_init, /* tp_init */
608 PyType_GenericAlloc, /* tp_alloc */
609 PyType_GenericNew, /* tp_new */
610 PyObject_GC_Del, /* tp_free */
614 /* implementation */
616 /* Given a buffer, return the long that is represented by the first
617 4 bytes, encoded as little endian. This partially reimplements
618 marshal.c:r_long() */
619 static long
620 get_long(unsigned char *buf) {
621 long x;
622 x = buf[0];
623 x |= (long)buf[1] << 8;
624 x |= (long)buf[2] << 16;
625 x |= (long)buf[3] << 24;
626 #if SIZEOF_LONG > 4
627 /* Sign extension for 64-bit machines */
628 x |= -(x & 0x80000000L);
629 #endif
630 return x;
634 read_directory(archive) -> files dict (new reference)
636 Given a path to a Zip archive, build a dict, mapping file names
637 (local to the archive, using SEP as a separator) to toc entries.
639 A toc_entry is a tuple:
641 (__file__, # value to use for __file__, available for all files
642 compress, # compression kind; 0 for uncompressed
643 data_size, # size of compressed data on disk
644 file_size, # size of decompressed data
645 file_offset, # offset of file header from start of archive
646 time, # mod time of file (in dos format)
647 date, # mod data of file (in dos format)
648 crc, # crc checksum of the data
651 Directories can be recognized by the trailing SEP in the name,
652 data_size and file_offset are 0.
654 static PyObject *
655 read_directory(char *archive)
657 PyObject *files = NULL;
658 FILE *fp;
659 long compress, crc, data_size, file_size, file_offset, date, time;
660 long header_offset, name_size, header_size, header_position;
661 long i, l, count;
662 size_t length;
663 char path[MAXPATHLEN + 5];
664 char name[MAXPATHLEN + 5];
665 char *p, endof_central_dir[22];
666 long arc_offset; /* offset from beginning of file to start of zip-archive */
668 if (strlen(archive) > MAXPATHLEN) {
669 PyErr_SetString(PyExc_OverflowError,
670 "Zip path name is too long");
671 return NULL;
673 strcpy(path, archive);
675 fp = fopen(archive, "rb");
676 if (fp == NULL) {
677 PyErr_Format(ZipImportError, "can't open Zip file: "
678 "'%.200s'", archive);
679 return NULL;
681 fseek(fp, -22, SEEK_END);
682 header_position = ftell(fp);
683 if (fread(endof_central_dir, 1, 22, fp) != 22) {
684 fclose(fp);
685 PyErr_Format(ZipImportError, "can't read Zip file: "
686 "'%.200s'", archive);
687 return NULL;
689 if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) {
690 /* Bad: End of Central Dir signature */
691 fclose(fp);
692 PyErr_Format(ZipImportError, "not a Zip file: "
693 "'%.200s'", archive);
694 return NULL;
697 header_size = get_long((unsigned char *)endof_central_dir + 12);
698 header_offset = get_long((unsigned char *)endof_central_dir + 16);
699 arc_offset = header_position - header_offset - header_size;
700 header_offset += arc_offset;
702 files = PyDict_New();
703 if (files == NULL)
704 goto error;
706 length = (long)strlen(path);
707 path[length] = SEP;
709 /* Start of Central Directory */
710 count = 0;
711 for (;;) {
712 PyObject *t;
713 int err;
715 fseek(fp, header_offset, 0); /* Start of file header */
716 l = PyMarshal_ReadLongFromFile(fp);
717 if (l != 0x02014B50)
718 break; /* Bad: Central Dir File Header */
719 fseek(fp, header_offset + 10, 0);
720 compress = PyMarshal_ReadShortFromFile(fp);
721 time = PyMarshal_ReadShortFromFile(fp);
722 date = PyMarshal_ReadShortFromFile(fp);
723 crc = PyMarshal_ReadLongFromFile(fp);
724 data_size = PyMarshal_ReadLongFromFile(fp);
725 file_size = PyMarshal_ReadLongFromFile(fp);
726 name_size = PyMarshal_ReadShortFromFile(fp);
727 header_size = 46 + name_size +
728 PyMarshal_ReadShortFromFile(fp) +
729 PyMarshal_ReadShortFromFile(fp);
730 fseek(fp, header_offset + 42, 0);
731 file_offset = PyMarshal_ReadLongFromFile(fp) + arc_offset;
732 if (name_size > MAXPATHLEN)
733 name_size = MAXPATHLEN;
735 p = name;
736 for (i = 0; i < name_size; i++) {
737 *p = (char)getc(fp);
738 if (*p == '/')
739 *p = SEP;
740 p++;
742 *p = 0; /* Add terminating null byte */
743 header_offset += header_size;
745 strncpy(path + length + 1, name, MAXPATHLEN - length - 1);
747 t = Py_BuildValue("siiiiiii", path, compress, data_size,
748 file_size, file_offset, time, date, crc);
749 if (t == NULL)
750 goto error;
751 err = PyDict_SetItemString(files, name, t);
752 Py_DECREF(t);
753 if (err != 0)
754 goto error;
755 count++;
757 fclose(fp);
758 if (Py_VerboseFlag)
759 PySys_WriteStderr("# zipimport: found %ld names in %s\n",
760 count, archive);
761 return files;
762 error:
763 fclose(fp);
764 Py_XDECREF(files);
765 return NULL;
768 /* Return the zlib.decompress function object, or NULL if zlib couldn't
769 be imported. The function is cached when found, so subsequent calls
770 don't import zlib again. Returns a *borrowed* reference.
771 XXX This makes zlib.decompress immortal. */
772 static PyObject *
773 get_decompress_func(void)
775 static PyObject *decompress = NULL;
777 if (decompress == NULL) {
778 PyObject *zlib;
779 static int importing_zlib = 0;
781 if (importing_zlib != 0)
782 /* Someone has a zlib.py[co] in their Zip file;
783 let's avoid a stack overflow. */
784 return NULL;
785 importing_zlib = 1;
786 zlib = PyImport_ImportModuleNoBlock("zlib");
787 importing_zlib = 0;
788 if (zlib != NULL) {
789 decompress = PyObject_GetAttrString(zlib,
790 "decompress");
791 Py_DECREF(zlib);
793 else
794 PyErr_Clear();
795 if (Py_VerboseFlag)
796 PySys_WriteStderr("# zipimport: zlib %s\n",
797 zlib != NULL ? "available": "UNAVAILABLE");
799 return decompress;
802 /* Given a path to a Zip file and a toc_entry, return the (uncompressed)
803 data as a new reference. */
804 static PyObject *
805 get_data(char *archive, PyObject *toc_entry)
807 PyObject *raw_data, *data = NULL, *decompress;
808 char *buf;
809 FILE *fp;
810 int err;
811 Py_ssize_t bytes_read = 0;
812 long l;
813 char *datapath;
814 long compress, data_size, file_size, file_offset;
815 long time, date, crc;
817 if (!PyArg_ParseTuple(toc_entry, "slllllll", &datapath, &compress,
818 &data_size, &file_size, &file_offset, &time,
819 &date, &crc)) {
820 return NULL;
823 fp = fopen(archive, "rb");
824 if (!fp) {
825 PyErr_Format(PyExc_IOError,
826 "zipimport: can not open file %s", archive);
827 return NULL;
830 /* Check to make sure the local file header is correct */
831 fseek(fp, file_offset, 0);
832 l = PyMarshal_ReadLongFromFile(fp);
833 if (l != 0x04034B50) {
834 /* Bad: Local File Header */
835 PyErr_Format(ZipImportError,
836 "bad local file header in %s",
837 archive);
838 fclose(fp);
839 return NULL;
841 fseek(fp, file_offset + 26, 0);
842 l = 30 + PyMarshal_ReadShortFromFile(fp) +
843 PyMarshal_ReadShortFromFile(fp); /* local header size */
844 file_offset += l; /* Start of file data */
846 raw_data = PyString_FromStringAndSize((char *)NULL, compress == 0 ?
847 data_size : data_size + 1);
848 if (raw_data == NULL) {
849 fclose(fp);
850 return NULL;
852 buf = PyString_AsString(raw_data);
854 err = fseek(fp, file_offset, 0);
855 if (err == 0)
856 bytes_read = fread(buf, 1, data_size, fp);
857 fclose(fp);
858 if (err || bytes_read != data_size) {
859 PyErr_SetString(PyExc_IOError,
860 "zipimport: can't read data");
861 Py_DECREF(raw_data);
862 return NULL;
865 if (compress != 0) {
866 buf[data_size] = 'Z'; /* saw this in zipfile.py */
867 data_size++;
869 buf[data_size] = '\0';
871 if (compress == 0) /* data is not compressed */
872 return raw_data;
874 /* Decompress with zlib */
875 decompress = get_decompress_func();
876 if (decompress == NULL) {
877 PyErr_SetString(ZipImportError,
878 "can't decompress data; "
879 "zlib not available");
880 goto error;
882 data = PyObject_CallFunction(decompress, "Oi", raw_data, -15);
883 error:
884 Py_DECREF(raw_data);
885 return data;
888 /* Lenient date/time comparison function. The precision of the mtime
889 in the archive is lower than the mtime stored in a .pyc: we
890 must allow a difference of at most one second. */
891 static int
892 eq_mtime(time_t t1, time_t t2)
894 time_t d = t1 - t2;
895 if (d < 0)
896 d = -d;
897 /* dostime only stores even seconds, so be lenient */
898 return d <= 1;
901 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
902 and return the code object. Return None if it the magic word doesn't
903 match (we do this instead of raising an exception as we fall back
904 to .py if available and we don't want to mask other errors).
905 Returns a new reference. */
906 static PyObject *
907 unmarshal_code(char *pathname, PyObject *data, time_t mtime)
909 PyObject *code;
910 char *buf = PyString_AsString(data);
911 Py_ssize_t size = PyString_Size(data);
913 if (size <= 9) {
914 PyErr_SetString(ZipImportError,
915 "bad pyc data");
916 return NULL;
919 if (get_long((unsigned char *)buf) != PyImport_GetMagicNumber()) {
920 if (Py_VerboseFlag)
921 PySys_WriteStderr("# %s has bad magic\n",
922 pathname);
923 Py_INCREF(Py_None);
924 return Py_None; /* signal caller to try alternative */
927 if (mtime != 0 && !eq_mtime(get_long((unsigned char *)buf + 4),
928 mtime)) {
929 if (Py_VerboseFlag)
930 PySys_WriteStderr("# %s has bad mtime\n",
931 pathname);
932 Py_INCREF(Py_None);
933 return Py_None; /* signal caller to try alternative */
936 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
937 if (code == NULL)
938 return NULL;
939 if (!PyCode_Check(code)) {
940 Py_DECREF(code);
941 PyErr_Format(PyExc_TypeError,
942 "compiled module %.200s is not a code object",
943 pathname);
944 return NULL;
946 return code;
949 /* Replace any occurances of "\r\n?" in the input string with "\n".
950 This converts DOS and Mac line endings to Unix line endings.
951 Also append a trailing "\n" to be compatible with
952 PyParser_SimpleParseFile(). Returns a new reference. */
953 static PyObject *
954 normalize_line_endings(PyObject *source)
956 char *buf, *q, *p = PyString_AsString(source);
957 PyObject *fixed_source;
959 if (!p)
960 return NULL;
962 /* one char extra for trailing \n and one for terminating \0 */
963 buf = (char *)PyMem_Malloc(PyString_Size(source) + 2);
964 if (buf == NULL) {
965 PyErr_SetString(PyExc_MemoryError,
966 "zipimport: no memory to allocate "
967 "source buffer");
968 return NULL;
970 /* replace "\r\n?" by "\n" */
971 for (q = buf; *p != '\0'; p++) {
972 if (*p == '\r') {
973 *q++ = '\n';
974 if (*(p + 1) == '\n')
975 p++;
977 else
978 *q++ = *p;
980 *q++ = '\n'; /* add trailing \n */
981 *q = '\0';
982 fixed_source = PyString_FromString(buf);
983 PyMem_Free(buf);
984 return fixed_source;
987 /* Given a string buffer containing Python source code, compile it
988 return and return a code object as a new reference. */
989 static PyObject *
990 compile_source(char *pathname, PyObject *source)
992 PyObject *code, *fixed_source;
994 fixed_source = normalize_line_endings(source);
995 if (fixed_source == NULL)
996 return NULL;
998 code = Py_CompileString(PyString_AsString(fixed_source), pathname,
999 Py_file_input);
1000 Py_DECREF(fixed_source);
1001 return code;
1004 /* Convert the date/time values found in the Zip archive to a value
1005 that's compatible with the time stamp stored in .pyc files. */
1006 static time_t
1007 parse_dostime(int dostime, int dosdate)
1009 struct tm stm;
1011 memset((void *) &stm, '\0', sizeof(stm));
1013 stm.tm_sec = (dostime & 0x1f) * 2;
1014 stm.tm_min = (dostime >> 5) & 0x3f;
1015 stm.tm_hour = (dostime >> 11) & 0x1f;
1016 stm.tm_mday = dosdate & 0x1f;
1017 stm.tm_mon = ((dosdate >> 5) & 0x0f) - 1;
1018 stm.tm_year = ((dosdate >> 9) & 0x7f) + 80;
1019 stm.tm_isdst = -1; /* wday/yday is ignored */
1021 return mktime(&stm);
1024 /* Given a path to a .pyc or .pyo file in the archive, return the
1025 modifictaion time of the matching .py file, or 0 if no source
1026 is available. */
1027 static time_t
1028 get_mtime_of_source(ZipImporter *self, char *path)
1030 PyObject *toc_entry;
1031 time_t mtime = 0;
1032 Py_ssize_t lastchar = strlen(path) - 1;
1033 char savechar = path[lastchar];
1034 path[lastchar] = '\0'; /* strip 'c' or 'o' from *.py[co] */
1035 toc_entry = PyDict_GetItemString(self->files, path);
1036 if (toc_entry != NULL && PyTuple_Check(toc_entry) &&
1037 PyTuple_Size(toc_entry) == 8) {
1038 /* fetch the time stamp of the .py file for comparison
1039 with an embedded pyc time stamp */
1040 int time, date;
1041 time = PyInt_AsLong(PyTuple_GetItem(toc_entry, 5));
1042 date = PyInt_AsLong(PyTuple_GetItem(toc_entry, 6));
1043 mtime = parse_dostime(time, date);
1045 path[lastchar] = savechar;
1046 return mtime;
1049 /* Return the code object for the module named by 'fullname' from the
1050 Zip archive as a new reference. */
1051 static PyObject *
1052 get_code_from_data(ZipImporter *self, int ispackage, int isbytecode,
1053 time_t mtime, PyObject *toc_entry)
1055 PyObject *data, *code;
1056 char *modpath;
1057 char *archive = PyString_AsString(self->archive);
1059 if (archive == NULL)
1060 return NULL;
1062 data = get_data(archive, toc_entry);
1063 if (data == NULL)
1064 return NULL;
1066 modpath = PyString_AsString(PyTuple_GetItem(toc_entry, 0));
1068 if (isbytecode) {
1069 code = unmarshal_code(modpath, data, mtime);
1071 else {
1072 code = compile_source(modpath, data);
1074 Py_DECREF(data);
1075 return code;
1078 /* Get the code object assoiciated with the module specified by
1079 'fullname'. */
1080 static PyObject *
1081 get_module_code(ZipImporter *self, char *fullname,
1082 int *p_ispackage, char **p_modpath)
1084 PyObject *toc_entry;
1085 char *subname, path[MAXPATHLEN + 1];
1086 int len;
1087 struct st_zip_searchorder *zso;
1089 subname = get_subname(fullname);
1091 len = make_filename(PyString_AsString(self->prefix), subname, path);
1092 if (len < 0)
1093 return NULL;
1095 for (zso = zip_searchorder; *zso->suffix; zso++) {
1096 PyObject *code = NULL;
1098 strcpy(path + len, zso->suffix);
1099 if (Py_VerboseFlag > 1)
1100 PySys_WriteStderr("# trying %s%c%s\n",
1101 PyString_AsString(self->archive),
1102 SEP, path);
1103 toc_entry = PyDict_GetItemString(self->files, path);
1104 if (toc_entry != NULL) {
1105 time_t mtime = 0;
1106 int ispackage = zso->type & IS_PACKAGE;
1107 int isbytecode = zso->type & IS_BYTECODE;
1109 if (isbytecode)
1110 mtime = get_mtime_of_source(self, path);
1111 if (p_ispackage != NULL)
1112 *p_ispackage = ispackage;
1113 code = get_code_from_data(self, ispackage,
1114 isbytecode, mtime,
1115 toc_entry);
1116 if (code == Py_None) {
1117 /* bad magic number or non-matching mtime
1118 in byte code, try next */
1119 Py_DECREF(code);
1120 continue;
1122 if (code != NULL && p_modpath != NULL)
1123 *p_modpath = PyString_AsString(
1124 PyTuple_GetItem(toc_entry, 0));
1125 return code;
1128 PyErr_Format(ZipImportError, "can't find module '%.200s'", fullname);
1129 return NULL;
1133 /* Module init */
1135 PyDoc_STRVAR(zipimport_doc,
1136 "zipimport provides support for importing Python modules from Zip archives.\n\
1138 This module exports three objects:\n\
1139 - zipimporter: a class; its constructor takes a path to a Zip archive.\n\
1140 - ZipImportError: exception raised by zipimporter objects. It's a\n\
1141 subclass of ImportError, so it can be caught as ImportError, too.\n\
1142 - _zip_directory_cache: a dict, mapping archive paths to zip directory\n\
1143 info dicts, as used in zipimporter._files.\n\
1145 It is usually not needed to use the zipimport module explicitly; it is\n\
1146 used by the builtin import mechanism for sys.path items that are paths\n\
1147 to Zip archives.");
1149 PyMODINIT_FUNC
1150 initzipimport(void)
1152 PyObject *mod;
1154 if (PyType_Ready(&ZipImporter_Type) < 0)
1155 return;
1157 /* Correct directory separator */
1158 zip_searchorder[0].suffix[0] = SEP;
1159 zip_searchorder[1].suffix[0] = SEP;
1160 zip_searchorder[2].suffix[0] = SEP;
1161 if (Py_OptimizeFlag) {
1162 /* Reverse *.pyc and *.pyo */
1163 struct st_zip_searchorder tmp;
1164 tmp = zip_searchorder[0];
1165 zip_searchorder[0] = zip_searchorder[1];
1166 zip_searchorder[1] = tmp;
1167 tmp = zip_searchorder[3];
1168 zip_searchorder[3] = zip_searchorder[4];
1169 zip_searchorder[4] = tmp;
1172 mod = Py_InitModule4("zipimport", NULL, zipimport_doc,
1173 NULL, PYTHON_API_VERSION);
1174 if (mod == NULL)
1175 return;
1177 ZipImportError = PyErr_NewException("zipimport.ZipImportError",
1178 PyExc_ImportError, NULL);
1179 if (ZipImportError == NULL)
1180 return;
1182 Py_INCREF(ZipImportError);
1183 if (PyModule_AddObject(mod, "ZipImportError",
1184 ZipImportError) < 0)
1185 return;
1187 Py_INCREF(&ZipImporter_Type);
1188 if (PyModule_AddObject(mod, "zipimporter",
1189 (PyObject *)&ZipImporter_Type) < 0)
1190 return;
1192 zip_directory_cache = PyDict_New();
1193 if (zip_directory_cache == NULL)
1194 return;
1195 Py_INCREF(zip_directory_cache);
1196 if (PyModule_AddObject(mod, "_zip_directory_cache",
1197 zip_directory_cache) < 0)
1198 return;