/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef hsStream_Defined
#define hsStream_Defined
#include // Included for GCC 3.2.2+
#include "HeadSpin.h"
#include "hsMemory.h"
#include "plString.h"
// Define this for use of Streams with Logging (commonly used w/ a packet sniffer)
// These streams log their reads to an event list
//#define STREAM_LOGGER
#ifndef STREAM_LOGGER
#define hsReadOnlyLoggingStream hsReadOnlyStream
#define LogRead(byteCount, buffer, desc) Read(byteCount, buffer)
#define LogReadSafeString() ReadSafeString()
#define LogReadSafeString_TEMP() ReadSafeString_TEMP()
#define LogReadSafeStringLong() ReadSafeStringLong();
#define LogSkip(deltaByteCount, desc) Skip(deltaByteCount)
#define LogReadLE(value, desc) ReadLE(value)
#define LogReadLEArray(count, values, desc) ReadLE(count, values)
#define LogSubStreamStart(desc) LogVoidFunc()
#define LogSubStreamPushDesc(desc) LogVoidFunc()
#define LogSubStreamEnd() LogVoidFunc()
#define LogStringString(s) LogVoidFunc()
#endif
class hsStream {
public:
enum {
kEolnCode = '\n',
kComment = '#'
};
protected:
uint32_t fBytesRead;
uint32_t fPosition;
bool IsTokenSeparator(char c);
public:
hsStream() : fBytesRead(0), fPosition(0) {}
virtual ~hsStream();
virtual bool Open(const char *, const char * = "rb")=0;
virtual bool Open(const wchar_t *, const wchar_t * = L"rb")=0;
virtual bool Close()=0;
virtual bool AtEnd();
virtual uint32_t Read(uint32_t byteCount, void * buffer) = 0;
virtual uint32_t Write(uint32_t byteCount, const void* buffer) = 0;
virtual void Skip(uint32_t deltaByteCount) = 0;
virtual void Rewind() = 0;
virtual void FastFwd();
virtual uint32_t GetPosition() const;
virtual void SetPosition(uint32_t position);
virtual void Truncate();
virtual void Flush() {}
#ifdef STREAM_LOGGER
// Logging Reads & Skips
virtual uint32_t LogRead(uint32_t byteCount, void * buffer, const char* desc) { return Read(byteCount,buffer); }
virtual char* LogReadSafeString() { return ReadSafeString(); }
virtual char* LogReadSafeStringLong() { return ReadSafeStringLong(); }
virtual void LogSkip(uint32_t deltaByteCount, const char* desc) { Skip(deltaByteCount); }
// Stream Notes for Logging
virtual void LogStringString(const char* s) { }
virtual void LogSubStreamStart(const char* desc) { }
virtual void LogSubStreamEnd() { }
virtual void LogSubStreamPushDesc(const char* desc) { }
#endif
void LogVoidFunc() { }
// Optimization for small Reads
virtual uint8_t ReadByte();
virtual bool Read4Bytes(void *buffer); // Reads 4 bytes, return true if success
virtual bool Read8Bytes(void *buffer); // Reads 8 bytes, return true if success
virtual bool Read12Bytes(void *buffer); // Reads 12 bytes, return true if success
virtual uint32_t GetEOF();
uint32_t GetSizeLeft();
virtual void CopyToMem(void* mem);
virtual bool IsCompressed() { return false; }
uint32_t WriteString(const char cstring[]);
uint32_t WriteString(const plString & string) { return WriteString(string.c_str()); }
uint32_t WriteFmt(const char * fmt, ...);
uint32_t WriteFmtV(const char * fmt, va_list av);
uint32_t WriteSafeStringLong(const plString &string); // uses 4 bytes for length
uint32_t WriteSafeWStringLong(const plString &string);
char * ReadSafeStringLong();
wchar_t * ReadSafeWStringLong();
uint32_t WriteSafeString(const plString &string); // uses 2 bytes for length
uint32_t WriteSafeWString(const plString &string);
char * ReadSafeString();
wchar_t * ReadSafeWString();
plString ReadSafeString_TEMP();
plString ReadSafeWString_TEMP();
bool GetToken(char *s, uint32_t maxLen=uint32_t(-1), const char beginComment=kComment, const char endComment=kEolnCode);
bool ReadLn(char* s, uint32_t maxLen=uint32_t(-1), const char beginComment=kComment, const char endComment=kEolnCode);
// Reads a 4-byte BOOLean
bool ReadBOOL();
// Reads a 1-byte boolean
bool ReadBool();
void ReadBool(int count, bool values[]);
uint16_t ReadLE16();
void ReadLE16(int count, uint16_t values[]);
uint32_t ReadLE32();
void ReadLE32(int count, uint32_t values[]);
uint32_t ReadBE32();
void WriteBOOL(bool value);
void WriteBool(bool value);
void WriteBool(int count, const bool values[]);
void WriteByte(uint8_t value);
void WriteLE16(uint16_t value);
void WriteLE16(int count, const uint16_t values[]);
void WriteLE32(uint32_t value);
void WriteLE32(int count, const uint32_t values[]);
void WriteBE32(uint32_t value);
/* Overloaded Begin (8 & 16 & 32 int)*/
/* yes, swapping an 8 bit value does nothing, just useful*/
void ReadLE(bool* value) { *value = this->ReadByte() ? true : false; }
void ReadLE(uint8_t* value) { *value = this->ReadByte(); }
void ReadLE(int count, uint8_t values[]) { this->Read(count, values); }
void ReadLE(uint16_t* value) { *value = this->ReadLE16(); }
void ReadLE(int count, uint16_t values[]) { this->ReadLE16(count, values); }
void ReadLE(uint32_t* value) { *value = this->ReadLE32(); }
void ReadLE(int count, uint32_t values[]) { this->ReadLE32(count, values); }
#ifdef STREAM_LOGGER
// Begin LogReadLEs
virtual void LogReadLE(bool* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLE(uint8_t* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, uint8_t values[], const char* desc) { this->ReadLE(count, values); }
virtual void LogReadLE(uint16_t* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, uint16_t values[], const char* desc) { this->ReadLE(count, values); }
virtual void LogReadLE(uint32_t* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, uint32_t values[], const char* desc) { this->ReadLE(count, values); }
// End LogReadLEs
#endif
void WriteLE(bool value) { this->Write(1,&value); }
void WriteLE(uint8_t value) { this->Write(1,&value); }
void WriteLE(int count, const uint8_t values[]) { this->Write(count, values); }
void WriteLE(uint16_t value) { this->WriteLE16(value); }
void WriteLE(int count, const uint16_t values[]) { this->WriteLE16(count, values); }
void WriteLE(uint32_t value) { this->WriteLE32(value); }
void WriteLE(int count, const uint32_t values[]) { this->WriteLE32(count, values); }
void ReadLE(int8_t* value) { *value = this->ReadByte(); }
void ReadLE(int count, int8_t values[]) { this->Read(count, values); }
void ReadLE(char* value) { *value = (char)this->ReadByte(); }
void ReadLE(int count, char values[]) { this->Read(count, values); }
void ReadLE(int16_t* value) { *value = (int16_t)this->ReadLE16(); }
void ReadLE(int count, int16_t values[]) { this->ReadLE16(count, (uint16_t*)values); }
void ReadLE(int32_t* value) { *value = (int32_t)this->ReadLE32(); }
void ReadLE(int count, int32_t values[]) { this->ReadLE32(count, (uint32_t*)values); }
#ifdef STREAM_LOGGER
// Begin LogReadLEs
virtual void LogReadLE(int8_t* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, int8_t values[], const char* desc) { this->ReadLE(count, values); }
virtual void LogReadLE(char* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, char values[], const char* desc) { this->ReadLE(count, values); }
virtual void LogReadLE(int16_t* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, int16_t values[], const char* desc) { this->ReadLE(count, (uint16_t*)values); }
virtual void LogReadLE(int32_t* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, int32_t values[], const char* desc) { this->ReadLE(count, (uint32_t*)values); }
virtual void LogReadLE(int* value, const char* desc) { this->ReadLE(value); }
virtual void LogReadLEArray(int count, int values[], const char* desc) { this->ReadLE(count, (uint32_t*)values); }
// End LogReadLEs
#endif
void WriteLE(int8_t value) { this->Write(1,&value); }
void WriteLE(int count, const int8_t values[]) { this->Write(count, values); }
void WriteLE(char value) { this->Write(1,(uint8_t*)&value); }
void WriteLE(int count, const char values[]) { this->Write(count, (uint8_t*)values); }
void WriteLE(int16_t value) { this->WriteLE16((uint16_t)value); }
void WriteLE(int count, const int16_t values[]) { this->WriteLE16(count, (uint16_t*)values); }
void WriteLE(int32_t value) { this->WriteLE32((uint32_t)value); }
void WriteLE(int count, const int32_t values[]) { this->WriteLE32(count, (uint32_t*)values); }
/* Overloaded End */
float ReadLEFloat();
void ReadLEFloat(int count, float values[]);
double ReadLEDouble();
void ReadLEDouble(int count, double values[]);
float ReadBEFloat();
void WriteLEFloat(float value);
void WriteLEFloat(int count, const float values[]);
void WriteLEDouble(double value);
void WriteLEDouble(int count, const double values[]);
void WriteBEFloat(float value);
/* Overloaded Begin (Float)*/
void ReadLE(float* value) { *value = ReadLEFloat(); }
void ReadLE(int count, float values[]) { ReadLEFloat(count, values); }
void ReadLE(double* value) { *value = ReadLEDouble(); }
void ReadLE(int count, double values[]) { ReadLEDouble(count, values); }
#ifdef STREAM_LOGGER
// Begin LogReadLEs
virtual void LogReadLE(float* value, const char* desc) { ReadLE(value); }
virtual void LogReadLEArray(int count, float values[], const char* desc) { ReadLE(count, values); }
virtual void LogReadLE(double* value, const char* desc) { ReadLE(value); }
virtual void LogReadLEArray(int count, double values[], const char* desc) { ReadLE(count, values); }
// End LogReadLEs
#endif
void WriteLE(float value) { WriteLEFloat(value); }
void WriteLE(int count, const float values[]) { WriteLEFloat(count, values); }
void WriteLE(double value) { WriteLEDouble(value); }
void WriteLE(int count, const double values[]) { WriteLEDouble(count, values); }
/* Overloaded End */
float ReadLEScalar() { return (float)this->ReadLEFloat(); }
void ReadLEScalar(int count, float values[])
{
this->ReadLEFloat(count, (float*)values);
}
float ReadBEScalar() { return (float)this->ReadBEFloat(); }
void WriteLEScalar(float value) { this->WriteLEFloat(value); }
void WriteLEScalar(int count, const float values[])
{
this->WriteLEFloat(count, (float*)values);
}
void WriteBEScalar(float value) { this->WriteBEFloat(value); }
void WriteLEAtom(uint32_t tag, uint32_t size);
uint32_t ReadLEAtom(uint32_t* size);
/* Overloaded Begin (Atom)*/
void WriteLE(uint32_t* tag, uint32_t size) { WriteLEAtom(*tag, size); }
void ReadLE(uint32_t* tag, uint32_t *size) { *tag = ReadLEAtom(size); }
/* Overloaded End */
};
class hsStreamable {
public:
virtual void Read(hsStream* stream) = 0;
virtual void Write(hsStream* stream) = 0;
virtual uint32_t GetStreamSize() = 0;
};
class hsFileStream: public hsStream
{
uint32_t fRef;
public:
hsFileStream();
virtual ~hsFileStream();
virtual bool Open(const char *name, const char *mode = "rb");
virtual bool Open(const wchar_t *name, const wchar_t *mode = L"rb");
virtual bool Close();
virtual bool AtEnd();
virtual uint32_t Read(uint32_t byteCount, void* buffer);
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void Truncate();
virtual uint32_t GetFileRef();
virtual void SetFileRef(uint32_t refNum);
};
class hsUNIXStream: public hsStream
{
FILE* fRef;
char* fBuff;
public:
hsUNIXStream(): fRef(0), fBuff(nil) {}
~hsUNIXStream();
virtual bool Open(const char* name, const char* mode = "rb");
virtual bool Open(const wchar_t *name, const wchar_t *mode = L"rb");
virtual bool Close();
virtual bool AtEnd();
virtual uint32_t Read(uint32_t byteCount, void* buffer);
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual void SetPosition(uint32_t position);
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void FastFwd();
virtual void Truncate();
virtual void Flush();
FILE* GetFILE() { return fRef; }
void SetFILE(FILE* file) { fRef = file; }
virtual uint32_t GetEOF();
};
// Small substream class: give it a base stream, an offset and a length, and it'll
// treat all ops as if you had a chunk from the base stream as a separate, vanilla
// stream of the given length.
class plReadOnlySubStream: public hsStream
{
hsStream *fBase;
uint32_t fOffset, fLength;
void IFixPosition( void );
public:
plReadOnlySubStream(): fBase( nil ), fOffset( 0 ), fLength( 0 ) {}
~plReadOnlySubStream();
virtual bool Open(const char *, const char *) { hsAssert(0, "plReadOnlySubStream::Open NotImplemented"); return false; }
virtual bool Open(const wchar_t *, const wchar_t *) { hsAssert(0, "plReadOnlySubStream::Open NotImplemented"); return false; }
void Open( hsStream *base, uint32_t offset, uint32_t length );
virtual bool Close() { fBase = nil; fOffset = 0; fLength = 0; return true; }
virtual bool AtEnd();
virtual uint32_t Read(uint32_t byteCount, void* buffer);
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void FastFwd();
virtual void Truncate();
virtual uint32_t GetEOF();
};
class hsRAMStream : public hsStream {
hsAppender fAppender;
hsAppenderIterator fIter;
public:
hsRAMStream();
hsRAMStream(uint32_t chunkSize);
virtual ~hsRAMStream();
virtual bool Open(const char *, const char *) { hsAssert(0, "hsRAMStream::Open NotImplemented"); return false; }
virtual bool Open(const wchar_t *, const wchar_t *) { hsAssert(0, "hsRAMStream::Open NotImplemented"); return false; }
virtual bool Close() { hsAssert(0, "hsRAMStream::Close NotImplemented"); return false; }
virtual bool AtEnd();
virtual uint32_t Read(uint32_t byteCount, void * buffer);
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void Truncate();
virtual uint32_t GetEOF();
virtual void CopyToMem(void* mem);
void Reset(); // clears the buffers
};
class hsNullStream : public hsStream {
public:
virtual bool Open(const char *, const char *) { return true; }
virtual bool Open(const wchar_t *, const wchar_t *) { return true; }
virtual bool Close() { return true; }
virtual uint32_t Read(uint32_t byteCount, void * buffer); // throw's exception
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void Truncate();
uint32_t GetBytesWritten() const { return fBytesRead; }
void Reset( ) { fBytesRead = 0; }
};
// read only mem stream
class hsReadOnlyStream : public hsStream {
protected:
char* fStart;
char* fData;
char* fStop;
public:
hsReadOnlyStream(int size, const void* data) { Init(size, data); }
hsReadOnlyStream() {}
virtual void Init(int size, const void* data) { fStart=((char*)data); fData=((char*)data); fStop=((char*)data + size); }
virtual bool Open(const char *, const char *) { hsAssert(0, "hsReadOnlyStream::Open NotImplemented"); return false; }
virtual bool Open(const wchar_t *, const wchar_t *) { hsAssert(0, "hsReadOnlyStream::Open NotImplemented"); return false; }
virtual bool Close() { hsAssert(0, "hsReadOnlyStream::Close NotImplemented"); return false; }
virtual bool AtEnd();
virtual uint32_t Read(uint32_t byteCount, void * buffer);
virtual uint32_t Write(uint32_t byteCount, const void* buffer); // throws exception
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void Truncate();
virtual uint32_t GetBytesRead() const { return fBytesRead; }
virtual uint32_t GetEOF() { return (uint32_t)(fStop-fStart); }
virtual void CopyToMem(void* mem);
};
// write only mem stream
class hsWriteOnlyStream : public hsReadOnlyStream {
public:
hsWriteOnlyStream(int size, const void* data) : hsReadOnlyStream(size, data) {}
hsWriteOnlyStream() {}
virtual bool Open(const char *, const char *) { hsAssert(0, "hsWriteOnlyStream::Open NotImplemented"); return false; }
virtual bool Open(const wchar_t *, const wchar_t *) { hsAssert(0, "hsWriteOnlyStream::Open NotImplemented"); return false; }
virtual bool Close() { hsAssert(0, "hsWriteOnlyStream::Close NotImplemented"); return false; }
virtual uint32_t Read(uint32_t byteCount, void * buffer); // throws exception
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual uint32_t GetBytesRead() const { return 0; }
virtual uint32_t GetBytesWritten() const { return fBytesRead; }
};
// circular queue stream
class hsQueueStream : public hsStream {
private:
char* fQueue;
uint32_t fReadCursor;
uint32_t fWriteCursor;
uint32_t fSize;
public:
hsQueueStream(int32_t size);
~hsQueueStream();
virtual bool Open(const char *, const char *) { hsAssert(0, "hsQueueStream::Open NotImplemented"); return false; }
virtual bool Open(const wchar_t *, const wchar_t *) { hsAssert(0, "hsQueueStream::Open NotImplemented"); return false; }
virtual bool Close() { hsAssert(0, "hsQueueStream::Close NotImplemented"); return false; }
virtual uint32_t Read(uint32_t byteCount, void * buffer);
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void FastFwd();
virtual bool AtEnd();
uint32_t GetSize() { return fSize; }
const char* GetQueue() { return fQueue; }
uint32_t GetReadCursor() { return fReadCursor; }
uint32_t GetWriteCursor() { return fWriteCursor; }
};
class hsBufferedStream : public hsStream
{
FILE* fRef;
uint32_t fFileSize;
enum { kBufferSize = 2*1024 };
char fBuffer[kBufferSize];
// If the buffer is empty, this is zero. Otherwise it is the size of the
// buffer (if we read a full block), or something less than that if we read
// a partial block at the end of the file.
uint32_t fBufferLen;
bool fWriteBufferUsed;
#ifdef HS_DEBUGGING
// For doing statistics on how efficient we are
int fBufferHits, fBufferMisses;
uint32_t fBufferReadIn, fBufferReadOut, fReadDirect, fLastReadPos;
char* fFilename;
const char* fCloseReason;
#endif
public:
hsBufferedStream();
virtual ~hsBufferedStream();
virtual bool Open(const char* name, const char* mode = "rb");
virtual bool Open(const wchar_t* name, const wchar_t* mode = L"rb");
virtual bool Close();
virtual bool AtEnd();
virtual uint32_t Read(uint32_t byteCount, void* buffer);
virtual uint32_t Write(uint32_t byteCount, const void* buffer);
virtual void Skip(uint32_t deltaByteCount);
virtual void Rewind();
virtual void Truncate();
virtual uint32_t GetEOF();
FILE* GetFileRef();
void SetFileRef(FILE* file);
// Something optional for when we're doing stats. Will log the reason why
// the file was closed. Really just for plRegistryPageNode.
void SetCloseReason(const char* reason)
{
#ifdef HS_DEBUGGING
fCloseReason = reason;
#endif
}
};
#endif