#include "pch.h"
#include "FloppyDrive.h"

#define FDD_DUMP_TRACK 0

const std::array<int, 4> CFloppyDrive::m_nSectorSizes = { 128, 256, 512, 1024 };

CFloppyDrive::CFloppyDrive()
	: m_nTracks(FLOPPY_TRACKS + 3)          // количество дорожек
	, m_nSides(FLOPPY_SIDES)                // количество сторон
	, m_nSectorsPerTrk(FLOPPY_TRACK_LEN)    // количество секторов на дорожке
	, m_nSectorSize(FLOPPY_SECTOR_TYPE)     // тип размера сектора
{
	SetArrays();
}


bool CFloppyDrive::SetArrays()
{
	m_nTrackSize = static_cast<size_t>(m_nSectorsPerTrk) * m_nSectorSizes[m_nSectorSize];
	m_nRawTrackSize = FLOPPY_TRKLEN_DD;
	m_nRawMarkerSize = m_nRawTrackSize / 2;

	if (m_pData)
	{
		m_pData.reset();
	}

	if (m_pMarker)
	{
		m_pMarker.reset();
	}

	m_pData = std::make_unique<uint8_t[]>(m_nRawTrackSize);
	m_pMarker = std::make_unique<uint8_t[]>(m_nRawMarkerSize);

	if (m_pData && m_pMarker)
	{
		memset(m_pData.get(), 0, m_nRawTrackSize);
		memset(m_pMarker.get(), 0, m_nRawMarkerSize);
		return true;
	}

	return false;
}

void CFloppyDrive::Reset()
{
	m_nDataTrack = m_nDataSide = -1;
	m_nDataPtr = 0;
}

bool CFloppyDrive::Attach(const fs::path &strFile, const bool bExclusive)
{
	// если пытаемся приаттачить уже ранее приаттаченный этот же образ
	if (CString(m_strFileName.c_str()).CollateNoCase(CString(strFile.c_str())) == 0)
	{
		return true; // то просто выйдем, как будто всё как надо сделали.
	}

	// Если какой-то другой образ подсоединён, сперва отсоединим
	Detach();
	UINT nOpenFlag = bExclusive ? CFile::shareDenyWrite : CFile::shareDenyNone;
	m_bReadOnly = false;
	bool bRes = !!m_File.Open(strFile.c_str(), CFile::modeReadWrite | nOpenFlag); // сперва для чтения-записи

	if (!bRes) // если не получилось
	{
		m_bReadOnly = true; // ставим защиту от записи
		bRes = !!m_File.Open(strFile.c_str(), CFile::modeRead | nOpenFlag); // то просто для чтения

		if (!bRes)
		{
			return false; // вообще никак не получилось открыть
		}
	}

	m_strFileName = strFile;
	Reset();
	return true;
}

void CFloppyDrive::Detach()
{
	FlushChanges();

	if (isAttached())
	{
		m_File.Close();
	}

	m_strFileName.clear();
	m_bReadOnly = false;
	Reset();
}

void CFloppyDrive::SetGeometry(const int nTracks, const int nSides, const int nSectPerTrk, const int nSectSz)
{
	m_nTracks = nTracks;
	m_nSides = nSides;
	m_nSectorsPerTrk = nSectPerTrk;
	m_nSectorSize = nSectSz & 3;
	SetArrays();
}

