From d2f49a0759ec97369fca9c5cad467a9b00f8dcab Mon Sep 17 00:00:00 2001 From: Alexandre Beloin Date: Wed, 21 Jan 2015 21:15:23 -0500 Subject: [PATCH] Update unrar2 from 0.99.3 to 0.99.6 --- lib/unrar2/.hgignore | 6 +- lib/unrar2/.hgtags | 3 + lib/unrar2/MANIFEST.in | 4 +- lib/unrar2/PKG-INFO | 27 - lib/unrar2/UnRAR2.html | 388 ++++----- lib/unrar2/UnRARDLL/unrar.h | 280 +++---- lib/unrar2/UnRARDLL/unrardll.txt | 1212 ++++++++++++++-------------- lib/unrar2/UnRARDLL/whatsnew.txt | 160 ++-- lib/unrar2/UnRARDLL/x64/readme.txt | 2 +- lib/unrar2/[test].rar | Bin 0 -> 84 bytes lib/unrar2/[test].txt | 2 + lib/unrar2/__init__.py | 357 ++++---- lib/unrar2/license.txt | 42 +- lib/unrar2/setup.py | 108 +-- lib/unrar2/test_UnRAR2.py | 325 ++++---- lib/unrar2/test_volumes.part1.rar | Bin 0 -> 17408 bytes lib/unrar2/test_volumes.part2.rar | Bin 0 -> 7471 bytes lib/unrar2/test_volumes_old.r00 | Bin 0 -> 7471 bytes lib/unrar2/test_volumes_old.rar | Bin 0 -> 17408 bytes lib/unrar2/unix.py | 45 +- lib/unrar2/windows.py | 35 +- sickbeard/providers/torrentday.py | 54 +- 22 files changed, 1571 insertions(+), 1479 deletions(-) delete mode 100644 lib/unrar2/PKG-INFO create mode 100644 lib/unrar2/[test].rar create mode 100644 lib/unrar2/[test].txt create mode 100644 lib/unrar2/test_volumes.part1.rar create mode 100644 lib/unrar2/test_volumes.part2.rar create mode 100644 lib/unrar2/test_volumes_old.r00 create mode 100644 lib/unrar2/test_volumes_old.rar diff --git a/lib/unrar2/.hgignore b/lib/unrar2/.hgignore index 28998a5c..7b51655b 100644 --- a/lib/unrar2/.hgignore +++ b/lib/unrar2/.hgignore @@ -1,4 +1,4 @@ -syntax: glob - -*.pyc +syntax: glob + +*.pyc build/* \ No newline at end of file diff --git a/lib/unrar2/.hgtags b/lib/unrar2/.hgtags index 9f0fd548..e94a771c 100644 --- a/lib/unrar2/.hgtags +++ b/lib/unrar2/.hgtags @@ -2,3 +2,6 @@ f2570b5f7205f1433661a9508f464f691cf63389 0.97 d3595b2c9a1aec510f8ae1dcfef1eb8562a77fc0 0.99.1 d23822f936c663784c5edda09cd5a6effe1e882d 0.99.2 855a137f51581bd6d7a79264856020aa52fd0b66 0.99.3 +160655e623388d65c35ac4c8e271b58566e8a489 0.99.4 +8225eb999c02735d0aead538870c91270d41df0c 0.99.5 +734f8f605597616bc102b60ca1e959d3a0ace5b6 0.99.6 diff --git a/lib/unrar2/MANIFEST.in b/lib/unrar2/MANIFEST.in index e7ce0a66..cf17db9d 100644 --- a/lib/unrar2/MANIFEST.in +++ b/lib/unrar2/MANIFEST.in @@ -1,2 +1,2 @@ -recursive-include UnRARDLL *.* -include test.rar UnRAR2.html license.txt +recursive-include UnRARDLL *.* +include test.rar UnRAR2.html license.txt diff --git a/lib/unrar2/PKG-INFO b/lib/unrar2/PKG-INFO deleted file mode 100644 index 4d0117f1..00000000 --- a/lib/unrar2/PKG-INFO +++ /dev/null @@ -1,27 +0,0 @@ -Metadata-Version: 1.1 -Name: pyUnRAR2 -Version: 0.99.3 -Summary: Improved Python wrapper around the free UnRAR.dll -Home-page: http://code.google.com/py-unrar2 -Author: Konstantin Yegupov -Author-email: yk4ever@gmail.com -License: MIT -Description: 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. -Platform: Windows -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Win32 (MS Windows) -Classifier: License :: OSI Approved :: MIT License -Classifier: Natural Language :: English -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: Python -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Archiving :: Compression diff --git a/lib/unrar2/UnRAR2.html b/lib/unrar2/UnRAR2.html index fa4d2057..ea5b0bac 100644 --- a/lib/unrar2/UnRAR2.html +++ b/lib/unrar2/UnRAR2.html @@ -1,194 +1,196 @@ - - -Python: package UnRAR2 - - - - -
 
- 
UnRAR2 (version 0.99.2)
index
/home/rainman/dev/py-unrar2/UnRAR2/__init__.py
-

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.

-

- - - - - -
 
-Package Contents
       
UnRAR2 (package)
-rar_exceptions
-
setup
-test_UnRAR2
-
unix
-windows
-

- - - - - -
 
-Classes
       
-
UnRAR2.unix.RarFileImplementation(__builtin__.object) -
-
-
RarFile -
-
-
__builtin__.object -
-
-
RarInfo -
-
-
-

- - - - - -
 
-class RarFile(UnRAR2.unix.RarFileImplementation)
    
Method resolution order:
-
RarFile
-
UnRAR2.unix.RarFileImplementation
-
__builtin__.object
-
-
-Methods defined here:
-
__del__(self)
- -
__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.
- -
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.
- -
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
- -
infolist(self)
Return a list of RarInfos, descripting the contents of the archive.
- -
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)
- -
-Methods inherited from UnRAR2.unix.RarFileImplementation:
-
call(self, cmd, options=[], files=[])
- -
destruct(self)
- -
escaped_password(self)
- -
init(self, password=None)
- -
-Data descriptors inherited from UnRAR2.unix.RarFileImplementation:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-

- - - - - - - -
 
-class RarInfo(__builtin__.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.
 
 Methods defined here:
-
__init__(self, rarfile, data)
- -
__str__(self)
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-

- - - - - -
 
-Functions
       
condition2checker(condition)
Converts different condition types to callback
-

- - - - - -
 
-Data
       __version__ = '0.99.2'
-in_windows = False
+ + +Python: package UnRAR2 + + + + + +
 
+ 
UnRAR2 (version 0.99.5)
index
z:\py-unrar2\unrar2\__init__.py
+

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.

+

+ + + + + +
 
+Package Contents
       
UnRAR2 (package)
+rar_exceptions
+
setup
+test_UnRAR2
+
unix
+windows
+

+ + + + + +
 
+Classes
       
+
UnRAR2.windows.RarFileImplementation(__builtin__.object) +
+
+
RarFile +
+
+
__builtin__.object +
+
+
RarInfo +
+
+
+

+ + + + + +
 
+class RarFile(UnRAR2.windows.RarFileImplementation)
    
Method resolution order:
+
RarFile
+
UnRAR2.windows.RarFileImplementation
+
__builtin__.object
+
+
+Methods defined here:
+
__del__(self)
+ +
__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.
+ +
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.
+ +
get_volume(self)
Determine which volume is it in a multi-volume archive. Returns None if it's not a 
+multi-volume archive, 0-based volume number otherwise.
+ +
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
+ +
infolist(self)
Return a list of RarInfos, descripting the contents of the archive.
+ +
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)
+ +
+Methods inherited from UnRAR2.windows.RarFileImplementation:
+
destruct(self)
+ +
init(self, password=None)
+ +
make_sure_ready(self)
+ +
+Data descriptors inherited from UnRAR2.windows.RarFileImplementation:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + + + +
 
+class RarInfo(__builtin__.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.
 
 Methods defined here:
+
__init__(self, rarfile, data)
+ +
__str__(self)
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + +
 
+Functions
       
condition2checker(condition)
Converts different condition types to callback
+

+ + + + + +
 
+Data
       __version__ = '0.99.5'
+in_windows = True
\ No newline at end of file diff --git a/lib/unrar2/UnRARDLL/unrar.h b/lib/unrar2/UnRARDLL/unrar.h index 4582f2c6..7643fa71 100644 --- a/lib/unrar2/UnRARDLL/unrar.h +++ b/lib/unrar2/UnRARDLL/unrar.h @@ -1,140 +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 +#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 diff --git a/lib/unrar2/UnRARDLL/unrardll.txt b/lib/unrar2/UnRARDLL/unrardll.txt index c49dd5b4..291c8715 100644 --- a/lib/unrar2/UnRARDLL/unrardll.txt +++ b/lib/unrar2/UnRARDLL/unrardll.txt @@ -1,606 +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. - + + 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. + diff --git a/lib/unrar2/UnRARDLL/whatsnew.txt b/lib/unrar2/UnRARDLL/whatsnew.txt index 874d19b1..84ad72cb 100644 --- a/lib/unrar2/UnRARDLL/whatsnew.txt +++ b/lib/unrar2/UnRARDLL/whatsnew.txt @@ -1,80 +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. +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. diff --git a/lib/unrar2/UnRARDLL/x64/readme.txt b/lib/unrar2/UnRARDLL/x64/readme.txt index bbfb340d..8f3b4e10 100644 --- a/lib/unrar2/UnRARDLL/x64/readme.txt +++ b/lib/unrar2/UnRARDLL/x64/readme.txt @@ -1 +1 @@ -This is x64 version of unrar.dll. +This is x64 version of unrar.dll. diff --git a/lib/unrar2/[test].rar b/lib/unrar2/[test].rar new file mode 100644 index 0000000000000000000000000000000000000000..1498d2ce20077a8ce0fca15faeb26d8f54273f86 GIT binary patch literal 84 zcmWGaEK-zWXE;Bhn1O+p0Rj&EC{dW8&%g!bfiP3FqoMu6UDkH823!mZK!NCz)Z&s@ ay^@L&h7BAmOF=wdE)aRdwwl3#odEzI&J^_k literal 0 HcmV?d00001 diff --git a/lib/unrar2/[test].txt b/lib/unrar2/[test].txt new file mode 100644 index 00000000..ce3f303d --- /dev/null +++ b/lib/unrar2/[test].txt @@ -0,0 +1,2 @@ +test +test \ No newline at end of file diff --git a/lib/unrar2/__init__.py b/lib/unrar2/__init__.py index fe27cfe1..516a82f4 100644 --- a/lib/unrar2/__init__.py +++ b/lib/unrar2/__init__.py @@ -1,177 +1,180 @@ -# 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.3' - -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 '' % (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 - - +# 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.6' + +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 '' % (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 get_volume(self): + """Determine which volume is it in a multi-volume archive. Returns None if it's not a + multi-volume archive, 0-based volume number otherwise.""" + return RarFileImplementation.get_volume(self) + +def condition2checker(condition): + """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 + + diff --git a/lib/unrar2/license.txt b/lib/unrar2/license.txt index a395801b..121b2f14 100644 --- a/lib/unrar2/license.txt +++ b/lib/unrar2/license.txt @@ -1,21 +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. +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. diff --git a/lib/unrar2/setup.py b/lib/unrar2/setup.py index 7fab60fe..99a07fc8 100644 --- a/lib/unrar2/setup.py +++ b/lib/unrar2/setup.py @@ -1,54 +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}, - ) +# 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}, + ) diff --git a/lib/unrar2/test_UnRAR2.py b/lib/unrar2/test_UnRAR2.py index 13c092b6..478b49fc 100644 --- a/lib/unrar2/test_UnRAR2.py +++ b/lib/unrar2/test_UnRAR2.py @@ -1,138 +1,187 @@ -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)) - - -# basic test -cleanup() -rarc = UnRAR2.RarFile('test.rar') -rarc.infolist() -assert rarc.comment == "This is a test." -for info in rarc.infoiter(): - saveinfo = info - assert (str(info)=="""""") - 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)=="""""") -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() -rarc = UnRAR2.RarFile('test_protected_files.rar', password="protected") -rarc.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 +import os,sys,inspect +currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +parentdir = os.path.dirname(currentdir) +sys.path.insert(0,parentdir) + +import unrar2 as 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)) + + +# basic test +cleanup() +rarc = UnRAR2.RarFile('test.rar') +assert rarc.get_volume() == None +rarc.infolist() +assert rarc.comment == "This is a test." +for info in rarc.infoiter(): + saveinfo = info + assert (str(info)=="""""") + 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)=="""""") +cleanup() + +# shell-unsafe-name test +cleanup() +rarc = UnRAR2.RarFile('[test].rar') +rarc.infolist() +for info in rarc.infoiter(): + saveinfo = info + assert (str(info)=="""""") + break +rarc.extract() +assert os.path.exists('[test].txt') +del rarc +assert (str(saveinfo)=="""""") +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() +rarc = UnRAR2.RarFile('test_protected_files.rar', password="protected") +rarc.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() +errored = False +try: + UnRAR2.RarFile('test_protected_files.rar').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() +errored = False +try: + UnRAR2.RarFile('test_protected_headers.rar').extract() +except IncorrectRARPassword: + errored = True +assert not os.path.exists('test'+os.sep+'top_secret_xxx_file.txt') +assert errored +cleanup() + +# check volume number +cleanup() +rarc1 = UnRAR2.RarFile('test_volumes.part1.rar') +assert rarc1.get_volume() == 0 +rarc2 = UnRAR2.RarFile('test_volumes.part2.rar') +assert rarc2.get_volume() == 1 +cleanup() +rarc1 = UnRAR2.RarFile('test_volumes_old.rar') +assert rarc1.get_volume() == 0 +rarc2 = UnRAR2.RarFile('test_volumes_old.r00') +assert rarc2.get_volume() == 1 +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 diff --git a/lib/unrar2/test_volumes.part1.rar b/lib/unrar2/test_volumes.part1.rar new file mode 100644 index 0000000000000000000000000000000000000000..6a60152ff13526db9a92ee8dc0673d1dd6f0a13e GIT binary patch literal 17408 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 DhaBxT literal 0 HcmV?d00001 diff --git a/lib/unrar2/test_volumes.part2.rar b/lib/unrar2/test_volumes.part2.rar new file mode 100644 index 0000000000000000000000000000000000000000..0f4119a8958f587a627be0097c37c364724d9c78 GIT binary patch literal 7471 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 literal 0 HcmV?d00001 diff --git a/lib/unrar2/test_volumes_old.r00 b/lib/unrar2/test_volumes_old.r00 new file mode 100644 index 0000000000000000000000000000000000000000..d7ee09ab0ad3e1c0d13d6f2c32329896d7936e53 GIT binary patch literal 7471 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 literal 0 HcmV?d00001 diff --git a/lib/unrar2/test_volumes_old.rar b/lib/unrar2/test_volumes_old.rar new file mode 100644 index 0000000000000000000000000000000000000000..9f35591f190154fdf301ce7c3c50184b25ab8019 GIT binary patch literal 17408 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 D@!;;j literal 0 HcmV?d00001 diff --git a/lib/unrar2/unix.py b/lib/unrar2/unix.py index bd9ee859..12cced48 100644 --- a/lib/unrar2/unix.py +++ b/lib/unrar2/unix.py @@ -74,13 +74,13 @@ class RarFileImplementation(object): accum = [] source = iter(stdoutdata.splitlines()) line = '' - while not (line.startswith('UNRAR')): + while (line.find('RAR ') == -1): line = source.next() signature = line # The code below is mighty flaky # and will probably crash on localized versions of RAR # but I see no safe way to rewrite it using a CLI tool - if signature.startswith("UNRAR 4"): + if signature.find("RAR 4") > -1: rar_executable_version = 4 while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')): if line.strip().endswith('is not RAR archive'): @@ -94,7 +94,7 @@ class RarFileImplementation(object): self.comment = '\n'.join(accum[:-1]) else: self.comment = None - elif signature.startswith("UNRAR 5"): + elif signature.find("RAR 5") > -1: rar_executable_version = 5 line = source.next() while not line.startswith('Archive:'): @@ -155,6 +155,7 @@ class RarFileImplementation(object): data['isdir'] = 'd' in attr.lower() data['datetime'] = time.strptime(fields[3]+" "+fields[4], '%d-%m-%y %H:%M') data['comment'] = None + data['volume'] = None yield data accum = [] i += 1 @@ -170,6 +171,7 @@ class RarFileImplementation(object): data['isdir'] = 'd' in attr.lower() data['datetime'] = time.strptime(fields[2]+" "+fields[3], '%d-%m-%y %H:%M') data['comment'] = None + data['volume'] = None yield data i += 1 line = source.next() @@ -214,5 +216,42 @@ class RarFileImplementation(object): def destruct(self): pass + + def get_volume(self): + command = "v" if rar_executable_version == 4 else "l" + stdoutdata, stderrdata = self.call(command, ['c-']).communicate() + + for line in stderrdata.splitlines(): + if line.strip().startswith("Cannot open"): + raise FileOpenError + + source = iter(stdoutdata.splitlines()) + line = '' + while not line.startswith('-----------'): + if line.strip().endswith('is not RAR archive'): + raise InvalidRARArchive + if line.startswith("CRC failed") or line.startswith("Checksum error"): + raise IncorrectRARPassword + line = source.next() + line = source.next() + if rar_executable_version == 4: + while not line.startswith('-----------'): + line = source.next() + line = source.next() + items = line.strip().split() + if len(items)>4 and items[4]=="volume": + return int(items[5]) - 1 + else: + return None + + elif rar_executable_version == 5: + while not line.startswith('-----------'): + line = source.next() + line = source.next() + items = line.strip().split() + if items[1]=="volume": + return int(items[2]) - 1 + else: + return None diff --git a/lib/unrar2/windows.py b/lib/unrar2/windows.py index bb92481b..19cca3d7 100644 --- a/lib/unrar2/windows.py +++ b/lib/unrar2/windows.py @@ -25,7 +25,7 @@ from __future__ import generators import ctypes, ctypes.wintypes -import os, os.path, sys +import os, os.path, sys, re import Queue import time @@ -43,6 +43,7 @@ ERAR_EREAD = 18 ERAR_EWRITE = 19 ERAR_SMALL_BUF = 20 ERAR_UNKNOWN = 21 +ERAR_MISSING_PASSWORD = 22 RAR_OM_LIST = 0 RAR_OM_EXTRACT = 1 @@ -66,6 +67,9 @@ dll_name = "unrar.dll" if architecture_bits == 64: dll_name = "x64\\unrar64.dll" +volume_naming1 = re.compile("\.r([0-9]{2})$") +volume_naming2 = re.compile("\.([0-9]{3}).rar$") +volume_naming3 = re.compile("\.part([0-9]+).rar$") try: unrar = ctypes.WinDLL(os.path.join(os.path.split(__file__)[0], 'UnRARDLL', dll_name)) @@ -188,7 +192,7 @@ class RarInfoIterator(object): self.index = 0 self.headerData = RARHeaderDataEx() self.res = RARReadHeaderEx(self.arc._handle, ctypes.byref(self.headerData)) - if self.res==ERAR_BAD_DATA: + if self.res in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]: raise IncorrectRARPassword self.arc.lockStatus = "locked" self.arc.needskip = False @@ -208,7 +212,7 @@ class RarInfoIterator(object): data = {} data['index'] = self.index - data['filename'] = self.headerData.FileName + data['filename'] = self.headerData.FileNameW data['datetime'] = DosDateTimeToTimeTuple(self.headerData.FileTime) data['isdir'] = ((self.headerData.Flags & 0xE0) == 0xE0) data['size'] = self.headerData.UnpSize + (self.headerData.UnpSizeHigh << 32) @@ -251,7 +255,8 @@ class RarFileImplementation(object): RARSetPassword(self._handle, password) self.lockStatus = "ready" - + + self.isVolume = archiveData.Flags & 1 def destruct(self): @@ -277,7 +282,7 @@ class RarFileImplementation(object): c_callback = UNRARCALLBACK(reader._callback) RARSetCallback(self._handle, c_callback, 1) tmpres = RARProcessFile(self._handle, RAR_TEST, None, None) - if tmpres==ERAR_BAD_DATA: + if tmpres in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]: raise IncorrectRARPassword self.needskip = False res.append((info, reader.get_result())) @@ -299,11 +304,29 @@ class RarFileImplementation(object): target = checkres if overwrite or (not os.path.exists(target)): tmpres = RARProcessFile(self._handle, RAR_EXTRACT, None, target) - if tmpres==ERAR_BAD_DATA: + if tmpres in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]: raise IncorrectRARPassword self.needskip = False res.append(info) return res + def get_volume(self): + if not self.isVolume: + return None + headerData = RARHeaderDataEx() + res = RARReadHeaderEx(self._handle, ctypes.byref(headerData)) + arcName = headerData.ArcNameW + match3 = volume_naming3.search(arcName) + if match3 != None: + return int(match3.group(1)) - 1 + match2 = volume_naming3.search(arcName) + if match2 != None: + return int(match2.group(1)) + match1 = volume_naming1.search(arcName) + if match1 != None: + return int(match1.group(1)) + 1 + return 0 + + diff --git a/sickbeard/providers/torrentday.py b/sickbeard/providers/torrentday.py index 9b6738d3..29aef590 100644 --- a/sickbeard/providers/torrentday.py +++ b/sickbeard/providers/torrentday.py @@ -1,19 +1,19 @@ # Author: Mr_Orange # -# This file is part of SickRage. +# This file is part of SickGear. # -# SickRage is free software: you can redistribute it and/or modify +# SickGear 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. # -# SickRage is distributed in the hope that it will be useful, +# SickGear 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 SickRage. If not, see . +# along with SickGear. If not, see . import re import datetime @@ -35,6 +35,11 @@ from sickbeard.helpers import sanitizeSceneName class TorrentDayProvider(generic.TorrentProvider): + urls = {'base_url': 'https://torrentday.eu', + 'login': 'https://torrentday.eu/torrents/', + 'search': 'https://torrentday.eu/V3/API/API.php', + 'download': 'https://torrentday.eu/download.php/%s/%s' + } def __init__(self): @@ -54,12 +59,6 @@ class TorrentDayProvider(generic.TorrentProvider): self.cache = TorrentDayCache(self) - self.urls = {'base_url': 'http://www.td.af', - 'login': 'http://www.td.af/torrents/', - 'search': 'http://www.td.af/V3/API/API.php', - 'download': 'http://www.td.af/download.php/%s/%s' - } - self.url = self.urls['base_url'] self.cookies = None @@ -84,7 +83,9 @@ class TorrentDayProvider(generic.TorrentProvider): return True if self._uid and self._hash: + requests.utils.add_dict_to_cookiejar(self.session.cookies, self.cookies) + else: login_params = {'username': self.username, @@ -93,9 +94,6 @@ class TorrentDayProvider(generic.TorrentProvider): 'submit.y': 0 } - if not self.session: - self.session = requests.Session() - try: response = self.session.post(self.urls['login'], data=login_params, timeout=30, verify=False) except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: @@ -110,20 +108,18 @@ class TorrentDayProvider(generic.TorrentProvider): logger.log(u'Invalid username or password for ' + self.name + ', Check your settings!', logger.ERROR) return False - try: - if requests.utils.dict_from_cookiejar(self.session.cookies)['uid'] and requests.utils.dict_from_cookiejar(self.session.cookies)['pass']: - self._uid = requests.utils.dict_from_cookiejar(self.session.cookies)['uid'] - self._hash = requests.utils.dict_from_cookiejar(self.session.cookies)['pass'] + if requests.utils.dict_from_cookiejar(self.session.cookies)['uid'] and requests.utils.dict_from_cookiejar(self.session.cookies)['pass']: + self._uid = requests.utils.dict_from_cookiejar(self.session.cookies)['uid'] + self._hash = requests.utils.dict_from_cookiejar(self.session.cookies)['pass'] - self.cookies = {'uid': self._uid, - 'pass': self._hash - } - return True - except: - pass + self.cookies = {'uid': self._uid, + 'pass': self._hash + } + return True - logger.log(u'Unable to obtain cookie for TorrentDay', logger.ERROR) - return False + else: + logger.log(u'Unable to obtain cookie for TorrentDay', logger.ERROR) + return False def _get_season_search_strings(self, ep_obj): @@ -169,7 +165,7 @@ class TorrentDayProvider(generic.TorrentProvider): for show_name in set(show_name_helpers.allPossibleShowNames(self.show)): ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, - 'episodenumber': ep_obj.scene_episode} + ' %s' % add_string + 'episodenumber': ep_obj.scene_episode} search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) @@ -183,7 +179,7 @@ class TorrentDayProvider(generic.TorrentProvider): freeleech = '&free=on' if self.freeleech else '' if not self._doLogin(): - return results + return [] for mode in search_params.keys(): for search_string in search_params[mode]: @@ -283,6 +279,8 @@ class TorrentDayCache(tvcache.TVCache): def _getRSSData(self): search_params = {'RSS': ['']} - return {'entries': self.provider._doSearch(search_params)} + return self.provider._doSearch(search_params) + + provider = TorrentDayProvider()