Merged luisangelsm/yacreader into default

This commit is contained in:
Felix Kauselmann
2015-08-20 12:28:47 +02:00
parent 3a6b2d9b98
commit 23c33cef61
64 changed files with 1758 additions and 877 deletions

View File

@ -1,7 +1,13 @@
If you are trying to compile YACReader, you need to donwload de source code of 7zip (Windows) or p7zip (Linux/MacOSX).
If you are trying to compile YACReader with a 7zip decompression backend, you need to download de source code of 7zip (Windows) or p7zip (Linux/MacOSX).
Please, extract it and rename the folder to lib7zip (Windows) or libp7zip (Linux/MacOSX), then copy it to $YACREADER_SRC/compressed_archive/ (this
folder). If you are using a 64 bit Linux-System, please apply libp7zip.patch for successfull compilation or use compileX11.sh.
Please extract it and rename the folder to lib7zip (Windows) or libp7zip (Linux/MacOSX), then copy it to $YACREADER_SRC/compressed_archive/ (this
folder).
YACReader is compiled using 7zip/p7zip 9.20.1
YACReader is compiled using 7zip/p7zip 9.20.1 and will not work with newer versions.
On Linux/Unix this means your YACReader installation will stop working if you update your installation of p7zip to a newer version. If you wish to keep using
p7zip with YACReader, you can copy 7z.so and Codecs/Rar29.so from p7zip 9.20.1 to "/usr/lib/yacreader/". YACReader will then detect these files and use
them instead of the system provided p7zip files which allows you to keep both YACReader and an up to date p7zip installation.
Please keep in mind this is only a workaround that is provided for backwards compatibility and not intended as a long time solution.
It is recommended that you switch to unarr as a decompression backend instead (see README.txt in compressed_archive/unarr).

View File