// Читаем дорожку из файла и заполняем m_data
void CFloppyDrive::PrepareTrack(const int nTrack, const int nSide)
{
	if (m_nDataTrack == nTrack && m_nDataSide == nSide)
	{
		return;
	}

	FlushChanges();
	m_nDataPtr = 0;
	m_nDataTrack = nTrack;
	m_nDataSide = nSide;
	// Предполагаем, что дорожка состоит из 10 секторов, 512 байтов каждый; смещение в файле === ((Track<<1)+SIDE)*m_nTrackSize
	LONGLONG foffset = (static_cast<LONGLONG>(nTrack) * m_nSides + nSide) * m_nTrackSize;
	auto data = std::vector<uint8_t>(m_nTrackSize);

	if (data.data())
	{
		memset(data.data(), 0, m_nTrackSize);

		if (isAttached())
		{
			if (foffset == m_File.Seek(foffset, CFile::SeekPosition::begin))
			{
				size_t count = m_File.Read(data.data(), m_nTrackSize);
				// TODO: Контроль ошибок чтения файла.
			}
		}

		// Заполняем массив m_data и массив m_marker промаркированными данными
		EncodeTrackData(data.data());
		TRACE("FDD::Encode track: %d side: %d\n", m_nDataTrack, m_nDataSide);
#if (_DEBUG && FDD_DUMP_TRACK)
		FILE *f = fopen("encoded_track.dat", "wb");

		if (f)
		{
			fwrite(m_pData.get(), 1, m_nRawTrackSize, f);
			fclose(f);
		}

#endif
	}
}

void CFloppyDrive::FlushChanges()
{
	if (!m_bTrackChanged || !isAttached())
	{
		return;
	}

	// Декодируем данные дорожки из m_data
	auto data = std::vector<uint8_t>(m_nTrackSize);

	if (data.data())
	{
		TRACE("FDD::Decode track: %d side: %d\n", m_nDataTrack, m_nDataSide);
#if (_DEBUG && FDD_DUMP_TRACK)
		FILE *f = fopen("decoded_track.dat", "wb");

		if (f)
		{
			fwrite(m_pData.get(), 1, m_nRawTrackSize, f);
			fclose(f);
		}

#endif
		bool decoded = DecodeTrackData(data.data());

		if (decoded)  // Записываем файл только если дорожка корректно декодировалась из raw data
		{
			// Предполагаем, что дорожка состоит из 10 секторов, 512 байтов каждый; смещение в файле === ((Track<<1)+SIDE)*m_nTrackSize
			size_t foffset = ((static_cast<size_t>(m_nDataTrack) * 2) + (m_nDataSide)) * m_nTrackSize;
			size_t foffset_end = foffset + m_nTrackSize;
			// Проверяем длину файла
			size_t currentFileSize = m_File.GetLength();
			std::array<uint8_t, 512> datafill{ 0 };
			datafill.fill(0);

			while (currentFileSize < foffset_end)
			{
				// увеличиваем файл посекторно на нужное кол-во секторов
				UINT bytesToWrite = (foffset_end - currentFileSize) % 512;

				if (bytesToWrite == 0)
				{
					bytesToWrite = 512;
				}

				m_File.Write(datafill.data(), bytesToWrite);
				// TODO: Проверка на ошибки записи
				currentFileSize += bytesToWrite;
			}

			// Сохраняем данные.
			m_File.Seek(foffset, CFile::SeekPosition::begin);
			// size_t dwBytesWritten =
			m_File.Write(data.data(), m_nTrackSize);
			// TODO: Проверка на ошибки записи
		}
		else
		{
			TRACE0("FDD::Ошибка декодирования дорожки.\n");
			// а иначе, просто не записываем, чтоб не попортить образ
		}
	}

	m_bTrackChanged = false;
}


