1 /********************************************************************************
2 *                                                                               *
3 *       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       *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2021 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #ifndef FXSTREAM_H
22 #define FXSTREAM_H
23 
24 namespace FX {
25 
26 
27 /// Stream data flow direction
28 enum FXStreamDirection {
29   FXStreamDead=0,               /// Unopened stream
30   FXStreamSave=1,               /// Saving stuff to stream
31   FXStreamLoad=2                /// Loading stuff from stream
32   };
33 
34 
35 /// Stream status codes
36 enum FXStreamStatus {
37   FXStreamOK=0,                 /// OK
38   FXStreamEnd=1,                /// Try read past end of stream
39   FXStreamFull=2,               /// Filled up stream buffer or disk full
40   FXStreamNoWrite=3,            /// Unable to open for write
41   FXStreamNoRead=4,             /// Unable to open for read
42   FXStreamFormat=5,             /// Stream format error
43   FXStreamUnknown=6,            /// Trying to read unknown class
44   FXStreamAlloc=7,              /// Alloc failed
45   FXStreamFailure=8             /// General failure
46   };
47 
48 
49 /// Stream seeking
50 enum FXWhence {
51   FXFromStart=0,                /// Seek from start position
52   FXFromCurrent=1,              /// Seek from current position
53   FXFromEnd=2                   /// Seek from end position
54   };
55 
56 
57 /**
58 * A stream is a way to serialize data and objects into a byte stream.
59 * Each item of data that is saved or loaded from the stream may be byte-swapped,
60 * thus allowing little-endian machines to read data produced on big endian ones
61 * and vice-versa.
62 * Data is serialized exactly as-is.  There are no tags or other markers
63 * inserted into the stream; thus, the stream may be used to save or load arbitrary
64 * binary data.
65 * Objects derived from FXObjects may be serialized also; whenever a reference to an
66 * object is serialized, a table is consulted to determine if the same object has
67 * been encountered previously; if not, the object is added to the table and then
68 * its contents are serialized.  If the object has been encountered before, only a
69 * reference to the object is serialized.
70 * When loading back a serialized object, new instances are constructed using
71 * the default constructor, and subsequently the object's contents are loaded.
72 * A special container object may be passed in which is placed in the table
73 * as if it had been encountered before; this will cause only references to this
74 * object to be saved.  The container object is typically the top-level document
75 * object which manages all objects contained by it.  Additional objects may be
76 * added using addObject(); these will not be actually saved or loaded.
77 */
78 class FXAPI FXStream {
79 protected:
80   FXHash             hash;      // Hash table
81   const FXObject    *parent;    // Parent object
82   FXuchar           *begptr;    // Begin of buffer
83   FXuchar           *endptr;    // End of buffer
84   FXuchar           *wrptr;     // Write pointer
85   FXuchar           *rdptr;     // Read pointer
86   FXlong             pos;       // Position
87   FXStreamDirection  dir;       // Direction of current transfer
88   FXStreamStatus     code;      // Status code
89   FXuint             seq;       // Sequence number
90   FXbool             owns;      // Stream owns buffer
91   FXbool             swap;      // Swap bytes on readin
92 protected:
93 
94   /**
95   * Write at least count bytes from the buffer;
96   * returns number of bytes available to be written.
97   */
98   virtual FXuval writeBuffer(FXuval count);
99 
100   /**
101   * Read at least count bytes into the buffer;
102   * returns number of bytes available to be read.
103   */
104   virtual FXuval readBuffer(FXuval count);
105 
106 private:
107   FXStream(const FXStream&);
108   FXStream &operator=(const FXStream&);
109 public:
110 
111   /**
112   * Construct stream with given container object.  The container object
113   * is an object that will itself not be saved to or loaded from the stream,
114   * but which may be referenced by other objects.  These references will be
115   * properly saved and restored.
116   */
117   FXStream(const FXObject* cont=NULL);
118 
119   /**
120   * Open stream for reading (FXStreamLoad) or for writing (FXStreamSave).
121   * An initial buffer size may be given, which must be at least 16 bytes.
122   * If data is not NULL, it is expected to point to an external data buffer
123   * of length size; otherwise stream will use an internally managed buffer.
124   */
125   FXbool open(FXStreamDirection save_or_load,FXuchar* data=NULL,FXuval size=8192UL,FXbool owned=false);
126 
127   /// Flush buffer
128   virtual FXbool flush();
129 
130   /// Close; return true if OK
131   virtual FXbool close();
132 
133   /// Get available buffer space
134   FXuval getSpace() const;
135 
136   /// Set available buffer space
137   void setSpace(FXuval sp);
138 
139   /// Set buffer ownership flag
setOwned(FXbool owned)140   void setOwned(FXbool owned){ owns=owned; }
141 
142   /// Get buffer ownership flag
isOwned()143   FXbool isOwned() const { return owns; }
144 
145   /// Get status code
status()146   FXStreamStatus status() const { return code; }
147 
148   /// Return true if at end of file or error
eof()149   FXbool eof() const { return code!=FXStreamOK; }
150 
151   /// Set status code
152   void setError(FXStreamStatus err);
153 
154   /// Obtain stream direction
direction()155   FXStreamDirection direction() const { return dir; }
156 
157   /// Get parent object
container()158   const FXObject* container() const { return parent; }
159 
160   /// Get position
position()161   FXlong position() const { return pos; }
162 
163   /// Move to position relative to head, tail, or current location
164   virtual FXbool position(FXlong offset,FXWhence whence=FXFromStart);
165 
166   /**
167   * Change swap bytes flag.
168   */
swapBytes(FXbool s)169   void swapBytes(FXbool s){ swap=s; }
170 
171   /**
172   * Get state of the swap bytes flag.
173   */
swapBytes()174   FXbool swapBytes() const { return swap; }
175 
176   /**
177   * Set stream to big endian mode if true.  Byte swapping will
178   * be enabled if the machine native byte order is not equal to
179   * the desired byte order.
180   */
181   void setBigEndian(FXbool big);
182 
183   /**
184   * Return true if big endian mode.
185   */
186   FXbool isBigEndian() const;
187 
188   /// Save single items to stream
189   FXStream& operator<<(const FXuchar& v);
190   FXStream& operator<<(const FXchar& v){ return *this << reinterpret_cast<const FXuchar&>(v); }
191   FXStream& operator<<(const FXbool& v){ return *this << reinterpret_cast<const FXuchar&>(v); }
192   FXStream& operator<<(const FXushort& v);
193   FXStream& operator<<(const FXshort& v){ return *this << reinterpret_cast<const FXushort&>(v); }
194   FXStream& operator<<(const FXuint& v);
195   FXStream& operator<<(const FXint& v){ return *this << reinterpret_cast<const FXuint&>(v); }
196   FXStream& operator<<(const FXfloat& v){ return *this << reinterpret_cast<const FXuint&>(v); }
197   FXStream& operator<<(const FXdouble& v);
198   FXStream& operator<<(const FXlong& v){ return *this << reinterpret_cast<const FXdouble&>(v); }
199   FXStream& operator<<(const FXulong& v){ return *this << reinterpret_cast<const FXdouble&>(v); }
200 
201   /// Save arrays of items to stream
202   FXStream& save(const FXuchar* p,FXuval n);
save(const FXchar * p,FXuval n)203   FXStream& save(const FXchar* p,FXuval n){ return save(reinterpret_cast<const FXuchar*>(p),n); }
save(const FXbool * p,FXuval n)204   FXStream& save(const FXbool* p,FXuval n){ return save(reinterpret_cast<const FXuchar*>(p),n); }
205   FXStream& save(const FXushort* p,FXuval n);
save(const FXshort * p,FXuval n)206   FXStream& save(const FXshort* p,FXuval n){ return save(reinterpret_cast<const FXushort*>(p),n); }
207   FXStream& save(const FXuint* p,FXuval n);
save(const FXint * p,FXuval n)208   FXStream& save(const FXint* p,FXuval n){ return save(reinterpret_cast<const FXuint*>(p),n); }
save(const FXfloat * p,FXuval n)209   FXStream& save(const FXfloat* p,FXuval n){ return save(reinterpret_cast<const FXuint*>(p),n); }
210   FXStream& save(const FXdouble* p,FXuval n);
save(const FXlong * p,FXuval n)211   FXStream& save(const FXlong* p,FXuval n){ return save(reinterpret_cast<const FXdouble*>(p),n); }
save(const FXulong * p,FXuval n)212   FXStream& save(const FXulong* p,FXuval n){ return save(reinterpret_cast<const FXdouble*>(p),n); }
213 
214   /// Load single items from stream
215   FXStream& operator>>(FXuchar& v);
216   FXStream& operator>>(FXchar& v){ return *this >> reinterpret_cast<FXuchar&>(v); }
217   FXStream& operator>>(FXbool& v){ return *this >> reinterpret_cast<FXuchar&>(v); }
218   FXStream& operator>>(FXushort& v);
219   FXStream& operator>>(FXshort& v){ return *this >> reinterpret_cast<FXushort&>(v); }
220   FXStream& operator>>(FXuint& v);
221   FXStream& operator>>(FXint& v){ return *this >> reinterpret_cast<FXuint&>(v); }
222   FXStream& operator>>(FXfloat& v){ return *this >> reinterpret_cast<FXuint&>(v); }
223   FXStream& operator>>(FXdouble& v);
224   FXStream& operator>>(FXlong& v){ return *this >> reinterpret_cast<FXdouble&>(v); }
225   FXStream& operator>>(FXulong& v){ return *this >> reinterpret_cast<FXdouble&>(v); }
226 
227   /// Load arrays of items from stream
228   FXStream& load(FXuchar* p,FXuval n);
load(FXchar * p,FXuval n)229   FXStream& load(FXchar* p,FXuval n){ return load(reinterpret_cast<FXuchar*>(p),n); }
load(FXbool * p,FXuval n)230   FXStream& load(FXbool* p,FXuval n){ return load(reinterpret_cast<FXuchar*>(p),n); }
231   FXStream& load(FXushort* p,FXuval n);
load(FXshort * p,FXuval n)232   FXStream& load(FXshort* p,FXuval n){ return load(reinterpret_cast<FXushort*>(p),n); }
233   FXStream& load(FXuint* p,FXuval n);
load(FXint * p,FXuval n)234   FXStream& load(FXint* p,FXuval n){ return load(reinterpret_cast<FXuint*>(p),n); }
load(FXfloat * p,FXuval n)235   FXStream& load(FXfloat* p,FXuval n){ return load(reinterpret_cast<FXuint*>(p),n); }
236   FXStream& load(FXdouble* p,FXuval n);
load(FXlong * p,FXuval n)237   FXStream& load(FXlong* p,FXuval n){ return load(reinterpret_cast<FXdouble*>(p),n); }
load(FXulong * p,FXuval n)238   FXStream& load(FXulong* p,FXuval n){ return load(reinterpret_cast<FXdouble*>(p),n); }
239 
240   /// Save object
241   FXStream& saveObject(const FXObject* v);
242 
243   /// Load object
244   FXStream& loadObject(FXObject*& v);
245 
246   /// Add object without saving or loading
247   FXStream& addObject(const FXObject* v);
248 
249   /// Load object
250   template<class TYPE>
251   FXStream& operator>>(TYPE*& obj){ return loadObject(reinterpret_cast<FXObject*&>(obj)); }
252 
253   /// Save object
254   template<class TYPE>
255   FXStream& operator<<(const TYPE* obj){ return saveObject(static_cast<const FXObject*>(obj)); }
256 
257   /// Destructor
258   virtual ~FXStream();
259   };
260 
261 }
262 
263 #endif
264