@ -18,7 +18,9 @@ DEFINE_GUID(CLSID_CFormatRar, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00,
DEFINE_GUID(CLSID_CFormatZip, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatTar, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0xee, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatArj, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0x04, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatBZip2, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00);
//unused Formats
/*DEFINE_GUID(CLSID_CFormatBZip2, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatCab, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatChm, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0xe9, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatCompound,0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0xe5, 0x00, 0x00);
@ -32,7 +34,7 @@ DEFINE_GUID(CLSID_CFormatNsis, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00,
DEFINE_GUID(CLSID_CFormatRpm, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0xeb, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatSplit, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0xea, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatWim, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0xe6, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatZ, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0x05, 0x00, 0x00);
DEFINE_GUID(CLSID_CFormatZ, 0x23170f69, 0x40c1, 0x278a, 0x10, 0x00, 0x00, 0x01, 0x10, 0x05, 0x00, 0x00);*/
#ifdef Q_OS_WIN
GUID _supportedFileFormats[] = {CLSID_CFormatRar,CLSID_CFormatZip,CLSID_CFormatTar,CLSID_CFormat7z,CLSID_CFormatArj};
@ -71,6 +73,13 @@ struct SevenZipInterface {
//SevenZipInterface * szInterface;
const char rar[7]={static_cast<char>(0x52), static_cast<char>(0x61), static_cast<char>(0x72), static_cast<char>(0x21), static_cast<char>(0x1A), static_cast<char>(0x07), static_cast<char>(0x00)};
const char rar5[8]={static_cast<char>(0x52), static_cast<char>(0x61), static_cast<char>(0x72), static_cast<char>(0x21), static_cast<char>(0x1A), static_cast<char>(0x07), static_cast<char>(0x01), static_cast<char>(0x00)};
const char zip[2]={static_cast<char>(0x50), static_cast<char>(0x4B)};
const char sevenz[6]={static_cast<char>(0x37), static_cast<char>(0x7A), static_cast<char>(0xBC), static_cast<char>(0xAF), static_cast<char>(0x27), static_cast<char>(0x1C)};
const char tar[6]="ustar";
const char arj[2]={static_cast<char>(0x60), static_cast<char>(0xEA)};
CompressedArchive::CompressedArchive(const QString & filePath, QObject *parent) :
QObject(parent),sevenzLib(0),valid(false),tools(false)
#ifdef Q_OS_UNIX
@ -97,63 +106,145 @@ CompressedArchive::CompressedArchive(const QString & filePath, QObject *parent)
openCallbackSpec->PasswordIsDefined = false;
// openCallbackSpec->PasswordIsDefined = true;
// openCallbackSpec->Password = L"1";
for(unsigned int i=0;i<supportedFileFormats.size();i++)
//get file type from suffix
int i=-1;
QFile filex(filePath);
if (!filex.open(QIODevice::ReadOnly))
return;
QByteArray magicNumber=filex.read(8); //read first 8 bytes
//if (memcmp(magicNumber,rar5,8)==0)
//return; //rar5 is not supported
//qDebug() << memcmp(magicNumber,rar,7);
//TODO: this suffix matching is rather primitive - better approach?
#ifdef Q_OS_UNIX
if (memcmp(magicNumber,rar,6) != 0)
{
//match suffix to GUID list
if (memcmp(magicNumber,zip,2)==0)
i=0;
else if (memcmp(magicNumber,sevenz,6)==0)
i=2;
else if (memcmp(magicNumber,arj,2)==0)
i=3;
else
{
filex.seek(257);
magicNumber=filex.read(8);
if (memcmp(magicNumber,tar,5)==0)
i=1;
}
if (i==-1) //fallback code
{
QFileInfo fileinfo(filePath);
if (fileinfo.suffix() == "zip" || fileinfo.suffix() == "cbz")
{
i=0;
}
else
{
return;
}
}
#else
if (memcmp(magicNumber,rar,6) == 0)
if (memcmp(magicNumber,rar5,7) == 0)
return;
else
i=0;
else if (memcmp(magicNumber,zip,2)==0)
i=1;
else if (memcmp(magicNumber,sevenz,6)==0)
i=3;
else if (memcmp(magicNumber,arj,2)==0)
i=4;
else {
filex.seek(257);
magicNumber=filex.read(8);
if (memcmp(magicNumber,tar,5)==0)
i=2;
}
if (i==-1) //fallback code
{
QFileInfo fileinfo(filePath);
if (fileinfo.suffix() == "zip" || fileinfo.suffix() == "cbz")
{
i=1;
}
else
{
return;
}
}
#endif
#ifdef UNICODE
if (!fileSpec->Open((LPCTSTR)filePath.toStdWString().c_str()))
#else
if (!fileSpec->Open((LPCTSTR)filePath.toStdString().c_str()))
#endif
{
qDebug() << "unable to load" + filePath;
return;
}
//GUID uuid = supportedFileFormats[i];
//qDebug() << "trying : " << uuid << endl;
if (szInterface->createObjectFunc(&supportedFileFormats[i], &IID_InArchive, (void **)&szInterface->archive) != S_OK)
{
qDebug() << "wrong format";
continue;
}
#ifdef UNICODE
if (!fileSpec->Open((LPCTSTR)filePath.toStdWString().c_str()))
#else
if (!fileSpec->Open((LPCTSTR)filePath.toStdString().c_str()))
#endif
{
qDebug() << "unable to load" + filePath;
continue;
}
//qDebug() << "Can not open archive file : " + filePath << endl;
if (szInterface->createObjectFunc(&supportedFileFormats[i], &IID_InArchive, (void **)&szInterface->archive) == S_OK)
{
//qDebug() << "Can not open archive file : " + filePath << endl;
if (szInterface->archive->Open(file, 0, openCallback) == S_OK)
{
valid = formatFound = true;
break;
}
else
qDebug() << "Can not open archive file : " + filePath << endl;
{
valid = formatFound = true;
qDebug() << "Opened archive file : " + filePath << endl;
setupFilesNames();
return;
}
}
if(!formatFound)
{
#ifdef Q_OS_WIN
if(!formatFound)
{
qDebug() << "Can not open archive" << endl;
}
}
}
#else
}
else
{
if (memcmp(magicNumber,rar5,7) == 0)
return;//we don't support rar5
isRar=true; //tell the destructor we *tried* to open a rar file!
if (szInterface->createObjectFunc(&CLSID_CFormatRar, &IID_InArchive, (void **)&szInterface->archive) != S_OK)
{
qDebug() << "Error creating rar archive :" + filePath;
return;
}
CMyComPtr<ISetCompressCodecsInfo> codecsInfo;
CMyComPtr<ISetCompressCodecsInfo> codecsInfo;
if (szInterface->archive->QueryInterface(IID_ISetCompressCodecsInfo,(void **)&codecsInfo) != S_OK)
{
qDebug() << "Error getting rar codec :" + filePath;
return;
}
if (codecsInfo->SetCompressCodecsInfo(this) != S_OK)
{
qDebug() << "Error setting rar codec";
return;
return;
}
#ifdef UNICODE
if (!fileSpec->Open((LPCTSTR)filePath.toStdWString().data()))
if (!fileSpec->Open((LPCTSTR)filePath.toStdWString().c_str()))
#else
if (!fileSpec->Open((LPCTSTR)filePath.toStdString().data()))
if (!fileSpec->Open((LPCTSTR)filePath.toStdString().c_str()))
#endif
{
qDebug() << "Error opening rar file :" + filePath;
@ -164,25 +255,31 @@ CompressedArchive::CompressedArchive(const QString & filePath, QObject *parent)
if (szInterface->archive->Open(file, 0, openCallback) == S_OK)
{
valid = formatFound = true;
isRar = true;
setupFilesNames();
//isRar = true;
}
else
qDebug() << "Error opening rar archive";
#endif
}
}
}
#endif
CompressedArchive::~CompressedArchive()
{
//always close the archive!
if (szInterface->archive)
{
szInterface->archive->Close();
}
#ifdef Q_OS_UNIX
if(isRar) //TODO: fix this!!! Possible memory leak. If AddRef is not used, a crash occurs in "delete szInterface"
if(isRar) //TODO: Memory leak!!!! If AddRef is not used, a crash occurs in "delete szInterface"
{
szInterface->archive->AddRef();
}
#endif
if(valid) //TODO: fix this!!! Memory leak.
delete szInterface;
delete szInterface;
#ifdef Q_OS_UNIX
delete rarLib;
#endif
@ -191,27 +288,27 @@ CompressedArchive::~CompressedArchive()
bool CompressedArchive::loadFunctions()
{
//LOAD library
//TODO check if this works in OSX (7z.so instead of 7z.dylib)
// fix1: try to load "7z.so"
// fix2: rename 7z.so to 7z.dylib
if(sevenzLib == 0)
//LOAD library
//TODO check if this works in OSX (7z.so instead of 7z.dylib)
// fix1: try to load "7z.so"
// fix2: rename 7z.so to 7z.dylib
if(sevenzLib == 0)
{
#if defined Q_OS_UNIX
#if defined Q_OS_MAC
#if defined Q_OS_MAC
rarLib = new QLibrary(QCoreApplication::applicationDirPath()+"/utils/Codecs/Rar29");
#else
//check if a yacreader specific version of p7zip exists on the system
QFileInfo rarCodec(QString(LIBDIR)+"/yacreader/Codecs/Rar29.so");
if (rarCodec.exists())
{
rarLib = new QLibrary(rarCodec.absoluteFilePath());
}
else
{
rarLib = new QLibrary(QString(LIBDIR)+"/p7zip/Codecs/Rar29.so");
}
#endif
#else
//check if a yacreader specific version of p7zip exists on the system
QFileInfo rarCodec(QString(LIBDIR)+"/yacreader/Codecs/Rar29.so");
if (rarCodec.exists())
{
rarLib = new QLibrary(rarCodec.absoluteFilePath());
}
else
{
rarLib = new QLibrary(QString(LIBDIR)+"/p7zip/Codecs/Rar29.so");
}
#endif
if(!rarLib->load())
{
qDebug() << "Error Loading Rar29.so : " + rarLib->errorString() << endl;
@ -220,43 +317,43 @@ bool CompressedArchive::loadFunctions()
}
#endif
#if defined Q_OS_UNIX && !defined Q_OS_MAC
QFileInfo sevenzlibrary(QString(LIBDIR)+"/yacreader/7z.so");
if (sevenzlibrary.exists())
{
sevenzLib = new QLibrary(sevenzlibrary.absoluteFilePath());
}
else
{
sevenzLib = new QLibrary(QString(LIBDIR)+"/p7zip/7z.so");
}
QFileInfo sevenzlibrary(QString(LIBDIR)+"/yacreader/7z.so");
if (sevenzlibrary.exists())
{
sevenzLib = new QLibrary(sevenzlibrary.absoluteFilePath());
}
else
{
sevenzLib = new QLibrary(QString(LIBDIR)+"/p7zip/7z.so");
}
#else
sevenzLib = new QLibrary(QCoreApplication::applicationDirPath()+"/utils/7z");
#endif
}
if(!sevenzLib->load())
{
if(!sevenzLib->load())
{
qDebug() << "Error Loading 7z.dll : " + sevenzLib->errorString() << endl;
QCoreApplication::exit(700); //TODO yacreader_global can't be used here, it is GUI dependant, YACReader::SevenZNotFound
return false;
}
else
{
qDebug() << "Loading functions" << endl;
return false;
}
else
{
qDebug() << "Loading functions" << endl;
if((szInterface->createObjectFunc = (CreateObjectFunc)sevenzLib->resolve("CreateObject")) == 0)
qDebug() << "fail loading function : CreateObject" << endl;
if((szInterface->getMethodPropertyFunc = (GetMethodPropertyFunc)sevenzLib->resolve("GetMethodProperty")) == 0)
qDebug() << "fail loading function : GetMethodProperty" << endl;
if((szInterface->getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)sevenzLib->resolve("GetNumberOfMethods")) == 0)
qDebug() << "fail loading function : GetNumberOfMethods" << endl;
if((szInterface->getNumberOfFormatsFunc = (GetNumberOfFormatsFunc)sevenzLib->resolve("GetNumberOfFormats")) == 0)
qDebug() << "fail loading function : GetNumberOfFormats" << endl;
if((szInterface->getHandlerPropertyFunc = (GetHandlerPropertyFunc)sevenzLib->resolve("GetHandlerProperty")) == 0)
qDebug() << "fail loading function : GetHandlerProperty" << endl;
if((szInterface->getHandlerPropertyFunc2 = (GetHandlerPropertyFunc2)sevenzLib->resolve("GetHandlerProperty2")) == 0)
qDebug() << "fail loading function : GetHandlerProperty2" << endl;
if((szInterface->setLargePageModeFunc = (SetLargePageModeFunc)sevenzLib->resolve("SetLargePageMode")) == 0)
qDebug() << "fail loading function : SetLargePageMode" << endl;
if((szInterface->createObjectFunc = (CreateObjectFunc)sevenzLib->resolve("CreateObject")) == 0)
qDebug() << "fail loading function : CreateObject" << endl;
if((szInterface->getMethodPropertyFunc = (GetMethodPropertyFunc)sevenzLib->resolve("GetMethodProperty")) == 0)
qDebug() << "fail loading function : GetMethodProperty" << endl;
if((szInterface->getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)sevenzLib->resolve("GetNumberOfMethods")) == 0)
qDebug() << "fail loading function : GetNumberOfMethods" << endl;
if((szInterface->getNumberOfFormatsFunc = (GetNumberOfFormatsFunc)sevenzLib->resolve("GetNumberOfFormats")) == 0)
qDebug() << "fail loading function : GetNumberOfFormats" << endl;
if((szInterface->getHandlerPropertyFunc = (GetHandlerPropertyFunc)sevenzLib->resolve("GetHandlerProperty")) == 0)
qDebug() << "fail loading function : GetHandlerProperty" << endl;
if((szInterface->getHandlerPropertyFunc2 = (GetHandlerPropertyFunc2)sevenzLib->resolve("GetHandlerProperty2")) == 0)
qDebug() << "fail loading function : GetHandlerProperty2" << endl;
if((szInterface->setLargePageModeFunc = (SetLargePageModeFunc)sevenzLib->resolve("SetLargePageMode")) == 0)
qDebug() << "fail loading function : SetLargePageMode" << endl;
#ifdef Q_OS_UNIX
if((szInterface->createObjectFuncRar = (CreateObjectFunc)rarLib->resolve("CreateObject")) == 0)
@ -266,95 +363,127 @@ bool CompressedArchive::loadFunctions()
if((szInterface->getNumberOfMethodsFuncRar = (GetNumberOfMethodsFunc)rarLib->resolve("GetNumberOfMethods")) == 0)
qDebug() << "fail loading function (rar) : GetNumberOfMethods" << endl;
#endif
}
}
return true;
return true;
}
void CompressedArchive::setupFilesNames()
{
quint32 numItems = getNumEntries();
quint32 p = 0;
for (quint32 i = 0; i < numItems; i++)
{
// Get name of file
NWindows::NCOM::CPropVariant prop;
szInterface->archive->GetProperty(i, kpidIsDir, &prop);
bool isDir;
if (prop.vt == VT_BOOL)
isDir = VARIANT_BOOLToBool(prop.boolVal);
else if (prop.vt == VT_EMPTY)
isDir = false;
if(!isDir)
{
szInterface->archive->GetProperty(i, kpidPath, &prop);
UString s = ConvertPropVariantToString(prop);
const wchar_t * chars = s.operator const wchar_t *();
files.append(QString::fromWCharArray(chars));
offsets.append(i);
indexesToPages.insert(i,p);
p++;
}
}
}
QVector<quint32> CompressedArchive::translateIndexes(const QVector<quint32> & indexes)
{
QVector<quint32> translatedIndexes;
foreach(quint32 i, indexes)
{
if(i < offsets.length())
translatedIndexes.append(offsets.at(i));
}
return translatedIndexes;
}
QList<QString> CompressedArchive::getFileNames()
{
QList<QString> files;
quint32 numItems = getNumFiles();
for (quint32 i = 0; i < numItems; i++)
{
{
// Get name of file
NWindows::NCOM::CPropVariant prop;
/*szInterface->archive->GetProperty(i, kpidIsDir, &prop);
bool isDir;
if (prop.vt == VT_BOOL)
isDir = VARIANT_BOOLToBool(prop.boolVal);
else if (prop.vt == VT_EMPTY)
isDir = false;
if(!isDir)
{*/
szInterface->archive->GetProperty(i, kpidPath, &prop);
UString s = ConvertPropVariantToString(prop);
const wchar_t * chars = s.operator const wchar_t *();
files.append(QString::fromWCharArray(chars));
//}
}
}
return files;
return files;
}
bool CompressedArchive::isValid()
{
return valid;
return valid;
}
bool CompressedArchive::toolsLoaded()
{
return tools;
return tools;
}
int CompressedArchive::getNumFiles()
{
quint32 numItems = 0;
szInterface->archive->GetNumberOfItems(&numItems);
return numItems;
return files.length();
}
int CompressedArchive::getNumEntries()
{
quint32 numItems = 0;
szInterface->archive->GetNumberOfItems(&numItems);
return numItems;
}
QList<QByteArray> CompressedArchive::getAllData(const QVector<quint32> & indexes, ExtractDelegate * delegate)
{
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback(true,delegate);
CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
extractCallbackSpec->Init(szInterface->archive, L""); // second parameter is output folder path
extractCallbackSpec->PasswordIsDefined = false;
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback(indexesToPages, true, delegate);
CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
extractCallbackSpec->Init(szInterface->archive, L""); // second parameter is output folder path
extractCallbackSpec->PasswordIsDefined = false;
HRESULT result;
if(indexes.isEmpty())
result = szInterface->archive->Extract(NULL, -1, false, extractCallback);
else
result = szInterface->archive->Extract(indexes.data(), indexes.count(), false, extractCallback);
if (result != S_OK)
{
qDebug() << "Extract Error" << endl;
}
return extractCallbackSpec->allFiles;
QVector<quint32> currentIndexes = translateIndexes(indexes);
HRESULT result;
if(indexes.isEmpty())
result = szInterface->archive->Extract(NULL, -1, false, extractCallback);
else
result = szInterface->archive->Extract(currentIndexes.data(), currentIndexes.count(), false, extractCallback);
if (result != S_OK)
{
qDebug() << "Extract Error" << endl;
}
return extractCallbackSpec->allFiles;
}
QByteArray CompressedArchive::getRawDataAtIndex(int index)
{
if(index>=0 && index < getNumFiles())
{
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
extractCallbackSpec->Init(szInterface->archive, L""); // second parameter is output folder path
extractCallbackSpec->PasswordIsDefined = false;
if(index>=0 && index < getNumFiles())
{
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback(indexesToPages);
CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
extractCallbackSpec->Init(szInterface->archive, L""); // second parameter is output folder path
extractCallbackSpec->PasswordIsDefined = false;
UInt32 indices[1];
indices[0] = index;
HRESULT result = szInterface->archive->Extract(indices, 1, false, extractCallback);
if (result != S_OK)
{
qDebug() << "Extract Error" << endl;
}
return QByteArray((char *)extractCallbackSpec->data,extractCallbackSpec->newFileSize);
}
UInt32 indices[1];
if(index < offsets.length())
indices[0] = offsets.at(index);
else
indices[0] = index;
HRESULT result = szInterface->archive->Extract(indices, 1, false, extractCallback);
if (result != S_OK)
{
qDebug() << "Extract Error" << endl;
}
return QByteArray((char *)extractCallbackSpec->data,extractCallbackSpec->newFileSize);
}
return QByteArray();
}
@ -384,5 +513,3 @@ STDMETHODIMP CompressedArchive::CreateEncoder(UInt32 index, const GUID *interfac
}
#endif

