mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-22 06:13:19 -07:00
"universal" unrar support (untested)
also merged clintons last changes please test the unpacker, im unsure if it works example here: http://www.daniweb.com/software-development/python/threads/290366/me-again-how-to-use-unrar2 or in /UnRAR2/test_UnRAR2.py
This commit is contained in:
parent
b9e9f9e225
commit
24d9b815ac
18 changed files with 1782 additions and 101 deletions
|
@ -1,4 +0,0 @@
|
||||||
@echo off
|
|
||||||
echo "Executing nzbToMedia..."
|
|
||||||
C:\Python27\python.exe C:\Downloaders\nzbToMedia\TorrentToMedia.py %TR_TORRENT_DIR% %TR_TORRENT_NAME%
|
|
||||||
pause
|
|
|
@ -11,6 +11,8 @@ from subprocess import call
|
||||||
|
|
||||||
# Custom imports
|
# Custom imports
|
||||||
import linktastic.linktastic as linktastic
|
import linktastic.linktastic as linktastic
|
||||||
|
import UnRAR2
|
||||||
|
from UnRAR2.rar_exceptions import *
|
||||||
import autoProcessMovie
|
import autoProcessMovie
|
||||||
import autoProcessTV
|
import autoProcessTV
|
||||||
from nzbToMediaEnv import *
|
from nzbToMediaEnv import *
|
||||||
|
@ -24,20 +26,12 @@ fileHandler.level = logging.DEBUG
|
||||||
Logger.addHandler(fileHandler)
|
Logger.addHandler(fileHandler)
|
||||||
|
|
||||||
|
|
||||||
def which(program): # Test if command exists
|
def cleanup(outputDestination):
|
||||||
def is_exe(fpath):
|
for path, dirs, files in os.walk(outputDestination):
|
||||||
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
for fn in files:
|
||||||
fpath, fname = os.path.split(program)
|
os.remove(os.path.join(path, fn))
|
||||||
if fpath:
|
for dir in dirs:
|
||||||
if is_exe(program):
|
os.removedirs(os.path.join(path, dir))
|
||||||
return program
|
|
||||||
else:
|
|
||||||
for path in os.environ["PATH"].split(os.pathsep):
|
|
||||||
path = path.strip('"')
|
|
||||||
exe_file = os.path.join(path, program)
|
|
||||||
if is_exe(exe_file):
|
|
||||||
return exe_file
|
|
||||||
return None
|
|
||||||
|
|
||||||
def category_search(inputDirectory, inputCategory, root):
|
def category_search(inputDirectory, inputCategory, root):
|
||||||
categorySearch = os.path.split(os.path.normpath(inputDirectory)) # Test for blackhole sub-directory
|
categorySearch = os.path.split(os.path.normpath(inputDirectory)) # Test for blackhole sub-directory
|
||||||
|
@ -112,57 +106,7 @@ def copy_link(source, target, useLink, outputDestination):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def unpack(dirpath, file, outputDestination):
|
def unpack(dirpath, file, outputDestination):
|
||||||
# Using Windows
|
# Create destination folder
|
||||||
if os.name == 'nt':
|
|
||||||
Logger.info("EXTRACTOR: We are using Windows")
|
|
||||||
if not os.path.exists(extractionTool):
|
|
||||||
Logger.error("Cant find 7-zip, Exiting")
|
|
||||||
sys.exit(-1)
|
|
||||||
else:
|
|
||||||
Logger.debug("EXTRACTOR: 7-zip found")
|
|
||||||
cmd_7zip = [extractionTool, 'x -y'] # We need to add a check if 7zip is actully present, or exit
|
|
||||||
ext_7zip = [".rar",".zip",".tar.gz","tgz",".tar.bz2",".tbz",".tar.lzma",".tlz",".7z",".xz"]
|
|
||||||
EXTRACT_COMMANDS = dict.fromkeys(ext_7zip, cmd_7zip)
|
|
||||||
|
|
||||||
# Using Linux
|
|
||||||
elif os.name == 'posix':
|
|
||||||
Logger.info("EXTRACTOR: We are using *nix")
|
|
||||||
required_cmds=["unrar", "unzip", "tar", "unxz", "unlzma", "7zr"] # Need to add a check for which commands that can be utilized in *nix systems
|
|
||||||
EXTRACT_COMMANDS = {
|
|
||||||
".rar": ["unrar", "x -o+ -y"],
|
|
||||||
".zip": ["unzip", ""],
|
|
||||||
".tar.gz": ["tar", "xzf"],
|
|
||||||
".tgz": ["tar", "xzf"],
|
|
||||||
".tar.bz2": ["tar", "xjf"],
|
|
||||||
".tbz": ["tar", "xjf"],
|
|
||||||
".tar.lzma": ["tar", "--lzma xf"],
|
|
||||||
".tlz": ["tar", "--lzma xf"],
|
|
||||||
".txz": ["tar", "--xz xf"],
|
|
||||||
".7z": ["7zr", "x"],
|
|
||||||
}
|
|
||||||
for cmd in required_cmds:
|
|
||||||
if not which(cmd):
|
|
||||||
for k,v in EXTRACT_COMMANDS.items():
|
|
||||||
if cmd in v[0]:
|
|
||||||
Logger.debug("EXTRACTOR: Command %s not found, disabling support for %s", cmd, k)
|
|
||||||
del EXTRACT_COMMANDS[k]
|
|
||||||
else:
|
|
||||||
Logger.error("EXTRACTOR: Cant determine host OS while extracting, Exiting")
|
|
||||||
|
|
||||||
ext = os.path.splitext(file)
|
|
||||||
fp = os.path.join(dirpath, file)
|
|
||||||
if ext[1] in (".gz", ".bz2", ".lzma"):
|
|
||||||
# Check if this is a tar
|
|
||||||
if os.path.splitext(ext[0])[1] == ".tar":
|
|
||||||
cmd = EXTRACT_COMMANDS[".tar" + ext[1]]
|
|
||||||
else:
|
|
||||||
if ext[1] in EXTRACT_COMMANDS:
|
|
||||||
cmd = EXTRACT_COMMANDS[ext[1]]
|
|
||||||
else:
|
|
||||||
Logger.debug("EXTRACTOR: Unknown file type: %s", ext[1])
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Create destination folder
|
|
||||||
if not os.path.exists(outputDestination):
|
if not os.path.exists(outputDestination):
|
||||||
try:
|
try:
|
||||||
Logger.debug("EXTRACTOR: Creating destination folder: %s", outputDestination)
|
Logger.debug("EXTRACTOR: Creating destination folder: %s", outputDestination)
|
||||||
|
@ -170,35 +114,16 @@ def unpack(dirpath, file, outputDestination):
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
Logger.error("EXTRACTOR: Not possible to create destination folder: %s", e)
|
Logger.error("EXTRACTOR: Not possible to create destination folder: %s", e)
|
||||||
return False
|
return False
|
||||||
|
path = os.path.join(dirpath, file)
|
||||||
Logger.info("EXTRACTOR: Extracting %s to %s", fp, outputDestination)
|
try:
|
||||||
# Running extraction process
|
archive = UnRAR2.RarFile(path)
|
||||||
Logger.debug("EXTRACTOR: Extracting %s %s %s %s", cmd[0], cmd[1], fp, outputDestination)
|
for rarinfo in archive.infoiter():
|
||||||
pwd = os.getcwd() # Get our present working directory
|
name = rarinfo.filename
|
||||||
os.chdir(outputDestination) # Not all unpack commands accept full paths, so just extract into this directory
|
archive.extract(name, outputDestination)
|
||||||
if os.name == 'nt': # Windows needs quotes around directory structure
|
Logger.error("EXTRACTOR: Files extracted from %s to %s", path, outputDestination)
|
||||||
try:
|
except Exception, e:
|
||||||
run = "\"" + cmd[0] + "\" " + cmd[1] + " \"" + fp + "\"" # Windows needs quotes around directories
|
Logger.error("EXTRACTOR: Extraction process failed: %s", e)
|
||||||
res = call(run)
|
sys.exit(-1)
|
||||||
if res == 0:
|
|
||||||
Logger.info("EXTRACTOR: Extraction was successful for %s to %s", fp, outputDestination)
|
|
||||||
else:
|
|
||||||
Logger.error("EXTRACTOR: Extraction failed for %s. 7zip result was %s", fp, res)
|
|
||||||
except:
|
|
||||||
Logger.error("EXTRACTOR: Extraction failed for %s. Could not call command %s", fp, run)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
if cmd[1] == "": # If calling unzip, we dont want to pass the ""
|
|
||||||
res = call([cmd[0], fp])
|
|
||||||
else:
|
|
||||||
res = call([cmd[0], cmd[1], fp])
|
|
||||||
if res == 0:
|
|
||||||
Logger.info("EXTRACTOR: Extraction was successful for %s to %s", fp, outputDestination)
|
|
||||||
else:
|
|
||||||
Logger.error("EXTRACTOR: Extraction failed for %s. 7zip result was %s", fp, res)
|
|
||||||
except:
|
|
||||||
Logger.error("EXTRACTOR: Extraction failed for %s. Could not call command %s %s %s %s", fp, cmd[0], cmd[1], fp)
|
|
||||||
os.chdir(pwd) # Go back to our Original Working Directory
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def flatten(outputDestination):
|
def flatten(outputDestination):
|
||||||
|
@ -293,8 +218,9 @@ else:
|
||||||
for file in filenames:
|
for file in filenames:
|
||||||
if root == 1:
|
if root == 1:
|
||||||
Logger.debug("MAIN: Looking for %s in filename", inputName)
|
Logger.debug("MAIN: Looking for %s in filename", inputName)
|
||||||
if (inputName in file) or (file in inputName):
|
if (inputName in file) or (os.path.splitext(file)[0] in inputName):
|
||||||
pass # This file does match the Torrent name
|
pass # This file does match the Torrent name
|
||||||
|
logger.debug("Found file %s that matches Torrent Name %s", file, inputName)
|
||||||
else:
|
else:
|
||||||
continue # This file does not match the Torrent name, skip it
|
continue # This file does not match the Torrent name, skip it
|
||||||
filePath = os.path.join(dirpath, file)
|
filePath = os.path.join(dirpath, file)
|
||||||
|
@ -336,20 +262,29 @@ else:
|
||||||
filePath = os.path.join(dirpath, file)
|
filePath = os.path.join(dirpath, file)
|
||||||
fileExtention = os.path.splitext(file)[1]
|
fileExtention = os.path.splitext(file)[1]
|
||||||
if fileExtention in mediaContainer: # If the file is a video file
|
if fileExtention in mediaContainer: # If the file is a video file
|
||||||
video2 = video2 + 1
|
if is_sample(file_path, Name):
|
||||||
|
Logger.info("file %s is a sample file. Removing", file_path)
|
||||||
|
os.unlink(file_path) #remove samples
|
||||||
|
else:
|
||||||
|
video2 = video2 + 1
|
||||||
if video2 >= video and video2 > 0: # Check that all video files were moved
|
if video2 >= video and video2 > 0: # Check that all video files were moved
|
||||||
status = 0
|
status = 0
|
||||||
|
|
||||||
if status == 0:
|
if status == 0:
|
||||||
Logger.info("MAIN: Successful run")
|
Logger.info("MAIN: Successful run")
|
||||||
# Now we pass off to CouchPotato or Sick-Beard
|
# Now we pass off to CouchPotato or Sick-Beard
|
||||||
# Still need to figure out how to log this output
|
## log this output.
|
||||||
|
old_stdout = sys.stdout ## Still crude, but we wat to capture this for now.
|
||||||
|
log_file = open(logFile,"a+")
|
||||||
|
sys.stdout = log_file
|
||||||
if inputCategory == movieCategory:
|
if inputCategory == movieCategory:
|
||||||
Logger.info("MAIN: Calling postprocessing script for CouchPotatoServer")
|
Logger.info("MAIN: Calling postprocessing script for CouchPotatoServer")
|
||||||
autoProcessMovie.process(outputDestination, inputName, status)
|
autoProcessMovie.process(outputDestination, inputName, status)
|
||||||
elif inputCategory == tvCategory:
|
elif inputCategory == tvCategory:
|
||||||
Logger.info("MAIN: Calling postprocessing script for Sick-Beard")
|
Logger.info("MAIN: Calling postprocessing script for Sick-Beard")
|
||||||
autoProcessTV.processEpisode(outputDestination, inputName, status)
|
autoProcessTV.processEpisode(outputDestination, inputName, status)
|
||||||
|
sys.stdout = old_stdout
|
||||||
|
log_file.close()
|
||||||
else:
|
else:
|
||||||
Logger.info("MAIN: Something failed! :(")
|
Logger.info("MAIN: Something failed! :(")
|
||||||
else:
|
else:
|
||||||
|
|
18
UnRAR2/UnRARDLL/license.txt
Normal file
18
UnRAR2/UnRARDLL/license.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
The unrar.dll library is freeware. This means:
|
||||||
|
|
||||||
|
1. All copyrights to RAR and the unrar.dll are exclusively
|
||||||
|
owned by the author - Alexander Roshal.
|
||||||
|
|
||||||
|
2. The unrar.dll library may be used in any software to handle RAR
|
||||||
|
archives without limitations free of charge.
|
||||||
|
|
||||||
|
3. THE RAR ARCHIVER AND THE UNRAR.DLL LIBRARY ARE DISTRIBUTED "AS IS".
|
||||||
|
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
|
||||||
|
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
|
||||||
|
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
|
||||||
|
OR MISUSING THIS SOFTWARE.
|
||||||
|
|
||||||
|
Thank you for your interest in RAR and unrar.dll.
|
||||||
|
|
||||||
|
|
||||||
|
Alexander L. Roshal
|
BIN
UnRAR2/UnRARDLL/unrar.dll
Normal file
BIN
UnRAR2/UnRARDLL/unrar.dll
Normal file
Binary file not shown.
140
UnRAR2/UnRARDLL/unrar.h
Normal file
140
UnRAR2/UnRARDLL/unrar.h
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#ifndef _UNRAR_DLL_
|
||||||
|
#define _UNRAR_DLL_
|
||||||
|
|
||||||
|
#define ERAR_END_ARCHIVE 10
|
||||||
|
#define ERAR_NO_MEMORY 11
|
||||||
|
#define ERAR_BAD_DATA 12
|
||||||
|
#define ERAR_BAD_ARCHIVE 13
|
||||||
|
#define ERAR_UNKNOWN_FORMAT 14
|
||||||
|
#define ERAR_EOPEN 15
|
||||||
|
#define ERAR_ECREATE 16
|
||||||
|
#define ERAR_ECLOSE 17
|
||||||
|
#define ERAR_EREAD 18
|
||||||
|
#define ERAR_EWRITE 19
|
||||||
|
#define ERAR_SMALL_BUF 20
|
||||||
|
#define ERAR_UNKNOWN 21
|
||||||
|
#define ERAR_MISSING_PASSWORD 22
|
||||||
|
|
||||||
|
#define RAR_OM_LIST 0
|
||||||
|
#define RAR_OM_EXTRACT 1
|
||||||
|
#define RAR_OM_LIST_INCSPLIT 2
|
||||||
|
|
||||||
|
#define RAR_SKIP 0
|
||||||
|
#define RAR_TEST 1
|
||||||
|
#define RAR_EXTRACT 2
|
||||||
|
|
||||||
|
#define RAR_VOL_ASK 0
|
||||||
|
#define RAR_VOL_NOTIFY 1
|
||||||
|
|
||||||
|
#define RAR_DLL_VERSION 4
|
||||||
|
|
||||||
|
#ifdef _UNIX
|
||||||
|
#define CALLBACK
|
||||||
|
#define PASCAL
|
||||||
|
#define LONG long
|
||||||
|
#define HANDLE void *
|
||||||
|
#define LPARAM long
|
||||||
|
#define UINT unsigned int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct RARHeaderData
|
||||||
|
{
|
||||||
|
char ArcName[260];
|
||||||
|
char FileName[260];
|
||||||
|
unsigned int Flags;
|
||||||
|
unsigned int PackSize;
|
||||||
|
unsigned int UnpSize;
|
||||||
|
unsigned int HostOS;
|
||||||
|
unsigned int FileCRC;
|
||||||
|
unsigned int FileTime;
|
||||||
|
unsigned int UnpVer;
|
||||||
|
unsigned int Method;
|
||||||
|
unsigned int FileAttr;
|
||||||
|
char *CmtBuf;
|
||||||
|
unsigned int CmtBufSize;
|
||||||
|
unsigned int CmtSize;
|
||||||
|
unsigned int CmtState;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct RARHeaderDataEx
|
||||||
|
{
|
||||||
|
char ArcName[1024];
|
||||||
|
wchar_t ArcNameW[1024];
|
||||||
|
char FileName[1024];
|
||||||
|
wchar_t FileNameW[1024];
|
||||||
|
unsigned int Flags;
|
||||||
|
unsigned int PackSize;
|
||||||
|
unsigned int PackSizeHigh;
|
||||||
|
unsigned int UnpSize;
|
||||||
|
unsigned int UnpSizeHigh;
|
||||||
|
unsigned int HostOS;
|
||||||
|
unsigned int FileCRC;
|
||||||
|
unsigned int FileTime;
|
||||||
|
unsigned int UnpVer;
|
||||||
|
unsigned int Method;
|
||||||
|
unsigned int FileAttr;
|
||||||
|
char *CmtBuf;
|
||||||
|
unsigned int CmtBufSize;
|
||||||
|
unsigned int CmtSize;
|
||||||
|
unsigned int CmtState;
|
||||||
|
unsigned int Reserved[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct RAROpenArchiveData
|
||||||
|
{
|
||||||
|
char *ArcName;
|
||||||
|
unsigned int OpenMode;
|
||||||
|
unsigned int OpenResult;
|
||||||
|
char *CmtBuf;
|
||||||
|
unsigned int CmtBufSize;
|
||||||
|
unsigned int CmtSize;
|
||||||
|
unsigned int CmtState;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RAROpenArchiveDataEx
|
||||||
|
{
|
||||||
|
char *ArcName;
|
||||||
|
wchar_t *ArcNameW;
|
||||||
|
unsigned int OpenMode;
|
||||||
|
unsigned int OpenResult;
|
||||||
|
char *CmtBuf;
|
||||||
|
unsigned int CmtBufSize;
|
||||||
|
unsigned int CmtSize;
|
||||||
|
unsigned int CmtState;
|
||||||
|
unsigned int Flags;
|
||||||
|
unsigned int Reserved[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum UNRARCALLBACK_MESSAGES {
|
||||||
|
UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2);
|
||||||
|
|
||||||
|
typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode);
|
||||||
|
typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData);
|
||||||
|
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData);
|
||||||
|
int PASCAL RARCloseArchive(HANDLE hArcData);
|
||||||
|
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData);
|
||||||
|
int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData);
|
||||||
|
int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName);
|
||||||
|
int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName);
|
||||||
|
void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData);
|
||||||
|
void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc);
|
||||||
|
void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc);
|
||||||
|
void PASCAL RARSetPassword(HANDLE hArcData,char *Password);
|
||||||
|
int PASCAL RARGetDllVersion();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
BIN
UnRAR2/UnRARDLL/unrar.lib
Normal file
BIN
UnRAR2/UnRARDLL/unrar.lib
Normal file
Binary file not shown.
606
UnRAR2/UnRARDLL/unrardll.txt
Normal file
606
UnRAR2/UnRARDLL/unrardll.txt
Normal file
|
@ -0,0 +1,606 @@
|
||||||
|
|
||||||
|
UnRAR.dll Manual
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
UnRAR.dll is a 32-bit Windows dynamic-link library which provides
|
||||||
|
file extraction from RAR archives.
|
||||||
|
|
||||||
|
|
||||||
|
Exported functions
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData)
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Open RAR archive and allocate memory structures
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
ArchiveData Points to RAROpenArchiveData structure
|
||||||
|
|
||||||
|
struct RAROpenArchiveData
|
||||||
|
{
|
||||||
|
char *ArcName;
|
||||||
|
UINT OpenMode;
|
||||||
|
UINT OpenResult;
|
||||||
|
char *CmtBuf;
|
||||||
|
UINT CmtBufSize;
|
||||||
|
UINT CmtSize;
|
||||||
|
UINT CmtState;
|
||||||
|
};
|
||||||
|
|
||||||
|
Structure fields:
|
||||||
|
|
||||||
|
ArcName
|
||||||
|
Input parameter which should point to zero terminated string
|
||||||
|
containing the archive name.
|
||||||
|
|
||||||
|
OpenMode
|
||||||
|
Input parameter.
|
||||||
|
|
||||||
|
Possible values
|
||||||
|
|
||||||
|
RAR_OM_LIST
|
||||||
|
Open archive for reading file headers only.
|
||||||
|
|
||||||
|
RAR_OM_EXTRACT
|
||||||
|
Open archive for testing and extracting files.
|
||||||
|
|
||||||
|
RAR_OM_LIST_INCSPLIT
|
||||||
|
Open archive for reading file headers only. If you open an archive
|
||||||
|
in such mode, RARReadHeader[Ex] will return all file headers,
|
||||||
|
including those with "file continued from previous volume" flag.
|
||||||
|
In case of RAR_OM_LIST such headers are automatically skipped.
|
||||||
|
So if you process RAR volumes in RAR_OM_LIST_INCSPLIT mode, you will
|
||||||
|
get several file header records for same file if file is split between
|
||||||
|
volumes. For such files only the last file header record will contain
|
||||||
|
the correct file CRC and if you wish to get the correct packed size,
|
||||||
|
you need to sum up packed sizes of all parts.
|
||||||
|
|
||||||
|
OpenResult
|
||||||
|
Output parameter.
|
||||||
|
|
||||||
|
Possible values
|
||||||
|
|
||||||
|
0 Success
|
||||||
|
ERAR_NO_MEMORY Not enough memory to initialize data structures
|
||||||
|
ERAR_BAD_DATA Archive header broken
|
||||||
|
ERAR_BAD_ARCHIVE File is not valid RAR archive
|
||||||
|
ERAR_UNKNOWN_FORMAT Unknown encryption used for archive headers
|
||||||
|
ERAR_EOPEN File open error
|
||||||
|
|
||||||
|
CmtBuf
|
||||||
|
Input parameter which should point to the buffer for archive
|
||||||
|
comments. Maximum comment size is limited to 64Kb. Comment text is
|
||||||
|
zero terminated. If the comment text is larger than the buffer
|
||||||
|
size, the comment text will be truncated. If CmtBuf is set to
|
||||||
|
NULL, comments will not be read.
|
||||||
|
|
||||||
|
CmtBufSize
|
||||||
|
Input parameter which should contain size of buffer for archive
|
||||||
|
comments.
|
||||||
|
|
||||||
|
CmtSize
|
||||||
|
Output parameter containing size of comments actually read into the
|
||||||
|
buffer, cannot exceed CmtBufSize.
|
||||||
|
|
||||||
|
CmtState
|
||||||
|
Output parameter.
|
||||||
|
|
||||||
|
Possible values
|
||||||
|
|
||||||
|
0 comments not present
|
||||||
|
1 Comments read completely
|
||||||
|
ERAR_NO_MEMORY Not enough memory to extract comments
|
||||||
|
ERAR_BAD_DATA Broken comment
|
||||||
|
ERAR_UNKNOWN_FORMAT Unknown comment format
|
||||||
|
ERAR_SMALL_BUF Buffer too small, comments not completely read
|
||||||
|
|
||||||
|
Return values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
Archive handle or NULL in case of error
|
||||||
|
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData)
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Similar to RAROpenArchive, but uses RAROpenArchiveDataEx structure
|
||||||
|
allowing to specify Unicode archive name and returning information
|
||||||
|
about archive flags.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
ArchiveData Points to RAROpenArchiveDataEx structure
|
||||||
|
|
||||||
|
struct RAROpenArchiveDataEx
|
||||||
|
{
|
||||||
|
char *ArcName;
|
||||||
|
wchar_t *ArcNameW;
|
||||||
|
unsigned int OpenMode;
|
||||||
|
unsigned int OpenResult;
|
||||||
|
char *CmtBuf;
|
||||||
|
unsigned int CmtBufSize;
|
||||||
|
unsigned int CmtSize;
|
||||||
|
unsigned int CmtState;
|
||||||
|
unsigned int Flags;
|
||||||
|
unsigned int Reserved[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
Structure fields:
|
||||||
|
|
||||||
|
ArcNameW
|
||||||
|
Input parameter which should point to zero terminated Unicode string
|
||||||
|
containing the archive name or NULL if Unicode name is not specified.
|
||||||
|
|
||||||
|
Flags
|
||||||
|
Output parameter. Combination of bit flags.
|
||||||
|
|
||||||
|
Possible values
|
||||||
|
|
||||||
|
0x0001 - Volume attribute (archive volume)
|
||||||
|
0x0002 - Archive comment present
|
||||||
|
0x0004 - Archive lock attribute
|
||||||
|
0x0008 - Solid attribute (solid archive)
|
||||||
|
0x0010 - New volume naming scheme ('volname.partN.rar')
|
||||||
|
0x0020 - Authenticity information present
|
||||||
|
0x0040 - Recovery record present
|
||||||
|
0x0080 - Block headers are encrypted
|
||||||
|
0x0100 - First volume (set only by RAR 3.0 and later)
|
||||||
|
|
||||||
|
Reserved[32]
|
||||||
|
Reserved for future use. Must be zero.
|
||||||
|
|
||||||
|
Information on other structure fields and function return values
|
||||||
|
is available above, in RAROpenArchive function description.
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
int PASCAL RARCloseArchive(HANDLE hArcData)
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
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.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
hArcData
|
||||||
|
This parameter should contain the archive handle obtained from the
|
||||||
|
RAROpenArchive function call.
|
||||||
|
|
||||||
|
Return values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
0 Success
|
||||||
|
ERAR_ECLOSE Archive close error
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
int PASCAL RARReadHeader(HANDLE hArcData,
|
||||||
|
struct RARHeaderData *HeaderData)
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Read header of file in archive.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
hArcData
|
||||||
|
This parameter should contain the archive handle obtained from the
|
||||||
|
RAROpenArchive function call.
|
||||||
|
|
||||||
|
HeaderData
|
||||||
|
It should point to RARHeaderData structure:
|
||||||
|
|
||||||
|
struct RARHeaderData
|
||||||
|
{
|
||||||
|
char ArcName[260];
|
||||||
|
char FileName[260];
|
||||||
|
UINT Flags;
|
||||||
|
UINT PackSize;
|
||||||
|
UINT UnpSize;
|
||||||
|
UINT HostOS;
|
||||||
|
UINT FileCRC;
|
||||||
|
UINT FileTime;
|
||||||
|
UINT UnpVer;
|
||||||
|
UINT Method;
|
||||||
|
UINT FileAttr;
|
||||||
|
char *CmtBuf;
|
||||||
|
UINT CmtBufSize;
|
||||||
|
UINT CmtSize;
|
||||||
|
UINT CmtState;
|
||||||
|
};
|
||||||
|
|
||||||
|
Structure fields:
|
||||||
|
|
||||||
|
ArcName
|
||||||
|
Output parameter which contains a zero terminated string of the
|
||||||
|
current archive name. May be used to determine the current volume
|
||||||
|
name.
|
||||||
|
|
||||||
|
FileName
|
||||||
|
Output parameter which contains a zero terminated string of the
|
||||||
|
file name in OEM (DOS) encoding.
|
||||||
|
|
||||||
|
Flags
|
||||||
|
Output parameter which contains file flags:
|
||||||
|
|
||||||
|
0x01 - file continued from previous volume
|
||||||
|
0x02 - file continued on next volume
|
||||||
|
0x04 - file encrypted with password
|
||||||
|
0x08 - file comment present
|
||||||
|
0x10 - compression of previous files is used (solid flag)
|
||||||
|
|
||||||
|
bits 7 6 5
|
||||||
|
|
||||||
|
0 0 0 - dictionary size 64 Kb
|
||||||
|
0 0 1 - dictionary size 128 Kb
|
||||||
|
0 1 0 - dictionary size 256 Kb
|
||||||
|
0 1 1 - dictionary size 512 Kb
|
||||||
|
1 0 0 - dictionary size 1024 Kb
|
||||||
|
1 0 1 - dictionary size 2048 KB
|
||||||
|
1 1 0 - dictionary size 4096 KB
|
||||||
|
1 1 1 - file is directory
|
||||||
|
|
||||||
|
Other bits are reserved.
|
||||||
|
|
||||||
|
PackSize
|
||||||
|
Output parameter means packed file size or size of the
|
||||||
|
file part if file was split between volumes.
|
||||||
|
|
||||||
|
UnpSize
|
||||||
|
Output parameter - unpacked file size.
|
||||||
|
|
||||||
|
HostOS
|
||||||
|
Output parameter - operating system used for archiving:
|
||||||
|
|
||||||
|
0 - MS DOS;
|
||||||
|
1 - OS/2.
|
||||||
|
2 - Win32
|
||||||
|
3 - Unix
|
||||||
|
|
||||||
|
FileCRC
|
||||||
|
Output parameter which contains unpacked file CRC. In case of file parts
|
||||||
|
split between volumes only the last part contains the correct CRC
|
||||||
|
and it is accessible only in RAR_OM_LIST_INCSPLIT listing mode.
|
||||||
|
|
||||||
|
FileTime
|
||||||
|
Output parameter - contains date and time in standard MS DOS format.
|
||||||
|
|
||||||
|
UnpVer
|
||||||
|
Output parameter - RAR version needed to extract file.
|
||||||
|
It is encoded as 10 * Major version + minor version.
|
||||||
|
|
||||||
|
Method
|
||||||
|
Output parameter - packing method.
|
||||||
|
|
||||||
|
FileAttr
|
||||||
|
Output parameter - file attributes.
|
||||||
|
|
||||||
|
CmtBuf
|
||||||
|
File comments support is not implemented in the new DLL version yet.
|
||||||
|
Now CmtState is always 0.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Input parameter which should point to the buffer for file
|
||||||
|
* comments. Maximum comment size is limited to 64Kb. Comment text is
|
||||||
|
* a zero terminated string in OEM encoding. If the comment text is
|
||||||
|
* larger than the buffer size, the comment text will be truncated.
|
||||||
|
* If CmtBuf is set to NULL, comments will not be read.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CmtBufSize
|
||||||
|
Input parameter which should contain size of buffer for archive
|
||||||
|
comments.
|
||||||
|
|
||||||
|
CmtSize
|
||||||
|
Output parameter containing size of comments actually read into the
|
||||||
|
buffer, should not exceed CmtBufSize.
|
||||||
|
|
||||||
|
CmtState
|
||||||
|
Output parameter.
|
||||||
|
|
||||||
|
Possible values
|
||||||
|
|
||||||
|
0 Absent comments
|
||||||
|
1 Comments read completely
|
||||||
|
ERAR_NO_MEMORY Not enough memory to extract comments
|
||||||
|
ERAR_BAD_DATA Broken comment
|
||||||
|
ERAR_UNKNOWN_FORMAT Unknown comment format
|
||||||
|
ERAR_SMALL_BUF Buffer too small, comments not completely read
|
||||||
|
|
||||||
|
Return values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
0 Success
|
||||||
|
ERAR_END_ARCHIVE End of archive
|
||||||
|
ERAR_BAD_DATA File header broken
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
int PASCAL RARReadHeaderEx(HANDLE hArcData,
|
||||||
|
struct RARHeaderDataEx *HeaderData)
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Similar to RARReadHeader, but uses RARHeaderDataEx structure,
|
||||||
|
containing information about Unicode file names and 64 bit file sizes.
|
||||||
|
|
||||||
|
struct RARHeaderDataEx
|
||||||
|
{
|
||||||
|
char ArcName[1024];
|
||||||
|
wchar_t ArcNameW[1024];
|
||||||
|
char FileName[1024];
|
||||||
|
wchar_t FileNameW[1024];
|
||||||
|
unsigned int Flags;
|
||||||
|
unsigned int PackSize;
|
||||||
|
unsigned int PackSizeHigh;
|
||||||
|
unsigned int UnpSize;
|
||||||
|
unsigned int UnpSizeHigh;
|
||||||
|
unsigned int HostOS;
|
||||||
|
unsigned int FileCRC;
|
||||||
|
unsigned int FileTime;
|
||||||
|
unsigned int UnpVer;
|
||||||
|
unsigned int Method;
|
||||||
|
unsigned int FileAttr;
|
||||||
|
char *CmtBuf;
|
||||||
|
unsigned int CmtBufSize;
|
||||||
|
unsigned int CmtSize;
|
||||||
|
unsigned int CmtState;
|
||||||
|
unsigned int Reserved[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
int PASCAL RARProcessFile(HANDLE hArcData,
|
||||||
|
int Operation,
|
||||||
|
char *DestPath,
|
||||||
|
char *DestName)
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
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.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
hArcData
|
||||||
|
This parameter should contain the archive handle obtained from the
|
||||||
|
RAROpenArchive function call.
|
||||||
|
|
||||||
|
Operation
|
||||||
|
File operation.
|
||||||
|
|
||||||
|
Possible values
|
||||||
|
|
||||||
|
RAR_SKIP Move to the next file in the archive. If the
|
||||||
|
archive is solid and RAR_OM_EXTRACT mode was set
|
||||||
|
when the archive was opened, the current file will
|
||||||
|
be processed - the operation will be performed
|
||||||
|
slower than a simple seek.
|
||||||
|
|
||||||
|
RAR_TEST Test the current file and move to the next file in
|
||||||
|
the archive. If the archive was opened with
|
||||||
|
RAR_OM_LIST mode, the operation is equal to
|
||||||
|
RAR_SKIP.
|
||||||
|
|
||||||
|
RAR_EXTRACT Extract the current file and move to the next file.
|
||||||
|
If the archive was opened with RAR_OM_LIST mode,
|
||||||
|
the operation is equal to RAR_SKIP.
|
||||||
|
|
||||||
|
|
||||||
|
DestPath
|
||||||
|
This parameter should point to a zero terminated string containing the
|
||||||
|
destination directory to which to extract files to. If DestPath is equal
|
||||||
|
to NULL, it means extract to the current directory. This parameter has
|
||||||
|
meaning only if DestName is NULL.
|
||||||
|
|
||||||
|
DestName
|
||||||
|
This parameter should point to a string containing the full path and name
|
||||||
|
to assign to extracted file or it can be NULL to use the default name.
|
||||||
|
If DestName is defined (not NULL), it overrides both the original file
|
||||||
|
name saved in the archive and path specigied in DestPath setting.
|
||||||
|
|
||||||
|
Both DestPath and DestName must be in OEM encoding. If necessary,
|
||||||
|
use CharToOem to convert text to OEM before passing to this function.
|
||||||
|
|
||||||
|
Return values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
0 Success
|
||||||
|
ERAR_BAD_DATA File CRC error
|
||||||
|
ERAR_BAD_ARCHIVE Volume is not valid RAR archive
|
||||||
|
ERAR_UNKNOWN_FORMAT Unknown archive format
|
||||||
|
ERAR_EOPEN Volume open error
|
||||||
|
ERAR_ECREATE File create error
|
||||||
|
ERAR_ECLOSE File close error
|
||||||
|
ERAR_EREAD Read error
|
||||||
|
ERAR_EWRITE Write error
|
||||||
|
|
||||||
|
|
||||||
|
Note: if you wish to cancel extraction, return -1 when processing
|
||||||
|
UCM_PROCESSDATA callback message.
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
int PASCAL RARProcessFileW(HANDLE hArcData,
|
||||||
|
int Operation,
|
||||||
|
wchar_t *DestPath,
|
||||||
|
wchar_t *DestName)
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Unicode version of RARProcessFile. It uses Unicode DestPath
|
||||||
|
and DestName parameters, other parameters and return values
|
||||||
|
are the same as in RARProcessFile.
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
void PASCAL RARSetCallback(HANDLE hArcData,
|
||||||
|
int PASCAL (*CallbackProc)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2),
|
||||||
|
LPARAM UserData);
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Set a user-defined callback function to process Unrar events.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
hArcData
|
||||||
|
This parameter should contain the archive handle obtained from the
|
||||||
|
RAROpenArchive function call.
|
||||||
|
|
||||||
|
CallbackProc
|
||||||
|
It should point to a user-defined callback function.
|
||||||
|
|
||||||
|
The function will be passed four parameters:
|
||||||
|
|
||||||
|
|
||||||
|
msg Type of event. Described below.
|
||||||
|
|
||||||
|
UserData User defined value passed to RARSetCallback.
|
||||||
|
|
||||||
|
P1 and P2 Event dependent parameters. Described below.
|
||||||
|
|
||||||
|
|
||||||
|
Possible events
|
||||||
|
|
||||||
|
UCM_CHANGEVOLUME Process volume change.
|
||||||
|
|
||||||
|
P1 Points to the zero terminated name
|
||||||
|
of the next volume.
|
||||||
|
|
||||||
|
P2 The function call mode:
|
||||||
|
|
||||||
|
RAR_VOL_ASK Required volume is absent. The function should
|
||||||
|
prompt user and return a positive value
|
||||||
|
to retry or return -1 value to terminate
|
||||||
|
operation. The function may also specify a new
|
||||||
|
volume name, placing it to the address specified
|
||||||
|
by P1 parameter.
|
||||||
|
|
||||||
|
RAR_VOL_NOTIFY Required volume is successfully opened.
|
||||||
|
This is a notification call and volume name
|
||||||
|
modification is not allowed. The function should
|
||||||
|
return a positive value to continue or -1
|
||||||
|
to terminate operation.
|
||||||
|
|
||||||
|
UCM_PROCESSDATA Process unpacked data. It may be used to read
|
||||||
|
a file while it is being extracted or tested
|
||||||
|
without actual extracting file to disk.
|
||||||
|
Return a positive value to continue process
|
||||||
|
or -1 to cancel the archive operation
|
||||||
|
|
||||||
|
P1 Address pointing to the unpacked data.
|
||||||
|
Function may refer to the data but must not
|
||||||
|
change it.
|
||||||
|
|
||||||
|
P2 Size of the unpacked data. It is guaranteed
|
||||||
|
only that the size will not exceed the maximum
|
||||||
|
dictionary size (4 Mb in RAR 3.0).
|
||||||
|
|
||||||
|
UCM_NEEDPASSWORD DLL needs a password to process archive.
|
||||||
|
This message must be processed if you wish
|
||||||
|
to be able to handle archives with encrypted
|
||||||
|
file names. It can be also used as replacement
|
||||||
|
of RARSetPassword function even for usual
|
||||||
|
encrypted files with non-encrypted names.
|
||||||
|
|
||||||
|
P1 Address pointing to the buffer for a password.
|
||||||
|
You need to copy a password here.
|
||||||
|
|
||||||
|
P2 Size of the password buffer.
|
||||||
|
|
||||||
|
|
||||||
|
UserData
|
||||||
|
User data passed to callback function.
|
||||||
|
|
||||||
|
Other functions of UnRAR.dll should not be called from the callback
|
||||||
|
function.
|
||||||
|
|
||||||
|
Return values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
void PASCAL RARSetChangeVolProc(HANDLE hArcData,
|
||||||
|
int PASCAL (*ChangeVolProc)(char *ArcName,int Mode));
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Obsoleted, use RARSetCallback instead.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
void PASCAL RARSetProcessDataProc(HANDLE hArcData,
|
||||||
|
int PASCAL (*ProcessDataProc)(unsigned char *Addr,int Size))
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Obsoleted, use RARSetCallback instead.
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
void PASCAL RARSetPassword(HANDLE hArcData,
|
||||||
|
char *Password);
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Set a password to decrypt files.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
hArcData
|
||||||
|
This parameter should contain the archive handle obtained from the
|
||||||
|
RAROpenArchive function call.
|
||||||
|
|
||||||
|
Password
|
||||||
|
It should point to a string containing a zero terminated password.
|
||||||
|
|
||||||
|
Return values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
None
|
||||||
|
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
void PASCAL RARGetDllVersion();
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
Description
|
||||||
|
~~~~~~~~~~~
|
||||||
|
Returns API version.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
~~~~~~~~~~
|
||||||
|
None.
|
||||||
|
|
||||||
|
Return values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
Returns an integer value denoting UnRAR.dll API version, which is also
|
||||||
|
defined in unrar.h as RAR_DLL_VERSION. API version number is incremented
|
||||||
|
only in case of noticeable changes in UnRAR.dll API. Do not confuse it
|
||||||
|
with version of UnRAR.dll stored in DLL resources, which is incremented
|
||||||
|
with every DLL rebuild.
|
||||||
|
|
||||||
|
If RARGetDllVersion() returns a value lower than UnRAR.dll which your
|
||||||
|
application was designed for, it may indicate that DLL version is too old
|
||||||
|
and it will fail to provide all necessary functions to your application.
|
||||||
|
|
||||||
|
This function is absent in old versions of UnRAR.dll, so it is safer
|
||||||
|
to use LoadLibrary and GetProcAddress to access this function.
|
||||||
|
|
80
UnRAR2/UnRARDLL/whatsnew.txt
Normal file
80
UnRAR2/UnRARDLL/whatsnew.txt
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
List of unrar.dll API changes. We do not include performance and reliability
|
||||||
|
improvements into this list, but this library and RAR/UnRAR tools share
|
||||||
|
the same source code. So the latest version of unrar.dll usually contains
|
||||||
|
same decompression algorithm changes as the latest UnRAR version.
|
||||||
|
============================================================================
|
||||||
|
|
||||||
|
-- 18 January 2008
|
||||||
|
|
||||||
|
all LONG parameters of CallbackProc function were changed
|
||||||
|
to LPARAM type for 64 bit mode compatibility.
|
||||||
|
|
||||||
|
|
||||||
|
-- 12 December 2007
|
||||||
|
|
||||||
|
Added new RAR_OM_LIST_INCSPLIT open mode for function RAROpenArchive.
|
||||||
|
|
||||||
|
|
||||||
|
-- 14 August 2007
|
||||||
|
|
||||||
|
Added NoCrypt\unrar_nocrypt.dll without decryption code for those
|
||||||
|
applications where presence of encryption or decryption code is not
|
||||||
|
allowed because of legal restrictions.
|
||||||
|
|
||||||
|
|
||||||
|
-- 14 December 2006
|
||||||
|
|
||||||
|
Added ERAR_MISSING_PASSWORD error type. This error is returned
|
||||||
|
if empty password is specified for encrypted file.
|
||||||
|
|
||||||
|
|
||||||
|
-- 12 June 2003
|
||||||
|
|
||||||
|
Added RARProcessFileW function, Unicode version of RARProcessFile
|
||||||
|
|
||||||
|
|
||||||
|
-- 9 August 2002
|
||||||
|
|
||||||
|
Added RAROpenArchiveEx function allowing to specify Unicode archive
|
||||||
|
name and get archive flags.
|
||||||
|
|
||||||
|
|
||||||
|
-- 24 January 2002
|
||||||
|
|
||||||
|
Added RARReadHeaderEx function allowing to read Unicode file names
|
||||||
|
and 64 bit file sizes.
|
||||||
|
|
||||||
|
|
||||||
|
-- 23 January 2002
|
||||||
|
|
||||||
|
Added ERAR_UNKNOWN error type (it is used for all errors which
|
||||||
|
do not have special ERAR code yet) and UCM_NEEDPASSWORD callback
|
||||||
|
message.
|
||||||
|
|
||||||
|
Unrar.dll automatically opens all next volumes not only when extracting,
|
||||||
|
but also in RAR_OM_LIST mode.
|
||||||
|
|
||||||
|
|
||||||
|
-- 27 November 2001
|
||||||
|
|
||||||
|
RARSetChangeVolProc and RARSetProcessDataProc are replaced by
|
||||||
|
the single callback function installed with RARSetCallback.
|
||||||
|
Unlike old style callbacks, the new function accepts the user defined
|
||||||
|
parameter. Unrar.dll still supports RARSetChangeVolProc and
|
||||||
|
RARSetProcessDataProc for compatibility purposes, but if you write
|
||||||
|
a new application, better use RARSetCallback.
|
||||||
|
|
||||||
|
File comments support is not implemented in the new DLL version yet.
|
||||||
|
Now CmtState is always 0.
|
||||||
|
|
||||||
|
|
||||||
|
-- 13 August 2001
|
||||||
|
|
||||||
|
Added RARGetDllVersion function, so you may distinguish old unrar.dll,
|
||||||
|
which used C style callback functions and the new one with PASCAL callbacks.
|
||||||
|
|
||||||
|
|
||||||
|
-- 10 May 2001
|
||||||
|
|
||||||
|
Callback functions in RARSetChangeVolProc and RARSetProcessDataProc
|
||||||
|
use PASCAL style call convention now.
|
1
UnRAR2/UnRARDLL/x64/readme.txt
Normal file
1
UnRAR2/UnRARDLL/x64/readme.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
This is x64 version of unrar.dll.
|
BIN
UnRAR2/UnRARDLL/x64/unrar64.dll
Normal file
BIN
UnRAR2/UnRARDLL/x64/unrar64.dll
Normal file
Binary file not shown.
BIN
UnRAR2/UnRARDLL/x64/unrar64.lib
Normal file
BIN
UnRAR2/UnRARDLL/x64/unrar64.lib
Normal file
Binary file not shown.
177
UnRAR2/__init__.py
Normal file
177
UnRAR2/__init__.py
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
# Copyright (c) 2003-2005 Jimmy Retzlaff, 2008 Konstantin Yegupov
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyUnRAR2 is a ctypes based wrapper around the free UnRAR.dll.
|
||||||
|
|
||||||
|
It is an modified version of Jimmy Retzlaff's pyUnRAR - more simple,
|
||||||
|
stable and foolproof.
|
||||||
|
Notice that it has INCOMPATIBLE interface.
|
||||||
|
|
||||||
|
It enables reading and unpacking of archives created with the
|
||||||
|
RAR/WinRAR archivers. There is a low-level interface which is very
|
||||||
|
similar to the C interface provided by UnRAR. There is also a
|
||||||
|
higher level interface which makes some common operations easier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = '0.99.2'
|
||||||
|
|
||||||
|
try:
|
||||||
|
WindowsError
|
||||||
|
in_windows = True
|
||||||
|
except NameError:
|
||||||
|
in_windows = False
|
||||||
|
|
||||||
|
if in_windows:
|
||||||
|
from windows import RarFileImplementation
|
||||||
|
else:
|
||||||
|
from unix import RarFileImplementation
|
||||||
|
|
||||||
|
|
||||||
|
import fnmatch, time, weakref
|
||||||
|
|
||||||
|
class RarInfo(object):
|
||||||
|
"""Represents a file header in an archive. Don't instantiate directly.
|
||||||
|
Use only to obtain information about file.
|
||||||
|
YOU CANNOT EXTRACT FILE CONTENTS USING THIS OBJECT.
|
||||||
|
USE METHODS OF RarFile CLASS INSTEAD.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
index - index of file within the archive
|
||||||
|
filename - name of the file in the archive including path (if any)
|
||||||
|
datetime - file date/time as a struct_time suitable for time.strftime
|
||||||
|
isdir - True if the file is a directory
|
||||||
|
size - size in bytes of the uncompressed file
|
||||||
|
comment - comment associated with the file
|
||||||
|
|
||||||
|
Note - this is not currently intended to be a Python file-like object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, rarfile, data):
|
||||||
|
self.rarfile = weakref.proxy(rarfile)
|
||||||
|
self.index = data['index']
|
||||||
|
self.filename = data['filename']
|
||||||
|
self.isdir = data['isdir']
|
||||||
|
self.size = data['size']
|
||||||
|
self.datetime = data['datetime']
|
||||||
|
self.comment = data['comment']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
try :
|
||||||
|
arcName = self.rarfile.archiveName
|
||||||
|
except ReferenceError:
|
||||||
|
arcName = "[ARCHIVE_NO_LONGER_LOADED]"
|
||||||
|
return '<RarInfo "%s" in "%s">' % (self.filename, arcName)
|
||||||
|
|
||||||
|
class RarFile(RarFileImplementation):
|
||||||
|
|
||||||
|
def __init__(self, archiveName, password=None):
|
||||||
|
"""Instantiate the archive.
|
||||||
|
|
||||||
|
archiveName is the name of the RAR file.
|
||||||
|
password is used to decrypt the files in the archive.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
comment - comment associated with the archive
|
||||||
|
|
||||||
|
>>> print RarFile('test.rar').comment
|
||||||
|
This is a test.
|
||||||
|
"""
|
||||||
|
self.archiveName = archiveName
|
||||||
|
RarFileImplementation.init(self, password)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.destruct()
|
||||||
|
|
||||||
|
def infoiter(self):
|
||||||
|
"""Iterate over all the files in the archive, generating RarInfos.
|
||||||
|
|
||||||
|
>>> import os
|
||||||
|
>>> for fileInArchive in RarFile('test.rar').infoiter():
|
||||||
|
... print os.path.split(fileInArchive.filename)[-1],
|
||||||
|
... print fileInArchive.isdir,
|
||||||
|
... print fileInArchive.size,
|
||||||
|
... print fileInArchive.comment,
|
||||||
|
... print tuple(fileInArchive.datetime)[0:5],
|
||||||
|
... print time.strftime('%a, %d %b %Y %H:%M', fileInArchive.datetime)
|
||||||
|
test True 0 None (2003, 6, 30, 1, 59) Mon, 30 Jun 2003 01:59
|
||||||
|
test.txt False 20 None (2003, 6, 30, 2, 1) Mon, 30 Jun 2003 02:01
|
||||||
|
this.py False 1030 None (2002, 2, 8, 16, 47) Fri, 08 Feb 2002 16:47
|
||||||
|
"""
|
||||||
|
for params in RarFileImplementation.infoiter(self):
|
||||||
|
yield RarInfo(self, params)
|
||||||
|
|
||||||
|
def infolist(self):
|
||||||
|
"""Return a list of RarInfos, descripting the contents of the archive."""
|
||||||
|
return list(self.infoiter())
|
||||||
|
|
||||||
|
def read_files(self, condition='*'):
|
||||||
|
"""Read specific files from archive into memory.
|
||||||
|
If "condition" is a list of numbers, then return files which have those positions in infolist.
|
||||||
|
If "condition" is a string, then it is treated as a wildcard for names of files to extract.
|
||||||
|
If "condition" is a function, it is treated as a callback function, which accepts a RarInfo object
|
||||||
|
and returns boolean True (extract) or False (skip).
|
||||||
|
If "condition" is omitted, all files are returned.
|
||||||
|
|
||||||
|
Returns list of tuples (RarInfo info, str contents)
|
||||||
|
"""
|
||||||
|
checker = condition2checker(condition)
|
||||||
|
return RarFileImplementation.read_files(self, checker)
|
||||||
|
|
||||||
|
|
||||||
|
def extract(self, condition='*', path='.', withSubpath=True, overwrite=True):
|
||||||
|
"""Extract specific files from archive to disk.
|
||||||
|
|
||||||
|
If "condition" is a list of numbers, then extract files which have those positions in infolist.
|
||||||
|
If "condition" is a string, then it is treated as a wildcard for names of files to extract.
|
||||||
|
If "condition" is a function, it is treated as a callback function, which accepts a RarInfo object
|
||||||
|
and returns either boolean True (extract) or boolean False (skip).
|
||||||
|
DEPRECATED: If "condition" callback returns string (only supported for Windows) -
|
||||||
|
that string will be used as a new name to save the file under.
|
||||||
|
If "condition" is omitted, all files are extracted.
|
||||||
|
|
||||||
|
"path" is a directory to extract to
|
||||||
|
"withSubpath" flag denotes whether files are extracted with their full path in the archive.
|
||||||
|
"overwrite" flag denotes whether extracted files will overwrite old ones. Defaults to true.
|
||||||
|
|
||||||
|
Returns list of RarInfos for extracted files."""
|
||||||
|
checker = condition2checker(condition)
|
||||||
|
return RarFileImplementation.extract(self, checker, path, withSubpath, overwrite)
|
||||||
|
|
||||||
|
def condition2checker(condition):
|
||||||
|
"""Converts different condition types to callback"""
|
||||||
|
if type(condition) in [str, unicode]:
|
||||||
|
def smatcher(info):
|
||||||
|
return fnmatch.fnmatch(info.filename, condition)
|
||||||
|
return smatcher
|
||||||
|
elif type(condition) in [list, tuple] and type(condition[0]) in [int, long]:
|
||||||
|
def imatcher(info):
|
||||||
|
return info.index in condition
|
||||||
|
return imatcher
|
||||||
|
elif callable(condition):
|
||||||
|
return condition
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
|
|
21
UnRAR2/license.txt
Normal file
21
UnRAR2/license.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
Copyright (c) 2003-2005 Jimmy Retzlaff, 2008 Konstantin Yegupov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
30
UnRAR2/rar_exceptions.py
Normal file
30
UnRAR2/rar_exceptions.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Copyright (c) 2003-2005 Jimmy Retzlaff, 2008 Konstantin Yegupov
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
# Low level interface - see UnRARDLL\UNRARDLL.TXT
|
||||||
|
|
||||||
|
|
||||||
|
class ArchiveHeaderBroken(Exception): pass
|
||||||
|
class InvalidRARArchive(Exception): pass
|
||||||
|
class FileOpenError(Exception): pass
|
||||||
|
class IncorrectRARPassword(Exception): pass
|
||||||
|
class InvalidRARArchiveUsage(Exception): pass
|
54
UnRAR2/setup.py
Normal file
54
UnRAR2/setup.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# setup.py, config file for distutils
|
||||||
|
|
||||||
|
import __init__
|
||||||
|
|
||||||
|
from distutils.core import setup
|
||||||
|
from distutils.command.install_data import install_data
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class smart_install_data(install_data):
|
||||||
|
def run(self):
|
||||||
|
#need to change self.install_dir to the actual library dir
|
||||||
|
install_cmd = self.get_finalized_command('install')
|
||||||
|
self.install_dir = getattr(install_cmd, 'install_lib')
|
||||||
|
return install_data.run(self)
|
||||||
|
|
||||||
|
|
||||||
|
data_files = []
|
||||||
|
for dirpath, dirnames, filenames in os.walk(r'.'):
|
||||||
|
for dirname in ['.svn','build', 'dist', '_sgbak', '.hg']:
|
||||||
|
try:
|
||||||
|
dirnames.remove(dirname)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
for filename in [fn for fn in filenames if os.path.splitext(fn)[-1].lower() in ('.pyc', '.pyo', '.scc')]:
|
||||||
|
filenames.remove(filename)
|
||||||
|
parts = ['UnRAR2']+dirpath.split(os.sep)[1:]
|
||||||
|
|
||||||
|
data_files.append((os.path.join(*parts), [os.path.join(dirpath, fn) for fn in filenames]))
|
||||||
|
|
||||||
|
setup(name='pyUnRAR2',
|
||||||
|
version=__init__.__version__,
|
||||||
|
description='Improved Python wrapper around the free UnRAR.dll',
|
||||||
|
long_description=__init__.__doc__.strip(),
|
||||||
|
author='Konstantin Yegupov',
|
||||||
|
author_email='yk4ever@gmail.com',
|
||||||
|
url='http://code.google.com/py-unrar2',
|
||||||
|
license='MIT',
|
||||||
|
platforms='Windows',
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 4 - Beta',
|
||||||
|
'Environment :: Win32 (MS Windows)',
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Operating System :: Microsoft :: Windows',
|
||||||
|
'Programming Language :: Python',
|
||||||
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
|
'Topic :: System :: Archiving :: Compression',
|
||||||
|
],
|
||||||
|
packages=['UnRAR2'],
|
||||||
|
package_dir={'UnRAR2' : ''},
|
||||||
|
data_files=data_files,
|
||||||
|
cmdclass = {'install_data': smart_install_data},
|
||||||
|
)
|
139
UnRAR2/test_UnRAR2.py
Normal file
139
UnRAR2/test_UnRAR2.py
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
import os, sys
|
||||||
|
|
||||||
|
import UnRAR2
|
||||||
|
from UnRAR2.rar_exceptions import *
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup(dir='test'):
|
||||||
|
for path, dirs, files in os.walk(dir):
|
||||||
|
for fn in files:
|
||||||
|
os.remove(os.path.join(path, fn))
|
||||||
|
for dir in dirs:
|
||||||
|
os.removedirs(os.path.join(path, dir))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# reuse RarArchive object, en
|
||||||
|
cleanup()
|
||||||
|
rarc = UnRAR2.RarFile('test.rar')
|
||||||
|
rarc.infolist()
|
||||||
|
for info in rarc.infoiter():
|
||||||
|
saveinfo = info
|
||||||
|
assert (str(info)=="""<RarInfo "test" in "test.rar">""")
|
||||||
|
break
|
||||||
|
rarc.extract()
|
||||||
|
assert os.path.exists('test'+os.sep+'test.txt')
|
||||||
|
assert os.path.exists('test'+os.sep+'this.py')
|
||||||
|
del rarc
|
||||||
|
assert (str(saveinfo)=="""<RarInfo "test" in "[ARCHIVE_NO_LONGER_LOADED]">""")
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
# extract all the files in test.rar
|
||||||
|
cleanup()
|
||||||
|
UnRAR2.RarFile('test.rar').extract()
|
||||||
|
assert os.path.exists('test'+os.sep+'test.txt')
|
||||||
|
assert os.path.exists('test'+os.sep+'this.py')
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
# extract all the files in test.rar matching the wildcard *.txt
|
||||||
|
cleanup()
|
||||||
|
UnRAR2.RarFile('test.rar').extract('*.txt')
|
||||||
|
assert os.path.exists('test'+os.sep+'test.txt')
|
||||||
|
assert not os.path.exists('test'+os.sep+'this.py')
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
# check the name and size of each file, extracting small ones
|
||||||
|
cleanup()
|
||||||
|
archive = UnRAR2.RarFile('test.rar')
|
||||||
|
assert archive.comment == 'This is a test.'
|
||||||
|
archive.extract(lambda rarinfo: rarinfo.size <= 1024)
|
||||||
|
for rarinfo in archive.infoiter():
|
||||||
|
if rarinfo.size <= 1024 and not rarinfo.isdir:
|
||||||
|
assert rarinfo.size == os.stat(rarinfo.filename).st_size
|
||||||
|
assert file('test'+os.sep+'test.txt', 'rt').read() == 'This is only a test.'
|
||||||
|
assert not os.path.exists('test'+os.sep+'this.py')
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
# extract this.py, overriding it's destination
|
||||||
|
cleanup('test2')
|
||||||
|
archive = UnRAR2.RarFile('test.rar')
|
||||||
|
archive.extract('*.py', 'test2', False)
|
||||||
|
assert os.path.exists('test2'+os.sep+'this.py')
|
||||||
|
cleanup('test2')
|
||||||
|
|
||||||
|
|
||||||
|
# extract test.txt to memory
|
||||||
|
cleanup()
|
||||||
|
archive = UnRAR2.RarFile('test.rar')
|
||||||
|
entries = UnRAR2.RarFile('test.rar').read_files('*test.txt')
|
||||||
|
assert len(entries)==1
|
||||||
|
assert entries[0][0].filename.endswith('test.txt')
|
||||||
|
assert entries[0][1]=='This is only a test.'
|
||||||
|
|
||||||
|
|
||||||
|
# extract all the files in test.rar with overwriting
|
||||||
|
cleanup()
|
||||||
|
fo = open('test'+os.sep+'test.txt',"wt")
|
||||||
|
fo.write("blah")
|
||||||
|
fo.close()
|
||||||
|
UnRAR2.RarFile('test.rar').extract('*.txt')
|
||||||
|
assert open('test'+os.sep+'test.txt',"rt").read()!="blah"
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
# extract all the files in test.rar without overwriting
|
||||||
|
cleanup()
|
||||||
|
fo = open('test'+os.sep+'test.txt',"wt")
|
||||||
|
fo.write("blahblah")
|
||||||
|
fo.close()
|
||||||
|
UnRAR2.RarFile('test.rar').extract('*.txt', overwrite = False)
|
||||||
|
assert open('test'+os.sep+'test.txt',"rt").read()=="blahblah"
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
# list big file in an archive
|
||||||
|
list(UnRAR2.RarFile('test_nulls.rar').infoiter())
|
||||||
|
|
||||||
|
# extract files from an archive with protected files
|
||||||
|
cleanup()
|
||||||
|
UnRAR2.RarFile('test_protected_files.rar', password="protected").extract()
|
||||||
|
assert os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||||
|
cleanup()
|
||||||
|
errored = False
|
||||||
|
try:
|
||||||
|
UnRAR2.RarFile('test_protected_files.rar', password="proteqted").extract()
|
||||||
|
except IncorrectRARPassword:
|
||||||
|
errored = True
|
||||||
|
assert not os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||||
|
assert errored
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
# extract files from an archive with protected headers
|
||||||
|
cleanup()
|
||||||
|
UnRAR2.RarFile('test_protected_headers.rar', password="secret").extract()
|
||||||
|
assert os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||||
|
cleanup()
|
||||||
|
errored = False
|
||||||
|
try:
|
||||||
|
UnRAR2.RarFile('test_protected_headers.rar', password="seqret").extract()
|
||||||
|
except IncorrectRARPassword:
|
||||||
|
errored = True
|
||||||
|
assert not os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||||
|
assert errored
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
# make sure docstring examples are working
|
||||||
|
import doctest
|
||||||
|
doctest.testmod(UnRAR2)
|
||||||
|
|
||||||
|
# update documentation
|
||||||
|
import pydoc
|
||||||
|
pydoc.writedoc(UnRAR2)
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
try:
|
||||||
|
os.remove('__init__.pyc')
|
||||||
|
except:
|
||||||
|
pass
|
175
UnRAR2/unix.py
Normal file
175
UnRAR2/unix.py
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
# Copyright (c) 2003-2005 Jimmy Retzlaff, 2008 Konstantin Yegupov
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
# Unix version uses unrar command line executable
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import gc
|
||||||
|
|
||||||
|
import os, os.path
|
||||||
|
import time, re
|
||||||
|
|
||||||
|
from rar_exceptions import *
|
||||||
|
|
||||||
|
class UnpackerNotInstalled(Exception): pass
|
||||||
|
|
||||||
|
rar_executable_cached = None
|
||||||
|
|
||||||
|
def call_unrar(params):
|
||||||
|
"Calls rar/unrar command line executable, returns stdout pipe"
|
||||||
|
global rar_executable_cached
|
||||||
|
if rar_executable_cached is None:
|
||||||
|
for command in ('unrar', 'rar'):
|
||||||
|
try:
|
||||||
|
subprocess.Popen([command], stdout=subprocess.PIPE)
|
||||||
|
rar_executable_cached = command
|
||||||
|
break
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
if rar_executable_cached is None:
|
||||||
|
raise UnpackerNotInstalled("No suitable RAR unpacker installed")
|
||||||
|
|
||||||
|
assert type(params) == list, "params must be list"
|
||||||
|
args = [rar_executable_cached] + params
|
||||||
|
try:
|
||||||
|
gc.disable() # See http://bugs.python.org/issue1336
|
||||||
|
return subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
finally:
|
||||||
|
gc.enable()
|
||||||
|
|
||||||
|
class RarFileImplementation(object):
|
||||||
|
|
||||||
|
def init(self, password=None):
|
||||||
|
self.password = password
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
stdoutdata, stderrdata = self.call('v', []).communicate()
|
||||||
|
|
||||||
|
for line in stderrdata.splitlines():
|
||||||
|
if line.strip().startswith("Cannot open"):
|
||||||
|
raise FileOpenError
|
||||||
|
if line.find("CRC failed")>=0:
|
||||||
|
raise IncorrectRARPassword
|
||||||
|
accum = []
|
||||||
|
source = iter(stdoutdata.splitlines())
|
||||||
|
line = ''
|
||||||
|
while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')):
|
||||||
|
if line.strip().endswith('is not RAR archive'):
|
||||||
|
raise InvalidRARArchive
|
||||||
|
line = source.next()
|
||||||
|
while not line.startswith('Pathname/Comment'):
|
||||||
|
accum.append(line.rstrip('\n'))
|
||||||
|
line = source.next()
|
||||||
|
if len(accum):
|
||||||
|
accum[0] = accum[0][9:]
|
||||||
|
self.comment = '\n'.join(accum[:-1])
|
||||||
|
else:
|
||||||
|
self.comment = None
|
||||||
|
|
||||||
|
def escaped_password(self):
|
||||||
|
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]
|
||||||
|
return call_unrar([cmd]+soptions+['--',self.archiveName]+files)
|
||||||
|
|
||||||
|
def infoiter(self):
|
||||||
|
|
||||||
|
stdoutdata, stderrdata = self.call('v', ['c-']).communicate()
|
||||||
|
|
||||||
|
for line in stderrdata.splitlines():
|
||||||
|
if line.strip().startswith("Cannot open"):
|
||||||
|
raise FileOpenError
|
||||||
|
|
||||||
|
accum = []
|
||||||
|
source = iter(stdoutdata.splitlines())
|
||||||
|
line = ''
|
||||||
|
while not line.startswith('--------------'):
|
||||||
|
if line.strip().endswith('is not RAR archive'):
|
||||||
|
raise InvalidRARArchive
|
||||||
|
if line.find("CRC failed")>=0:
|
||||||
|
raise IncorrectRARPassword
|
||||||
|
line = source.next()
|
||||||
|
line = source.next()
|
||||||
|
i = 0
|
||||||
|
re_spaces = re.compile(r"\s+")
|
||||||
|
while not line.startswith('--------------'):
|
||||||
|
accum.append(line)
|
||||||
|
if len(accum)==2:
|
||||||
|
data = {}
|
||||||
|
data['index'] = i
|
||||||
|
data['filename'] = accum[0].strip()
|
||||||
|
info = re_spaces.split(accum[1].strip())
|
||||||
|
data['size'] = int(info[0])
|
||||||
|
attr = info[5]
|
||||||
|
data['isdir'] = 'd' in attr.lower()
|
||||||
|
data['datetime'] = time.strptime(info[3]+" "+info[4], '%d-%m-%y %H:%M')
|
||||||
|
data['comment'] = None
|
||||||
|
yield data
|
||||||
|
accum = []
|
||||||
|
i += 1
|
||||||
|
line = source.next()
|
||||||
|
|
||||||
|
def read_files(self, checker):
|
||||||
|
res = []
|
||||||
|
for info in self.infoiter():
|
||||||
|
checkres = checker(info)
|
||||||
|
if checkres==True and not info.isdir:
|
||||||
|
pipe = self.call('p', ['inul'], [info.filename]).stdout
|
||||||
|
res.append((info, pipe.read()))
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def extract(self, checker, path, withSubpath, overwrite):
|
||||||
|
res = []
|
||||||
|
command = 'x'
|
||||||
|
if not withSubpath:
|
||||||
|
command = 'e'
|
||||||
|
options = []
|
||||||
|
if overwrite:
|
||||||
|
options.append('o+')
|
||||||
|
else:
|
||||||
|
options.append('o-')
|
||||||
|
if not path.endswith(os.sep):
|
||||||
|
path += os.sep
|
||||||
|
names = []
|
||||||
|
for info in self.infoiter():
|
||||||
|
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:
|
||||||
|
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:
|
||||||
|
raise IncorrectRARPassword
|
||||||
|
return res
|
||||||
|
|
||||||
|
def destruct(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
309
UnRAR2/windows.py
Normal file
309
UnRAR2/windows.py
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
# Copyright (c) 2003-2005 Jimmy Retzlaff, 2008 Konstantin Yegupov
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
# Low level interface - see UnRARDLL\UNRARDLL.TXT
|
||||||
|
|
||||||
|
from __future__ import generators
|
||||||
|
|
||||||
|
import ctypes, ctypes.wintypes
|
||||||
|
import os, os.path, sys
|
||||||
|
import Queue
|
||||||
|
import time
|
||||||
|
|
||||||
|
from rar_exceptions import *
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
RAR_OM_LIST = 0
|
||||||
|
RAR_OM_EXTRACT = 1
|
||||||
|
|
||||||
|
RAR_SKIP = 0
|
||||||
|
RAR_TEST = 1
|
||||||
|
RAR_EXTRACT = 2
|
||||||
|
|
||||||
|
RAR_VOL_ASK = 0
|
||||||
|
RAR_VOL_NOTIFY = 1
|
||||||
|
|
||||||
|
RAR_DLL_VERSION = 3
|
||||||
|
|
||||||
|
# enum UNRARCALLBACK_MESSAGES
|
||||||
|
UCM_CHANGEVOLUME = 0
|
||||||
|
UCM_PROCESSDATA = 1
|
||||||
|
UCM_NEEDPASSWORD = 2
|
||||||
|
|
||||||
|
architecture_bits = ctypes.sizeof(ctypes.c_voidp)*8
|
||||||
|
dll_name = "unrar.dll"
|
||||||
|
if architecture_bits == 64:
|
||||||
|
dll_name = "x64\\unrar64.dll"
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
unrar = ctypes.WinDLL(os.path.join(os.path.split(__file__)[0], 'UnRARDLL', dll_name))
|
||||||
|
except WindowsError:
|
||||||
|
unrar = ctypes.WinDLL(dll_name)
|
||||||
|
|
||||||
|
|
||||||
|
class RAROpenArchiveDataEx(ctypes.Structure):
|
||||||
|
def __init__(self, ArcName=None, ArcNameW=u'', OpenMode=RAR_OM_LIST):
|
||||||
|
self.CmtBuf = ctypes.c_buffer(64*1024)
|
||||||
|
ctypes.Structure.__init__(self, ArcName=ArcName, ArcNameW=ArcNameW, OpenMode=OpenMode, _CmtBuf=ctypes.addressof(self.CmtBuf), CmtBufSize=ctypes.sizeof(self.CmtBuf))
|
||||||
|
|
||||||
|
_fields_ = [
|
||||||
|
('ArcName', ctypes.c_char_p),
|
||||||
|
('ArcNameW', ctypes.c_wchar_p),
|
||||||
|
('OpenMode', ctypes.c_uint),
|
||||||
|
('OpenResult', ctypes.c_uint),
|
||||||
|
('_CmtBuf', ctypes.c_voidp),
|
||||||
|
('CmtBufSize', ctypes.c_uint),
|
||||||
|
('CmtSize', ctypes.c_uint),
|
||||||
|
('CmtState', ctypes.c_uint),
|
||||||
|
('Flags', ctypes.c_uint),
|
||||||
|
('Reserved', ctypes.c_uint*32),
|
||||||
|
]
|
||||||
|
|
||||||
|
class RARHeaderDataEx(ctypes.Structure):
|
||||||
|
def __init__(self):
|
||||||
|
self.CmtBuf = ctypes.c_buffer(64*1024)
|
||||||
|
ctypes.Structure.__init__(self, _CmtBuf=ctypes.addressof(self.CmtBuf), CmtBufSize=ctypes.sizeof(self.CmtBuf))
|
||||||
|
|
||||||
|
_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_voidp),
|
||||||
|
('CmtBufSize', ctypes.c_uint),
|
||||||
|
('CmtSize', ctypes.c_uint),
|
||||||
|
('CmtState', ctypes.c_uint),
|
||||||
|
('Reserved', ctypes.c_uint*1024),
|
||||||
|
]
|
||||||
|
|
||||||
|
def DosDateTimeToTimeTuple(dosDateTime):
|
||||||
|
"""Convert an MS-DOS format date time to a Python time tuple.
|
||||||
|
"""
|
||||||
|
dosDate = dosDateTime >> 16
|
||||||
|
dosTime = dosDateTime & 0xffff
|
||||||
|
day = dosDate & 0x1f
|
||||||
|
month = (dosDate >> 5) & 0xf
|
||||||
|
year = 1980 + (dosDate >> 9)
|
||||||
|
second = 2*(dosTime & 0x1f)
|
||||||
|
minute = (dosTime >> 5) & 0x3f
|
||||||
|
hour = dosTime >> 11
|
||||||
|
return time.localtime(time.mktime((year, month, day, hour, minute, second, 0, 1, -1)))
|
||||||
|
|
||||||
|
def _wrap(restype, function, argtypes):
|
||||||
|
result = function
|
||||||
|
result.argtypes = argtypes
|
||||||
|
result.restype = restype
|
||||||
|
return result
|
||||||
|
|
||||||
|
RARGetDllVersion = _wrap(ctypes.c_int, unrar.RARGetDllVersion, [])
|
||||||
|
|
||||||
|
RAROpenArchiveEx = _wrap(ctypes.wintypes.HANDLE, unrar.RAROpenArchiveEx, [ctypes.POINTER(RAROpenArchiveDataEx)])
|
||||||
|
|
||||||
|
RARReadHeaderEx = _wrap(ctypes.c_int, unrar.RARReadHeaderEx, [ctypes.wintypes.HANDLE, ctypes.POINTER(RARHeaderDataEx)])
|
||||||
|
|
||||||
|
_RARSetPassword = _wrap(ctypes.c_int, unrar.RARSetPassword, [ctypes.wintypes.HANDLE, ctypes.c_char_p])
|
||||||
|
def RARSetPassword(*args, **kwargs):
|
||||||
|
_RARSetPassword(*args, **kwargs)
|
||||||
|
|
||||||
|
RARProcessFile = _wrap(ctypes.c_int, unrar.RARProcessFile, [ctypes.wintypes.HANDLE, ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p])
|
||||||
|
|
||||||
|
RARCloseArchive = _wrap(ctypes.c_int, unrar.RARCloseArchive, [ctypes.wintypes.HANDLE])
|
||||||
|
|
||||||
|
UNRARCALLBACK = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_uint, ctypes.c_long, ctypes.c_long, ctypes.c_long)
|
||||||
|
RARSetCallback = _wrap(ctypes.c_int, unrar.RARSetCallback, [ctypes.wintypes.HANDLE, UNRARCALLBACK, ctypes.c_long])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RARExceptions = {
|
||||||
|
ERAR_NO_MEMORY : MemoryError,
|
||||||
|
ERAR_BAD_DATA : ArchiveHeaderBroken,
|
||||||
|
ERAR_BAD_ARCHIVE : InvalidRARArchive,
|
||||||
|
ERAR_EOPEN : FileOpenError,
|
||||||
|
}
|
||||||
|
|
||||||
|
class PassiveReader:
|
||||||
|
"""Used for reading files to memory"""
|
||||||
|
def __init__(self, usercallback = None):
|
||||||
|
self.buf = []
|
||||||
|
self.ucb = usercallback
|
||||||
|
|
||||||
|
def _callback(self, msg, UserData, P1, P2):
|
||||||
|
if msg == UCM_PROCESSDATA:
|
||||||
|
data = (ctypes.c_char*P2).from_address(P1).raw
|
||||||
|
if self.ucb!=None:
|
||||||
|
self.ucb(data)
|
||||||
|
else:
|
||||||
|
self.buf.append(data)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def get_result(self):
|
||||||
|
return ''.join(self.buf)
|
||||||
|
|
||||||
|
class RarInfoIterator(object):
|
||||||
|
def __init__(self, arc):
|
||||||
|
self.arc = arc
|
||||||
|
self.index = 0
|
||||||
|
self.headerData = RARHeaderDataEx()
|
||||||
|
self.res = RARReadHeaderEx(self.arc._handle, ctypes.byref(self.headerData))
|
||||||
|
if self.res==ERAR_BAD_DATA:
|
||||||
|
raise IncorrectRARPassword
|
||||||
|
self.arc.lockStatus = "locked"
|
||||||
|
self.arc.needskip = False
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
if self.index>0:
|
||||||
|
if self.arc.needskip:
|
||||||
|
RARProcessFile(self.arc._handle, RAR_SKIP, None, None)
|
||||||
|
self.res = RARReadHeaderEx(self.arc._handle, ctypes.byref(self.headerData))
|
||||||
|
|
||||||
|
if self.res:
|
||||||
|
raise StopIteration
|
||||||
|
self.arc.needskip = True
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['index'] = self.index
|
||||||
|
data['filename'] = self.headerData.FileName
|
||||||
|
data['datetime'] = DosDateTimeToTimeTuple(self.headerData.FileTime)
|
||||||
|
data['isdir'] = ((self.headerData.Flags & 0xE0) == 0xE0)
|
||||||
|
data['size'] = self.headerData.UnpSize + (self.headerData.UnpSizeHigh << 32)
|
||||||
|
if self.headerData.CmtState == 1:
|
||||||
|
data['comment'] = self.headerData.CmtBuf.value
|
||||||
|
else:
|
||||||
|
data['comment'] = None
|
||||||
|
self.index += 1
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.arc.lockStatus = "finished"
|
||||||
|
|
||||||
|
def generate_password_provider(password):
|
||||||
|
def password_provider_callback(msg, UserData, P1, P2):
|
||||||
|
if msg == UCM_NEEDPASSWORD and password!=None:
|
||||||
|
(ctypes.c_char*P2).from_address(P1).value = password
|
||||||
|
return 1
|
||||||
|
return password_provider_callback
|
||||||
|
|
||||||
|
class RarFileImplementation(object):
|
||||||
|
|
||||||
|
def init(self, password=None):
|
||||||
|
self.password = password
|
||||||
|
archiveData = RAROpenArchiveDataEx(ArcNameW=self.archiveName, OpenMode=RAR_OM_EXTRACT)
|
||||||
|
self._handle = RAROpenArchiveEx(ctypes.byref(archiveData))
|
||||||
|
self.c_callback = UNRARCALLBACK(generate_password_provider(self.password))
|
||||||
|
RARSetCallback(self._handle, self.c_callback, 1)
|
||||||
|
|
||||||
|
if archiveData.OpenResult != 0:
|
||||||
|
raise RARExceptions[archiveData.OpenResult]
|
||||||
|
|
||||||
|
if archiveData.CmtState == 1:
|
||||||
|
self.comment = archiveData.CmtBuf.value
|
||||||
|
else:
|
||||||
|
self.comment = None
|
||||||
|
|
||||||
|
if password:
|
||||||
|
RARSetPassword(self._handle, password)
|
||||||
|
|
||||||
|
self.lockStatus = "ready"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def destruct(self):
|
||||||
|
if self._handle and RARCloseArchive:
|
||||||
|
RARCloseArchive(self._handle)
|
||||||
|
|
||||||
|
def make_sure_ready(self):
|
||||||
|
if self.lockStatus == "locked":
|
||||||
|
raise InvalidRARArchiveUsage("cannot execute infoiter() without finishing previous one")
|
||||||
|
if self.lockStatus == "finished":
|
||||||
|
self.destruct()
|
||||||
|
self.init(self.password)
|
||||||
|
|
||||||
|
def infoiter(self):
|
||||||
|
self.make_sure_ready()
|
||||||
|
return RarInfoIterator(self)
|
||||||
|
|
||||||
|
def read_files(self, checker):
|
||||||
|
res = []
|
||||||
|
for info in self.infoiter():
|
||||||
|
if checker(info) and not info.isdir:
|
||||||
|
reader = PassiveReader()
|
||||||
|
c_callback = UNRARCALLBACK(reader._callback)
|
||||||
|
RARSetCallback(self._handle, c_callback, 1)
|
||||||
|
tmpres = RARProcessFile(self._handle, RAR_TEST, None, None)
|
||||||
|
if tmpres==ERAR_BAD_DATA:
|
||||||
|
raise IncorrectRARPassword
|
||||||
|
self.needskip = False
|
||||||
|
res.append((info, reader.get_result()))
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def extract(self, checker, path, withSubpath, overwrite):
|
||||||
|
res = []
|
||||||
|
for info in self.infoiter():
|
||||||
|
checkres = checker(info)
|
||||||
|
if checkres!=False and not info.isdir:
|
||||||
|
if checkres==True:
|
||||||
|
fn = info.filename
|
||||||
|
if not withSubpath:
|
||||||
|
fn = os.path.split(fn)[-1]
|
||||||
|
target = os.path.join(path, fn)
|
||||||
|
else:
|
||||||
|
raise DeprecationWarning, "Condition callbacks returning strings are deprecated and only supported in Windows"
|
||||||
|
target = checkres
|
||||||
|
if overwrite or (not os.path.exists(target)):
|
||||||
|
tmpres = RARProcessFile(self._handle, RAR_EXTRACT, None, target)
|
||||||
|
if tmpres==ERAR_BAD_DATA:
|
||||||
|
raise IncorrectRARPassword
|
||||||
|
|
||||||
|
self.needskip = False
|
||||||
|
res.append(info)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue