0ad/source/ps/FileIo.h
janwas c0ed950657 had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).

it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.

after several hours, the code now requires fewer casts and less
guesswork.

other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.

This was SVN commit r5942.
2008-05-11 18:48:32 +00:00

137 lines
3.6 KiB
C++

/**
* =========================================================================
* File : FileIo.h
* Project : 0 A.D.
* Description : endian-safe binary file IO helpers.
* =========================================================================
*/
// the file format has passing similarity to IFF. note however that
// "chunks" aren't identified by FOURCCs; only the file header is
// so marked.
// all > 8-bit integers are stored in little-endian format
// (hence the _le suffix). however, the caller is responsible for
// swapping their raw data before passing it to PackRaw. a convenience
// routine is provided for the common case of storing size_t.
#ifndef INCLUDED_FILEPACKER
#define INCLUDED_FILEPACKER
#include "CStr.h"
#include "lib/file/vfs/vfs_path.h"
#include "ps/Filesystem.h" // WriteBuffer
#include "ps/Errors.h"
ERROR_GROUP(File);
ERROR_TYPE(File, OpenFailed);
ERROR_TYPE(File, WriteFailed);
ERROR_TYPE(File, InvalidType);
ERROR_TYPE(File, InvalidVersion);
ERROR_TYPE(File, ReadFailed);
ERROR_TYPE(File, UnexpectedEOF);
/**
* helper class for writing binary files. this is basically a
* resizable buffer that allows adding raw data and strings;
* upon calling Write(), everything is written out to disk.
**/
class CFilePacker
{
public:
/**
* adds version and signature (i.e. the header) to the buffer.
* this means Write() can write the entire buffer to file in one go,
* which is simpler and more efficient than writing in pieces.
**/
CFilePacker(u32 version, const char magic[4]);
~CFilePacker();
/**
* write out to file all packed data added so far.
* it's safe to call this multiple times, but typically would
* only be done once.
**/
void Write(const VfsPath& filename);
/**
* pack given number of bytes onto the end of the data stream
**/
void PackRaw(const void* rawData, size_t rawDataSize);
/**
* convenience: convert a number (almost always a size type) to
* little-endian u32 and pack that.
**/
void PackSize(size_t value);
/**
* pack a string onto the end of the data stream
* (encoded as a 32-bit length followed by the characters)
**/
void PackString(const CStr& str);
private:
/**
* the output data stream built during pack operations.
* contains the header, so we can write this out in one go.
**/
WriteBuffer m_writeBuffer;
};
/**
* helper class for reading binary files
**/
class CFileUnpacker
{
public:
CFileUnpacker();
~CFileUnpacker();
/**
* open and read in given file, check magic bits against those given;
* throw variety of exceptions if open failed / version incorrect, etc.
**/
void Read(const VfsPath& filename, const char magic[4]);
/**
* @return version number that was stored in the file's header.
**/
u32 GetVersion() const
{
return m_version;
}
/**
* unpack given number of bytes from the input into the given array.
* throws PSERROR_File_UnexpectedEOF if the end of the data stream is
* reached before the given number of bytes have been read.
**/
void UnpackRaw(void* rawData, size_t rawDataSize);
/**
* use UnpackRaw to retrieve 32-bits; returns their value as size_t
* after converting from little endian to native byte order.
**/
size_t UnpackSize();
/**
* unpack a string from the raw data stream.
* @param result is assigned a newly constructed CStr8 holding the
* string read from the input stream.
**/
void UnpackString(CStr8& result);
private:
// the data read from file and used during unpack operations
shared_ptr<u8> m_buf;
size_t m_bufSize;
size_t m_unpackPos; /// current unpack position in stream
u32 m_version; /// version that was stored in the file header
};
#endif