// Заполняем массив m_data и массив m_marker промаркированными данными
void CFloppyDrive::EncodeTrackData(uint8_t *pSrc)
{
	memset(m_pMarker.get(), 0, m_nRawMarkerSize);
	size_t ptr = 0;
	int gap = 42;  // длина GAP4a + GAP1

	for (int sect = 0; sect < m_nSectorsPerTrk; ++sect)
	{
		// GAP
		//for (int count = gap; count > 0; count--)
		//{
		//  m_pData[ptr++] = 0x4e;
		//}
		memset(&m_pData[ptr], 0x4e, gap);
		ptr += gap;
		// заголовок сектора
		//for (int count = 12; count > 0; count--)
		//{
		//  m_pData[ptr++] = 0x00;
		//}
		memset(&m_pData[ptr], 0x00, 12);
		ptr += 12;
		// маркер
		m_pMarker[ptr / 2] = true;  // Индексный маркер; начало подсчёта CRC
		uint8_t *pCrcPtr = &m_pData[ptr]; size_t nCrcPtr = ptr;
		m_pData[ptr++] = 0xa1;
		m_pData[ptr++] = 0xa1;
		m_pData[ptr++] = 0xa1;
		m_pData[ptr++] = 0xfe;
		m_pData[ptr++] = LOBYTE(m_nDataTrack);
		m_pData[ptr++] = LOBYTE(m_nDataSide);
		m_pData[ptr++] = sect + 1;
		m_pData[ptr++] = m_nSectorSize; // Предполагается 512 байтов на сектор;
		// crc
		uint16_t crc = getCrc(pCrcPtr, ptr - nCrcPtr);
		m_pData[ptr++] = HIBYTE(crc);
		m_pData[ptr++] = LOBYTE(crc);
		// синхропоследовательность
		//for (int count = 22; count > 0; count--)
		//{
		//  m_pData[ptr++] = 0x4e;
		//}
		memset(&m_pData[ptr], 0x4e, 22);
		ptr += 22;
		// заголовок данных
		//for (int count = 12; count > 0; count--)
		//{
		//  m_pData[ptr++] = 0x00;
		//}
		memset(&m_pData[ptr], 0x00, 12);
		ptr += 12;
		// маркер
		m_pMarker[ptr / 2] = true;  // Маркер данных; начало подсчёта CRC
		pCrcPtr = &m_pData[ptr]; nCrcPtr = ptr;
		m_pData[ptr++] = 0xa1;
		m_pData[ptr++] = 0xa1;
		m_pData[ptr++] = 0xa1;
		m_pData[ptr++] = 0xfb;
		// данные
		const size_t nSectSize = m_nSectorSizes[m_nSectorSize];
		memcpy(m_pData.get() + ptr, pSrc, nSectSize);
		ptr += nSectSize;
		pSrc += nSectSize;
		// crc
		crc = getCrc(pCrcPtr, ptr - nCrcPtr);
		m_pData[ptr++] = HIBYTE(crc);
		m_pData[ptr++] = LOBYTE(crc); // CRC
		gap = 36;  // длина GAP3
	}

	// заполняем GAP4B до конца дорожки
	while (ptr < m_nRawTrackSize)
	{
		m_pData[ptr++] = 0x4e;
	}
}

