[Patches] Patch for zipfile.py

Gottfried Ganßauge gotti@gmx.de
Sun, 25 Jun 2000 22:52:30 +0200


This is a multi-part message in MIME format.

------=_NextPart_000_0005_01BFDEF8.0AC1C530
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 8bit

Currently I am writing the build script for my company's software system
and used that as an opportunity to learn python.
One of the tasks performed during our builds is the extraction of some
precompiled objects from a Zip-File compressed using pkzip-2.5.
As we don't have that installed on all of our machines I wanted to write
a small python class which would extract all of the files from that Zip
archive.
A quick search on the internet brought zipfile.py to my knowledge,
a few minutes later the class ZipFile was written.
During my tests I permanently got decompression errors on Zip archives
known to be good.
When I traced back to the error i found out about a small missinterpretation
of the zip format within unzip.py: The central directory obviously need not
contain
an exact copy of the local file header: The value "extra field length"
was always 0 in the central directory whereas it was different in the
local file header.
After correcting that error I went on with debugging and almost immediately
found out, that crc32() is not an attribute of binascii in Python 1.5.2.
So I expanded the trial import of zlib:
If module zlib is available, we take the crc32() routine from there,
otherwise we check binascii and if that fails (it does under 1.5.2), we
define a dummy crc32() which just raises NotImplementedError.

The attached patch is a context diff against zipfile.py Version 1.2 from the
CVS repository

Here comes my test module:
-------------8>< snip 8><--------------------------8>< snip
8><----------------
#
# Utility Modules
#
import os
import string
import sys
import time
import zipfile

#
# Encapsulation of PKZip
class Unzip:
    def __init__(self):
        "Constructor"

    #
    # extract an archive
    #
    # @param archive
    # archive to extract
    #
    # @param dir
    # destination directory
    #
    def extract(self, archive, dir):
        if not os.access (archive, os.R_OK):
            raise "Cannot access %s" % (archive)

        if not zipfile.is_zipfile(archive):
            raise "%s: not a zipfile" % (archive)

        z = zipfile.ZipFile (archive)
        for name in z.namelist():
            outfile = os.path.join (dir, name)
            makedir (os.path.dirname (outfile))
            f    = open (outfile, "wb")
            f.write (z.read (name))
            f.close ()
            date = z.getinfo (name).date_time # year, month, day, hour, min,
sec
            try:
                os.utime (
                    outfile,
                    (self._makedate (date),
                     self._makedate (date)))
            except:
                pass    # ignore errors


    #
    # Create a time value from a tuple returned by the ZIP-Functions
    #
    # @param zipdate
    # tuple: (year, month, day, hour, min, sec)
    def _makedate(self, zipdate):
        "Create a time value from a tuple returned by the ZIP-Functions"
        year, month, day, hour, min, sec = zipdate
        return time.mktime ((year, month, day, hour, min, sec, 0, 0, -1))

#
############################################################################
########
#
# Try to create a directory
# fail only if it doesn't exist afterwards
#
# @param path
# Directory to make
#
def makedir(path):
    try:
        os.makedirs (path)
    except:
        if not os.path.isdir (path):
            raise

Unzip().extract ("i:\\_BuildTools\\x.zip", "i:\\_BuildTools\\fred")

-------------8>< snip 8><--------------------------8>< snip
8><----------------

I confirm that, to the best of my knowledge and belief, this
contribution is free of any claims of third parties under
copyright, patent or other rights or interests ("claims").  To
the extent that I have any such claims, I hereby grant to CNRI a
nonexclusive, irrevocable, royalty-free, worldwide license to
reproduce, distribute, perform and/or display publicly, prepare
derivative versions, and otherwise use this contribution as part
of the Python software and its related documentation, or any
derivative versions thereof, at no cost to CNRI or its licensed
users, and to authorize others to do so.

I acknowledge that CNRI may, at its sole discretion, decide
whether or not to incorporate this contribution in the Python
software and its related documentation.  I further grant CNRI
permission to use my name and other identifying information
provided to CNRI by me for use in connection with the Python
software and its related documentation.

mit freundlichen Grüßen,

Gottfried Ganßauge
Gorkistraße 120
13509 Berlin
ganssauge@gmx.de

------=_NextPart_000_0005_01BFDEF8.0AC1C530
Content-Type: text/x-vcard;
	name="=?iso-8859-1?Q?Gottfried_Gan=DFauge.vcf?="
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="=?iso-8859-1?Q?Gottfried_Gan=DFauge.vcf?="

BEGIN:VCARD
VERSION:2.1
N:Gan=DFauge;Gottfried
FN:Gottfried Gan=DFauge
ORG:;Softwareentwicklung
TEL;HOME;FAX:+49-30-434 90 038
ADR;WORK:;;;Berlin;Berlin;;Deutschland
LABEL;WORK;ENCODING=3DQUOTED-PRINTABLE:Berlin, =
Berlin=3D0D=3D0ADeutschland
ADR;HOME:;;Gorkistra=DFe 120;Berlin;Berlin;13509;Deutschland
LABEL;HOME;ENCODING=3DQUOTED-PRINTABLE:Gorkistra=3DDFe =
120=3D0D=3D0ABerlin, Berlin 13509=3D0D=3D0ADeutschland
X-WAB-GENDER:2
BDAY:19620226
EMAIL;PREF;INTERNET:ganssauge@gmx.de
REV:20000625T205230Z
END:VCARD

------=_NextPart_000_0005_01BFDEF8.0AC1C530
Content-Type: application/octet-stream;
	name="zipfile.py.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="zipfile.py.patch"

