StatsDb._getstoredfileid could return None. This was a problem in methods which
[translate_toolkit.git] / misc / zipfileext.py
blob736e1d65a059dd8f1f6019094318317529855338
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2004, 2005 Zuza Software Foundation
5 #
6 # This file is part of translate.
8 # translate is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 """extensions to zipfile standard module that will hopefully get included in future..."""
24 from zipfile import ZipFile, struct, structCentralDir, stringCentralDir, structEndArchive, stringEndArchive
26 class ZipFileExt(ZipFile, object):
27 """a ZipFile that can handle replacing objects"""
28 def delete(self, name):
29 """Delete the file from the archive. If it appears multiple
30 times only the first instance will be deleted."""
31 for i in range (0, len(self.filelist)):
32 if self.filelist[i].filename == name:
33 if self.debug:
34 print "Removing", name
35 deleted_offset = self.filelist[i].header_offset
36 deleted_size = (self.filelist[i].file_offset - self.filelist[i].header_offset) + self.filelist[i].compress_size
37 zinfo_size = struct.calcsize(structCentralDir) + len(self.filelist[i].filename) + len(self.filelist[i].extra)
38 # Remove the file's data from the archive.
39 current_offset = self.fp.tell()
40 # go to the end of the archive to calculate the total archive_size
41 self.fp.seek(0, 2)
42 archive_size = self.fp.tell()
43 self.fp.seek(deleted_offset + deleted_size)
44 buf = self.fp.read()
45 self.fp.seek(deleted_offset)
46 self.fp.write(buf)
47 self.fp.truncate(archive_size - deleted_size - zinfo_size)
48 # go to the end of the archive to calculate the total archive_size
49 self.fp.seek(0, 2)
50 if self.debug >= 2:
51 if self.fp.tell() != archive_size - deleted_size - zinfo_size:
52 print "truncation failed: %r != %r" % (self.fp.tell(), archive_size - deleted_size - zinfo_size)
53 if current_offset > deleted_offset + deleted_size:
54 current_offset -= deleted_size
55 elif current_offset > deleted_offset:
56 current_offset = deleted_offset
57 self.fp.seek(current_offset, 0)
58 # Remove file from central directory.
59 del self.filelist[i]
60 # Adjust the remaining offsets in the central directory.
61 for j in range (i, len(self.filelist)):
62 if self.filelist[j].header_offset > deleted_offset:
63 self.filelist[j].header_offset -= deleted_size
64 if self.filelist[j].file_offset > deleted_offset:
65 self.filelist[j].file_offset -= deleted_size
66 del self.NameToInfo[name]
67 return
68 if self.debug:
69 print name, "not in archive"
71 def close(self):
72 """Close the file, and for mode "w" and "a" write the ending
73 records."""
74 if self.fp is None:
75 return
76 self.writeendrec()
77 if not self._filePassed:
78 self.fp.close()
79 self.fp = None
81 def writeendrec(self):
82 """Write the ending records (without neccessarily closing the file)"""
83 if self.mode in ("w", "a"): # write ending records
84 count = 0
85 current_offset = self.fp.tell()
86 pos1 = self.fp.tell()
87 for zinfo in self.filelist: # write central directory
88 count = count + 1
89 dt = zinfo.date_time
90 dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
91 dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
92 centdir = struct.pack(structCentralDir,
93 stringCentralDir, zinfo.create_version,
94 zinfo.create_system, zinfo.extract_version, zinfo.reserved,
95 zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
96 zinfo.CRC, zinfo.compress_size, zinfo.file_size,
97 len(zinfo.filename), len(zinfo.extra), len(zinfo.comment),
98 0, zinfo.internal_attr, zinfo.external_attr,
99 zinfo.header_offset)
100 self.fp.write(centdir)
101 self.fp.write(zinfo.filename)
102 self.fp.write(zinfo.extra)
103 self.fp.write(zinfo.comment)
104 pos2 = self.fp.tell()
105 # Write end-of-zip-archive record
106 endrec = struct.pack(structEndArchive, stringEndArchive,
107 0, 0, count, count, pos2 - pos1, pos1, 0)
108 self.fp.write(endrec)
109 self.fp.seek(pos1)