// MSFManager.cpp: implementation of the CMSFManager class.
//


#include "pch.h"
#include "MSFManager.h"
#include "BKMessageBox.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif

/////////////////////////////////////////////////////////////////////////////
// Construction/Destruction

#pragma warning(disable:4996)

CMSFManager::CMSFManager()
	: m_pMSFFile(nullptr)
	, m_bOpenForLoad(true)
	, m_header({ MSF_STATE_ID, MSF_VERSION_CURRENT, 0 })
{
}

CMSFManager::~CMSFManager()
{
	ReleaseFile();
}


bool CMSFManager::ReleaseFile()
{
	if (m_pMSFFile) // если файл был открыт
	{
		fclose(m_pMSFFile); // закрываем
		m_pMSFFile = nullptr;
		m_blocks.RemoveAll();
		return true;
	}

	return false;
}

bool CMSFManager::Seek(int nOffset, UINT nFrom) const
{
	return (fseek(m_pMSFFile, nOffset, nFrom) == 0);
}

// проверка msf файла
bool CMSFManager::CheckFile(const fs::path &strPath, bool bSilent)
{
	bool bRet = true;
	ReleaseFile();
	m_pMSFFile = _tfopen(strPath.c_str(), _T("rb"));

	if (m_pMSFFile) // если файл открылся
	{
		m_bOpenForLoad = true;
		int nFilePos = 0;

		// прочитаем заголовок
		if (fread(&m_header, 1, sizeof(m_header), m_pMSFFile) == sizeof(m_header))
		{
			nFilePos += sizeof(m_header);

			if (m_header.type == MSF_STATE_ID) // если ид верный
			{
				if (m_header.version > MSF_VERSION_CURRENT)
				{
					if (!bSilent)
					{
						g_BKMsgBox.Show(IDS_BK_ERROR_MSFVERSIONMISMATCH, MB_OK);
					}

					bRet = false;
				}
				else
				{
					// если старый msf файл
					if (m_header.version < MSF_VERSION_MINIMAL)
					{
						if (!bSilent)
						{
							g_BKMsgBox.Show(IDS_BK_ERROR_MSFOLDVERSION, MB_OK);
						}

						MSF_BLOCK_INFO_OLD bi_old{};
						MSF_BLOCK_INFO bi{};

						// начинаем читать заголовки блоков
						while (fread(&bi_old.header, 1, sizeof(MSF_BLOCK_HEADER_OLD), m_pMSFFile) == sizeof(MSF_BLOCK_HEADER_OLD))
						{
							bi_old.offset = nFilePos;
							// сконвертируем старый заголовок в новый
							bi.offset = bi_old.offset;
							bi.header.type = bi_old.header.type;
							bi.header.id = DWORD(-1);
							bi.header.length = bi_old.header.length;
							// и сохраним
							m_blocks.Add(bi);

							if (!Seek(bi_old.header.length - sizeof(MSF_BLOCK_HEADER_OLD), SEEK_CUR))
							{
								if (!bSilent)
								{
									g_BKMsgBox.Show(IDS_BK_ERROR_MSFCORRUPTMSF, MB_OK);
								}

								bRet = false;
								break;
							}

							nFilePos += bi_old.header.length;
						}
					}
					else
					{
						MSF_BLOCK_INFO bi{};

						// начинаем читать заголовки блоков
						while (fread(&bi.header, 1, sizeof(MSF_BLOCK_HEADER), m_pMSFFile) == sizeof(MSF_BLOCK_HEADER))
						{
							bi.offset = nFilePos;   // заполняем смещение
							m_blocks.Add(bi);       // добавляем блок в список найденных блоков

							// переместимся к следующему блоку
							if (!Seek(bi.header.length - sizeof(MSF_BLOCK_HEADER), SEEK_CUR))
							{
								if (!bSilent)
								{
									g_BKMsgBox.Show(IDS_BK_ERROR_MSFCORRUPTMSF, MB_OK);
								}

								bRet = false;
								break;
							}

							nFilePos += bi.header.length; // скорректируем смещение
						}
					}
				}
			}
			else
			{
				if (!bSilent)
				{
					g_BKMsgBox.Show(IDS_BK_ERROR_MSFNOMSFFILE, MB_OK);
				}

				bRet = false;
			}
		}
		else
		{
			if (!bSilent)
			{
				g_BKMsgBox.Show(IDS_BK_ERROR_MSFREADHEADERRROR, MB_OK);
			}

			bRet = false;
		}

		ReleaseFile(); // закрываем файл и очищаем список блоков
	}
	else
	{
		if (!bSilent)
		{
			g_BKMsgBox.Show(IDS_BK_ERROR_MSFOPENFILEERROR, MB_OK);
		}

		bRet = false;
	}

	return bRet;
}

bool CMSFManager::OpenFile(const fs::path &strPath, bool bLoad, bool bSilent)
{
	bool bRet = true;
	ReleaseFile();
	CString strFlag = bLoad ? _T("rb") : _T("w+b");
	m_pMSFFile = _tfopen(strPath.c_str(), strFlag);

	if (m_pMSFFile) // если файл открылся
	{
		m_bOpenForLoad = bLoad;

		if (bLoad)
		{
			// если открываем для чтения
			// прочитаем заголовок
			if (fread(&m_header, 1, sizeof(m_header), m_pMSFFile) == sizeof(m_header))
			{
				int nFilePos = sizeof(m_header);

				if (m_header.type == MSF_STATE_ID)
				{
					// если старый msf файл
					if (m_header.version < MSF_VERSION_MINIMAL)
					{
						MSF_BLOCK_INFO_OLD bi_old{};
						MSF_BLOCK_INFO bi{};

						// начинаем читать заголовки блоков
						while (fread(&bi_old.header, 1, sizeof(MSF_BLOCK_HEADER_OLD), m_pMSFFile) == sizeof(MSF_BLOCK_HEADER_OLD))
						{
							bi_old.offset = nFilePos;
							// сконвертируем старый заголовок в новый
							bi.offset = bi_old.offset;
							bi.header.type = bi_old.header.type;
							bi.header.id = DWORD(-1);
							bi.header.length = bi_old.header.length;
							// и сохраним
							m_blocks.Add(bi);

							if (!Seek(bi_old.header.length - sizeof(MSF_BLOCK_HEADER_OLD), SEEK_CUR))
							{
								if (!bSilent)
								{
									g_BKMsgBox.Show(IDS_BK_ERROR_MSFCORRUPTMSF, MB_OK);
								}

								bRet = false;
								break;
							}

							nFilePos += bi_old.header.length;
						}
					}
					else
					{
						MSF_BLOCK_INFO bi{};

						// начинаем читать заголовки блоков
						while (fread(&bi.header, 1, sizeof(MSF_BLOCK_HEADER), m_pMSFFile) == sizeof(MSF_BLOCK_HEADER))
						{
							bi.offset = nFilePos;
							m_blocks.Add(bi);

							if (!Seek(bi.header.length - sizeof(MSF_BLOCK_HEADER), SEEK_CUR))
							{
								if (!bSilent)
								{
									g_BKMsgBox.Show(IDS_BK_ERROR_MSFCORRUPTMSF, MB_OK);
								}

								bRet = false;
								break;
							}

							nFilePos += bi.header.length;
						}
					}
				}
				else
				{
					if (!bSilent)
					{
						g_BKMsgBox.Show(IDS_BK_ERROR_MSFNOMSFFILE, MB_OK);
					}

					bRet = false;
				}
			}
			else
			{
				if (!bSilent)
				{
					g_BKMsgBox.Show(IDS_BK_ERROR_MSFREADHEADERRROR, MB_OK);
				}

				bRet = false;
			}
		}
		else
		{
			// если открываем для записи
			// запишем заголовок
			if (fwrite(&m_header, 1, sizeof(m_header), m_pMSFFile) != sizeof(m_header))
			{
				if (!bSilent)
				{
					g_BKMsgBox.Show(IDS_BK_ERROR_MSFWRITEHEADERRROR, MB_OK);
				}

				bRet = false;
			}
		}
	}
	else
	{
		if (!bSilent)
		{
			g_BKMsgBox.Show(IDS_BK_ERROR_MSFOPENFILEERROR, MB_OK);
		}

		bRet = false;
	}

	if (!bRet)
	{
		ReleaseFile();
	}

	return bRet;
}

// ищем нужный блок в массиве
bool CMSFManager::FindBlock(DWORD blockType, DWORD id, MSF_BLOCK_INFO *pBi) const
{
	for (int n = 0; n < m_blocks.GetSize(); ++n)
	{
		if (id == DWORD(-1))
		{
			if (m_blocks[n].header.type == blockType)
			{
				*pBi = m_blocks[n];
				return true;
			}
		}
		else
		{
			if (m_blocks[n].header.type == blockType && m_blocks[n].header.id == id)
			{
				*pBi = m_blocks[n];
				return true;
			}
		}
	}

	return false;
}


bool CMSFManager::SetBlockHeader(MSF_BLOCK_INFO *pBi) const
{
	return SetBlockData(reinterpret_cast<uint8_t *>(&pBi->header), sizeof(MSF_BLOCK_HEADER));
}

bool CMSFManager::GetBlockHeader(MSF_BLOCK_INFO *pBi) const
{
	bool bRet = false;

	if (Seek(pBi->offset, SEEK_SET)) // сначала переместимся к началу блока
	{
		if (m_header.version < MSF_VERSION_MINIMAL /*&& pBi->header.type == MSF_BLOCKTYPE_WAVE*/)
		{
			MSF_BLOCK_HEADER_OLD hdr_old;

			// затем прочитаем заголовок
			if (fread(&hdr_old, 1, sizeof(MSF_BLOCK_HEADER_OLD), m_pMSFFile) == sizeof(MSF_BLOCK_HEADER_OLD))
			{
				MSF_BLOCK_HEADER hdr{ hdr_old.type, DWORD(-1), hdr_old.length};

				if (pBi->header == hdr)
				{
					bRet = true;
				}
			}
		}
		else
		{
			MSF_BLOCK_HEADER hdr;

			// затем прочитаем заголовок
			if (fread(&hdr, 1, sizeof(MSF_BLOCK_HEADER), m_pMSFFile) == sizeof(MSF_BLOCK_HEADER))
			{
				if (pBi->header == hdr)
				{
					bRet = true;
				}
			}
		}
	}
	else
	{
		g_BKMsgBox.Show(IDS_BK_ERROR_MSFSEEKERROR, MB_OK);
	}

	return bRet;
}


bool CMSFManager::SetBlockData(uint8_t *pBuff, UINT length) const
{
	if (length && pBuff)
	{
		return (fwrite(pBuff, 1, length, m_pMSFFile) == length);
	}

	return true;
}


bool CMSFManager::GetBlockData(uint8_t *pBuff, UINT length) const
{
	if (length && pBuff)
	{
		return (fread(pBuff, 1, length, m_pMSFFile) == length);
	}

	return true;
}


// проверка размера блока, перед его чтением. На тот случай, если я опять наизменял конфигурацию
// вход: bi - указатель на блок заголовка
//      size - sizeof структуры
// выход: true - всё нормально
//      false - размер не совпадает.
bool CMSFManager::CheckBlockSize(MSF_BLOCK_INFO *pbi, DWORD size) const
{
	return (pbi->header.length == sizeof(MSF_BLOCK_HEADER) + size);
}

bool CMSFManager::SetBlockTape(uint8_t *pPackedWave, DWORD nBitsLength, DWORD nPackLength) const
{
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(IDS_BK_ERROR_BLKTAPE));
	MSF_BLOCK_INFO bi{ 0,
		{
			MSF_BLOCKTYPE_WAVE,
			DWORD(-1),
			sizeof(MSF_BLOCK_HEADER) + sizeof(DWORD) + nPackLength
		}
	};

	if (SetBlockHeader(&bi))
	{
		if (SetBlockData(reinterpret_cast<uint8_t *>(&nBitsLength), sizeof(DWORD)))
		{
			if (SetBlockData(reinterpret_cast<uint8_t *>(pPackedWave), nPackLength))
			{
				bRet = true;
			}
			else
			{
				str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_HDRBLKWRERR, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}

bool CMSFManager::GetBlockTape(uint8_t *pPackedWave, DWORD *pnBitsLength, DWORD *pnPackLength) const
{
	MSF_BLOCK_INFO bi;
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(IDS_BK_ERROR_BLKTAPE));

	if (FindBlock(MSF_BLOCKTYPE_WAVE, DWORD(-1), &bi))
	{
		if (GetBlockHeader(&bi))
		{
			DWORD nPackLength = bi.header.length - sizeof(MSF_BLOCK_HEADER) - sizeof(DWORD);

			if (GetBlockData(reinterpret_cast<uint8_t *>(pnBitsLength), sizeof(DWORD)))
			{
				if (!pPackedWave)
				{
					*pnPackLength = nPackLength;
					return true;
				}

				if (GetBlockData(reinterpret_cast<uint8_t *>(pPackedWave), nPackLength))
				{
					bRet = true;
				}
				else
				{
					str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
					g_BKMsgBox.Show(str, MB_OK);
				}
			}
			else
			{
				str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKRDERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_BLKNOTFOUND, CString(MAKEINTRESOURCE(IDS_BK_ERROR_BLKTAPE)));
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}


bool CMSFManager::SetBlockPlatformData(MSF_PLATFORM_DATA *pPD) const
{
	ASSERT(pPD);    // по алгоритму, pPD никогда не должен быть null
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_PLATFORM)]));
	MSF_BLOCK_INFO bi{ 0,
		{
			MSF_BLOCKTYPE_PLATFORM,
			DWORD(-1),
			sizeof(MSF_BLOCK_HEADER) // размер заголовка
			+ sizeof(DWORD) * 2 // размер двух первых двордов MSF_PLATFORM_DATA
			+ sizeof(MSF_DEVICE_ID) *pPD->nDevNum  // размер MSF_DEVICE_ID по количеству устройств
		}
	};

	if (SetBlockHeader(&bi))
	{
		if (SetBlockData(reinterpret_cast<uint8_t *>(pPD), sizeof(DWORD) * 2)
		        && SetBlockData(reinterpret_cast<uint8_t *>(pPD->pDevices.data()), sizeof(MSF_DEVICE_ID) * pPD->nDevNum))
		{
			bRet = true;
		}
		else
		{
			str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_HDRBLKWRERR, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}

bool CMSFManager::GetBlockPlatformData(MSF_PLATFORM_DATA *pPD) const
{
	MSF_BLOCK_INFO bi;
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_PLATFORM)]));

	if (FindBlock(MSF_BLOCKTYPE_PLATFORM, DWORD(-1), &bi))
	{
		if (GetBlockHeader(&bi))
		{
			if (GetBlockData(reinterpret_cast<uint8_t *>(pPD), sizeof(DWORD) * 2))
			{
				if (pPD->nDevNum)
				{
					pPD->pDevices.resize(pPD->nDevNum);

					if (pPD->pDevices.data())
					{
						if (GetBlockData(reinterpret_cast<uint8_t *>(pPD->pDevices.data()), sizeof(MSF_DEVICE_ID) * pPD->nDevNum))
						{
							bRet = true;
						}
					}
					else
					{
						g_BKMsgBox.Show(IDS_BK_ERROR_NOTENMEMR, MB_OK);
					}
				}
				else
				{
					pPD->pDevices.clear();
					bRet = true;
				}
			}

			if (!bRet)
			{
				str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKRDERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_BLKNOTFOUND, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}


bool CMSFManager::SetBlockPreview(HBITMAP hScreenshot) const
{
	DIBSECTION ds{};
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_PREVIEW)]));

	if (::GetObject(hScreenshot, sizeof(ds), &ds))
	{
		MSF_BLOCK_INFO bi{ 0,
			{
				MSF_BLOCKTYPE_PREVIEW,
				DWORD(-1),
				sizeof(MSF_BLOCK_HEADER) + sizeof(ds.dsBmih) + ds.dsBmih.biSizeImage
			}
		};

		if (SetBlockHeader(&bi))
		{
			if (SetBlockData(reinterpret_cast<uint8_t *>(&ds.dsBmih), sizeof(ds.dsBmih)))
			{
				ASSERT(ds.dsBm.bmBits);

				if (SetBlockData(reinterpret_cast<uint8_t *>(ds.dsBm.bmBits), ds.dsBmih.biSizeImage))
				{
					bRet = true;
				}
				else
				{
					str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
					g_BKMsgBox.Show(str, MB_OK);
				}
			}
			else
			{
				str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKWRERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		g_BKMsgBox.Show(IDS_BK_ERROR_MSFPREVIEWBLK_OBJ);
	}

	return bRet;
}


bool CMSFManager::GetBlockPreview(HBITMAP *hScreenshot, uint8_t **pBits) const
{
	MSF_BLOCK_INFO bi;
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_PREVIEW)]));

	if (FindBlock(MSF_BLOCKTYPE_PREVIEW, DWORD(-1), &bi))
	{
		if (GetBlockHeader(&bi))
		{
			BITMAPINFOHEADER bmih{};

			if (GetBlockData(reinterpret_cast<uint8_t *>(&bmih), sizeof(BITMAPINFOHEADER)))
			{
				*pBits = nullptr;

				if ((*hScreenshot = ::CreateDIBSection(nullptr, (BITMAPINFO *)&bmih, DIB_RGB_COLORS, (void **)pBits, nullptr, 0)))
				{
					if (GetBlockData(*pBits, bmih.biSizeImage))
					{
						bRet = true;
					}
					else
					{
						str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
						g_BKMsgBox.Show(str, MB_OK);
					}
				}
				else
				{
					g_BKMsgBox.Show(IDS_BK_ERROR_MSFPREVIEWBLK_DIB, MB_OK);
				}
			}
			else
			{
				str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKRDERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_BLKNOTFOUND, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}

bool CMSFManager::SetBlockConfig() const
{
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_CONFIG)]));
	MSF_BLOCK_INFO bi{ 0,
		{
			MSF_BLOCKTYPE_CONFIG,
			DWORD(-1),
			sizeof(MSF_BLOCK_HEADER)
		}  // + длина блока. длина переменная
	};
	UINT nSize = _MAX_PATH * 1000;
	auto pBlock = std::vector<uint8_t>(nSize); // размер будет достаточен наверняка, 1000 строк длиной 256 байтов

	if (pBlock.data())
	{
		ZeroMemory(pBlock.data(), nSize);
		ULONGLONG len = g_Config.SaveConfig_ToMemory(pBlock.data(), nSize);
		bi.header.length += DWORD(len);

		if (SetBlockHeader(&bi))
		{
			if (SetBlockData(pBlock.data(), DWORD(len)))
			{
				bRet = true;
			}
			else
			{
				str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKWRERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		g_BKMsgBox.Show(IDS_BK_ERROR_NOTENMEMR, MB_OK);
	}

	return bRet;
}

bool CMSFManager::GetBlockConfig() const
{
	MSF_BLOCK_INFO bi;
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_CONFIG)]));

	if (FindBlock(MSF_BLOCKTYPE_CONFIG, DWORD(-1), &bi))
	{
		if (GetBlockHeader(&bi))
		{
			DWORD nBlockLength = bi.header.length - sizeof(MSF_BLOCK_HEADER);
			auto pBlock = std::vector<uint8_t>(nBlockLength);

			if (pBlock.data())
			{
				if (GetBlockData(pBlock.data(), nBlockLength))
				{
					g_Config.LoadConfig_FromMemory(pBlock.data(), nBlockLength);
					bRet = true;
				}
				else
				{
					str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
					g_BKMsgBox.Show(str, MB_OK);
				}
			}
			else
			{
				g_BKMsgBox.Show(IDS_BK_ERROR_NOTENMEMR, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKRDERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_BLKNOTFOUND, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}


bool CMSFManager::SetBlockFrameData(MSF_FRAMEDATA *FDBlock) const
{
	return SetBlock(MSF_BLOCKTYPE_FRAMEDATA, DWORD(-1), reinterpret_cast<uint8_t *>(FDBlock), sizeof(MSF_FRAMEDATA));
}

bool CMSFManager::GetBlockFrameData(MSF_FRAMEDATA *FDBlock) const
{
	if (m_header.version < MSF_VERSION_MINIMAL)
	{
		return false;
	}

	return GetBlock(MSF_BLOCKTYPE_FRAMEDATA, DWORD(-1), reinterpret_cast<uint8_t *>(FDBlock), sizeof(MSF_FRAMEDATA));
}


bool CMSFManager::SetBlockCPURegisters(MSF_CPU_REGISTERS *pCPURegisters) const
{
	return SetBlock(MSF_BLOCKTYPE_CPU_REGISTERS, DWORD(-1), reinterpret_cast<uint8_t *>(pCPURegisters), sizeof(MSF_CPU_REGISTERS));
}

bool CMSFManager::GetBlockCPURegisters(MSF_CPU_REGISTERS *pCPURegisters) const
{
	return GetBlock(MSF_BLOCKTYPE_CPU_REGISTERS, DWORD(-1), reinterpret_cast<uint8_t *>(pCPURegisters), sizeof(MSF_CPU_REGISTERS));
}


bool CMSFManager::SetBlockMemMap(DWORD id, BKMEMBank_t *MBType, UINT nMemMapSize, uint32_t nROMPresent) const
{
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_MEMMAP)]));
	MSF_BLOCK_INFO bi{ 0,
		{
			MSF_BLOCKTYPE_MEMMAP,
			id,
			sizeof(MSF_BLOCK_HEADER) + sizeof(BKMEMBank_t) *nMemMapSize + sizeof(nROMPresent)
		}
	};

	if (SetBlockHeader(&bi))
	{
		if (SetBlockData(reinterpret_cast<uint8_t *>(MBType), sizeof(BKMEMBank_t) * nMemMapSize)
		        && SetBlockData(reinterpret_cast<uint8_t *>(&nROMPresent), sizeof(nROMPresent)))
		{
			bRet = true;
		}
		else
		{
			str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_HDRBLKWRERR, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}

bool CMSFManager::GetBlockMemMap(DWORD id, BKMEMBank_t *MBType, UINT nMemMapSize, uint32_t &nROMPresent) const
{
	MSF_BLOCK_INFO bi;
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(MSF_BLOCKTYPE_MEMMAP)]));

	if (FindBlock(MSF_BLOCKTYPE_MEMMAP, id, &bi))
	{
		if (GetBlockHeader(&bi))
		{
			if (CheckBlockSize(&bi, sizeof(BKMEMBank_t) * nMemMapSize) + sizeof(nROMPresent))
			{
				bRet = GetBlockData(reinterpret_cast<uint8_t *>(MBType), sizeof(BKMEMBank_t) * nMemMapSize);
				uint32_t data = 0;
				bRet = bRet && GetBlockData(reinterpret_cast<uint8_t *>(&data), sizeof(nROMPresent));
				nROMPresent = data;
			}

			if (!bRet)
			{
				str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKRDERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		// в старых версиях этого блока не было,
		// поэтому старые версии будут не совместимы с новой. и ничего тут не поделать
		str.Format(IDS_BK_ERROR_BLKNOTFOUND, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}


bool CMSFManager::SetBlockBaseMemory(DWORD id, uint8_t *pMemory, UINT nSize) const
{
	return SetBlock(MSF_BLOCKTYPE_BASEMEMORY, id, pMemory, nSize);
}

bool CMSFManager::GetBlockBaseMemory(DWORD id, uint8_t *pMemory, UINT nSize) const
{
	return GetBlock(MSF_BLOCKTYPE_BASEMEMORY, id, pMemory, nSize);
}


bool CMSFManager::SetBlockPortRegs(DWORD id, MSF_PORT_REGS *pPortRegs) const
{
	return SetBlock(MSF_BLOCKTYPE_PORT_REGS, id, reinterpret_cast<uint8_t *>(pPortRegs), sizeof(MSF_PORT_REGS));
}

bool CMSFManager::GetBlockPortRegs(DWORD id, MSF_PORT_REGS *pPortRegs) const
{
	if (m_header.version < MSF_VERSION_MINIMAL)
	{
		return false;
	}

	return GetBlock(MSF_BLOCKTYPE_PORT_REGS, id, reinterpret_cast<uint8_t *>(pPortRegs), sizeof(MSF_PORT_REGS));
}


bool CMSFManager::SetBlockCustomData(DWORD id, uint8_t *pData, UINT nSize) const
{
	return SetBlock(MSF_BLOCKTYPE_CUSTOM, id, pData, nSize);
}

bool CMSFManager::GetBlockCustomData(DWORD id, uint8_t *pData, UINT nSize) const
{
	return GetBlock(MSF_BLOCKTYPE_CUSTOM, id, pData, nSize);
}


const UINT CMSFManager::m_arBlkStrID[] =
{
	IDS_BK_ERROR_BLKPLATFORMDATA,
	IDS_BK_ERROR_BLKPREVIEW,
	IDS_BK_ERROR_BLKCONFIG,
	IDS_BK_ERROR_BLKFRAMEDATA,
	IDS_BK_ERROR_BLKCPUREGS,
	IDS_BK_ERROR_BLKBASEMEM,
	IDS_BK_ERROR_BLKSYSREGS,
	IDS_BK_ERROR_BLKMEMMAPMGR,
	IDS_BK_ERROR_BLKCUSTOM,
};

bool CMSFManager::SetBlock(MSF_BLOCKTYPE bt, DWORD id, uint8_t *pData, UINT nSize) const
{
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(bt)]));
	MSF_BLOCK_INFO bi{ 0,
		{
			bt,
			id,
			sizeof(MSF_BLOCK_HEADER) + nSize
		}
	};

	if (SetBlockHeader(&bi))
	{
		if (SetBlockData(pData, nSize))
		{
			bRet = true;
		}
		else
		{
			str.Format(IDS_BK_ERROR_DTABLKWRERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_HDRBLKWRERR, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}

bool CMSFManager::GetBlock(MSF_BLOCKTYPE bt, DWORD id, uint8_t *pData, UINT nSize) const
{
	MSF_BLOCK_INFO bi;
	CString str;
	bool bRet = false;
	CString strMsg = CString(MAKEINTRESOURCE(m_arBlkStrID[static_cast<UINT>(bt)]));

	if (FindBlock(bt, id, &bi))
	{
		if (GetBlockHeader(&bi))
		{
			if (CheckBlockSize(&bi, nSize))
			{
				bRet = GetBlockData(pData, nSize);
			}

			if (!bRet)
			{
				str.Format(IDS_BK_ERROR_DTABLKRDERR, strMsg);
				g_BKMsgBox.Show(str, MB_OK);
			}
		}
		else
		{
			str.Format(IDS_BK_ERROR_HDRBLKRDERR, strMsg);
			g_BKMsgBox.Show(str, MB_OK);
		}
	}
	else
	{
		str.Format(IDS_BK_ERROR_BLKNOTFOUND, strMsg);
		g_BKMsgBox.Show(str, MB_OK);
	}

	return bRet;
}


