[Python-modules-commits] [python-rarfile] 01/03: Imported Upstream version 2.8

Hugo Lefeuvre hle at moszumanska.debian.org
Sat Jun 18 22:31:01 UTC 2016


This is an automated email from the git hooks/post-receive script.

hle pushed a commit to branch master
in repository python-rarfile.

commit 30bec760e39f8492fcc7438cb82aab00cbb67cc9
Author: Hugo Lefeuvre <hle at debian.org>
Date:   Sat Jun 18 21:43:50 2016 +0200

    Imported Upstream version 2.8
---
 LICENSE       |   2 +-
 Makefile      |   7 +-
 PKG-INFO      |  56 +++++++++++++
 README.rst    |  24 ++++--
 doc/conf.py   |   2 +-
 doc/faq.rst   |  18 +++-
 doc/news.rst  |  34 ++++++++
 dumprar.py    |  15 +++-
 rarfile.py    | 265 +++++++++++++++++++++++++++++++---------------------------
 test/Makefile |   3 +-
 test/test1.sh |   2 +-
 test/test2.sh |   2 +-
 12 files changed, 283 insertions(+), 147 deletions(-)

diff --git a/LICENSE b/LICENSE
index 8b7826f..cd53af0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
 
-Copyright (c) 2005-2013 Marko Kreen <markokr at gmail.com>
+Copyright (c) 2005-2016 Marko Kreen <markokr at gmail.com>
 
 Permission to use, copy, modify, and/or distribute this software for any
 purpose with or without fee is hereby granted, provided that the above
diff --git a/Makefile b/Makefile
index 03df499..45e3c2b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,6 @@
 
 prefix = /usr/local
 
-web = mkz at shell.berlios.de:/home/groups/rarfile/htdocs
-
 all:
 	python setup.py build
 
@@ -26,5 +24,8 @@ lint:
 	pylint -E rarfile.py
 
 rbuild:
-	curl -X POST http://readthedocs.org/build/6715
+	curl -X POST https://readthedocs.org/build/6715
+
+upload:
+	python setup.py sdist upload
 
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..282b56d
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,56 @@
+Metadata-Version: 1.1
+Name: rarfile
+Version: 2.8
+Summary: RAR archive reader for Python
+Home-page: https://github.com/markokr/rarfile
+Author: Marko Kreen
+Author-email: markokr at gmail.com
+License: ISC
+Description: rarfile - RAR archive reader for Python
+        =======================================
+        
+        This is Python module for RAR_ archive reading.  The interface
+        is made as zipfile_ like as possible.  Licensed under ISC_
+        license.
+        
+        Features:
+        
+        - Supports both RAR2 and RAR3 archives (WinRAR 2.x .. WinRAR 4.x).
+        - Supports multi volume archives.
+        - Supports Unicode filenames.
+        - Supports password-protected archives.
+        - Supports archive and file comments.
+        - Archive parsing and non-compressed files are handled in pure Python code.
+        - Compressed files are extracted by executing external tool: either ``unrar``
+          from RARLAB_ or ``bsdtar`` from libarchive_.
+        - Works with both Python 2.7 and 3.x.
+        
+        Notes:
+        
+        - Does not support the RAR5 format introduced in WinRAR 5.0.
+        - ``bsdtar`` does not support all RAR3 features.
+        
+        Links:
+        
+        - `Documentation`_
+        - `Downloads`_
+        - `Git`_ repo
+        
+        .. _RAR: https://en.wikipedia.org/wiki/RAR_%28file_format%29
+        .. _zipfile: https://docs.python.org/2/library/zipfile.html
+        .. _ISC: https://en.wikipedia.org/wiki/ISC_license
+        .. _Git: https://github.com/markokr/rarfile
+        .. _Downloads: https://pypi.python.org/pypi/rarfile
+        .. _Documentation: https://rarfile.readthedocs.io/
+        .. _libarchive: https://github.com/libarchive/libarchive
+        .. _RARLAB: http://www.rarlab.com/
+Keywords: rar,unrar,archive
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: ISC License (ISCL)
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: System :: Archiving :: Compression
diff --git a/README.rst b/README.rst
index 6b511e7..596ca91 100644
--- a/README.rst
+++ b/README.rst
@@ -6,20 +6,22 @@ This is Python module for RAR_ archive reading.  The interface
 is made as zipfile_ like as possible.  Licensed under ISC_
 license.
 
