/********************************************************************************
* *
* P e r s i s t e n t S t o r a g e S t r e a m C l a s s e s *
* *
*********************************************************************************
* Copyright (C) 1997,2024 by Jeroen van der Zijp. All Rights Reserved. *
*********************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This library 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see *
********************************************************************************/
#ifndef FXSTREAM_H
#define FXSTREAM_H
namespace FX {
class FXObject;
/// Stream data flow direction
enum FXStreamDirection {
FXStreamDead=0, /// Unopened stream
FXStreamSave=1, /// Saving stuff to stream
FXStreamLoad=2 /// Loading stuff from stream
};
/// Stream status codes
enum FXStreamStatus {
FXStreamOK=0, /// OK
FXStreamEnd=1, /// Try read past end of stream
FXStreamFull=2, /// Filled up stream buffer or disk full
FXStreamNoWrite=3, /// Unable to open for write
FXStreamNoRead=4, /// Unable to open for read
FXStreamFormat=5, /// Stream format error
FXStreamUnknown=6, /// Trying to read unknown class
FXStreamAlloc=7, /// Alloc failed
FXStreamFailure=8 /// General failure
};
/// Stream seeking
enum FXWhence {
FXFromStart=0, /// Seek from start position
FXFromCurrent=1, /// Seek from current position
FXFromEnd=2 /// Seek from end position
};
/**
* A stream is a way to serialize data and objects into a byte stream.
* Each item of data that is saved or loaded from the stream may be byte-swapped,
* thus allowing little-endian machines to read data produced on big endian ones
* and vice-versa.
* Data is serialized exactly as-is. There are no tags or other markers
* inserted into the stream; thus, the stream may be used to save or load arbitrary
* binary data.
* Objects derived from FXObjects may be serialized also; whenever a reference to an
* object is serialized, a table is consulted to determine if the same object has
* been encountered previously; if not, the object is added to the table and then
* its contents are serialized. If the object has been encountered before, only a
* reference to the object is serialized.
* When loading back a serialized object, new instances are constructed using
* the default constructor, and subsequently the object's contents are loaded.
* A special container object may be passed in which is placed in the table
* as if it had been encountered before; this will cause only references to this
* object to be saved. The container object is typically the top-level document
* object which manages all objects contained by it. Additional objects may be
* added using addObject(); these will not be actually saved or loaded.
*/
class FXAPI FXStream {
protected:
FXHash hash; // Hash table
const FXObject *parent; // Parent object
FXuchar *begptr; // Begin of buffer
FXuchar *endptr; // End of buffer
FXuchar *wrptr; // Write pointer
FXuchar *rdptr; // Read pointer
FXlong pos; // Position
FXStreamDirection dir; // Direction of current transfer
FXStreamStatus code; // Status code
FXuint seq; // Sequence number
FXbool owns; // Stream owns buffer
FXbool swap; // Swap bytes on readin
protected:
/**
* Write at least count bytes from the buffer;
* returns number of bytes available to be written.
*/
virtual FXuval writeBuffer(FXuval count);
/**
* Read at least count bytes into the buffer;
* returns number of bytes available to be read.
*/
virtual FXuval readBuffer(FXuval count);
private:
FXStream(const FXStream&);
FXStream &operator=(const FXStream&);
public:
/**
* Construct stream with given container object. The container object
* is an object that will itself not be saved to or loaded from the stream,
* but which may be referenced by other objects. These references will be
* properly saved and restored.
*/
FXStream(const FXObject* cont=nullptr);
/**
* Open stream for reading (FXStreamLoad) or for writing (FXStreamSave).
* An initial buffer size may be given, which must be at least 16 bytes.
* If data is not NULL, it is expected to point to an external data buffer
* of length size; otherwise stream will use an internally managed buffer.
*/
FXbool open(FXStreamDirection save_or_load,FXuchar* data=nullptr,FXuval size=8192UL,FXbool owned=false);
/// Flush buffer
virtual FXbool flush();
/// Close; return true if OK
virtual FXbool close();
/// Get available buffer space
FXuval getSpace() const;
/// Set available buffer space
void setSpace(FXuval sp);
/// Set buffer ownership flag
void setOwned(FXbool owned){ owns=owned; }
/// Get buffer ownership flag
FXbool isOwned() const { return owns; }
/// Get status code
FXStreamStatus status() const { return code; }
/// Return true if at end of file or error
FXbool eof() const { return code!=FXStreamOK; }
/// Set status code
void setError(FXStreamStatus err);
/// Obtain stream direction
FXStreamDirection direction() const { return dir; }
/// Get parent object
const FXObject* container() const { return parent; }
/// Get position
FXlong position() const { return pos; }
/// Move to position relative to head, tail, or current location
virtual FXbool position(FXlong offset,FXWhence whence=FXFromStart);
/**
* Change swap bytes flag.
*/
void swapBytes(FXbool s){ swap=s; }
/**
* Get state of the swap bytes flag.
*/
FXbool swapBytes() const { return swap; }
/**
* Set stream to big endian mode if true. Byte swapping will
* be enabled if the machine native byte order is not equal to
* the desired byte order.
*/
void setBigEndian(FXbool big);
/**
* Return true if big endian mode.
*/
FXbool isBigEndian() const;
/// Save single items to stream
FXStream& operator<<(const FXuchar& v);
FXStream& operator<<(const FXchar& v){ return *this << reinterpret_cast(v); }
FXStream& operator<<(const FXbool& v);
FXStream& operator<<(const FXushort& v);
FXStream& operator<<(const FXshort& v){ return *this << reinterpret_cast(v); }
FXStream& operator<<(const FXuint& v);
FXStream& operator<<(const FXint& v){ return *this << reinterpret_cast(v); }
FXStream& operator<<(const FXfloat& v){ return *this << reinterpret_cast(v); }
FXStream& operator<<(const FXdouble& v);
FXStream& operator<<(const FXlong& v){ return *this << reinterpret_cast(v); }
FXStream& operator<<(const FXulong& v){ return *this << reinterpret_cast(v); }
/// Save arrays of items to stream
FXStream& save(const FXuchar* p,FXuval n);
FXStream& save(const FXchar* p,FXuval n){ return save(reinterpret_cast(p),n); }
FXStream& save(const FXbool* p,FXuval n);
FXStream& save(const FXushort* p,FXuval n);
FXStream& save(const FXshort* p,FXuval n){ return save(reinterpret_cast(p),n); }
FXStream& save(const FXuint* p,FXuval n);
FXStream& save(const FXint* p,FXuval n){ return save(reinterpret_cast(p),n); }
FXStream& save(const FXfloat* p,FXuval n){ return save(reinterpret_cast(p),n); }
FXStream& save(const FXdouble* p,FXuval n);
FXStream& save(const FXlong* p,FXuval n){ return save(reinterpret_cast(p),n); }
FXStream& save(const FXulong* p,FXuval n){ return save(reinterpret_cast(p),n); }
/// Load single items from stream
FXStream& operator>>(FXuchar& v);
FXStream& operator>>(FXchar& v){ return *this >> reinterpret_cast(v); }
FXStream& operator>>(FXbool& v);
FXStream& operator>>(FXushort& v);
FXStream& operator>>(FXshort& v){ return *this >> reinterpret_cast(v); }
FXStream& operator>>(FXuint& v);
FXStream& operator>>(FXint& v){ return *this >> reinterpret_cast(v); }
FXStream& operator>>(FXfloat& v){ return *this >> reinterpret_cast(v); }
FXStream& operator>>(FXdouble& v);
FXStream& operator>>(FXlong& v){ return *this >> reinterpret_cast(v); }
FXStream& operator>>(FXulong& v){ return *this >> reinterpret_cast(v); }
/// Load arrays of items from stream
FXStream& load(FXuchar* p,FXuval n);
FXStream& load(FXchar* p,FXuval n){ return load(reinterpret_cast(p),n); }
FXStream& load(FXbool* p,FXuval n);
FXStream& load(FXushort* p,FXuval n);
FXStream& load(FXshort* p,FXuval n){ return load(reinterpret_cast(p),n); }
FXStream& load(FXuint* p,FXuval n);
FXStream& load(FXint* p,FXuval n){ return load(reinterpret_cast(p),n); }
FXStream& load(FXfloat* p,FXuval n){ return load(reinterpret_cast(p),n); }
FXStream& load(FXdouble* p,FXuval n);
FXStream& load(FXlong* p,FXuval n){ return load(reinterpret_cast(p),n); }
FXStream& load(FXulong* p,FXuval n){ return load(reinterpret_cast(p),n); }
/// Save object
FXStream& saveObject(const FXObject* v);
/// Load object
FXStream& loadObject(FXObject*& v);
/// Add object without saving or loading
FXStream& addObject(const FXObject* v);
/// Load object
template
FXStream& operator>>(TYPE*& obj){ return loadObject(reinterpret_cast(obj)); }
/// Save object
template
FXStream& operator<<(const TYPE* obj){ return saveObject(static_cast(obj)); }
/// Destructor
virtual ~FXStream();
};
}
#endif