Browse Source

Update unrar2

pull/5911/head
Ruud 9 years ago
parent
commit
b41ad8fd86
  1. 8
      libs/unrar2/__init__.py
  2. 54
      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. higher level interface which makes some common operations easier.
""" """
__version__ = '0.99.3' __version__ = '0.99.6'
try: try:
WindowsError WindowsError
@ -159,6 +159,12 @@ class RarFile(RarFileImplementation):
checker = condition2checker(condition) checker = condition2checker(condition)
return RarFileImplementation.extract(self, checker, path, withSubpath, overwrite) 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): def condition2checker(condition):
"""Converts different condition types to callback""" """Converts different condition types to callback"""
if type(condition) in [str, unicode]: if type(condition) in [str, unicode]:

54
libs/unrar2/unix.py

@ -23,13 +23,14 @@
# Unix version uses unrar command line executable # Unix version uses unrar command line executable
import platform import platform
import stat import stat
import subprocess import subprocess
import gc 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 dateutil.parser import parse
from rar_exceptions import * from rar_exceptions import *
@ -87,13 +88,13 @@ class RarFileImplementation(object):
accum = [] accum = []
source = iter(stdoutdata.splitlines()) source = iter(stdoutdata.splitlines())
line = '' line = ''
while not (line.startswith('UNRAR')): while (line.find('RAR ') == -1):
line = source.next() line = source.next()
signature = line signature = line
# The code below is mighty flaky # The code below is mighty flaky
# and will probably crash on localized versions of RAR # and will probably crash on localized versions of RAR
# but I see no safe way to rewrite it using a CLI tool # 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 rar_executable_version = 4
while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')): while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')):
if line.strip().endswith('is not RAR archive'): if line.strip().endswith('is not RAR archive'):
@ -107,7 +108,7 @@ class RarFileImplementation(object):
self.comment = '\n'.join(accum[:-1]) self.comment = '\n'.join(accum[:-1])
else: else:
self.comment = None self.comment = None
elif signature.startswith("UNRAR 5"): elif signature.find("RAR 5") > -1:
rar_executable_version = 5 rar_executable_version = 5
line = source.next() line = source.next()
while not line.startswith('Archive:'): while not line.startswith('Archive:'):
@ -168,6 +169,7 @@ class RarFileImplementation(object):
data['isdir'] = 'd' in attr.lower() 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['comment'] = None
data['volume'] = None
yield data yield data
accum = [] accum = []
i += 1 i += 1
@ -183,6 +185,7 @@ class RarFileImplementation(object):
data['isdir'] = 'd' in attr.lower() data['isdir'] = 'd' in attr.lower()
data['datetime'] = parse(fields[2] + " " + fields[3]).timetuple() data['datetime'] = parse(fields[2] + " " + fields[3]).timetuple()
data['comment'] = None data['comment'] = None
data['volume'] = None
yield data yield data
i += 1 i += 1
line = source.next() line = source.next()
@ -228,4 +231,41 @@ class RarFileImplementation(object):
def destruct(self): def destruct(self):
pass 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 __future__ import generators
from couchpotato.environment import Env from couchpotato.environment import Env
from shutil import copyfile from shutil import copyfile
import ctypes.wintypes
import os.path import ctypes, ctypes.wintypes
import os, os.path, re
import time import time
from rar_exceptions import * from rar_exceptions import *
@ -43,6 +44,7 @@ ERAR_EREAD = 18
ERAR_EWRITE = 19 ERAR_EWRITE = 19
ERAR_SMALL_BUF = 20 ERAR_SMALL_BUF = 20
ERAR_UNKNOWN = 21 ERAR_UNKNOWN = 21
ERAR_MISSING_PASSWORD = 22
RAR_OM_LIST = 0 RAR_OM_LIST = 0
RAR_OM_EXTRACT = 1 RAR_OM_EXTRACT = 1
@ -75,8 +77,12 @@ if os.path.isfile(dll_copy):
copyfile(dll_file, 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): class RAROpenArchiveDataEx(ctypes.Structure):
def __init__(self, ArcName=None, ArcNameW=u'', OpenMode=RAR_OM_LIST): def __init__(self, ArcName=None, ArcNameW=u'', OpenMode=RAR_OM_LIST):
@ -193,7 +199,7 @@ class RarInfoIterator(object):
self.index = 0 self.index = 0
self.headerData = RARHeaderDataEx() self.headerData = RARHeaderDataEx()
self.res = RARReadHeaderEx(self.arc._handle, ctypes.byref(self.headerData)) 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 raise IncorrectRARPassword
self.arc.lockStatus = "locked" self.arc.lockStatus = "locked"
self.arc.needskip = False self.arc.needskip = False
@ -213,7 +219,7 @@ class RarInfoIterator(object):
data = {} data = {}
data['index'] = self.index data['index'] = self.index
data['filename'] = self.headerData.FileName data['filename'] = self.headerData.FileNameW
data['datetime'] = DosDateTimeToTimeTuple(self.headerData.FileTime) data['datetime'] = DosDateTimeToTimeTuple(self.headerData.FileTime)
data['isdir'] = ((self.headerData.Flags & 0xE0) == 0xE0) data['isdir'] = ((self.headerData.Flags & 0xE0) == 0xE0)
data['size'] = self.headerData.UnpSize + (self.headerData.UnpSizeHigh << 32) data['size'] = self.headerData.UnpSize + (self.headerData.UnpSizeHigh << 32)
@ -257,6 +263,7 @@ class RarFileImplementation(object):
self.lockStatus = "ready" self.lockStatus = "ready"
self.isVolume = archiveData.Flags & 1
def destruct(self): def destruct(self):
@ -282,7 +289,7 @@ class RarFileImplementation(object):
c_callback = UNRARCALLBACK(reader._callback) c_callback = UNRARCALLBACK(reader._callback)
RARSetCallback(self._handle, c_callback, 1) RARSetCallback(self._handle, c_callback, 1)
tmpres = RARProcessFile(self._handle, RAR_TEST, None, None) tmpres = RARProcessFile(self._handle, RAR_TEST, None, None)
if tmpres==ERAR_BAD_DATA: if tmpres in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]:
raise IncorrectRARPassword raise IncorrectRARPassword
self.needskip = False self.needskip = False
res.append((info, reader.get_result())) res.append((info, reader.get_result()))
@ -304,11 +311,29 @@ class RarFileImplementation(object):
target = checkres target = checkres
if overwrite or (not os.path.exists(target)): if overwrite or (not os.path.exists(target)):
tmpres = RARProcessFile(self._handle, RAR_EXTRACT, None, 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 raise IncorrectRARPassword
self.needskip = False self.needskip = False
res.append(info) res.append(info)
return res 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