openmedialibrary_platform/Shared/lib/python3.7/site-packages/unrar/unrarlib.py
2019-01-29 16:10:06 +05:30

254 lines
8.6 KiB
Python

# -*- coding: utf-8 -*-
# Copyright (C) 2012 Matias Bordese
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
import ctypes
import os
import platform
from ctypes.util import find_library
from unrar import constants
__all__ = ["RAROpenArchiveDataEx", "RARHeaderDataEx", "RAROpenArchiveEx",
"RARCloseArchive", "RARReadHeaderEx", "RARProcessFile",
"RARSetPassword", "RARGetDllVersion", "RARSetCallback",
"dostime_to_timetuple"]
lib_path = os.environ.get('UNRAR_LIB_PATH', None)
# find and load unrar library
unrarlib = None
if platform.system() == 'Windows':
from ctypes.wintypes import HANDLE as WIN_HANDLE
HANDLE = WIN_HANDLE
UNRARCALLBACK = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_uint,
ctypes.c_long, ctypes.c_long,
ctypes.c_long)
lib_path = lib_path or find_library("unrar.dll")
if lib_path:
unrarlib = ctypes.WinDLL(lib_path)
else:
# assume unix
HANDLE = ctypes.c_void_p
UNRARCALLBACK = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_uint,
ctypes.c_long, ctypes.c_long,
ctypes.c_long)
lib_path = lib_path or find_library("unrar")
if lib_path:
unrarlib = ctypes.cdll.LoadLibrary(lib_path)
if unrarlib is None:
raise LookupError("Couldn't find path to unrar library.")
def dostime_to_timetuple(dostime):
"""Convert a RAR archive member DOS time to a Python time tuple."""
dostime = dostime >> 16
dostime = dostime & 0xffff
day = dostime & 0x1f
month = (dostime >> 5) & 0xf
year = 1980 + (dostime >> 9)
second = 2 * (dostime & 0x1f)
minute = (dostime >> 5) & 0x3f
hour = dostime >> 11
return (year, month, day, hour, minute, second)
class UnrarException(Exception):
"""Lib errors exception."""
class _Structure(ctypes.Structure):
"""Customized ctypes Structure base class."""
def __repr__(self):
"""Print the structure fields."""
res = []
for field in self._fields_:
field_value = repr(getattr(self, field[0]))
res.append('%s=%s' % (field[0], field_value))
return self.__class__.__name__ + '(' + ','.join(res) + ')'
class RAROpenArchiveDataEx(_Structure):
"""Rar compressed file structure."""
_fields_ = [
('ArcName', ctypes.c_char_p),
('ArcNameW', ctypes.c_wchar_p),
('OpenMode', ctypes.c_uint),
('OpenResult', ctypes.c_uint),
('_CmtBuf', ctypes.c_void_p),
('CmtBufSize', ctypes.c_uint),
('CmtSize', ctypes.c_uint),
('CmtState', ctypes.c_uint),
('Flags', ctypes.c_uint),
('Reserved', ctypes.c_uint * 32),
]
def __init__(self, filename, mode=constants.RAR_OM_LIST):
# comments buffer, max 64kb
self.CmtBuf = ctypes.create_string_buffer(b'', 64 * 1024)
super(RAROpenArchiveDataEx, self).__init__(
ArcName=None,
ArcNameW=filename, OpenMode=mode,
_CmtBuf=ctypes.addressof(self.CmtBuf),
CmtBufSize=ctypes.sizeof(self.CmtBuf))
def __str__(self):
return self.ArcNameW
class RARHeaderDataEx(_Structure):
"""Rar file header structure."""
_fields_ = [
('ArcName', ctypes.c_char * 1024),
('ArcNameW', ctypes.c_wchar * 1024),
('FileName', ctypes.c_char * 1024),
('FileNameW', ctypes.c_wchar * 1024),
('Flags', ctypes.c_uint),
('PackSize', ctypes.c_uint),
('PackSizeHigh', ctypes.c_uint),
('UnpSize', ctypes.c_uint),
('UnpSizeHigh', ctypes.c_uint),
('HostOS', ctypes.c_uint),
('FileCRC', ctypes.c_uint),
('FileTime', ctypes.c_uint),
('UnpVer', ctypes.c_uint),
('Method', ctypes.c_uint),
('FileAttr', ctypes.c_uint),
('_CmtBuf', ctypes.c_void_p),
('CmtBufSize', ctypes.c_uint),
('CmtSize', ctypes.c_uint),
('CmtState', ctypes.c_uint),
('Reserved', ctypes.c_uint * 1024),
]
def __init__(self):
# comments buffer, max 64kb
self.CmtBuf = ctypes.create_string_buffer(b'', 64 * 1024)
super(RARHeaderDataEx, self).__init__(
_CmtBuf=ctypes.addressof(self.CmtBuf),
CmtBufSize=ctypes.sizeof(self.CmtBuf))
def __str__(self):
return self.FileNameW
def _c_func(func, restype, argtypes, errcheck=None):
"""Wrap c function setting prototype."""
func.restype = restype
func.argtypes = argtypes
if errcheck is not None:
func.errcheck = errcheck
return func
def _check_open_result(res, func, args):
if res is None:
raise UnrarException("Archive open error")
# res is the archive handle
return res
def _check_readheader_result(res, func, args):
if res == constants.ERAR_BAD_DATA:
raise UnrarException("Bad header data.")
# res == SUCCESS | res == ERAR_END_ARCHIVE
return res
def _check_process_result(res, func, args):
if res == constants.ERAR_ECLOSE:
raise UnrarException("File close error")
elif res == constants.ERAR_BAD_DATA:
raise UnrarException("File CRC error")
elif res == constants.ERAR_BAD_ARCHIVE:
raise UnrarException("Not valid RAR archive")
elif res == constants.ERAR_UNKNOWN_FORMAT:
raise UnrarException("Unknown archive format")
elif res == constants.ERAR_EOPEN:
raise UnrarException("Volume open error")
elif res == constants.ERAR_ECREATE:
raise UnrarException("File create error")
elif res == constants.ERAR_EREAD:
raise UnrarException("Read error")
elif res == constants.ERAR_EWRITE:
raise UnrarException("Write error")
# res == SUCCESS | res == ERAR_END_ARCHIVE
return res
def _check_close_result(res, func, args):
if res == constants.ERAR_ECLOSE:
raise UnrarException("Archive close error")
# res == SUCCESS
return res
# Return library API version.
RARGetDllVersion = _c_func(unrarlib.RARGetDllVersion, ctypes.c_int, [])
# Open RAR archive and allocate memory structures (unicode)
RAROpenArchiveEx = _c_func(unrarlib.RAROpenArchiveEx, HANDLE,
[ctypes.POINTER(RAROpenArchiveDataEx)],
_check_open_result)
# Set a password to decrypt files.
RARSetPassword = _c_func(unrarlib.RARSetPassword, ctypes.c_int,
[HANDLE, ctypes.c_char_p])
# Read header of file in archive (unicode).
RARReadHeaderEx = _c_func(unrarlib.RARReadHeaderEx, ctypes.c_int,
[HANDLE, ctypes.POINTER(RARHeaderDataEx)],
_check_readheader_result)
# Performs action and moves the current position in the archive to
# the next file. Extract or test the current file from the archive
# opened in RAR_OM_EXTRACT mode. If the mode RAR_OM_LIST is set,
# then a call to this function will simply skip the archive position
# to the next file.
RARProcessFile = _c_func(unrarlib.RARProcessFile, ctypes.c_int,
[HANDLE, ctypes.c_int, ctypes.c_char_p,
ctypes.c_char_p], _check_process_result)
# Performs action and moves the current position in the archive to
# the next file. Extract or test the current file from the archive
# opened in RAR_OM_EXTRACT mode. If the mode RAR_OM_LIST is set,
# then a call to this function will simply skip the archive position
# to the next file. (unicode version)
RARProcessFileW = _c_func(unrarlib.RARProcessFileW, ctypes.c_int,
[HANDLE, ctypes.c_int, ctypes.c_wchar_p,
ctypes.c_wchar_p], _check_process_result)
# Close RAR archive and release allocated memory. It must be called when
# archive processing is finished, even if the archive processing was stopped
# due to an error.
RARCloseArchive = _c_func(unrarlib.RARCloseArchive, ctypes.c_int, [HANDLE],
_check_close_result)
# Set a user-defined callback function to process Unrar events.
RARSetCallback = _c_func(unrarlib.RARSetCallback, None,
[HANDLE, UNRARCALLBACK, ctypes.c_long])