diff --git a/DiskImage.cpp b/DiskImage.cpp new file mode 100644 index 0000000..fb6b3ca --- /dev/null +++ b/DiskImage.cpp @@ -0,0 +1,3092 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "DiskImage.h" +#include "file_io.h" + +#define ERR_OPEN "Error: can't open source file" +#define ERR_GETLEN "Error: can't get file length!" +#define ERR_NOMEM "Error: no memory!" +#define ERR_FORMAT "Error: incorrect format" +#define ERR_FILEVER "Error: unknown version of" +#define ERR_FILECRC "Error: bad file CRC" +#define ERR_CANTWRITE "Error: write to file failed!" +#define ERR_UNKFORMAT "Error: Unknown format of source file!" +#define ERR_BADCREATE "Допустимо создавать только TRD, SCL и FDI файлы!" +#define ERR_MANYCYLS "Error: out of 256 cylinders in opening source file!" +#define ERR_MANYSIDS "Error: out of 2 surfaces in opening source file!" +#define ERR_IMPOSSIBLE "Error: impossible format in opening source file!" +#define ERR_CORRUPT "Error: source file is corrupted!" +#define ERR_TD0DOSALLOC "Error: files TD0 in 'DOS Allocated sectors were copied' format not supported!" + +#define ERR_BADOPENED "Error: file opened in incorrect mode (write only?)" + +#define STR_CREATEDISKNAME "ZXMAK " + +char errsect[] = "ERROR: THIS SECTOR NOT FOUND OR IN NON TR-DOS FORMAT!"; + +char fdicomment[] = "\r\nCreated by TRX2X converter\r\n(C)2002 Alex Makeev\r\nhttp://zxmak.chat.ru/\r\n\r\n"; + +unsigned char sbootimage[4]; + +unsigned char sbootdir[16] = { + 0x62, 0x6F, 0x6F, 0x74, 0x20, 0x20, 0x20, 0x20, 0x42, 0xFC, 0x06, 0xFC, 0x06, 0x07, 0x09, 0x00 +}; + + +long CalcCRC32(long CRC, unsigned char Symbol) +{ + long temp; + CRC ^= -1l ^ Symbol; + for (int k = 8; k--;) + { + temp = -(CRC & 1), CRC >>= 1, CRC ^= 0xEDB88320ul & temp; + } + CRC ^= -1l; + return CRC; +} + +long filelength(int hfile) +{ + long ret = lseek(hfile, 0, SEEK_END); + lseek(hfile, 0, SEEK_SET); + return ret; +} + +//---------------------------------------------------------------------------- +TDiskImage::TDiskImage() +{ + AddBOOT = false; + + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + FTracksPtr[t][s][0] = NULL; + FTracksPtr[t][s][1] = NULL; + } + + DiskPresent = false; + ReadOnly = true; + Changed = false; + FType = DIT_UNK; + MaxTrack = 81; + MaxSide = 0x01; +} +//----------------------------------------------------------------------------- +TDiskImage::~TDiskImage() +{ + FlushImage(); + ReadOnly = true; + DiskPresent = false; + Changed = false; + FType = DIT_UNK; + + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } +} +//----------------------------------------------------------------------------- +unsigned short TDiskImage::MakeVGCRC(unsigned char *data, unsigned long length) +{ + unsigned short CRC = 0xFFFF; + for (unsigned int i = 0; i < length; i++) + { + CRC ^= data[i] << 8; + for (unsigned int j = 0; j < 8; j++) + { + if (CRC & 0x8000) CRC = (CRC << 1) ^ 0x1021; + else CRC <<= 1; + } + } + return CRC; // H<-->L !!! +} +//----------------------------------------------------------------------------- +void TDiskImage::ApplySectorCRC(VGFIND_SECTOR vgfs) +{ + unsigned char *TrackPtr = vgfs.vgfa.TrackPointer; + unsigned int TrackLen = vgfs.vgfa.TrackLength; + unsigned int len = vgfs.OffsetEndSector - vgfs.MarkedOffsetSector; + if (vgfs.OffsetEndSector < vgfs.MarkedOffsetSector) + len = (TrackLen - vgfs.MarkedOffsetSector) + vgfs.OffsetEndSector; + + unsigned int off1 = vgfs.MarkedOffsetSector; + unsigned int len1 = TrackLen - vgfs.MarkedOffsetSector; + if (len1 > len) len1 = len; + unsigned int off2 = 0; + unsigned int len2 = 0; + if (len1 < len) len2 = len - len1; + + unsigned int i; + unsigned short CRC = 0xFFFF; + for (i = 0; i < len1; i++) + { + CRC ^= TrackPtr[off1 + i] << 8; + for (unsigned int j = 0; j < 8; j++) + { + if (CRC & 0x8000) CRC = (CRC << 1) ^ 0x1021; + else CRC <<= 1; + } + } + for (i = 0; i < len2; i++) + { + CRC ^= TrackPtr[off2 + i] << 8; + for (unsigned int j = 0; j < 8; j++) + { + if (CRC & 0x8000) CRC = (CRC << 1) ^ 0x1021; + else CRC <<= 1; + } + } + unsigned int crcoff = (off1 + len1) % TrackLen; + if (len2) crcoff = (off2 + len2) % TrackLen; + + TrackPtr[crcoff] = (unsigned char)(CRC >> 8); + TrackPtr[(crcoff + 1) % TrackLen] = (unsigned char)(CRC & 0xFF); +} +//----------------------------------------------------------------------------- +// +// DANGER! CRC checking not prepared for track length overflow! +// +bool TDiskImage::FindADMark(unsigned char CYL, unsigned char SIDE, + unsigned int FromOffset, + VGFIND_ADM *vgfa) +{ + vgfa->TrackPointer = NULL; + vgfa->ClkPointer = NULL; + vgfa->TrackLength = 0; + vgfa->ADMPointer = NULL; + vgfa->ADMLength = 0; + vgfa->FoundADM = false; + vgfa->CRCOK = false; + + if ((!DiskPresent) | + ((CYL > MaxTrack) || (SIDE > MaxSide)) | + ((!FTracksPtr[CYL][SIDE][0]) || (!FTracksPtr[CYL][SIDE][1]))) + { + return false; // ERROR: disk not ready + } + + unsigned char *track = vgfa->TrackPointer = FTracksPtr[CYL][SIDE][0]; + unsigned char *clks = vgfa->ClkPointer = FTracksPtr[CYL][SIDE][1]; + unsigned int tlen = vgfa->TrackLength = FTrackLength[CYL][SIDE]; + + unsigned int off, rc; + + unsigned int pos = FromOffset; + for (; pos < tlen + FromOffset; pos++) + { + off = pos%tlen; + if ((track[off] == 0xA1) && (clks[off])) // fnd Mark + { + off = (off + 1) % tlen; + + rc = tlen; + while ((track[off] == 0xA1) && (clks[off])) // repeat Mark + { + if (!rc) return false; // ERROR: MFM marks all disk + off = (off + 1) % tlen; + rc--; + } + + if (track[off] != 0xFE) continue; + + off = (off + 1) % tlen; + + vgfa->FoundADM = true; + vgfa->MarkedOffsetADM = pos%tlen; + vgfa->OffsetADM = off; + vgfa->OffsetEndADM = (off + 6) % tlen; + vgfa->ADMLength = 6; + vgfa->ADMPointer = track + off; + + unsigned short crc = MakeVGCRC(track + (pos%tlen), (off - (pos%tlen)) + 4); + + vgfa->CRCOK = (track[(off + 4) % tlen] == (crc >> 8)) && (track[(off + 5) % tlen] == (crc & 0xFF)); + + return true; + } + } + + return false; +} +//----------------------------------------------------------------------------- +// +// DANGER! CRC checking not prepared for track length overflow! +// +bool TDiskImage::FindSector(unsigned char CYL, unsigned char SIDE, + unsigned char SECT, + VGFIND_SECTOR *vgfs, unsigned int FromOffset) +{ + vgfs->SectorPointer = NULL; + vgfs->SectorLength = 0; + vgfs->FoundDATA = false; + vgfs->CRCOK = false; + + if ((!DiskPresent) | + ((CYL > MaxTrack) || (SIDE > MaxSide)) | + ((!FTracksPtr[CYL][SIDE][0]) || (!FTracksPtr[CYL][SIDE][1]))) + { + vgfs->vgfa.TrackPointer = NULL; + vgfs->vgfa.ClkPointer = NULL; + vgfs->vgfa.TrackLength = 0; + vgfs->vgfa.ADMPointer = NULL; + vgfs->vgfa.ADMLength = 0; + vgfs->vgfa.FoundADM = false; + vgfs->vgfa.CRCOK = false; + return false; // ERROR: disk not ready + } + + unsigned int TrackOffset = FromOffset; + + bool FirstFind = true; + unsigned int FirstPos; + + // Поиск адресной метки требуемого сектора... + bool ADFOUND = false; + for (;;) + { + if (!FindADMark(CYL, SIDE, TrackOffset, &(vgfs->vgfa))) + return false; // ERROR: No ADMARK found on track + + if (vgfs->vgfa.TrackPointer[(vgfs->vgfa.OffsetADM + 2) % vgfs->vgfa.TrackLength] == SECT) + { + ADFOUND = true; + break; + } + + if (!FirstFind) + { + if (vgfs->vgfa.OffsetEndADM == FirstPos) break; + } + else + { + FirstPos = vgfs->vgfa.OffsetEndADM; + FirstFind = false; + } + + TrackOffset = vgfs->vgfa.OffsetEndADM; + }; + + if (!ADFOUND) return false; + + // ADRMARK нужного найден, поиск массива данных... + + unsigned char *track = vgfs->vgfa.TrackPointer; + unsigned char *clks = vgfs->vgfa.ClkPointer; + unsigned int tlen = vgfs->vgfa.TrackLength; + + unsigned int pos = vgfs->vgfa.OffsetEndADM; + + unsigned int off, rc; + + for (; pos < tlen * 2; pos++) + { + off = pos%tlen; + if ((track[off] == 0xA1) && (clks[off])) // fnd Mark + { + off = (off + 1) % tlen; + + rc = tlen; + while ((track[off] == 0xA1) && (clks[off])) // repeat Mark + { + if (!rc) return false; // ERROR: MFM marks all disk + off = (off + 1) % tlen; + rc--; + } + + if ((track[off] < 0xF8) || (track[off] > 0xFB)) + { + break; // ERROR: data array not found + } + vgfs->DataMarker = track[off]; + + off = (off + 1) % tlen; + + vgfs->FoundDATA = true; + + unsigned char SL = vgfs->vgfa.TrackPointer[(vgfs->vgfa.OffsetADM + 3) % vgfs->vgfa.TrackLength]; + vgfs->SectorLength = 128; + if (SL) vgfs->SectorLength <<= SL; + vgfs->SectorPointer = track + off; + + vgfs->MarkedOffsetSector = pos%tlen; + vgfs->OffsetSector = off; + vgfs->OffsetEndSector = (off + vgfs->SectorLength) % tlen; + + unsigned short crc = MakeVGCRC(track + (pos%tlen), (off - (pos%tlen)) + vgfs->SectorLength); + vgfs->CRCOK = (track[(off + vgfs->SectorLength) % tlen] == (crc >> 8)) && (track[(off + vgfs->SectorLength + 1) % tlen] == (crc & 0xFF)); + + return true; // OK read + } + } + + return false; +} +//----------------------------------------------------------------------------- +bool TDiskImage::FindTrack(unsigned char CYL, unsigned char SIDE, VGFIND_TRACK *vgft) +{ + vgft->FoundTrack = false; + vgft->TrackPointer = NULL; + vgft->ClkPointer = NULL; + vgft->TrackLength = 0; + + if ((!DiskPresent) | + ((CYL > MaxTrack) || (SIDE > MaxSide)) | + ((!FTracksPtr[CYL][SIDE][0]) || (!FTracksPtr[CYL][SIDE][1]))) + { + return false; // ERROR: disk not ready + } + + vgft->TrackPointer = FTracksPtr[CYL][SIDE][0]; + vgft->ClkPointer = FTracksPtr[CYL][SIDE][1]; + vgft->TrackLength = FTrackLength[CYL][SIDE]; + vgft->FoundTrack = true; + return true; +} + +//----------------------------------------------------------------------------- + +void TDiskImage::FlushImage() +{ + if (ReadOnly) return; + if (!Changed) return; + if (FType == DIT_HOB) return; + + int hfile = open((char*)FFileName, O_CREAT | O_RDWR | O_TRUNC); + if (hfile < 0) + { + ShowError(ERR_CANTWRITE); + return; + } + + if (FType == DIT_TRD) writeTRD(hfile); + if (FType == DIT_SCL) writeSCL(hfile); + if (FType == DIT_FDI) writeFDI(hfile); + if (FType == DIT_UDI) writeUDI(hfile); + if (FType == DIT_TD0) writeTD0(hfile); + if (FType == DIT_FDD) writeFDD(hfile); + + close(hfile); + Changed = false; +} +//----------------------------------------------------------------------------- +void TDiskImage::Open(const char *filename, bool ROnly) +{ + FlushImage(); + + const char *ext = ""; + if (strlen(filename) > 4) ext = filename + strlen(filename) - 4; + + TDiskImageType typ = DIT_UNK; + if (!strcasecmp(ext, ".TRD")) typ = DIT_TRD; + if (!strcasecmp(ext, ".SCL")) typ = DIT_SCL; + if (!strcasecmp(ext, ".FDI")) typ = DIT_FDI; + if (!strcasecmp(ext, ".UDI")) typ = DIT_UDI; + if (!strcasecmp(ext, ".TD0")) typ = DIT_TD0; + if (!strcasecmp(ext, ".FDD")) typ = DIT_FDD; + if (!memcmp(ext + 1, ".$", 2)) typ = DIT_HOB; + if (!memcmp(ext + 1, ".!", 2)) typ = DIT_HOB; + + if (!((FType == DIT_HOB) && (typ == DIT_HOB))) // if not hobeta clear disk... + { + ReadOnly = true; + DiskPresent = false; + Changed = false; + FType = DIT_UNK; + + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } + } + + if (typ == DIT_UNK) + { + ShowError(ERR_UNKFORMAT); + return; + } + strcpy((char*)FFileName, filename); + FType = typ; + + int hfile = open(filename, O_RDONLY); + + if (hfile < 0) + { + char sbuf[8192]; + sprintf(sbuf, ERR_OPEN" %s", filename); + ShowError(sbuf); + return; + } + + if (typ == DIT_TRD) readTRD(hfile, ROnly); + if (typ == DIT_SCL) readSCL(hfile, ROnly); + if (typ == DIT_FDI) readFDI(hfile, ROnly); + if (typ == DIT_UDI) readUDI(hfile, ROnly); + if (typ == DIT_TD0) readTD0(hfile, ROnly); + if (typ == DIT_FDD) readFDD(hfile, ROnly); + if (typ == DIT_HOB) readHOB(hfile); + + close(hfile); +} +//----------------------------------------------------------------------------- +void TDiskImage::formatTRDOS(unsigned int Tcount, unsigned int Scount) +{ + MaxTrack = Tcount - 1; + MaxSide = Scount - 1; + + unsigned short TotalSecs = Tcount*Scount * 16 - 16; + + // форматирование нового диска под TR-DOS (16 x 256bytes sector per track)... + unsigned int ptrcrc; + unsigned int r; + unsigned short vgcrc; + for (unsigned int trk = 0; trk <= unsigned(MaxTrack); trk++) + for (unsigned int side = 0; side <= unsigned(MaxSide); side++) + { + FTrackLength[trk][side] = 6250; + + FTracksPtr[trk][side][0] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // trk img + FTracksPtr[trk][side][1] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // clk img + + unsigned int tptr = 0; + for (int sec = 0; sec < 16; sec++) + { + for (r = 0; r < 10; r++) // Первый пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < 12; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + ptrcrc = tptr; + for (r = 0; r < 3; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + FTracksPtr[trk][side][0][tptr] = 0xFE; // Метка "Адрес" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + FTracksPtr[trk][side][0][tptr] = (unsigned char)trk; // cyl + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)0x00; // head (TR always 0) + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(sec + 1); // secN + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)0x01; // len=256b + FTracksPtr[trk][side][1][tptr++] = 0x00; + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < 22; r++) // Второй пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < 12; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + ptrcrc = tptr; + for (r = 0; r < 3; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + FTracksPtr[trk][side][0][tptr] = 0xFB; // Метка "Данные" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < 256; r++) // сектор 256байт + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + if ((trk == 0) && (side == 0) && (sec == 8)) // make TR-DOS id + { + int ssec = tptr - 256; + FTracksPtr[trk][side][0][ssec + 0xE1] = 0x00; // first free SECT + FTracksPtr[trk][side][0][ssec + 0xE2] = 0x01; // first free TRACK + FTracksPtr[trk][side][0][ssec + 0xE3] = 0x16; // 80trk DS + FTracksPtr[trk][side][0][ssec + 0xE4] = 0x00; // file count + *(unsigned short*)(FTracksPtr[trk][side][0] + ssec + 0xE5) + = TotalSecs; // free SECS count + FTracksPtr[trk][side][0][ssec + 0xE7] = 0x10; // TR-DOS id + FTracksPtr[trk][side][0][ssec + 0xF4] = 0x00; // deleted file count + + memcpy(FTracksPtr[trk][side][0] + ssec + 0xF5, + STR_CREATEDISKNAME" ", 8); // disk name + FTracksPtr[trk][side][0][ssec + 0xFD] = 0x00; // zero + FTracksPtr[trk][side][0][ssec + 0xFE] = 0x00; // zero + FTracksPtr[trk][side][0][ssec + 0xFF] = 0x00; // zero + } + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < 60; r++) // Третий пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + for (int eoftrk = tptr; eoftrk < 6250; eoftrk++) + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } +} +//----------------------------------------------------------------------------- +void TDiskImage::readUDI(int hfile, bool ronly) +{ + long fsize = filelength(hfile); + if (fsize < 0) + { + ShowError(ERR_GETLEN); + return; + } + + unsigned char *ptr = (unsigned char*)new char[fsize + 1024 * 2048]; + if (!ptr) + { + ShowError(ERR_NOMEM); + return; + } + + unsigned long rsize = read(hfile, ptr, fsize + 1024); + if (rsize < 16 + 4) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + if (memcmp(ptr, "UDI!", 4) != 0) + { + delete ptr; + ShowError(ERR_FORMAT" UDI!"); + return; + } + + UDI_HEADER *udi_hdr = (UDI_HEADER*)(ptr); + + if ((udi_hdr->Version != 0x00) || (udi_hdr->_zero != 0x00) || (udi_hdr->ExtHdrLength != 0)) + { + delete ptr; + ShowError(ERR_FILEVER" UDI!"); + return; + } + if (rsize != (udi_hdr->UnpackedLength + 4)) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + MaxTrack = udi_hdr->MaxCylinder; + MaxSide = udi_hdr->MaxSide; + + + // checking for corrupt... + unsigned int udiOFF = 0x10; + + unsigned int trk, side; + + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + unsigned char frmt = ptr[udiOFF++]; + if (rsize < udiOFF + 4) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + if (frmt) + { + udiOFF += *((unsigned long*)(ptr + udiOFF)); + udiOFF += 4; + continue; + } + + unsigned ccctlen = *((unsigned short*)(ptr + udiOFF)); + udiOFF += ccctlen; + udiOFF += 2; + if (rsize < udiOFF + 4) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + udiOFF += ccctlen / 8 + ((ccctlen - (ccctlen / 8) * 8) ? 1 : 0); + if (rsize < udiOFF + 4) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + } + + + udiOFF = 0x10; + + unsigned int trklen; + + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + if (udiOFF >= rsize) break; + + if (ptr[udiOFF++] != 0) // non MFM track? + { + FTrackLength[trk][side] = 6250; + // make unformatted track... + FTracksPtr[trk][side][0] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // trk img + FTracksPtr[trk][side][1] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // clk img + for (unsigned ij = 0; ij < 6250; ij++) + { + FTracksPtr[trk][side][0][ij] = 0x00; + FTracksPtr[trk][side][1][ij] = 0x00; + } + + udiOFF += *((unsigned long*)(ptr + udiOFF)); + udiOFF += 4; + continue; + } + trklen = *((unsigned short*)(ptr + udiOFF)); + udiOFF += 2; + FTrackLength[trk][side] = trklen; + + // make unformatted track... + FTracksPtr[trk][side][0] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // trk img + FTracksPtr[trk][side][1] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // clk img + for (unsigned ij = 0; ij < FTrackLength[trk][side]; ij++) + { + FTracksPtr[trk][side][0][ij] = 0x00; + FTracksPtr[trk][side][1][ij] = 0x00; + } + + memcpy(FTracksPtr[trk][side][0], ptr + udiOFF, FTrackLength[trk][side]); + udiOFF += trklen; + + unsigned int MFMinfoLen = trklen / 8 + ((trklen - (trklen / 8) * 8) ? 1 : 0); + + unsigned char mask; + for (unsigned i = 0; i < MFMinfoLen; i++) + { + mask = 0x01; + for (int j = 0; j < 8; j++) + { + if (ptr[udiOFF] & mask) FTracksPtr[trk][side][1][i * 8 + j] = 0xFF; + else FTracksPtr[trk][side][1][i * 8 + j] = 0x00; + mask <<= 1; + } + udiOFF++; + } + } + long CRC = -1l; + for (unsigned int i = 0; i < udiOFF; i++) CRC = CalcCRC32(CRC, ptr[i]); + + + if (udiOFF < rsize) + if (*((long*)(ptr + udiOFF)) != CRC) + ShowError(ERR_FILECRC" UDI!"); + + delete ptr; + ReadOnly = ronly; + FType = DIT_UDI; + DiskPresent = true; +} +//----------------------------------------------------------------------------- +void TDiskImage::writeUDI(int hfile) +{ + long CRC = -1l; + unsigned int i; + + UDI_HEADER hudi; + memcpy(hudi.ID, "UDI!", 4); + hudi.UnpackedLength = 0; + hudi.Version = 0x00; + hudi.MaxCylinder = MaxTrack; + hudi.MaxSide = MaxSide; + hudi._zero = 0x00; + hudi.ExtHdrLength = 0; + + lseek(hfile, 0, SEEK_SET); + write(hfile, &hudi, 16); + lseek(hfile, 0, SEEK_SET); + char testbuf[1024]; + long trs = read(hfile, testbuf, 16); + if ((trs < 0) || (memcmp(testbuf, &hudi, 16) != 0)) + { + ShowError(ERR_BADOPENED); + return; + } + + + unsigned char valB; + unsigned short valS; + unsigned char clkbuf[65536]; + + for (unsigned int trk = 0; trk <= unsigned(MaxTrack); trk++) + for (unsigned int side = 0; side <= unsigned(MaxSide); side++) + { + valB = 0x00; + write(hfile, &valB, 1); + valS = FTrackLength[trk][side]; + write(hfile, &valS, 2); + write(hfile, FTracksPtr[trk][side][0], valS); + + unsigned int cptr = 0; + unsigned char mask; + for (i = 0; i < unsigned(valS / 8 + ((valS - (valS / 8) * 8) ? 1 : 0)); i++) + { + clkbuf[cptr] = 0x00; + mask = 0x01; + for (int j = 0; j < 8; j++) + { + + if (FTracksPtr[trk][side][1][i * 8 + j]) clkbuf[cptr] |= mask; + mask <<= 1; + } + cptr++; + } + + write(hfile, clkbuf, (valS / 8 + ((valS - (valS / 8) * 8) ? 1 : 0))); + } + + long len = filelength(hfile); + lseek(hfile, 0, SEEK_SET); + char *cbuf = new char[len + 0x10000]; + UDI_HEADER *newudi = (UDI_HEADER*)cbuf; + read(hfile, cbuf, len); + newudi->UnpackedLength = len; + + CRC = -1l; + for (i = 0; i < len; i++) CRC = CalcCRC32(CRC, cbuf[i]); + + lseek(hfile, 0, SEEK_SET); + write(hfile, cbuf, len); + write(hfile, &CRC, 4); +} +//----------------------------------------------------------------------------- +void TDiskImage::readTRD(int hfile, bool readonly) +{ + long fsize = filelength(hfile); + if (fsize < 0) + { + ShowError(ERR_GETLEN); + return; + } + + unsigned char *ptr = (unsigned char*)new char[fsize + 1024 * 2048]; + if (!ptr) + { + ShowError(ERR_NOMEM); + return; + } + + unsigned long rsize = read(hfile, ptr, fsize); + + if (!rsize) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + if (rsize % (256 * 16 * 2)) + { + delete ptr; + ShowError(ERR_UNKFORMAT); + return; + } + MaxSide = 1; + MaxTrack = (rsize / (256 * 16 * 2)) - 1; + + + // форматирование нового диска под TR-DOS... + + unsigned short vgcrc; + for (unsigned int trk = 0; trk <= unsigned(MaxTrack); trk++) + for (unsigned int side = 0; side <= unsigned(MaxSide); side++) + { + FTrackLength[trk][side] = 6250; + + FTracksPtr[trk][side][0] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // trk img + FTracksPtr[trk][side][1] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // clk img + + + unsigned int r; + unsigned int tptr = 0; + unsigned int ptrcrc; + + for (int sec = 0; sec < 16; sec++) + { + for (r = 0; r < 10; r++) // Первый пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < 12; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + ptrcrc = tptr; + for (r = 0; r < 3; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + FTracksPtr[trk][side][0][tptr] = 0xFE; // Метка "Адрес" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + FTracksPtr[trk][side][0][tptr] = (unsigned char)trk; // cyl + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)0x00; // head (TR always 0) + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(sec + 1); // secN + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)0x01; // len=256b + FTracksPtr[trk][side][1][tptr++] = 0x00; + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < 22; r++) // Второй пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < 12; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + ptrcrc = tptr; + for (r = 0; r < 3; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + FTracksPtr[trk][side][0][tptr] = 0xFB; // Метка "Данные" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < 256; r++) // сектор 256байт + { + FTracksPtr[trk][side][0][tptr] = ptr[(trk * 2 + side) * 4096 + sec * 256 + r]; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < 60; r++) // Третий пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + for (int eoftrk = tptr; eoftrk < 6250; eoftrk++) + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + + delete ptr; + ReadOnly = readonly; + FType = DIT_TRD; + DiskPresent = true; +} + +void TDiskImage::writeTRD(int hfile) +{ + VGFIND_SECTOR vgfs; + + // prepare nullbuf... + unsigned char nullbuf[256]; + for (int i = 0; i < 256; i++) nullbuf[i] = '*'; + memcpy(nullbuf, errsect, sizeof(errsect)); + + for (unsigned int trk = 0; trk <= unsigned(MaxTrack); trk++) + for (unsigned int side = 0; side <= unsigned(MaxSide); side++) + for (unsigned int sec = 0; sec < 16; sec++) + { + if (FindSector(trk, side, sec + 1, &vgfs)) + { + write(hfile, vgfs.SectorPointer, 256); + if ((!vgfs.CRCOK) || (!vgfs.vgfa.CRCOK)) printf("Warning: sector %d on track %d, side %d with BAD CRC!\n", sec + 1, trk, side); + if (vgfs.SectorLength != 256) printf("Warning: sector %d on track %d, side %d is non 256 bytes!\n", sec + 1, trk, side); + } + else + { + write(hfile, nullbuf, 256); + printf("DANGER! Sector %d on track %d, side %d not found!\n", sec + 1, trk, side); + } + } +} + +//----------------------------------------------------------------------------- +void TDiskImage::readFDI(int hfile, bool readonly) +{ + long fsize = filelength(hfile); + if (fsize < 0) + { + ShowError(ERR_GETLEN); + return; + } + + unsigned char *ptr = (unsigned char*)new char[fsize + 1024 * 2048]; + if (!ptr) + { + ShowError(ERR_NOMEM); + return; + } + + unsigned long rsize = read(hfile, ptr, fsize); + if (rsize < 14) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + if (memcmp(ptr, "FDI", 3) != 0) + { + delete ptr; + ShowError(ERR_FORMAT" FDI!"); + return; + } + + // ========================================== + // ********** Analyse FDI header ************... + // ------------------------------------------ + unsigned short *fdihead = (unsigned short*)(ptr + 4); + unsigned int fdiCylCount = fdihead[0]; // +4 + unsigned int fdiSideCount = fdihead[1]; // +6 + // unsigned int fdiOFFtext = fdihead[2]; // +8 + unsigned int fdiOFFdata = fdihead[3]; // +A + unsigned int fdiSIZEext = fdihead[4]; // +C + + if ((fdiCylCount > 256) || (fdiCylCount == 0)) + { + delete ptr; + ShowError(ERR_MANYCYLS); + return; + } + if ((fdiSideCount > 256) || (fdiSideCount == 0)) + { + delete ptr; + ShowError(ERR_MANYSIDS); + return; + } + + MaxTrack = (unsigned char)(fdiCylCount - 1); + MaxSide = (unsigned char)(fdiSideCount - 1); + + if (rsize < (0x0E + fdiSIZEext + (unsigned(MaxTrack) + 1)*(unsigned(MaxSide) + 1) * 7)) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + struct FDISECINFO + { + unsigned char ADAM[5]; + unsigned int SectorOffset; // относит DataOffset + }; + struct FDITRACKHDR + { + unsigned int DataOffset; // относит начала файла + unsigned int SectorCount; + FDISECINFO SectorsInfo[256]; + }; + FDITRACKHDR *tracksinfo = new FDITRACKHDR[(unsigned(MaxTrack) + 1)*(unsigned(MaxSide) + 1)]; + + unsigned int fdiOFF = 0x0E + fdiSIZEext; + + unsigned int trk, side; + // Анализ области заголовков треков... + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + if (rsize < fdiOFF) + { + delete tracksinfo; + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + tracksinfo[trk*(MaxSide + 1) + side].DataOffset = *((unsigned long*)(ptr + fdiOFF)); + fdiOFF += 4; + + if (rsize < fdiOFFdata + tracksinfo[trk*(MaxSide + 1) + side].DataOffset) + { + delete tracksinfo; + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + fdiOFF += 2; // "Всегда содержит 0 (резерв для модернизации)" + + tracksinfo[trk*(MaxSide + 1) + side].SectorCount = unsigned(ptr[fdiOFF++]); + + for (unsigned isec = 0; isec < tracksinfo[trk*(MaxSide + 1) + side].SectorCount; isec++) + { + memcpy(tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[isec].ADAM, ptr + fdiOFF, 5); + fdiOFF += 5; + tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[isec].SectorOffset = unsigned(*((unsigned short*)(ptr + fdiOFF))); + fdiOFF += 2; + + if (rsize < fdiOFFdata + tracksinfo[trk*(MaxSide + 1) + side].DataOffset + tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[isec].SectorOffset) + { + delete tracksinfo; + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + } + } + + // форматирование нового диска и размещение FDI секторов... + unsigned int ptrcrc; + unsigned int r; + unsigned short vgcrc; + unsigned int trkdatalen; + unsigned SecCount; + unsigned SL; + + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + FTrackLength[trk][side] = 6250; + + // make unformatted track... + FTracksPtr[trk][side][0] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // trk img + FTracksPtr[trk][side][1] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // clk img + for (unsigned ij = 0; ij < 6250; ij++) + { + FTracksPtr[trk][side][0][ij] = 0x00; + FTracksPtr[trk][side][1][ij] = 0x00; + } + + SecCount = tracksinfo[trk*(MaxSide + 1) + side].SectorCount; + + // Вычисляем необходимое число байт под данные: + trkdatalen = 0; + for (unsigned int ilsec = 0; ilsec < SecCount; ilsec++) + { + trkdatalen += 2 + 6; // for marks: 0xA1, 0xFE, 6bytes + SL = unsigned(tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[ilsec].ADAM[3]); + if (!SL) SL = 128; + else SL = 128 << SL; + + if (tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[ilsec].ADAM[4] & 0x40) + SL = 0; // заголовок без массива данных + else + trkdatalen += 4; // for data header/crc: 0xA1, 0xFB, ...,2bytes + + trkdatalen += SL; + } + + if (trkdatalen + SecCount*(3 + 2) > 6250) // 3x4E & 2x00 per sec checking + { + delete tracksinfo; + delete ptr; + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } + ShowError(ERR_IMPOSSIBLE); + return; + } + + unsigned int FreeSpace = 6250 - (trkdatalen + SecCount*(3 + 2)); + + unsigned int SynchroPulseLen = 1; // 1 уже учтен в trkdatalen... + unsigned int FirstSpaceLen = 1; + unsigned int SecondSpaceLen = 1; + unsigned int ThirdSpaceLen = 1; + unsigned int SynchroSpaceLen = 1; + FreeSpace -= FirstSpaceLen + SecondSpaceLen + ThirdSpaceLen + SynchroSpaceLen; + + // Распределяем длины пробелов и синхропромежутка: + while (FreeSpace > 0) + { + if (FreeSpace >= (SecCount * 2)) + if (SynchroSpaceLen < 12) { SynchroSpaceLen++; FreeSpace -= SecCount * 2; } // Synchro for ADM & DATA + if (FreeSpace < SecCount) break; + + if (FirstSpaceLen < 10) { FirstSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + if (SecondSpaceLen < 22) { SecondSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + if (ThirdSpaceLen < 60) { ThirdSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + + if ((SynchroSpaceLen >= 12) && (FirstSpaceLen >= 10) && (SecondSpaceLen >= 22) && (ThirdSpaceLen >= 60)) break; + }; + // по возможности делаем три синхроимпульса... + if (FreeSpace >(SecCount * 2) + 10) { SynchroPulseLen++; FreeSpace -= SecCount; } + if (FreeSpace >(SecCount * 2) + 9) SynchroPulseLen++; + + // Форматируем дорожку... + + unsigned int tptr = 0; + for (unsigned sec = 0; sec < SecCount; sec++) + { + for (r = 0; r < FirstSpaceLen; r++) // Первый пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < SynchroSpaceLen; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + ptrcrc = tptr; + for (r = 0; r < SynchroPulseLen; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + FTracksPtr[trk][side][0][tptr] = 0xFE; // Метка "Адрес" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + FTracksPtr[trk][side][0][tptr] = tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[sec].ADAM[0]; // cyl + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[sec].ADAM[1]; // head + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[sec].ADAM[2]; // secN + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[sec].ADAM[3]; // len code + FTracksPtr[trk][side][1][tptr++] = 0x00; + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < SecondSpaceLen; r++) // Второй пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < SynchroSpaceLen; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + + unsigned char fdiSectorFlags = tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[sec].ADAM[4]; + + // !!!!!!!!! + // !WARNING! this feature of FDI format is NOT FULL DOCUMENTED!!! + // !!!!!!!!! + // + // Flags::bit6 - Возможно, 1 в данном разряде + // будет обозначать адресный маркер без области данных. + // + + if (!(fdiSectorFlags & 0x40)) // oh-oh, data area not present... ;-) + { + ptrcrc = tptr; + for (r = 0; r < SynchroPulseLen; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + + if (fdiSectorFlags & 0x80) + FTracksPtr[trk][side][0][tptr] = 0xF8; // Метка "Удаленные данные" + else + FTracksPtr[trk][side][0][tptr] = 0xFB; // Метка "Данные" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + + SL = unsigned(tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[sec].ADAM[3]); + if (!SL) SL = 128; + else SL = 128 << SL; + + unsigned int secDATAOFF = fdiOFFdata + tracksinfo[trk*(MaxSide + 1) + side].DataOffset + tracksinfo[trk*(MaxSide + 1) + side].SectorsInfo[sec].SectorOffset; + + for (r = 0; r < SL; r++) // сектор SL байт + { + FTracksPtr[trk][side][0][tptr] = ptr[secDATAOFF + r]; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + + + if (fdiSectorFlags & 0x3F) // CRC correct? + { + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + else // oh-oh, high technology... CRC bad... ;-) + { + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8) ^ 0xFF; // emulation bad CRC... ;) + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF) ^ 0xFF; // --//-- ;) + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + + + for (r = 0; r < ThirdSpaceLen; r++) // Третий пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + for (int eoftrk = tptr; eoftrk < 6250; eoftrk++) + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + + delete tracksinfo; + delete ptr; + ReadOnly = readonly; + FType = DIT_FDI; + DiskPresent = true; +} +void TDiskImage::writeFDI(int hfile) +{ + unsigned char *ptr = (unsigned char*)new char[(MaxTrack + 1)*(MaxSide + 1) * 6250 + 524288]; + unsigned short *headptr = (unsigned short*)(ptr + 4); + memcpy(ptr, "FDI", 3); + ptr[3] = 0x00; // write enabled + headptr[0] = ((unsigned short)MaxTrack) + 1; // Cyl count + headptr[1] = ((unsigned short)MaxSide) + 1; // Head count + headptr[4] = 0; // extension length + + unsigned int trk, side; + VGFIND_SECTOR vgfs; + VGFIND_ADM vgfa; + + unsigned char *htrkSectorCount; + unsigned int fdiOFF = 0x0E; + unsigned int trackOFF = 0; + unsigned int SectorCount; + unsigned int sectOFF; + + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + *((unsigned long*)(ptr + fdiOFF)) = trackOFF; + fdiOFF += 4; + *((unsigned short*)(ptr + fdiOFF)) = 0; // Всегда содержит 0 (резерв) + fdiOFF += 2; + htrkSectorCount = ptr + fdiOFF; + fdiOFF++; + SectorCount = 0; + sectOFF = 0; + + unsigned int TrackPtr = 0; + bool FirstFindAD = true; + unsigned int FirstOffset; + for (;;) + { + if (!FindADMark(trk, side, TrackPtr, &vgfa)) break; + if (!FirstFindAD) + { + if (vgfa.OffsetADM == FirstOffset) break; + } + else + { + FirstOffset = vgfa.OffsetADM; + FirstFindAD = false; + } + TrackPtr = vgfa.OffsetEndADM; + + SectorCount++; + + memcpy(ptr + fdiOFF, vgfa.ADMPointer, 4); + fdiOFF += 4; + unsigned char flags = 0x00; + if (!FindSector(trk, side, vgfa.ADMPointer[2], &vgfs, vgfa.MarkedOffsetADM)) + flags |= 0x40; + else + { + if (vgfs.DataMarker == 0xF8) flags |= 0x80; + if (vgfs.CRCOK) flags |= (vgfs.SectorLength >> 7) & 0x3F; + } + ptr[fdiOFF++] = flags; + *((unsigned short*)(ptr + fdiOFF)) = sectOFF; + fdiOFF += 2; + + if (!(flags & 0x40)) sectOFF += vgfs.SectorLength; + } + *htrkSectorCount = (unsigned char)SectorCount; + trackOFF += sectOFF; + } + headptr[2] = fdiOFF; // Text offset + memcpy(ptr + fdiOFF, fdicomment, sizeof(fdicomment)); + fdiOFF += sizeof(fdicomment); + + headptr[3] = fdiOFF; // Data offset + + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + unsigned int TrackPtr = 0; + bool FirstFindAD = true; + unsigned int FirstOffset; + for (;;) + { + if (!FindADMark(trk, side, TrackPtr, &vgfa)) break; + if (!FirstFindAD) + { + if (vgfa.OffsetADM == FirstOffset) break; + } + else + { + FirstOffset = vgfa.OffsetADM; + FirstFindAD = false; + } + TrackPtr = vgfa.OffsetEndADM; + + if (FindSector(trk, side, vgfa.ADMPointer[2], &vgfs, vgfa.MarkedOffsetADM)) + { + memcpy(ptr + fdiOFF, vgfs.SectorPointer, vgfs.SectorLength); + fdiOFF += vgfs.SectorLength; + } + } + } + + write(hfile, ptr, fdiOFF); + delete ptr; +} +//----------------------------------------------------------------------------- +void TDiskImage::readFDD(int hfile, bool readonly) +{ + + long fsize = filelength(hfile); + if (fsize < 0) + { + ShowError(ERR_GETLEN); + return; + } + + unsigned char *ptr = (unsigned char*)new char[fsize + 1024 * 32]; + if (!ptr) + { + ShowError(ERR_NOMEM); + return; + } + + unsigned long rsize = read(hfile, ptr, fsize); + if (rsize < sizeof(FDD_MAIN_HEADER)) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + FDD_MAIN_HEADER *fdd_hdr = (FDD_MAIN_HEADER*)ptr; + + int MaxC = fdd_hdr->MaxTracks; + int MaxH = fdd_hdr->MaxHeads; + + if (MaxH > 2) + { + delete ptr; + ShowError(ERR_MANYSIDS); + return; + } + + + MaxH = (MaxH - 1) & 0xFF; + MaxC = (MaxC - 1) & 0xFF; + + + MaxTrack = MaxC; + MaxSide = MaxH; + + + // форматирование нового диска и размещение FDD секторов... + unsigned int ptrcrc; + unsigned int r; + unsigned short vgcrc; + unsigned int trkdatalen; + unsigned SecCount; + unsigned SL; + + FDD_TRACK_HEADER *trackinfo; + + unsigned int trk, side; + + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + FTrackLength[trk][side] = 6250; + + // make unformatted track... + FTracksPtr[trk][side][0] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // trk img + FTracksPtr[trk][side][1] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // clk img + for (unsigned ij = 0; ij < 6250; ij++) + { + FTracksPtr[trk][side][0][ij] = 0x00; + FTracksPtr[trk][side][1][ij] = 0x00; + } + + if ((fdd_hdr->DataOffset[trk*(MaxSide + 1) + side] + 2) > int(rsize)) + { + delete ptr; + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } + ShowError(ERR_CORRUPT); + return; + } + + trackinfo = (FDD_TRACK_HEADER *)(ptr + fdd_hdr->DataOffset[trk*(MaxSide + 1) + side]); + + SecCount = trackinfo->SectNum; + + if ((2 + SecCount * 8 + fdd_hdr->DataOffset[trk*(MaxSide + 1) + side]) > rsize) + { + delete ptr; + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } + ShowError(ERR_CORRUPT); + return; + } + else if (trackinfo->sect[SecCount - 1].SectPos > int(rsize)) + { + delete ptr; + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } + ShowError(ERR_CORRUPT); + return; + } + + + + // Вычисляем необходимое число байт под данные: + trkdatalen = 0; + for (unsigned int ilsec = 0; ilsec < SecCount; ilsec++) + { + trkdatalen += 2 + 6; // for marks: 0xA1, 0xFE, 6bytes + SL = unsigned(trackinfo->sect[ilsec].size); + if (!SL) SL = 128; + else SL = 128 << SL; + + trkdatalen += 4; // for data header/crc: 0xA1, 0xFB, ...,2bytes + + trkdatalen += SL; + } + + if (trkdatalen + SecCount*(3 + 2) > 6250) // 3x4E & 2x00 per sec checking + { + delete ptr; + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } + ShowError(ERR_IMPOSSIBLE); + return; + } + + unsigned int FreeSpace = 6250 - (trkdatalen + SecCount*(3 + 2)); + + unsigned int SynchroPulseLen = 1; // 1 уже учтен в trkdatalen... + unsigned int FirstSpaceLen = 1; + unsigned int SecondSpaceLen = 1; + unsigned int ThirdSpaceLen = 1; + unsigned int SynchroSpaceLen = 1; + FreeSpace -= FirstSpaceLen + SecondSpaceLen + ThirdSpaceLen + SynchroSpaceLen; + + // Распределяем длины пробелов и синхропромежутка: + while (FreeSpace > 0) + { + if (FreeSpace >= (SecCount * 2)) + if (SynchroSpaceLen < 12) { SynchroSpaceLen++; FreeSpace -= SecCount * 2; } // Synchro for ADM & DATA + if (FreeSpace < SecCount) break; + + if (FirstSpaceLen < 10) { FirstSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + if (SecondSpaceLen < 22) { SecondSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + if (ThirdSpaceLen < 60) { ThirdSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + + if ((SynchroSpaceLen >= 12) && (FirstSpaceLen >= 10) && (SecondSpaceLen >= 22) && (ThirdSpaceLen >= 60)) break; + }; + // по возможности делаем три синхроимпульса... + if (FreeSpace >(SecCount * 2) + 10) { SynchroPulseLen++; FreeSpace -= SecCount; } + if (FreeSpace >(SecCount * 2) + 9) SynchroPulseLen++; + + // Форматируем дорожку... + + unsigned int tptr = 0; + for (unsigned sec = 0; sec < SecCount; sec++) + { + for (r = 0; r < FirstSpaceLen; r++) // Первый пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < SynchroSpaceLen; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + ptrcrc = tptr; + for (r = 0; r < SynchroPulseLen; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + FTracksPtr[trk][side][0][tptr] = 0xFE; // Метка "Адрес" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + FTracksPtr[trk][side][0][tptr] = trackinfo->sect[sec].trk; // cyl + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = trackinfo->sect[sec].side; // head + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = trackinfo->sect[sec].sect; // secN + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = trackinfo->sect[sec].size; // len code + FTracksPtr[trk][side][1][tptr++] = 0x00; + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < SecondSpaceLen; r++) // Второй пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < SynchroSpaceLen; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + + + // DATA AM + ptrcrc = tptr; + for (r = 0; r < SynchroPulseLen; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + + FTracksPtr[trk][side][0][tptr] = 0xFB; // Метка "Данные" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + + SL = unsigned(trackinfo->sect[sec].size); + if (!SL) SL = 128; + else SL = 128 << SL; + + unsigned int secDATAOFF = trackinfo->sect[sec].SectPos; + + for (r = 0; r < SL; r++) // сектор SL байт + { + FTracksPtr[trk][side][0][tptr] = ptr[secDATAOFF + r]; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + + + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + + for (r = 0; r < ThirdSpaceLen; r++) // Третий пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + for (int eoftrk = tptr; eoftrk < 6250; eoftrk++) + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + + delete ptr; + ReadOnly = readonly; + FType = DIT_FDD; + DiskPresent = true; + +} +//----------------------------------------------------------------------------- +void TDiskImage::writeFDD(int hfile) +{ + char fddid[32] = "SPM DISK (c) 1996 MOA v0.1 "; + + + unsigned char *ptr = (unsigned char*)new char[(MaxTrack + 1)*(MaxSide + 1) * 6250 + 524288]; + + FDD_MAIN_HEADER *fdd_hdr = (FDD_MAIN_HEADER*)(ptr); + + memcpy(fdd_hdr->ID, fddid, 30); + fdd_hdr->MaxTracks = (MaxTrack + 1) & 0xFF; + fdd_hdr->MaxHeads = (MaxSide + 1) & 0xFF; + fdd_hdr->diskIndex = 0; + // fdd_hdr->DataOffset = + + + + + unsigned int trk, side; + VGFIND_SECTOR vgfs; + VGFIND_ADM vgfa; + + unsigned char *htrkSectorCount; + unsigned int fddOFF = 36 + 4 * (MaxTrack + 1)*(MaxSide + 1); + + unsigned int SectorCount; + unsigned int sectOFF; + + char secbuf[32768]; + + for (trk = 0; trk <= unsigned(MaxTrack); trk++) + for (side = 0; side <= unsigned(MaxSide); side++) + { + fdd_hdr->DataOffset[trk*(MaxSide + 1) + side] = fddOFF; + FDD_TRACK_HEADER *trackinfo = (FDD_TRACK_HEADER*)(ptr + fddOFF); + fddOFF += 2; + + SectorCount = 0; + + + unsigned int TrackPtr = 0; + bool FirstFindAD = true; + unsigned int FirstOffset; + for (;;) + { + if (!FindADMark(trk, side, TrackPtr, &vgfa)) break; + if (!FirstFindAD) + { + if (vgfa.OffsetADM == FirstOffset) break; + } + else + { + FirstOffset = vgfa.OffsetADM; + FirstFindAD = false; + } + TrackPtr = vgfa.OffsetEndADM; + + trackinfo->sect[SectorCount].trk = vgfa.ADMPointer[0]; + trackinfo->sect[SectorCount].side = vgfa.ADMPointer[1]; + trackinfo->sect[SectorCount].sect = vgfa.ADMPointer[2]; + trackinfo->sect[SectorCount].size = vgfa.ADMPointer[3]; + trackinfo->sect[SectorCount].SectPos = vgfa.MarkedOffsetADM; // tmp + + SectorCount++; + fddOFF += 8; + } + + trackinfo->SectNum = SectorCount; + trackinfo->trkType = 0; + + + for (int ilsec = 0; ilsec < int(SectorCount); ilsec++) + { + int SL = trackinfo->sect[ilsec].size; + SL &= 3; + if (!SL) SL = 128; + else SL = 128 << SL; + + + if (!FindSector(trk, side, trackinfo->sect[ilsec].sect, &vgfs, trackinfo->sect[ilsec].SectPos)) + { + for (int i = 0; i < sizeof(secbuf); i++) secbuf[i] = 0; + memcpy(secbuf, "***ERROR: SECTOR NOT FOUND!***", 31); + } + else + memcpy(secbuf, vgfs.SectorPointer, SL); + + trackinfo->sect[ilsec].SectPos = fddOFF; + + memcpy(ptr + fddOFF, secbuf, SL); + fddOFF += SL; + } + } + + write(hfile, ptr, fddOFF); + delete ptr; +} +//----------------------------------------------------------------------------- + +void TDiskImage::readSCL(int hfile, bool readonly) +{ + long fsize = filelength(hfile); + if (fsize < 0) + { + ShowError(ERR_GETLEN); + return; + } + unsigned char *ptr = (unsigned char*)new char[fsize + 1024 * 2048]; + if (!ptr) + { + ShowError(ERR_NOMEM); + return; + } + unsigned long rsize = read(hfile, ptr, fsize); + + if (!rsize) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + if (rsize < 9 + 4) // header + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + if (memcmp(ptr, "SINCLAIR", 8) != 0) + { + delete ptr; + ShowError(ERR_FORMAT" SCL!"); + return; + } + + unsigned int FileCount = ptr[8]; + if (rsize < 9 + 4 + FileCount * 14) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + TRDOS_DIR_ELEMENT *fileinfo[256]; + + unsigned short FilesTotalSecs = 0; + + // checking for corrupt + SCL-CRC + FileDIRS parse + unsigned long SCLCRC = 0; + unsigned sclOFF = 0; + unsigned int i, j; + for (i = 0; i < 9; i++) SCLCRC += unsigned(ptr[sclOFF++]); + + for (i = 0; i < FileCount; i++) + { + fileinfo[i] = (TRDOS_DIR_ELEMENT*)(ptr + sclOFF); + for (j = 0; j < 14; j++) SCLCRC += unsigned(ptr[sclOFF++]); + } + for (i = 0; i < FileCount; i++) + { + unsigned SL = unsigned(fileinfo[i]->SecLen) * 256; + FilesTotalSecs += fileinfo[i]->SecLen; + if (rsize < sclOFF + 4 + SL) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + for (j = 0; j < SL; j++) SCLCRC += unsigned(ptr[sclOFF++]); + } + + if (*((unsigned long*)(ptr + sclOFF)) != SCLCRC) + ShowError(ERR_FILECRC" SCL!"); + + + if (FilesTotalSecs < 2544) FilesTotalSecs = 2544; + else + { + int cyls = ((16 + FilesTotalSecs) / (16 * 2)) + (((16 + FilesTotalSecs) % (16 * 2)) ? 1 : 0); + FilesTotalSecs = (cyls * 16 * 2) - 16; + } + + formatTRDOS((FilesTotalSecs + 16) / (16 * 2), 2); + ReadOnly = true; + FType = DIT_SCL; + DiskPresent = true; + + sclOFF = 9 + 14 * FileCount; + + bool BOOTADD = true; + + unsigned char SEC = 0, TRK = 1; + unsigned short FreeSEC = 2544; + unsigned char _FileCount = 0; + unsigned char _DelFileCount = 0; + + TRDOS_DIR_ELEMENT trdosde; + VGFIND_SECTOR vgfs; + char sbuf[512]; + + for (i = 0; i < FileCount; i++) + { + if (TRK >= (MaxTrack + 1)*(MaxSide + 1)) break; // disk full ? + + memcpy(sbuf, fileinfo[i]->FileName, 9); + if (sbuf[0] == 0x01) _DelFileCount++; + _FileCount++; + for (char *p = sbuf; *p != 0; p++) *p = toupper(*p); + if (!memcmp(sbuf, "BOOT B", 9)) BOOTADD = false; + + memcpy(&trdosde, fileinfo[i], 14); + + trdosde.FirstSec = SEC; + trdosde.FirstTrk = TRK; + + unsigned int dirsec = ((i * 16) / 256) + 1; + if (FindSector(0, 0, dirsec, &vgfs)) // DIR ELEMENT write + { + memcpy(vgfs.SectorPointer + ((i * 16) % 256), &trdosde, 16); + ApplySectorCRC(vgfs); + } + + for (j = 0; j < unsigned(trdosde.SecLen); j++) + { + if (FindSector(TRK / 2, TRK % 2, SEC + 1, &vgfs)) // SECTOR write + { + memcpy(vgfs.SectorPointer, ptr + sclOFF, 256); + ApplySectorCRC(vgfs); + } + sclOFF += 256; + SEC++; + FreeSEC--; + if (SEC > 15) { SEC = 0; TRK++; } + + if (TRK >= (MaxTrack + 1)*(MaxSide + 1)) break; // disk full ? + } + } + if (!AddBOOT) BOOTADD = false; + + if (BOOTADD && (unsigned(_FileCount) + unsigned(_DelFileCount) < 127)) + { + unsigned int dirsec = ((_FileCount * 16) / 256) + 1; + if (FindSector(0, 0, dirsec, &vgfs)) // DIR ELEMENT write + { + memcpy(vgfs.SectorPointer + ((i * 16) % 256), sbootdir, 16); + ApplySectorCRC(vgfs); + } + _FileCount++; + + memcpy(&trdosde, sbootdir, 16); + + unsigned char _bSEC = trdosde.FirstSec + 1; + unsigned int _bOFF = 0; + + for (j = 0; j < unsigned(trdosde.SecLen); j++) + { + if (FindSector(0, 0, _bSEC++, &vgfs)) // SECTOR write + { + memcpy(vgfs.SectorPointer, sbootimage + _bOFF, 256); + ApplySectorCRC(vgfs); + } + _bOFF += 256; + if (_bSEC > 16) break; + } + } + + if (FindSector(0, 0, 9, &vgfs)) // update disk info + { + vgfs.SectorPointer[0xE1] = SEC; + vgfs.SectorPointer[0xE2] = TRK; + vgfs.SectorPointer[0xE4] = _FileCount; + vgfs.SectorPointer[0xF4] = _DelFileCount; + *((unsigned short*)(vgfs.SectorPointer + 0xE5)) = FreeSEC; + ApplySectorCRC(vgfs); + } + + delete ptr; + ReadOnly = readonly; +} +void TDiskImage::writeSCL(int hfile) +{ + VGFIND_SECTOR vgfs; + + if (!FindSector(0, 0, 9, &vgfs)) + { + printf("DANGER! Sector 9 on track 0, side 0 not found!\n"); + return; + } + else if ((!vgfs.CRCOK) || (!vgfs.vgfa.CRCOK)) printf("Warning: sector 9 on track 0, side 0 with BAD CRC!\n"); + if (vgfs.SectorLength != 256) printf("DANGER! Sector 9 on track 0, side 0 is non 256 bytes!\n"); + + + if (vgfs.SectorPointer[0xE7] != 0x10) + { + printf("Error: source disk image in non TR-DOS format!\n"); + return; + } + unsigned int FileCount = unsigned(vgfs.SectorPointer[0xE4]); + if (FileCount > 144) + { + printf("Error: source disk image contain incorrect sector 9, track 0, side 0!\n"); + return; + } + + unsigned int SideCount = 2; + if ((vgfs.SectorPointer[0xE3] == 0x18) || (vgfs.SectorPointer[0xE3] == 0x19)) + SideCount = 1; + if ((vgfs.SectorPointer[0xE3] != 0x16) && (vgfs.SectorPointer[0xE3] != 0x17) && + (vgfs.SectorPointer[0xE3] != 0x18) && (vgfs.SectorPointer[0xE3] != 0x19)) + { + printf("Error: source disk image in non TR-DOS format!\n"); + return; + } + + unsigned i, j; + unsigned long SCLCRC = 0; + unsigned char buf[256 * 16]; + memcpy(buf, "SINCLAIR", 8); + buf[8] = (unsigned char)FileCount; + for (i = 0; i < 9; i++) SCLCRC += unsigned(buf[i]); + + write(hfile, buf, 9); + + // prepare nullbuf... + unsigned char nullbuf[256]; + for (i = 0; i < 256; i++) nullbuf[i] = '*'; + memcpy(nullbuf, errsect, sizeof(errsect)); + TRDOS_DIR_ELEMENT nulldir; + memcpy(nulldir.FileName, "WRONGSEC", 8); + nulldir.Type = 'E'; + nulldir.Start = 0xEEEE; + nulldir.Length = 0xEEEE; + nulldir.SecLen = 0; + nulldir.FirstSec = 0x00; + nulldir.FirstSec = 0x00; + + TRDOS_DIR_ELEMENT fileinfo[256]; + for (i = 0; i < FileCount; i++) + { + if (FindSector(0, 0, ((i * 16) / 256) + 1, &vgfs)) + { + memcpy(&fileinfo[i], vgfs.SectorPointer + (i * 16) % 256, 16); + if ((!vgfs.CRCOK) || (!vgfs.vgfa.CRCOK)) printf("Warning: sector %d on track 0, side 0 with BAD CRC!\n", (((i * 16) / 256) + 1)); + if (vgfs.SectorLength != 256) printf("Warning: sector %d on track 0, side 0 is non TR-DOS!\n", (((i * 16) / 256) + 1)); + } + else + { + memcpy(&fileinfo[i], &nulldir, 16); + printf("DANGER! Sector %d on track 0, side 0 size is non 256 bytes!\n", (((i * 16) / 256) + 1)); + } + memcpy(buf, &fileinfo[i], 16); + + write(hfile, buf, 14); + for (j = 0; j < 14; j++) SCLCRC += unsigned(buf[j]); + } + + unsigned char SEC, TRK; + for (i = 0; i < FileCount; i++) + { + SEC = fileinfo[i].FirstSec; + TRK = fileinfo[i].FirstTrk; + + for (j = 0; j < unsigned(fileinfo[i].SecLen); j++) + { + if (FindSector(TRK / SideCount, TRK%SideCount, SEC + 1, &vgfs)) + { + memcpy(buf, vgfs.SectorPointer, 256); + if ((!vgfs.CRCOK) || (!vgfs.vgfa.CRCOK)) printf("Warning: sector %d on track %d, side %d with BAD CRC!", SEC + 1, TRK / SideCount, TRK%SideCount); + if (vgfs.SectorLength != 256) printf("Warning: sector %d on track %d, side %d is non 256 bytes!\n", SEC + 1, TRK / SideCount, TRK%SideCount); + } + else + { + memcpy(buf, nullbuf, 256); + printf("DANGER! Sector %d on track %d, side %d not found!\n", SEC + 1, TRK / SideCount, TRK%SideCount); + } + write(hfile, buf, 256); + for (unsigned k = 0; k < 256; k++) SCLCRC += unsigned(buf[k]); + SEC++; + if (SEC > 15) { SEC = 0; TRK++; } + } + } + write(hfile, &SCLCRC, 4); +} +//----------------------------------------------------------------------------- +void TDiskImage::readHOB(int hfile) +{ + long fsize = filelength(hfile); + if (fsize < 0) + { + ShowError(ERR_GETLEN); + return; + } + unsigned char *ptr = (unsigned char*)new char[fsize + 1024 * 2048]; + if (!ptr) + { + ShowError(ERR_NOMEM); + return; + } + unsigned long rsize = read(hfile, ptr, fsize); + + if (!rsize) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + if (rsize < 17) // header + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + TRDOS_DIR_ELEMENT dired; + memcpy(&dired, ptr, 14); + + unsigned short hobRealCRC = *((unsigned short*)(ptr + 0x0F)); + unsigned int DataLength = *((unsigned short*)(ptr + 0x0D)); + + if (rsize < 17 + (DataLength & 0xFF00)) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + unsigned int i; + unsigned short CRC = 0; + for (i = 0; i < 15; i++) CRC = CRC + ptr[i]; + CRC *= 257; + CRC += 105; // сумма чисел от 0 до 14 + + if (CRC != hobRealCRC) + ShowError(ERR_FILECRC" HOBETA!"); + + + + + ReadOnly = true; + if (!DiskPresent) + { + formatTRDOS(80, 2); + FType = DIT_HOB; + DiskPresent = true; + } + + // --- read file... + dired.SecLen = ptr[0x0E]; // число секторов файла + + VGFIND_SECTOR vgfs9; + if (!FindSector(0, 0, 9, &vgfs9)) { delete ptr; return; } + + dired.FirstSec = vgfs9.SectorPointer[0xE1]; + dired.FirstTrk = vgfs9.SectorPointer[0xE2]; + + VGFIND_SECTOR vgfs; + + unsigned char SEC = dired.FirstSec, TRK = dired.FirstTrk; + unsigned short FreeSEC = *((unsigned short*)(vgfs9.SectorPointer + 0xE5)); + unsigned char FileCount = vgfs9.SectorPointer[0xE4]; + unsigned char DelFileCount = vgfs9.SectorPointer[0xF4]; + + if (TRK >= 160) // disk full ? + { + delete ptr; + return; + } + + for (unsigned int j = 0; j < unsigned(dired.SecLen); j++) + { + if (FindSector(TRK / 2, TRK % 2, SEC + 1, &vgfs)) + { + memcpy(vgfs.SectorPointer, ptr + 17 + j * 256, 256); + ApplySectorCRC(vgfs); + } + SEC++; + FreeSEC--; + if (SEC > 15) { SEC = 0; TRK++; } + + if (TRK >= 160) break; // disk full? + } + + if (FindSector(0, 0, ((FileCount * 16) / 256) + 1, &vgfs)) + { + memcpy(vgfs.SectorPointer + ((FileCount * 16) % 256), &dired, 16); + ApplySectorCRC(vgfs); + } + + if (dired.FileName[0] == 0x01) DelFileCount++; + FileCount++; + + vgfs9.SectorPointer[0xE1] = SEC; + vgfs9.SectorPointer[0xE2] = TRK; + *((unsigned short*)(vgfs9.SectorPointer + 0xE5)) = FreeSEC; + vgfs9.SectorPointer[0xE4] = FileCount; + vgfs9.SectorPointer[0xF4] = DelFileCount; + ApplySectorCRC(vgfs9); +} +//----------------------------------------------------------------------------- +bool unpack_td0(unsigned char *data, long &size); +unsigned short TD0CRC(unsigned char *buf, unsigned int len); + +#define WORD2(a,b) ((a)+(b)*0x100) + +void TDiskImage::readTD0(int hfile, bool readonly) +{ + long fsize = filelength(hfile); + if (fsize < 0) + { + ShowError(ERR_GETLEN); + return; + } + unsigned char *ptr = (unsigned char*)new char[fsize + 256 * 20000]; + if (!ptr) + { + ShowError(ERR_NOMEM); + return; + } + long rsize = read(hfile, ptr, fsize); + + TD0_MAIN_HEADER *td0hdr = (TD0_MAIN_HEADER*)ptr; + TD0_INFO_DATA *td0inf = (TD0_INFO_DATA*)(ptr + 12); + + if (!rsize) + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + if (rsize < 12) // header + { + delete ptr; + ShowError(ERR_CORRUPT); + return; + } + + if ((*(short*)ptr != WORD2('T', 'D')) && (*(short*)ptr != WORD2('t', 'd')))// non TD0 + { + delete ptr; + ShowError(ERR_FORMAT" TD0!"); + return; + } + if (TD0CRC(ptr, 10) != td0hdr->CRC) // CRC bad... + { + delete ptr; + ShowError(ERR_FILECRC" TD0!"); + return; + } + if ((td0hdr->Ver > 21) || (td0hdr->Ver < 10)) // 1.0 <= version <= 2.1... + { + delete ptr; + ShowError(ERR_FILEVER" TD0!"); + return; + } + if (td0hdr->DataDOS != 0) // if DOS allocated sectors only... + { + delete ptr; + ShowError(ERR_TD0DOSALLOC); + return; + } + if (!unpack_td0(ptr, rsize)) + { + delete ptr; + ShowError(ERR_FORMAT" TD0!"); + return; + } + + // loading unpacked TD0... + + int tdOFF = 12; + if (ptr[7] & 0x80) tdOFF += sizeof(TD0_INFO_DATA) + td0inf->strLen; + + TD0_TRACK_HEADER *tdtrk; + TD0_SECT_HEADER *tdsect; + + MaxTrack = 0; + MaxSide = 0; + + for (; tdOFF < rsize;) + { + tdtrk = (TD0_TRACK_HEADER*)(ptr + tdOFF); + tdOFF += sizeof(TD0_TRACK_HEADER); + + if (tdOFF >= rsize) break; + if (tdtrk->SectorCount == 0xFF) break; // EOF marker + + + unsigned trk = tdtrk->Track; + unsigned side = tdtrk->Side; + FTrackLength[trk][side] = 6250; + + // make unformatted track... + FTracksPtr[trk][side][0] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // trk img + FTracksPtr[trk][side][1] = (unsigned char*)new char[FTrackLength[trk][side] + 1024]; // clk img + for (unsigned ij = 0; ij < 6250; ij++) + { + FTracksPtr[trk][side][0][ij] = 0x00; + FTracksPtr[trk][side][1][ij] = 0x00; + } + + + unsigned SecCount = tdtrk->SectorCount; + + unsigned int tmpOFF = tdOFF; + + // Вычисляем необходимое число байт под данные: + unsigned int trkdatalen = 0; + unsigned int SL; + for (unsigned int ilsec = 0; ilsec < SecCount; ilsec++) + { + tdsect = (TD0_SECT_HEADER*)(ptr + tmpOFF); + tmpOFF += sizeof(TD0_SECT_HEADER) + tdsect->DataLength; + + trkdatalen += 2 + 6; // for marks: 0xA1, 0xFE, 6bytes + trkdatalen += 4; // for data header/crc: 0xA1, 0xFB, ...,2bytes + // SL = unsigned(tdsect->ADRM[3]); + // if(!SL) SL = 128; + // else SL = 128 << SL; + SL = tdsect->DataLength - 1; + trkdatalen += SL; + } + + // проверка на возможность формата... + if (trkdatalen + SecCount*(3 + 2) > 6250) // 3x4E & 2x00 per sec checking + { + delete ptr; + for (int t = 0; t < 256; t++) + for (int s = 0; s < 256; s++) + { + FTrackLength[t][s] = 0; + if (FTracksPtr[t][s][0]) delete FTracksPtr[t][s][0]; + FTracksPtr[t][s][0] = NULL; + if (FTracksPtr[t][s][1]) delete FTracksPtr[t][s][1]; + FTracksPtr[t][s][1] = NULL; + } + ShowError(ERR_IMPOSSIBLE); + return; + } + + unsigned int FreeSpace = 6250 - (trkdatalen + SecCount*(3 + 2)); + + unsigned int SynchroPulseLen = 1; // 1 уже учтен в trkdatalen... + unsigned int FirstSpaceLen = 1; + unsigned int SecondSpaceLen = 1; + unsigned int ThirdSpaceLen = 1; + unsigned int SynchroSpaceLen = 1; + FreeSpace -= FirstSpaceLen + SecondSpaceLen + ThirdSpaceLen + SynchroSpaceLen; + + // Распределяем длины пробелов и синхропромежутка: + while (FreeSpace > 0) + { + if (FreeSpace >= (SecCount * 2)) + if (SynchroSpaceLen < 12) { SynchroSpaceLen++; FreeSpace -= SecCount * 2; } // Synchro for ADM & DATA + if (FreeSpace < SecCount) break; + + if (FirstSpaceLen < 10) { FirstSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + if (SecondSpaceLen < 22) { SecondSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + if (ThirdSpaceLen < 60) { ThirdSpaceLen++; FreeSpace -= SecCount; } + if (FreeSpace < SecCount) break; + + if ((SynchroSpaceLen >= 12) && (FirstSpaceLen >= 10) && (SecondSpaceLen >= 22) && (ThirdSpaceLen >= 60)) break; + }; + // по возможности делаем три синхроимпульса... + if (FreeSpace >(SecCount * 2) + 10) { SynchroPulseLen++; FreeSpace -= SecCount; } + if (FreeSpace >(SecCount * 2) + 9) SynchroPulseLen++; + + // Форматируем дорожку... + + unsigned int tptr = 0; + unsigned int ptrcrc; + unsigned int r; + unsigned short vgcrc; + for (unsigned sec = 0; sec < SecCount; sec++) + { + tdsect = (TD0_SECT_HEADER*)(ptr + tdOFF); + tdOFF += sizeof(TD0_SECT_HEADER) + 1; + + for (r = 0; r < FirstSpaceLen; r++) // Первый пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < SynchroSpaceLen; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + ptrcrc = tptr; + for (r = 0; r < SynchroPulseLen; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + FTracksPtr[trk][side][0][tptr] = 0xFE; // Метка "Адрес" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + FTracksPtr[trk][side][0][tptr] = tdsect->ADRM[0]; // cyl + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = tdsect->ADRM[1]; // head + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = tdsect->ADRM[2]; // secN + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = tdsect->ADRM[3]; // len code + FTracksPtr[trk][side][1][tptr++] = 0x00; + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + + for (r = 0; r < SecondSpaceLen; r++) // Второй пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + for (r = 0; r < SynchroSpaceLen; r++) // Синхропромежуток + { + FTracksPtr[trk][side][0][tptr] = 0x00; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + + if (tdsect->DataLength - 1) // oh-oh, data area not present... ;-) + { + ptrcrc = tptr; + for (r = 0; r < SynchroPulseLen; r++) // Синхроимпульс + { + FTracksPtr[trk][side][0][tptr] = 0xA1; + FTracksPtr[trk][side][1][tptr++] = 0xFF; + } + + FTracksPtr[trk][side][0][tptr] = 0xFB; // Метка "Данные" + FTracksPtr[trk][side][1][tptr++] = 0x00; + + // SL = unsigned(tdsect->ADRM[3]); + // if(!SL) SL = 128; + // else SL = 128 << SL; + SL = tdsect->DataLength - 1; + + for (r = 0; r < SL; r++) // сектор SL байт + { + FTracksPtr[trk][side][0][tptr] = ptr[tdOFF + r]; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + tdOFF += SL; + + vgcrc = MakeVGCRC(FTracksPtr[trk][side][0] + ptrcrc, tptr - ptrcrc); + + + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc >> 8); // VG93 CRC + FTracksPtr[trk][side][1][tptr++] = 0x00; + FTracksPtr[trk][side][0][tptr] = (unsigned char)(vgcrc & 0xFF); + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + + for (r = 0; r < ThirdSpaceLen; r++) // Третий пробел + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + } + for (int eoftrk = tptr; eoftrk < 6250; eoftrk++) + { + FTracksPtr[trk][side][0][tptr] = 0x4E; + FTracksPtr[trk][side][1][tptr++] = 0x00; + } + + if (unsigned(MaxTrack) < trk) MaxTrack = trk; + if (unsigned(MaxSide) < side) MaxSide = side; + } + + delete ptr; + ReadOnly = readonly; + FType = DIT_TD0; + DiskPresent = true; +} +void TDiskImage::writeTD0(int hfile) +{ + TD0_MAIN_HEADER td0hdr; + + td0hdr.ID[0] = 'T'; td0hdr.ID[1] = 'D'; td0hdr.__t = 0x00; + td0hdr.__1 = 0x00; + td0hdr.Ver = 21; + td0hdr.__2 = 0x00; + td0hdr.DiskType = 0x03; + td0hdr.Info = 0x00; + td0hdr.DataDOS = 0x00; + td0hdr.ChkdSides = 0x02; + td0hdr.CRC = TD0CRC((unsigned char*)&td0hdr, 10); + write(hfile, &td0hdr, sizeof(td0hdr)); + + // TD0_INFO_DATA td0inf; + + VGFIND_SECTOR vgfs; + VGFIND_ADM vgfa; + + TD0_TRACK_HEADER tdtrk; + TD0_SECT_HEADER tdsect; + + // prepare nullbuf... + unsigned char nullbuf[256]; + for (int i = 0; i < 256; i++) nullbuf[i] = '*'; + memcpy(nullbuf, errsect, sizeof(errsect)); + + unsigned char secbuf[32768]; + + unsigned char sectorsMap[256]; + + unsigned int SectorCount; + for (unsigned int trk = 0; trk <= unsigned(MaxTrack); trk++) + for (unsigned int side = 0; side <= unsigned(MaxSide); side++) + { + SectorCount = 0; + + unsigned int TrackPtr = 0; + bool FirstFindAD = true; + unsigned int FirstOffset; + for (;;) + { + if (!FindADMark(trk, side, TrackPtr, &vgfa)) break; + if (!FirstFindAD) + { + if (vgfa.OffsetADM == FirstOffset) break; + } + else + { + FirstOffset = vgfa.OffsetADM; + FirstFindAD = false; + } + TrackPtr = vgfa.OffsetEndADM; + + sectorsMap[SectorCount] = vgfa.ADMPointer[2]; + + SectorCount++; + } + if (SectorCount > 0xFE) SectorCount = 0xFE; + + tdtrk.SectorCount = (unsigned char)SectorCount; + tdtrk.Track = (unsigned char)trk; + tdtrk.Side = (unsigned char)side; + tdtrk.CRCL = (unsigned char)(TD0CRC((unsigned char*)&tdtrk, 3) & 0xFF); + + write(hfile, &tdtrk, sizeof(TD0_TRACK_HEADER)); + + for (unsigned int sec = 0; sec < SectorCount; sec++) + { + if (FindSector(trk, side, sectorsMap[sec], &vgfs)) + memcpy(secbuf + 1, vgfs.SectorPointer, vgfs.SectorLength); + else memcpy(secbuf + 1, nullbuf, vgfs.SectorLength); + secbuf[0] = 0x00; + tdsect.ADRM[5] = (unsigned char)(TD0CRC(secbuf, vgfs.SectorLength + 1) & 0xFF); + tdsect.DataLength = vgfs.SectorLength + 1; + if (vgfs.vgfa.FoundADM) memcpy(tdsect.ADRM, vgfs.vgfa.ADMPointer, 4); + tdsect.ADRM[4] = 0x00; + + write(hfile, &tdsect, sizeof(TD0_SECT_HEADER)); + write(hfile, secbuf, tdsect.DataLength); + } + } + + tdtrk.SectorCount = 0xFF; + tdtrk.Track = 0x00; + tdtrk.Side = 0x00; + tdtrk.CRCL = 0x00; + write(hfile, &tdtrk, sizeof(TD0_TRACK_HEADER)); + +} +//----------------------------------------------------------------------------- + +void TDiskImage::ShowError(const char *str) +{ + printf("DiskImage Error: %s\n", str); +} + +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// convert packed td0 to unpacked + +unsigned short TD0CRC(unsigned char *buf, unsigned int len); +unsigned unpack_lzh(unsigned char *src, unsigned size, unsigned char *buf); +unsigned char *td0_dst, *td0_src; + + +void td0_move(unsigned size) +{ + memcpy(td0_dst, td0_src, size); + td0_dst += size; + td0_src += size; +} + +//---------------------------------------------------------------------------- +bool unpack_td0(unsigned char *data, long &size) +{ + if (size < 12) return false; + if ((*(short*)data != WORD2('T', 'D')) && (*(short*)data != WORD2('t', 'd'))) + return false; // non TD0 + if (TD0CRC(data, 10) != *((unsigned short*)(data + 0x0A))) + return false; // CRC bad... + if (data[4] > 21) + return false; // version > 2.1... + + unsigned char *snbuf = (unsigned char*)new char[size * 2 + 1500000]; // if compressed then UUUUFF ;-/ + if (!snbuf) return false; + + memcpy(snbuf, data, size); + if (*(short*)snbuf == WORD2('t', 'd')) // packed disk + { + if (snbuf[4] < 20) // unsupported Old Advanced compression + { + delete snbuf; + return false; + } + unpack_lzh((unsigned char*)data + 12, size - 12, (unsigned char*)snbuf + 12), *(short*)snbuf = WORD2('T', 'D'); + } + + td0_src = snbuf, td0_dst = data; + td0_move(12); + + if (snbuf[7] & 0x80) // additional info... + { + unsigned short *cs = (unsigned short*)(snbuf + 12 + 2); + + if (TD0CRC(snbuf + 12 + 2, 8 + *cs) != cs[-1]) + { + delete snbuf; + return false; + } + td0_move(10); + td0_move(*((unsigned short*)(snbuf + 12 + 2))); + } + + for (;;) + { + unsigned char s = *td0_src; + td0_move(4); + if (s == 0xFF) break; + for (; s; s--) + { + // unsigned char *sec = td0_src; + unsigned size = 128; if (td0_src[3]) size <<= td0_src[3]; + td0_move(6); + *(unsigned short*)td0_dst = size + 1; td0_dst += 2; + *td0_dst++ = 0; + unsigned char *dst = td0_dst; + unsigned src_size = *(unsigned short*)td0_src; td0_src += 2; + unsigned char *end_packed_data = td0_src + src_size; + memset(td0_dst, 0, size); + switch (*td0_src++) + { + case 0: + memcpy(dst, td0_src, src_size - 1); break; + case 1: + { + unsigned n = *(unsigned short*)td0_src; + td0_src += 2; + unsigned short data = *(unsigned short*)td0_src; + for (; n; n--) *(unsigned short*)dst = data, dst += 2; + break; + } + case 2: + { + unsigned short data; + unsigned char s; + do + { + switch (*td0_src++) + { + case 0: + for (s = *td0_src++; s; s--) *dst++ = *td0_src++; + break; + case 1: + s = *td0_src++; + data = *(unsigned short*)td0_src; + td0_src += 2; + for (; s; s--) *(unsigned short*)dst = data, dst += 2; + break; + default: shit: + delete snbuf; + return false; // "bad TD0 file" + } + } while (td0_src < end_packed_data); + break; + } + default: goto shit; + } + td0_dst += size; + td0_src = end_packed_data; + } + } + size = unsigned(td0_dst) - unsigned(data); + delete snbuf; + return true; +} +//---------------------------------------------------------------------------- +// +// TD0 CRC - table&proc grabed from TDCHECK.EXE by Alex Makeev +// +unsigned char tbltd0crc[512] = { + 0x00,0x00,0xA0,0x97,0xE1,0xB9,0x41,0x2E,0x63,0xE5,0xC3,0x72,0x82,0x5C,0x22,0xCB, + 0xC7,0xCA,0x67,0x5D,0x26,0x73,0x86,0xE4,0xA4,0x2F,0x04,0xB8,0x45,0x96,0xE5,0x01, + 0x2F,0x03,0x8F,0x94,0xCE,0xBA,0x6E,0x2D,0x4C,0xE6,0xEC,0x71,0xAD,0x5F,0x0D,0xC8, + 0xE8,0xC9,0x48,0x5E,0x09,0x70,0xA9,0xE7,0x8B,0x2C,0x2B,0xBB,0x6A,0x95,0xCA,0x02, + 0x5E,0x06,0xFE,0x91,0xBF,0xBF,0x1F,0x28,0x3D,0xE3,0x9D,0x74,0xDC,0x5A,0x7C,0xCD, + 0x99,0xCC,0x39,0x5B,0x78,0x75,0xD8,0xE2,0xFA,0x29,0x5A,0xBE,0x1B,0x90,0xBB,0x07, + 0x71,0x05,0xD1,0x92,0x90,0xBC,0x30,0x2B,0x12,0xE0,0xB2,0x77,0xF3,0x59,0x53,0xCE, + 0xB6,0xCF,0x16,0x58,0x57,0x76,0xF7,0xE1,0xD5,0x2A,0x75,0xBD,0x34,0x93,0x94,0x04, + 0xBC,0x0C,0x1C,0x9B,0x5D,0xB5,0xFD,0x22,0xDF,0xE9,0x7F,0x7E,0x3E,0x50,0x9E,0xC7, + 0x7B,0xC6,0xDB,0x51,0x9A,0x7F,0x3A,0xE8,0x18,0x23,0xB8,0xB4,0xF9,0x9A,0x59,0x0D, + 0x93,0x0F,0x33,0x98,0x72,0xB6,0xD2,0x21,0xF0,0xEA,0x50,0x7D,0x11,0x53,0xB1,0xC4, + 0x54,0xC5,0xF4,0x52,0xB5,0x7C,0x15,0xEB,0x37,0x20,0x97,0xB7,0xD6,0x99,0x76,0x0E, + 0xE2,0x0A,0x42,0x9D,0x03,0xB3,0xA3,0x24,0x81,0xEF,0x21,0x78,0x60,0x56,0xC0,0xC1, + 0x25,0xC0,0x85,0x57,0xC4,0x79,0x64,0xEE,0x46,0x25,0xE6,0xB2,0xA7,0x9C,0x07,0x0B, + 0xCD,0x09,0x6D,0x9E,0x2C,0xB0,0x8C,0x27,0xAE,0xEC,0x0E,0x7B,0x4F,0x55,0xEF,0xC2, + 0x0A,0xC3,0xAA,0x54,0xEB,0x7A,0x4B,0xED,0x69,0x26,0xC9,0xB1,0x88,0x9F,0x28,0x08, + 0xD8,0x8F,0x78,0x18,0x39,0x36,0x99,0xA1,0xBB,0x6A,0x1B,0xFD,0x5A,0xD3,0xFA,0x44, + 0x1F,0x45,0xBF,0xD2,0xFE,0xFC,0x5E,0x6B,0x7C,0xA0,0xDC,0x37,0x9D,0x19,0x3D,0x8E, + 0xF7,0x8C,0x57,0x1B,0x16,0x35,0xB6,0xA2,0x94,0x69,0x34,0xFE,0x75,0xD0,0xD5,0x47, + 0x30,0x46,0x90,0xD1,0xD1,0xFF,0x71,0x68,0x53,0xA3,0xF3,0x34,0xB2,0x1A,0x12,0x8D, + 0x86,0x89,0x26,0x1E,0x67,0x30,0xC7,0xA7,0xE5,0x6C,0x45,0xFB,0x04,0xD5,0xA4,0x42, + 0x41,0x43,0xE1,0xD4,0xA0,0xFA,0x00,0x6D,0x22,0xA6,0x82,0x31,0xC3,0x1F,0x63,0x88, + 0xA9,0x8A,0x09,0x1D,0x48,0x33,0xE8,0xA4,0xCA,0x6F,0x6A,0xF8,0x2B,0xD6,0x8B,0x41, + 0x6E,0x40,0xCE,0xD7,0x8F,0xF9,0x2F,0x6E,0x0D,0xA5,0xAD,0x32,0xEC,0x1C,0x4C,0x8B, + 0x64,0x83,0xC4,0x14,0x85,0x3A,0x25,0xAD,0x07,0x66,0xA7,0xF1,0xE6,0xDF,0x46,0x48, + 0xA3,0x49,0x03,0xDE,0x42,0xF0,0xE2,0x67,0xC0,0xAC,0x60,0x3B,0x21,0x15,0x81,0x82, + 0x4B,0x80,0xEB,0x17,0xAA,0x39,0x0A,0xAE,0x28,0x65,0x88,0xF2,0xC9,0xDC,0x69,0x4B, + 0x8C,0x4A,0x2C,0xDD,0x6D,0xF3,0xCD,0x64,0xEF,0xAF,0x4F,0x38,0x0E,0x16,0xAE,0x81, + 0x3A,0x85,0x9A,0x12,0xDB,0x3C,0x7B,0xAB,0x59,0x60,0xF9,0xF7,0xB8,0xD9,0x18,0x4E, + 0xFD,0x4F,0x5D,0xD8,0x1C,0xF6,0xBC,0x61,0x9E,0xAA,0x3E,0x3D,0x7F,0x13,0xDF,0x84, + 0x15,0x86,0xB5,0x11,0xF4,0x3F,0x54,0xA8,0x76,0x63,0xD6,0xF4,0x97,0xDA,0x37,0x4D, + 0xD2,0x4C,0x72,0xDB,0x33,0xF5,0x93,0x62,0xB1,0xA9,0x11,0x3E,0x50,0x10,0xF0,0x87, +}; +unsigned short TD0CRC(unsigned char *buf, unsigned int len) +{ + unsigned short CRC = 0; + int j; + for (unsigned int i = 0; i < len; i++) + { + CRC ^= *buf++; + j = CRC & 0xFF; + CRC &= 0xFF00; + CRC = (CRC << 8) | (CRC >> 8); + CRC ^= ((unsigned short*)tbltd0crc)[j]; + } + return (CRC << 8) | (CRC >> 8); +} +// ---------------------------------------------------------------------------- + + + + + +unsigned char *packed_ptr, *packed_end; + +int readChar(void) +{ + if (packed_ptr < packed_end) return *packed_ptr++; + else return -1; +} + +// ------------------------------------------------------ LZH unpacker + +unsigned char d_code[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +}; + +unsigned char d_len[256] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, +}; + + +const int N = 4096; // buffer size +const int F = 60; // lookahead buffer size +const int THRESHOLD = 2; +const int NIL = N; // leaf of tree + +unsigned char text_buf[N + F - 1]; + +const int N_CHAR = (256 - THRESHOLD + F); // kinds of characters (character code = 0..N_CHAR-1) +const int T = (N_CHAR * 2 - 1); // size of table +const int R = (T - 1); // position of root +const int MAX_FREQ = 0x8000; // updates tree when the + // root frequency comes to this value. + +unsigned short freq[T + 1]; // frequency table + +short prnt[T + N_CHAR]; // pointers to parent nodes, except for the + // elements [T..T + N_CHAR - 1] which are used to get + // the positions of leaves corresponding to the codes. +short son[T]; // pointers to child nodes (son[], son[] + 1) + + +int r; + +unsigned getbuf; +unsigned char getlen; + +int GetBit(void) /* get one bit */ +{ + int i; + + while (getlen <= 8) + { + if ((i = readChar()) == -1) i = 0; + getbuf |= i << (8 - getlen); + getlen += 8; + } + i = getbuf; + getbuf <<= 1; + getlen--; + return ((i >> 15) & 1); +} + +int GetByte(void) /* get one byte */ +{ + unsigned i; + + while (getlen <= 8) + { + if ((i = readChar()) == -1) i = 0; + getbuf |= i << (8 - getlen); + getlen += 8; + } + i = getbuf; + getbuf <<= 8; + getlen -= 8; + return (i >> 8) & 0xFF; +} + +void StartHuff(void) +{ + int i, j; + + getbuf = 0, getlen = 0; + for (i = 0; i < N_CHAR; i++) { + freq[i] = 1; + son[i] = i + T; + prnt[i + T] = i; + } + i = 0; j = N_CHAR; + while (j <= R) { + freq[j] = freq[i] + freq[i + 1]; + son[j] = i; + prnt[i] = prnt[i + 1] = j; + i += 2; j++; + } + freq[T] = 0xffff; + prnt[R] = 0; + + for (i = 0; i < N - F; i++) text_buf[i] = ' '; + r = N - F; +} + +/* reconstruction of tree */ +void reconst(void) +{ + int i, j, k; + int f, l; + + /* collect leaf nodes in the first half of the table */ + /* and replace the freq by (freq + 1) / 2. */ + j = 0; + for (i = 0; i < T; i++) + { + if (son[i] >= T) + { + freq[j] = (freq[i] + 1) / 2; + son[j] = son[i]; + j++; + } + } + /* begin constructing tree by connecting sons */ + for (i = 0, j = N_CHAR; j < T; i += 2, j++) + { + k = i + 1; + f = freq[j] = freq[i] + freq[k]; + for (k = j - 1; f < freq[k]; k--); + k++; + l = (j - k) * sizeof(*freq); + memmove(&freq[k + 1], &freq[k], l); + freq[k] = f; + memmove(&son[k + 1], &son[k], l); + son[k] = i; + } + /* connect prnt */ + for (i = 0; i < T; i++) + if ((k = son[i]) >= T) prnt[k] = i; + else prnt[k] = prnt[k + 1] = i; +} + + +/* increment frequency of given code by one, and update tree */ + +void update(int c) +{ + int i, j, k, l; + + if (freq[R] == MAX_FREQ) reconst(); + + c = prnt[c + T]; + do { + k = ++freq[c]; + + /* if the order is disturbed, exchange nodes */ + if (k > freq[l = c + 1]) + { + while (k > freq[++l]); + l--; + freq[c] = freq[l]; + freq[l] = k; + + i = son[c]; + prnt[i] = l; + if (i < T) prnt[i + 1] = l; + + j = son[l]; + son[l] = i; + + prnt[j] = c; + if (j < T) prnt[j + 1] = c; + son[c] = j; + + c = l; + } + } while ((c = prnt[c]) != 0); /* repeat up to root */ +} + +int DecodeChar(void) +{ + int c; + + c = son[R]; + + /* travel from root to leaf, */ + /* choosing the smaller child node (son[]) if the read bit is 0, */ + /* the bigger (son[]+1} if 1 */ + while (c < T) c = son[c + GetBit()]; + c -= T; + update(c); + return c; +} + +int DecodePosition(void) +{ + int i, j, c; + + /* recover upper 6 bits from table */ + i = GetByte(); + c = (int)d_code[i] << 6; + j = d_len[i]; + /* read lower 6 bits verbatim */ + j -= 2; + while (j--) i = (i << 1) + GetBit(); + return c | (i & 0x3f); +} + +unsigned unpack_lzh(unsigned char *src, unsigned size, unsigned char *buf) +{ + packed_ptr = src; + packed_end = src + size; + int i, j, k, c; + unsigned count = 0; + StartHuff(); + + // while (count < textsize) // textsize - sizeof unpacked data + while (packed_ptr < packed_end) + { + c = DecodeChar(); + if (c < 256) + { + *buf++ = c; + text_buf[r++] = c; + r &= (N - 1); + count++; + } + else { + i = (r - DecodePosition() - 1) & (N - 1); + j = c - 255 + THRESHOLD; + for (k = 0; k < j; k++) + { + c = text_buf[(i + k) & (N - 1)]; + *buf++ = c; + text_buf[r++] = c; + r &= (N - 1); + count++; + } + } + } + return count; +} + +//-------------------------------------------------------------------------- + +extern "C" int x2trd(char *name, fileTYPE *f) +{ + TDiskImage *img = new TDiskImage; + img->Open(getFullPath(name), true); + + if (!FileOpenEx(f, "vtrd", -1)) + { + delete img; + printf("ERROR: fail to create /vtrd\n"); + return 0; + } + + img->writeTRD(f->fd); + delete(img); + + struct stat64 st; + int ret = fstat64(f->fd, &st); + if (ret < 0) + { + printf("x2trd(fstat) error: %d.\n", ret); + FileClose(f); + return 0; + } + + f->size = st.st_size; + FileSeekLBA(f, 0); + printf("x2trd: vtrd size=%llu.\n", f->size); + + return 1; +} + +extern "C" int x2trd_ext_supp(char *name) +{ + const char *ext = ""; + if (strlen(name) > 4) ext = name + strlen(name) - 4; + return (!strcasecmp(ext, ".scl") || !strcasecmp(ext, ".fdi") || !strcasecmp(ext, ".udi")); +} diff --git a/DiskImage.h b/DiskImage.h new file mode 100644 index 0000000..986ecf0 --- /dev/null +++ b/DiskImage.h @@ -0,0 +1,206 @@ +#ifndef __DISKIMAGE_H +#define __DISKIMAGE_H +//----------------------------------------------------------------------------- + +#ifdef __cplusplus + +enum TDiskImageType { DIT_UNK, DIT_TRD, DIT_SCL, DIT_FDI, DIT_TD0, DIT_UDI, DIT_HOB, DIT_FDD }; + +struct VGFIND_TRACK +{ + unsigned char *TrackPointer; + unsigned char *ClkPointer; + unsigned int TrackLength; + bool FoundTrack; +}; + + +struct VGFIND_ADM +{ + unsigned char* TrackPointer; + unsigned char* ClkPointer; + unsigned int TrackLength; + + unsigned char *ADMPointer; + unsigned int ADMLength; + + unsigned int MarkedOffsetADM; + unsigned int OffsetADM; + unsigned int OffsetEndADM; + bool FoundADM; + bool CRCOK; +}; + + +struct VGFIND_SECTOR +{ + VGFIND_ADM vgfa; + + unsigned char *SectorPointer; + unsigned int SectorLength; + + unsigned int MarkedOffsetSector; + unsigned int OffsetSector; + unsigned int OffsetEndSector; + bool FoundDATA; + bool CRCOK; + unsigned char DataMarker; +}; + + +class TDiskImage +{ + unsigned int FTrackLength[256][256]; + unsigned char* FTracksPtr[256][256][2]; + + unsigned char FFileName[4096]; + TDiskImageType FType; + unsigned char Fdefbuf[16384]; + + unsigned short MakeVGCRC(unsigned char *data, unsigned long length); +public: + bool Changed; + + bool ReadOnly; + bool DiskPresent; + unsigned char MaxTrack; + unsigned char MaxSide; + + bool AddBOOT; + + TDiskImage(); + ~TDiskImage(); + + bool FindTrack(unsigned char CYL, unsigned char SIDE, VGFIND_TRACK *vgft); + bool FindADMark(unsigned char CYL, unsigned char SIDE, + unsigned int FromOffset, + VGFIND_ADM *vgfa); + bool FindSector(unsigned char CYL, unsigned char SIDE, + unsigned char SECT, + VGFIND_SECTOR *vgfs, unsigned int FromOffset=0); + void ApplySectorCRC(VGFIND_SECTOR vgfs); + + + void FlushImage(); + void Open(const char *filename, bool ReadOnly); + char* GetDiskFileName() {return (char*)FFileName; } + + void readTRD(int hfile, bool readonly); + void writeTRD(int hfile); + void readSCL(int hfile, bool readonly); + void writeSCL(int hfile); + void readFDI(int hfile, bool readonly); + void writeFDI(int hfile); + void readUDI(int hfile, bool readonly); + void writeUDI(int hfile); + void readTD0(int hfile, bool readonly); + void writeTD0(int hfile); + void readFDD(int hfile, bool readonly); + void writeFDD(int hfile); + void readHOB(int hfile); + + void formatTRDOS(unsigned int tracks, unsigned int sides); + + void ShowError(const char *str); +}; + +#pragma pack(1) +struct UDI_HEADER // 16 bytes +{ + unsigned char ID[4]; + unsigned long UnpackedLength; + unsigned char Version; + unsigned char MaxCylinder; + unsigned char MaxSide; + unsigned char _zero; + unsigned long ExtHdrLength; +}; + +struct TD0_MAIN_HEADER // 12 bytes +{ + char ID[2]; // +0: "TD" - 'Normal'; "td" - packed LZH ('New Advanced data compression') + unsigned char __t; // +2: = 0x00 + unsigned char __1; // +3: ??? + unsigned char Ver; // +4: Source version (1.0 -> 10, ..., 2.1 -> 21) + unsigned char __2; // +5: ??? + unsigned char DiskType; // +6: Source disk type + unsigned char Info; // +7: D7-­ «ЁзЁҐ image info + unsigned char DataDOS; // +8: if(=0)'All sectors were copied', else'DOS Allocated sectors were copied' + unsigned char ChkdSides; // +9: if(=1)'One side was checked', else'Both sides were checked' + unsigned short CRC; // +A: CRC еЁ¤Ґа  TD0_MAIN_HEADER (Єа®¬Ґ Ў ©в б CRC) +}; + +struct TD0_INFO_DATA // 10 Ў ©в ЎҐ§ бва®ЄЁ Є®¬Ґ­в аЁп... +{ + unsigned short CRC; // +0: CRC ¤«п бвагЄвгал COMMENT_DATA (ЎҐ§ Ў ©в®ў CRC) + unsigned short strLen; // +2: „«Ё­  бва®ЄЁ Є®¬Ґ­в аЁп + unsigned char Year; // +4: „ в  б®§¤ ­Ёп - Ј®¤ (1900 + X) + unsigned char Month; // +5: „ в  б®§¤ ­Ёп - ¬Ґбпж (џ­ў ам=0, ”Ґўа «м=1,...) + unsigned char Day; // +6: „ в  б®§¤ ­Ёп - зЁб«® + unsigned char Hours; // +7: ‚६п б®§¤ ­Ёп - з бл + unsigned char Minutes; // +8: ‚६п б®§¤ ­Ёп - ¬Ё­гвл + unsigned char Seconds; // +9: ‚६п б®§¤ ­Ёп - ᥪ㭤л +}; + +struct TD0_TRACK_HEADER // 4 bytes +{ + unsigned char SectorCount; + unsigned char Track; + unsigned char Side; + unsigned char CRCL; +}; + +struct TD0_SECT_HEADER // 8 bytes +{ + unsigned char ADRM[6]; + unsigned short DataLength; +}; + +struct FDD_MAIN_HEADER +{ + char ID[30]; /* бЁЈ­ вга  */ + unsigned char MaxTracks; /* зЁб«® в४®ў (жЁ«Ё­¤а®ў) */ + unsigned char MaxHeads; /* зЁб«® Ј®«®ў®Є (1 Ё«Ё 2) */ + long diskIndex; /* unused */ + long DataOffset[512*2]; /* ᬥ饭ЁҐ ў д ©«Ґ Є бвагЄвга ¬ § Ј®«®ўЄ®ў */ + /* в४®ў */ +}; + +struct FDD_TRACK_HEADER +{ + unsigned char trkType; /* unused */ + unsigned char SectNum; /* зЁб«® ᥪв®а®ў ­  в४Ґ */ + struct + { + /* § Ј®«®ў®Є ᥪв®а  */ + unsigned char trk; /* ­®¬Ґа в४  */ + unsigned char side; /* ­®¬Ґа бв®а®­л */ + /* 7 ЎЁв нв®Ј® Ў ©в  гЄ §лў Ґв ЎЁв a */ + unsigned char sect; /* ­®¬Ґа ᥪв®а  */ + unsigned char size; /* а §¬Ґа ᥪв®а  (Є®¤) */ + long SectPos; /* ᬥ饭ЁҐ ў д ©«Ґ Є ¤ ­­л¬ ᥪв®а  */ + } sect[256]; +}; + + +struct TRDOS_DIR_ELEMENT // 16 bytes +{ + char FileName[8]; + char Type; + unsigned short Start; + unsigned short Length; + unsigned char SecLen; + unsigned char FirstSec; + unsigned char FirstTrk; +}; +#pragma pack() + +#else + +int x2trd(char *name, fileTYPE *f); +int x2trd_ext_supp(char *name); + +#endif + +//----------------------------------------------------------------------------- +#endif \ No newline at end of file diff --git a/Makefile b/Makefile index e177431..ea68904 100644 --- a/Makefile +++ b/Makefile @@ -11,16 +11,18 @@ STRIP = $(BASE)-strip PRJ = MiSTer SRC = $(wildcard *.c) +SRC2 = $(wildcard *.cpp) -OBJ = $(SRC:.c=.o) -DEP = $(SRC:.c=.d) +OBJ = $(SRC:.c=.o) $(SRC2:.cpp=.o) +DEP = $(SRC:.c=.d) $(SRC2:.cpp=.d) CFLAGS = $(DFLAGS) -c -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DVDATE=\"`date +"%y%m%d"`\" -LFLAGS = -lc +LFLAGS = -lc -lstdc++ -lrt $(PRJ): $(OBJ) @$(info $@) @$(LD) $(LFLAGS) -o $@ $+ + @cp $@ $@.elf @$(STRIP) $@ clean: @@ -31,9 +33,16 @@ clean: @$(info $<) @$(CC) $(CFLAGS) -o $@ -c $< 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):\([0-9]\+\):/\1(\2,\ \3):/g' +%.o: %.cpp + @$(info $<) + @$(CC) $(CFLAGS) -o $@ -c $< 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):\([0-9]\+\):/\1(\2,\ \3):/g' + -include $(DEP) %.d: %.c @$(CC) $(DFLAGS) -MM $< -MT $@ -MT $*.o -MF $@ 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):\([0-9]\+\):/\1(\2,\ \3):/g' +%.d: %.cpp + @$(CC) $(DFLAGS) -MM $< -MT $@ -MT $*.o -MF $@ 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):\([0-9]\+\):/\1(\2,\ \3):/g' + # Ensure correct time stamp main.o: $(filter-out main.o, $(OBJ)) diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index 31b8657..78c6a0b 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -42,6 +42,7 @@ + @@ -66,6 +67,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index b829b6c..cec2238 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -71,6 +71,9 @@ Source Files + + Source Files + @@ -157,6 +160,9 @@ Header Files + + Header Files + diff --git a/user_io.c b/user_io.c index bdb349e..6fc8396 100644 --- a/user_io.c +++ b/user_io.c @@ -21,6 +21,7 @@ #include "menu.h" #include "x86.h" #include "tzx2wav.h" +#include "DiskImage.h" #define BREAK 0x8000 @@ -591,9 +592,18 @@ void user_io_set_index(unsigned char index) int user_io_file_mount(int num, char *name) { - int writable = FileCanWrite(name); + int writable = 0; + int ret = 0; + if (x2trd_ext_supp(name)) + { + ret = x2trd(name, sd_image+num); + } + else + { + writable = FileCanWrite(name); + ret = FileOpenEx(&sd_image[num], name, writable ? (O_RDWR | O_SYNC) : O_RDONLY); + } - int ret = FileOpenEx(&sd_image[num], name, writable ? (O_RDWR | O_SYNC) : O_RDONLY); if (!ret) { writable = 0;