*** org/zipfile.py	Sun Jun 25 20:22:24 2000=0A=
--- ./zipfile.py	Sun Jun 25 20:46:36 2000=0A=
***************=0A=
*** 6,14 ****=0A=
  import binascii, py_compile=0A=
  =0A=
  try:=0A=
!     import zlib	# We may need its compression method=0A=
  except:=0A=
!     zlib =3D None=0A=
  =0A=
  class _BadZipfile(Exception):=0A=
      pass=0A=
--- 6,20 ----=0A=
  import binascii, py_compile=0A=
  =0A=
  try:=0A=
!     import zlib         # We may need its compression method=0A=
!     crc32 =3D zlib.crc32  # O.K., then let's also take crc32 from =
there (and that works under 1.5.2!)=0A=
  except:=0A=
!     zlib  =3D None=0A=
!     if hasattr(binascii, "crc32"):=0A=
!         crc32 =3D binascii.crc32  # no zlib, if we need crc32 we might =
get it here? (on 1.6!)=0A=
!     else:=0A=
!         def crc32 (bytes):      # O.k. We give up, if someone needs =
crc32, he must implement it himself=0A=
!             raise NotImplementedError=0A=
  =0A=
  class _BadZipfile(Exception):=0A=
      pass=0A=
***************=0A=
*** 181,187 ****=0A=
              if fname !=3D data.filename:=0A=
                  raise RuntimeError, \=0A=
   'File name in Central Directory "%s" and File Header "%s" differ.' % (=0A=
!                              data.filename, fname)=0A=
  =0A=
      def namelist(self):=0A=
          "Return a list of file names in the archive"=0A=
--- 187,196 ----=0A=
              if fname !=3D data.filename:=0A=
                  raise RuntimeError, \=0A=
   'File name in Central Directory "%s" and File Header "%s" differ.' % (=0A=
!                              data.filename, fname)=0A=
! =0A=
!             # The data in the central directory doesn't say it all ... =
           =0A=
!             data.file_offset =3D data.header_offset + 30 + fheader[10] =
+ fheader[11]=0A=
  =0A=
      def namelist(self):=0A=
          "Return a list of file names in the archive"=0A=
***************=0A=
*** 232,238 ****=0A=
                  raise RuntimeError, \=0A=
                  "De-compression requires the (missing) zlib module"=0A=
              # zlib compress/decompress code by Jeremy Hylton of CNRI=0A=
!             dc =3D zlib.decompressobj(-15)=0A=
              bytes =3D dc.decompress(bytes)=0A=
              # need to feed in unused pad byte so that zlib won't choke=0A=
              ex =3D dc.decompress('Z') + dc.flush()=0A=
--- 241,247 ----=0A=
                  raise RuntimeError, \=0A=
                  "De-compression requires the (missing) zlib module"=0A=
              # zlib compress/decompress code by Jeremy Hylton of CNRI=0A=
!             dc    =3D zlib.decompressobj(-15)=0A=
              bytes =3D dc.decompress(bytes)=0A=
              # need to feed in unused pad byte so that zlib won't choke=0A=
              ex =3D dc.decompress('Z') + dc.flush()=0A=
***************=0A=
*** 242,248 ****=0A=
              raise BadZipfile, \=0A=
              "Unsupported compression method %d for file %s" % \=0A=
              (zinfo.compress_type, name)=0A=
!         crc =3D binascii.crc32(bytes)=0A=
          if crc !=3D zinfo.CRC:=0A=
              raise BadZipfile, "Bad CRC-32 for file %s" % name=0A=
          return bytes=0A=
--- 251,257 ----=0A=
              raise BadZipfile, \=0A=
              "Unsupported compression method %d for file %s" % \=0A=
              (zinfo.compress_type, name)=0A=
!         crc =3D crc32(bytes)=0A=
          if crc !=3D zinfo.CRC:=0A=
              raise BadZipfile, "Bad CRC-32 for file %s" % name=0A=
          return bytes=0A=
***************=0A=
*** 298,304 ****=0A=
              if not buf:=0A=
                  break=0A=
              file_size =3D file_size + len(buf)=0A=
!             CRC =3D binascii.crc32(buf, CRC)=0A=
              if cmpr:=0A=
                  buf =3D cmpr.compress(buf)=0A=
                  compress_size =3D compress_size + len(buf)=0A=
--- 307,313 ----=0A=
              if not buf:=0A=
                  break=0A=
              file_size =3D file_size + len(buf)=0A=
!             CRC =3D crc32(buf, CRC)=0A=
              if cmpr:=0A=
                  buf =3D cmpr.compress(buf)=0A=
                  compress_size =3D compress_size + len(buf)=0A=
***************=0A=
*** 323,329 ****=0A=
          'Write a file into the archive.  The contents is the string =
"bytes"'=0A=
          self._writecheck(zinfo)=0A=
          zinfo.file_size =3D len(bytes)		# Uncompressed size=0A=
!         zinfo.CRC =3D binascii.crc32(bytes)	# CRC-32 checksum=0A=
          if zinfo.compress_type =3D=3D ZIP_DEFLATED:=0A=
              co =3D zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,=0A=
                   zlib.DEFLATED, -15)=0A=
--- 332,338 ----=0A=
          'Write a file into the archive.  The contents is the string =
"bytes"'=0A=
          self._writecheck(zinfo)=0A=
          zinfo.file_size =3D len(bytes)		# Uncompressed size=0A=
!         zinfo.CRC =3D crc32(bytes)	# CRC-32 checksum=0A=
          if zinfo.compress_type =3D=3D ZIP_DEFLATED:=0A=
              co =3D zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,=0A=
                   zlib.DEFLATED, -15)=0A=

------=_NextPart_000_0005_01BFDEF8.0AC1C530--