2017-07-13 10:26:03 +02:00
|
|
|
/*
|
|
|
|
* CBinaryReader.cpp, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
2012-07-22 18:02:13 +03:00
|
|
|
#include "StdInc.h"
|
|
|
|
#include "CBinaryReader.h"
|
2013-07-28 17:49:50 +03:00
|
|
|
|
2012-07-22 18:02:13 +03:00
|
|
|
#include <SDL_endian.h>
|
|
|
|
#include "CInputStream.h"
|
2013-10-26 00:45:14 +03:00
|
|
|
#include "../CGeneralTextHandler.h"
|
2012-07-22 18:02:13 +03:00
|
|
|
|
2012-07-23 13:23:43 +03:00
|
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
|
|
template <typename CData>
|
|
|
|
CData readLE(CData data)
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
2012-07-23 13:23:43 +03:00
|
|
|
auto dataPtr = (char*)&data;
|
|
|
|
std::reverse(dataPtr, dataPtr + sizeof(data));
|
|
|
|
return data;
|
2012-07-22 18:02:13 +03:00
|
|
|
}
|
2012-07-23 13:23:43 +03:00
|
|
|
#else
|
|
|
|
template <typename CData>
|
|
|
|
CData readLE(CData data)
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
2012-07-23 13:23:43 +03:00
|
|
|
return data;
|
2012-07-22 18:02:13 +03:00
|
|
|
}
|
2012-07-23 13:23:43 +03:00
|
|
|
#endif
|
2012-07-22 18:02:13 +03:00
|
|
|
|
2012-07-23 13:23:43 +03:00
|
|
|
CBinaryReader::CBinaryReader() : stream(nullptr)
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-11-06 19:39:29 +03:00
|
|
|
CBinaryReader::CBinaryReader(CInputStream * stream) : stream(stream)
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-07-23 13:23:43 +03:00
|
|
|
CInputStream * CBinaryReader::getStream()
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
2012-07-23 13:23:43 +03:00
|
|
|
return stream;
|
2012-07-22 18:02:13 +03:00
|
|
|
}
|
|
|
|
|
2012-11-06 19:39:29 +03:00
|
|
|
void CBinaryReader::setStream(CInputStream * stream)
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
2012-11-11 15:23:31 +03:00
|
|
|
this->stream = stream;
|
2012-07-22 18:02:13 +03:00
|
|
|
}
|
|
|
|
|
2012-07-23 13:23:43 +03:00
|
|
|
si64 CBinaryReader::read(ui8 * data, si64 size)
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
2013-10-26 00:45:14 +03:00
|
|
|
si64 bytesRead = stream->read(data, size);
|
|
|
|
if(bytesRead != size)
|
|
|
|
{
|
|
|
|
throw std::runtime_error(getEndOfStreamExceptionMsg(size));
|
|
|
|
}
|
|
|
|
return bytesRead;
|
2012-07-22 18:02:13 +03:00
|
|
|
}
|
|
|
|
|
2012-07-23 13:23:43 +03:00
|
|
|
template <typename CData>
|
|
|
|
CData CBinaryReader::readInteger()
|
2012-07-22 18:02:13 +03:00
|
|
|
{
|
2012-07-23 13:23:43 +03:00
|
|
|
CData val;
|
2013-10-26 00:45:14 +03:00
|
|
|
stream->read(reinterpret_cast<unsigned char *>(&val), sizeof(val));
|
2012-07-23 13:23:43 +03:00
|
|
|
return readLE(val);
|
2012-07-22 18:02:13 +03:00
|
|
|
}
|
|
|
|
|
2012-07-23 13:23:43 +03:00
|
|
|
//FIXME: any way to do this without macro?
|
|
|
|
#define INSTANTIATE(datatype, methodname) \
|
|
|
|
datatype CBinaryReader::methodname() \
|
|
|
|
{ return readInteger<datatype>(); }
|
|
|
|
|
|
|
|
// While it is certanly possible to leave only template method
|
|
|
|
// but typing template parameter every time can be annoying
|
|
|
|
// and templates parameters can't be resolved by return type
|
|
|
|
INSTANTIATE(ui8, readUInt8)
|
|
|
|
INSTANTIATE(si8, readInt8)
|
|
|
|
INSTANTIATE(ui16, readUInt16)
|
|
|
|
INSTANTIATE(si16, readInt16)
|
|
|
|
INSTANTIATE(ui32, readUInt32)
|
|
|
|
INSTANTIATE(si32, readInt32)
|
|
|
|
INSTANTIATE(ui64, readUInt64)
|
|
|
|
INSTANTIATE(si64, readInt64)
|
|
|
|
|
|
|
|
#undef INSTANTIATE
|
2012-07-22 18:02:13 +03:00
|
|
|
|
2013-02-07 20:02:15 +03:00
|
|
|
std::string CBinaryReader::readString()
|
|
|
|
{
|
2013-10-26 00:45:14 +03:00
|
|
|
unsigned int len = readUInt32();
|
|
|
|
assert(len <= 500000); //not too long
|
|
|
|
if (len > 0)
|
2013-02-07 20:02:15 +03:00
|
|
|
{
|
2013-10-26 00:45:14 +03:00
|
|
|
std::string ret;
|
|
|
|
ret.resize(len);
|
|
|
|
read(reinterpret_cast<ui8*>(&ret[0]), len);
|
|
|
|
//FIXME: any need to move this into separate "read localized string" method?
|
|
|
|
if (Unicode::isValidASCII(ret))
|
|
|
|
return ret;
|
|
|
|
return Unicode::toUnicode(ret);
|
2013-02-07 20:02:15 +03:00
|
|
|
}
|
2013-10-26 00:45:14 +03:00
|
|
|
return "";
|
|
|
|
|
2013-02-07 20:02:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void CBinaryReader::skip(int count)
|
|
|
|
{
|
|
|
|
stream->skip(count);
|
|
|
|
}
|
|
|
|
|
2012-07-22 18:02:13 +03:00
|
|
|
std::string CBinaryReader::getEndOfStreamExceptionMsg(long bytesToRead) const
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "The end of the stream was reached unexpectedly. The stream has a length of " << stream->getSize() << " and the current reading position is "
|
|
|
|
<< stream->tell() << ". The client wanted to read " << bytesToRead << " bytes.";
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
}
|