annotate zipfile.py @ 9:ed90b375d197

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