Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
279
Src/external_dependencies/openmpt-trunk/unarchiver/unrar.cpp
Normal file
279
Src/external_dependencies/openmpt-trunk/unarchiver/unrar.cpp
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* unrar.cpp
|
||||
* ---------
|
||||
* Purpose: Implementation file for extracting modules from .rar archives
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "unrar.h"
|
||||
|
||||
#ifdef MPT_WITH_UNRAR
|
||||
|
||||
#include "../common/mptFileIO.h"
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#else // !MPT_OS_WINDOWS
|
||||
#ifdef _UNIX
|
||||
#define MPT_UNRAR_UNIX_WAS_DEFINED
|
||||
#else
|
||||
#define _UNIX
|
||||
#endif
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#include "unrar/dll.hpp"
|
||||
|
||||
#if !MPT_OS_WINDOWS
|
||||
#ifndef MPT_UNRAR_UNIX_WAS_DEFINED
|
||||
#undef _UNIX
|
||||
#undef MPT_UNRAR_UNIX_WAS_DEFINED
|
||||
#endif
|
||||
#endif // !MPT_OS_WINDOWS
|
||||
|
||||
#endif // MPT_WITH_UNRAR
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#ifdef MPT_WITH_UNRAR
|
||||
|
||||
|
||||
struct RARHandle // RAII
|
||||
{
|
||||
HANDLE rar = nullptr;
|
||||
explicit RARHandle(HANDLE rar_) : rar(rar_) { return; }
|
||||
RARHandle(const RARHandle &) = delete;
|
||||
~RARHandle() { if(rar) RARCloseArchive(rar); }
|
||||
|
||||
operator HANDLE () const { return rar; }
|
||||
};
|
||||
|
||||
|
||||
static int CALLBACK RARCallback(unsigned int msg, LPARAM userData, LPARAM p1, LPARAM p2)
|
||||
{
|
||||
int result = 0;
|
||||
CRarArchive *that = reinterpret_cast<CRarArchive *>(userData);
|
||||
switch(msg)
|
||||
{
|
||||
case UCM_PROCESSDATA:
|
||||
// Receive extracted data
|
||||
that->RARCallbackProcessData(reinterpret_cast<const char *>(p1), p2);
|
||||
result = 1;
|
||||
break;
|
||||
default:
|
||||
// No support for passwords or volumes
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void CRarArchive::RARCallbackProcessData(const char * buf, std::size_t size)
|
||||
{
|
||||
if(!captureCurrentFile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mpt::append(data, buf, buf + size);
|
||||
}
|
||||
|
||||
|
||||
CRarArchive::CRarArchive(FileReader &file)
|
||||
: ArchiveBase(file)
|
||||
{
|
||||
// NOTE:
|
||||
// We open the archive twice, once for listing the contents in the
|
||||
// constructor and once for actual decompression in ExtractFile.
|
||||
// For solid archives, listing the contents via RAR_OM_LIST is way faster.
|
||||
// The overhead of opening twice for non-solid archives is negligable if the
|
||||
// archive does not contain a lot of files (and archives with large amount of
|
||||
// files are pretty useless for OpenMPT anyway).
|
||||
|
||||
// Early reject files with no Rar! magic
|
||||
// so that we do not have to instantiate OnDiskFileWrapper.
|
||||
inFile.Rewind();
|
||||
if(!inFile.ReadMagic("Rar!\x1A"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
inFile.Rewind();
|
||||
|
||||
diskFile = std::make_unique<OnDiskFileWrapper>(inFile);
|
||||
if(!diskFile->IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::wstring ArcName = diskFile->GetFilename().ToWide();
|
||||
std::vector<wchar_t> ArcNameBuf(ArcName.c_str(), ArcName.c_str() + ArcName.length() + 1);
|
||||
std::vector<wchar_t> CmtBuf(65536);
|
||||
RAROpenArchiveDataEx ArchiveData = {};
|
||||
ArchiveData.OpenMode = RAR_OM_LIST;
|
||||
ArchiveData.ArcNameW = ArcNameBuf.data();
|
||||
ArchiveData.CmtBufW = CmtBuf.data();
|
||||
ArchiveData.CmtBufSize = static_cast<unsigned int>(CmtBuf.size());
|
||||
RARHandle rar(RAROpenArchiveEx(&ArchiveData));
|
||||
if(!rar)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(ArchiveData.CmtState)
|
||||
{
|
||||
case 1:
|
||||
if(ArchiveData.CmtSize)
|
||||
{
|
||||
comment = mpt::ToUnicode(std::wstring(ArchiveData.CmtBufW, ArchiveData.CmtBufW + ArchiveData.CmtSize - 1));
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case 0:
|
||||
comment = mpt::ustring();
|
||||
break;
|
||||
default:
|
||||
Reset();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
bool eof = false;
|
||||
int RARResult = 0;
|
||||
while(!eof)
|
||||
{
|
||||
RARHeaderDataEx HeaderData = {};
|
||||
RARResult = RARReadHeaderEx(rar, &HeaderData);
|
||||
switch(RARResult)
|
||||
{
|
||||
case ERAR_SUCCESS:
|
||||
break;
|
||||
case ERAR_END_ARCHIVE:
|
||||
eof = true;
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
Reset();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
ArchiveFileInfo fileInfo;
|
||||
fileInfo.name = mpt::PathString::FromWide(HeaderData.FileNameW);
|
||||
fileInfo.type = ArchiveFileType::Normal;
|
||||
fileInfo.size = HeaderData.UnpSize;
|
||||
contents.push_back(fileInfo);
|
||||
RARResult = RARProcessFileW(rar, RAR_SKIP, NULL, NULL);
|
||||
switch(RARResult)
|
||||
{
|
||||
case ERAR_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
Reset();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
CRarArchive::~CRarArchive()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CRarArchive::ExtractFile(std::size_t index)
|
||||
{
|
||||
|
||||
if(!diskFile || !diskFile->IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(index >= contents.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring ArcName = diskFile->GetFilename().ToWide();
|
||||
std::vector<wchar_t> ArcNameBuf(ArcName.c_str(), ArcName.c_str() + ArcName.length() + 1);
|
||||
RAROpenArchiveDataEx ArchiveData = {};
|
||||
ArchiveData.OpenMode = RAR_OM_EXTRACT;
|
||||
ArchiveData.ArcNameW = ArcNameBuf.data();
|
||||
ArchiveData.Callback = RARCallback;
|
||||
ArchiveData.UserData = reinterpret_cast<LPARAM>(this);
|
||||
RARHandle rar(RAROpenArchiveEx(&ArchiveData));
|
||||
if(!rar)
|
||||
{
|
||||
ResetFile();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t i = 0;
|
||||
int RARResult = 0;
|
||||
bool eof = false;
|
||||
while(!eof)
|
||||
{
|
||||
RARHeaderDataEx HeaderData = {};
|
||||
RARResult = RARReadHeaderEx(rar, &HeaderData);
|
||||
switch(RARResult)
|
||||
{
|
||||
case ERAR_SUCCESS:
|
||||
break;
|
||||
case ERAR_END_ARCHIVE:
|
||||
eof = true;
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
ResetFile();
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
captureCurrentFile = (i == index);
|
||||
RARResult = RARProcessFileW(rar, captureCurrentFile ? RAR_TEST : RAR_SKIP, NULL, NULL);
|
||||
switch(RARResult)
|
||||
{
|
||||
case ERAR_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
ResetFile();
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
if(captureCurrentFile)
|
||||
{ // done
|
||||
return true;
|
||||
}
|
||||
captureCurrentFile = false;
|
||||
++i;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CRarArchive::Reset()
|
||||
{
|
||||
captureCurrentFile = false;
|
||||
comment = mpt::ustring();
|
||||
contents = std::vector<ArchiveFileInfo>();
|
||||
data = std::vector<char>();
|
||||
}
|
||||
|
||||
|
||||
void CRarArchive::ResetFile()
|
||||
{
|
||||
captureCurrentFile = false;
|
||||
data = std::vector<char>();
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_WITH_UNRAR
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
Loading…
Add table
Add a link
Reference in a new issue