/******************************************************************************** * * * 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