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