#include "StdAfx.h"
#include "BKDMikrodos.h"

CBKDMikrodos::CBKDMikrodos(const PARSE_RESULT &image) : CBKDImage(image)
{
}

CBKDMikrodos::~CBKDMikrodos(void)
{
}

BOOL CBKDMikrodos::ReadCatalog()
{
	if (!CBKDImage::ReadCatalog())
	{
		return FALSE;
	}

	MikrodosFileRecord curr_record;
	FileRecord curr_fr;

	//читаем нулевой сектор
	if (m_sPImg.nBaseOffset + 0 != m_ImgFile.Seek(m_sPImg.nBaseOffset + 0, CFile::begin))
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
		return FALSE;
	}

	if (m_ImgFile.Read(m_mSector, sizeof(m_mSector)) != sizeof(m_mSector))
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
		return FALSE;
	}

	int recs_count = 0;
	int files_total = *(WORD *)&m_mSector[FMT_MIKRODOS_CAT_RECORD_NUMBER]; //читаем общее кол-во файлов.
	m_sDiskCat.nTotalRecs = (012000 - FMT_MIKRODOS_CAT_BEGIN) / sizeof(MikrodosFileRecord); //это у нас объём каталога, из него надо будет вычесть общее количество записей
	int used_size = 0;

	if (m_sPImg.nBaseOffset + FMT_MIKRODOS_CAT_BEGIN != m_ImgFile.Seek(m_sPImg.nBaseOffset + FMT_MIKRODOS_CAT_BEGIN, CFile::begin)) //перемещаемся к началу каталога.
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
		return FALSE;
	}

	while (--files_total >= 0)
	{
		if (m_ImgFile.Read(&curr_record, sizeof(MikrodosFileRecord)) < sizeof(MikrodosFileRecord))
		{
			m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
			return FALSE; //если даже каталог не прочёлся, а файл уже кончился, то образ повреждён,
			//и делать с ним нечего.
		}

		recs_count++;
		//успешно прочли запись, теперь преобразуем её и поместим в массив
		curr_fr.clear();

		if (curr_record.dir_dir & 0200)
		{
			curr_fr.nAttr |= FR_ATTR_BAD;

			if (curr_record.name[0] == 0)
			{
				curr_record.name[0] = 'B';
				curr_record.name[1] = 'A';
				curr_record.name[2] = 'D';
			}
		}

		if ((curr_record.name[0] == 0177) || (curr_record.len_blk == 0))
		{
			//если директория
			curr_fr.nAttr |= FR_ATTR_DIR;
			curr_fr.nRecType = RECORD_TYPE_DIR;

			if (curr_record.name[0] == 0177)
			{
				curr_fr.strName = BKToUNICODE((BYTE *)curr_record.name + 1, 13, koi8tbl10).Trim();
			}
			else
			{
				curr_fr.strName = BKToUNICODE((BYTE *)curr_record.name, 14, koi8tbl10).Trim();
			}

			curr_fr.nDirBelong = curr_record.dir_num & 0x7f;
			curr_fr.nDirNum = curr_record.dir_dir & 0x7f;
			curr_fr.nAddress = 0; //если копировать curr_record.address, то директории начинают притворяться линками,
			//а в микродосе их по известным мне данным, не должно быть
			curr_fr.nBlkSize = 0;
		}
		else
		{
			//если файл
			curr_fr.nRecType = RECORD_TYPE_FILE;
			CString name = BKToUNICODE((BYTE *)curr_record.name, 14, koi8tbl10).Trim();
			CString ext = _T("");
			int l = name.GetLength();
			int t = name.ReverseFind(_T('.'));

			if (t >= 0) //если расширение есть
			{
				ext = name.Right(l - t - 1);
				name = name.Left(t).Trim();
			}

			if (!ext.IsEmpty())
			{
				name += _T(".") + ext;
			}

			curr_fr.strName = name;
			curr_fr.nDirBelong = 0; //curr_record.dir_num & 0x7f;
			/* из-за непоняток, откуда взялись директории в микродос, может это какой-то
			* единичный экзотический формат, или ошибочно распознались aodos или hord,
			* каталоги покажем как каталоги, но файлы сделаем принадлежащими корню,
			* т.к. есть случаи, когда получалось, что файлы принадлежали несуществующему
			* каталогу и из-за этого вообще не отображались
			*/
			curr_fr.nDirNum = 0;
			curr_fr.nAddress = curr_record.address;
			used_size += curr_record.len_blk;
			curr_fr.nBlkSize = curr_record.len_blk;
		}

		/*  правильный расчёт длины файла.
		т.к. в curr_record.length хранится остаток длины по модулю 0200000, нам из длины в блоках надо узнать
		сколько частей по 0200000 т.е. сколько в блоках частей по 128 блоков.(128блоков == 65536.== 0200000)

		hw = (curr_record.len_blk >>7 ) << 16; //это старшее слова двойного слова
		hw = (curr_record.len_blk / 128) * 65536 = curr_record.len_blk * 512
		*/
		DWORD hw = (curr_record.len_blk << 9) & 0xffff0000; //это старшее слово двойного слова
		curr_fr.nSize = hw + curr_record.length; //это ст.слово + мл.слово
		curr_fr.nStartBlock = curr_record.start_blok;
		m_sDiskCat.vecFC.push_back(curr_fr);
	}

	m_sDiskCat.nFreeRecs = m_sDiskCat.nTotalRecs - recs_count;
	m_sDiskCat.nTotalBlocks = *(WORD *)&m_mSector[FMT_MIKRODOS_DISK_SIZE] - 10;
	m_sDiskCat.nFreeBlocks = m_sDiskCat.nTotalBlocks - used_size;
	return TRUE;
}


