irrlicht/source/Irrlicht/CPakReader.cpp

197 lines
4.3 KiB
C++

// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// Code contributed by skreamz
#include "CPakReader.h"
#ifdef __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_
#include "os.h"
#include "coreutil.h"
namespace irr
{
namespace io
{
namespace
{
inline bool isHeaderValid(const SPAKFileHeader& header)
{
const c8* tag = header.tag;
return tag[0] == 'P' &&
tag[1] == 'A' &&
tag[2] == 'C' &&
tag[3] == 'K';
}
} // end namespace
//! Constructor
CArchiveLoaderPAK::CArchiveLoaderPAK( io::IFileSystem* fs)
: FileSystem(fs)
{
#ifdef _DEBUG
setDebugName("CArchiveLoaderPAK");
#endif
}
//! returns true if the file maybe is able to be loaded by this class
bool CArchiveLoaderPAK::isALoadableFileFormat(const io::path& filename) const
{
return core::hasFileExtension(filename, "pak");
}
//! Check to see if the loader can create archives of this type.
bool CArchiveLoaderPAK::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const
{
return fileType == EFAT_PAK;
}
//! Creates an archive from the filename
/** \param file File handle to check.
\return Pointer to newly created archive, or 0 upon error. */
IFileArchive* CArchiveLoaderPAK::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;
}
//! creates/loads an archive from the file.
//! \return Pointer to the created archive. Returns 0 if loading failed.
IFileArchive* CArchiveLoaderPAK::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const
{
IFileArchive *archive = 0;
if ( file )
{
file->seek ( 0 );
archive = new CPakReader(file, ignoreCase, ignorePaths);
}
return archive;
}
//! Check if the file might be loaded by this class
/** Check might look into the file.
\param file File handle to check.
\return True if file seems to be loadable. */
bool CArchiveLoaderPAK::isALoadableFileFormat(io::IReadFile* file) const
{
SPAKFileHeader header;
file->read(&header, sizeof(header));
return isHeaderValid(header);
}
/*!
PAK Reader
*/
CPakReader::CPakReader(IReadFile* file, bool ignoreCase, bool ignorePaths)
: CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file)
{
#ifdef _DEBUG
setDebugName("CPakReader");
#endif
if (File)
{
File->grab();
scanLocalHeader();
sort();
}
}
CPakReader::~CPakReader()
{
if (File)
File->drop();
}
const IFileList* CPakReader::getFileList() const
{
return this;
}
bool CPakReader::scanLocalHeader()
{
SPAKFileHeader header;
// Read and validate the header
File->read(&header, sizeof(header));
if (!isHeaderValid(header))
return false;
// Seek to the table of contents
#ifdef __BIG_ENDIAN__
header.offset = os::Byteswap::byteswap(header.offset);
header.length = os::Byteswap::byteswap(header.length);
#endif
File->seek(header.offset);
const int numberOfFiles = header.length / sizeof(SPAKFileEntry);
// Loop through each entry in the table of contents
for(int i = 0; i < numberOfFiles; i++)
{
// read an entry
SPAKFileEntry entry;
File->read(&entry, sizeof(entry));
#ifdef _DEBUG
os::Printer::log(entry.name);
#endif
#ifdef __BIG_ENDIAN__
entry.offset = os::Byteswap::byteswap(entry.offset);
entry.length = os::Byteswap::byteswap(entry.length);
#endif
addItem(io::path(entry.name), entry.offset, entry.length, false );
}
return true;
}
//! opens a file by file name
IReadFile* CPakReader::createAndOpenFile(const io::path& filename)
{
s32 index = findFile(filename, false);
if (index != -1)
return createAndOpenFile(index);
return 0;
}
//! opens a file by index
IReadFile* CPakReader::createAndOpenFile(u32 index)
{
if (index >= Files.size() )
return 0;
const SFileListEntry &entry = Files[index];
return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
}
} // end namespace io
} // end namespace irr
#endif // __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_