winamp/Src/external_dependencies/openmpt-trunk/unarchiver/unlha.cpp
2024-09-24 14:54:57 +02:00

163 lines
3.0 KiB
C++

/*
* unlha.cpp
* ---------
* Purpose: Implementation file for extracting modules from .lha archives, making use of lhasa
* 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 "unlha.h"
#ifdef MPT_WITH_LHASA
#include "lhasa.h"
#endif // MPT_WITH_LHASA
OPENMPT_NAMESPACE_BEGIN
#ifdef MPT_WITH_LHASA
static int LHAreadFileReader(void *handle, void *buf, size_t buf_len)
{
FileReader *f = reinterpret_cast<FileReader*>(handle);
int read_len = mpt::saturate_cast<int>(buf_len);
int result = mpt::saturate_cast<int>(f->ReadRaw(mpt::span(mpt::void_cast<std::byte*>(buf), read_len)).size());
if(result == 0)
{
return -1;
}
return result;
}
static int LHAskipFileReader(void *handle, size_t bytes)
{
FileReader *f = reinterpret_cast<FileReader*>(handle);
if(f->CanRead(bytes))
{
f->Skip(bytes);
return 1;
}
return 0;
}
static void LHAcloseFileReader(void * /*handle*/)
{
return;
}
static LHAInputStreamType vtable =
{
LHAreadFileReader,
LHAskipFileReader,
LHAcloseFileReader
};
CLhaArchive::CLhaArchive(FileReader &file) : ArchiveBase(file), inputstream(nullptr), reader(nullptr), firstfile(nullptr)
{
OpenArchive();
for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader))
{
ArchiveFileInfo info;
info.name = mpt::PathString::FromUnicode(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, fileheader->filename));
info.size = fileheader->length;
info.type = ArchiveFileType::Normal;
contents.push_back(info);
}
CloseArchive();
}
CLhaArchive::~CLhaArchive()
{
return;
}
void CLhaArchive::OpenArchive()
{
inFile.Rewind();
inputstream = lha_input_stream_new(&vtable, &inFile);
if(inputstream)
{
reader = lha_reader_new(inputstream);
}
if(reader)
{
lha_reader_set_dir_policy(reader, LHA_READER_DIR_END_OF_DIR);
firstfile = lha_reader_next_file(reader);
}
}
void CLhaArchive::CloseArchive()
{
if(reader)
{
lha_reader_free(reader);
reader = nullptr;
}
if(inputstream)
{
lha_input_stream_free(inputstream);
inputstream = nullptr;
}
}
bool CLhaArchive::ExtractFile(std::size_t index)
{
if(index >= contents.size())
{
return false;
}
data.clear();
OpenArchive();
const std::size_t bufSize = 4096;
std::size_t i = 0;
for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader))
{
if(index == i)
{
data.clear();
std::size_t countRead = 0;
do
{
try
{
data.resize(data.size() + bufSize);
} catch(...)
{
CloseArchive();
return false;
}
countRead = lha_reader_read(reader, &data[data.size() - bufSize], bufSize);
if(countRead < bufSize)
{
try
{
data.resize(data.size() - (bufSize - countRead));
} catch(...)
{
CloseArchive();
return false;
}
}
} while(countRead > 0);
}
++i;
}
CloseArchive();
return data.size() > 0;
}
#endif // MPT_WITH_LHASA
OPENMPT_NAMESPACE_END