annotate zipfiles/zipfile31.py @ 246:1bc89faac941 2.04

Fixed: match='re' could produce duplicate test identifiers files.Files.regexp(pattern) now makes sure to return only one metafile for each matching virtual path, namely, the one that would be returned for that virtual path by files.Files.from_virtual_path.
author Oleg Oshmyan <chortos@inbox.lv>
date Thu, 03 Oct 2013 01:19:09 +0300
parents b993d9257400
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."""
170
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
901 if pwd and not isinstance(pwd, bytes):
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
902 raise TypeError("pwd: expected bytes, got %s" % type(pwd))
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
903 if pwd:
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
904 self.pwd = pwd
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
905 else:
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
906 self.pwd = None
21
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 read(self, name, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
909 """Return file bytes (as a string) for name."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
910 return self.open(name, "r", pwd).read()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
911
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
912 def open(self, name, mode="r", pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
913 """Return file-like object for 'name'."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
914 if mode not in ("r", "U", "rU"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
915 raise RuntimeError('open() requires mode "r", "U", or "rU"')
170
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
916 if pwd and not isinstance(pwd, bytes):
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
917 raise TypeError("pwd: expected bytes, got %s" % type(pwd))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
918 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
919 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
920 "Attempt to read ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
921
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
922 # Only open a new file for instances where we were not
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
923 # given a file object in the constructor
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
924 if self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
925 zef_file = self.fp
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
926 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
927 zef_file = io.open(self.filename, 'rb')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
928
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
929 # Make sure we have an info object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
930 if isinstance(name, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
931 # 'name' is already an info object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
932 zinfo = name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
933 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
934 # Get info object for name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
935 zinfo = self.getinfo(name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
936
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
937 zef_file.seek(zinfo.header_offset, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
938
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
939 # Skip the file header:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
940 fheader = zef_file.read(sizeFileHeader)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
941 if fheader[0:4] != stringFileHeader:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
942 raise BadZipfile("Bad magic number for file header")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
943
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
944 fheader = struct.unpack(structFileHeader, fheader)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
945 fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
946 if fheader[_FH_EXTRA_FIELD_LENGTH]:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
947 zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
948
170
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
949 if zinfo.flag_bits & 0x800:
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
950 # UTF-8 filename
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
951 fname_str = fname.decode("utf-8")
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
952 else:
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
953 fname_str = fname.decode("cp437")
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
954
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
955 if fname_str != zinfo.orig_filename:
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
956 raise BadZipfile(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
957 'File name in directory %r and header %r differ.'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
958 % (zinfo.orig_filename, fname))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
959
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
960 # check for encrypted flag & handle password
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
961 is_encrypted = zinfo.flag_bits & 0x1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
962 zd = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
963 if is_encrypted:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
964 if not pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
965 pwd = self.pwd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
966 if not pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
967 raise RuntimeError("File %s is encrypted, "
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
968 "password required for extraction" % name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
969
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
970 zd = _ZipDecrypter(pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
971 # 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
972 # used to strengthen the algorithm. The first 11 bytes are
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
973 # completely random, while the 12th contains the MSB of the CRC,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
974 # 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
975 # and is used to check the correctness of the password.
170
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
976 header = zef_file.read(12)
b993d9257400 Updated zipfiles
Oleg Oshmyan <chortos@inbox.lv>
parents: 153
diff changeset
977 h = list(map(zd, header[0:12]))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
978 if zinfo.flag_bits & 0x8:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
979 # compare against the file type from extended local headers
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
980 check_byte = (zinfo._raw_time >> 8) & 0xff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
981 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
982 # compare against the CRC otherwise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
983 check_byte = (zinfo.CRC >> 24) & 0xff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
984 if h[11] != check_byte:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
985 raise RuntimeError("Bad password for file", name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
986
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
987 # build and return a ZipExtFile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
988 if zd is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
989 zef = ZipExtFile(zef_file, zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
990 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
991 zef = ZipExtFile(zef_file, zinfo, zd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
992
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
993 # set universal newlines on ZipExtFile if necessary
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
994 if "U" in mode:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
995 zef.set_univ_newlines(True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
996 return zef
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 def extract(self, member, path=None, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
999 """Extract a member from the archive to the current working directory,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1000 using its full name. Its file information is extracted as accurately
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1001 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
1002 specify a different directory using `path'.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1003 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1004 if not isinstance(member, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1005 member = self.getinfo(member)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1006
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1007 if path is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1008 path = os.getcwd()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1009
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1010 return self._extract_member(member, 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 extractall(self, path=None, members=None, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1013 """Extract all members from the archive to the current working
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1014 directory. `path' specifies a different directory to extract to.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1015 `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
1016 by namelist().
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1017 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1018 if members is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1019 members = self.namelist()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1020
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1021 for zipinfo in members:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1022 self.extract(zipinfo, path, pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1023
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1024 def _extract_member(self, member, targetpath, pwd):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1025 """Extract the ZipInfo object 'member' to a physical
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1026 file on the path targetpath.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1027 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1028 # build the destination pathname, replacing
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1029 # forward slashes to platform specific separators.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1030 # Strip trailing path separator, unless it represents the root.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1031 if (targetpath[-1:] in (os.path.sep, os.path.altsep)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1032 and len(os.path.splitdrive(targetpath)[1]) > 1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1033 targetpath = targetpath[:-1]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1034
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1035 # don't include leading "/" from file name if present
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1036 if member.filename[0] == '/':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1037 targetpath = os.path.join(targetpath, member.filename[1:])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1038 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1039 targetpath = os.path.join(targetpath, member.filename)
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 targetpath = os.path.normpath(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1042
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1043 # Create all upper directories if necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1044 upperdirs = os.path.dirname(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1045 if upperdirs and not os.path.exists(upperdirs):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1046 os.makedirs(upperdirs)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1047
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1048 if member.filename[-1] == '/':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1049 if not os.path.isdir(targetpath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1050 os.mkdir(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1051 return targetpath
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1052
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1053 source = self.open(member, pwd=pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1054 target = open(targetpath, "wb")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1055 shutil.copyfileobj(source, target)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1056 source.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1057 target.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1058
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1059 return targetpath
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1060
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1061 def _writecheck(self, zinfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1062 """Check for errors before writing a file to the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1063 if zinfo.filename in self.NameToInfo:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1064 if self.debug: # Warning for duplicate names
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1065 print("Duplicate name:", zinfo.filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1066 if self.mode not in ("w", "a"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1067 raise RuntimeError('write() requires mode "w" or "a"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1068 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1069 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1070 "Attempt to write ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1071 if zinfo.compress_type == ZIP_DEFLATED and not zlib:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1072 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1073 "Compression requires the (missing) zlib module")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1074 if zinfo.compress_type == ZIP_BZIP2 and not bz2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1075 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1076 "Compression requires the (missing) bz2 module")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1077 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
1078 raise RuntimeError("That compression method is not supported")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1079 if zinfo.file_size > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1080 if not self._allowZip64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1081 raise LargeZipFile("Filesize would require ZIP64 extensions")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1082 if zinfo.header_offset > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1083 if not self._allowZip64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1084 raise LargeZipFile(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1085 "Zipfile size would require ZIP64 extensions")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1086
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1087 def write(self, filename, arcname=None, compress_type=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1088 """Put the bytes from filename into the archive under the name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1089 arcname."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1090 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1091 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1092 "Attempt to write to ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1093
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1094 st = os.stat(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1095 isdir = stat.S_ISDIR(st.st_mode)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1096 mtime = time.localtime(st.st_mtime)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1097 date_time = mtime[0:6]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1098 # Create ZipInfo instance to store file information
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1099 if arcname is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1100 arcname = filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1101 arcname = os.path.normpath(os.path.splitdrive(arcname)[1])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1102 while arcname[0] in (os.sep, os.altsep):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1103 arcname = arcname[1:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1104 if isdir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1105 arcname += '/'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1106 zinfo = ZipInfo(arcname, date_time)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1107 zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1108 if compress_type is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1109 zinfo.compress_type = self.compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1110 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1111 zinfo.compress_type = compress_type
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1112
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1113 zinfo.file_size = st.st_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1114 zinfo.flag_bits = 0x00
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1115 zinfo.header_offset = self.fp.tell() # Start of header bytes
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 self._writecheck(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1118 self._didModify = True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1119
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1120 if isdir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1121 zinfo.file_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1122 zinfo.compress_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1123 zinfo.CRC = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1124 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1125 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1126 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1127 return
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1128
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1129 with open(filename, "rb") as fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1130 # Must overwrite CRC and sizes with correct data later
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1131 zinfo.CRC = CRC = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1132 zinfo.compress_size = compress_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1133 zinfo.file_size = file_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1134 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1135 if zinfo.compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1136 cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1137 zlib.DEFLATED, -15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1138 elif zinfo.compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1139 cmpr = bz2.BZ2Compressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1140 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1141 cmpr = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1142 while 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1143 buf = fp.read(1024 * 8)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1144 if not buf:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1145 break
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1146 file_size = file_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1147 CRC = crc32(buf, CRC) & 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1148 if cmpr:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1149 buf = cmpr.compress(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1150 compress_size = compress_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1151 self.fp.write(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1152 if cmpr:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1153 buf = cmpr.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1154 compress_size = compress_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1155 self.fp.write(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1156 zinfo.compress_size = compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1157 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1158 zinfo.compress_size = file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1159 zinfo.CRC = CRC
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1160 zinfo.file_size = file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1161 # Seek backwards and write CRC and file sizes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1162 position = self.fp.tell() # Preserve current position in file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1163 self.fp.seek(zinfo.header_offset + 14, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1164 self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1165 zinfo.file_size))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1166 self.fp.seek(position, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1167 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1168 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1169
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1170 def writestr(self, zinfo_or_arcname, data):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1171 """Write a file into the archive. The contents is 'data', which
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1172 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
1173 it is encoded as UTF-8 first.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1174 'zinfo_or_arcname' is either a ZipInfo instance or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1175 the name of the file in the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1176 if isinstance(data, str):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1177 data = data.encode("utf-8")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1178 if not isinstance(zinfo_or_arcname, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1179 zinfo = ZipInfo(filename=zinfo_or_arcname,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1180 date_time=time.localtime(time.time())[:6])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1181 zinfo.compress_type = self.compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1182 zinfo.external_attr = 0o600 << 16
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1183 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1184 zinfo = zinfo_or_arcname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1185
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1186 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1187 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1188 "Attempt to write to ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1189
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1190 zinfo.file_size = len(data) # Uncompressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1191 zinfo.header_offset = self.fp.tell() # Start of header data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1192 self._writecheck(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1193 self._didModify = True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1194 zinfo.CRC = crc32(data) & 0xffffffff # CRC-32 checksum
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1195 if zinfo.compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1196 co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1197 zlib.DEFLATED, -15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1198 data = co.compress(data) + co.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1199 zinfo.compress_size = len(data) # Compressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1200 elif zinfo.compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1201 co = bz2.BZ2Compressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1202 data = co.compress(data) + co.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1203 zinfo.compress_size = len(data) # Compressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1204 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1205 zinfo.compress_size = zinfo.file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1206 zinfo.header_offset = self.fp.tell() # Start of header data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1207 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1208 self.fp.write(data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1209 self.fp.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1210 if zinfo.flag_bits & 0x08:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1211 # Write CRC and file sizes after the file data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1212 self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1213 zinfo.file_size))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1214 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1215 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1216
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1217 def __del__(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1218 """Call the "close()" method in case the user forgot."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1219 self.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1220
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1221 def close(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1222 """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
1223 records."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1224 if self.fp is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1225 return
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1226
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1227 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
1228 count = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1229 pos1 = self.fp.tell()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1230 for zinfo in self.filelist: # write central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1231 count = count + 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1232 dt = zinfo.date_time
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1233 dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1234 dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1235 extra = []
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1236 if zinfo.file_size > ZIP64_LIMIT \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1237 or zinfo.compress_size > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1238 extra.append(zinfo.file_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1239 extra.append(zinfo.compress_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1240 file_size = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1241 compress_size = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1242 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1243 file_size = zinfo.file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1244 compress_size = zinfo.compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1245
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1246 if zinfo.header_offset > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1247 extra.append(zinfo.header_offset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1248 header_offset = 0xffffffff
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 header_offset = zinfo.header_offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1251
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1252 extra_data = zinfo.extra
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1253 if extra:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1254 # Append a ZIP64 field to the extra's
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1255 extra_data = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1256 '<HH' + 'Q'*len(extra),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1257 1, 8*len(extra), *extra) + extra_data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1258
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1259 extract_version = max(45, zinfo.extract_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1260 create_version = max(45, zinfo.create_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1261 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1262 extract_version = zinfo.extract_version
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1263 create_version = zinfo.create_version
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1264
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1265 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1266 filename, flag_bits = zinfo._encodeFilenameFlags()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1267 centdir = struct.pack(structCentralDir,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1268 stringCentralDir, create_version,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1269 zinfo.create_system, extract_version, zinfo.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1270 flag_bits, zinfo.compress_type, dostime, dosdate,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1271 zinfo.CRC, compress_size, file_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1272 len(filename), len(extra_data), len(zinfo.comment),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1273 0, zinfo.internal_attr, zinfo.external_attr,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1274 header_offset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1275 except DeprecationWarning:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1276 print((structCentralDir, stringCentralDir, create_version,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1277 zinfo.create_system, extract_version, zinfo.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1278 zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1279 zinfo.CRC, compress_size, file_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1280 len(zinfo.filename), len(extra_data), len(zinfo.comment),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1281 0, zinfo.internal_attr, zinfo.external_attr,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1282 header_offset), file=sys.stderr)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1283 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1284 self.fp.write(centdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1285 self.fp.write(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1286 self.fp.write(extra_data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1287 self.fp.write(zinfo.comment)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1288
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1289 pos2 = self.fp.tell()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1290 # Write end-of-zip-archive record
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1291 centDirCount = count
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1292 centDirSize = pos2 - pos1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1293 centDirOffset = pos1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1294 if (centDirCount >= ZIP_FILECOUNT_LIMIT or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1295 centDirOffset > ZIP64_LIMIT or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1296 centDirSize > ZIP64_LIMIT):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1297 # Need to write the ZIP64 end-of-archive records
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1298 zip64endrec = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1299 structEndArchive64, stringEndArchive64,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1300 44, 45, 45, 0, 0, centDirCount, centDirCount,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1301 centDirSize, centDirOffset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1302 self.fp.write(zip64endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1303
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1304 zip64locrec = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1305 structEndArchive64Locator,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1306 stringEndArchive64Locator, 0, pos2, 1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1307 self.fp.write(zip64locrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1308 centDirCount = min(centDirCount, 0xFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1309 centDirSize = min(centDirSize, 0xFFFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1310 centDirOffset = min(centDirOffset, 0xFFFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1311
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1312 # check for valid comment length
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1313 if len(self.comment) >= ZIP_MAX_COMMENT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1314 if self.debug > 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1315 msg = 'Archive comment is too long; truncating to %d bytes' \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1316 % ZIP_MAX_COMMENT
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1317 self.comment = self.comment[:ZIP_MAX_COMMENT]
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 endrec = struct.pack(structEndArchive, stringEndArchive,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1320 0, 0, centDirCount, centDirCount,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1321 centDirSize, centDirOffset, len(self.comment))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1322 self.fp.write(endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1323 self.fp.write(self.comment)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1324 self.fp.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1325
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1326 if not self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1327 self.fp.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1328 self.fp = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1329
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1330
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1331 class PyZipFile(ZipFile):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1332 """Class to create ZIP archives with Python library files and packages."""
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 def writepy(self, pathname, basename=""):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1335 """Add all files from "pathname" to the ZIP archive.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1336
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1337 If pathname is a package directory, search the directory and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1338 all package subdirectories recursively for all *.py and enter
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1339 the modules into the archive. If pathname is a plain
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1340 directory, listdir *.py and enter all modules. Else, pathname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1341 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
1342 archive. Added modules are always module.pyo or module.pyc.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1343 This method will compile the module.py into module.pyc if
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1344 necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1345 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1346 dir, name = os.path.split(pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1347 if os.path.isdir(pathname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1348 initname = os.path.join(pathname, "__init__.py")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1349 if os.path.isfile(initname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1350 # This is a package directory, add it
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1351 if basename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1352 basename = "%s/%s" % (basename, name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1353 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1354 basename = name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1355 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1356 print("Adding package in", pathname, "as", basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1357 fname, arcname = self._get_codename(initname[0:-3], basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1358 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1359 print("Adding", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1360 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1361 dirlist = os.listdir(pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1362 dirlist.remove("__init__.py")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1363 # Add all *.py files and package subdirectories
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1364 for filename in dirlist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1365 path = os.path.join(pathname, filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1366 root, ext = os.path.splitext(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1367 if os.path.isdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1368 if os.path.isfile(os.path.join(path, "__init__.py")):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1369 # This is a package directory, add it
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1370 self.writepy(path, basename) # Recursive call
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1371 elif ext == ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1372 fname, arcname = self._get_codename(path[0:-3],
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1373 basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1374 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1375 print("Adding", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1376 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1377 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1378 # 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
1379 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1380 print("Adding files from directory", pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1381 for filename in os.listdir(pathname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1382 path = os.path.join(pathname, filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1383 root, ext = os.path.splitext(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1384 if ext == ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1385 fname, arcname = self._get_codename(path[0:-3],
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1386 basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1387 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1388 print("Adding", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1389 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1390 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1391 if pathname[-3:] != ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1392 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1393 'Files added with writepy() must end with ".py"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1394 fname, arcname = self._get_codename(pathname[0:-3], basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1395 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1396 print("Adding file", arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1397 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1398
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1399 def _get_codename(self, pathname, basename):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1400 """Return (filename, archivename) for the path.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1401
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1402 Given a module name path, return the correct file path and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1403 archive name, compiling if necessary. For example, given
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1404 /python/lib/string, return (/python/lib/string.pyc, string).
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1405 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1406 file_py = pathname + ".py"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1407 file_pyc = pathname + ".pyc"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1408 file_pyo = pathname + ".pyo"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1409 if os.path.isfile(file_pyo) and \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1410 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
1411 fname = file_pyo # Use .pyo file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1412 elif not os.path.isfile(file_pyc) or \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1413 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
1414 import py_compile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1415 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1416 print("Compiling", file_py)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1417 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1418 py_compile.compile(file_py, file_pyc, None, True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1419 except py_compile.PyCompileError as err:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1420 print(err.msg)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1421 fname = file_pyc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1422 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1423 fname = file_pyc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1424 archivename = os.path.split(fname)[1]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1425 if basename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1426 archivename = "%s/%s" % (basename, archivename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1427 return (fname, archivename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1428
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 def main(args = None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1431 import textwrap
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1432 USAGE=textwrap.dedent("""\
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1433 Usage:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1434 zipfile.py -l zipfile.zip # Show listing of a zipfile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1435 zipfile.py -t zipfile.zip # Test if a zipfile is valid
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1436 zipfile.py -e zipfile.zip target # Extract zipfile into target dir
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1437 zipfile.py -c zipfile.zip src ... # Create zipfile from sources
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1438 """)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1439 if args is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1440 args = sys.argv[1:]
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 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
1443 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1444 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1445
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1446 if args[0] == '-l':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1447 if len(args) != 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1448 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1449 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1450 zf = ZipFile(args[1], 'r')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1451 zf.printdir()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1452 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1453
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1454 elif args[0] == '-t':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1455 if len(args) != 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1456 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1457 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1458 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
1459 badfile = zf.testzip()
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
1460 if badfile:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 28
diff changeset
1461 print("The following enclosed file is corrupted: {!r}".format(badfile))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1462 print("Done testing")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1463
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1464 elif args[0] == '-e':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1465 if len(args) != 3:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1466 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1467 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1468
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1469 zf = ZipFile(args[1], 'r')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1470 out = args[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1471 for path in zf.namelist():
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1472 if path.startswith('./'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1473 tgt = os.path.join(out, path[2:])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1474 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1475 tgt = os.path.join(out, path)
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 tgtdir = os.path.dirname(tgt)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1478 if not os.path.exists(tgtdir):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1479 os.makedirs(tgtdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1480 with open(tgt, 'wb') as fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1481 fp.write(zf.read(path))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1482 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1483
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1484 elif args[0] == '-c':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1485 if len(args) < 3:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1486 print(USAGE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1487 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1488
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1489 def addToZip(zf, path, zippath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1490 if os.path.isfile(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1491 zf.write(path, zippath, ZIP_DEFLATED)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1492 elif os.path.isdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1493 for nm in os.listdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1494 addToZip(zf,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1495 os.path.join(path, nm), os.path.join(zippath, nm))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1496 # else: ignore
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1497
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1498 zf = ZipFile(args[1], 'w', allowZip64=True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1499 for src in args[2:]:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1500 addToZip(zf, src, os.path.basename(src))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1501
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1502 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1503
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1504 if __name__ == "__main__":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1505 main()