1 /////////////////////////////////////////
2 //
3 // OpenLieroX
4 //
5 // Auxiliary Software class library
6 //
7 // based on the work of JasonB
8 // enhanced by Dark Charlie and Albert Zeyer
9 //
10 // code under LGPL
11 //
12 /////////////////////////////////////////
13
14
15 // Byte stream class
16 // Created 13/10/01
17 // Jason Boettcher
18
19
20 #ifndef __CBYTESTREAM_H__
21 #define __CBYTESTREAM_H__
22
23 #include <SDL.h> // for SInt16
24 #include <string>
25 #include <set>
26 #include "types.h"
27 #include "Networking.h"
28 #include "SmartPointer.h"
29
30 struct ScriptVar_t;
31 struct Logger;
32 struct PrintOutFct;
33
34 class CBytestream {
35 public:
CBytestream()36 CBytestream() : pos(0), bitPos(0), Data("") {}
CBytestream(const std::string & rawData)37 CBytestream(const std::string& rawData) : pos(0), bitPos(0), Data(rawData) {}
38
CBytestream(const CBytestream & bs)39 CBytestream(const CBytestream& bs) {
40 operator=(bs);
41 }
42
43 CBytestream& operator=(const CBytestream& bs) {
44 pos = bs.pos;
45 Data = bs.Data;
46 bitPos = bs.bitPos;
47 return *this;
48 }
49
50 private:
51 // Attributes
52 size_t pos;
53 size_t bitPos;
54 std::string Data;
55
56 public:
57 // Methods
58
59 // Debug
60 void Test();
61
62
63 // Generic data
ResetBitPos()64 void ResetBitPos() { bitPos = 0; }
ResetPosToBegin()65 void ResetPosToBegin() { pos = 0; bitPos = 0; }
GetLength()66 size_t GetLength() const { return Data.size(); }
GetPos()67 size_t GetPos() const { return pos; }
GetRestLen()68 size_t GetRestLen() const { return isPosAtEnd() ? 0 : (Data.size() - pos); }
isPosAtEnd()69 bool isPosAtEnd() const { return GetPos() >= GetLength(); }
revertByte()70 void revertByte() { assert(pos > 0); pos--; }
flushOld()71 void flushOld() { Data.erase(0, pos); pos = 0; }
getRawData(size_t start,size_t end)72 std::string getRawData(size_t start, size_t end) { assert(start <= end); return Data.substr(start, end - start + 1); }
73
74 void Clear();
75 void Append(CBytestream *bs);
76
77 // Note: marks positions are relative to start; start=0 means from the very beginning of the stream (not from pos)
78 void Dump(const PrintOutFct& printer, const std::set<size_t>& marks = std::set<size_t>(), size_t start = 0, size_t count = (size_t)-1);
79 void Dump();
80
81 // Writes
82 bool writeByte(uchar byte);
83 bool writeBool(bool value);
84 bool writeInt(int value, uchar numbytes);
85 bool writeInt16(Sint16 value);
86 bool writeUInt64(Uint64 value);
87 bool writeFloat(float value);
88 bool writeString(const std::string& value);
89 bool write2Int12(short x, short y);
90 bool write2Int4(short x, short y);
91 bool writeBit(bool bit);
92 bool writeData(const std::string& value); // Do not append '\0' at the end, writes just the raw data
93 bool writeVar(const ScriptVar_t& var);
94
95 // Reads
96 uchar readByte();
97 bool readBool();
98 int readInt(uchar numbytes); // readInt(2) will return 0:65535 range, not -32768:32767, so save it into Sint16
99 Sint16 readInt16();
100 Uint64 readUInt64();
101 float readFloat();
102 std::string readString();
103 std::string readString(size_t maxlen);
104 void read2Int12(short& x, short& y);
105 void read2Int4(short& x, short& y);
106 bool readBit();
107 std::string readData( size_t size = (size_t)(-1) );
108 bool readVar(ScriptVar_t& var);
109
110 // Peeks
111 uchar peekByte() const;
112 std::string peekData(size_t len) const;
113
114 // Skips
115 // Folowing functions return true if we're at the end of stream after the skip
116 bool Skip(size_t num);
SkipInt()117 bool SkipInt() { return Skip(4); }
SkipFloat()118 bool SkipFloat() { return Skip(4); }
SkipShort()119 bool SkipShort() { return Skip(2); }
120 bool SkipString();
SkipAll()121 void SkipAll() { pos = Data.size(); }
SkipRestBits()122 bool SkipRestBits() { if(isPosAtEnd()) return true; ResetBitPos(); pos++; return isPosAtEnd(); }
123
124 // Networking stuff
125 bool Send(NetworkSocket* sock);
126 size_t Read(NetworkSocket* sock);
Send(const SmartPointer<NetworkSocket> & sock)127 bool Send(const SmartPointer<NetworkSocket>& sock) { return Send(sock.get()); }
Read(const SmartPointer<NetworkSocket> & sock)128 size_t Read(const SmartPointer<NetworkSocket>& sock) { return Read(sock.get()); }
129 };
130
131 // Inline class to operate with bits for dirt updates, hopefully optimized by compiler
132 // No bound-checking is made, be sure your data is large enough
133 class CBytestreamBitIterator
134 {
135 char * data;
136 size_t pos;
137 Uint8 bitMask;
138
139 public:
140
CBytestreamBitIterator(char * Data)141 CBytestreamBitIterator(char * Data): data(Data)
142 {
143 resetPos();
144 }
145
getPos()146 size_t getPos() const
147 {
148 return pos;
149 }
resetPos()150 void resetPos()
151 {
152 pos = 0;
153 bitMask = 1;
154 }
155
156 CBytestreamBitIterator& operator ++()
157 {
158 if( bitMask >= 128 )
159 {
160 bitMask = 1;
161 pos ++;
162 }
163 else
164 bitMask *= 2;
165 return *this;
166 }
167
getBit()168 bool getBit() const
169 {
170 return ( data[pos] & bitMask ) != 0;
171 }
setBit()172 void setBit()
173 {
174 data[pos] |= bitMask;
175 }
clearBit()176 void clearBit()
177 {
178 data[pos] &= ~ bitMask;
179 }
xorBit()180 void xorBit()
181 {
182 data[pos] ^= bitMask;
183 }
184
185 // Slower functions
readBit()186 bool readBit()
187 {
188 bool ret = getBit();
189 ++(*this);
190 return ret;
191 }
writeBit(bool bit)192 void writeBit( bool bit )
193 {
194 if( bit )
195 setBit();
196 else
197 clearBit();
198 ++(*this);
199 }
200
getSizeInBytes(size_t bits)201 static size_t getSizeInBytes( size_t bits )
202 {
203 size_t bytes = bits / 8;
204 if( bits % 8 )
205 bytes++;
206 return bytes;
207 }
208 };
209
210
211 template< bool (*fct1) (CBytestream*), bool (*fct2) (CBytestream*) >
SkipMult(CBytestream * bs)212 bool SkipMult(CBytestream* bs) { return (*fct1)(bs) && (*fct2)(bs); }
213
214 template< size_t NUM >
Skip(CBytestream * bs)215 bool Skip(CBytestream* bs) { return bs->Skip(NUM); }
216
SkipString(CBytestream * bs)217 inline bool SkipString(CBytestream* bs) { return bs->SkipString(); }
218
219 #endif // __CBITSTREAM_H__
220