Browse Source

Update unrar2

pull/5911/head
Ruud 9 years ago
parent
commit
b41ad8fd86
  1. 8
      libs/unrar2/__init__.py
  2. 76
      libs/unrar2/unix.py
  3. 39
      libs/unrar2/windows.py

8
libs/unrar2/__init__.py

@ -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.
"""
__version__ = '0.99.3'
__version__ = '0.99.6'
try:
WindowsError
@ -159,6 +159,12 @@ class RarFile(RarFileImplementation):
checker = condition2checker(condition)
return RarFileImplementation.extract(self, checker, path, withSubpath, overwrite)
def get_volume(self):
"""Determine which volume is it in a multi-volume archive. Returns None if it's not a
multi-volume archive, 0-based volume number otherwise."""
return RarFileImplementation.get_volume(self)
def condition2checker(condition):
"""Converts different condition types to callback"""
if type(condition) in [str, unicode]:

76
libs/unrar2/unix.py

@ -23,13 +23,14 @@
# Unix version uses unrar command line executable
import platform
import stat
import subprocess
import gc
import os
import os.path
import time
import re
import os, os.path
import time, re
from rar_exceptions import *
from dateutil.parser import parse
from rar_exceptions import *
@ -54,7 +55,7 @@ def call_unrar(params, custom_path = None):
for command in (custom_path, 'unrar', 'rar', osx_unrar):
if not command: continue
try:
subprocess.Popen([command], stdout = subprocess.PIPE)
subprocess.Popen([command], stdout=subprocess.PIPE)
rar_executable_cached = command
break
except OSError:
@ -66,7 +67,7 @@ def call_unrar(params, custom_path = None):
args = [rar_executable_cached] + params
try:
gc.disable() # See http://bugs.python.org/issue1336
return subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
return subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
finally:
gc.enable()
@ -82,18 +83,18 @@ class RarFileImplementation(object):
for line in stderrdata.splitlines():
if line.strip().startswith("Cannot open"):
raise FileOpenError
if line.find("CRC failed") >= 0:
if line.find("CRC failed")>=0:
raise IncorrectRARPassword
accum = []
source = iter(stdoutdata.splitlines())
line = ''
while not (line.startswith('UNRAR')):
while (line.find('RAR ') == -1):
line = source.next()
signature = line
# 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"):
if signature.find("RAR 4") > -1:
rar_executable_version = 4
while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')):
if line.strip().endswith('is not RAR archive'):
@ -107,7 +108,7 @@ class RarFileImplementation(object):
self.comment = '\n'.join(accum[:-1])
else:
self.comment = None
elif signature.startswith("UNRAR 5"):
elif signature.find("RAR 5") > -1:
rar_executable_version = 5
line = source.next()
while not line.startswith('Archive:'):
@ -128,9 +129,9 @@ class RarFileImplementation(object):
return '-' if self.password == None else self.password
def call(self, cmd, options = [], files = []):
options2 = options + ['p' + self.escaped_password()]
soptions = ['-' + x for x in options2]
def call(self, cmd, options=[], files=[]):
options2 = options + ['p'+self.escaped_password()]
soptions = ['-'+x for x in options2]
return call_unrar([cmd] + soptions + ['--', self.archiveName] + files, self.custom_path)
def infoiter(self):
@ -157,7 +158,7 @@ class RarFileImplementation(object):
if rar_executable_version == 4:
while not line.startswith('-----------'):
accum.append(line)
if len(accum) == 2:
if len(accum)==2:
data = {}
data['index'] = i
# asterisks mark password-encrypted files
@ -166,8 +167,9 @@ class RarFileImplementation(object):
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['datetime'] = time.strptime(fields[3]+" "+fields[4], '%d-%m-%y %H:%M')
data['comment'] = None
data['volume'] = None
yield data
accum = []
i += 1
@ -183,6 +185,7 @@ class RarFileImplementation(object):
data['isdir'] = 'd' in attr.lower()
data['datetime'] = parse(fields[2] + " " + fields[3]).timetuple()
data['comment'] = None
data['volume'] = None
yield data
i += 1
line = source.next()
@ -192,7 +195,7 @@ class RarFileImplementation(object):
res = []
for info in self.infoiter():
checkres = checker(info)
if checkres == True and not info.isdir:
if checkres==True and not info.isdir:
pipe = self.call('p', ['inul'], [info.filename]).stdout
res.append((info, pipe.read()))
return res
@ -215,17 +218,54 @@ class RarFileImplementation(object):
checkres = checker(info)
if type(checkres) in [str, unicode]:
raise NotImplementedError("Condition callbacks returning strings are deprecated and only supported in Windows")
if checkres == True and not info.isdir:
if checkres==True and not info.isdir:
names.append(info.filename)
res.append(info)
names.append(path)
proc = self.call(command, options, names)
stdoutdata, stderrdata = proc.communicate()
if stderrdata.find("CRC failed") >= 0 or stderrdata.find("Checksum error") >= 0:
if stderrdata.find("CRC failed")>=0 or stderrdata.find("Checksum error")>=0:
raise IncorrectRARPassword
return res
def destruct(self):
pass
def get_volume(self):
command = "v" if rar_executable_version == 4 else "l"
stdoutdata, stderrdata = self.call(command, ['c-']).communicate()
for line in stderrdata.splitlines():
if line.strip().startswith("Cannot open"):
raise FileOpenError
source = iter(stdoutdata.splitlines())
line = ''
while not line.startswith('-----------'):
if line.strip().endswith('is not RAR archive'):
raise InvalidRARArchive
if line.startswith("CRC failed") or line.startswith("Checksum error"):
raise IncorrectRARPassword
line = source.next()
line = source.next()
if rar_executable_version == 4:
while not line.startswith('-----------'):
line = source.next()
line = source.next()
items = line.strip().split()
if len(items)>4 and items[4]=="volume":
return int(items[5]) - 1
else:
return None
elif rar_executable_version == 5:
while not line.startswith('-----------'):
line = source.next()
line = source.next()
items = line.strip().split()
if items[1]=="volume":
return int(items[2]) - 1
else:
return None

39
libs/unrar2/windows.py

@ -25,8 +25,9 @@
from __future__ import generators
from couchpotato.environment import Env
from shutil import copyfile
import ctypes.wintypes
import os.path
import ctypes, ctypes.wintypes
import os, os.path, re
import time
from rar_exceptions import *
@ -43,6 +44,7 @@ ERAR_EREAD = 18
ERAR_EWRITE = 19
ERAR_SMALL_BUF = 20
ERAR_UNKNOWN = 21
ERAR_MISSING_PASSWORD = 22
RAR_OM_LIST = 0
RAR_OM_EXTRACT = 1
@ -75,8 +77,12 @@ if os.path.isfile(dll_copy):
copyfile(dll_file, dll_copy)
unrar = ctypes.WinDLL(dll_copy)
volume_naming1 = re.compile("\.r([0-9]{2})$")
volume_naming2 = re.compile("\.([0-9]{3}).rar$")
volume_naming3 = re.compile("\.part([0-9]+).rar$")
unrar = ctypes.WinDLL(dll_copy)
class RAROpenArchiveDataEx(ctypes.Structure):
def __init__(self, ArcName=None, ArcNameW=u'', OpenMode=RAR_OM_LIST):
@ -193,7 +199,7 @@ class RarInfoIterator(object):
self.index = 0
self.headerData = RARHeaderDataEx()
self.res = RARReadHeaderEx(self.arc._handle, ctypes.byref(self.headerData))
if self.res==ERAR_BAD_DATA:
if self.res in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]:
raise IncorrectRARPassword
self.arc.lockStatus = "locked"
self.arc.needskip = False
@ -213,7 +219,7 @@ class RarInfoIterator(object):
data = {}
data['index'] = self.index
data['filename'] = self.headerData.FileName
data['filename'] = self.headerData.FileNameW
data['datetime'] = DosDateTimeToTimeTuple(self.headerData.FileTime)
data['isdir'] = ((self.headerData.Flags & 0xE0) == 0xE0)
data['size'] = self.headerData.UnpSize + (self.headerData.UnpSizeHigh << 32)
@ -257,6 +263,7 @@ class RarFileImplementation(object):
self.lockStatus = "ready"
self.isVolume = archiveData.Flags & 1
def destruct(self):
@ -282,7 +289,7 @@ class RarFileImplementation(object):
c_callback = UNRARCALLBACK(reader._callback)
RARSetCallback(self._handle, c_callback, 1)
tmpres = RARProcessFile(self._handle, RAR_TEST, None, None)
if tmpres==ERAR_BAD_DATA:
if tmpres in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]:
raise IncorrectRARPassword
self.needskip = False
res.append((info, reader.get_result()))
@ -304,11 +311,29 @@ class RarFileImplementation(object):
target = checkres
if overwrite or (not os.path.exists(target)):
tmpres = RARProcessFile(self._handle, RAR_EXTRACT, None, target)
if tmpres==ERAR_BAD_DATA:
if tmpres in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]:
raise IncorrectRARPassword
self.needskip = False
res.append(info)
return res
def get_volume(self):
if not self.isVolume:
return None
headerData = RARHeaderDataEx()
res = RARReadHeaderEx(self._handle, ctypes.byref(headerData))
arcName = headerData.ArcNameW
match3 = volume_naming3.search(arcName)
if match3 != None:
return int(match3.group(1)) - 1
match2 = volume_naming3.search(arcName)
if match2 != None:
return int(match2.group(1))
match1 = volume_naming1.search(arcName)
if match1 != None:
return int(match1.group(1)) + 1
return 0

Loading…
Cancel
Save