protected byte[] GetChecksum(SectorInfo sector, bool header) { ushort crc = 0; int mask = (sector.errorCode & 0x18) | (header ? 1 : 0); switch (mask) { case 0: case 0x18: crc = sector.calcDataCRC; break; case 1: case 0x9: crc = sector.calcHeaderCRC; break; case 0x8: crc = sector.imgDataCRC; break; case 0x19: crc = sector.imgHeaderCRC; break; } byte[] crcBytes = BitConverter.GetBytes(crc); return(crcBytes); }
protected int WriteChecksum(BinaryWriter writer, SectorInfo sector, bool header) { byte[] crcBytes = GetChecksum(sector, header); writer.Write(crcBytes[1]); writer.Write(crcBytes[0]); // in Big Endian return(2); }
private int FindDataMark(byte[] contents, SectorInfo sector, int offset, out int markPos) { byte mark = 0xfb; int pos = -1; bool done = false; int searchOffset = offset; do { pos = FindMark(contents, searchOffset, dataMark, 0, out markPos); mark = contents[searchOffset + markPos + 3]; if ((mark & 0xfc) == 0xf8) { done = true; if (mark == 0xf8) { sector.errorCode |= 0x20; // dam deleted } } else { searchOffset += (markPos + 4); } } while (!done); markPos += (searchOffset - offset); return(pos + (searchOffset - offset)); }
private PhysicalContents Analyse() { PhysicalContents _contents = new PhysicalContents(); byte[] contents = File.ReadAllBytes(_filename); int bytesPerSector = contents[11] + (contents[12] << 8); int sectorsPerTrack = contents[24] + (contents[25] << 8); int sides = contents[26] + (contents[27] << 8); byte diskFormat = contents[21]; int trackSize = bytesPerSector * sectorsPerTrack; int numTracks = contents.Length / (trackSize * sides); for (int trk = 0; trk < numTracks; trk++) { TrackInfo info = new TrackInfo(); for (int side = 0; side < sides; side++) { TrackSide ts = new TrackSide(); for (int sector = 0; sector < sectorsPerTrack; sector++) { SectorInfo sec = new SectorInfo(); sec.contents = new byte[bytesPerSector]; int index = (((trk * sides) + side) * trackSize) + (sector * bytesPerSector); Array.Copy(contents, index, sec.contents, 0, bytesPerSector); ts.sectors.Add(sec); } info.sides.Add(ts); } _contents.tracks.Add(info); } FillPhysicalDefaults(_contents, bytesPerSector, diskFormat); return(_contents); }
private bool UpdateCRCs(TrackSide track, byte[] trackData, List <int> dataStarts) { Dictionary <SectorInfo, bool> sectorsToUpdate = new Dictionary <SectorInfo, bool>(); int sectNum = 0; int numSect = track.sectors.Count; bool succes = true; foreach (SectorInfo sector in track.sectors) { int sectorOffset = 1; bool done = false; int SectorSize = SectorSizeFromCode(sector.sizecode); bool overlapCRC = (sector.contents.Length != SectorSize) && ((sector.errorCode & 0x18) == 0); if ((overlapCRC) || (sectorsToUpdate.ContainsKey(sector))) { ushort crc = CalcCRC16(trackData, dataStarts[sectNum] - 4, SectorSize + 4); if (overlapCRC) { while (!done) { SectorInfo nextSector = track.sectors[sectNum + sectorOffset]; if ((SectorSize + dataStarts[sectNum]) < dataStarts[sectNum + sectorOffset] + nextSector.contents.Length) // falls within this sector? { if ((SectorSize + dataStarts[sectNum]) >= dataStarts[sectNum + sectorOffset]) { sectorsToUpdate[nextSector] = true; } else { // to do, use gap info succes = false; } done = true; } else { sectorOffset++; if ((sectNum + sectorOffset) == numSect) // lead out gap { done = true; } } } } if (succes) { trackData[dataStarts[sectNum] + SectorSize] = (byte)((crc & 0xFF00) >> 8); trackData[dataStarts[sectNum] + SectorSize + 1] = (byte)((crc & 0xFF)); } } sectNum++; } return(succes); }
private PhysicalContents Analyze() { PhysicalContents _contents = new PhysicalContents(); byte[] contents = File.ReadAllBytes(_filename); int NumTrackBlocks = contents.Length / 0x2B00; _contents.diskformat = contents[0x08]; bool DS = ((_contents.diskformat & 1) == 1); for (int i = 0; i < NumTrackBlocks; i++) { TrackInfo trackInfo = new TrackInfo(); for (int j = 0; j < 2; j++) { TrackSide trackside = new TrackSide(); if (!DS || j == 0) { trackInfo = new TrackInfo(); trackInfo.sides = new List <TrackSide>(); _contents.tracks.Add(trackInfo); } trackInfo.sides.Add(trackside); int PhysTrack = DS ? i : i / 2; int PhysHead = DS ? j : 0; trackInfo.sides[PhysHead] = trackside; trackside.physicalTrackNr = PhysTrack; trackside.HeadNr = PhysHead; trackside.sectors = new List <SectorInfo>(); long adr = (i * 0x2B00) + j * 0x180; trackside.diskformat = contents[adr + 0x08]; int Sectors = contents[adr + 0x09]; trackside.flag = contents[adr + 0x0A]; trackside.gaps = new Gap[5]; for (int k = 0; k < 5; k++) { trackside.gaps[k] = new Gap(((contents[adr + (k * 2) + 0x11]) << 8) + (contents[adr + (k * 2) + 0x10]), contents[adr + k + 0x0B]); } long dataAddr = (i * 0x2B00) + 0x300 + (j * 0x1400); long sectOffset = 0; for (int sect = 0; sect < Sectors; sect++) { SectorInfo sectInfo = AnalyzeSector(contents, dataAddr + sectOffset, adr, sect); sectOffset += sectInfo.contents.Length; trackside.sectors.Add(sectInfo); } } } return(_contents); }
public void WriteExtractedSector(string filename, int num, SectorInfo sector) { string outputName = filename; if (num > 0) { outputName += num.ToString(); } FileStream outputStream = new FileStream(outputName, FileMode.Create); BinaryWriter writer = new BinaryWriter(outputStream); writer.Write(sector.contents, 0, SectorSizeFromCode(sector.sizecode)); writer.Close(); }
private void FixOverlappedGap(TrackSide track) { bool done = false; int numSectors = track.sectors.Count; for (int i = 0; !done && (i < numSectors); i++) { SectorInfo sector = track.sectors[i]; if (sector.contents.Length != SectorSizeFromCode(sector.sizecode)) { track.gaps[3].Size = sector.gaps[1]; track.gaps[3].Filler = sector.gapFillers[1]; if (track.sectors.Count > (i + 1)) { track.gaps[2].Size = track.sectors[i + 1].gaps[0]; track.gaps[2].Filler = track.sectors[i + 1].gapFillers[0]; } done = true; } } }
private SectorInfo AnalyzeSector(byte[] contents, long dataOffset, long adr, int sect) { SectorInfo sectorData = new SectorInfo(); sectorData.track = contents[adr + 0x1A + sect]; sectorData.head = contents[adr + 0x38 + sect]; sectorData.sector = contents[adr + 0x56 + sect]; sectorData.sizecode = contents[adr + 0x74 + sect]; int sectsize = SectorSizeFromCode(sectorData.sizecode); sectorData.imgHeaderCRC = (ushort)(((contents[adr + 0x92 + sect] << 8)) + contents[adr + 0xb0 + sect]); sectorData.errorCode = contents[adr + 0xce + sect]; int realsize = contents[adr + 0xec + (sect * 2)] + ((contents[adr + 0xed + (sect * 2)]) << 8); int sectorLength = sectsize; if (realsize != 0) { sectorLength = realsize; } sectorData.contents = new byte[sectorLength]; sectorData.dam = 0xfb; if ((sectorData.errorCode & 0x20) != 0) // dam deleted ? { sectorData.dam = 0xf8; } ushort crc = 0xffff; CalcCRC16(new byte[] { 0xa1, 0xa1, 0xa1, sectorData.dam }, 0, 4, ref crc); CalcCRC16(contents, dataOffset, sectsize, ref crc); sectorData.calcDataCRC = crc; crc = 0xffff; CalcCRC16(new byte[] { 0xa1, 0xa1, 0xa1, 0xfe, sectorData.track, sectorData.head, sectorData.sector, sectorData.sizecode }, 0, 8, ref crc); sectorData.calcHeaderCRC = crc; Array.Copy(contents, dataOffset, sectorData.contents, 0, sectorLength); sectorData.imgDataCRC = (ushort)(((contents[adr + 0x128 + (sect * 2)]) << 8) + contents[adr + 0x129 + (sect * 2)]); return(sectorData); }
private int WriteSector(BinaryWriter writer, SectorInfo sector, Gap[] gaps) { int DamOffset = -1; Stream stream = writer.BaseStream; WriteBytes(writer, 0, 12); WriteBytes(writer, 0xA1, 3); WriteBytes(writer, 0xFE, 1); // address mark WriteBytes(writer, sector.track, 1); WriteBytes(writer, sector.head, 1); WriteBytes(writer, sector.sector, 1); WriteBytes(writer, sector.sizecode, 1); WriteChecksum(writer, sector, true); WriteGap(writer, gaps[2]); WriteBytes(writer, 0, 12); WriteBytes(writer, 0xA1, 3); if ((sector.errorCode & 0x20) == 0) { WriteBytes(writer, 0xFB, 1); // data mark } else { WriteBytes(writer, 0xF8, 1); // deleted data mark } DamOffset = (int)stream.Position; writer.Write(sector.contents, 0, sector.contents.Length); if (sector.contents.Length != SectorSizeFromCode(sector.sizecode)) { WriteBytes(writer, 0, 2); // just use zero, it's not the right position for the checksum } else { WriteChecksum(writer, sector, false); } WriteGap(writer, gaps[3]); return(DamOffset); }
public void WriteExtractedSector(String filename, int track, int head, int blockOrSector, bool isSectorNumber) { if (blockOrSector == 0) { WriteExractedTrack(filename, track, head); } else if (isSectorNumber) { int count = 0; foreach (SectorInfo sector in Contents.physical.tracks[track].sides[head].sectors) { if (sector.sector == blockOrSector) { WriteExtractedSector(filename, count, sector); count++; } } } else { SectorInfo sector = Contents.physical.tracks[track].sides[head].sectors[blockOrSector]; WriteExtractedSector(filename, 0, sector); } }
private void AnalyzeTrack(TrackSide track, byte[] contents, int offset, int tracksize) { int markPos; int startTrack = offset; List <int> IDAMS = new List <int>(); int index = 0; while ((index < 64) && GetMultiByteVal(contents, offset + (index * 2), 2, false) != 0) { int idam = (int)GetMultiByteVal(contents, offset + (index * 2), 2, false); IDAMS.Add(idam); index++; } IDAMS.Add(0); // add end marker index = offset + 128; // end of IDAM block int trackstart = index; int pos = FindMark(contents, index, indexMark, startTrack + (IDAMS[0] & 0x3FFF), out markPos); if (pos != -1) { track.gaps[0].Size = pos; track.gaps[0].Filler = FindMostOccuringByte(contents, index, pos); index += markPos + 4; } int count = 0; foreach (int idam in IDAMS) { if (idam != 0) { int nextIdamOffset = 0; if (IDAMS[count + 1] > 0) { nextIdamOffset = (IDAMS[count + 1] & 0x3FFF) + startTrack; } else { nextIdamOffset = (startTrack + tracksize) * -1; // negative to indicate start of next track instead } SectorInfo sector = AnalyzeSector(contents, track, ref index, count + 1, nextIdamOffset); if (sector != null) { track.sectors.Add(sector); } count++; } } if (count > 0) { track.gaps[2].Size /= count; } if (count > 1) { track.gaps[3].Size /= (count - 1); } else { track.gaps[3].Size = 54; // set to default } if (track.sectors.Count > 0) { track.sectors[track.sectors.Count - 1].gaps[1] = track.gaps[3].Size; track.sectors[track.sectors.Count - 1].gapFillers[1] = FindMostOccuringByte(contents, index, track.gaps[3].Size); } if ((index + track.gaps[3].Size) < (startTrack + tracksize)) { index += track.gaps[3].Size; } track.gaps[4].Size = tracksize - (index - trackstart) - 128; track.gaps[4].Filler = FindMostOccuringByte(contents, index, (tracksize + startTrack) - index); if (track.gaps[0].Size > 4) { track.gaps[0].Size -= 4; } FixOverlappedGap(track); }
private SectorInfo AnalyzeSector(byte[] contents, TrackSide track, ref int index, int sectorBlock, int nextIdamOffset) { int markPos; SectorInfo sector = new SectorInfo(); int offset = 0; int pos = FindMark(contents, index + offset, addressMark, 0, out markPos); if (sectorBlock == 1) { track.gaps[1].Size = pos; track.gaps[1].Filler = FindMostOccuringByte(contents, index, pos); } else { track.gaps[3].Size += (pos); byte filler = FindMostOccuringByte(contents, index, pos); if (track.sectors.Count > (sectorBlock - 2)) { track.sectors[sectorBlock - 2].gaps[1] = pos; track.sectors[sectorBlock - 2].gapFillers[1] = filler; } if (sectorBlock == 2) // if we're at the 2nd sector, we're actually looking for the endgap of the first sector { track.gaps[3].Filler = filler; } } index += markPos + 4; sector.track = contents[index++]; sector.head = contents[index++]; sector.sector = contents[index++]; sector.sizecode = contents[index++]; int size = SectorSizeFromCode(sector.sizecode); sector.calcHeaderCRC = CalcCRC16(new byte[] { 0xa1, 0xa1, 0xa1, 0xfe, sector.track, sector.head, sector.sector, sector.sizecode }, 0, 8); sector.imgHeaderCRC = (ushort)GetMultiByteVal(contents, index, 2, true); index += 2; pos = FindDataMark(contents, sector, index, out markPos); if ((nextIdamOffset <= 0) || ((index + pos) < nextIdamOffset)) { sector.dam = contents[index + markPos + 3]; track.gaps[2].Size += pos; sector.gaps[0] = pos; sector.gapFillers[0] = FindMostOccuringByte(contents, index, pos); if (sectorBlock == 1) { track.gaps[2].Filler = sector.gapFillers[0]; } index += markPos + 4; ushort dataCRC = CalcCRC16(new byte[] { 0xa1, 0xa1, 0xa1, sector.dam }, 0, 4); CalcCRC16(contents, index, size, ref dataCRC); sector.calcDataCRC = dataCRC; int realSize = FindRealDataSize(contents, size, index, nextIdamOffset); sector.contents = new byte[realSize]; Array.Copy(contents, index, sector.contents, 0, realSize); sector.imgDataCRC = (ushort)GetMultiByteVal(contents, index + size, 2, true); index += realSize; if (sector.calcHeaderCRC != sector.imgHeaderCRC) { sector.errorCode |= 0x18; } else if (sector.calcDataCRC != sector.imgDataCRC) { sector.errorCode |= 0x08; } index += 2; // checksum } else { sector = null; // ignore this one for now. } return(sector); }