mirror of
https://github.com/ciromattia/kcc
synced 2025-12-15 18:56:28 +00:00
rarfile updated to 2.6
This commit is contained in:
250
kcc/rarfile.py
250
kcc/rarfile.py
@@ -1,6 +1,6 @@
|
|||||||
# rarfile.py
|
# rarfile.py
|
||||||
#
|
#
|
||||||
# Copyright (c) 2005-2012 Marko Kreen <markokr@gmail.com>
|
# Copyright (c) 2005-2013 Marko Kreen <markokr@gmail.com>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for any
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
# purpose with or without fee is hereby granted, provided that the above
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
r"""RAR archive reader.
|
r"""RAR archive reader.
|
||||||
|
|
||||||
This is Python module for Rar archive reading. The interface
|
This is Python module for Rar archive reading. The interface
|
||||||
is made as zipfile like as possible.
|
is made as :mod:`zipfile`-like as possible.
|
||||||
|
|
||||||
Basic logic:
|
Basic logic:
|
||||||
- Parse archive structure with Python.
|
- Parse archive structure with Python.
|
||||||
@@ -34,7 +34,17 @@ Example::
|
|||||||
for f in rf.infolist():
|
for f in rf.infolist():
|
||||||
print f.filename, f.file_size
|
print f.filename, f.file_size
|
||||||
if f.filename == 'README':
|
if f.filename == 'README':
|
||||||
print rf.read(f)
|
print(rf.read(f))
|
||||||
|
|
||||||
|
Archive files can also be accessed via file-like object returned
|
||||||
|
by :meth:`RarFile.open`::
|
||||||
|
|
||||||
|
import rarfile
|
||||||
|
|
||||||
|
with rarfile.RarFile('archive.rar') as rf:
|
||||||
|
with rf.open('README') as f:
|
||||||
|
for ln in f:
|
||||||
|
print(ln.strip())
|
||||||
|
|
||||||
There are few module-level parameters to tune behaviour,
|
There are few module-level parameters to tune behaviour,
|
||||||
here they are with defaults, and reason to change it::
|
here they are with defaults, and reason to change it::
|
||||||
@@ -64,7 +74,7 @@ For more details, refer to source.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '2.5'
|
__version__ = '2.6'
|
||||||
|
|
||||||
# export only interesting items
|
# export only interesting items
|
||||||
__all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
|
__all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
|
||||||
@@ -148,45 +158,45 @@ except ImportError:
|
|||||||
## Module configuration. Can be tuned after importing.
|
## Module configuration. Can be tuned after importing.
|
||||||
##
|
##
|
||||||
|
|
||||||
# default fallback charset
|
#: default fallback charset
|
||||||
DEFAULT_CHARSET = "windows-1252"
|
DEFAULT_CHARSET = "windows-1252"
|
||||||
|
|
||||||
# list of encodings to try, with fallback to DEFAULT_CHARSET if none succeed
|
#: list of encodings to try, with fallback to DEFAULT_CHARSET if none succeed
|
||||||
TRY_ENCODINGS = ('utf8', 'utf-16le')
|
TRY_ENCODINGS = ('utf8', 'utf-16le')
|
||||||
|
|
||||||
# 'unrar', 'rar' or full path to either one
|
#: 'unrar', 'rar' or full path to either one
|
||||||
UNRAR_TOOL = "unrar"
|
UNRAR_TOOL = "unrar"
|
||||||
|
|
||||||
# Command line args to use for opening file for reading.
|
#: Command line args to use for opening file for reading.
|
||||||
OPEN_ARGS = ('p', '-inul')
|
OPEN_ARGS = ('p', '-inul')
|
||||||
|
|
||||||
# Command line args to use for extracting file to disk.
|
#: Command line args to use for extracting file to disk.
|
||||||
EXTRACT_ARGS = ('x', '-y', '-idq')
|
EXTRACT_ARGS = ('x', '-y', '-idq')
|
||||||
|
|
||||||
# args for testrar()
|
#: args for testrar()
|
||||||
TEST_ARGS = ('t', '-idq')
|
TEST_ARGS = ('t', '-idq')
|
||||||
|
|
||||||
# whether to speed up decompression by using tmp archive
|
#: whether to speed up decompression by using tmp archive
|
||||||
USE_EXTRACT_HACK = 1
|
USE_EXTRACT_HACK = 1
|
||||||
|
|
||||||
# limit the filesize for tmp archive usage
|
#: limit the filesize for tmp archive usage
|
||||||
HACK_SIZE_LIMIT = 20*1024*1024
|
HACK_SIZE_LIMIT = 20*1024*1024
|
||||||
|
|
||||||
# whether to parse file/archive comments.
|
#: whether to parse file/archive comments.
|
||||||
NEED_COMMENTS = 1
|
NEED_COMMENTS = 1
|
||||||
|
|
||||||
# whether to convert comments to unicode strings
|
#: whether to convert comments to unicode strings
|
||||||
UNICODE_COMMENTS = 0
|
UNICODE_COMMENTS = 0
|
||||||
|
|
||||||
# When RAR is corrupt, stopping on bad header is better
|
#: When RAR is corrupt, stopping on bad header is better
|
||||||
# On unknown/misparsed RAR headers reporting is better
|
#: On unknown/misparsed RAR headers reporting is better
|
||||||
REPORT_BAD_HEADER = 0
|
REPORT_BAD_HEADER = 0
|
||||||
|
|
||||||
# Convert RAR time tuple into datetime() object
|
#: Convert RAR time tuple into datetime() object
|
||||||
USE_DATETIME = 0
|
USE_DATETIME = 0
|
||||||
|
|
||||||
# Separator for path name components. RAR internally uses '\\'.
|
#: Separator for path name components. RAR internally uses '\\'.
|
||||||
# Use '/' to be similar with zipfile.
|
#: Use '/' to be similar with zipfile.
|
||||||
PATH_SEP = '\\'
|
PATH_SEP = '\\'
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -337,49 +347,57 @@ def is_rarfile(fn):
|
|||||||
|
|
||||||
|
|
||||||
class RarInfo(object):
|
class RarInfo(object):
|
||||||
'''An entry in rar archive.
|
r'''An entry in rar archive.
|
||||||
|
|
||||||
@ivar filename:
|
|
||||||
File name with relative path.
|
|
||||||
Default path separator is '/', to change set rarfile.PATH_SEP.
|
|
||||||
Always unicode string.
|
|
||||||
@ivar date_time:
|
|
||||||
Modification time, tuple of (year, month, day, hour, minute, second).
|
|
||||||
Or datetime() object if USE_DATETIME is set.
|
|
||||||
@ivar file_size:
|
|
||||||
Uncompressed size.
|
|
||||||
@ivar compress_size:
|
|
||||||
Compressed size.
|
|
||||||
@ivar compress_type:
|
|
||||||
Compression method: 0x30 - 0x35.
|
|
||||||
@ivar extract_version:
|
|
||||||
Minimal Rar version needed for decompressing.
|
|
||||||
@ivar host_os:
|
|
||||||
Host OS type, one of RAR_OS_* constants.
|
|
||||||
@ivar mode:
|
|
||||||
File attributes. May be either dos-style or unix-style, depending on host_os.
|
|
||||||
@ivar CRC:
|
|
||||||
CRC-32 of uncompressed file, unsigned int.
|
|
||||||
@ivar volume:
|
|
||||||
Volume nr, starting from 0.
|
|
||||||
@ivar volume_file:
|
|
||||||
Volume file name, where file starts.
|
|
||||||
@ivar type:
|
|
||||||
One of RAR_BLOCK_* types. Only entries with type==RAR_BLOCK_FILE are shown in .infolist().
|
|
||||||
@ivar flags:
|
|
||||||
For files, RAR_FILE_* bits.
|
|
||||||
@ivar comment:
|
|
||||||
File comment (unicode string or None).
|
|
||||||
|
|
||||||
@ivar mtime:
|
:mod:`zipfile`-compatible fields:
|
||||||
Optional time field: Modification time, with float seconds.
|
|
||||||
Same as .date_time but with more precision.
|
filename
|
||||||
@ivar ctime:
|
File name with relative path.
|
||||||
Optional time field: creation time, with float seconds.
|
Default path separator is '\\', to change set rarfile.PATH_SEP.
|
||||||
@ivar atime:
|
Always unicode string.
|
||||||
Optional time field: last access time, with float seconds.
|
date_time
|
||||||
@ivar arctime:
|
Modification time, tuple of (year, month, day, hour, minute, second).
|
||||||
Optional time field: archival time, with float seconds.
|
Or datetime() object if USE_DATETIME is set.
|
||||||
|
file_size
|
||||||
|
Uncompressed size.
|
||||||
|
compress_size
|
||||||
|
Compressed size.
|
||||||
|
CRC
|
||||||
|
CRC-32 of uncompressed file, unsigned int.
|
||||||
|
comment
|
||||||
|
File comment. Byte string or None. Use UNICODE_COMMENTS
|
||||||
|
to get automatic decoding to unicode.
|
||||||
|
volume
|
||||||
|
Volume nr, starting from 0.
|
||||||
|
|
||||||
|
RAR-specific fields:
|
||||||
|
|
||||||
|
compress_type
|
||||||
|
Compression method: 0x30 - 0x35.
|
||||||
|
extract_version
|
||||||
|
Minimal Rar version needed for decompressing.
|
||||||
|
host_os
|
||||||
|
Host OS type, one of RAR_OS_* constants.
|
||||||
|
mode
|
||||||
|
File attributes. May be either dos-style or unix-style, depending on host_os.
|
||||||
|
volume_file
|
||||||
|
Volume file name, where file starts.
|
||||||
|
mtime
|
||||||
|
Optional time field: Modification time, with float seconds.
|
||||||
|
Same as .date_time but with more precision.
|
||||||
|
ctime
|
||||||
|
Optional time field: creation time, with float seconds.
|
||||||
|
atime
|
||||||
|
Optional time field: last access time, with float seconds.
|
||||||
|
arctime
|
||||||
|
Optional time field: archival time, with float seconds.
|
||||||
|
|
||||||
|
Internal fields:
|
||||||
|
|
||||||
|
type
|
||||||
|
One of RAR_BLOCK_* types. Only entries with type==RAR_BLOCK_FILE are shown in .infolist().
|
||||||
|
flags
|
||||||
|
For files, RAR_FILE_* bits.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
@@ -433,19 +451,27 @@ class RarInfo(object):
|
|||||||
|
|
||||||
class RarFile(object):
|
class RarFile(object):
|
||||||
'''Parse RAR structure, provide access to files in archive.
|
'''Parse RAR structure, provide access to files in archive.
|
||||||
|
|
||||||
@ivar comment:
|
|
||||||
Archive comment (unicode string or None).
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
#: Archive comment. Byte string or None. Use UNICODE_COMMENTS
|
||||||
|
#: to get automatic decoding to unicode.
|
||||||
|
comment = None
|
||||||
|
|
||||||
def __init__(self, rarfile, mode="r", charset=None, info_callback=None, crc_check = True):
|
def __init__(self, rarfile, mode="r", charset=None, info_callback=None, crc_check = True):
|
||||||
"""Open and parse a RAR archive.
|
"""Open and parse a RAR archive.
|
||||||
|
|
||||||
@param rarfile: archive file name
|
Parameters:
|
||||||
@param mode: only 'r' is supported.
|
|
||||||
@param charset: fallback charset to use, if filenames are not already Unicode-enabled.
|
rarfile
|
||||||
@param info_callback: debug callback, gets to see all archive entries.
|
archive file name
|
||||||
@param crc_check: set to False to disable CRC checks
|
mode
|
||||||
|
only 'r' is supported.
|
||||||
|
charset
|
||||||
|
fallback charset to use, if filenames are not already Unicode-enabled.
|
||||||
|
info_callback
|
||||||
|
debug callback, gets to see all archive entries.
|
||||||
|
crc_check
|
||||||
|
set to False to disable CRC checks
|
||||||
"""
|
"""
|
||||||
self.rarfile = rarfile
|
self.rarfile = rarfile
|
||||||
self.comment = None
|
self.comment = None
|
||||||
@@ -457,6 +483,7 @@ class RarFile(object):
|
|||||||
self._needs_password = False
|
self._needs_password = False
|
||||||
self._password = None
|
self._password = None
|
||||||
self._crc_check = crc_check
|
self._crc_check = crc_check
|
||||||
|
self._vol_list = []
|
||||||
|
|
||||||
self._main = None
|
self._main = None
|
||||||
|
|
||||||
@@ -489,6 +516,14 @@ class RarFile(object):
|
|||||||
'''Return RarInfo objects for all files/directories in archive.'''
|
'''Return RarInfo objects for all files/directories in archive.'''
|
||||||
return self._info_list
|
return self._info_list
|
||||||
|
|
||||||
|
def volumelist(self):
|
||||||
|
'''Returns filenames of archive volumes.
|
||||||
|
|
||||||
|
In case of single-volume archive, the list contains
|
||||||
|
just the name of main archive file.
|
||||||
|
'''
|
||||||
|
return self._vol_list
|
||||||
|
|
||||||
def getinfo(self, fname):
|
def getinfo(self, fname):
|
||||||
'''Return RarInfo for file.'''
|
'''Return RarInfo for file.'''
|
||||||
|
|
||||||
@@ -510,7 +545,8 @@ class RarFile(object):
|
|||||||
raise NoRarEntry("No such file: "+fname)
|
raise NoRarEntry("No such file: "+fname)
|
||||||
|
|
||||||
def open(self, fname, mode = 'r', psw = None):
|
def open(self, fname, mode = 'r', psw = None):
|
||||||
'''Return open file object, where the data can be read.
|
'''Returns file-like object (:class:`RarExtFile`),
|
||||||
|
from where the data can be read.
|
||||||
|
|
||||||
The object implements io.RawIOBase interface, so it can
|
The object implements io.RawIOBase interface, so it can
|
||||||
be further wrapped with io.BufferedReader and io.TextIOWrapper.
|
be further wrapped with io.BufferedReader and io.TextIOWrapper.
|
||||||
@@ -522,9 +558,14 @@ class RarFile(object):
|
|||||||
uncompressed files, on compressed files the seeking is implemented
|
uncompressed files, on compressed files the seeking is implemented
|
||||||
by reading ahead and/or restarting the decompression.
|
by reading ahead and/or restarting the decompression.
|
||||||
|
|
||||||
@param fname: file name or RarInfo instance.
|
Parameters:
|
||||||
@param mode: must be 'r'
|
|
||||||
@param psw: password to use for extracting.
|
fname
|
||||||
|
file name or RarInfo instance.
|
||||||
|
mode
|
||||||
|
must be 'r'
|
||||||
|
psw
|
||||||
|
password to use for extracting.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if mode != 'r':
|
if mode != 'r':
|
||||||
@@ -571,8 +612,12 @@ class RarFile(object):
|
|||||||
|
|
||||||
For longer files using .open() may be better idea.
|
For longer files using .open() may be better idea.
|
||||||
|
|
||||||
@param fname: filename or RarInfo instance
|
Parameters:
|
||||||
@param psw: password to use for extracting.
|
|
||||||
|
fname
|
||||||
|
filename or RarInfo instance
|
||||||
|
psw
|
||||||
|
password to use for extracting.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
f = self.open(fname, 'r', psw)
|
f = self.open(fname, 'r', psw)
|
||||||
@@ -593,9 +638,14 @@ class RarFile(object):
|
|||||||
def extract(self, member, path=None, pwd=None):
|
def extract(self, member, path=None, pwd=None):
|
||||||
"""Extract single file into current directory.
|
"""Extract single file into current directory.
|
||||||
|
|
||||||
@param member: filename or RarInfo instance
|
Parameters:
|
||||||
@param path: optional destination path
|
|
||||||
@param pwd: optional password to use
|
member
|
||||||
|
filename or RarInfo instance
|
||||||
|
path
|
||||||
|
optional destination path
|
||||||
|
pwd
|
||||||
|
optional password to use
|
||||||
"""
|
"""
|
||||||
if isinstance(member, RarInfo):
|
if isinstance(member, RarInfo):
|
||||||
fname = member.filename
|
fname = member.filename
|
||||||
@@ -606,9 +656,14 @@ class RarFile(object):
|
|||||||
def extractall(self, path=None, members=None, pwd=None):
|
def extractall(self, path=None, members=None, pwd=None):
|
||||||
"""Extract all files into current directory.
|
"""Extract all files into current directory.
|
||||||
|
|
||||||
@param path: optional destination path
|
Parameters:
|
||||||
@param members: optional filename or RarInfo instance list to extract
|
|
||||||
@param pwd: optional password to use
|
path
|
||||||
|
optional destination path
|
||||||
|
members
|
||||||
|
optional filename or RarInfo instance list to extract
|
||||||
|
pwd
|
||||||
|
optional password to use
|
||||||
"""
|
"""
|
||||||
fnlist = []
|
fnlist = []
|
||||||
if members is not None:
|
if members is not None:
|
||||||
@@ -693,6 +748,7 @@ class RarFile(object):
|
|||||||
more_vols = 0
|
more_vols = 0
|
||||||
endarc = 0
|
endarc = 0
|
||||||
volfile = self.rarfile
|
volfile = self.rarfile
|
||||||
|
self._vol_list = [self.rarfile]
|
||||||
while 1:
|
while 1:
|
||||||
if endarc:
|
if endarc:
|
||||||
h = None # don't read past ENDARC
|
h = None # don't read past ENDARC
|
||||||
@@ -707,6 +763,7 @@ class RarFile(object):
|
|||||||
self._fd = fd
|
self._fd = fd
|
||||||
more_vols = 0
|
more_vols = 0
|
||||||
endarc = 0
|
endarc = 0
|
||||||
|
self._vol_list.append(volfile)
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
h.volume = volume
|
h.volume = volume
|
||||||
@@ -1210,7 +1267,7 @@ class UnicodeFilename:
|
|||||||
|
|
||||||
|
|
||||||
class RarExtFile(RawIOBase):
|
class RarExtFile(RawIOBase):
|
||||||
"""Base class for 'file-like' object that RarFile.open() returns.
|
"""Base class for file-like object that :meth:`RarFile.open` returns.
|
||||||
|
|
||||||
Provides public methods and common crc checking.
|
Provides public methods and common crc checking.
|
||||||
|
|
||||||
@@ -1218,13 +1275,15 @@ class RarExtFile(RawIOBase):
|
|||||||
- no short reads - .read() and .readinfo() read as much as requested.
|
- no short reads - .read() and .readinfo() read as much as requested.
|
||||||
- no internal buffer, use io.BufferedReader for that.
|
- no internal buffer, use io.BufferedReader for that.
|
||||||
|
|
||||||
@ivar name:
|
If :mod:`io` module is available (Python 2.6+, 3.x), then this calls
|
||||||
filename of the archive entry.
|
will inherit from :class:`io.RawIOBase` class. This makes line-based
|
||||||
|
access available: :meth:`RarExtFile.readline` and ``for ln in f``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, rf, inf):
|
#: Filename of the archive entry
|
||||||
"""Fill common fields"""
|
name = None
|
||||||
|
|
||||||
|
def __init__(self, rf, inf):
|
||||||
RawIOBase.__init__(self)
|
RawIOBase.__init__(self)
|
||||||
|
|
||||||
# standard io.* properties
|
# standard io.* properties
|
||||||
@@ -1325,7 +1384,13 @@ class RarExtFile(RawIOBase):
|
|||||||
return self.inf.file_size - self.remain
|
return self.inf.file_size - self.remain
|
||||||
|
|
||||||
def seek(self, ofs, whence = 0):
|
def seek(self, ofs, whence = 0):
|
||||||
"""Seek in data."""
|
"""Seek in data.
|
||||||
|
|
||||||
|
On uncompressed files, the seeking works by actual
|
||||||
|
seeks so it's fast. On compresses files its slow
|
||||||
|
- forward seeking happends by reading ahead,
|
||||||
|
backwards by re-opening and decompressing from the start.
|
||||||
|
"""
|
||||||
|
|
||||||
# disable crc check when seeking
|
# disable crc check when seeking
|
||||||
self.crc_check = 0
|
self.crc_check = 0
|
||||||
@@ -1374,8 +1439,17 @@ class RarExtFile(RawIOBase):
|
|||||||
"""Returns True"""
|
"""Returns True"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def writable(self):
|
||||||
|
"""Returns False.
|
||||||
|
|
||||||
|
Writing is not supported."""
|
||||||
|
return False
|
||||||
|
|
||||||
def seekable(self):
|
def seekable(self):
|
||||||
"""Returns True"""
|
"""Returns True.
|
||||||
|
|
||||||
|
Seeking is supported, although it's slow on compressed files.
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def readall(self):
|
def readall(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user