// Декодирование данных дорожки из raw data
// pDest - массив m_nTrackSize байтов
// Возвращается: true - декодировано, false - ошибка декодирования
bool CFloppyDrive::DecodeTrackData(uint8_t *pDest) const
{
	uint8_t sectcyl{}, secthd{}, sectsec{}, sectno{};
	int sectorsize{};
	size_t ptr = 0;  // Смещение в массиве m_data

	// у полноценного формата ещё есть маркер индекса.
	// найдём его
	while (ptr < m_nRawTrackSize && m_pData[ptr] == 0x4e)
	{
		ptr++;    // Пропускаем GAP1
	}

	if (ptr >= m_nRawTrackSize)
	{
		return true;    // Конец дорожки или ошибка
	}

	if (m_pData[ptr] == 0xc1) // если нашли
	{
		ptr += 4;           // пропустим, и за ним снова будет 4e
	}
	else if (m_pData[ptr] == 0) // если не нашли, а сразу наткнулись на синхропрследовательность
	{
		ptr--;  // чуть вернёмся назад, чтобы алгоритм не ломать.
	}

	for (;;)
	{
		while (ptr < m_nRawTrackSize && m_pData[ptr] == 0x4e)
		{
			ptr++;    // Пропускаем GAP1 или GAP3
		}

		if (ptr >= m_nRawTrackSize)
		{
			break;    // Конец дорожки или ошибка
		}

		while (m_pData[ptr] == 0x00)
		{
			if (++ptr >= m_nRawTrackSize)    // Пропускаем синхропоследовательность
			{
				return false;    // Что-то не так
			}
		}

		uint8_t *pCrcPtr = &m_pData[ptr]; size_t nCrcPtr = ptr;

		if (ptr < m_nRawTrackSize && m_pData[ptr] == 0xa1)
		{
			ptr++;
		}

		if (ptr < m_nRawTrackSize && m_pData[ptr] == 0xa1)
		{
			ptr++;
		}

		if (ptr < m_nRawTrackSize && m_pData[ptr] == 0xa1)
		{
			ptr++;
		}

		if (ptr >= m_nRawTrackSize)
		{
			return false;    // Что-то не так
		}

		if (m_pData[ptr++] != 0xfe)
		{
			TRACE0("FDD::индексный маркер не найден.\n");
			return false;    // Индексный маркер не найден
		}

		if (ptr < m_nRawTrackSize)
		{
			sectcyl = m_pData[ptr++];

			if (sectcyl != m_nDataTrack)
			{
				TRACE0("FDD::неверный номер дорожки.\n");
				return false; // неверный номер дорожки
			}
		}

		if (ptr < m_nRawTrackSize)
		{
			secthd = m_pData[ptr++];

			if (secthd != m_nDataSide)
			{
				TRACE0("FDD::неверный номер стороны.\n");
				return false; // неверный номер стороны
			}
		}

		if (ptr < m_nRawTrackSize)
		{
			sectsec = m_pData[ptr++];

			if (sectsec == 0 || sectsec > m_nSectorsPerTrk)
			{
				TRACE0("FDD::неверный номер сектора.\n");
				return false; // несуществующий номер сектора
			}
		}

		if (ptr < m_nRawTrackSize)
		{
			sectno = m_pData[ptr++];

			switch (sectno)
			{
				case 0:
					sectorsize = 128;
					break;

				case 1:
					sectorsize = 256;
					break;

				case 2:
					sectorsize = 512;
					break;

				case 3:
					sectorsize = 1024;
					break;

				default:
					TRACE0("FDD::неверный тип размера сектора.\n");
					return false;    // Что-то не так: неправильный размер сектора
			}
		}

		if (ptr >= m_nRawTrackSize)
		{
			return false;    // Что-то не так
		}

		// crc
		uint16_t crc = getCrc(pCrcPtr, ptr - nCrcPtr);
		uint16_t crcRd = 0xffff;

		if (ptr < m_nRawTrackSize)
		{
			crcRd = (m_pData[ptr++]) << 8;
		}

		if (ptr < m_nRawTrackSize)
		{
			crcRd |= (m_pData[ptr++]);
		}

		if (crc != crcRd)
		{
			TRACE0("FDD::неверный CRC заголовка.\n");
			return false; // несуществующий номер сектора
		}

		while (m_pData[ptr] == 0x4e)
		{
			if (++ptr >= m_nRawTrackSize)    // Пропускаем GAP2
			{
				return false;    // Что-то не так
			}
		}

		while (m_pData[ptr] == 0x00)
		{
			if (++ptr >= m_nRawTrackSize)    // Пропускаем синхропоследовательность
			{
				return false;    // Что-то не так
			}
		}

		pCrcPtr = &m_pData[ptr]; nCrcPtr = ptr;

		if (ptr < m_nRawTrackSize && m_pData[ptr] == 0xa1)
		{
			ptr++;
		}

		if (ptr < m_nRawTrackSize && m_pData[ptr] == 0xa1)
		{
			ptr++;
		}

		if (ptr < m_nRawTrackSize && m_pData[ptr] == 0xa1)
		{
			ptr++;
		}

		if (ptr >= m_nRawTrackSize)
		{
			return false;    // Что-то не так
		}

		if (m_pData[ptr] != 0xfb && m_pData[ptr] != 0xf8)
		{
			TRACE0("FDD::маркер данных не найден.\n");
			return false;    // Маркер данных не найден
		}

		ptr++;
		// Копируем данные сектора, так мы можем пытаться интерпретировать пользовательский формат.
		// вообще почти любой нестандартный, включая интерлив.
		// исключение - нельзя задавать произвольные номера дорожки и стороны.
		size_t destptr = (static_cast<size_t>(sectsec) - 1) * sectorsize;
		// если в процессе вылезем за пределы массива-приёмника
		bool bBrk = false;

		if (destptr + sectorsize >= m_nTrackSize)
		{
			sectorsize -= int((destptr + sectorsize) - m_nTrackSize); // корректируем количество копируемых данных
			bBrk = true;
		}

		int ndd = 0;

		// но если и теперь в процессе вылезем за пределы массива m_data
		if (ptr + sectorsize >= m_nRawTrackSize)
		{
			ndd = sectorsize;
			sectorsize -= int((ptr + sectorsize) - m_nRawTrackSize); // то корректируем количество копируемых данных
			ndd -= sectorsize; // а разницу надо будет заполнить нулями
		}

		// копируем
		memcpy(pDest + destptr, m_pData.get() + ptr, sectorsize);
		ptr += sectorsize;

		if (bBrk) // всё, конец дорожки
		{
			if (ndd) // ещё и вообще хреновый конец
			{
				memset(pDest + destptr + sectorsize, 0, ndd);
				return false;
			}

			break;
		}

		// crc
		crc = getCrc(pCrcPtr, ptr - nCrcPtr);
		crcRd = 0xffff;

		if (ptr < m_nRawTrackSize)
		{
			crcRd = (m_pData[ptr++]) << 8;
		}

		if (ptr < m_nRawTrackSize)
		{
			crcRd |= (m_pData[ptr++]);
		}

		if (crc != crcRd)
		{
			TRACE0("FDD::неверный CRC данных.\n");
			return false; // несуществующий номер сектора
		}
	}

	return true;
}

uint16_t CFloppyDrive::getCrc(uint8_t *ptr, size_t len) const
{
	int crc = 0xffff;

	while (len--)
	{
		uint8_t val = *ptr++;
		crc ^= val << 8;

		for (int i = 8; i > 0; i--)
		{
			if ((crc <<= 1) & 0x10000)
			{
				crc ^= 0x1021;
			}
		}
	}

	return (crc & 0xffff);
}

LONGLONG CFloppyDrive::FDSeek(LONGLONG pos, UINT from)
{
	return m_File.Seek(pos, from);
}

UINT CFloppyDrive::FDRead(void *lpBuf, UINT nCount)
{
	return m_File.Read(lpBuf, nCount);
}

void CFloppyDrive::FDWrite(void *lpBuf, UINT nCount)
{
	m_File.Write(lpBuf, nCount);
}

void CFloppyDrive::MovePtr()
{
	m_nDataPtr += 2;

	if (m_nDataPtr >= m_nRawTrackSize)
	{
		m_nDataPtr = 0;
	}
}

void CFloppyDrive::WrData(uint16_t w)
{
	*(reinterpret_cast<uint16_t *>(&m_pData[m_nDataPtr])) = w;
	m_bTrackChanged = true;
}

uint16_t CFloppyDrive::RdData() const
{
	//return (m_pData[m_nDataPtr] << 8) | m_pData[m_nDataPtr + 1];
	uint16_t t = *(reinterpret_cast<uint16_t *>(&m_pData[m_nDataPtr]));
	return ((t & 0377) << 8) | ((t >> 8) & 0377);
}




//////////////////////////////////////////////////////////////////////////
// для эмуляции ВГ93, т.к. не получилось сходу приспособить класс CFloppyDrive

CFloppyVG93::CFloppyVG93()
{
	flp_set_hd(false);
	SetArrays();
}

CFloppyVG93::~CFloppyVG93()
{
}

bool CFloppyVG93::SetArrays()
{
	if (CFloppyDrive::SetArrays())
	{
		if (m_pField)
		{
			m_pField.reset();
		}

		m_pField = std::make_unique<uint8_t[]>(m_nRawTrackSize);

		if (m_pField)
		{
			memset(m_pField.get(), 0, m_nRawTrackSize);
			return true;
		}
	}

	return false;
}


void CFloppyVG93::flp_set_hd(bool hd)
{
	m_nRawTrackSize = hd ? FLOPPY_TRKLEN_HD : FLOPPY_TRKLEN_DD;
}

void CFloppyVG93::flpWr(uint8_t val)
{
	if (isAttached())
	{
		m_bTrackChanged = true;
		m_pData[m_nDataPtr] = val;
	}
}

uint8_t CFloppyVG93::flpRd() const
{
	if (!isAttached())
	{
		return 0xff;
	}

	return m_pData[m_nDataPtr];
}

void CFloppyVG93::flpStep(FLP_STEP dir)
{
	switch (dir)
	{
		case FLP_STEP::FLP_FORWARD:
			if (m_nDataTrack < m_nTracks)
			{
				PrepareTrack(m_nDataTrack + 1, m_nDataSide);
			}

			break;

		case FLP_STEP::FLP_BACK:
			if (m_nDataTrack > 0)
			{
				PrepareTrack(m_nDataTrack - 1, m_nDataSide);
			}

			break;
	}
}

bool CFloppyVG93::flpNext()
{
	bool res = false;

	if (isAttached())
	{
		m_nDataPtr++;

		if (m_nDataPtr >= m_nRawTrackSize)
		{
			m_nDataPtr = 0;
			res = true;
		}

		m_index = !!(m_nDataPtr < 4);      // ~90ms index pulse
		m_field = m_pField[m_nDataPtr] & 0x0f;
	}
	else
	{
		m_field = 0;
	}

	return res;
}

static std::array<uint8_t, 4> trk_mark = { 0xc1, 0xc1, 0xc1, 0xfc };
static std::array<uint8_t, 4> hd_mark = { 0xa1, 0xa1, 0xa1, 0xfe };
static std::array<uint8_t, 4> dat_mark = { 0xa1, 0xa1, 0xa1, 0xfb };


void CFloppyVG93::EncodeTrackData(uint8_t *pSrc)
{
	uint8_t *ptr = m_pData.get(); //raw буфер
	int slen = m_nSectorSizes[m_nSectorSize]; // корректный размер степени 2
	int spc = int(m_nRawTrackSize - 20) / m_nSectorsPerTrk; // размер raw данных под один сектор
	spc -= (72 + slen);     // межсекторное расстояние

	if (spc < 10)
	{
		// если слишком мало места между секторами остаётся - выход
		return;
	}

	memset(ptr, 0x4e, m_nRawTrackSize); // сперва заполним всё заполнителем.
	ptr += 12;  // запишем маркер дорожки
	memcpy(ptr, trk_mark.data(), 4); ptr += 4;

	// теперь для каждого сектора
	for (int sect = 1; sect <= m_nSectorsPerTrk; ++sect)
	{
		ptr += 10;
		memset(ptr, 0x00, 12); ptr += 12;
		uint8_t *stp = ptr;
		memcpy(ptr, hd_mark.data(), 4); ptr += 4;
		*(ptr++) = m_nDataTrack & 0xff;
		*(ptr++) = m_nDataSide & 1;
		*(ptr++) = sect & 0xff;
		*(ptr++) = m_nSectorSize & 0xff;
		uint16_t crc = getCrc(stp, ptr - stp);
		*(ptr++) = (crc >> 8) & 0xff;
		*(ptr++) = crc & 0xff;
		ptr += 22;
		memset(ptr, 0x00, 12); ptr += 12;
		stp = ptr;
		memcpy(ptr, dat_mark.data(), 4); ptr += 4;

		if (pSrc)
		{
			memcpy(ptr, pSrc, slen);
			ptr += slen;
			pSrc += slen;
		}
		else
		{
			memset(ptr, 0x00, slen);
			ptr += slen;
		}

		crc = getCrc(stp, ptr - stp);
		*(ptr++) = (crc >> 8) & 0xff;
		*(ptr++) = crc & 0xff;
		ptr += spc;
	}

	flpFillFields(false);
}


