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 #include <cassert>
21 #include <stdarg.h>
22 #include <iomanip>
23 
24 #include "CBytestream.h"
25 #include "EndianSwap.h"
26 #include "StringUtils.h"
27 #include "MathLib.h"
28 #include "CScriptableVars.h"
29 #include "Debug.h"
30 #include "Iterator.h"
31 #include "Utils.h"
32 
33 
Test()34 void CBytestream::Test()
35 {
36 	notes << endl;
37 	notes << "Running a Bytestream debug test:" << endl;
38 	notes << "Tested function / Original / Write / Read / Warning" << endl;
39 
40 	// Byte
41 	uchar b = 125;
42 	notes << "Byte: (" << b << ") ";
43 	writeByte(b);
44 	ResetPosToBegin();
45 	notes << "(" << Data << ") ";
46 	uchar b2 = readByte();
47 	notes << "(" << b2 << ") ";
48 	if (b2 != b)
49 		notes << "NOT SAME!";
50 	notes <<endl;
51 	Clear();
52 
53 	// Bool
54 	bool boo = true;
55 	notes << "Bool: (" << boo << ") ";
56 	writeByte(boo);
57 	ResetPosToBegin();
58 	notes << "(" << Data << ") ";
59 	bool boo2 = readBool();
60 	notes << "(" << boo2 << ") ";
61 	if (boo2 != boo)
62 		notes << "NOT SAME!";
63 	notes << endl;
64 	Clear();
65 
66 	{
67 		// Integer
68 		int i = 125;
69 		notes << "Int: (" << i << ") ";
70 		writeInt(i, 4);
71 		ResetPosToBegin();
72 		notes << "(" << Data << ") ";
73 		int i2 = readInt(4);
74 		notes << "(" << itoa(i2) << ") ";
75 		if (i2 != i)
76 			notes << "NOT SAME!";
77 		notes <<endl;
78 		Clear();
79 	}
80 
81 	{
82 		// Integer
83 		Sint16 i = -126;
84 		notes << "Int: (" << i << ") ";
85 		writeInt(i, 2);
86 		ResetPosToBegin();
87 		notes << "(" << Data << ") ";
88 		Sint16 i2 = readInt(2);
89 		notes << "(" << itoa(i2) << ") ";
90 		if (i2 != i)
91 			notes << "NOT SAME!";
92 		notes <<endl;
93 		Clear();
94 	}
95 
96 	// Short
97 	short s = 125;
98 	notes << "Short: (" << s << ") ";
99 	writeInt16(s);
100 	ResetPosToBegin();
101 	notes << "(" << Data << ") ";
102 	short s2 = readInt16();
103 	notes << "(" << s2 << ") ";
104 	if (s2 != s)
105 		notes << "NOT SAME!";
106 	notes <<endl;
107 	Clear();
108 
109 	// Float
110 	float f = 125.125f;
111 	notes << "Float: (" << f << ") ";
112 	writeFloat(f);
113 	ResetPosToBegin();
114 	notes << "(" << Data << ") ";
115 	float f2 = readFloat();
116 	notes << "(" << f2 << ") ";
117 	if (f2 != f)
118 		notes << "NOT SAME!";
119 	notes <<endl;
120 	Clear();
121 
122 	// String
123 	std::string str = "Test";
124 	notes << "String: (" << str << ") ";
125 	writeString(str);
126 	ResetPosToBegin();
127 	notes << "(" << Data << ") ";
128 	std::string str2 = readString();
129 	notes << "(" << str2 << ") ";
130 	if (str2 != str)
131 		notes << "NOT SAME!";
132 	notes <<endl;
133 	Clear();
134 
135 	// 2Int12
136 	short x = 125;
137 	short y = 521;
138 	notes << "2Int12: (" << x << "/" << y << ") ";
139 	write2Int12(x, y);
140 	ResetPosToBegin();
141 	notes << "(" << Data << ") ";
142 	short x2, y2;
143 	read2Int12(x2, y2);
144 	notes << "(" << x2 << "/" << y2 << ") ";
145 	if (x2 != x || y2 != y)
146 		notes << "NOT SAME!";
147 	notes <<endl;
148 	Clear();
149 
150 	// 2Int4
151 	short u = 10;
152 	short v = 12;
153 	notes << "2Int4: (" << u << "/" << v << ") ";
154 	write2Int4(u, v);
155 	ResetPosToBegin();
156 	notes << "(" << Data << ") ";
157 	short u2, v2;
158 	read2Int4(u2, v2);
159 	notes << "(" << u2 << "/" << v2 << ") ";
160 	if (u2 != u || v2 != v)
161 		notes << "NOT SAME!";
162 	notes <<endl;
163 	Clear();
164 
165 	// Bits
166 	writeBit(1);
167 	writeBit(1);
168 	writeBit(0);
169 	writeBit(1);
170 	writeBit(1);
171 	writeBit(1);
172 	writeBit(0);
173 	writeBit(0);
174 	writeBit(1);
175 	notes << "Data.size() = " << Data.size() << " ";
176 	notes << "Bits: (" << (unsigned)Data[0] << ", " << (unsigned)Data[1] << ") ";
177 	ResetPosToBegin();
178 	if(
179 		readBit() != 1 ||
180 		readBit() != 1 ||
181 		readBit() != 0 ||
182 		readBit() != 1 ||
183 		readBit() != 1 ||
184 		readBit() != 1 ||
185 		readBit() != 0 ||
186 		readBit() != 0 ||
187 		readBit() != 1
188 		)
189 		notes << "NOT SAME!";
190 	notes <<endl;
191 	Clear();
192 
193 	std::string str1( "Lala\0_1\0!2345", 12 );
194 	notes << "Data: " << str1.size() << " ";
195 	writeData(str1);
196 	//ResetPosToBegin();
197 	readByte();
198 	if( readData(1) != "a" )
199 		notes << "NOT SAME!";
200 	str2 = readData();
201 	if( str2.size() <= 4 || str2[5] != 0 )
202 		notes << "\"" << str2 << "\" size " << str2.size() << " NOT SAME!";
203 	notes <<endl;
204 	Clear();
205 
206 	// Bit iterator
207 	char bitData[10];
208 	bitData[0] = 0;
209 	bitData[1] = 0;
210 	CBytestreamBitIterator bitIter(bitData);
211 	bitIter.setBit(); ++bitIter;
212 	bitIter.setBit(); ++bitIter;
213 	++bitIter;
214 	bitIter.setBit(); ++bitIter;
215 	bitIter.setBit(); ++bitIter;
216 	bitIter.setBit(); ++bitIter;
217 	++bitIter;
218 	++bitIter;
219 	bitIter.setBit(); ++bitIter;
220 	bitIter.resetPos();
221 	notes << "Bits iterator: (" << (unsigned)bitData[0] << ", " << (unsigned)bitData[1] << ") ";
222 	if(
223 		bitIter.readBit() != 1 ||
224 		bitIter.readBit() != 1 ||
225 		bitIter.readBit() != 0 ||
226 		bitIter.readBit() != 1 ||
227 		bitIter.readBit() != 1 ||
228 		bitIter.readBit() != 1 ||
229 		bitIter.readBit() != 0 ||
230 		bitIter.readBit() != 0 ||
231 		bitIter.readBit() != 1
232 		)
233 		notes << "NOT SAME!";
234 	notes <<endl;
235 
236 }
237 
Clear()238 void CBytestream::Clear() {
239 	Data = "";
240 	pos = 0;
241 	bitPos = 0;
242 }
243 
244 
245 ///////////////////
246 // Append another bytestream onto this one
Append(CBytestream * bs)247 void CBytestream::Append(CBytestream *bs) {
248 	Data += bs->Data;
249 }
250 
251 
252 ///////////////////
253 // Dump the data out
Dump(const PrintOutFct & printer,const std::set<size_t> & marks,size_t start,size_t count)254 void CBytestream::Dump(const PrintOutFct& printer, const std::set<size_t>& marks, size_t start, size_t count) {
255 	Iterator<char>::Ref it = GetConstIterator(Data);
256 	if(start > 0) it->nextn(start);
257 	HexDump(it, printer, marks, count);
258 }
259 
Dump()260 void CBytestream::Dump() {
261 	Dump(PrintOnLogger(notes), Set(pos));
262 }
263 
264 
265 // Writes
266 
267 
268 ///////////////////
269 // Writes a single byte
writeByte(uchar byte)270 bool CBytestream::writeByte(uchar byte)
271 {
272 	Data += byte;
273 	return true;
274 }
275 
276 
277 ///////////////////
278 // Writes a boolean value to the stream
writeBool(bool value)279 bool CBytestream::writeBool(bool value)
280 {
281 	return writeByte((uchar)value);
282 }
283 
284 
285 ///////////////////
286 // Writes an integer to the stream
writeInt(int value,uchar numbytes)287 bool CBytestream::writeInt(int value, uchar numbytes)
288 {
289 	// Numbytes cannot be more then 4
290 	assert(numbytes > 0 && numbytes < 5);
291 
292 	// HINT: we send always in little endian
293 	Uint32 val = (Uint32)value;
294 	EndianSwap(val);
295 
296 	for(short n = 0; n < numbytes; n++)
297 		writeByte( ((uchar *)&val)[n] );
298 
299 	return true;
300 }
301 
writeUInt64(Uint64 val)302 bool CBytestream::writeUInt64(Uint64 val) {
303 	EndianSwap(val);
304 
305 	for(short n = 0; n < 8; n++)
306 		writeByte( ((uchar *)&val)[n] );
307 
308 	return true;
309 }
310 
311 ///////////////////
312 // Write a short to the stream
writeInt16(Sint16 value)313 bool CBytestream::writeInt16(Sint16 value)
314 {
315 	// HINT: this time, the value is stored in big endian
316 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
317 	ByteSwap5(value);
318 #endif
319 
320 	writeByte( ((uchar *)&value)[0]);
321 	writeByte( ((uchar *)&value)[1]);
322 
323 	return true;
324 }
325 
326 
327 ///////////////////
328 // Writes a float to the stream
writeFloat(float value)329 bool CBytestream::writeFloat(float value)
330 {
331 	union {
332 		uchar bin[4];
333 		float val;
334 	} tmp;
335 	tmp.val = value;
336 
337 	// HINT: original LX uses little endian floats over network
338 	EndianSwap(tmp.bin);
339 
340 	for(short i = 0; i < 4; i++)
341 		writeByte(tmp.bin[i]);
342 
343 	return true;
344 }
345 
346 
writeString(const std::string & value)347 bool CBytestream::writeString(const std::string& value) {
348 	Data += value.c_str(); // convert it to a C-string because we don't want null-bytes in it
349 	Data += (char)'\0';
350 
351 	return true;
352 }
353 
354 // cast 2 int12 to 3 bytes
write2Int12(short x,short y)355 bool CBytestream::write2Int12(short x, short y) {
356 	writeByte((ushort)x & 0xff);
357 	writeByte((((ushort)x & 0xf00) >> 8) + (((ushort)y & 0xf) << 4));
358 	writeByte(((ushort)y & 0xff0) >> 4);
359 	return true;
360 }
361 
362 // cast 2 int4 to 1 byte
write2Int4(short x,short y)363 bool CBytestream::write2Int4(short x, short y) {
364 	return writeByte(((ushort)x & 0xf) + (((ushort)y & 0xf) << 4));
365 }
366 
367 
writeBit(bool bit)368 bool CBytestream::writeBit(bool bit)
369 {
370 	if( bitPos == 0 )
371 		writeByte( 0 );
372 	uchar byte = Data[ Data.size() - 1 ];
373 	byte = byte | ( ( bit ? 1 : 0 ) << bitPos );
374 	Data[ Data.size() - 1 ] = byte;
375 	bitPos ++; bitPos %= 8;
376 	return true;
377 }
378 
writeData(const std::string & value)379 bool CBytestream::writeData(const std::string& value)
380 {
381 	Data.append( value );
382 	return true;
383 }
384 
writeVar(const ScriptVar_t & var)385 bool CBytestream::writeVar(const ScriptVar_t& var) {
386 	assert( var.type >= 0 && var.type <= 4 );
387 	if(!writeByte( var.type )) return false;
388 	switch( var.type ) {
389 		case SVT_BOOL: return writeBool(var.b);
390 		case SVT_INT: return writeInt(var.i, 4);
391 		case SVT_FLOAT: return writeFloat(var.f);
392 		case SVT_STRING: return writeString(var.s);
393 		case SVT_COLOR: {
394 			writeByte(var.c.r);
395 			writeByte(var.c.g);
396 			writeByte(var.c.b);
397 			writeByte(var.c.a);
398 			return true;
399 		}
400 		default: assert(false); return false;
401 	}
402 }
403 
404 
405 
406 // Reads
407 
408 
409 
410 
411 ///////////////////
412 // Reads a single byte
readByte()413 uchar CBytestream::readByte() {
414 	if(!isPosAtEnd())
415 		return Data[pos++];
416 	else {
417 #ifndef FUZZY_ERROR_TESTING
418 		errors <<"reading from stream behind end" << endl;
419 #endif
420 		return 0;
421 	}
422 }
423 
424 
425 ///////////////////
426 // Reads a boolean value from the stream
readBool()427 bool CBytestream::readBool()
428 {
429 	return readByte() != 0;
430 }
431 
432 
433 ///////////////////
434 // Reads an interger value from the stream
readInt(uchar numbytes)435 int CBytestream::readInt(uchar numbytes)
436 {
437 	// Numbytes cannot be more than 4
438 	if(numbytes <= 0 || numbytes >= 5)
439 		return 0;
440 
441 	Uint32 ret = 0;
442 	for(short n=0; n<numbytes; n++)
443 		ret += (Uint32)readByte() << (n * 8);
444 
445 	return (unsigned)ret;
446 }
447 
readUInt64()448 Uint64 CBytestream::readUInt64()
449 {
450 
451 	Uint64 ret = 0;
452 	for(short n=0; n<8; n++)
453 		ret += (Uint64)readByte() << (n * 8);
454 
455 	return ret;
456 }
457 
458 
459 
460 
461 ///////////////////
462 // Read a short from the stream
readInt16()463 Sint16 CBytestream::readInt16()
464 {
465 	// HINT: this time, the value is stored in big endian
466 	uchar dat[2];
467 	dat[1] = readByte();
468 	dat[0] = readByte();
469 
470 	Uint16 value;
471 	value = (Uint16)dat[0];
472 	value += (Uint16)dat[1] << 8;
473 
474 	return (Sint16)value;
475 }
476 
477 
478 
479 ///////////////////
480 // Read a float value from the stream
readFloat()481 float CBytestream::readFloat()
482 {
483 	union {
484 		uchar bin[4];
485 		float val;
486 	} tmp;
487 
488 	tmp.val = 0;
489 
490 	for(short i = 0; i < 4; i++)
491 		tmp.bin[i] = readByte();
492 
493 	// HINT: original LX uses little endian floats over network
494 	EndianSwap(tmp.bin);
495 
496 	return tmp.val;
497 }
498 
499 
readString()500 std::string CBytestream::readString() {
501 	std::string result = "";
502 	uchar b;
503 	while((b = readByte()) != 0) result += (char)b;
504 	return result;
505 }
506 
readString(size_t maxlen)507 std::string CBytestream::readString(size_t maxlen) {
508 	std::string result = "";
509 	size_t i = 0;
510 	uchar b = 0;
511 	while(i < maxlen && (b = readByte()) != 0) {
512 		result += b;
513 		++i;
514 	}
515 	if(b != 0)
516 		warnings("WARNING: CBytestream: stop reading string at no real ending\n");
517 	return result;
518 }
519 
520 ////////////////////
521 // cast 3 bytes to 2 int12
read2Int12(short & x,short & y)522 void CBytestream::read2Int12(short& x, short& y) {
523 	ushort dat[3];
524 	dat[0] = readByte();
525 	dat[1] = readByte();
526 	dat[2] = readByte();
527 
528 	x = dat[0] + ((dat[1] & 0xf) << 8);
529 	y = (short)(((dat[1] & 0xf0) >> 4) + (dat[2] << 4));
530 }
531 
532 ///////////////////
533 // cast 1 byte to 2 int4
read2Int4(short & x,short & y)534 void CBytestream::read2Int4(short& x, short& y) {
535 	uchar tmp = readByte();
536 	x = tmp & 0xf;
537 	y = (short)((tmp & 0xf0) >> 4);
538 }
539 
540 
541 ////////////////////
542 // Read one bit from the bytestream
readBit()543 bool CBytestream::readBit()
544 {
545 	if( isPosAtEnd() )
546 	{
547 		errors << "reading from stream behind end" << endl;
548 		return false;
549 	}
550 	bool ret = (Data[pos] & ( 1 << bitPos )) != 0;
551 	bitPos ++;
552 	if( bitPos >= 8 )
553 	{
554 		bitPos = 0;
555 		pos ++;
556 	}
557 	return ret;
558 }
559 
560 /////////////////////
561 // Get data from the bytestream
readData(size_t size)562 std::string CBytestream::readData( size_t size )
563 {
564 	size = MIN( size, GetLength() - pos );
565 	size_t oldpos = pos;
566 	pos += size;
567 	return Data.substr( oldpos, size );
568 }
569 
readVar(ScriptVar_t & var)570 bool CBytestream::readVar(ScriptVar_t& var) {
571 	assert( var.type >= 0 && var.type <= 4 );
572 	var.type = (ScriptVarType_t)readByte();
573 	switch( var.type ) {
574 		case SVT_BOOL: var.b = readBool(); break;
575 		case SVT_INT: var.i = readInt(4); break;
576 		case SVT_FLOAT: var.f = readFloat(); break;
577 		case SVT_STRING: var.s = readString(); break;
578 		case SVT_COLOR: var.c.r = readInt(1); var.c.g = readInt(1); var.c.b = readInt(1); var.c.a = readInt(1); break;
579 		default:
580 			warnings << "read var has invalid type" << endl;
581 			var = ScriptVar_t();
582 	}
583 	return true;
584 }
585 
586 
587 
588 /////////////////////
589 // Read a byte but don't change the position
peekByte() const590 uchar CBytestream::peekByte() const
591 {
592 	if (!isPosAtEnd())
593 		return Data[GetPos()];
594 	errors << "CBytestream::peekByte(): reading from stream beyond end" << endl;
595 	return 0;
596 }
597 
598 ///////////////////////
599 // Peek data from the bytestream
peekData(size_t len) const600 std::string CBytestream::peekData(size_t len) const
601 {
602 	if (GetPos() + len <= GetLength())
603 		return Data.substr(GetPos(), len);
604 	return "";
605 }
606 
607 
608 // Skips a string, including the terminating character
609 // Returns true if we're at the end of the stream after the skip
SkipString()610 bool CBytestream::SkipString() {
611 	readString();
612 	return isPosAtEnd();
613 }
614 
Skip(size_t num)615 bool CBytestream::Skip(size_t num) {
616 	pos += num;
617 	return isPosAtEnd();
618 }
619 
620 ////////////////
621 // Read from network
622 // WARNING: overrides any previous data
Read(NetworkSocket * sock)623 size_t CBytestream::Read(NetworkSocket* sock) {
624 	Clear();
625 	char buf[4096];
626 	size_t len = 0;
627 	int res; // MUST be signed, else an overflow can occur (ReadScoket can return -1!)
628 	while(true) {
629 		res = sock->Read(buf, sizeof(buf));
630 		if(res <= 0) break;
631 		Data.append(buf, res);
632 		len += res;
633 		if((size_t)res < sizeof(buf)) break;
634 	}
635 
636 #ifdef DEBUG
637 	// DEBUG: randomly drop packets to test network stability
638 /*	if (GetRandomInt(128) > 110)  {
639 		warnings("DEBUG: packet ignored\n");
640 		Dump();
641 		warnings("\n");
642 		Clear();
643 		return 0;
644 	}*/
645 #endif
646 
647 	return len;
648 }
649 
Send(NetworkSocket * sock)650 bool CBytestream::Send(NetworkSocket* sock) {
651 	return (size_t)sock->Write(Data) == Data.size();
652 }
653 
654