163 lines
3.0 KiB
C++
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
|