Commit b410b526 authored by hybrid's avatar hybrid

PAK archive reader patch and test, submitted by Carmen Wick.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2741 dfc29bdd-3216-0410-991c-e03cc46cb475
parent d3eff725
......@@ -15,20 +15,34 @@ 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
#ifdef _DEBUG
setDebugName("CArchiveLoaderPAK");
#endif
#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" );
return core::hasFileExtension(filename, "pak");
}
//! Check to see if the loader can create archives of this type.
......@@ -47,7 +61,7 @@ IFileArchive* CArchiveLoaderPAK::createArchive(const io::path& filename, bool ig
if (file)
{
archive = createArchive ( file, ignoreCase, ignorePaths );
archive = createArchive(file, ignoreCase, ignorePaths);
file->drop ();
}
......@@ -76,9 +90,9 @@ bool CArchiveLoaderPAK::isALoadableFileFormat(io::IReadFile* file) const
{
SPAKFileHeader header;
file->read( &header.tag, 4 );
file->read(&header, sizeof(header));
return header.tag[0] == 'P' && header.tag[1] == 'A';
return isHeaderValid(header);
}
......@@ -88,17 +102,14 @@ bool CArchiveLoaderPAK::isALoadableFileFormat(io::IReadFile* file) const
CPakReader::CPakReader(IReadFile* file, bool ignoreCase, bool ignorePaths)
: CFileList(file ? file->getFileName() : "", ignoreCase, ignorePaths), File(file)
{
#ifdef _DEBUG
#ifdef _DEBUG
setDebugName("CPakReader");
#endif
#endif
if (File)
{
File->grab();
// scan local headers
scanLocalHeader();
sort();
}
}
......@@ -116,48 +127,43 @@ const IFileList* CPakReader::getFileList() const
return this;
}
//! scans for a local header, returns false if there is no more local file header.
bool CPakReader::scanLocalHeader()
{
SPAKFileHeader header;
// Read and validate the header
File->read(&header, sizeof(header));
if (!isHeaderValid(header))
return false;
c8 tmp[1024];
io::path PakFileName;
memset(&header, 0, sizeof(SPAKFileHeader));
File->read(&header, sizeof(SPAKFileHeader));
if (header.tag[0] != 'P' && header.tag[1] != 'A')
return false; // local file headers end here.
// 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 count = header.length / ((sizeof(u32) * 2) + 56);
const int numberOfFiles = header.length / sizeof(SPAKFileEntry);
for(int i = 0; i < count; i++)
Offsets.reallocate(numberOfFiles);
// Loop through each entry in the table of contents
for(int i = 0; i < numberOfFiles; i++)
{
// read filename
PakFileName.reserve(56+2);
File->read(tmp, 56);
tmp[56] = 0x0;
PakFileName = tmp;
#ifdef _DEBUG
os::Printer::log(PakFileName.c_str());
#endif
// read an entry
SPAKFileEntry entry;
File->read(&entry, sizeof(entry));
s32 offset;
s32 size;
File->read(&offset, sizeof(u32));
File->read(&size, sizeof(u32));
#ifdef _DEBUG
os::Printer::log(entry.name);
#endif
#ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(offset);
os::Byteswap::byteswap(size);
entry.offset = os::Byteswap::byteswap(entry.offset);
entry.length = os::Byteswap::byteswap(entry.length);
#endif
addItem(PakFileName, size, false, Offsets.size());
Offsets.push_back(offset);
addItem(io::path(entry.name), entry.length, false, Offsets.size());
Offsets.push_back(entry.offset);
}
return true;
}
......
......@@ -20,13 +20,24 @@ namespace irr
{
namespace io
{
//! File header containing location and size of the table of contents
struct SPAKFileHeader
{
// Don't change the order of these fields! They must match the order stored on disk.
c8 tag[4];
u32 offset;
u32 length;
};
//! An entry in the PAK file's table of contents.
struct SPAKFileEntry
{
// Don't change the order of these fields! They must match the order stored on disk.
c8 name[56];
u32 offset;
u32 length;
};
//! Archiveloader capable of loading PAK Archives
class CArchiveLoaderPAK : public IArchiveLoader
{
......@@ -79,7 +90,6 @@ namespace io
// file archive methods
//! return the id of the file Archive
virtual const io::path& getArchiveName() const
{
return File->getFileName();
......@@ -99,16 +109,11 @@ namespace io
private:
//! scans for a local header, returns false if there is no more local file header.
//! scans for a local header, returns false if the header is invalid
bool scanLocalHeader();
//! splits filename from zip file into useful filenames and paths
//void extractFilename(SPakFileEntry* entry);
IReadFile* File;
SPAKFileHeader header;
//! Contains offsets of the files from the start of the archive file
core::array<u32> Offsets;
};
......
......@@ -58,6 +58,7 @@ int main(int argumentCount, char * arguments[])
TEST(disambiguateTextures); // Normally you should run this first, since it validates the working directory.
TEST(filesystem);
TEST(zipReader);
TEST(pakReader);
TEST(exports);
TEST(sceneCollisionManager);
TEST(testVector3d);
......
#include "testUtils.h"
using namespace irr;
using namespace core;
using namespace io;
bool pakReader(void)
{
IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d<u32>(1, 1));
assert(device);
if(!device)
return false;
io::IFileSystem * fs = device->getFileSystem ();
if ( !fs )
return false;
if ( !fs->addFileArchive(io::path("media/sample_pakfile.pak"), /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) )
return false;
// log what we got
io::IFileArchive* archive = fs->getFileArchive(fs->getFileArchiveCount()-1);
const io::IFileList* fileList = archive->getFileList();
for ( u32 f=0; f < fileList->getFileCount(); ++f)
{
logTestString("File name: %s\n", fileList->getFileName(f).c_str());
logTestString("Full path: %s\n", fileList->getFullFileName(f).c_str());
}
bool result = true;
io::path filename("test/test.txt");
result &= fs->existFile(filename);
if (!result )
{
logTestString("existFile failed");
}
IReadFile* readFile = fs->createAndOpenFile(filename);
if ( !readFile )
{
result = false;
logTestString("createAndOpenFilefailed");
}
char tmp[123] = {'\0'};
readFile->read(tmp, sizeof(tmp));
if (strncmp(tmp, "Hello world!", sizeof(tmp)))
{
result = false;
logTestString("Read bad data from pak file.\n");
}
return result;
}
Test suite pass at GMT Tue Oct 20 16:15:59 2009
Test suite pass at GMT Fri Oct 23 12:34:07 2009
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment