///////////////////////////////////////////////////////////////////////////////
//  CFileImageAnalyser.cpp

#include <string>
#include <vector>
#include <string.h>
#include "CFileImageAnalyser.h"

namespace fileimage {

CFileImageAnalyser::CFileImageAnalyser(const unsigned char* pData, const unsigned char* pDataEnd) :
m_pData(pData),
m_pDataBegin(pData),
m_pDataEnd(pDataEnd)
{
}

CFileImageAnalyser::~CFileImageAnalyser()
{
}

bool CFileImageAnalyser::IsEnd(void) const
{
	return (m_pData >= m_pDataEnd);
}

bool CFileImageAnalyser::Skip(int Size)
{
	if (m_pData + Size > m_pDataEnd) return false;

	m_pData += Size;

	return true;
}

bool CFileImageAnalyser::IsCanRead(int Size) const
{
	return (m_pData + Size <= m_pDataEnd);
}

bool CFileImageAnalyser::GetChar(char& Data)
{
	if (!IsCanRead(sizeof(char))) return false;

	Data = *reinterpret_cast<const char*>(m_pData);

	m_pData += sizeof(char);

	return true;
}

bool CFileImageAnalyser::GetByte(unsigned char& Data)
{
	if (!IsCanRead(sizeof(unsigned char))) return false;

	Data = *m_pData;

	m_pData += sizeof(unsigned char);

	return true;
}

bool CFileImageAnalyser::GetBool(bool& Data)
{
	if (!IsCanRead(sizeof(unsigned char))) return false;

	Data = (*m_pData == 1);

	m_pData += sizeof(unsigned char);

	return true;
}

bool CFileImageAnalyser::GetShort(short& Data)
{
	if (!IsCanRead(sizeof(short))) return false;

	Data = GetShortNoCheck();
	
	return true;
}

bool CFileImageAnalyser::GetWord(unsigned short& Data)
{
	if (!IsCanRead(sizeof(unsigned short))) return false;

	Data = GetWordNoCheck();

	return true;
}

bool CFileImageAnalyser::GetInt(int& Data)
{
	if (!IsCanRead(sizeof(int))) return false;

	Data = GetIntNoCheck();
	
	return true;
}

bool CFileImageAnalyser::GetDWord(unsigned int& Data)
{
	if (!IsCanRead(sizeof(unsigned int))) return false;

	Data = GetDWordNoCheck();

	return true;
}

bool CFileImageAnalyser::GetFloat(float& Data)
{
	unsigned int DWordData;
	if (!GetDWord(DWordData)) return false;

	Data = *reinterpret_cast<const float*>(&DWordData);

	return true;
}

bool CFileImageAnalyser::GetString(std::string& Text, int Length)
{
	if (!IsCanRead(Length)) return false;

	Text = std::string(reinterpret_cast<const char*>(m_pData), Length).c_str();

	m_pData += Length;

	return true;
}

bool CFileImageAnalyser::GetZeroTerminatedString(std::string& Text)
{
	const unsigned char* pData = m_pData;

	for (;;) {
		if (m_pData >= m_pDataEnd) return false;

		if (*m_pData == 0) break;

		m_pData++;
	}

	Text = std::string(reinterpret_cast<const char*>(pData), reinterpret_cast<const char*>(m_pData));

	m_pData++;

	return true;
}

bool CFileImageAnalyser::GetStringAligned4(std::string& Text)
{
	if (!GetZeroTerminatedString(Text)) return false;

	size_t WrittenLength = Text.length() + 1;

	while ((WrittenLength % 4) != 0) {
		if (!Skip(1)) return false;
		++WrittenLength;
	}

	return true;
}

bool CFileImageAnalyser::GetTextLine(std::string& Text)
{
	std::vector<char> Buffer;

	for (;;) {
		if (m_pData >= m_pDataEnd) return false;

		const char Char = *reinterpret_cast<const char*>(m_pData);

		if (Char == '\r') {
			++m_pData;
			continue;
		}
		else if (Char == '\n') {
			++m_pData;
			break;
		}

		Buffer.push_back(Char);

		++m_pData;
	}

	Buffer.push_back('\0');

	Text = &Buffer[0];

	return true;
}

bool CFileImageAnalyser::GetMemoryBlock(unsigned char* pData, int Size)
{
	if (!IsCanRead(Size)) return false;

	memcpy(pData, m_pData, Size);

	m_pData += Size;

	return true;
}

// オーバーランチェックをおこなわない読み込み
// 先にIsCanReadでオーバーしないようチェックしておくべき
unsigned char CFileImageAnalyser::GetByteNoCheck()
{
	const unsigned char Data = *m_pData;

	m_pData += sizeof(unsigned char);

	return Data;
}

short CFileImageAnalyser::GetShortNoCheck()
{
	const short Data = static_cast<short>(
		(static_cast<unsigned short>(m_pData[0])) |
		(static_cast<unsigned short>(m_pData[1]) << 8));

	m_pData += sizeof(short);

	return Data;
}

unsigned short CFileImageAnalyser::GetWordNoCheck()
{
	const unsigned short Data = (
		(static_cast<unsigned short>(m_pData[0])) |
		(static_cast<unsigned short>(m_pData[1]) << 8));

	m_pData += sizeof(unsigned short);

	return Data;
}

int CFileImageAnalyser::GetIntNoCheck()
{
	const int Data = static_cast<int>(
		(static_cast<unsigned int>(m_pData[0])) |
		(static_cast<unsigned int>(m_pData[1]) << 8) |
		(static_cast<unsigned int>(m_pData[2]) << 16) |
		(static_cast<unsigned int>(m_pData[3]) << 24));

	m_pData += sizeof(int);

	return Data;
}

unsigned int CFileImageAnalyser::GetDWordNoCheck()
{
	const unsigned int Data = (
		(static_cast<unsigned int>(m_pData[0])) |
		(static_cast<unsigned int>(m_pData[1]) << 8) |
		(static_cast<unsigned int>(m_pData[2]) << 16) |
		(static_cast<unsigned int>(m_pData[3]) << 24));

	m_pData += sizeof(unsigned int);

	return Data;
}

float CFileImageAnalyser::GetFloatNoCheck()
{
	const unsigned int DWordData = GetDWordNoCheck();

	return *reinterpret_cast<const float*>(&DWordData);

}

//
const unsigned char* CFileImageAnalyser::GetReadPointer() const
{
	if (IsEnd()) return 0;

	return m_pData;

}

int CFileImageAnalyser::GetCanReadSize() const
{
	return static_cast<int>(m_pDataEnd - m_pData);
}

int CFileImageAnalyser::GetPos() const
{
	return static_cast<int>(m_pData - m_pDataBegin);
}

} // end of namespace fileimage

