annotate zipfiles/zipfile27.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 45d4a9dc707b
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 # Improved by Chortos-2 in 2010 (added bzip2 support)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
5 import struct, os, time, sys, shutil
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
6 import binascii, cStringIO, stat
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
7 import io
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
8 import re
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 = "<4s4H2LH"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
56 stringEndArchive = "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 = "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 = "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 = "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 = "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:] == "\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("")
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 = "" # Comment for each file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
305 self.extra = "" # 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 if isinstance(self.filename, unicode):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
360 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
361 return self.filename.encode('ascii'), self.flag_bits
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
362 except UnicodeEncodeError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
363 return self.filename.encode('utf-8'), self.flag_bits | 0x800
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
364 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
365 return self.filename, self.flag_bits
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
366
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
367 def _decodeFilename(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
368 if self.flag_bits & 0x800:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
369 return self.filename.decode('utf-8')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
370 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
371 return self.filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
372
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
373 def _decodeExtra(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
374 # Try to decode the extra field.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
375 extra = self.extra
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
376 unpack = struct.unpack
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
377 while extra:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
378 tp, ln = unpack('<HH', extra[:4])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
379 if tp == 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
380 if ln >= 24:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
381 counts = unpack('<QQQ', extra[4:28])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
382 elif ln == 16:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
383 counts = unpack('<QQ', extra[4:20])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
384 elif ln == 8:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
385 counts = unpack('<Q', extra[4:12])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
386 elif ln == 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
387 counts = ()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
388 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
389 raise RuntimeError, "Corrupt extra field %s"%(ln,)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
390
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
391 idx = 0
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 # ZIP64 extension (large files and/or large archives)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
394 if self.file_size in (0xffffffffffffffffL, 0xffffffffL):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
395 self.file_size = 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 if self.compress_size == 0xFFFFFFFFL:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
399 self.compress_size = counts[idx]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
400 idx += 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
401
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
402 if self.header_offset == 0xffffffffL:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
403 old = self.header_offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
404 self.header_offset = counts[idx]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
405 idx+=1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
406
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
407 extra = extra[ln+4:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
408
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
409
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
410 class _ZipDecrypter:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
411 """Class to handle decryption of files stored within a ZIP archive.
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 ZIP supports a password-based form of encryption. Even though known
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
414 plaintext attacks have been found against it, it is still useful
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
415 to be able to get data out of such a file.
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 Usage:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
418 zd = _ZipDecrypter(mypwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
419 plain_char = zd(cypher_char)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
420 plain_text = map(zd, cypher_text)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
421 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
422
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
423 def _GenerateCRCTable():
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
424 """Generate a CRC-32 table.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
425
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
426 ZIP encryption uses the CRC32 one-byte primitive for scrambling some
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
427 internal keys. We noticed that a direct implementation is faster than
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
428 relying on binascii.crc32().
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
429 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
430 poly = 0xedb88320
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
431 table = [0] * 256
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
432 for i in range(256):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
433 crc = i
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
434 for j in range(8):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
435 if crc & 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
436 crc = ((crc >> 1) & 0x7FFFFFFF) ^ poly
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
437 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
438 crc = ((crc >> 1) & 0x7FFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
439 table[i] = crc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
440 return table
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
441 crctable = _GenerateCRCTable()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
442
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
443 def _crc32(self, ch, crc):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
444 """Compute the CRC32 primitive on one byte."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
445 return ((crc >> 8) & 0xffffff) ^ self.crctable[(crc ^ ord(ch)) & 0xff]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
446
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
447 def __init__(self, pwd):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
448 self.key0 = 305419896
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
449 self.key1 = 591751049
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
450 self.key2 = 878082192
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
451 for p in pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
452 self._UpdateKeys(p)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
453
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
454 def _UpdateKeys(self, c):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
455 self.key0 = self._crc32(c, self.key0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
456 self.key1 = (self.key1 + (self.key0 & 255)) & 4294967295
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
457 self.key1 = (self.key1 * 134775813 + 1) & 4294967295
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
458 self.key2 = self._crc32(chr((self.key1 >> 24) & 255), self.key2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
459
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
460 def __call__(self, c):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
461 """Decrypt a single character."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
462 c = ord(c)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
463 k = self.key2 | 2
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
464 c = c ^ (((k * (k^1)) >> 8) & 255)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
465 c = chr(c)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
466 self._UpdateKeys(c)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
467 return c
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
468
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
469 class ZipExtFile(io.BufferedIOBase):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
470 """File-like object for reading an archive member.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
471 Is returned by ZipFile.open().
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
472 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
473
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
474 # Max size supported by decompressor.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
475 MAX_N = 1 << 31 - 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
476
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
477 # Read from compressed files in 4k blocks.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
478 MIN_READ_SIZE = 4096
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
479
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
480 # Search for universal newlines or line chunks.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
481 PATTERN = re.compile(r'^(?P<chunk>[^\r\n]+)|(?P<newline>\n|\r\n?)')
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 def __init__(self, fileobj, mode, zipinfo, decrypter=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
484 self._fileobj = fileobj
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
485 self._decrypter = decrypter
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
486
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
487 self._compress_type = zipinfo.compress_type
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
488 self._compress_size = zipinfo.compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
489 self._compress_left = zipinfo.compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
490
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
491 if self._compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
492 self._decompressor = zlib.decompressobj(-15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
493 elif self._compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
494 self._decompressor = bz2.BZ2Decompressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
495 self.MIN_READ_SIZE = 900000
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
496 self._unconsumed = ''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
497
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
498 self._readbuffer = ''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
499 self._offset = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
500
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
501 self._universal = 'U' in mode
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
502 self.newlines = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
503
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
504 # Adjust read size for encrypted files since the first 12 bytes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
505 # are for the encryption/password information.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
506 if self._decrypter is not None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
507 self._compress_left -= 12
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
508
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
509 self.mode = mode
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
510 self.name = zipinfo.filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
511
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
512 if hasattr(zipinfo, 'CRC'):
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
513 self._expected_crc = zipinfo.CRC
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
514 self._running_crc = crc32(b'') & 0xffffffff
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
515 else:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
516 self._expected_crc = None
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
517
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
518 def readline(self, limit=-1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
519 """Read and return a line from the stream.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
520
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
521 If limit is specified, at most limit bytes will be read.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
522 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
523
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
524 if not self._universal and limit < 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
525 # Shortcut common case - newline found in buffer.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
526 i = self._readbuffer.find('\n', self._offset) + 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
527 if i > 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
528 line = self._readbuffer[self._offset: i]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
529 self._offset = i
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
530 return line
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
531
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
532 if not self._universal:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
533 return io.BufferedIOBase.readline(self, limit)
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 line = ''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
536 while limit < 0 or len(line) < limit:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
537 readahead = self.peek(2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
538 if readahead == '':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
539 return line
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
540
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
541 #
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
542 # Search for universal newlines or line chunks.
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 # The pattern returns either a line chunk or a newline, but not
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
545 # both. Combined with peek(2), we are assured that the sequence
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
546 # '\r\n' is always retrieved completely and never split into
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
547 # separate newlines - '\r', '\n' due to coincidental readaheads.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
548 #
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
549 match = self.PATTERN.search(readahead)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
550 newline = match.group('newline')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
551 if newline is not None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
552 if self.newlines is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
553 self.newlines = []
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
554 if newline not in self.newlines:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
555 self.newlines.append(newline)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
556 self._offset += len(newline)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
557 return line + '\n'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
558
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
559 chunk = match.group('chunk')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
560 if limit >= 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
561 chunk = chunk[: limit - len(line)]
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 self._offset += len(chunk)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
564 line += chunk
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
565
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
566 return line
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
567
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
568 def peek(self, n=1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
569 """Returns buffered bytes without advancing the position."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
570 if n > len(self._readbuffer) - self._offset:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
571 chunk = self.read(n)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
572 self._offset -= len(chunk)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
573
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
574 # Return up to 512 bytes to reduce allocation overhead for tight loops.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
575 return self._readbuffer[self._offset: self._offset + 512]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
576
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
577 def readable(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
578 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
579
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
580 def read(self, n=-1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
581 """Read and return up to n bytes.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
582 If the argument is omitted, None, or negative, data is read and returned until EOF is reached..
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
583 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
584 buf = ''
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
585 if n is None:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
586 n = -1
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
587 while True:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
588 if n < 0:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
589 data = self.read1(n)
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
590 elif n > len(buf):
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
591 data = self.read1(n - len(buf))
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
592 else:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
593 return buf
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
594 if len(data) == 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
595 return buf
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
596 buf += data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
597
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
598 def _update_crc(self, newdata, eof):
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
599 # Update the CRC using the given data.
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
600 if self._expected_crc is None:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
601 # 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: 21
diff changeset
602 return
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
603 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: 21
diff changeset
604 # 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: 21
diff changeset
605 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: 21
diff changeset
606 raise BadZipfile("Bad CRC-32 for file %r" % self.name)
21
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 def read1(self, n):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
609 """Read up to n bytes with at most one read() system call."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
610
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
611 # Simplify algorithm (branching) by transforming negative n to large n.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
612 if n < 0 or n is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
613 n = self.MAX_N
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
614
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
615 # Bytes available in read buffer.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
616 len_readbuffer = len(self._readbuffer) - self._offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
617
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
618 # Read from file.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
619 if self._compress_left > 0 and n > len_readbuffer + len(self._unconsumed):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
620 nbytes = n - len_readbuffer - len(self._unconsumed)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
621 nbytes = max(nbytes, self.MIN_READ_SIZE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
622 nbytes = min(nbytes, self._compress_left)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
623
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
624 data = self._fileobj.read(nbytes)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
625 self._compress_left -= len(data)
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 if data and self._decrypter is not None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
628 data = ''.join(map(self._decrypter, data))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
629
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
630 if self._compress_type == ZIP_STORED:
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
631 self._update_crc(data, eof=(self._compress_left==0))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
632 self._readbuffer = self._readbuffer[self._offset:] + data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
633 self._offset = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
634 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
635 # Prepare deflated bytes for decompression.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
636 self._unconsumed += data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
637
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
638 # Handle unconsumed data.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
639 if (len(self._unconsumed) > 0 and n > len_readbuffer and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
640 self._compress_type == ZIP_DEFLATED):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
641 data = self._decompressor.decompress(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
642 self._unconsumed,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
643 max(n - len_readbuffer, self.MIN_READ_SIZE)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
644 )
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
645
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
646 self._unconsumed = self._decompressor.unconsumed_tail
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
647 eof = len(self._unconsumed) == 0 and self._compress_left == 0
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
648 if eof:
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
649 data += self._decompressor.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
650
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
651 self._update_crc(data, eof=eof)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
652 self._readbuffer = self._readbuffer[self._offset:] + data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
653 self._offset = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
654 elif (len(self._unconsumed) > 0 and n > len_readbuffer and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
655 self._compress_type == ZIP_BZIP2):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
656 data = self._decompressor.decompress(self._unconsumed)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
657
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
658 self._unconsumed = ''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
659 self._readbuffer = self._readbuffer[self._offset:] + data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
660 self._offset = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
661
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
662 # Read from buffer.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
663 data = self._readbuffer[self._offset: self._offset + n]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
664 self._offset += len(data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
665 return data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
666
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
667
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
668
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
669 class ZipFile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
670 """ Class with methods to open, read, write, close, list zip files.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
671
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
672 z = ZipFile(file, mode="r", compression=ZIP_STORED, allowZip64=False)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
673
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
674 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
675 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
676 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
677 compression: ZIP_STORED (no compression), ZIP_DEFLATED (requires zlib),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
678 or ZIP_BZIP2 (requires bz2).
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
679 allowZip64: if True ZipFile will create files with ZIP64 extensions when
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
680 needed, otherwise it will raise an exception when this would
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
681 be necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
682
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
683 """
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 fp = None # Set here since __del__ checks it
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 def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
688 """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
689 if mode not in ("r", "w", "a"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
690 raise RuntimeError('ZipFile() requires mode "r", "w", or "a"')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
691
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
692 if compression == ZIP_STORED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
693 pass
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
694 elif compression == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
695 if not zlib:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
696 raise RuntimeError,\
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
697 "Compression requires the (missing) zlib module"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
698 elif compression == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
699 if not bz2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
700 raise RuntimeError,\
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
701 "Compression requires the (missing) bz2 module"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
702 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
703 raise RuntimeError, "That compression method is not supported"
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 self._allowZip64 = allowZip64
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
706 self._didModify = False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
707 self.debug = 0 # Level of printing: 0 through 3
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
708 self.NameToInfo = {} # Find file info given name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
709 self.filelist = [] # List of ZipInfo instances for archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
710 self.compression = compression # Method of compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
711 self.mode = key = mode.replace('b', '')[0]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
712 self.pwd = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
713 self.comment = ''
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
714
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
715 # Check if we were passed a file-like object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
716 if isinstance(file, basestring):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
717 self._filePassed = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
718 self.filename = file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
719 modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
720 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
721 self.fp = open(file, modeDict[mode])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
722 except IOError:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
723 if mode == 'a':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
724 mode = key = 'w'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
725 self.fp = open(file, modeDict[mode])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
726 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
727 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
728 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
729 self._filePassed = 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
730 self.fp = file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
731 self.filename = getattr(file, 'name', None)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
732
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
733 if key == 'r':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
734 self._GetContents()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
735 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
736 # 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
737 # 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
738 self._didModify = True
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
739 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
740 try:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
741 # See if file is a zip file
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
742 self._RealGetContents()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
743 # seek to start of directory and overwrite
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
744 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
745 except BadZipfile:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
746 # file is not a zip file, just append
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
747 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
748
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
749 # 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
750 # 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
751 self._didModify = True
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
752 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
753 if not self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
754 self.fp.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
755 self.fp = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
756 raise RuntimeError, 'Mode must be "r", "w" or "a"'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
757
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
758 def __enter__(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
759 return self
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
760
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
761 def __exit__(self, type, value, traceback):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
762 self.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
763
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
764 def _GetContents(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
765 """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
766 is bad."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
767 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
768 self._RealGetContents()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
769 except BadZipfile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
770 if not self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
771 self.fp.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
772 self.fp = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
773 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
774
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
775 def _RealGetContents(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
776 """Read in the table of contents for the ZIP file."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
777 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
778 try:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
779 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
780 except IOError:
3000bb94addb Updated zipfile to 2.7.1 and 3.1.3 final releases.
Oleg Oshmyan <chortos@inbox.lv>
parents: 29
diff changeset
781 raise BadZipfile("File is not a zip file")
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
782 if not endrec:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
783 raise BadZipfile, "File is not a zip file"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
784 if self.debug > 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
785 print endrec
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
786 size_cd = endrec[_ECD_SIZE] # bytes in central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
787 offset_cd = endrec[_ECD_OFFSET] # offset of central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
788 self.comment = endrec[_ECD_COMMENT] # archive comment
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
789
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
790 # "concat" is zero, unless zip was concatenated to another file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
791 concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
792 if endrec[_ECD_SIGNATURE] == stringEndArchive64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
793 # If Zip64 extension structures are present, account for them
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
794 concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
795
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
796 if self.debug > 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
797 inferred = concat + offset_cd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
798 print "given, inferred, offset", offset_cd, inferred, concat
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
799 # self.start_dir: Position of start of central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
800 self.start_dir = offset_cd + concat
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
801 fp.seek(self.start_dir, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
802 data = fp.read(size_cd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
803 fp = cStringIO.StringIO(data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
804 total = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
805 while total < size_cd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
806 centdir = fp.read(sizeCentralDir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
807 if centdir[0:4] != stringCentralDir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
808 raise BadZipfile, "Bad magic number for central directory"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
809 centdir = struct.unpack(structCentralDir, centdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
810 if self.debug > 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
811 print centdir
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
812 filename = fp.read(centdir[_CD_FILENAME_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
813 # Create ZipInfo instance to store file information
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
814 x = ZipInfo(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
815 x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
816 x.comment = fp.read(centdir[_CD_COMMENT_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
817 x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
818 (x.create_version, x.create_system, x.extract_version, x.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
819 x.flag_bits, x.compress_type, t, d,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
820 x.CRC, x.compress_size, x.file_size) = centdir[1:12]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
821 x.volume, x.internal_attr, x.external_attr = centdir[15:18]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
822 # Convert date/time code to (year, month, day, hour, min, sec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
823 x._raw_time = t
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
824 x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
825 t>>11, (t>>5)&0x3F, (t&0x1F) * 2 )
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
826
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
827 x._decodeExtra()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
828 x.header_offset = x.header_offset + concat
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
829 x.filename = x._decodeFilename()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
830 self.filelist.append(x)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
831 self.NameToInfo[x.filename] = x
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
832
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
833 # update total bytes read from central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
834 total = (total + sizeCentralDir + centdir[_CD_FILENAME_LENGTH]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
835 + centdir[_CD_EXTRA_FIELD_LENGTH]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
836 + centdir[_CD_COMMENT_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
837
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
838 if self.debug > 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
839 print "total", total
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
840
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 def namelist(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
843 """Return a list of file names in the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
844 l = []
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
845 for data in self.filelist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
846 l.append(data.filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
847 return l
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
848
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
849 def infolist(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
850 """Return a list of class ZipInfo instances for files in the
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
851 archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
852 return self.filelist
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
853
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
854 def printdir(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
855 """Print a table of contents for the zip file."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
856 print "%-46s %19s %12s" % ("File Name", "Modified ", "Size")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
857 for zinfo in self.filelist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
858 date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time[:6]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
859 print "%-46s %s %12d" % (zinfo.filename, date, zinfo.file_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
860
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
861 def testzip(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
862 """Read all the files and check the CRC."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
863 chunk_size = 2 ** 20
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
864 for zinfo in self.filelist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
865 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
866 # Read by chunks, to avoid an OverflowError or a
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
867 # MemoryError with very large embedded files.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
868 f = self.open(zinfo.filename, "r")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
869 while f.read(chunk_size): # Check CRC-32
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
870 pass
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
871 except BadZipfile:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
872 return zinfo.filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
873
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
874 def getinfo(self, name):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
875 """Return the instance of ZipInfo given 'name'."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
876 info = self.NameToInfo.get(name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
877 if info is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
878 raise KeyError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
879 'There is no item named %r in the archive' % name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
880
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
881 return info
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
882
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
883 def setpassword(self, pwd):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
884 """Set default password for encrypted files."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
885 self.pwd = pwd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
886
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
887 def read(self, name, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
888 """Return file bytes (as a string) for name."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
889 return self.open(name, "r", pwd).read()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
890
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
891 def open(self, name, mode="r", pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
892 """Return file-like object for 'name'."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
893 if mode not in ("r", "U", "rU"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
894 raise RuntimeError, 'open() requires mode "r", "U", or "rU"'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
895 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
896 raise RuntimeError, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
897 "Attempt to read ZIP archive that was already closed"
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 # Only open a new file for instances where we were not
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
900 # given a file object in the constructor
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
901 if self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
902 zef_file = self.fp
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
903 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
904 zef_file = open(self.filename, 'rb')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
905
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
906 # Make sure we have an info object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
907 if isinstance(name, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
908 # 'name' is already an info object
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
909 zinfo = name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
910 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
911 # Get info object for name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
912 zinfo = self.getinfo(name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
913
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
914 zef_file.seek(zinfo.header_offset, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
915
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
916 # Skip the file header:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
917 fheader = zef_file.read(sizeFileHeader)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
918 if fheader[0:4] != stringFileHeader:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
919 raise BadZipfile, "Bad magic number for file header"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
920
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
921 fheader = struct.unpack(structFileHeader, fheader)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
922 fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
923 if fheader[_FH_EXTRA_FIELD_LENGTH]:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
924 zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
925
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
926 if fname != zinfo.orig_filename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
927 raise BadZipfile, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
928 'File name in directory "%s" and header "%s" differ.' % (
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
929 zinfo.orig_filename, fname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
930
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
931 # check for encrypted flag & handle password
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
932 is_encrypted = zinfo.flag_bits & 0x1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
933 zd = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
934 if is_encrypted:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
935 if not pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
936 pwd = self.pwd
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
937 if not pwd:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
938 raise RuntimeError, "File %s is encrypted, " \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
939 "password required for extraction" % name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
940
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
941 zd = _ZipDecrypter(pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
942 # 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
943 # used to strengthen the algorithm. The first 11 bytes are
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
944 # completely random, while the 12th contains the MSB of the CRC,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
945 # 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
946 # and is used to check the correctness of the password.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
947 bytes = zef_file.read(12)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
948 h = map(zd, bytes[0:12])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
949 if zinfo.flag_bits & 0x8:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
950 # compare against the file type from extended local headers
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
951 check_byte = (zinfo._raw_time >> 8) & 0xff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
952 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
953 # compare against the CRC otherwise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
954 check_byte = (zinfo.CRC >> 24) & 0xff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
955 if ord(h[11]) != check_byte:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
956 raise RuntimeError("Bad password for file", name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
957
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
958 return ZipExtFile(zef_file, mode, zinfo, zd)
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 def extract(self, member, path=None, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
961 """Extract a member from the archive to the current working directory,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
962 using its full name. Its file information is extracted as accurately
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
963 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
964 specify a different directory using `path'.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
965 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
966 if not isinstance(member, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
967 member = self.getinfo(member)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
968
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
969 if path is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
970 path = os.getcwd()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
971
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
972 return self._extract_member(member, path, pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
973
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
974 def extractall(self, path=None, members=None, pwd=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
975 """Extract all members from the archive to the current working
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
976 directory. `path' specifies a different directory to extract to.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
977 `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
978 by namelist().
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
979 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
980 if members is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
981 members = self.namelist()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
982
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
983 for zipinfo in members:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
984 self.extract(zipinfo, path, pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
985
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
986 def _extract_member(self, member, targetpath, pwd):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
987 """Extract the ZipInfo object 'member' to a physical
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
988 file on the path targetpath.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
989 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
990 # build the destination pathname, replacing
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
991 # forward slashes to platform specific separators.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
992 # Strip trailing path separator, unless it represents the root.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
993 if (targetpath[-1:] in (os.path.sep, os.path.altsep)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
994 and len(os.path.splitdrive(targetpath)[1]) > 1):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
995 targetpath = targetpath[:-1]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
996
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
997 # don't include leading "/" from file name if present
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
998 if member.filename[0] == '/':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
999 targetpath = os.path.join(targetpath, member.filename[1:])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1000 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1001 targetpath = os.path.join(targetpath, member.filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1002
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1003 targetpath = os.path.normpath(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1004
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1005 # Create all upper directories if necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1006 upperdirs = os.path.dirname(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1007 if upperdirs and not os.path.exists(upperdirs):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1008 os.makedirs(upperdirs)
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 if member.filename[-1] == '/':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1011 if not os.path.isdir(targetpath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1012 os.mkdir(targetpath)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1013 return targetpath
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1014
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1015 source = self.open(member, pwd=pwd)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1016 target = file(targetpath, "wb")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1017 shutil.copyfileobj(source, target)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1018 source.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1019 target.close()
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 return targetpath
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1022
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1023 def _writecheck(self, zinfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1024 """Check for errors before writing a file to the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1025 if zinfo.filename in self.NameToInfo:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1026 if self.debug: # Warning for duplicate names
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1027 print "Duplicate name:", zinfo.filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1028 if self.mode not in ("w", "a"):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1029 raise RuntimeError, 'write() requires mode "w" or "a"'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1030 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1031 raise RuntimeError, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1032 "Attempt to write ZIP archive that was already closed"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1033 if zinfo.compress_type == ZIP_DEFLATED and not zlib:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1034 raise RuntimeError, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1035 "Compression requires the (missing) zlib module"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1036 if zinfo.compress_type == ZIP_BZIP2 and not bz2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1037 raise RuntimeError, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1038 "Compression requires the (missing) bz2 module"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1039 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
1040 raise RuntimeError, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1041 "That compression method is not supported"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1042 if zinfo.file_size > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1043 if not self._allowZip64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1044 raise LargeZipFile("Filesize would require ZIP64 extensions")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1045 if zinfo.header_offset > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1046 if not self._allowZip64:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1047 raise LargeZipFile("Zipfile size would require ZIP64 extensions")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1048
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1049 def write(self, filename, arcname=None, compress_type=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1050 """Put the bytes from filename into the archive under the name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1051 arcname."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1052 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1053 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1054 "Attempt to write to ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1055
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1056 st = os.stat(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1057 isdir = stat.S_ISDIR(st.st_mode)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1058 mtime = time.localtime(st.st_mtime)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1059 date_time = mtime[0:6]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1060 # Create ZipInfo instance to store file information
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1061 if arcname is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1062 arcname = filename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1063 arcname = os.path.normpath(os.path.splitdrive(arcname)[1])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1064 while arcname[0] in (os.sep, os.altsep):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1065 arcname = arcname[1:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1066 if isdir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1067 arcname += '/'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1068 zinfo = ZipInfo(arcname, date_time)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1069 zinfo.external_attr = (st[0] & 0xFFFF) << 16L # Unix attributes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1070 if compress_type is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1071 zinfo.compress_type = self.compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1072 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1073 zinfo.compress_type = compress_type
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1074
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1075 zinfo.file_size = st.st_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1076 zinfo.flag_bits = 0x00
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1077 zinfo.header_offset = self.fp.tell() # Start of header bytes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1078
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1079 self._writecheck(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1080 self._didModify = True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1081
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1082 if isdir:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1083 zinfo.file_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1084 zinfo.compress_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1085 zinfo.CRC = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1086 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1087 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1088 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1089 return
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1090
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1091 with open(filename, "rb") as fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1092 # Must overwrite CRC and sizes with correct data later
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1093 zinfo.CRC = CRC = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1094 zinfo.compress_size = compress_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1095 zinfo.file_size = file_size = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1096 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1097 if zinfo.compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1098 cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1099 zlib.DEFLATED, -15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1100 elif zinfo.compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1101 cmpr = bz2.BZ2Compressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1102 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1103 cmpr = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1104 while 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1105 buf = fp.read(1024 * 8)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1106 if not buf:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1107 break
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1108 file_size = file_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1109 CRC = crc32(buf, CRC) & 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1110 if cmpr:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1111 buf = cmpr.compress(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1112 compress_size = compress_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1113 self.fp.write(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1114 if cmpr:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1115 buf = cmpr.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1116 compress_size = compress_size + len(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1117 self.fp.write(buf)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1118 zinfo.compress_size = compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1119 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1120 zinfo.compress_size = file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1121 zinfo.CRC = CRC
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1122 zinfo.file_size = file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1123 # Seek backwards and write CRC and file sizes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1124 position = self.fp.tell() # Preserve current position in file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1125 self.fp.seek(zinfo.header_offset + 14, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1126 self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1127 zinfo.file_size))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1128 self.fp.seek(position, 0)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1129 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1130 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1131
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1132 def writestr(self, zinfo_or_arcname, bytes, compress_type=None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1133 """Write a file into the archive. The contents is the string
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1134 'bytes'. 'zinfo_or_arcname' is either a ZipInfo instance or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1135 the name of the file in the archive."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1136 if not isinstance(zinfo_or_arcname, ZipInfo):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1137 zinfo = ZipInfo(filename=zinfo_or_arcname,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1138 date_time=time.localtime(time.time())[:6])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1139
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1140 zinfo.compress_type = self.compression
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1141 zinfo.external_attr = 0600 << 16
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1142 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1143 zinfo = zinfo_or_arcname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1144
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1145 if not self.fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1146 raise RuntimeError(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1147 "Attempt to write to ZIP archive that was already closed")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1148
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1149 if compress_type is not None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1150 zinfo.compress_type = compress_type
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1151
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1152 zinfo.file_size = len(bytes) # Uncompressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1153 zinfo.header_offset = self.fp.tell() # Start of header bytes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1154 self._writecheck(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1155 self._didModify = True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1156 zinfo.CRC = crc32(bytes) & 0xffffffff # CRC-32 checksum
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1157 if zinfo.compress_type == ZIP_DEFLATED:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1158 co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1159 zlib.DEFLATED, -15)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1160 bytes = co.compress(bytes) + co.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1161 zinfo.compress_size = len(bytes) # Compressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1162 elif zinfo.compress_type == ZIP_BZIP2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1163 co = bz2.BZ2Compressor()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1164 bytes = co.compress(bytes) + co.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1165 zinfo.compress_size = len(bytes) # Compressed size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1166 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1167 zinfo.compress_size = zinfo.file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1168 zinfo.header_offset = self.fp.tell() # Start of header bytes
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1169 self.fp.write(zinfo.FileHeader())
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1170 self.fp.write(bytes)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1171 self.fp.flush()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1172 if zinfo.flag_bits & 0x08:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1173 # Write CRC and file sizes after the file data
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1174 self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1175 zinfo.file_size))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1176 self.filelist.append(zinfo)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1177 self.NameToInfo[zinfo.filename] = zinfo
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1178
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1179 def __del__(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1180 """Call the "close()" method in case the user forgot."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1181 self.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1182
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1183 def close(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1184 """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
1185 records."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1186 if self.fp is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1187 return
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1188
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1189 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
1190 count = 0
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1191 pos1 = self.fp.tell()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1192 for zinfo in self.filelist: # write central directory
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1193 count = count + 1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1194 dt = zinfo.date_time
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1195 dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1196 dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1197 extra = []
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1198 if zinfo.file_size > ZIP64_LIMIT \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1199 or zinfo.compress_size > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1200 extra.append(zinfo.file_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1201 extra.append(zinfo.compress_size)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1202 file_size = 0xffffffff
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1203 compress_size = 0xffffffff
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 file_size = zinfo.file_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1206 compress_size = zinfo.compress_size
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1207
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1208 if zinfo.header_offset > ZIP64_LIMIT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1209 extra.append(zinfo.header_offset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1210 header_offset = 0xffffffffL
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1211 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1212 header_offset = zinfo.header_offset
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1213
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1214 extra_data = zinfo.extra
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1215 if extra:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1216 # Append a ZIP64 field to the extra's
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1217 extra_data = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1218 '<HH' + 'Q'*len(extra),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1219 1, 8*len(extra), *extra) + extra_data
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 extract_version = max(45, zinfo.extract_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1222 create_version = max(45, zinfo.create_version)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1223 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1224 extract_version = zinfo.extract_version
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1225 create_version = zinfo.create_version
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 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1228 filename, flag_bits = zinfo._encodeFilenameFlags()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1229 centdir = struct.pack(structCentralDir,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1230 stringCentralDir, create_version,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1231 zinfo.create_system, extract_version, zinfo.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1232 flag_bits, zinfo.compress_type, dostime, dosdate,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1233 zinfo.CRC, compress_size, file_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1234 len(filename), len(extra_data), len(zinfo.comment),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1235 0, zinfo.internal_attr, zinfo.external_attr,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1236 header_offset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1237 except DeprecationWarning:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1238 print >>sys.stderr, (structCentralDir,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1239 stringCentralDir, create_version,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1240 zinfo.create_system, extract_version, zinfo.reserved,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1241 zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1242 zinfo.CRC, compress_size, file_size,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1243 len(zinfo.filename), len(extra_data), len(zinfo.comment),
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1244 0, zinfo.internal_attr, zinfo.external_attr,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1245 header_offset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1246 raise
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1247 self.fp.write(centdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1248 self.fp.write(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1249 self.fp.write(extra_data)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1250 self.fp.write(zinfo.comment)
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 pos2 = self.fp.tell()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1253 # Write end-of-zip-archive record
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1254 centDirCount = count
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1255 centDirSize = pos2 - pos1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1256 centDirOffset = pos1
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1257 if (centDirCount >= ZIP_FILECOUNT_LIMIT or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1258 centDirOffset > ZIP64_LIMIT or
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1259 centDirSize > ZIP64_LIMIT):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1260 # Need to write the ZIP64 end-of-archive records
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1261 zip64endrec = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1262 structEndArchive64, stringEndArchive64,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1263 44, 45, 45, 0, 0, centDirCount, centDirCount,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1264 centDirSize, centDirOffset)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1265 self.fp.write(zip64endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1266
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1267 zip64locrec = struct.pack(
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1268 structEndArchive64Locator,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1269 stringEndArchive64Locator, 0, pos2, 1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1270 self.fp.write(zip64locrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1271 centDirCount = min(centDirCount, 0xFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1272 centDirSize = min(centDirSize, 0xFFFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1273 centDirOffset = min(centDirOffset, 0xFFFFFFFF)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1274
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1275 # check for valid comment length
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1276 if len(self.comment) >= ZIP_MAX_COMMENT:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1277 if self.debug > 0:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1278 msg = 'Archive comment is too long; truncating to %d bytes' \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1279 % ZIP_MAX_COMMENT
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1280 self.comment = self.comment[:ZIP_MAX_COMMENT]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1281
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1282 endrec = struct.pack(structEndArchive, stringEndArchive,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1283 0, 0, centDirCount, centDirCount,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1284 centDirSize, centDirOffset, len(self.comment))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1285 self.fp.write(endrec)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1286 self.fp.write(self.comment)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1287 self.fp.flush()
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 if not self._filePassed:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1290 self.fp.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1291 self.fp = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1292
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1293
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1294 class PyZipFile(ZipFile):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1295 """Class to create ZIP archives with Python library files and packages."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1296
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1297 def writepy(self, pathname, basename = ""):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1298 """Add all files from "pathname" to the ZIP archive.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1299
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1300 If pathname is a package directory, search the directory and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1301 all package subdirectories recursively for all *.py and enter
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1302 the modules into the archive. If pathname is a plain
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1303 directory, listdir *.py and enter all modules. Else, pathname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1304 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
1305 archive. Added modules are always module.pyo or module.pyc.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1306 This method will compile the module.py into module.pyc if
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1307 necessary.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1308 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1309 dir, name = os.path.split(pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1310 if os.path.isdir(pathname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1311 initname = os.path.join(pathname, "__init__.py")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1312 if os.path.isfile(initname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1313 # This is a package directory, add it
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1314 if basename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1315 basename = "%s/%s" % (basename, name)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1316 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1317 basename = name
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1318 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1319 print "Adding package in", pathname, "as", basename
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1320 fname, arcname = self._get_codename(initname[0:-3], basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1321 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1322 print "Adding", arcname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1323 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1324 dirlist = os.listdir(pathname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1325 dirlist.remove("__init__.py")
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1326 # Add all *.py files and package subdirectories
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1327 for filename in dirlist:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1328 path = os.path.join(pathname, filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1329 root, ext = os.path.splitext(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1330 if os.path.isdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1331 if os.path.isfile(os.path.join(path, "__init__.py")):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1332 # This is a package directory, add it
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1333 self.writepy(path, basename) # Recursive call
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1334 elif ext == ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1335 fname, arcname = self._get_codename(path[0:-3],
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1336 basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1337 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1338 print "Adding", arcname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1339 self.write(fname, arcname)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1340 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1341 # 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
1342 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1343 print "Adding files from directory", pathname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1344 for filename in os.listdir(pathname):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1345 path = os.path.join(pathname, filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1346 root, ext = os.path.splitext(filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1347 if ext == ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1348 fname, arcname = self._get_codename(path[0:-3],
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1349 basename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1350 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1351 print "Adding", arcname
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1352 self.write(fname, arcname)
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 if pathname[-3:] != ".py":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1355 raise RuntimeError, \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1356 'Files added with writepy() must end with ".py"'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1357 fname, arcname = self._get_codename(pathname[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 file", 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
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1362 def _get_codename(self, pathname, basename):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1363 """Return (filename, archivename) for the path.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1364
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1365 Given a module name path, return the correct file path and
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1366 archive name, compiling if necessary. For example, given
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1367 /python/lib/string, return (/python/lib/string.pyc, string).
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1368 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1369 file_py = pathname + ".py"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1370 file_pyc = pathname + ".pyc"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1371 file_pyo = pathname + ".pyo"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1372 if os.path.isfile(file_pyo) and \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1373 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
1374 fname = file_pyo # Use .pyo file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1375 elif not os.path.isfile(file_pyc) or \
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1376 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
1377 import py_compile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1378 if self.debug:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1379 print "Compiling", file_py
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1380 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1381 py_compile.compile(file_py, file_pyc, None, True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1382 except py_compile.PyCompileError,err:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1383 print err.msg
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1384 fname = file_pyc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1385 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1386 fname = file_pyc
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1387 archivename = os.path.split(fname)[1]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1388 if basename:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1389 archivename = "%s/%s" % (basename, archivename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1390 return (fname, archivename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1391
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1392
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1393 def main(args = None):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1394 import textwrap
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1395 USAGE=textwrap.dedent("""\
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1396 Usage:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1397 zipfile.py -l zipfile.zip # Show listing of a zipfile
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1398 zipfile.py -t zipfile.zip # Test if a zipfile is valid
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1399 zipfile.py -e zipfile.zip target # Extract zipfile into target dir
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1400 zipfile.py -c zipfile.zip src ... # Create zipfile from sources
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 if args is None:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1403 args = sys.argv[1:]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1404
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1405 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
1406 print USAGE
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1407 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1408
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1409 if args[0] == '-l':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1410 if len(args) != 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1411 print USAGE
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1412 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1413 zf = ZipFile(args[1], 'r')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1414 zf.printdir()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1415 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1416
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1417 elif args[0] == '-t':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1418 if len(args) != 2:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1419 print USAGE
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1420 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1421 zf = ZipFile(args[1], 'r')
29
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
1422 badfile = zf.testzip()
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
1423 if badfile:
a8cc383b787c Clean up zipfiles and diff them to stock ones
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
1424 print("The following enclosed file is corrupted: {!r}".format(badfile))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1425 print "Done testing"
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1426
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1427 elif args[0] == '-e':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1428 if len(args) != 3:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1429 print USAGE
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1430 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1431
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1432 zf = ZipFile(args[1], 'r')
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1433 out = args[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1434 for path in zf.namelist():
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1435 if path.startswith('./'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1436 tgt = os.path.join(out, path[2:])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1437 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1438 tgt = os.path.join(out, path)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1439
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1440 tgtdir = os.path.dirname(tgt)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1441 if not os.path.exists(tgtdir):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1442 os.makedirs(tgtdir)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1443 with open(tgt, 'wb') as fp:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1444 fp.write(zf.read(path))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1445 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1446
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1447 elif args[0] == '-c':
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1448 if len(args) < 3:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1449 print USAGE
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1450 sys.exit(1)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1451
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1452 def addToZip(zf, path, zippath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1453 if os.path.isfile(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1454 zf.write(path, zippath, ZIP_DEFLATED)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1455 elif os.path.isdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1456 for nm in os.listdir(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1457 addToZip(zf,
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1458 os.path.join(path, nm), os.path.join(zippath, nm))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1459 # else: ignore
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1460
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1461 zf = ZipFile(args[1], 'w', allowZip64=True)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1462 for src in args[2:]:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1463 addToZip(zf, src, os.path.basename(src))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1464
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1465 zf.close()
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1466
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1467 if __name__ == "__main__":
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
1468 main()