void CFloppyVG93::flpPrev()
{
	if (isAttached())
	{
		if (m_nDataPtr > 0)
		{
			m_nDataPtr--;
		}
		else
		{
			m_nDataPtr = m_nRawTrackSize - 1;
		}

		m_field = m_pField[m_nDataPtr] & 0x0f;
	}
	else
	{
		m_field = 0;
	}
}

// заполняем служебную область.

void CFloppyVG93::flpFillFields(bool flag)
{
	int bcnt = 0;
	uint8_t fld = 0;
	uint8_t *cpos = m_pData.get();
	uint8_t *bpos = cpos;
	uint8_t scn = 0;        // sector number (1+)
	uint8_t sct = 1;        // sector size code

	// сперва очистим массив
	for (int &i : m_map)
	{
		i = 0;
	}

	// теперь пройдёмся по всей raw дорожке
	for (size_t i = 0; i < m_nRawTrackSize; i++)
	{
		// поле: 1 - заголовок
		//      2 - данные сектора
		//      3 - данные скрытого сектора
		//      0xf - поле маркера
		//      0 - всё остальное
		m_pField[i] = fld;
		fld &= 0x0f;        // reset flags

		if (flag) // тут декодируем байты инициализации в маркеры
		{
			if ((fld == 0) || (fld == 0x0f))
			{
				if ((*bpos) == 0xf5)
				{
					*bpos = 0xa1;
				}

				if ((*bpos) == 0xf6)
				{
					*bpos = 0xc2;
				}
			}
		}

		if (bcnt > 0)
		{
			bcnt--;

			if (bcnt == 0)
			{
				if (fld < 4)
				{
					if (flag) // и рассчитываем КС
					{
						cpos -= 3;      // including a1,a1,a1
						uint16_t crc = getCrc(cpos, bpos - cpos + 1);
						*(bpos + 1) = ((crc & 0xff00) >> 8);
						*(bpos + 2) = (crc & 0xff);
					}

					fld = 4;
					bcnt = 2;
				}
				else
				{
					fld = 0;
				}
			}
		}
		else
		{
			// TODO: find A1 here, then skip until !A1, this m_pData will be marker
			if (m_pData[i] == 0xa1)
			{
				fld = 0x0f;
			}
			else
			{
				if (fld == 0x0f)
				{
					switch (m_pData[i] & 0xfe)
					{
						case 0xfe:          // fe/ff : IDAM, head
							cpos = bpos;
							fld = 0x01;
							bcnt = 4;
							scn = m_pData[i + 3];
							sct = m_pData[i + 4];
							break;

						// case 0xfc:           // fc/fd : IAM, index marker
						//  break
						case 0xfa:          // fa/fb : DAM, data
							cpos = bpos;
							fld = 0x02;
							bcnt = (128 << (sct & 3));

							if (scn > 0)
							{
								m_map[scn] = int(i) + 1;
								scn = 0;
							}

							break;

						case 0xf8:          // f8/f9 : DDAM, deleted data
							cpos = bpos;
							fld = 0x03;
							bcnt = (128 << (sct & 3));

							if (scn > 0)
							{
								m_map[scn] = int(i) + 1;
								scn = 0;
							}

							break;

						default:
							fld = 0;
							break;
					}
				}
			}
		}

		bpos++;
	}

#if (_DEBUG && FDD_DUMP_TRACK)
	FILE *f = fopen("encoded_track_field.dat", "wb");

	if (f)
	{
		fwrite(m_pField.get(), 1, m_nRawTrackSize, f);
		fclose(f);
	}

#endif // _DEBUG
}


