1
// Copyright (C) 2009-2011 Gaz Davidson
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
5
#include "CTarReader.h"
7
#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_
10
#include "CLimitReadFile.h"
13
#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
23
CArchiveLoaderTAR::CArchiveLoaderTAR(io::IFileSystem* fs)
27
setDebugName("CArchiveLoaderTAR");
32
//! returns true if the file maybe is able to be loaded by this class
33
bool CArchiveLoaderTAR::isALoadableFileFormat(const io::path& filename) const
35
return core::hasFileExtension(filename, "tar");
38
//! Check to see if the loader can create archives of this type.
39
bool CArchiveLoaderTAR::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const
41
return fileType == EFAT_TAR;
44
//! Creates an archive from the filename
45
/** \param file File handle to check.
46
\return Pointer to newly created archive, or 0 upon error. */
47
IFileArchive* CArchiveLoaderTAR::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const
49
IFileArchive *archive = 0;
50
io::IReadFile* file = FileSystem->createAndOpenFile(filename);
54
archive = createArchive(file, ignoreCase, ignorePaths);
62
//! creates/loads an archive from the file.
63
//! \return Pointer to the created archive. Returns 0 if loading failed.
64
IFileArchive* CArchiveLoaderTAR::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const
66
IFileArchive *archive = 0;
70
archive = new CTarReader(file, ignoreCase, ignorePaths);
75
//! Check if the file might be loaded by this class
76
/** Check might look into the file.
77
\param file File handle to check.
78
\return True if file seems to be loadable. */
79
bool CArchiveLoaderTAR::isALoadableFileFormat(io::IReadFile* file) const
81
// TAR files consist of blocks of 512 bytes
82
// if it isn't a multiple of 512 then it's not a TAR file.
83
if (file->getSize() % 512)
88
// read header of first file
90
file->read(&fHead, sizeof(STarHeader));
93
sscanf(fHead.Checksum, "%o", &checksum);
97
// some old TAR writers assume that chars are signed, others assume unsigned
98
// USTAR archives have a longer header, old TAR archives end after linkname
103
// remember to blank the checksum field!
104
memset(fHead.Checksum, ' ', 8);
107
for (u8* p = (u8*)(&fHead); p < (u8*)(&fHead.Magic[0]); ++p)
113
if (!strncmp(fHead.Magic, "ustar", 5))
115
for (u8* p = (u8*)(&fHead.Magic[0]); p < (u8*)(&fHead) + sizeof(fHead); ++p)
121
return checksum1 == checksum || checksum2 == (s32)checksum;
127
CTarReader::CTarReader(IReadFile* file, bool ignoreCase, bool ignorePaths)
128
: CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file)
131
setDebugName("CTarReader");
138
// fill the file list
146
CTarReader::~CTarReader()
152
const IFileList* CTarReader::getFileList() const
158
u32 CTarReader::populateFileList()
164
while ( s32(pos + sizeof(STarHeader)) < File->getSize())
166
// seek to next file header
170
File->read(&fHead, sizeof(fHead));
172
// only add standard files for now
173
if (fHead.Link == ETLI_REGULAR_FILE || ETLI_REGULAR_FILE_OLD)
175
io::path fullPath = "";
176
fullPath.reserve(255);
178
// USTAR archives have a filename prefix
179
// may not be null terminated, copy carefully!
180
if (!strncmp(fHead.Magic, "ustar", 5))
182
c8* np = fHead.FileNamePrefix;
183
while(*np && (np - fHead.FileNamePrefix) < 155)
184
fullPath.append(*np);
188
// append the file name
189
c8* np = fHead.FileName;
190
while(*np && (np - fHead.FileName) < 100)
192
fullPath.append(*np);
197
core::stringc sSize = "";
200
while(*np && (np - fHead.Size) < 12)
206
u32 size = strtoul(sSize.c_str(), NULL, 8);
207
#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
209
os::Printer::log("File too large", fullPath, ELL_WARNING);
212
// save start position
213
u32 offset = pos + 512;
215
// move to next file header block
216
pos = offset + (size / 512) * 512 + ((size % 512) ? 512 : 0);
219
addItem(fullPath, offset, size, false );
223
// todo: ETLI_DIRECTORY, ETLI_LINK_TO_ARCHIVED_FILE
225
// move to next block
234
//! opens a file by file name
235
IReadFile* CTarReader::createAndOpenFile(const io::path& filename)
237
const s32 index = findFile(filename, false);
240
return createAndOpenFile(index);
245
//! opens a file by index
246
IReadFile* CTarReader::createAndOpenFile(u32 index)
248
if (index >= Files.size() )
251
const SFileListEntry &entry = Files[index];
252
return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
255
} // end namespace io
256
} // end namespace irr
258
#endif // __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_