#include "CTarReader.h"
#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_
#include "CFileList.h"
#include "CLimitReadFile.h"
#include "os.h"
#include "coreutil.h"
#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
#include "errno.h"
#endif
namespace irr
{
namespace io
{
CArchiveLoaderTAR::CArchiveLoaderTAR(io::IFileSystem* fs)
: FileSystem(fs)
{
#ifdef _DEBUG
setDebugName("CArchiveLoaderTAR");
#endif
}
bool CArchiveLoaderTAR::isALoadableFileFormat(const io::path& filename) const
{
return core::hasFileExtension(filename, "tar");
}
bool CArchiveLoaderTAR::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const
{
return fileType == EFAT_TAR;
}
IFileArchive* CArchiveLoaderTAR::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const
{
IFileArchive *archive = 0;
io::IReadFile* file = FileSystem->createAndOpenFile(filename);
if (file)
{
archive = createArchive(file, ignoreCase, ignorePaths);
file->drop();
}
return archive;
}
IFileArchive* CArchiveLoaderTAR::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const
{
IFileArchive *archive = 0;
if (file)
{
file->seek(0);
archive = new CTarReader(file, ignoreCase, ignorePaths);
}
return archive;
}
bool CArchiveLoaderTAR::isALoadableFileFormat(io::IReadFile* file) const
{
if (file->getSize() % 512)
return false;
file->seek(0);
STarHeader fHead;
file->read(&fHead, sizeof(STarHeader));
u32 checksum = 0;
sscanf(fHead.Checksum, "%o", &checksum);
u32 checksum1=0;
s32 checksum2=0;
memset(fHead.Checksum, ' ', 8);
for (u8* p = (u8*)(&fHead); p < (u8*)(&fHead.Magic[0]); ++p)
{
checksum1 += *p;
checksum2 += c8(*p);
}
if (!strncmp(fHead.Magic, "ustar", 5))
{
for (u8* p = (u8*)(&fHead.Magic[0]); p < (u8*)(&fHead) + sizeof(fHead); ++p)
{
checksum1 += *p;
checksum2 += c8(*p);
}
}
return checksum1 == checksum || checksum2 == (s32)checksum;
}
CTarReader::CTarReader(IReadFile* file, bool ignoreCase, bool ignorePaths)
: CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file)
{
#ifdef _DEBUG
setDebugName("CTarReader");
#endif
if (File)
{
File->grab();
populateFileList();
sort();
}
}
CTarReader::~CTarReader()
{
if (File)
File->drop();
}
const IFileList* CTarReader::getFileList() const
{
return this;
}
u32 CTarReader::populateFileList()
{
STarHeader fHead;
Files.clear();
u32 pos = 0;
while ( s32(pos + sizeof(STarHeader)) < File->getSize())
{
File->seek(pos);
File->read(&fHead, sizeof(fHead));
if (fHead.Link == ETLI_REGULAR_FILE || ETLI_REGULAR_FILE_OLD)
{
io::path fullPath = "";
fullPath.reserve(255);
if (!strncmp(fHead.Magic, "ustar", 5))
{
c8* np = fHead.FileNamePrefix;
while(*np && (np - fHead.FileNamePrefix) < 155)
fullPath.append(*np);
np++;
}
c8* np = fHead.FileName;
while(*np && (np - fHead.FileName) < 100)
{
fullPath.append(*np);
np++;
}
core::stringc sSize = "";
sSize.reserve(12);
np = fHead.Size;
while(*np && (np - fHead.Size) < 12)
{
sSize.append(*np);
np++;
}
u32 size = strtoul(sSize.c_str(), NULL, 8);
#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
if (errno == ERANGE)
os::Printer::log("File too large", fullPath, ELL_WARNING);
#endif
u32 offset = pos + 512;
pos = offset + (size / 512) * 512 + ((size % 512) ? 512 : 0);
addItem(fullPath, offset, size, false );
}
else
{
pos += 512;
}
}
return Files.size();
}
IReadFile* CTarReader::createAndOpenFile(const io::path& filename)
{
const s32 index = findFile(filename, false);
if (index != -1)
return createAndOpenFile(index);
return 0;
}
IReadFile* CTarReader::createAndOpenFile(u32 index)
{
if (index >= Files.size() )
return 0;
const SFileListEntry &entry = Files[index];
return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
}
}
}
#endif