View File

@ -28,6 +28,7 @@ typedef quint32 (_MY_WINAPI *SetLargePageModeFunc)();
class QLibrary;
#include <QString>
#include <QList>
#include <QMap>
struct SevenZipInterface;
@ -59,6 +60,7 @@ signals:
public slots:
int getNumFiles();
int getNumEntries();
QList<QByteArray> getAllData(const QVector<quint32> & indexes, ExtractDelegate * delegate = 0);
QByteArray getRawDataAtIndex(int index);
QList<QString> getFileNames();
@ -66,6 +68,7 @@ public slots:
bool toolsLoaded();
private:
SevenZipInterface * szInterface;
QLibrary * sevenzLib;
#ifdef Q_OS_UNIX
QLibrary * rarLib;
@ -73,6 +76,12 @@ private:
bool loadFunctions();
bool tools;
bool valid;
QList<QString> files;
QList<qint32> offsets;
QMap<qint32, qint32> indexesToPages;
void setupFilesNames();
QVector<quint32> translateIndexes(const QVector<quint32> &indexes);
friend class MyCodecs;
};

View File

@ -90,8 +90,9 @@ public:
UString Password;
Byte * data;
UInt64 newFileSize;
QMap<qint32, qint32> indexesToPages;
CArchiveExtractCallback(bool c = false,ExtractDelegate * d = 0) : PasswordIsDefined(false),all(c),delegate(d) {}
CArchiveExtractCallback(const QMap<qint32, qint32> & indexesToPages ,bool c = false,ExtractDelegate * d = 0) : PasswordIsDefined(false),all(c),delegate(d),indexesToPages(indexesToPages) {}
~CArchiveExtractCallback() {MidFree(data);}
};
@ -117,7 +118,11 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index,
{
*outStream = 0;
_outFileStream.Release();
_index = index;
if(indexesToPages.isEmpty())
_index = index;
else
_index = indexesToPages.value(index);
{
// Get Name

View File

@ -0,0 +1,6 @@
To use unarr as a decompression engine when building YACReader, download https://github.com/zeniko/unarr/archive/master.zip and extract it in this folder.
This will build unarr as a part of YACReader (static build).
If you're on a Linux/Unix system and prefer to use unarr as a shared library, have a look at https://github.com/selmf/unarr/
This fork of unarr includes a CMake based build system that allows you to build and install unarr as a shared library. YACReader will detect and use
the installed library at build time if it is installed.

View File

@ -0,0 +1,127 @@
#include "compressed_archive.h"
#include <QFileInfo>
#include <QDebug>
#include "extract_delegate.h"
extern"C" {
#include "unarr.h"
}
CompressedArchive::CompressedArchive(const QString & filePath, QObject *parent) :
QObject(parent),valid(false),tools(true),numFiles(0),ar(NULL),stream(NULL)
{
//open file
stream = ar_open_file(filePath.toStdString().c_str());
if (!stream)
{
return;
}
//open archive
ar = ar_open_rar_archive(stream);
//TODO: build unarr with 7z support and test this!
//if (!ar) ar = ar_open_7z_archive(stream);
if (!ar) ar = ar_open_tar_archive(stream);
//zip detection is costly, so it comes last...
if (!ar) ar = ar_open_zip_archive(stream, false);
if (!ar)
{
return;
}
//initial parse
while (ar_parse_entry(ar))
{
//make sure we really got a file header
if (ar_entry_get_size(ar) > 0)
{
fileNames.append(ar_entry_get_name(ar));
offsets.append(ar_entry_get_offset(ar));
numFiles++;
}
}
if (!ar_at_eof(ar))
{
//fail if the initial parse didn't reach EOF
//this might be a bit too drastic
qDebug() << "Error while parsing archive";
return;
}
if (numFiles > 0)
{
valid = true;
}
}
CompressedArchive::~CompressedArchive()
{
ar_close_archive(ar);
ar_close(stream);
}
QList<QString> CompressedArchive::getFileNames()
{
return fileNames;
}
bool CompressedArchive::isValid()
{
return valid;
}
bool CompressedArchive::toolsLoaded()
{
//for backwards compatibilty
return tools;
}
int CompressedArchive::getNumFiles()
{
return numFiles;
}
void CompressedArchive::getAllData(const QVector<quint32> & indexes, ExtractDelegate * delegate)
{
if (indexes.isEmpty())
return;
QByteArray buffer;
int i=0;
while (i < indexes.count())
{
//use the offset list so we generated so we're not getting any non-page files
ar_parse_entry_at(ar, offsets.at(indexes.at(i))); //set ar_entry to start of indexes
buffer.resize(ar_entry_get_size(ar));
if (ar_entry_uncompress(ar, buffer.data(), buffer.size())) //did we extract it?
{
delegate->fileExtracted(indexes.at(i), buffer); //return extracted file
}
else
{
delegate->crcError(indexes.at(i)); //we could not extract it...
}
i++;
}
}
QByteArray CompressedArchive::getRawDataAtIndex(int index)
{
QByteArray buffer;
if(index >= 0 && index < getNumFiles())
{
ar_parse_entry_at(ar, offsets.at(index));
buffer.resize(ar_entry_get_size(ar));
if(ar_entry_uncompress(ar, buffer.data(), buffer.size()))
{
return buffer;
}
else
{
return QByteArray();
}
}
return buffer;
}

View File

@ -0,0 +1,37 @@
#ifndef COMPRESSED_ARCHIVE_H
#define COMPRESSED_ARCHIVE_H
#include <QObject>
#include "extract_delegate.h"
extern"C" {
#include "unarr.h"
}
class CompressedArchive : public QObject
{
Q_OBJECT
public:
explicit CompressedArchive(const QString & filePath, QObject *parent = 0);
~CompressedArchive();
signals:
public slots:
int getNumFiles();
void getAllData(const QVector<quint32> & indexes, ExtractDelegate * delegate=0);
QByteArray getRawDataAtIndex(int index);
QList<QString> getFileNames();
bool isValid();
bool toolsLoaded();
private:
bool tools;
bool valid;
QList<QString> fileNames;
int numFiles;
ar_archive *ar;
ar_stream *stream;
QList<qint64> offsets;
};
#endif // COMPRESSED_ARCHIVE_H

View File

@ -0,0 +1,14 @@
#ifndef EXTRACT_DELEGATE_H
#define EXTRACT_DELEGATE_H
#include <QByteArray>
class ExtractDelegate
{
public:
virtual void fileExtracted(int index, const QByteArray & rawData) = 0;
virtual void crcError(int index) = 0;
virtual void unknownError(int index) = 0;
};
#endif //EXTRACT_DELEGATE_H

View File

@ -0,0 +1,36 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/extract_delegate.h \
$$PWD/compressed_archive.h \
SOURCES += $$PWD/compressed_archive.cpp \
unix:!macx:exists (/usr/include/unarr.h) {
message(Using system provided unarr installation)
LIBS+=-lunarr
DEFINES+=use_unarr
}
else:macx:exists (../../dependencies/unarr/libunarr.dynlib) {
LIBS += -L../../dependencies/unarr/ -lunarr
DEFINES+=use_unarr
}
else:win32:exists (../../dependencies/unarr/unarr.dll) {
LIBS += -L../../dependencies/unarr/ -lunarr
DEFINES+=use_unarr
}
else:exists ($$PWD/unarr-master) {
message(Found unarr source-code)
message(Unarr will be build as a part of YACReader)
#qmake based unarr build system
#this should only be used for testing or as a last resort
include(unarr.pro)
DEFINES+=use_unarr
}
else {
error(Missing dependency: unarr decrompression backend. Please install libunarr on your system\
or provide a copy of the unarr source code in compressed_archive/unarr/unarr-master)
}

View File

@ -0,0 +1,51 @@
INCLUDEPATH += $$PWD/unarr-master/
DEPENDPATH += $$PWD/unarr-master/
HEADERS+=$$PWD/unarr-master/common/allocator.h\
$$PWD/unarr-master/common/unarr-imp.h\
$$PWD/unarr-master/lzmasdk/CpuArch.h\
$$PWD/unarr-master/lzmasdk/Ppmd7.h\
$$PWD/unarr-master/lzmasdk/Ppmd.h\
$$PWD/unarr-master/lzmasdk/LzmaDec.h\
$$PWD/unarr-master/lzmasdk/Ppmd8.h\
$$PWD/unarr-master/lzmasdk/Types.h\
$$PWD/unarr-master/lzmasdk/CpuArch.h\
$$PWD/unarr-master/lzmasdk/Ppmd7.h\
$$PWD/unarr-master/lzmasdk/Ppmd.h\
$$PWD/unarr-master/lzmasdk/LzmaDec.h\
$$PWD/unarr-master/lzmasdk/Ppmd8.h\
$$PWD/unarr-master/lzmasdk/Types.h\
$$PWD/unarr-master/lzmasdk/CpuArch.h\
$$PWD/unarr-master/lzmasdk/Ppmd7.h\
$$PWD/unarr-master/lzmasdk/Ppmd.h\
$$PWD/unarr-master/lzmasdk/LzmaDec.h\
$$PWD/unarr-master/lzmasdk/Ppmd8.h\
$$PWD/unarr-master/lzmasdk/Types.h\
$$PWD/unarr-master/tar/tar.h\
$$PWD/unarr-master/_7z/_7z.h\
$$PWD/unarr-master/unarr.h
SOURCES+=$$PWD/unarr-master/common/conv.c\
$$PWD/unarr-master/common/custalloc.c\
$$PWD/unarr-master/common/unarr.c\
$$PWD/unarr-master/common/crc32.c\
$$PWD/unarr-master/common/stream.c\
$$PWD/unarr-master/lzmasdk/CpuArch.c\
$$PWD/unarr-master/lzmasdk/Ppmd7.c\
$$PWD/unarr-master/lzmasdk/Ppmd8.c\
$$PWD/unarr-master/lzmasdk/LzmaDec.c\
$$PWD/unarr-master/lzmasdk/Ppmd7Dec.c\
$$PWD/unarr-master/lzmasdk/Ppmd8Dec.c\
$$PWD/unarr-master/zip/inflate.c\
$$PWD/unarr-master/zip/parse-zip.c\
$$PWD/unarr-master/zip/uncompress-zip.c\
$$PWD/unarr-master/zip/zip.c\
$$PWD/unarr-master/rar/filter-rar.c\
$$PWD/unarr-master/rar/parse-rar.c\
$$PWD/unarr-master/rar/rarvm.c\
$$PWD/unarr-master/rar/huffman-rar.c\
$$PWD/unarr-master/rar/rar.c\
$$PWD/unarr-master/rar/uncompress-rar.c\
$$PWD/unarr-master/tar/parse-tar.c\
$$PWD/unarr-master/tar/tar.c\
$$PWD/unarr-master/_7z/_7z.c

View File

@ -1,6 +1,23 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
win32 {
!exists (../compressed_archive/lib7zip) {
error(You\'ll need 7zip source code to compile YACReader. \
Please check the compressed_archive folder for further instructions.)
}
}
unix {
exists (../compressed_archive/libp7zip) {
message(Found p7zip source code...)
system(patch -N -p0 -i libp7zip.patch)
} else {
error(You\'ll need 7zip source code to compile YACReader. \
Please check the compressed_archive folder for further instructions.)
}
}
CONFIG += precompile_header
win32 {PRECOMPILED_HEADER = $$PWD/StdAfx.h}