1 /***************************************************************************
2  *   Copyright (C) 2012 by Andrey Afletdinov <fheroes2@gmail.com>          *
3  *                                                                         *
4  *   Part of the Free Heroes2 Engine:                                      *
5  *   http://sourceforge.net/projects/fheroes2                              *
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21  ***************************************************************************/
22 
23 #include <algorithm>
24 #include <cstring>
25 #include <string>
26 
27 #include "logging.h"
28 #include "serialize.h"
29 
30 #define MINCAPACITY 1024
31 
setconstbuf(bool f)32 void StreamBase::setconstbuf( bool f )
33 {
34     if ( f )
35         flags |= 0x00001000;
36     else
37         flags &= ~0x00001000;
38 }
39 
isconstbuf(void) const40 bool StreamBase::isconstbuf( void ) const
41 {
42     return ( flags & 0x00001000 ) != 0;
43 }
44 
bigendian(void) const45 bool StreamBase::bigendian( void ) const
46 {
47     return ( flags & 0x80000000 ) != 0;
48 }
49 
setbigendian(bool f)50 void StreamBase::setbigendian( bool f )
51 {
52     if ( f )
53         flags |= 0x80000000;
54     else
55         flags &= ~0x80000000;
56 }
57 
setfail(bool f)58 void StreamBase::setfail( bool f )
59 {
60     if ( f )
61         flags |= 0x00000001;
62     else
63         flags &= ~0x00000001;
64 }
65 
fail(void) const66 bool StreamBase::fail( void ) const
67 {
68     return flags & 0x00000001;
69 }
70 
get16()71 u16 StreamBase::get16()
72 {
73     return bigendian() ? getBE16() : getLE16();
74 }
75 
get32()76 u32 StreamBase::get32()
77 {
78     return bigendian() ? getBE32() : getLE32();
79 }
80 
operator >>(bool & v)81 StreamBase & StreamBase::operator>>( bool & v )
82 {
83     v = ( get8() != 0 );
84     return *this;
85 }
86 
operator >>(char & v)87 StreamBase & StreamBase::operator>>( char & v )
88 {
89     v = get8();
90     return *this;
91 }
92 
operator >>(u8 & v)93 StreamBase & StreamBase::operator>>( u8 & v )
94 {
95     v = get8();
96     return *this;
97 }
98 
operator >>(u16 & v)99 StreamBase & StreamBase::operator>>( u16 & v )
100 {
101     v = get16();
102     return *this;
103 }
104 
operator >>(int16_t & v)105 StreamBase & StreamBase::operator>>( int16_t & v )
106 {
107     v = get16();
108     return *this;
109 }
110 
operator >>(u32 & v)111 StreamBase & StreamBase::operator>>( u32 & v )
112 {
113     v = get32();
114     return *this;
115 }
116 
operator >>(s32 & v)117 StreamBase & StreamBase::operator>>( s32 & v )
118 {
119     v = get32();
120     return *this;
121 }
122 
operator >>(std::string & v)123 StreamBase & StreamBase::operator>>( std::string & v )
124 {
125     u32 size = get32();
126     v.resize( size );
127 
128     for ( std::string::iterator it = v.begin(); it != v.end(); ++it )
129         *it = get8();
130 
131     return *this;
132 }
133 
operator >>(fheroes2::Point & point_)134 StreamBase & StreamBase::operator>>( fheroes2::Point & point_ )
135 {
136     return *this >> point_.x >> point_.y;
137 }
138 
put16(u16 v)139 void StreamBase::put16( u16 v )
140 {
141     bigendian() ? putBE16( v ) : putLE16( v );
142 }
143 
put32(u32 v)144 void StreamBase::put32( u32 v )
145 {
146     bigendian() ? putBE32( v ) : putLE32( v );
147 }
148 
operator <<(const bool v)149 StreamBase & StreamBase::operator<<( const bool v )
150 {
151     put8( v );
152     return *this;
153 }
154 
operator <<(const char v)155 StreamBase & StreamBase::operator<<( const char v )
156 {
157     put8( v );
158     return *this;
159 }
160 
operator <<(const u8 v)161 StreamBase & StreamBase::operator<<( const u8 v )
162 {
163     put8( v );
164     return *this;
165 }
166 
operator <<(const u16 v)167 StreamBase & StreamBase::operator<<( const u16 v )
168 {
169     put16( v );
170     return *this;
171 }
172 
operator <<(const int16_t v)173 StreamBase & StreamBase::operator<<( const int16_t v )
174 {
175     put16( v );
176     return *this;
177 }
178 
operator <<(const s32 v)179 StreamBase & StreamBase::operator<<( const s32 v )
180 {
181     put32( v );
182     return *this;
183 }
184 
operator <<(const u32 v)185 StreamBase & StreamBase::operator<<( const u32 v )
186 {
187     put32( v );
188     return *this;
189 }
190 
operator <<(const std::string & v)191 StreamBase & StreamBase::operator<<( const std::string & v )
192 {
193     put32( static_cast<uint32_t>( v.size() ) );
194 
195     for ( std::string::const_iterator it = v.begin(); it != v.end(); ++it )
196         put8( *it );
197 
198     return *this;
199 }
200 
operator <<(const fheroes2::Point & point_)201 StreamBase & StreamBase::operator<<( const fheroes2::Point & point_ )
202 {
203     return *this << point_.x << point_.y;
204 }
205 
StreamBuf(size_t sz)206 StreamBuf::StreamBuf( size_t sz )
207     : itbeg( nullptr )
208     , itget( nullptr )
209     , itput( nullptr )
210     , itend( nullptr )
211 {
212     if ( sz )
213         reallocbuf( sz );
214     setbigendian( IS_BIGENDIAN ); /* default: hardware endian */
215 }
216 
~StreamBuf()217 StreamBuf::~StreamBuf()
218 {
219     if ( itbeg && !isconstbuf() )
220         delete[] itbeg;
221 }
222 
StreamBuf(const StreamBuf & st)223 StreamBuf::StreamBuf( const StreamBuf & st )
224     : itbeg( nullptr )
225     , itget( nullptr )
226     , itput( nullptr )
227     , itend( nullptr )
228 {
229     copy( st );
230 }
231 
StreamBuf(const std::vector<u8> & buf)232 StreamBuf::StreamBuf( const std::vector<u8> & buf )
233     : itbeg( nullptr )
234     , itget( nullptr )
235     , itput( nullptr )
236     , itend( nullptr )
237 {
238     itbeg = (u8 *)&buf[0];
239     itend = itbeg + buf.size();
240     itget = itbeg;
241     itput = itend;
242     setconstbuf( true );
243     setbigendian( IS_BIGENDIAN ); /* default: hardware endian */
244 }
245 
StreamBuf(const u8 * buf,size_t bufsz)246 StreamBuf::StreamBuf( const u8 * buf, size_t bufsz )
247     : itbeg( nullptr )
248     , itget( nullptr )
249     , itput( nullptr )
250     , itend( nullptr )
251 {
252     itbeg = const_cast<u8 *>( buf );
253     itend = itbeg + bufsz;
254     itget = itbeg;
255     itput = itend;
256     setconstbuf( true );
257     setbigendian( IS_BIGENDIAN ); /* default: hardware endian */
258 }
259 
operator =(const StreamBuf & st)260 StreamBuf & StreamBuf::operator=( const StreamBuf & st )
261 {
262     if ( &st != this )
263         copy( st );
264     return *this;
265 }
266 
capacity(void) const267 size_t StreamBuf::capacity( void ) const
268 {
269     return itend - itbeg;
270 }
271 
data(void) const272 const u8 * StreamBuf::data( void ) const
273 {
274     return itget;
275 }
276 
size(void) const277 size_t StreamBuf::size( void ) const
278 {
279     return sizeg();
280 }
281 
reset(void)282 void StreamBuf::reset( void )
283 {
284     itput = itbeg;
285     itget = itbeg;
286 }
287 
tellg(void) const288 size_t StreamBuf::tellg( void ) const
289 {
290     return itget - itbeg;
291 }
292 
tellp(void) const293 size_t StreamBuf::tellp( void ) const
294 {
295     return itput - itbeg;
296 }
297 
sizeg(void) const298 size_t StreamBuf::sizeg( void ) const
299 {
300     return itput - itget;
301 }
302 
sizep(void) const303 size_t StreamBuf::sizep( void ) const
304 {
305     return itend - itput;
306 }
307 
reallocbuf(size_t sz)308 void StreamBuf::reallocbuf( size_t sz )
309 {
310     setconstbuf( false );
311 
312     if ( !itbeg ) {
313         if ( sz < MINCAPACITY )
314             sz = MINCAPACITY;
315 
316         itbeg = new u8[sz];
317         itend = itbeg + sz;
318         std::fill( itbeg, itend, 0 );
319 
320         reset();
321     }
322     else if ( sizep() < sz ) {
323         if ( sz < MINCAPACITY )
324             sz = MINCAPACITY;
325 
326         u8 * ptr = new u8[sz];
327 
328         std::fill( ptr, ptr + sz, 0 );
329         std::copy( itbeg, itput, ptr );
330 
331         itput = ptr + tellp();
332         itget = ptr + tellg();
333 
334         delete[] itbeg;
335 
336         itbeg = ptr;
337         itend = itbeg + sz;
338     }
339 }
340 
copy(const StreamBuf & sb)341 void StreamBuf::copy( const StreamBuf & sb )
342 {
343     if ( capacity() < sb.size() )
344         reallocbuf( sb.size() );
345 
346     std::copy( sb.itget, sb.itput, itbeg );
347 
348     itput = itbeg + sb.tellp();
349     itget = itbeg + sb.tellg();
350     flags = 0;
351 
352     setbigendian( sb.bigendian() );
353 }
354 
put8(const uint8_t v)355 void StreamBuf::put8( const uint8_t v )
356 {
357     if ( sizep() == 0 )
358         reallocbuf( capacity() + capacity() / 2 );
359 
360     if ( sizep() > 0 )
361         *itput++ = v;
362 }
363 
get8()364 u8 StreamBuf::get8()
365 {
366     if ( sizeg() )
367         return *itget++;
368     else
369         return 0u;
370 }
371 
getBE16()372 u16 StreamBuf::getBE16()
373 {
374     u16 result = ( get8() << 8 );
375     result |= get8();
376 
377     return result;
378 }
379 
getLE16()380 u16 StreamBuf::getLE16()
381 {
382     u16 result = get8();
383     result |= ( get8() << 8 );
384 
385     return result;
386 }
387 
getBE32()388 u32 StreamBuf::getBE32()
389 {
390     u32 result = ( get8() << 24 );
391     result |= ( get8() << 16 );
392     result |= ( get8() << 8 );
393     result |= get8();
394 
395     return result;
396 }
397 
getLE32()398 u32 StreamBuf::getLE32()
399 {
400     u32 result = get8();
401     result |= ( get8() << 8 );
402     result |= ( get8() << 16 );
403     result |= ( get8() << 24 );
404 
405     return result;
406 }
407 
putBE16(u16 v)408 void StreamBuf::putBE16( u16 v )
409 {
410     put8( v >> 8 );
411     put8( v & 0xFF );
412 }
413 
putLE16(u16 v)414 void StreamBuf::putLE16( u16 v )
415 {
416     put8( v & 0xFF );
417     put8( v >> 8 );
418 }
419 
putBE32(u32 v)420 void StreamBuf::putBE32( u32 v )
421 {
422     put8( v >> 24 );
423     put8( ( v >> 16 ) & 0xFF );
424     put8( ( v >> 8 ) & 0xFF );
425     put8( v & 0xFF );
426 }
427 
putLE32(u32 v)428 void StreamBuf::putLE32( u32 v )
429 {
430     put8( v & 0xFF );
431     put8( ( v >> 8 ) & 0xFF );
432     put8( ( v >> 16 ) & 0xFF );
433     put8( v >> 24 );
434 }
435 
getRaw(size_t sz)436 std::vector<u8> StreamBuf::getRaw( size_t sz )
437 {
438     const size_t remainSize = sizeg();
439     const size_t dataSize = sz > 0 ? sz : remainSize;
440 
441     std::vector<uint8_t> v( dataSize, 0 );
442     const size_t copySize = dataSize < remainSize ? dataSize : remainSize;
443     memcpy( v.data(), itget, copySize );
444 
445     itget += copySize;
446 
447     return v;
448 }
449 
putRaw(const char * ptr,size_t sz)450 void StreamBuf::putRaw( const char * ptr, size_t sz )
451 {
452     for ( size_t it = 0; it < sz; ++it )
453         *this << ptr[it];
454 }
455 
toString(size_t sz)456 std::string StreamBuf::toString( size_t sz )
457 {
458     u8 * it1 = itget;
459     u8 * it2 = itget + ( sz ? sz : sizeg() );
460     it2 = std::find( it1, it2, 0 );
461     itget = it1 + ( sz ? sz : sizeg() );
462     return std::string( it1, it2 );
463 }
464 
skip(size_t sz)465 void StreamBuf::skip( size_t sz )
466 {
467     itget += sz <= sizeg() ? sz : sizeg();
468 }
469 
seek(size_t sz)470 void StreamBuf::seek( size_t sz )
471 {
472     itget = itbeg + sz < itend ? itbeg + sz : itend;
473 }
474 
StreamFile()475 StreamFile::StreamFile()
476     : _file( nullptr )
477 {}
478 
~StreamFile()479 StreamFile::~StreamFile()
480 {
481     close();
482 }
483 
open(const std::string & fn,const std::string & mode)484 bool StreamFile::open( const std::string & fn, const std::string & mode )
485 {
486     _file = std::fopen( fn.c_str(), mode.c_str() );
487     if ( !_file )
488         ERROR_LOG( fn );
489     return _file != nullptr;
490 }
491 
close(void)492 void StreamFile::close( void )
493 {
494     if ( _file ) {
495         std::fclose( _file );
496         _file = nullptr;
497     }
498 }
499 
size(void) const500 size_t StreamFile::size( void ) const
501 {
502     if ( !_file )
503         return 0;
504     const long pos = std::ftell( _file );
505     std::fseek( _file, 0, SEEK_END );
506     const long len = std::ftell( _file );
507     std::fseek( _file, pos, SEEK_SET );
508     return static_cast<size_t>( len );
509 }
510 
tell(void) const511 size_t StreamFile::tell( void ) const
512 {
513     return tellg();
514 }
515 
seek(size_t pos)516 void StreamFile::seek( size_t pos )
517 {
518     if ( _file )
519         std::fseek( _file, static_cast<long>( pos ), SEEK_SET );
520 }
521 
sizeg(void) const522 size_t StreamFile::sizeg( void ) const
523 {
524     if ( !_file )
525         return 0;
526     const long pos = std::ftell( _file );
527     std::fseek( _file, 0, SEEK_END );
528     const long len = std::ftell( _file );
529     std::fseek( _file, pos, SEEK_SET );
530     return static_cast<size_t>( len - pos );
531 }
532 
tellg(void) const533 size_t StreamFile::tellg( void ) const
534 {
535     return _file ? static_cast<size_t>( std::ftell( _file ) ) : 0;
536 }
537 
sizep(void) const538 size_t StreamFile::sizep( void ) const
539 {
540     return sizeg();
541 }
542 
tellp(void) const543 size_t StreamFile::tellp( void ) const
544 {
545     return tellg();
546 }
547 
skip(size_t pos)548 void StreamFile::skip( size_t pos )
549 {
550     if ( _file )
551         std::fseek( _file, static_cast<long int>( pos ), SEEK_CUR );
552 }
553 
get8()554 u8 StreamFile::get8()
555 {
556     return getUint<uint8_t>();
557 }
558 
put8(const uint8_t v)559 void StreamFile::put8( const uint8_t v )
560 {
561     putUint<uint8_t>( v );
562 }
563 
getBE16()564 uint16_t StreamFile::getBE16()
565 {
566     return be16toh( getUint<uint16_t>() );
567 }
568 
getLE16()569 uint16_t StreamFile::getLE16()
570 {
571     return le16toh( getUint<uint16_t>() );
572 }
573 
getBE32()574 uint32_t StreamFile::getBE32()
575 {
576     return be32toh( getUint<uint32_t>() );
577 }
578 
getLE32()579 uint32_t StreamFile::getLE32()
580 {
581     return le32toh( getUint<uint32_t>() );
582 }
583 
putBE16(uint16_t val)584 void StreamFile::putBE16( uint16_t val )
585 {
586     putUint<uint16_t>( htobe16( val ) );
587 }
588 
putLE16(uint16_t val)589 void StreamFile::putLE16( uint16_t val )
590 {
591     putUint<uint16_t>( htole16( val ) );
592 }
593 
putBE32(uint32_t val)594 void StreamFile::putBE32( uint32_t val )
595 {
596     putUint<uint32_t>( htobe32( val ) );
597 }
598 
putLE32(uint32_t val)599 void StreamFile::putLE32( uint32_t val )
600 {
601     putUint<uint32_t>( htole32( val ) );
602 }
603 
getRaw(size_t sz)604 std::vector<uint8_t> StreamFile::getRaw( size_t sz )
605 {
606     const size_t chunkSize = sz > 0 ? sz : sizeg();
607     if ( chunkSize == 0 || !_file ) {
608         return std::vector<uint8_t>();
609     }
610 
611     std::vector<uint8_t> v( sz ? sz : sizeg() );
612     const size_t count = std::fread( &v[0], chunkSize, 1, _file );
613     if ( count != 1 ) {
614         setfail( true );
615         v.clear();
616     }
617 
618     return v;
619 }
620 
putRaw(const char * ptr,size_t sz)621 void StreamFile::putRaw( const char * ptr, size_t sz )
622 {
623     if ( _file )
624         std::fwrite( ptr, sz, 1, _file );
625 }
626 
toStreamBuf(size_t sz)627 StreamBuf StreamFile::toStreamBuf( size_t sz )
628 {
629     StreamBuf sb;
630     std::vector<uint8_t> buf = getRaw( sz );
631     sb.putRaw( reinterpret_cast<const char *>( &buf[0] ), buf.size() );
632     return sb;
633 }
634 
toString(size_t sz)635 std::string StreamFile::toString( size_t sz )
636 {
637     const std::vector<uint8_t> buf = getRaw( sz );
638     std::vector<uint8_t>::const_iterator itend = std::find( buf.begin(), buf.end(), 0 );
639     return std::string( buf.begin(), itend != buf.end() ? itend : buf.end() );
640 }
641