Files
Main/DiskImage.cpp

3093 lines
84 KiB
C++

#include <unistd.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#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"));
}