annotate zipfile31.py @ 80:809b77302b21

Win32-specific module with memory and CPU time limits The Win32-specific implementation of call() and friends now lives in module win32, looks clean and in addition is able to enforce memory and CPU time limits on NT kernels, in particular on Windows 2000 and up asking the system to terminate the process as soon as or (in the case of CPU time) almost as soon as the limits are broken. According to my observations, malloc() in the limited process does not return NULL when memory usage is close to the limit and instead crashes the process (which Upreckon happily translates into 'memory limit exceeded'). The catch is that the module is not actually used yet; coming soon.
author Oleg Oshmyan <chortos@inbox.lv>
date Wed, 16 Feb 2011 00:01:33 +0000
parents 4ea7133ac25c
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
2 Read and write ZIP files.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
3
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
4 XXX references to utf-8 need further investigation.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
5 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
6 # Improved by Chortos-2 in 2010 (added bzip2 support)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
7 import struct, os, time, sys, shutil
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
8 import binascii, io, stat
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
9
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
10 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
11 import zlib # We may need its compression method
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
12 crc32 = zlib.crc32
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
13 except ImportError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
14 zlib = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
15 crc32 = binascii.crc32
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
16
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
17 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
18 import bz2 # We may need its compression method
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
19 except ImportError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
20 bz2 = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
22 __all__ = ["BadZipfile", "error", "ZIP_STORED", "ZIP_DEFLATED", "is_zipfile",
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
23 "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile", "ZIP_BZIP2" ]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
24
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
25 class BadZipfile(Exception):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
26 pass
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
27
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
28
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
29 class LargeZipFile(Exception):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
30 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
31 Raised when writing a zipfile, the zipfile requires ZIP64 extensions
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
32 and those extensions are disabled.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
33 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
34
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
35 error = BadZipfile # The exception raised by this module
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
36
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
37 ZIP64_LIMIT = (1 << 31) - 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
38 ZIP_FILECOUNT_LIMIT = 1 << 16
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
39 ZIP_MAX_COMMENT = (1 << 16) - 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
40
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
41 # constants for Zip file compression methods
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
42 ZIP_STORED = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
43 ZIP_DEFLATED = 8
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
44 ZIP_BZIP2 = 12
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
45 # Other ZIP compression methods not supported
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
46
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
47 # Below are some formats and associated data for reading/writing headers using
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
48 # the struct module. The names and structures of headers/records are those used
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
49 # in the PKWARE description of the ZIP file format:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
50 # http://www.pkware.com/documents/casestudies/APPNOTE.TXT
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
51 # (URL valid as of January 2008)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
52
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
53 # The "end of central directory" structure, magic number, size, and indices
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
54 # (section V.I in the format document)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
55 structEndArchive = b"<4s4H2LH"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
56 stringEndArchive = b"PK\005\006"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
57 sizeEndCentDir = struct.calcsize(structEndArchive)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
58
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
59 _ECD_SIGNATURE = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
60 _ECD_DISK_NUMBER = 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
61 _ECD_DISK_START = 2
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
62 _ECD_ENTRIES_THIS_DISK = 3
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
63 _ECD_ENTRIES_TOTAL = 4
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
64 _ECD_SIZE = 5
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
65 _ECD_OFFSET = 6
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
66 _ECD_COMMENT_SIZE = 7
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
67 # These last two indices are not part of the structure as defined in the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
68 # spec, but they are used internally by this module as a convenience
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
69 _ECD_COMMENT = 8
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
70 _ECD_LOCATION = 9
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
71
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
72 # The "central directory" structure, magic number, size, and indices
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
73 # of entries in the structure (section V.F in the format document)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
74 structCentralDir = "<4s4B4HL2L5H2L"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
75 stringCentralDir = b"PK\001\002"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
76 sizeCentralDir = struct.calcsize(structCentralDir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
77
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
78 # indexes of entries in the central directory structure
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
79 _CD_SIGNATURE = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
80 _CD_CREATE_VERSION = 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
81 _CD_CREATE_SYSTEM = 2
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
82 _CD_EXTRACT_VERSION = 3
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
83 _CD_EXTRACT_SYSTEM = 4
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
84 _CD_FLAG_BITS = 5
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
85 _CD_COMPRESS_TYPE = 6
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
86 _CD_TIME = 7
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
87 _CD_DATE = 8
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
88 _CD_CRC = 9
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
89 _CD_COMPRESSED_SIZE = 10
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
90 _CD_UNCOMPRESSED_SIZE = 11
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
91 _CD_FILENAME_LENGTH = 12
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
92 _CD_EXTRA_FIELD_LENGTH = 13
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
93 _CD_COMMENT_LENGTH = 14
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
94 _CD_DISK_NUMBER_START = 15
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
95 _CD_INTERNAL_FILE_ATTRIBUTES = 16
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
96 _CD_EXTERNAL_FILE_ATTRIBUTES = 17
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
97 _CD_LOCAL_HEADER_OFFSET = 18
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
98
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
99 # The "local file header" structure, magic number, size, and indices
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
100 # (section V.A in the format document)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
101 structFileHeader = "<4s2B4HL2L2H"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
102 stringFileHeader = b"PK\003\004"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
103 sizeFileHeader = struct.calcsize(structFileHeader)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
104
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
105 _FH_SIGNATURE = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
106 _FH_EXTRACT_VERSION = 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
107 _FH_EXTRACT_SYSTEM = 2
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
108 _FH_GENERAL_PURPOSE_FLAG_BITS = 3
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
109 _FH_COMPRESSION_METHOD = 4
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
110 _FH_LAST_MOD_TIME = 5
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
111 _FH_LAST_MOD_DATE = 6
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
112 _FH_CRC = 7
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
113 _FH_COMPRESSED_SIZE = 8
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
114 _FH_UNCOMPRESSED_SIZE = 9
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
115 _FH_FILENAME_LENGTH = 10
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
116 _FH_EXTRA_FIELD_LENGTH = 11
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
117
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
118 # The "Zip64 end of central directory locator" structure, magic number, and size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
119 structEndArchive64Locator = "<4sLQL"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
120 stringEndArchive64Locator = b"PK\x06\x07"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
121 sizeEndCentDir64Locator = struct.calcsize(structEndArchive64Locator)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
122
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
123 # The "Zip64 end of central directory" record, magic number, size, and indices
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
124 # (section V.G in the format document)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
125 structEndArchive64 = "<4sQ2H2L4Q"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
126 stringEndArchive64 = b"PK\x06\x06"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
127 sizeEndCentDir64 = struct.calcsize(structEndArchive64)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
128
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
129 _CD64_SIGNATURE = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
130 _CD64_DIRECTORY_RECSIZE = 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
131 _CD64_CREATE_VERSION = 2
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
132 _CD64_EXTRACT_VERSION = 3
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
133 _CD64_DISK_NUMBER = 4
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
134 _CD64_DISK_NUMBER_START = 5
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
135 _CD64_NUMBER_ENTRIES_THIS_DISK = 6
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
136 _CD64_NUMBER_ENTRIES_TOTAL = 7
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
137 _CD64_DIRECTORY_SIZE = 8
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
138 _CD64_OFFSET_START_CENTDIR = 9
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
139
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
140 def _check_zipfile(fp):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
141 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
142 if _EndRecData(fp):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
143 return True # file has correct magic number
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
144 except IOError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
145 pass
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
146 return False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
147
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
148 def is_zipfile(filename):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
149 """Quickly see if a file is a ZIP file by checking the magic number.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
150
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
151 The filename argument may be a file or file-like object too.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
152 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
153 result = False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
154 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
155 if hasattr(filename, "read"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
156 result = _check_zipfile(fp=filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
157 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
158 with open(filename, "rb") as fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
159 result = _check_zipfile(fp)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
160 except IOError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
161 pass
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
162 return result
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
163
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
164 def _EndRecData64(fpin, offset, endrec):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
165 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
166 Read the ZIP64 end-of-archive records and use that to update endrec
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
167 """
32
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
168 try:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
169 fpin.seek(offset - sizeEndCentDir64Locator, 2)
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
170 except IOError:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
171 # If the seek fails, the file is not large enough to contain a ZIP64
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
172 # end-of-archive record, so just return the end record we were given.
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
173 return endrec
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
174
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
175 data = fpin.read(sizeEndCentDir64Locator)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
176 sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
177 if sig != stringEndArchive64Locator:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
178 return endrec
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
179
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
180 if diskno != 0 or disks != 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
181 raise BadZipfile("zipfiles that span multiple disks are not supported")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
182
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
183 # Assume no 'zip64 extensible data'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
184 fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
185 data = fpin.read(sizeEndCentDir64)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
186 sig, sz, create_version, read_version, disk_num, disk_dir, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
187 dircount, dircount2, dirsize, diroffset = \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
188 struct.unpack(structEndArchive64, data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
189 if sig != stringEndArchive64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
190 return endrec
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
191
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
192 # Update the original endrec using data from the ZIP64 record
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
193 endrec[_ECD_SIGNATURE] = sig
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
194 endrec[_ECD_DISK_NUMBER] = disk_num
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
195 endrec[_ECD_DISK_START] = disk_dir
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
196 endrec[_ECD_ENTRIES_THIS_DISK] = dircount
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
197 endrec[_ECD_ENTRIES_TOTAL] = dircount2
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
198 endrec[_ECD_SIZE] = dirsize
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
199 endrec[_ECD_OFFSET] = diroffset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
200 return endrec
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
201
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
202
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
203 def _EndRecData(fpin):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
204 """Return data from the "End of Central Directory" record, or None.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
205
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
206 The data is a list of the nine items in the ZIP "End of central dir"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
207 record followed by a tenth item, the file seek offset of this record."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
208
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
209 # Determine file size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
210 fpin.seek(0, 2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
211 filesize = fpin.tell()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
212
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
213 # Check to see if this is ZIP file with no archive comment (the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
214 # "end of central directory" structure should be the last item in the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
215 # file if this is the case).
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
216 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
217 fpin.seek(-sizeEndCentDir, 2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
218 except IOError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
219 return None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
220 data = fpin.read()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
221 if data[0:4] == stringEndArchive and data[-2:] == b"\000\000":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
222 # the signature is correct and there's no comment, unpack structure
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
223 endrec = struct.unpack(structEndArchive, data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
224 endrec=list(endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
225
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
226 # Append a blank comment and record start offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
227 endrec.append(b"")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
228 endrec.append(filesize - sizeEndCentDir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
229
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
230 # Try to read the "Zip64 end of central directory" structure
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
231 return _EndRecData64(fpin, -sizeEndCentDir, endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
232
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
233 # Either this is not a ZIP file, or it is a ZIP file with an archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
234 # comment. Search the end of the file for the "end of central directory"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
235 # record signature. The comment is the last item in the ZIP file and may be
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
236 # up to 64K long. It is assumed that the "end of central directory" magic
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
237 # number does not appear in the comment.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
238 maxCommentStart = max(filesize - (1 << 16) - sizeEndCentDir, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
239 fpin.seek(maxCommentStart, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
240 data = fpin.read()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
241 start = data.rfind(stringEndArchive)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
242 if start >= 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
243 # found the magic number; attempt to unpack and interpret
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
244 recData = data[start:start+sizeEndCentDir]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
245 endrec = list(struct.unpack(structEndArchive, recData))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
246 comment = data[start+sizeEndCentDir:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
247 # check that comment length is correct
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
248 if endrec[_ECD_COMMENT_SIZE] == len(comment):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
249 # Append the archive comment and start offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
250 endrec.append(comment)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
251 endrec.append(maxCommentStart + start)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
252
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
253 # Try to read the "Zip64 end of central directory" structure
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
254 return _EndRecData64(fpin, maxCommentStart + start - filesize,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
255 endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
256
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
257 # Unable to find a valid end of central directory structure
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
258 return
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
259
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
260
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
261 class ZipInfo (object):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
262 """Class with attributes describing each file in the ZIP archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
263
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
264 __slots__ = (
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
265 'orig_filename',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
266 'filename',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
267 'date_time',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
268 'compress_type',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
269 'comment',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
270 'extra',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
271 'create_system',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
272 'create_version',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
273 'extract_version',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
274 'reserved',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
275 'flag_bits',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
276 'volume',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
277 'internal_attr',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
278 'external_attr',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
279 'header_offset',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
280 'CRC',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
281 'compress_size',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
282 'file_size',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
283 '_raw_time',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
284 )
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
285
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
286 def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
287 self.orig_filename = filename # Original file name in archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
288
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
289 # Terminate the file name at the first null byte. Null bytes in file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
290 # names are used as tricks by viruses in archives.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
291 null_byte = filename.find(chr(0))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
292 if null_byte >= 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
293 filename = filename[0:null_byte]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
294 # This is used to ensure paths in generated ZIP files always use
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
295 # forward slashes as the directory separator, as required by the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
296 # ZIP format specification.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
297 if os.sep != "/" and os.sep in filename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
298 filename = filename.replace(os.sep, "/")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
299
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
300 self.filename = filename # Normalized file name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
301 self.date_time = date_time # year, month, day, hour, min, sec
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
302 # Standard values:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
303 self.compress_type = ZIP_STORED # Type of compression for the file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
304 self.comment = b"" # Comment for each file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
305 self.extra = b"" # ZIP extra data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
306 if sys.platform == 'win32':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
307 self.create_system = 0 # System which created ZIP archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
308 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
309 # Assume everything else is unix-y
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
310 self.create_system = 3 # System which created ZIP archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
311 self.create_version = 20 # Version which created ZIP archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
312 self.extract_version = 20 # Version needed to extract archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
313 self.reserved = 0 # Must be zero
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
314 self.flag_bits = 0 # ZIP flag bits
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
315 self.volume = 0 # Volume number of file header
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
316 self.internal_attr = 0 # Internal attributes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
317 self.external_attr = 0 # External file attributes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
318 # Other attributes are set by class ZipFile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
319 # header_offset Byte offset to the file header
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
320 # CRC CRC-32 of the uncompressed file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
321 # compress_size Size of the compressed file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
322 # file_size Size of the uncompressed file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
323
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
324 def FileHeader(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
325 """Return the per-file header as a string."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
326 dt = self.date_time
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
327 dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
328 dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
329 if self.flag_bits & 0x08:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
330 # Set these to zero because we write them after the file data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
331 CRC = compress_size = file_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
332 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
333 CRC = self.CRC
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
334 compress_size = self.compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
335 file_size = self.file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
336
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
337 extra = self.extra
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
338
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
339 if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
340 # File is larger than what fits into a 4 byte integer,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
341 # fall back to the ZIP64 extension
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
342 fmt = '<HHQQ'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
343 extra = extra + struct.pack(fmt,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
344 1, struct.calcsize(fmt)-4, file_size, compress_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
345 file_size = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
346 compress_size = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
347 self.extract_version = max(45, self.extract_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
348 self.create_version = max(45, self.extract_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
349
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
350 filename, flag_bits = self._encodeFilenameFlags()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
351 header = struct.pack(structFileHeader, stringFileHeader,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
352 self.extract_version, self.reserved, flag_bits,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
353 self.compress_type, dostime, dosdate, CRC,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
354 compress_size, file_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
355 len(filename), len(extra))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
356 return header + filename + extra
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
357
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
358 def _encodeFilenameFlags(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
359 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
360 return self.filename.encode('ascii'), self.flag_bits
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
361 except UnicodeEncodeError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
362 return self.filename.encode('utf-8'), self.flag_bits | 0x800
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
363
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
364 def _decodeExtra(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
365 # Try to decode the extra field.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
366 extra = self.extra
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
367 unpack = struct.unpack
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
368 while extra:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
369 tp, ln = unpack('<HH', extra[:4])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
370 if tp == 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
371 if ln >= 24:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
372 counts = unpack('<QQQ', extra[4:28])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
373 elif ln == 16:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
374 counts = unpack('<QQ', extra[4:20])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
375 elif ln == 8:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
376 counts = unpack('<Q', extra[4:12])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
377 elif ln == 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
378 counts = ()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
379 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
380 raise RuntimeError("Corrupt extra field %s"%(ln,))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
381
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
382 idx = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
383
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
384 # ZIP64 extension (large files and/or large archives)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
385 if self.file_size in (0xffffffffffffffff, 0xffffffff):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
386 self.file_size = counts[idx]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
387 idx += 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
388
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
389 if self.compress_size == 0xFFFFFFFF:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
390 self.compress_size = counts[idx]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
391 idx += 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
392
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
393 if self.header_offset == 0xffffffff:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
394 old = self.header_offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
395 self.header_offset = counts[idx]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
396 idx+=1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
397
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
398 extra = extra[ln+4:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
399
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
400
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
401 class _ZipDecrypter:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
402 """Class to handle decryption of files stored within a ZIP archive.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
403
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
404 ZIP supports a password-based form of encryption. Even though known
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
405 plaintext attacks have been found against it, it is still useful
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
406 to be able to get data out of such a file.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
407
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
408 Usage:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
409 zd = _ZipDecrypter(mypwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
410 plain_char = zd(cypher_char)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
411 plain_text = map(zd, cypher_text)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
412 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
413
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
414 def _GenerateCRCTable():
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
415 """Generate a CRC-32 table.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
416
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
417 ZIP encryption uses the CRC32 one-byte primitive for scrambling some
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
418 internal keys. We noticed that a direct implementation is faster than
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
419 relying on binascii.crc32().
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
420 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
421 poly = 0xedb88320
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
422 table = [0] * 256
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
423 for i in range(256):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
424 crc = i
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
425 for j in range(8):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
426 if crc & 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
427 crc = ((crc >> 1) & 0x7FFFFFFF) ^ poly
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
428 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
429 crc = ((crc >> 1) & 0x7FFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
430 table[i] = crc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
431 return table
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
432 crctable = _GenerateCRCTable()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
433
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
434 def _crc32(self, ch, crc):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
435 """Compute the CRC32 primitive on one byte."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
436 return ((crc >> 8) & 0xffffff) ^ self.crctable[(crc ^ ch) & 0xff]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
437
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
438 def __init__(self, pwd):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
439 self.key0 = 305419896
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
440 self.key1 = 591751049
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
441 self.key2 = 878082192
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
442 for p in pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
443 self._UpdateKeys(p)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
444
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
445 def _UpdateKeys(self, c):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
446 self.key0 = self._crc32(c, self.key0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
447 self.key1 = (self.key1 + (self.key0 & 255)) & 4294967295
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
448 self.key1 = (self.key1 * 134775813 + 1) & 4294967295
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
449 self.key2 = self._crc32((self.key1 >> 24) & 255, self.key2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
450
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
451 def __call__(self, c):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
452 """Decrypt a single character."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
453 assert isinstance(c, int)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
454 k = self.key2 | 2
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
455 c = c ^ (((k * (k^1)) >> 8) & 255)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
456 self._UpdateKeys(c)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
457 return c
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
458
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
459 class ZipExtFile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
460 """File-like object for reading an archive member.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
461 Is returned by ZipFile.open().
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
462 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
463
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
464 def __init__(self, fileobj, zipinfo, decrypt=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
465 self.fileobj = fileobj
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
466 self.decrypter = decrypt
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
467 self.bytes_read = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
468 self.rawbuffer = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
469 self.readbuffer = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
470 self.linebuffer = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
471 self.eof = False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
472 self.univ_newlines = False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
473 self.nlSeps = (b"\n", )
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
474 self.lastdiscard = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
475
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
476 self.compress_type = zipinfo.compress_type
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
477 self.compress_size = zipinfo.compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
478
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
479 self.closed = False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
480 self.mode = "r"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
481 self.name = zipinfo.filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
482
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
483 # read from compressed files in 64k blocks
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
484 self.compreadsize = 64*1024
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
485 if self.compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
486 self.dc = zlib.decompressobj(-15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
487 elif self.compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
488 self.dc = bz2.BZ2Decompressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
489 self.compreadsize = 900000
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
490
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
491 if hasattr(zipinfo, 'CRC'):
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
492 self._expected_crc = zipinfo.CRC
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
493 self._running_crc = crc32(b'') & 0xffffffff
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
494 else:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
495 self._expected_crc = None
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
496
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
497 def set_univ_newlines(self, univ_newlines):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
498 self.univ_newlines = univ_newlines
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
499
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
500 # pick line separator char(s) based on universal newlines flag
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
501 self.nlSeps = (b"\n", )
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
502 if self.univ_newlines:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
503 self.nlSeps = (b"\r\n", b"\r", b"\n")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
504
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
505 def __iter__(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
506 return self
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
507
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
508 def __next__(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
509 nextline = self.readline()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
510 if not nextline:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
511 raise StopIteration()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
512
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
513 return nextline
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
514
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
515 def close(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
516 self.closed = True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
517
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
518 def _checkfornewline(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
519 nl, nllen = -1, -1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
520 if self.linebuffer:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
521 # ugly check for cases where half of an \r\n pair was
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
522 # read on the last pass, and the \r was discarded. In this
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
523 # case we just throw away the \n at the start of the buffer.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
524 if (self.lastdiscard, self.linebuffer[:1]) == (b'\r', b'\n'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
525 self.linebuffer = self.linebuffer[1:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
526
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
527 for sep in self.nlSeps:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
528 nl = self.linebuffer.find(sep)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
529 if nl >= 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
530 nllen = len(sep)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
531 return nl, nllen
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
532
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
533 return nl, nllen
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
534
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
535 def readline(self, size = -1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
536 """Read a line with approx. size. If size is negative,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
537 read a whole line.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
538 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
539 if size < 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
540 size = sys.maxsize
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
541 elif size == 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
542 return b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
543
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
544 # check for a newline already in buffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
545 nl, nllen = self._checkfornewline()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
546
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
547 if nl >= 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
548 # the next line was already in the buffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
549 nl = min(nl, size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
550 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
551 # no line break in buffer - try to read more
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
552 size -= len(self.linebuffer)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
553 while nl < 0 and size > 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
554 buf = self.read(min(size, 100))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
555 if not buf:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
556 break
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
557 self.linebuffer += buf
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
558 size -= len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
559
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
560 # check for a newline in buffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
561 nl, nllen = self._checkfornewline()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
562
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
563 # we either ran out of bytes in the file, or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
564 # met the specified size limit without finding a newline,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
565 # so return current buffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
566 if nl < 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
567 s = self.linebuffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
568 self.linebuffer = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
569 return s
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
570
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
571 buf = self.linebuffer[:nl]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
572 self.lastdiscard = self.linebuffer[nl:nl + nllen]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
573 self.linebuffer = self.linebuffer[nl + nllen:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
574
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
575 # line is always returned with \n as newline char (except possibly
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
576 # for a final incomplete line in the file, which is handled above).
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
577 return buf + b"\n"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
578
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
579 def readlines(self, sizehint = -1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
580 """Return a list with all (following) lines. The sizehint parameter
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
581 is ignored in this implementation.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
582 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
583 result = []
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
584 while True:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
585 line = self.readline()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
586 if not line: break
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
587 result.append(line)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
588 return result
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
589
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
590 def _update_crc(self, newdata, eof):
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
591 # Update the CRC using the given data.
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
592 if self._expected_crc is None:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
593 # No need to compute the CRC if we don't have a reference value
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
594 return
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
595 self._running_crc = crc32(newdata, self._running_crc) & 0xffffffff
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
596 # Check the CRC if we're at the end of the file
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
597 if eof and self._running_crc != self._expected_crc:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
598 raise BadZipfile("Bad CRC-32 for file %r" % self.name)
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
599
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
600 def read(self, size = None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
601 # act like file obj and return empty string if size is 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
602 if size == 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
603 return b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
604
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
605 # determine read size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
606 bytesToRead = self.compress_size - self.bytes_read
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
607
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
608 # adjust read size for encrypted files since the first 12 bytes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
609 # are for the encryption/password information
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
610 if self.decrypter is not None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
611 bytesToRead -= 12
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
612
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
613 if size is not None and size >= 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
614 if self.compress_type == ZIP_STORED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
615 lr = len(self.readbuffer)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
616 bytesToRead = min(bytesToRead, size - lr)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
617 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
618 if len(self.readbuffer) > size:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
619 # the user has requested fewer bytes than we've already
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
620 # pulled through the decompressor; don't read any more
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
621 bytesToRead = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
622 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
623 # user will use up the buffer, so read some more
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
624 lr = len(self.rawbuffer)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
625 bytesToRead = min(bytesToRead, self.compreadsize - lr)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
626
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
627 # avoid reading past end of file contents
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
628 if bytesToRead + self.bytes_read > self.compress_size:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
629 bytesToRead = self.compress_size - self.bytes_read
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
630
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
631 # try to read from file (if necessary)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
632 if bytesToRead > 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
633 data = self.fileobj.read(bytesToRead)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
634 self.bytes_read += len(data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
635 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
636 self.rawbuffer += data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
637 except:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
638 print(repr(self.fileobj), repr(self.rawbuffer),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
639 repr(data))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
640 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
641
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
642 # handle contents of raw buffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
643 if self.rawbuffer:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
644 newdata = self.rawbuffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
645 self.rawbuffer = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
646
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
647 # decrypt new data if we were given an object to handle that
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
648 if newdata and self.decrypter is not None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
649 newdata = bytes(map(self.decrypter, newdata))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
650
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
651 # decompress newly read data if necessary
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
652 if newdata and self.compress_type != ZIP_STORED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
653 newdata = self.dc.decompress(newdata)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
654 self.rawbuffer = self.dc.unconsumed_tail if self.compress_type == ZIP_DEFLATED else ''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
655 if self.eof and len(self.rawbuffer) == 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
656 # we're out of raw bytes (both from the file and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
657 # the local buffer); flush just to make sure the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
658 # decompressor is done
28
3d535503161f hasattr -> try
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
659 try:
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
660 newdata += self.dc.flush()
28
3d535503161f hasattr -> try
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
661 except AttributeError:
3d535503161f hasattr -> try
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
662 pass
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
663 # prevent decompressor from being used again
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
664 self.dc = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
665
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
666 self._update_crc(newdata, eof=(
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
667 self.compress_size == self.bytes_read and
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
668 len(self.rawbuffer) == 0))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
669 self.readbuffer += newdata
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
670
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
671 # return what the user asked for
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
672 if size is None or len(self.readbuffer) <= size:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
673 data = self.readbuffer
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
674 self.readbuffer = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
675 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
676 data = self.readbuffer[:size]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
677 self.readbuffer = self.readbuffer[size:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
678
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
679 return data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
680
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
681
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
682 class ZipFile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
683 """ Class with methods to open, read, write, close, list zip files.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
684
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
685 z = ZipFile(file, mode="r", compression=ZIP_STORED, allowZip64=False)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
686
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
687 file: Either the path to the file, or a file-like object.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
688 If it is a path, the file will be opened and closed by ZipFile.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
689 mode: The mode can be either read "r", write "w" or append "a".
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
690 compression: ZIP_STORED (no compression), ZIP_DEFLATED (requires zlib),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
691 or ZIP_BZIP2 (requires bz2).
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
692 allowZip64: if True ZipFile will create files with ZIP64 extensions when
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
693 needed, otherwise it will raise an exception when this would
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
694 be necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
695
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
696 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
697
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
698 fp = None # Set here since __del__ checks it
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
699
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
700 def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
701 """Open the ZIP file with mode read "r", write "w" or append "a"."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
702 if mode not in ("r", "w", "a"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
703 raise RuntimeError('ZipFile() requires mode "r", "w", or "a"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
704
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
705 if compression == ZIP_STORED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
706 pass
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
707 elif compression == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
708 if not zlib:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
709 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
710 "Compression requires the (missing) zlib module")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
711 elif compression == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
712 if not bz2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
713 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
714 "Compression requires the (missing) bz2 module")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
715 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
716 raise RuntimeError("That compression method is not supported")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
717
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
718 self._allowZip64 = allowZip64
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
719 self._didModify = False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
720 self.debug = 0 # Level of printing: 0 through 3
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
721 self.NameToInfo = {} # Find file info given name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
722 self.filelist = [] # List of ZipInfo instances for archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
723 self.compression = compression # Method of compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
724 self.mode = key = mode.replace('b', '')[0]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
725 self.pwd = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
726 self.comment = b''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
727
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
728 # Check if we were passed a file-like object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
729 if isinstance(file, str):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
730 # No, it's a filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
731 self._filePassed = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
732 self.filename = file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
733 modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
734 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
735 self.fp = io.open(file, modeDict[mode])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
736 except IOError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
737 if mode == 'a':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
738 mode = key = 'w'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
739 self.fp = io.open(file, modeDict[mode])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
740 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
741 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
742 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
743 self._filePassed = 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
744 self.fp = file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
745 self.filename = getattr(file, 'name', None)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
746
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
747 if key == 'r':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
748 self._GetContents()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
749 elif key == 'w':
32
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
750 # set the modified flag so central directory gets written
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
751 # even if no files are added to the archive
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
752 self._didModify = True
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
753 elif key == 'a':
32
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
754 try:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
755 # See if file is a zip file
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
756 self._RealGetContents()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
757 # seek to start of directory and overwrite
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
758 self.fp.seek(self.start_dir, 0)
32
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
759 except BadZipfile:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
760 # file is not a zip file, just append
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
761 self.fp.seek(0, 2)
32
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
762
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
763 # set the modified flag so central directory gets written
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
764 # even if no files are added to the archive
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
765 self._didModify = True
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
766 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
767 if not self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
768 self.fp.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
769 self.fp = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
770 raise RuntimeError('Mode must be "r", "w" or "a"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
771
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
772 def _GetContents(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
773 """Read the directory, making sure we close the file if the format
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
774 is bad."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
775 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
776 self._RealGetContents()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
777 except BadZipfile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
778 if not self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
779 self.fp.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
780 self.fp = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
781 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
782
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
783 def _RealGetContents(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
784 """Read in the table of contents for the ZIP file."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
785 fp = self.fp
32
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
786 try:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
787 endrec = _EndRecData(fp)
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
788 except IOError:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
789 raise BadZipfile("File is not a zip file")
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
790 if not endrec:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
791 raise BadZipfile("File is not a zip file")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
792 if self.debug > 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
793 print(endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
794 size_cd = endrec[_ECD_SIZE] # bytes in central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
795 offset_cd = endrec[_ECD_OFFSET] # offset of central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
796 self.comment = endrec[_ECD_COMMENT] # archive comment
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
797
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
798 # "concat" is zero, unless zip was concatenated to another file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
799 concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
800 if endrec[_ECD_SIGNATURE] == stringEndArchive64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
801 # If Zip64 extension structures are present, account for them
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
802 concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
803
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
804 if self.debug > 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
805 inferred = concat + offset_cd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
806 print("given, inferred, offset", offset_cd, inferred, concat)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
807 # self.start_dir: Position of start of central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
808 self.start_dir = offset_cd + concat
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
809 fp.seek(self.start_dir, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
810 data = fp.read(size_cd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
811 fp = io.BytesIO(data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
812 total = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
813 while total < size_cd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
814 centdir = fp.read(sizeCentralDir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
815 if centdir[0:4] != stringCentralDir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
816 raise BadZipfile("Bad magic number for central directory")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
817 centdir = struct.unpack(structCentralDir, centdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
818 if self.debug > 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
819 print(centdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
820 filename = fp.read(centdir[_CD_FILENAME_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
821 flags = centdir[5]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
822 if flags & 0x800:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
823 # UTF-8 file names extension
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
824 filename = filename.decode('utf-8')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
825 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
826 # Historical ZIP filename encoding
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
827 filename = filename.decode('cp437')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
828 # Create ZipInfo instance to store file information
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
829 x = ZipInfo(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
830 x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
831 x.comment = fp.read(centdir[_CD_COMMENT_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
832 x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
833 (x.create_version, x.create_system, x.extract_version, x.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
834 x.flag_bits, x.compress_type, t, d,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
835 x.CRC, x.compress_size, x.file_size) = centdir[1:12]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
836 x.volume, x.internal_attr, x.external_attr = centdir[15:18]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
837 # Convert date/time code to (year, month, day, hour, min, sec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
838 x._raw_time = t
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
839 x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
840 t>>11, (t>>5)&0x3F, (t&0x1F) * 2 )
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
841
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
842 x._decodeExtra()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
843 x.header_offset = x.header_offset + concat
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
844 self.filelist.append(x)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
845 self.NameToInfo[x.filename] = x
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
846
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
847 # update total bytes read from central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
848 total = (total + sizeCentralDir + centdir[_CD_FILENAME_LENGTH]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
849 + centdir[_CD_EXTRA_FIELD_LENGTH]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
850 + centdir[_CD_COMMENT_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
851
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
852 if self.debug > 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
853 print("total", total)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
854
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
855
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
856 def namelist(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
857 """Return a list of file names in the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
858 l = []
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
859 for data in self.filelist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
860 l.append(data.filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
861 return l
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
862
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
863 def infolist(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
864 """Return a list of class ZipInfo instances for files in the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
865 archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
866 return self.filelist
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
867
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
868 def printdir(self, file=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
869 """Print a table of contents for the zip file."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
870 print("%-46s %19s %12s" % ("File Name", "Modified ", "Size"),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
871 file=file)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
872 for zinfo in self.filelist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
873 date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time[:6]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
874 print("%-46s %s %12d" % (zinfo.filename, date, zinfo.file_size),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
875 file=file)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
876
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
877 def testzip(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
878 """Read all the files and check the CRC."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
879 chunk_size = 2 ** 20
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
880 for zinfo in self.filelist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
881 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
882 # Read by chunks, to avoid an OverflowError or a
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
883 # MemoryError with very large embedded files.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
884 f = self.open(zinfo.filename, "r")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
885 while f.read(chunk_size): # Check CRC-32
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
886 pass
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
887 except BadZipfile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
888 return zinfo.filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
889
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
890 def getinfo(self, name):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
891 """Return the instance of ZipInfo given 'name'."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
892 info = self.NameToInfo.get(name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
893 if info is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
894 raise KeyError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
895 'There is no item named %r in the archive' % name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
896
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
897 return info
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
898
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
899 def setpassword(self, pwd):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
900 """Set default password for encrypted files."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
901 assert isinstance(pwd, bytes)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
902 self.pwd = pwd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
903
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
904 def read(self, name, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
905 """Return file bytes (as a string) for name."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
906 return self.open(name, "r", pwd).read()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
907
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
908 def open(self, name, mode="r", pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
909 """Return file-like object for 'name'."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
910 if mode not in ("r", "U", "rU"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
911 raise RuntimeError('open() requires mode "r", "U", or "rU"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
912 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
913 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
914 "Attempt to read ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
915
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
916 # Only open a new file for instances where we were not
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
917 # given a file object in the constructor
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
918 if self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
919 zef_file = self.fp
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
920 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
921 zef_file = io.open(self.filename, 'rb')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
922
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
923 # Make sure we have an info object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
924 if isinstance(name, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
925 # 'name' is already an info object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
926 zinfo = name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
927 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
928 # Get info object for name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
929 zinfo = self.getinfo(name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
930
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
931 zef_file.seek(zinfo.header_offset, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
932
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
933 # Skip the file header:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
934 fheader = zef_file.read(sizeFileHeader)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
935 if fheader[0:4] != stringFileHeader:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
936 raise BadZipfile("Bad magic number for file header")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
937
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
938 fheader = struct.unpack(structFileHeader, fheader)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
939 fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
940 if fheader[_FH_EXTRA_FIELD_LENGTH]:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
941 zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
942
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
943 if fname != zinfo.orig_filename.encode("utf-8"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
944 raise BadZipfile(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
945 'File name in directory %r and header %r differ.'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
946 % (zinfo.orig_filename, fname))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
947
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
948 # check for encrypted flag & handle password
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
949 is_encrypted = zinfo.flag_bits & 0x1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
950 zd = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
951 if is_encrypted:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
952 if not pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
953 pwd = self.pwd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
954 if not pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
955 raise RuntimeError("File %s is encrypted, "
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
956 "password required for extraction" % name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
957
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
958 zd = _ZipDecrypter(pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
959 # The first 12 bytes in the cypher stream is an encryption header
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
960 # used to strengthen the algorithm. The first 11 bytes are
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
961 # completely random, while the 12th contains the MSB of the CRC,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
962 # or the MSB of the file time depending on the header type
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
963 # and is used to check the correctness of the password.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
964 bytes = zef_file.read(12)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
965 h = list(map(zd, bytes[0:12]))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
966 if zinfo.flag_bits & 0x8:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
967 # compare against the file type from extended local headers
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
968 check_byte = (zinfo._raw_time >> 8) & 0xff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
969 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
970 # compare against the CRC otherwise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
971 check_byte = (zinfo.CRC >> 24) & 0xff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
972 if h[11] != check_byte:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
973 raise RuntimeError("Bad password for file", name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
974
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
975 # build and return a ZipExtFile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
976 if zd is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
977 zef = ZipExtFile(zef_file, zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
978 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
979 zef = ZipExtFile(zef_file, zinfo, zd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
980
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
981 # set universal newlines on ZipExtFile if necessary
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
982 if "U" in mode:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
983 zef.set_univ_newlines(True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
984 return zef
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
985
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
986 def extract(self, member, path=None, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
987 """Extract a member from the archive to the current working directory,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
988 using its full name. Its file information is extracted as accurately
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
989 as possible. `member' may be a filename or a ZipInfo object. You can
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
990 specify a different directory using `path'.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
991 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
992 if not isinstance(member, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
993 member = self.getinfo(member)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
994
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
995 if path is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
996 path = os.getcwd()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
997
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
998 return self._extract_member(member, path, pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
999
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1000 def extractall(self, path=None, members=None, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1001 """Extract all members from the archive to the current working
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1002 directory. `path' specifies a different directory to extract to.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1003 `members' is optional and must be a subset of the list returned
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1004 by namelist().
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1005 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1006 if members is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1007 members = self.namelist()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1008
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1009 for zipinfo in members:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1010 self.extract(zipinfo, path, pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1011
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1012 def _extract_member(self, member, targetpath, pwd):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1013 """Extract the ZipInfo object 'member' to a physical
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1014 file on the path targetpath.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1015 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1016 # build the destination pathname, replacing
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1017 # forward slashes to platform specific separators.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1018 # Strip trailing path separator, unless it represents the root.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1019 if (targetpath[-1:] in (os.path.sep, os.path.altsep)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1020 and len(os.path.splitdrive(targetpath)[1]) > 1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1021 targetpath = targetpath[:-1]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1022
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1023 # don't include leading "/" from file name if present
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1024 if member.filename[0] == '/':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1025 targetpath = os.path.join(targetpath, member.filename[1:])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1026 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1027 targetpath = os.path.join(targetpath, member.filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1028
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1029 targetpath = os.path.normpath(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1030
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1031 # Create all upper directories if necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1032 upperdirs = os.path.dirname(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1033 if upperdirs and not os.path.exists(upperdirs):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1034 os.makedirs(upperdirs)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1035
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1036 if member.filename[-1] == '/':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1037 if not os.path.isdir(targetpath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1038 os.mkdir(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1039 return targetpath
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1040
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1041 source = self.open(member, pwd=pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1042 target = open(targetpath, "wb")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1043 shutil.copyfileobj(source, target)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1044 source.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1045 target.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1046
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1047 return targetpath
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1048
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1049 def _writecheck(self, zinfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1050 """Check for errors before writing a file to the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1051 if zinfo.filename in self.NameToInfo:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1052 if self.debug: # Warning for duplicate names
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1053 print("Duplicate name:", zinfo.filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1054 if self.mode not in ("w", "a"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1055 raise RuntimeError('write() requires mode "w" or "a"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1056 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1057 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1058 "Attempt to write ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1059 if zinfo.compress_type == ZIP_DEFLATED and not zlib:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1060 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1061 "Compression requires the (missing) zlib module")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1062 if zinfo.compress_type == ZIP_BZIP2 and not bz2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1063 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1064 "Compression requires the (missing) bz2 module")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1065 if zinfo.compress_type not in (ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1066 raise RuntimeError("That compression method is not supported")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1067 if zinfo.file_size > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1068 if not self._allowZip64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1069 raise LargeZipFile("Filesize would require ZIP64 extensions")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1070 if zinfo.header_offset > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1071 if not self._allowZip64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1072 raise LargeZipFile(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1073 "Zipfile size would require ZIP64 extensions")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1074
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1075 def write(self, filename, arcname=None, compress_type=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1076 """Put the bytes from filename into the archive under the name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1077 arcname."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1078 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1079 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1080 "Attempt to write to ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1081
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1082 st = os.stat(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1083 isdir = stat.S_ISDIR(st.st_mode)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1084 mtime = time.localtime(st.st_mtime)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1085 date_time = mtime[0:6]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1086 # Create ZipInfo instance to store file information
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1087 if arcname is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1088 arcname = filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1089 arcname = os.path.normpath(os.path.splitdrive(arcname)[1])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1090 while arcname[0] in (os.sep, os.altsep):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1091 arcname = arcname[1:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1092 if isdir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1093 arcname += '/'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1094 zinfo = ZipInfo(arcname, date_time)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1095 zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1096 if compress_type is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1097 zinfo.compress_type = self.compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1098 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1099 zinfo.compress_type = compress_type
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1100
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1101 zinfo.file_size = st.st_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1102 zinfo.flag_bits = 0x00
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1103 zinfo.header_offset = self.fp.tell() # Start of header bytes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1104
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1105 self._writecheck(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1106 self._didModify = True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1107
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1108 if isdir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1109 zinfo.file_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1110 zinfo.compress_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1111 zinfo.CRC = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1112 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1113 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1114 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1115 return
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1116
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1117 with open(filename, "rb") as fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1118 # Must overwrite CRC and sizes with correct data later
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1119 zinfo.CRC = CRC = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1120 zinfo.compress_size = compress_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1121 zinfo.file_size = file_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1122 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1123 if zinfo.compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1124 cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1125 zlib.DEFLATED, -15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1126 elif zinfo.compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1127 cmpr = bz2.BZ2Compressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1128 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1129 cmpr = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1130 while 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1131 buf = fp.read(1024 * 8)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1132 if not buf:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1133 break
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1134 file_size = file_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1135 CRC = crc32(buf, CRC) & 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1136 if cmpr:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1137 buf = cmpr.compress(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1138 compress_size = compress_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1139 self.fp.write(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1140 if cmpr:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1141 buf = cmpr.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1142 compress_size = compress_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1143 self.fp.write(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1144 zinfo.compress_size = compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1145 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1146 zinfo.compress_size = file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1147 zinfo.CRC = CRC
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1148 zinfo.file_size = file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1149 # Seek backwards and write CRC and file sizes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1150 position = self.fp.tell() # Preserve current position in file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1151 self.fp.seek(zinfo.header_offset + 14, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1152 self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1153 zinfo.file_size))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1154 self.fp.seek(position, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1155 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1156 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1157
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1158 def writestr(self, zinfo_or_arcname, data):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1159 """Write a file into the archive. The contents is 'data', which
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1160 may be either a 'str' or a 'bytes' instance; if it is a 'str',
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1161 it is encoded as UTF-8 first.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1162 'zinfo_or_arcname' is either a ZipInfo instance or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1163 the name of the file in the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1164 if isinstance(data, str):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1165 data = data.encode("utf-8")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1166 if not isinstance(zinfo_or_arcname, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1167 zinfo = ZipInfo(filename=zinfo_or_arcname,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1168 date_time=time.localtime(time.time())[:6])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1169 zinfo.compress_type = self.compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1170 zinfo.external_attr = 0o600 << 16
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1171 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1172 zinfo = zinfo_or_arcname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1173
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1174 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1175 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1176 "Attempt to write to ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1177
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1178 zinfo.file_size = len(data) # Uncompressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1179 zinfo.header_offset = self.fp.tell() # Start of header data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1180 self._writecheck(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1181 self._didModify = True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1182 zinfo.CRC = crc32(data) & 0xffffffff # CRC-32 checksum
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1183 if zinfo.compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1184 co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1185 zlib.DEFLATED, -15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1186 data = co.compress(data) + co.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1187 zinfo.compress_size = len(data) # Compressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1188 elif zinfo.compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1189 co = bz2.BZ2Compressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1190 data = co.compress(data) + co.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1191 zinfo.compress_size = len(data) # Compressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1192 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1193 zinfo.compress_size = zinfo.file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1194 zinfo.header_offset = self.fp.tell() # Start of header data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1195 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1196 self.fp.write(data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1197 self.fp.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1198 if zinfo.flag_bits & 0x08:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1199 # Write CRC and file sizes after the file data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1200 self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1201 zinfo.file_size))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1202 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1203 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1204
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1205 def __del__(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1206 """Call the "close()" method in case the user forgot."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1207 self.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1208
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1209 def close(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1210 """Close the file, and for mode "w" and "a" write the ending
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1211 records."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1212 if self.fp is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1213 return
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1214
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1215 if self.mode in ("w", "a") and self._didModify: # write ending records
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1216 count = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1217 pos1 = self.fp.tell()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1218 for zinfo in self.filelist: # write central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1219 count = count + 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1220 dt = zinfo.date_time
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1221 dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1222 dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1223 extra = []
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1224 if zinfo.file_size > ZIP64_LIMIT \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1225 or zinfo.compress_size > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1226 extra.append(zinfo.file_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1227 extra.append(zinfo.compress_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1228 file_size = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1229 compress_size = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1230 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1231 file_size = zinfo.file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1232 compress_size = zinfo.compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1233
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1234 if zinfo.header_offset > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1235 extra.append(zinfo.header_offset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1236 header_offset = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1237 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1238 header_offset = zinfo.header_offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1239
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1240 extra_data = zinfo.extra
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1241 if extra:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1242 # Append a ZIP64 field to the extra's
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1243 extra_data = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1244 '<HH' + 'Q'*len(extra),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1245 1, 8*len(extra), *extra) + extra_data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1246
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1247 extract_version = max(45, zinfo.extract_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1248 create_version = max(45, zinfo.create_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1249 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1250 extract_version = zinfo.extract_version
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1251 create_version = zinfo.create_version
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1252
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1253 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1254 filename, flag_bits = zinfo._encodeFilenameFlags()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1255 centdir = struct.pack(structCentralDir,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1256 stringCentralDir, create_version,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1257 zinfo.create_system, extract_version, zinfo.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1258 flag_bits, zinfo.compress_type, dostime, dosdate,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1259 zinfo.CRC, compress_size, file_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1260 len(filename), len(extra_data), len(zinfo.comment),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1261 0, zinfo.internal_attr, zinfo.external_attr,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1262 header_offset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1263 except DeprecationWarning:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1264 print((structCentralDir, stringCentralDir, create_version,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1265 zinfo.create_system, extract_version, zinfo.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1266 zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1267 zinfo.CRC, compress_size, file_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1268 len(zinfo.filename), len(extra_data), len(zinfo.comment),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1269 0, zinfo.internal_attr, zinfo.external_attr,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1270 header_offset), file=sys.stderr)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1271 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1272 self.fp.write(centdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1273 self.fp.write(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1274 self.fp.write(extra_data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1275 self.fp.write(zinfo.comment)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1276
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1277 pos2 = self.fp.tell()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1278 # Write end-of-zip-archive record
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1279 centDirCount = count
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1280 centDirSize = pos2 - pos1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1281 centDirOffset = pos1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1282 if (centDirCount >= ZIP_FILECOUNT_LIMIT or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1283 centDirOffset > ZIP64_LIMIT or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1284 centDirSize > ZIP64_LIMIT):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1285 # Need to write the ZIP64 end-of-archive records
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1286 zip64endrec = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1287 structEndArchive64, stringEndArchive64,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1288 44, 45, 45, 0, 0, centDirCount, centDirCount,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1289 centDirSize, centDirOffset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1290 self.fp.write(zip64endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1291
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1292 zip64locrec = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1293 structEndArchive64Locator,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1294 stringEndArchive64Locator, 0, pos2, 1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1295 self.fp.write(zip64locrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1296 centDirCount = min(centDirCount, 0xFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1297 centDirSize = min(centDirSize, 0xFFFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1298 centDirOffset = min(centDirOffset, 0xFFFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1299
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1300 # check for valid comment length
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1301 if len(self.comment) >= ZIP_MAX_COMMENT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1302 if self.debug > 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1303 msg = 'Archive comment is too long; truncating to %d bytes' \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1304 % ZIP_MAX_COMMENT
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1305 self.comment = self.comment[:ZIP_MAX_COMMENT]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1306
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1307 endrec = struct.pack(structEndArchive, stringEndArchive,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1308 0, 0, centDirCount, centDirCount,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1309 centDirSize, centDirOffset, len(self.comment))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1310 self.fp.write(endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1311 self.fp.write(self.comment)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1312 self.fp.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1313
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1314 if not self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1315 self.fp.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1316 self.fp = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1317
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1318
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1319 class PyZipFile(ZipFile):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1320 """Class to create ZIP archives with Python library files and packages."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1321
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1322 def writepy(self, pathname, basename=""):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1323 """Add all files from "pathname" to the ZIP archive.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1324
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1325 If pathname is a package directory, search the directory and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1326 all package subdirectories recursively for all *.py and enter
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1327 the modules into the archive. If pathname is a plain
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1328 directory, listdir *.py and enter all modules. Else, pathname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1329 must be a Python *.py file and the module will be put into the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1330 archive. Added modules are always module.pyo or module.pyc.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1331 This method will compile the module.py into module.pyc if
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1332 necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1333 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1334 dir, name = os.path.split(pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1335 if os.path.isdir(pathname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1336 initname = os.path.join(pathname, "__init__.py")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1337 if os.path.isfile(initname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1338 # This is a package directory, add it
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1339 if basename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1340 basename = "%s/%s" % (basename, name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1341 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1342 basename = name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1343 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1344 print("Adding package in", pathname, "as", basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1345 fname, arcname = self._get_codename(initname[0:-3], basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1346 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1347 print("Adding", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1348 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1349 dirlist = os.listdir(pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1350 dirlist.remove("__init__.py")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1351 # Add all *.py files and package subdirectories
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1352 for filename in dirlist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1353 path = os.path.join(pathname, filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1354 root, ext = os.path.splitext(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1355 if os.path.isdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1356 if os.path.isfile(os.path.join(path, "__init__.py")):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1357 # This is a package directory, add it
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1358 self.writepy(path, basename) # Recursive call
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1359 elif ext == ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1360 fname, arcname = self._get_codename(path[0:-3],
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1361 basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1362 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1363 print("Adding", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1364 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1365 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1366 # This is NOT a package directory, add its files at top level
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1367 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1368 print("Adding files from directory", pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1369 for filename in os.listdir(pathname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1370 path = os.path.join(pathname, filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1371 root, ext = os.path.splitext(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1372 if ext == ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1373 fname, arcname = self._get_codename(path[0:-3],
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1374 basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1375 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1376 print("Adding", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1377 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1378 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1379 if pathname[-3:] != ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1380 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1381 'Files added with writepy() must end with ".py"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1382 fname, arcname = self._get_codename(pathname[0:-3], basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1383 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1384 print("Adding file", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1385 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1386
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1387 def _get_codename(self, pathname, basename):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1388 """Return (filename, archivename) for the path.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1389
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1390 Given a module name path, return the correct file path and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1391 archive name, compiling if necessary. For example, given
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1392 /python/lib/string, return (/python/lib/string.pyc, string).
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1393 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1394 file_py = pathname + ".py"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1395 file_pyc = pathname + ".pyc"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1396 file_pyo = pathname + ".pyo"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1397 if os.path.isfile(file_pyo) and \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1398 os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1399 fname = file_pyo # Use .pyo file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1400 elif not os.path.isfile(file_pyc) or \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1401 os.stat(file_pyc).st_mtime < os.stat(file_py).st_mtime:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1402 import py_compile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1403 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1404 print("Compiling", file_py)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1405 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1406 py_compile.compile(file_py, file_pyc, None, True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1407 except py_compile.PyCompileError as err:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1408 print(err.msg)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1409 fname = file_pyc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1410 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1411 fname = file_pyc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1412 archivename = os.path.split(fname)[1]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1413 if basename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1414 archivename = "%s/%s" % (basename, archivename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1415 return (fname, archivename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1416
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1417
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1418 def main(args = None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1419 import textwrap
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1420 USAGE=textwrap.dedent("""\
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1421 Usage:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1422 zipfile.py -l zipfile.zip # Show listing of a zipfile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1423 zipfile.py -t zipfile.zip # Test if a zipfile is valid
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1424 zipfile.py -e zipfile.zip target # Extract zipfile into target dir
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1425 zipfile.py -c zipfile.zip src ... # Create zipfile from sources
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1426 """)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1427 if args is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1428 args = sys.argv[1:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1429
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1430 if not args or args[0] not in ('-l', '-c', '-e', '-t'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1431 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1432 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1433
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1434 if args[0] == '-l':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1435 if len(args) != 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1436 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1437 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1438 zf = ZipFile(args[1], 'r')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1439 zf.printdir()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1440 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1441
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1442 elif args[0] == '-t':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1443 if len(args) != 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1444 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1445 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1446 zf = ZipFile(args[1], 'r')
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
1447 badfile = zf.testzip()
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
1448 if badfile:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
1449 print("The following enclosed file is corrupted: {!r}".format(badfile))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1450 print("Done testing")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1451
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1452 elif args[0] == '-e':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1453 if len(args) != 3:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1454 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1455 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1456
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1457 zf = ZipFile(args[1], 'r')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1458 out = args[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1459 for path in zf.namelist():
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1460 if path.startswith('./'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1461 tgt = os.path.join(out, path[2:])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1462 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1463 tgt = os.path.join(out, path)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1464
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1465 tgtdir = os.path.dirname(tgt)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1466 if not os.path.exists(tgtdir):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1467 os.makedirs(tgtdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1468 with open(tgt, 'wb') as fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1469 fp.write(zf.read(path))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1470 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1471
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1472 elif args[0] == '-c':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1473 if len(args) < 3:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1474 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1475 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1476
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1477 def addToZip(zf, path, zippath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1478 if os.path.isfile(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1479 zf.write(path, zippath, ZIP_DEFLATED)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1480 elif os.path.isdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1481 for nm in os.listdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1482 addToZip(zf,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1483 os.path.join(path, nm), os.path.join(zippath, nm))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1484 # else: ignore
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1485
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1486 zf = ZipFile(args[1], 'w', allowZip64=True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1487 for src in args[2:]:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1488 addToZip(zf, src, os.path.basename(src))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1489
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1490 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1491
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1492 if __name__ == "__main__":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1493 main()