mirror of
https://github.com/ciromattia/kcc
synced 2025-12-13 09:46:25 +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
|
||||
#
|
||||
# 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
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -17,7 +17,7 @@
|
||||
r"""RAR archive reader.
|
||||
|
||||
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:
|
||||
- Parse archive structure with Python.
|
||||
@@ -34,7 +34,17 @@ Example::
|
||||
for f in rf.infolist():
|
||||
print f.filename, f.file_size
|
||||
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,
|
||||
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
|
||||
__all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
|
||||
@@ -148,45 +158,45 @@ except ImportError:
|
||||
## Module configuration. Can be tuned after importing.
|
||||
##
|
||||
|
||||
# default fallback charset
|
||||
#: default fallback charset
|
||||
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')
|
||||
|
||||
# 'unrar', 'rar' or full path to either one
|
||||
#: 'unrar', 'rar' or full path to either one
|
||||
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')
|
||||
|
||||
# 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')
|
||||
|
||||
# args for testrar()
|
||||
#: args for testrar()
|
||||
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
|
||||
|
||||
# limit the filesize for tmp archive usage
|
||||
#: limit the filesize for tmp archive usage
|
||||
HACK_SIZE_LIMIT = 20*1024*1024
|
||||
|
||||
# whether to parse file/archive comments.
|
||||
#: whether to parse file/archive comments.
|
||||
NEED_COMMENTS = 1
|
||||
|
||||
# whether to convert comments to unicode strings
|
||||
#: whether to convert comments to unicode strings
|
||||
UNICODE_COMMENTS = 0
|
||||
|
||||
# When RAR is corrupt, stopping on bad header is better
|
||||
# On unknown/misparsed RAR headers reporting is better
|
||||
#: When RAR is corrupt, stopping on bad header is better
|
||||
#: On unknown/misparsed RAR headers reporting is better
|
||||
REPORT_BAD_HEADER = 0
|
||||
|
||||
# Convert RAR time tuple into datetime() object
|
||||
#: Convert RAR time tuple into datetime() object
|
||||
USE_DATETIME = 0
|
||||
|
||||
# Separator for path name components. RAR internally uses '\\'.
|
||||
# Use '/' to be similar with zipfile.
|
||||
#: Separator for path name components. RAR internally uses '\\'.
|
||||
#: Use '/' to be similar with zipfile.
|
||||
PATH_SEP = '\\'
|
||||
|
||||
##
|
||||
@@ -337,49 +347,57 @@ def is_rarfile(fn):
|
||||
|
||||
|
||||
class RarInfo(object):
|
||||
'''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).
|
||||
r'''An entry in rar archive.
|
||||
|
||||
@ivar mtime:
|
||||
Optional time field: Modification time, with float seconds.
|
||||
Same as .date_time but with more precision.
|
||||
@ivar ctime:
|
||||
Optional time field: creation time, with float seconds.
|
||||
@ivar atime:
|
||||
Optional time field: last access time, with float seconds.
|
||||
@ivar arctime:
|
||||
Optional time field: archival time, with float seconds.
|
||||
:mod:`zipfile`-compatible fields:
|
||||
|
||||
filename
|
||||
File name with relative path.
|
||||
Default path separator is '\\', to change set rarfile.PATH_SEP.
|
||||
Always unicode string.
|
||||
date_time
|
||||
Modification time, tuple of (year, month, day, hour, minute, second).
|
||||
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__ = (
|
||||
@@ -433,19 +451,27 @@ class RarInfo(object):
|
||||
|
||||
class RarFile(object):
|
||||
'''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):
|
||||
"""Open and parse a RAR archive.
|
||||
|
||||
@param rarfile: archive file name
|
||||
@param mode: only 'r' is supported.
|
||||
@param charset: fallback charset to use, if filenames are not already Unicode-enabled.
|
||||
@param info_callback: debug callback, gets to see all archive entries.
|
||||
@param crc_check: set to False to disable CRC checks
|
||||
Parameters:
|
||||
|
||||
rarfile
|
||||
archive file name
|
||||
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.comment = None
|
||||
@@ -457,6 +483,7 @@ class RarFile(object):
|
||||
self._needs_password = False
|
||||
self._password = None
|
||||
self._crc_check = crc_check
|
||||
self._vol_list = []
|
||||
|
||||
self._main = None
|
||||
|
||||
@@ -489,6 +516,14 @@ class RarFile(object):
|
||||
'''Return RarInfo objects for all files/directories in archive.'''
|
||||
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):
|
||||
'''Return RarInfo for file.'''
|
||||
|
||||
@@ -510,7 +545,8 @@ class RarFile(object):
|
||||
raise NoRarEntry("No such file: "+fname)
|
||||
|
||||
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
|
||||
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
|
||||
by reading ahead and/or restarting the decompression.
|
||||
|
||||
@param fname: file name or RarInfo instance.
|
||||
@param mode: must be 'r'
|
||||
@param psw: password to use for extracting.
|
||||
Parameters:
|
||||
|
||||
fname
|
||||
file name or RarInfo instance.
|
||||
mode
|
||||
must be 'r'
|
||||
psw
|
||||
password to use for extracting.
|
||||
'''
|
||||
|
||||
if mode != 'r':
|
||||
@@ -571,8 +612,12 @@ class RarFile(object):
|
||||
|
||||
For longer files using .open() may be better idea.
|
||||
|
||||
@param fname: filename or RarInfo instance
|
||||
@param psw: password to use for extracting.
|
||||
Parameters:
|
||||
|
||||
fname
|
||||
filename or RarInfo instance
|
||||
psw
|
||||
password to use for extracting.
|
||||
"""
|
||||
|
||||
f = self.open(fname, 'r', psw)
|
||||
@@ -593,9 +638,14 @@ class RarFile(object):
|
||||
def extract(self, member, path=None, pwd=None):
|
||||
"""Extract single file into current directory.
|
||||
|
||||
@param member: filename or RarInfo instance
|
||||
@param path: optional destination path
|
||||
@param pwd: optional password to use
|
||||
Parameters:
|
||||
|
||||
member
|
||||
filename or RarInfo instance
|
||||
path
|
||||
optional destination path
|
||||
pwd
|
||||
optional password to use
|
||||
"""
|
||||
if isinstance(member, RarInfo):
|
||||
fname = member.filename
|
||||
@@ -606,9 +656,14 @@ class RarFile(object):
|
||||
def extractall(self, path=None, members=None, pwd=None):
|
||||
"""Extract all files into current directory.
|
||||
|
||||
@param path: optional destination path
|
||||
@param members: optional filename or RarInfo instance list to extract
|
||||
@param pwd: optional password to use
|
||||
Parameters:
|
||||
|
||||
path
|
||||
optional destination path
|
||||
members
|
||||
optional filename or RarInfo instance list to extract
|
||||
pwd
|
||||
optional password to use
|
||||
"""
|
||||
fnlist = []
|
||||
if members is not None:
|
||||
@@ -693,6 +748,7 @@ class RarFile(object):
|
||||
more_vols = 0
|
||||
endarc = 0
|
||||
volfile = self.rarfile
|
||||
self._vol_list = [self.rarfile]
|
||||
while 1:
|
||||
if endarc:
|
||||
h = None # don't read past ENDARC
|
||||
@@ -707,6 +763,7 @@ class RarFile(object):
|
||||
self._fd = fd
|
||||
more_vols = 0
|
||||
endarc = 0
|
||||
self._vol_list.append(volfile)
|
||||
continue
|
||||
break
|
||||
h.volume = volume
|
||||
@@ -1210,7 +1267,7 @@ class UnicodeFilename:
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -1218,13 +1275,15 @@ class RarExtFile(RawIOBase):
|
||||
- no short reads - .read() and .readinfo() read as much as requested.
|
||||
- no internal buffer, use io.BufferedReader for that.
|
||||
|
||||
@ivar name:
|
||||
filename of the archive entry.
|
||||
If :mod:`io` module is available (Python 2.6+, 3.x), then this calls
|
||||
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):
|
||||
"""Fill common fields"""
|
||||
#: Filename of the archive entry
|
||||
name = None
|
||||
|
||||
def __init__(self, rf, inf):
|
||||
RawIOBase.__init__(self)
|
||||
|
||||
# standard io.* properties
|
||||
@@ -1325,7 +1384,13 @@ class RarExtFile(RawIOBase):
|
||||
return self.inf.file_size - self.remain
|
||||
|
||||
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
|
||||
self.crc_check = 0
|
||||
@@ -1374,8 +1439,17 @@ class RarExtFile(RawIOBase):
|
||||
"""Returns True"""
|
||||
return True
|
||||
|
||||
def writable(self):
|
||||
"""Returns False.
|
||||
|
||||
Writing is not supported."""
|
||||
return False
|
||||
|
||||
def seekable(self):
|
||||
"""Returns True"""
|
||||
"""Returns True.
|
||||
|
||||
Seeking is supported, although it's slow on compressed files.
|
||||
"""
|
||||
return True
|
||||
|
||||
def readall(self):
|
||||
|
||||
Reference in New Issue
Block a user