mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
libunrar.py with support for extracting files from archive
This commit is contained in:
parent
99e11d3693
commit
bc4e05a417
190
src/libprs500/libunrar.py
Normal file
190
src/libprs500/libunrar.py
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
## Copyright (C) 2006 Kovid Goyal kovid@kovidgoyal.net
|
||||||
|
## This program is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License along
|
||||||
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
This module provides a thin ctypes based wrapper around libunrar.
|
||||||
|
|
||||||
|
See ftp://ftp.rarlabs.com/rar/unrarsrc-3.7.5.tar.gz
|
||||||
|
"""
|
||||||
|
from ctypes import Structure, c_char_p, c_uint, c_void_p, POINTER, \
|
||||||
|
byref, c_wchar_p, CFUNCTYPE, c_int, c_long, c_char, c_wchar
|
||||||
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
from libprs500 import iswindows
|
||||||
|
|
||||||
|
_librar_name = 'libunrar.so'
|
||||||
|
if iswindows:
|
||||||
|
Structure._pack_ = 1
|
||||||
|
_librar_name = 'unrar'
|
||||||
|
from ctypes import windll
|
||||||
|
_libunrar = windll.LoadLibrary('unrar')
|
||||||
|
else:
|
||||||
|
from ctypes import cdll
|
||||||
|
_libunrar = cdll.LoadLibrary(_librar_name)
|
||||||
|
|
||||||
|
RAR_OM_LIST = 0
|
||||||
|
RAR_OM_EXTRACT = 1
|
||||||
|
|
||||||
|
ERAR_END_ARCHIVE = 10
|
||||||
|
ERAR_NO_MEMORY = 11
|
||||||
|
ERAR_BAD_DATA = 12
|
||||||
|
ERAR_BAD_ARCHIVE = 13
|
||||||
|
ERAR_UNKNOWN_FORMAT = 14
|
||||||
|
ERAR_EOPEN = 15
|
||||||
|
ERAR_ECREATE = 16
|
||||||
|
ERAR_ECLOSE = 17
|
||||||
|
ERAR_EREAD = 18
|
||||||
|
ERAR_EWRITE = 19
|
||||||
|
ERAR_SMALL_BUF = 20
|
||||||
|
ERAR_UNKNOWN = 21
|
||||||
|
ERAR_MISSING_PASSWORD = 22
|
||||||
|
|
||||||
|
RAR_VOL_ASK = 0
|
||||||
|
RAR_VOL_NOTIFY = 1
|
||||||
|
|
||||||
|
RAR_SKIP = 0
|
||||||
|
RAR_TEST = 1
|
||||||
|
RAR_EXTRACT = 2
|
||||||
|
|
||||||
|
class UnRARException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class RAROpenArchiveDataEx(Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('ArcName', c_char_p),
|
||||||
|
('ArcNameW', c_wchar_p),
|
||||||
|
('OpenMode', c_uint),
|
||||||
|
('OpenResult', c_uint),
|
||||||
|
('CmtBuf', c_char_p),
|
||||||
|
('CmtBufSize', c_uint),
|
||||||
|
('CmtSize', c_uint),
|
||||||
|
('CmtState', c_uint),
|
||||||
|
('Flags', c_uint),
|
||||||
|
('Reserved', c_uint * 32)
|
||||||
|
]
|
||||||
|
|
||||||
|
class RARHeaderDataEx(Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('ArcName', c_char*1024),
|
||||||
|
('ArcNameW', c_wchar*1024),
|
||||||
|
('FileName', c_char*1024),
|
||||||
|
('FileNameW', c_wchar*1024),
|
||||||
|
('Flags', c_uint),
|
||||||
|
('PackSize', c_uint),
|
||||||
|
('PackSizeHigh', c_uint),
|
||||||
|
('UnpSize', c_uint),
|
||||||
|
('UnpSizeHigh', c_uint),
|
||||||
|
('HostOS', c_uint),
|
||||||
|
('FileCRC', c_uint),
|
||||||
|
('FileTime', c_uint),
|
||||||
|
('UnpVer', c_uint),
|
||||||
|
('Method', c_uint),
|
||||||
|
('FileAttr', c_uint),
|
||||||
|
('CmtBuf', c_char_p),
|
||||||
|
('CmtBufSize', c_uint),
|
||||||
|
('CmtSize', c_uint),
|
||||||
|
('CmtState', c_uint),
|
||||||
|
('Reserved', c_uint*1024)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Define a callback function
|
||||||
|
#CALLBACK_FUNC = CFUNCTYPE(c_int, c_uint, c_long, c_char_p, c_long)
|
||||||
|
#def py_callback_func(msg, user_data, p1, p2):
|
||||||
|
# return 0
|
||||||
|
|
||||||
|
#callback_func = CALLBACK_FUNC(py_callback_func)
|
||||||
|
|
||||||
|
_libunrar.RAROpenArchiveEx.argtypes = [POINTER(RAROpenArchiveDataEx)]
|
||||||
|
_libunrar.RAROpenArchiveEx.restype = c_void_p
|
||||||
|
_libunrar.RARReadHeaderEx.argtypes = [c_void_p, POINTER(RARHeaderDataEx)]
|
||||||
|
_libunrar.RARReadHeaderEx.restype = c_int
|
||||||
|
_libunrar.RARProcessFileW.argtypes = [c_void_p, c_int, c_wchar_p, c_wchar_p]
|
||||||
|
_libunrar.RARProcessFileW.restype = c_int
|
||||||
|
_libunrar.RARCloseArchive.argtypes = [c_void_p]
|
||||||
|
_libunrar.RARCloseArchive.restype = c_int
|
||||||
|
_libunrar.RARSetPassword.argtypes = [c_void_p, c_char_p]
|
||||||
|
#_libunrar.RARSetCallback.argtypes = [c_void_p, CALLBACK_FUNC, c_long]
|
||||||
|
|
||||||
|
|
||||||
|
def _interpret_open_error(code, path):
|
||||||
|
msg = 'Unknown error.'
|
||||||
|
if code == ERAR_NO_MEMORY:
|
||||||
|
msg = "Not enough memory to process " + path
|
||||||
|
elif code == ERAR_BAD_DATA:
|
||||||
|
msg = "Archive header broken: " + path
|
||||||
|
elif code == ERAR_BAD_ARCHIVE:
|
||||||
|
msg = path + ' is not a RAR archive.'
|
||||||
|
elif code == ERAR_EOPEN:
|
||||||
|
msg = 'Cannot open ' + path
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def _interpret_process_file_error(code):
|
||||||
|
msg = 'Unknown Error'
|
||||||
|
if code == ERAR_UNKNOWN_FORMAT:
|
||||||
|
msg = 'Unknown archive format'
|
||||||
|
elif code == ERAR_BAD_ARCHIVE:
|
||||||
|
msg = 'Bad volume'
|
||||||
|
elif code == ERAR_ECREATE:
|
||||||
|
msg = 'File create error'
|
||||||
|
elif code == ERAR_EOPEN:
|
||||||
|
msg = 'Volume open error'
|
||||||
|
elif code == ERAR_ECLOSE:
|
||||||
|
msg = 'File close error'
|
||||||
|
elif code == ERAR_EREAD:
|
||||||
|
msg = 'Read error'
|
||||||
|
elif code == ERAR_EWRITE:
|
||||||
|
msg = 'Write error'
|
||||||
|
elif code == ERAR_BAD_DATA:
|
||||||
|
msg = 'CRC error'
|
||||||
|
elif code == ERAR_MISSING_PASSWORD:
|
||||||
|
msg = 'Password is required.'
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def get_archive_info(flags):
|
||||||
|
ios = StringIO()
|
||||||
|
print >>ios, 'Volume:\t\t', 'yes' if (flags & 1) else 'no'
|
||||||
|
print >>ios, 'Comment:\t', 'yes' if (flags & 2) else 'no'
|
||||||
|
print >>ios, 'Locked:\t\t', 'yes' if (flags & 4) else 'no'
|
||||||
|
print >>ios, 'Solid:\t\t', 'yes' if (flags & 8) else 'no'
|
||||||
|
print >>ios, 'New naming:\t', 'yes' if (flags & 16) else 'no'
|
||||||
|
print >>ios, 'Authenticity:\t', 'yes' if (flags & 32) else 'no'
|
||||||
|
print >>ios, 'Recovery:\t', 'yes' if (flags & 64) else 'no'
|
||||||
|
print >>ios, 'Encr.headers:\t', 'yes' if (flags & 128) else 'no'
|
||||||
|
print >>ios, 'First Volume:\t', 'yes' if (flags & 256) else 'no or older than 3.0'
|
||||||
|
return ios.getvalue()
|
||||||
|
|
||||||
|
def extract(path):
|
||||||
|
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))
|
||||||
|
print 'Archive:', path
|
||||||
|
print get_archive_info(open_archive_data.Flags)
|
||||||
|
header_data = RARHeaderDataEx(CmtBuf=None)
|
||||||
|
#_libunrar.RARSetCallback(arc_data, callback_func, mode)
|
||||||
|
while True:
|
||||||
|
RHCode = _libunrar.RARReadHeaderEx(arc_data, byref(header_data))
|
||||||
|
if RHCode != 0:
|
||||||
|
break
|
||||||
|
PFCode = _libunrar.RARProcessFileW(arc_data, RAR_EXTRACT, None, None)
|
||||||
|
if PFCode != 0:
|
||||||
|
raise UnRARException(_interpret_process_file_error(PFCode))
|
||||||
|
if RHCode == ERAR_BAD_DATA:
|
||||||
|
raise UnRARException('File header broken')
|
||||||
|
finally:
|
||||||
|
_libunrar.RARCloseArchive(arc_data)
|
||||||
|
|
||||||
|
extract(r'z:\home\test.rar')
|
||||||
|
#extract('/home/kovid/ero/Fansadox Collections/C21 Ponygirl Inferno.rar')
|
Loading…
x
Reference in New Issue
Block a user