diff --git a/src/calibre/libunrar.py b/src/calibre/libunrar.py index bff284d4c8..bf38a47d64 100644 --- a/src/calibre/libunrar.py +++ b/src/calibre/libunrar.py @@ -217,7 +217,41 @@ def names(path): finally: _libunrar.RARCloseArchive(arc_data) -def extract_member(path, match=re.compile(r'\.(jpg|jpeg|gif|png)\s*$', re.I), name=None): +def _extract_member(path, match, name): + + def is_match(fname): + return (name is not None and fname == name) or \ + (match is not None and match.search(fname) is not None) + + open_archive_data = RAROpenArchiveDataEx(ArcName=path, OpenMode=RAR_OM_EXTRACT, CmtBuf=None) + arc_data = _libunrar.RAROpenArchiveEx(byref(open_archive_data)) + try: + if open_archive_data.OpenResult != 0: + raise UnRARException(_interpret_open_error(open_archive_data.OpenResult, path)) + header_data = RARHeaderDataEx(CmtBuf=None) + first = True + while True: + if _libunrar.RARReadHeaderEx(arc_data, byref(header_data)) != 0: + raise UnRARException('%s has no files'%path if first + else 'No match found in %s'%path) + file_name = header_data.FileNameW + if is_match(file_name): + PFCode = _libunrar.RARProcessFileW(arc_data, RAR_EXTRACT, None, None) + if PFCode != 0: + raise UnRARException(_interpret_process_file_error(PFCode)) + abspath = os.path.abspath(*file_name.split('/')) + return abspath + else: + PFCode = _libunrar.RARProcessFileW(arc_data, RAR_SKIP, None, None) + if PFCode != 0: + raise UnRARException(_interpret_process_file_error(PFCode)) + first = False + + finally: + _libunrar.RARCloseArchive(arc_data) + +def extract_member(path, match=re.compile(r'\.(jpg|jpeg|gif|png)\s*$', re.I), + name=None, as_file=False): if hasattr(path, 'read'): data = path.read() f = NamedTemporaryFile(suffix='.rar') @@ -225,34 +259,13 @@ def extract_member(path, match=re.compile(r'\.(jpg|jpeg|gif|png)\s*$', re.I), na f.flush() path = f.name - def is_match(fname): - return (name is not None and fname == name) or \ - (match is not None and match.search(fname)) - - with TemporaryDirectory('_libunrar') as dir: - with CurrentDir(dir): - open_archive_data = RAROpenArchiveDataEx(ArcName=path, OpenMode=RAR_OM_EXTRACT, CmtBuf=None) - arc_data = _libunrar.RAROpenArchiveEx(byref(open_archive_data)) - try: - if open_archive_data.OpenResult != 0: - raise UnRARException(_interpret_open_error(open_archive_data.OpenResult, path)) - header_data = RARHeaderDataEx(CmtBuf=None) - while True: - if _libunrar.RARReadHeaderEx(arc_data, byref(header_data)) != 0: - raise UnRARException('%s has no files'%path) - file_name = header_data.FileNameW - if is_match(file_name): - PFCode = _libunrar.RARProcessFileW(arc_data, RAR_EXTRACT, None, None) - if PFCode != 0: - raise UnRARException(_interpret_process_file_error(PFCode)) - return header_data.FileNameW.replace('/', os.sep), \ - open(os.path.join(dir, *header_data.FileNameW.split('/')), 'rb').read() - else: - PFCode = _libunrar.RARProcessFileW(arc_data, RAR_SKIP, None, None) - if PFCode != 0: - raise UnRARException(_interpret_process_file_error(PFCode)) - - finally: - _libunrar.RARCloseArchive(arc_data) - + path = os.path.abspath(path) + if as_file: + path = _extract_member(path, match, name) + return path, open(path, 'rb') + else: + with TemporaryDirectory('_libunrar') as tdir: + with CurrentDir(tdir): + path = _extract_member(path, match, name) + return path, open(path, 'rb').read()