#pragma once

#include <exception>
#include <string>


/*!
 * オブジェクトの読み書き中の例外
 */
class CObjectReaderWriterException
	: public std::exception
{
private:
	DWORD errcode_;

public:
	CObjectReaderWriterException(DWORD errcode)
		: errcode_(errcode)
	{
	}

	DWORD GetErrorCode() const
	{
		return errcode_;
	}
};


/*!
 * オブジェクトの読み込み。
 * バイナリデータのポータビリティ(アライメントやバイトオーダー)は考慮されていません。
 */
class CObjectReader
{
private:

	/*!
	 * ファイルハンドル
	 */
	HANDLE hFile_;

	CObjectReader(const CObjectReader&); //<! 実装なし
	CObjectReader& operator=(const CObjectReader&); //<! 実装なし

public:
	/*!
	 * ファイルハンドルを指定して構築する。
	 * このクラス自身はハンドルのオープンおよびクローズ等は処理しない。
	 */
	CObjectReader(HANDLE hFile);

	/*!
	 * ファイルの現在位置からDWORDを読み込む。
	 * 読み込みが失敗したか、読み込んだ結果サイズが一致しなければ例外をスローする。
	 * \return 読み込まれたDWORD
	 */
	DWORD ReadDWORD();

	/*!
	 * ファイルの現在位置からboolを読み込む。
	 * 読み込みが失敗したか、読み込んだ結果サイズが一致しなければ例外をスローする。
	 * \return 読み込まれたbool
	 */
	bool ReadBool();

	/*!
	 * ファイルの現在位置からunsigned __int64を読み込む。
	 * 読み込みが失敗したか、読み込んだ結果サイズが一致しなければ例外をスローする。
	 * \return 読み込まれたunsigned __int64
	 */
	unsigned __int64 ReadInt64();

	/*!
	 * ファイルの現在位置からFILETIMEを読み込む。
	 * 読み込みが失敗したか、読み込んだ結果サイズが一致しなければ例外をスローする。
	 * \param 読み込まれたFILETIMEの格納先
	 */
	void ReadFILETIME(FILETIME &value);

	/*!
	 * ファイルの現在位置からtstringを読み込む。
	 * 文字は実行中のプロセスがUNICODEであればUNICODEで格納されていなければならず、
	 * MBCSであればMBCSで格納されていなければなりません。
	 * 一致しない場合は例外がスローされます。
	 * 読み込みが失敗したか、読み込んだ結果サイズが一致しなければ例外をスローする。
	 * \param 読み込まれた文字列の格納先
	 */
	void ReadString(tstring& value);

	/*!
	 * 任意のバイトを読み込みます。
	 * 読み込みが失敗したか、読み込んだ結果サイズが一致しなければ例外をスローする。
	 * \param pBuf 読み込まれたバイトの格納先
	 * \param siz 格納サイズ
	 */
	void ReadBytes(void *pBuf, size_t siz);

	/*!
	 * DWORDで構成される識別子が一致するか確認します。
	 * DWORDが読みとれなかったか、一致しない場合は例外がスローされます。
	 */
	void VerifySig(DWORD sig);

	/*!
	 * GUIDで構成される識別子が一致するか確認します。
	 * GUIDが読み取れなかったか、一致しない場合は例外がスローされます。
	 */
	void VerifySig(const GUID &sig);
};


/*!
 * オブジェクトの書き込み。
 * バイナリデータのポータビリティ(アライメントやバイトオーダー)は考慮されていません。
 */
class CObjectWriter
{
private:

	/*!
	 * ファイルハンドル
	 */
	HANDLE hFile_;

	CObjectWriter(const CObjectReader&); //<! 実装なし
	CObjectWriter& operator=(const CObjectReader&); //<! 実装なし

public:
	/*!
	 * ファイルハンドルを指定して構築します。
	 * このクラスはファイルのオープン、クローズ等の処理はしません。
	 */
	CObjectWriter(HANDLE hFile);

	/*!
	 * DWORDを書き込みます。
	 * 書き込みに失敗すると例外がスローされます。
	 * \param value 書き込み値
	 */
	void WriteDWORD(DWORD value);

	/*!
	 * boolを書き込みます。
	 * 書き込みに失敗すると例外がスローされます。
	 * \param value 書き込み値
	 */
	void WriteBool(bool value);

	/*!
	 * unsigned __int64を書き込みます。
	 * 書き込みに失敗すると例外がスローされます。
	 * \param value 書き込み値
	 */
	void WriteInt64(unsigned __int64 value);

	/*!
	 * DWORDを書き込みます。
	 * 書き込みに失敗すると例外がスローされます。
	 * \param value 書き込み値
	 */
	void WriteFILETIME(const FILETIME &value);

	/*!
	 * 文字列を書き込みます。
	 * 現在のプロセスがUNICODEであればUNICODEで格納されます。
	 * MBCSであればMBCSで格納されます。
	 * 書き込みに失敗すると例外がスローされます。
	 * \param value 書き込み値
	 */
	void WriteString(const tstring& value);

	/*!
	 * バイトデータを書き込みます。
	 * 書き込みに失敗すると例外がスローされます。
	 * \param pBuf 書き込みデータのポインタ
	 * \param siz 書き込みサイズ
	 */
	void WriteBytes(const void *pBuf, size_t siz);

	/*!
	 * DWORDで構成する識別子を書き込みます。
	 * 書き込みに失敗すると例外がスローされます。
	 */
	void WriteSig(DWORD sig);

	/*!
	 * GUIDで構成する識別子を書き込みます。
	 * 書き込みに失敗すると例外がスローされます。
	 */
	void WriteSig(const GUID &sig);
};
