Merge pull request #3042 from mano3m/develop_update_unrar

Update unrar2 lib to 0.99.3
This commit is contained in:
Ruud Burger
2014-04-04 15:56:34 +02:00
2 changed files with 69 additions and 26 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ similar to the C interface provided by UnRAR. There is also a
higher level interface which makes some common operations easier. higher level interface which makes some common operations easier.
""" """
__version__ = '0.99.2' __version__ = '0.99.3'
try: try:
WindowsError WindowsError
+68 -25
View File
@@ -33,6 +33,7 @@ from rar_exceptions import *
class UnpackerNotInstalled(Exception): pass class UnpackerNotInstalled(Exception): pass
rar_executable_cached = None rar_executable_cached = None
rar_executable_version = None
def call_unrar(params): def call_unrar(params):
"Calls rar/unrar command line executable, returns stdout pipe" "Calls rar/unrar command line executable, returns stdout pipe"
@@ -59,10 +60,10 @@ def call_unrar(params):
class RarFileImplementation(object): class RarFileImplementation(object):
def init(self, password = None): def init(self, password = None):
global rar_executable_version
self.password = password self.password = password
stdoutdata, stderrdata = self.call('v', []).communicate() stdoutdata, stderrdata = self.call('v', []).communicate()
for line in stderrdata.splitlines(): for line in stderrdata.splitlines():
@@ -73,18 +74,42 @@ class RarFileImplementation(object):
accum = [] accum = []
source = iter(stdoutdata.splitlines()) source = iter(stdoutdata.splitlines())
line = '' line = ''
while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')): while not (line.startswith('UNRAR')):
if line.strip().endswith('is not RAR archive'):
raise InvalidRARArchive
line = source.next() line = source.next()
while not line.startswith('Pathname/Comment'): signature = line
accum.append(line.rstrip('\n')) # The code below is mighty flaky
# and will probably crash on localized versions of RAR
# but I see no safe way to rewrite it using a CLI tool
if signature.startswith("UNRAR 4"):
rar_executable_version = 4
while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')):
if line.strip().endswith('is not RAR archive'):
raise InvalidRARArchive
line = source.next()
while not line.startswith('Pathname/Comment'):
accum.append(line.rstrip('\n'))
line = source.next()
if len(accum):
accum[0] = accum[0][9:] # strip out "Comment:" part
self.comment = '\n'.join(accum[:-1])
else:
self.comment = None
elif signature.startswith("UNRAR 5"):
rar_executable_version = 5
line = source.next() line = source.next()
if len(accum): while not line.startswith('Archive:'):
accum[0] = accum[0][9:] if line.strip().endswith('is not RAR archive'):
self.comment = '\n'.join(accum[:-1]) raise InvalidRARArchive
accum.append(line.rstrip('\n'))
line = source.next()
if len(accum):
self.comment = '\n'.join(accum[:-1]).strip()
else:
self.comment = None
else: else:
self.comment = None raise UnpackerNotInstalled("Unsupported RAR version, expected 4.x or 5.x, found: "
+ signature.split(" ")[1])
def escaped_password(self): def escaped_password(self):
return '-' if self.password == None else self.password return '-' if self.password == None else self.password
@@ -97,7 +122,8 @@ class RarFileImplementation(object):
def infoiter(self): def infoiter(self):
stdoutdata, stderrdata = self.call('v', ['c-']).communicate() command = "v" if rar_executable_version == 4 else "l"
stdoutdata, stderrdata = self.call(command, ['c-']).communicate()
for line in stderrdata.splitlines(): for line in stderrdata.splitlines():
if line.strip().startswith("Cannot open"): if line.strip().startswith("Cannot open"):
@@ -106,31 +132,48 @@ class RarFileImplementation(object):
accum = [] accum = []
source = iter(stdoutdata.splitlines()) source = iter(stdoutdata.splitlines())
line = '' line = ''
while not line.startswith('--------------'): while not line.startswith('-----------'):
if line.strip().endswith('is not RAR archive'): if line.strip().endswith('is not RAR archive'):
raise InvalidRARArchive raise InvalidRARArchive
if line.find("CRC failed") >= 0: if line.startswith("CRC failed") or line.startswith("Checksum error"):
raise IncorrectRARPassword raise IncorrectRARPassword
line = source.next() line = source.next()
line = source.next() line = source.next()
i = 0 i = 0
re_spaces = re.compile(r"\s+") re_spaces = re.compile(r"\s+")
while not line.startswith('--------------'): if rar_executable_version == 4:
accum.append(line) while not line.startswith('-----------'):
if len(accum) == 2: accum.append(line)
if len(accum) == 2:
data = {}
data['index'] = i
# asterisks mark password-encrypted files
data['filename'] = accum[0].strip().lstrip("*") # asterisks marks password-encrypted files
fields = re_spaces.split(accum[1].strip())
data['size'] = int(fields[0])
attr = fields[5]
data['isdir'] = 'd' in attr.lower()
data['datetime'] = time.strptime(fields[3] + " " + fields[4], '%d-%m-%y %H:%M')
data['comment'] = None
yield data
accum = []
i += 1
line = source.next()
elif rar_executable_version == 5:
while not line.startswith('-----------'):
fields = line.strip().lstrip("*").split()
data = {} data = {}
data['index'] = i data['index'] = i
data['filename'] = accum[0].strip() data['filename'] = " ".join(fields[4:])
info = re_spaces.split(accum[1].strip()) data['size'] = int(fields[1])
data['size'] = int(info[0]) attr = fields[0]
attr = info[5]
data['isdir'] = 'd' in attr.lower() data['isdir'] = 'd' in attr.lower()
data['datetime'] = time.strptime(info[3] + " " + info[4], '%d-%m-%y %H:%M') data['datetime'] = time.strptime(fields[2] + " " + fields[3], '%d-%m-%y %H:%M')
data['comment'] = None data['comment'] = None
yield data yield data
accum = []
i += 1 i += 1
line = source.next() line = source.next()
def read_files(self, checker): def read_files(self, checker):
res = [] res = []
@@ -151,7 +194,7 @@ class RarFileImplementation(object):
if overwrite: if overwrite:
options.append('o+') options.append('o+')
else: else:
options.append('o-') options.append('o-')
if not path.endswith(os.sep): if not path.endswith(os.sep):
path += os.sep path += os.sep
names = [] names = []
@@ -165,7 +208,7 @@ class RarFileImplementation(object):
names.append(path) names.append(path)
proc = self.call(command, options, names) proc = self.call(command, options, names)
stdoutdata, stderrdata = proc.communicate() stdoutdata, stderrdata = proc.communicate()
if stderrdata.find("CRC failed") >= 0: if stderrdata.find("CRC failed") >= 0 or stderrdata.find("Checksum error") >= 0:
raise IncorrectRARPassword raise IncorrectRARPassword
return res return res