0ad/source/ps/FileUnpacker.cpp
janwas a859562ea7 improvements and fixes:
- properly differentiate between buffer/offset alignment and length
alignment (relevant since block size has been increased to 256k)
- use VfsPath for most game paths instead of CStr
- clean up timer interface and implementation
- self-tests no longer crash
- file_cache.cpp: fix for the case where allocation fails (prevent
deleter from seeing a null pointer)
- allocators: move all shared_ptr-related stuff to its own component;
add DummySharedPtr
- codec: disable checksums (important for performance at work)
- File: made into an interface class to avoid export problems. not
entirely sure about this..
- vfs_path.h, path.h, os_path.h: proper fix for using
fs::change_extension and similar utility functions with derivatives of
basic_path
- lib_api: automatically link against import lib if building lib/ as a
DLL
- path_util: remove unused functions (this component is deprecated)
- compiler.h: add INLINE
- Xeromyces.cpp: pass PIVFS so that GetXMBPath works in self-test
(should do this mostly everywhere rather than have one singleton g_VFS)

This was SVN commit r5537.
2008-01-07 20:03:19 +00:00

108 lines
3.2 KiB
C++

/**
* =========================================================================
* File : FileUnpacker.cpp
* Project : 0 A.D.
* Description : Buffer and 'stream' for reading binary files
* =========================================================================
*/
#include "precompiled.h"
#include "ps/FileUnpacker.h"
#include "ps/CStr.h"
#include "ps/Filesystem.h"
#include "lib/byte_order.h"
////////////////////////////////////////////////////////////////////////////////////////
// CFileUnpacker constructor
CFileUnpacker::CFileUnpacker()
{
m_Size = 0;
m_UnpackPos = 0;
m_Version = 0;
}
CFileUnpacker::~CFileUnpacker()
{
}
////////////////////////////////////////////////////////////////////////////////////////
// Read: open and read in given file, check magic bits against those given; throw
// variety of exceptions for missing files etc
void CFileUnpacker::Read(const VfsPath& filename, const char magicstr[4])
{
// avoid vfs_load complaining about missing data files (which happens
// too often). better to check here than squelch internal VFS error
// reporting. we disable this in release mode to avoid a speed hit.
// UPDATE: We don't disable this in release mode, because vfs_load now
// complains about missing files when running in release
//#ifndef NDEBUG
if(!FileExists(filename))
throw PSERROR_File_OpenFailed();
//#endif
// load the whole thing into memory
if(g_VFS->LoadFile(filename, m_Buf, m_Size) < 0)
throw PSERROR_File_OpenFailed();
// make sure we read enough for the header
if(m_Size < 12)
{
m_Buf.reset();
m_Size = 0;
throw PSERROR_File_ReadFailed();
}
// extract data from header
u8* header = (u8*)m_Buf.get();
char* magic = (char*)(header+0);
// FIXME m_Version and datasize: Byte order? -- Simon
m_Version = read_le32(header+4);
u32 datasize = read_le32(header+8);
// check we've got the right kind of file
// .. and that we read exactly headersize+datasize
if(strncmp(magic, magicstr, 4) != 0 || m_Size != 12+datasize)
{
m_Buf.reset();
m_Size = 0;
throw PSERROR_File_InvalidType();
}
m_UnpackPos = 12;
}
////////////////////////////////////////////////////////////////////////////////////////
// UnpackRaw: unpack given number of bytes from the input stream into the given array
// - throws CFileEOFError if the end of the data stream is reached before the given
// number of bytes have been read
void CFileUnpacker::UnpackRaw(void* rawdata, size_t rawdatalen)
{
// fail if reading past end of stream
if (m_UnpackPos+rawdatalen > m_Size)
throw PSERROR_File_UnexpectedEOF();
void* src = m_Buf.get() + m_UnpackPos;
cpu_memcpy(rawdata, src, rawdatalen);
m_UnpackPos += rawdatalen;
}
////////////////////////////////////////////////////////////////////////////////////////
// UnpackString: unpack a string from the raw data stream
// - throws CFileEOFError if eof is reached before the string length has been
// satisfied
void CFileUnpacker::UnpackString(CStr& result)
{
// get string length
u32 length_le;
UnpackRaw(&length_le, sizeof(length_le));
const size_t length = to_le32(length_le);
// fail if reading past end of stream
if (m_UnpackPos + length > m_Size)
throw PSERROR_File_UnexpectedEOF();
result = CStr((char*)m_Buf.get()+m_UnpackPos, length);
m_UnpackPos += length;
}