-.. _RAR: http://en.wikipedia.org/wiki/RAR
-.. _zipfile: http://docs.python.org/library/zipfile.html
-.. _ISC: http://en.wikipedia.org/wiki/ISC_license
-
 Features:
 
-- Supports both RAR 2.x and 3.x archives.
+- Supports both RAR2 and RAR3 archives (WinRAR 2.x .. WinRAR 4.x).
 - Supports multi volume archives.
 - Supports Unicode filenames.
 - Supports password-protected archives.
 - Supports archive and file comments.
 - Archive parsing and non-compressed files are handled in pure Python code.
-- For compressed files runs ``unrar`` utility.
-- Works with both Python 2.x and 3.x.
+- Compressed files are extracted by executing external tool: either ``unrar``
+  from RARLAB_ or ``bsdtar`` from libarchive_.
+- Works with both Python 2.7 and 3.x.
+
+Notes:
+
+- Does not support the RAR5 format introduced in WinRAR 5.0.
+- ``bsdtar`` does not support all RAR3 features.
 
 Links:
 
@@ -27,7 +29,11 @@ Links:
 - `Downloads`_
 - `Git`_ repo
 
+.. _RAR: https://en.wikipedia.org/wiki/RAR_%28file_format%29
+.. _zipfile: https://docs.python.org/2/library/zipfile.html
+.. _ISC: https://en.wikipedia.org/wiki/ISC_license
 .. _Git: https://github.com/markokr/rarfile
 .. _Downloads: https://pypi.python.org/pypi/rarfile
-.. _Documentation: https://rarfile.readthedocs.org/
-
+.. _Documentation: https://rarfile.readthedocs.io/
+.. _libarchive: https://github.com/libarchive/libarchive
+.. _RARLAB: http://www.rarlab.com/
diff --git a/doc/conf.py b/doc/conf.py
index 6d14dcd..4709473 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -48,7 +48,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'RarFile'
-copyright = u'2005-2013, Marko Kreen'
+copyright = u'2005-2016, Marko Kreen'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/doc/faq.rst b/doc/faq.rst
index fd3139b..488b42a 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -8,10 +8,22 @@ What are the dependencies?
 --------------------------
 
 It depends on ``unrar`` command-line utility to do the actual decompression.
-
 Note that by default it expect it to be in ``PATH``.  If unrar
 launching fails, you need to fix this.
 
+Alternatively, :mod:`rarfile` can use bsdtar_ from libarchive_ as
+decompression backend, but that is a bit problematic as bsdtar_ does not support
+all RAR features.
+
+.. _bsdtar: https://github.com/libarchive/libarchive/wiki/ManPageBsdtar1
+.. _libarchive: http://www.libarchive.org/
+
+It depends on cryptography_ or PyCrypto_ modules to process
+archives with password-protected headers.
+
+.. _cryptography: https://pypi.python.org/pypi/cryptography
+.. _PyCrypto: https://pypi.python.org/pypi/pycrypto
+
 Does it parse ``unrar`` output to get archive contents?
 -------------------------------------------------------
 
@@ -54,8 +66,8 @@ In the meantime use either Zip_ (better compatibility) or 7z_ (better compressio
 format for your own archives.
 
 .. _RARLAB: http://www.rarlab.com/
-.. _Zip: http://en.wikipedia.org/wiki/ZIP_%28file_format%29
-.. _7z:  http://en.wikipedia.org/wiki/7z
+.. _Zip: https://en.wikipedia.org/wiki/ZIP_%28file_format%29
+.. _7z:  https://en.wikipedia.org/wiki/7z
 
 What is the USE_EXTRACT_HACK?
 -----------------------------
diff --git a/doc/news.rst b/doc/news.rst
index 12d95cd..85d00f1 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -4,6 +4,40 @@ rarfile history
 
 .. py:currentmodule:: rarfile
 
+Version 2.8 (2016-06-07)
+------------------------
+
+* Fix: support solid archives from in-memory file object.
+  Full archive will be written out to temp file.
+  [`#21 <https://github.com/markokr/rarfile/issues/21>`_]
+
+* Fix: ask unrar stop switches scanning,
+  to handle archive names starting with "-".
+  (Alexander Shadchin)
+  [`#12 <https://github.com/markokr/rarfile/pull/12>`_]
+
+* Fix: add missing _parse_error variable to RarFile object.
+  (Gregory Mazzola)
+  [`#20 <https://github.com/markokr/rarfile/pull/20>`_]
+
+* Fix: return proper boolean from :meth:`RarInfo.needs_password`.
+  [`#22 <https://github.com/markokr/rarfile/issues/22>`_]
+
+* Fix: do not insert non-string rarfile into exception string.
+  (Tim Muller)
+  [`#23 <https://github.com/markokr/rarfile/pull/23>`_]
+
+* Fix: make :meth:`RarFile.extract` and :meth:`RarFile.testrar`
+  support in-memory archives.
+
+* Use cryptography_ module as preferred crypto backend.
+  PyCrypto_ will be used as fallback.
+
+* Cleanup: remove compat code for Python 2.4/2.5/2.6.
+
+.. _cryptography: https://pypi.python.org/pypi/cryptography
+.. _PyCrypto: https://pypi.python.org/pypi/pycrypto
+
 Version 2.7 (2014-11-23)
 ------------------------
 
diff --git a/dumprar.py b/dumprar.py
index c922fe3..f7ab062 100755
--- a/dumprar.py
+++ b/dumprar.py
@@ -2,6 +2,7 @@
 
 """Dump archive contents, test extraction."""
 
+import io
 import sys
 import rarfile as rf
 from binascii import crc32, hexlify
@@ -24,7 +25,7 @@ switches:
   -pPSW      set password
   -Ccharset  set fallback charset
   -v         increase verbosity
-  -t         attemt to read all files
+  -t         attempt to read all files
   -x         write read files out
   -c         show archive comment
   -h         show usage
@@ -190,6 +191,7 @@ cf_charset = None
 cf_extract = 0
 cf_test_read = 0
 cf_test_unrar = 0
+cf_test_memory = 0
 
 def check_crc(f, inf):
     ucrc = f.CRC
@@ -242,13 +244,17 @@ def test_real(fn, psw):
     if cf_verbose > 1:
         cb = show_item
 
+    rfarg = fn
+    if cf_test_memory:
+        rfarg = io.BytesIO(open(fn, 'rb').read())
+
     # check if rar
-    if not rf.is_rarfile(fn):
+    if not rf.is_rarfile(rfarg):
         xprint(" --- %s is not a RAR file ---", fn)
         return
 
     # open
-    r = rf.RarFile(fn, charset = cf_charset, info_callback = cb)
+    r = rf.RarFile(rfarg, charset = cf_charset, info_callback = cb)
     # set password
     if r.needs_password():
         if psw:
@@ -302,6 +308,7 @@ def test(fn, psw):
 def main():
     global cf_verbose, cf_show_comment, cf_charset
     global cf_extract, cf_test_read, cf_test_unrar
+    global cf_test_memory
 
     # parse args
     args = []
@@ -333,6 +340,8 @@ def main():
             cf_test_read += 1
         elif a == '-T':
             cf_test_unrar = 1
+        elif a == '-M':
+            cf_test_memory = 1
         elif a[1] == 'C':
             cf_charset = a[2:]
         else:
diff --git a/rarfile.py b/rarfile.py
index 3db5840..25b6119 100644
--- a/rarfile.py
+++ b/rarfile.py
@@ -1,6 +1,6 @@
 # rarfile.py
 #
-# Copyright (c) 2005-2014  Marko Kreen <markokr at gmail.com>
+# Copyright (c) 2005-2016  Marko Kreen <markokr at gmail.com>
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -74,7 +74,7 @@ For more details, refer to source.
 
 """
 
-__version__ = '2.7'
+__version__ = '2.8'
 
 # export only interesting items
 __all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
@@ -84,19 +84,34 @@ __all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
 ##
 
 import sys, os, struct, errno
-from struct import pack, unpack
+from struct import pack, unpack, Struct
 from binascii import crc32
 from tempfile import mkstemp
 from subprocess import Popen, PIPE, STDOUT
 from datetime import datetime
+from io import RawIOBase
+from hashlib import sha1
 
 # only needed for encryped headers
 try:
-    from Crypto.Cipher import AES
     try:
-        from hashlib import sha1
+        from cryptography.hazmat.primitives.ciphers import algorithms, modes, Cipher
+        from cryptography.hazmat.backends import default_backend
+        class AES_CBC_Decrypt(object):
+            block_size = 16
+            def __init__(self, key, iv):
+                ciph = Cipher(algorithms.AES(key), modes.CBC(iv), default_backend())
+                self.dec = ciph.decryptor()
+            def decrypt(self, data):
+                return self.dec.update(data)
     except ImportError:
-        from sha import new as sha1
+        from Crypto.Cipher import AES
+        class AES_CBC_Decrypt(object):
+            block_size = 16
+            def __init__(self, key, iv):
+                self.dec = AES.new(key, AES.MODE_CBC, iv)
+            def decrypt(self, data):
+                return self.dec.decrypt(data)
     _have_crypto = 1
 except ImportError:
     _have_crypto = 0
@@ -105,57 +120,9 @@ except ImportError:
 if sys.hexversion < 0x3000000:
     # prefer 3.x behaviour
     range = xrange
-    # py2.6 has broken bytes()
-    def bytes(s, enc):
-        return str(s)
 else:
     unicode = str
 
-# see if compat bytearray() is needed
-try:
-    bytearray
-except NameError:
-    import array
-    class bytearray:
-        def __init__(self, val = ''):
-            self.arr = array.array('B', val)
-            self.append = self.arr.append
-            self.__getitem__ = self.arr.__getitem__
-            self.__len__ = self.arr.__len__
-        def decode(self, *args):
-            return self.arr.tostring().decode(*args)
-
-# Optimized .readinto() requires memoryview
-try:
-    memoryview
-    have_memoryview = 1
-except NameError:
-    have_memoryview = 0
-
-# Struct() for older python
-try:
-    from struct import Struct
-except ImportError:
-    class Struct:
-        def __init__(self, fmt):
-            self.format = fmt
-            self.size = struct.calcsize(fmt)
-        def unpack(self, buf):
-            return unpack(self.format, buf)
-        def unpack_from(self, buf, ofs = 0):
-            return unpack(self.format, buf[ofs : ofs + self.size])
-        def pack(self, *args):
-            return pack(self.format, *args)
-
-# file object superclass
-try:
-    from io import RawIOBase
-except ImportError:
-    class RawIOBase(object):
-        def close(self):
-            pass
-
-
 ##
 ## Module configuration.  Can be tuned after importing.
 ##
@@ -294,9 +261,9 @@ RAR_M5 = 0x35
 ## internal constants
 ##
 
-RAR_ID = bytes("Rar!\x1a\x07\x00", 'ascii')
-ZERO = bytes("\0", 'ascii')
-EMPTY = bytes("", 'ascii')
+RAR_ID = b"Rar!\x1a\x07\x00"
+ZERO = b"\0"
+EMPTY = b""
 
 S_BLK_HDR = Struct('<HBHH')
 S_FILE_HDR = Struct('<LLBLLBBHL')
@@ -465,7 +432,7 @@ class RarInfo(object):
         return False
 
     def needs_password(self):
-        return self.flags & RAR_FILE_PASSWORD
+        return (self.flags & RAR_FILE_PASSWORD) > 0
 
 
 class RarFile(object):
@@ -503,6 +470,7 @@ class RarFile(object):
 
         self._info_list = []
         self._info_map = {}
+        self._parse_error = None
         self._needs_password = False
         self._password = None
         self._crc_check = crc_check
@@ -540,7 +508,7 @@ class RarFile(object):
 
     def namelist(self):
         '''Return list of filenames in archive.'''
-        return [f.filename for f in self._info_list]
+        return [f.filename for f in self.infolist()]
 
     def infolist(self):
         '''Return RarInfo objects for all files/directories in archive.'''
@@ -638,6 +606,8 @@ class RarFile(object):
             return self._open_clear(inf)
         elif use_hack:
             return self._open_hack(inf, psw)
+        elif is_filelike(self.rarfile):
+            return self._open_unrar_membuf(self.rarfile, inf, psw)
         else:
             return self._open_unrar(self.rarfile, inf, psw)
 
@@ -666,7 +636,7 @@ class RarFile(object):
 
     def printdir(self):
         """Print archive file list to stdout."""
-        for f in self._info_list:
+        for f in self.infolist():
             print(f.filename)
 
     def extract(self, member, path=None, pwd=None):
@@ -713,10 +683,22 @@ class RarFile(object):
         """
         cmd = [UNRAR_TOOL] + list(TEST_ARGS)
         add_password_arg(cmd, self._password)
-        cmd.append(self.rarfile)
-        p = custom_popen(cmd)
-        output = p.communicate()[0]
-        check_returncode(p, output)
+        cmd.append('--')
+
+        if is_filelike(self.rarfile):
+            tmpname = membuf_tempfile(self.rarfile)
+            cmd.append(tmpname)
+        else:
+            tmpname = None
+            cmd.append(self.rarfile)
+
+        try:
+            p = custom_popen(cmd)
+            output = p.communicate()[0]
+            check_returncode(p, output)
+        finally:
+            if tmpname:
+                os.unlink(tmpname)
 
     def strerror(self):
         """Return error string if parsing failed,
@@ -786,7 +768,9 @@ class RarFile(object):
         self._fd = fd
         id = fd.read(len(RAR_ID))
         if id != RAR_ID:
-            raise NotRarFile("Not a Rar archive: "+self.rarfile)
+            if isinstance(self.rarfile, (str, unicode)):
+                raise NotRarFile("Not a Rar archive: {}".format(self.rarfile))
+            raise NotRarFile("Not a Rar archive")
 
         volume = 0  # first vol (.rar) is 0
         more_vols = 0
@@ -1177,18 +1161,24 @@ class RarFile(object):
         if self._crc_check:
             crc = crc32(cmt)
             if crc < 0:
-                crc += (long(1) << 32)
+                crc += (1 << 32)
             if crc != inf.CRC:
                 return None
 
         return self._decode_comment(cmt)
 
+    # write in-memory archive to temp file - needed for solid archives
+    def _open_unrar_membuf(self, memfile, inf, psw):
+        tmpname = membuf_tempfile(memfile)
+        return self._open_unrar(tmpname, inf, psw, tmpname)
+
     # extract using unrar
     def _open_unrar(self, rarfile, inf, psw = None, tmpfile = None):
         if is_filelike(rarfile):
             raise ValueError("Cannot use unrar directly on memory buffer")
         cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
         add_password_arg(cmd, psw)
+        cmd.append("--")
         cmd.append(rarfile)
 
         # not giving filename avoids encoding related problems
@@ -1221,9 +1211,15 @@ class RarFile(object):
         # pasoword
         psw = psw or self._password
         add_password_arg(cmd, psw)
+        cmd.append('--')
 
         # rar file
-        cmd.append(self.rarfile)
+        if is_filelike(self.rarfile):
+            tmpname = membuf_tempfile(self.rarfile)
+            cmd.append(tmpname)
+        else:
+            tmpname = None
+            cmd.append(self.rarfile)
 
         # file list
         for fn in fnlist:
@@ -1236,15 +1232,19 @@ class RarFile(object):
             cmd.append(path + os.sep)
 
         # call
-        p = custom_popen(cmd)
-        output = p.communicate()[0]
-        check_returncode(p, output)
+        try:
+            p = custom_popen(cmd)
+            output = p.communicate()[0]
+            check_returncode(p, output)
+        finally:
+            if tmpname:
+                os.unlink(tmpname)
 
 ##
 ## Utility classes
 ##
 
-class UnicodeFilename:
+class UnicodeFilename(object):
     """Handle unicode filename decompression"""
 
     def __init__(self, name, encdata):
@@ -1321,7 +1321,7 @@ class RarExtFile(RawIOBase):
     name = None
 
     def __init__(self, rf, inf):
-        RawIOBase.__init__(self)
+        super(RarExtFile, self).__init__()
 
         # standard io.* properties
         self.name = inf.filename
@@ -1379,7 +1379,7 @@ class RarExtFile(RawIOBase):
             raise BadRarFile("Failed the read enough data")
         crc = self.CRC
         if crc < 0:
-            crc += (long(1) << 32)
+            crc += (1 << 32)
         if crc != self.inf.CRC:
             raise BadRarFile("Corrupt file - CRC check failed: " + self.inf.filename)
 
@@ -1389,7 +1389,7 @@ class RarExtFile(RawIOBase):
     def close(self):
         """Close open resources."""
 
-        RawIOBase.close(self)
+        super(RarExtFile, self).close()
 
         if self.fd:
             self.fd.close()
@@ -1502,7 +1502,7 @@ class PipeReader(RarExtFile):
         self.cmd = cmd
         self.proc = None
         self.tempfile = tempfile
-        RarExtFile.__init__(self, rf, inf)
+        super(PipeReader, self).__init__(rf, inf)
 
     def _close_proc(self):
         if not self.proc:
@@ -1518,7 +1518,7 @@ class PipeReader(RarExtFile):
         self.proc = None
 
     def _open(self):
-        RarExtFile._open(self)
+        super(PipeReader, self)._open()
 
         # stop old process
         self._close_proc()
@@ -1555,7 +1555,7 @@ class PipeReader(RarExtFile):
         """Close open resources."""
 
         self._close_proc()
-        RarExtFile.close(self)
+        super(PipeReader, self).close()
 
         if self.tempfile:
             try:
@@ -1564,30 +1564,29 @@ class PipeReader(RarExtFile):
                 pass
             self.tempfile = None
 
-    if have_memoryview:
-        def readinto(self, buf):
-            """Zero-copy read directly into buffer."""
-            cnt = len(buf)
-            if cnt > self.remain:
-                cnt = self.remain
-            vbuf = memoryview(buf)
-            res = got = 0
-            while got < cnt:
-                res = self.fd.readinto(vbuf[got : cnt])
-                if not res:
-                    break
-                if self.crc_check:
-                    self.CRC = crc32(vbuf[got : got + res], self.CRC)
-                self.remain -= res
-                got += res
-            return got
+    def readinto(self, buf):
+        """Zero-copy read directly into buffer."""
+        cnt = len(buf)
+        if cnt > self.remain:
+            cnt = self.remain
+        vbuf = memoryview(buf)
+        res = got = 0
+        while got < cnt:
+            res = self.fd.readinto(vbuf[got : cnt])
+            if not res:
+                break
+            if self.crc_check:
+                self.CRC = crc32(vbuf[got : got + res], self.CRC)
+            self.remain -= res
+            got += res
+        return got
 
 
 class DirectReader(RarExtFile):
     """Read uncompressed data directly from archive."""
 
     def _open(self):
-        RarExtFile._open(self)
+        super(DirectReader, self)._open()
 
         self.volfile = self.inf.volume_file
         self.fd = XFile(self.volfile, 0)
@@ -1674,39 +1673,38 @@ class DirectReader(RarExtFile):
             self.cur_avail = cur.add_size
             return True
 
-    if have_memoryview:
-        def readinto(self, buf):
-            """Zero-copy read directly into buffer."""
-            got = 0
-            vbuf = memoryview(buf)
-            while got < len(buf):
-                # next vol needed?
-                if self.cur_avail == 0:
-                    if not self._open_next():
-                        break
+    def readinto(self, buf):
+        """Zero-copy read directly into buffer."""
+        got = 0
+        vbuf = memoryview(buf)
+        while got < len(buf):
+            # next vol needed?
+            if self.cur_avail == 0:
+                if not self._open_next():
+                    break
 
-                # lenght for next read
-                cnt = len(buf) - got
-                if cnt > self.cur_avail:
-                    cnt = self.cur_avail
+            # length for next read
+            cnt = len(buf) - got
+            if cnt > self.cur_avail:
+                cnt = self.cur_avail
 
-                # read into temp view
-                res = self.fd.readinto(vbuf[got : got + cnt])
-                if not res:
-                    break
-                if self.crc_check:
-                    self.CRC = crc32(vbuf[got : got + res], self.CRC)
-                self.cur_avail -= res
-                self.remain -= res
-                got += res
-            return got
+            # read into temp view
+            res = self.fd.readinto(vbuf[got : got + cnt])
+            if not res:
+                break
+            if self.crc_check:
+                self.CRC = crc32(vbuf[got : got + res], self.CRC)
+            self.cur_avail -= res
+            self.remain -= res
+            got += res
+        return got
 
 
-class HeaderDecrypt:
+class HeaderDecrypt(object):
     """File-like object that decrypts from another file"""
     def __init__(self, f, key, iv):
         self.f = f
-        self.ciph = AES.new(key, AES.MODE_CBC, iv)
+        self.ciph = AES_CBC_Decrypt(key, iv)
         self.buf = EMPTY
 
     def tell(self):
@@ -1814,7 +1812,7 @@ def rar_decompress(vers, meth, data, declen=0, flags=0, crc=0, psw=None, salt=No
     flags |= RAR_LONG_BLOCK
 
     # file header
-    fname = bytes('data', 'ascii')
+    fname = b'data'
     date = 0
     mode = 0x20
     fhdr = S_FILE_HDR.pack(len(data), declen, RAR_OS_MSDOS, crc,
@@ -1908,8 +1906,7 @@ def custom_popen(cmd):
         p = Popen(cmd, bufsize = 0,
                   stdout = PIPE, stdin = PIPE, stderr = STDOUT,
                   creationflags = creationflags)
-    except OSError:
-        ex = sys.exc_info()[1]
+    except OSError as ex:
         if ex.errno == errno.ENOENT:
             raise RarCannotExec("Unrar not installed? (rarfile.UNRAR_TOOL=%r)" % UNRAR_TOOL)
         raise
@@ -1963,6 +1960,26 @@ def check_returncode(p, out):
 
     raise exc(msg)
 
+def membuf_tempfile(memfile):
+    memfile.seek(0, 0)
+
+    tmpfd, tmpname = mkstemp(suffix='.rar')
+    tmpf = os.fdopen(tmpfd, "wb")
+
+    try:
+        BSIZE = 32*1024
+        while True:
+            buf = memfile.read(BSIZE)
+            if not buf:
+                break
+            tmpf.write(buf)
+        tmpf.close()
+        return tmpname
+    except:
+        tmpf.close()
+        os.unlink(tmpname)
+        raise
+
 #
 # Check if unrar works
 #
diff --git a/test/Makefile b/test/Makefile
index 027bc5f..5383db3 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,5 +1,6 @@
 test:
-	./test.sh
+	./test1.sh
+	./test2.sh
 
 clean:
 	rm -rf __pycache__
diff --git a/test/test1.sh b/test/test1.sh
index e9f5bbd..5b0f86a 100755
--- a/test/test1.sh
+++ b/test/test1.sh
@@ -6,7 +6,7 @@ export PYTHONPATH
 JAVA_OPTIONS="-Dpython.path=`pwd`/.."
 export JAVA_OPTIONS
 
-plist="python2.4 python2.5 python2.6 python2.7 python3.1 python3.2 python3.3 python3.4 pypy jython jython2.7"
+plist="python2.7 python3.2 python3.3 python3.4 python3.5 python3.6 pypy jython jython2.7"
 
 rm -f test.diffs
 
diff --git a/test/test2.sh b/test/test2.sh
index b8bfb77..328e3ea 100755
--- a/test/test2.sh
+++ b/test/test2.sh
@@ -4,7 +4,7 @@ cp ../rarfile.py .
 
 #ulimit -n 16
 
-plist="python2.4 python2.5 python2.6 python2.7 python3.1 python3.2 python3.3 python3.4 pypy jython jython2.7"
+plist="python2.7 python3.2 python3.3 python3.4 python3.5 python3.6 pypy jython jython2.7"
 
 for py in $plist; do
   if which $py > /dev/null; then

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-rarfile.git



More information about the Python-modules-commits mailing list