#include "stdafx.h"

#include "ObjectReaderWriter.hpp"

#include <vector>
#include <assert.h>



CObjectReader::CObjectReader(HANDLE hFile)
	: hFile_(hFile)
{
	assert(hFile_ != INVALID_HANDLE_VALUE && "ファイルハンドルが不正です。");
	assert(hFile_ != NULL && "ファイルハンドルが不正(NULL)です。");
}


DWORD CObjectReader::ReadDWORD()
{
	DWORD value = 0;
	DWORD rd = 0;
	if (!ReadFile(hFile_, &value, sizeof(DWORD), &rd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (rd != sizeof(DWORD)) {
		throw CObjectReaderWriterException(ERROR_HANDLE_EOF);
	}
	return value;
}

bool CObjectReader::ReadBool()
{
	unsigned char value = 0;
	DWORD rd = 0;
	if (!ReadFile(hFile_, &value, sizeof(unsigned char), &rd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (rd != sizeof(unsigned char)) {
		throw CObjectReaderWriterException(ERROR_HANDLE_EOF);
	}
	return value != 0;
}

unsigned __int64 CObjectReader::ReadInt64()
{
	unsigned __int64 value = 0;
	DWORD rd = 0;
	if (!ReadFile(hFile_, &value, sizeof(unsigned __int64), &rd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (rd != sizeof(unsigned __int64)) {
		throw CObjectReaderWriterException(ERROR_HANDLE_EOF);
	}
	return value;
}

void CObjectReader::ReadFILETIME(FILETIME &v_value)
{
	FILETIME value = {0};
	DWORD rd = 0;
	if (!ReadFile(hFile_, &value, sizeof(FILETIME), &rd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (rd != sizeof(FILETIME)) {
		throw CObjectReaderWriterException(ERROR_HANDLE_EOF);
	}
	v_value = value;
}

void CObjectReader::ReadString(tstring& value)
{
	bool unicode = ReadBool();
#ifdef _UNICODE
	if (!unicode) {
		throw CObjectReaderWriterException(ERROR_INVALID_DATA);
	}
#else
	if (unicode) {
		throw CObjectReaderWriterException(ERROR_INVALID_DATA);
	}
#endif
	DWORD len = ReadDWORD();
	std::vector<TCHAR> buf(len);
	DWORD rd;
	if (!ReadFile(hFile_, &buf[0], len * sizeof(TCHAR), &rd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (rd != (len * sizeof(TCHAR))) {
		throw CObjectReaderWriterException(ERROR_HANDLE_EOF);
	}
	value.clear();
	value.append(buf.begin(), buf.end());
}

void CObjectReader::ReadBytes(void *pBuf, size_t siz)
{
	assert(pBuf != NULL && "バッファがNULLです。");
	if (siz == 0) {
		return;
	}
	DWORD rd;
	if (!ReadFile(hFile_, pBuf, static_cast<DWORD>(siz), &rd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (rd != siz) {
		throw CObjectReaderWriterException(ERROR_HANDLE_EOF);
	}
}

void CObjectReader::VerifySig(DWORD sig)
{
	DWORD value = ReadDWORD();
	if (value != sig) {
		throw CObjectReaderWriterException(ERROR_INVALID_DATA);
	}
}

void CObjectReader::VerifySig(const GUID &sig)
{
	GUID value = {0};
	DWORD rd;
	if ( !ReadFile(hFile_, &value, sizeof(GUID), &rd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (rd != sizeof(GUID)) {
		throw CObjectReaderWriterException(ERROR_HANDLE_EOF);
	}
	if ( !IsEqualGUID(sig, value)) {
		throw CObjectReaderWriterException(ERROR_INVALID_DATA);
	}
}


//////////////////////////////////


CObjectWriter::CObjectWriter(HANDLE hFile)
	: hFile_(hFile)
{
	assert(hFile_ != INVALID_HANDLE_VALUE && "ファイルハンドルが不正です。");
	assert(hFile_ != NULL && "ファイルハンドルが不正(NULL)です。");
}


void CObjectWriter::WriteDWORD(DWORD value)
{
	DWORD wd;
	if (!WriteFile(hFile_, &value, sizeof(DWORD), &wd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (wd != sizeof(DWORD)) {
		throw CObjectReaderWriterException(ERROR_DISK_FULL);
	}
}

void CObjectWriter::WriteBool(bool v_value)
{
	unsigned char value = v_value ? 1 : 0;
	DWORD wd;
	if (!WriteFile(hFile_, &value, sizeof(unsigned char), &wd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (wd != sizeof(unsigned char)) {
		throw CObjectReaderWriterException(ERROR_DISK_FULL);
	}
}

void CObjectWriter::WriteInt64(unsigned __int64 value)
{
	DWORD wd;
	if (!WriteFile(hFile_, &value, sizeof(unsigned __int64), &wd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (wd != sizeof(unsigned __int64)) {
		throw CObjectReaderWriterException(ERROR_DISK_FULL);
	}
}

void CObjectWriter::WriteFILETIME(const FILETIME &value)
{
	DWORD wd;
	if (!WriteFile(hFile_, &value, sizeof(FILETIME), &wd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (wd != sizeof(FILETIME)) {
		throw CObjectReaderWriterException(ERROR_DISK_FULL);
	}
}

void CObjectWriter::WriteString(const tstring& value)
{
	bool unicode;
#ifdef _UNICODE
	unicode = true;
#else
	unicode = false;
#endif
	WriteBool(unicode);
	DWORD len = static_cast<DWORD>(value.length());
	WriteDWORD(len);
	DWORD wd;
	if (!WriteFile(hFile_, value.c_str(), len * sizeof(TCHAR), &wd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (wd != (len * sizeof(TCHAR))) {
		throw CObjectReaderWriterException(ERROR_DISK_FULL);
	}
}

void CObjectWriter::WriteBytes(const void *pBuf, size_t siz)
{
	if (siz == 0) {
		return;
	}
	assert(pBuf != NULL && "バッファがNULLです。");

	DWORD wd;
	if (!WriteFile(hFile_, pBuf, static_cast<DWORD>(siz), &wd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (wd != siz) {
		throw CObjectReaderWriterException(ERROR_DISK_FULL);
	}
}

void CObjectWriter::WriteSig(DWORD sig)
{
	WriteDWORD(sig);
}

void CObjectWriter::WriteSig(const GUID &sig)
{
	DWORD wd;
	if (!WriteFile(hFile_, &sig, sizeof(GUID), &wd, NULL)) {
		DWORD err = GetLastError();
		throw CObjectReaderWriterException(err);
	}
	if (wd != sizeof(GUID)) {
		throw CObjectReaderWriterException(ERROR_DISK_FULL);
	}
}

