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