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); }
protected Gap[] GetNormalizedGaps(TrackSide track, int maxSize) { Gap[] gaps = new Gap[5]; track.gaps[0].Size += 4; // adding 4 equals the gap to openMSX/DskPro for (int i = 0; i < 5; i++) { gaps[i] = new Gap(track.gaps[i]); } int trackSize = GetTrackSize(track); int oversize = trackSize - maxSize; if (oversize > 0) { oversize -= reduceGaps(oversize, gaps, new int[] { 4 }, new int[] { 100 }); } if (oversize > 0) { int sectors = track.sectors.Count; if (sectors > 0) { oversize -= (sectors * reduceGaps((oversize / sectors) + 1, gaps, new int[] { 3, 2 }, new int[] { 20, 20 })); } } if (oversize > 0) { // Utils.Multiprint(String.Format("Can't reduce track {0}, head {1} from {2} to {3}", track.physicalTrackNr, track.HeadNr, trackSize, maxSize),true); } if (oversize < 0) { gaps[4].Size -= oversize; // just put any oversize in the lead out gap } return(gaps); }
private void WriteTrackData(BinaryWriter writer, TrackSide track, int tracksize, Gap[] gaps) { List <int> dataStarts = new List <int>(); byte[] trackData = new byte[tracksize]; MemoryStream stream = new MemoryStream(trackData); BinaryWriter memWriter = new BinaryWriter(stream); WriteGap(memWriter, gaps[0]); WriteBytes(memWriter, 0, 12); WriteBytes(memWriter, 0xC2, 3); WriteBytes(memWriter, 0xFC, 1); // index mark WriteGap(memWriter, gaps[1]); foreach (SectorInfo sect in track.sectors) { int dam = WriteSector(memWriter, sect, gaps); dataStarts.Add(dam); } WriteGap(memWriter, gaps[4]); long testPos = stream.Position; memWriter.Close(); UpdateCRCs(track, trackData, dataStarts); writer.Write(trackData); }
protected override void WriteExractedTrack(string filename, int trackNr, int headNr) { int maxTrackSize = FindMaxTrackSize(); FileStream outputStream = new FileStream(filename, FileMode.Create); BinaryWriter writer = new BinaryWriter(outputStream); TrackSide track = Contents.physical.tracks[trackNr].sides[headNr]; WriteTrackData(writer, track, maxTrackSize, GetNormalizedGaps(track, maxTrackSize)); }
private int GetTrackSize(TrackSide track) { int trackSize = 16 + track.gaps[0].Size + track.gaps[1].Size + track.gaps[4].Size; foreach (SectorInfo sect in track.sectors) { trackSize += (40 + track.gaps[2].Size + track.gaps[3].Size + sect.contents.Length); } return(trackSize); }
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 void WriteTrack(BinaryWriter writer, TrackSide track, int tracksize) { if (track == null) { WriteBytes(writer, 0, tracksize + 128); } else { Gap[] gaps = GetNormalizedGaps(track, MaxTrackSize); WriteIDAMBlock(writer, track, tracksize, gaps); WriteTrackData(writer, track, tracksize, gaps); } }
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); }
private PhysicalContents Analyze() { PhysicalContents _contents = new PhysicalContents(); byte[] contents = File.ReadAllBytes(_filename); int numTracks = contents[0x01]; int trackSize = contents[0x02] + (contents[0x03] << 8); bool SSOnly = (contents[0x04] & 0x10) == 0x10; // ignore the rest for now for (int t = 0; t < numTracks; t++) { TrackInfo track = new TrackInfo(); for (int s = 0; s < 2; s++) { TrackSide side = new TrackSide(); side.physicalTrackNr = t; side.HeadNr = s; int headerOffset = ((t * 2) + s) * trackSize + 0x10; AnalyzeTrack(side, contents, headerOffset, trackSize); track.sides.Add(side); } _contents.tracks.Add(track); } TrackSide track0 = _contents.tracks[0].sides[0]; _contents.diskformat = 0xFC; foreach (SectorInfo sector in track0.sectors) { if (sector.sector == 1) // found the boot { _contents.diskformat = sector.contents[0x15]; } } if (SSOnly) { _contents.diskformat |= 0x01; // force double sided } if (numTracks > 42) { _contents.diskformat &= 0xFB; // force 80 tracks } foreach (TrackInfo track in _contents.tracks) { foreach (TrackSide side in track.sides) { side.diskformat = _contents.diskformat; } } return(_contents); }
private byte[] readSector(int track, int head, byte sector) { byte[] retVal = null; TrackSide ts = Contents.physical.tracks[track].sides[head]; int numSectors = ts.sectors.Count; for (int sect = 0; (retVal == null) && (sect < numSectors); sect++) { if (ts.sectors[sect].sector == sector) { retVal = ts.sectors[sect].contents; } } return(retVal); }
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 void WriteIDAMBlock(BinaryWriter writer, TrackSide track, int tracksize, Gap[] gaps) { int sectBlock = 0; int totalSectorContent = 0; foreach (SectorInfo sect in track.sectors) { int IDAMpos = totalSectorContent + +128 // IDAM pointer block + gaps[0].Size + gaps[1].Size + 16 // 12x0 + 3xF6 + 1xFC + 15 // IDAM position within the "per sector" block + (sectBlock * (gaps[2].Size + gaps[3].Size + 40 // 12x0 + 3*A1 + 1xFE + track/head/sector/size(4) + 2*checksum(4) + 12x0 + 3xA1 + 1xFB ) ); writer.Write((ushort)(IDAMpos | 0x8000)); sectBlock++; totalSectorContent += sect.contents.Length; } WriteBytes(writer, 0, (64 - sectBlock) * 2); // rest of IDAM block }
private void WritePDI(string filename) { PhysicalContents _contents = Contents.physical; byte[] buffer = new byte[0x180]; FileStream outputStream = new FileStream(filename, FileMode.Create); BinaryWriter writer = new BinaryWriter(outputStream); int numTracks = _contents.tracks.Count; int numSides = (_contents.diskformat & 1) + 1; if ((numSides == 1) && ((numTracks % 2) == 1)) // we can't have an odd track { TrackInfo track = new TrackInfo(); track.sides.Add(new TrackSide()); _contents.tracks.Add(track); } int numBlocks = numTracks * numSides; for (int block = 0; block < numBlocks; block += 2) { for (int i = 0; i < 2; i++) { Array.Clear(buffer, 0, 0x180); int track = (block + i) / numSides; int side = (block + i) % numSides; TrackSide ts = _contents.tracks[track].sides[side]; Array.Copy(new ASCIIEncoding().GetBytes("PDI-MSX"), 0, buffer, 0, 7); buffer[0x07] = 0x20; buffer[0x08] = _contents.diskformat; buffer[0x09] = (byte)ts.sectors.Count; buffer[0x0a] = (byte)1; for (int g = 0; g < 5; g++) { buffer[0x0b + g] = (byte)ts.gaps[g].Filler; buffer[0x10 + (g * 2)] = (byte)(ts.gaps[g].Size & 0xFF); buffer[0x11 + (g * 2)] = (byte)((ts.gaps[g].Size & 0xFF00) >> 8); } int count = 0; foreach (SectorInfo sector in ts.sectors) { buffer[0x1A + count] = sector.track; buffer[0x38 + count] = sector.head; buffer[0x56 + count] = sector.sector; buffer[0x74 + count] = sector.sizecode; buffer[0x92 + count] = (byte)((sector.imgHeaderCRC & 0xFF00) >> 8); buffer[0xb0 + count] = (byte)(sector.imgHeaderCRC & 0xFF); buffer[0xce + count] = sector.errorCode; int dataSize = SectorSizeFromCode(sector.sizecode); int realSize = 0; if (sector.contents.Length != dataSize) { realSize = sector.contents.Length; if (realSize == 0) { realSize = 1; // PDI doesn't support a zero size sector. } } buffer[0xec + (2 * count)] = (byte)(realSize & 0xFF); buffer[0xed + (2 * count)] = (byte)((realSize & 0xFF00) >> 8); buffer[0x128 + (2 * count)] = (byte)(sector.imgDataCRC & 0xFF); buffer[0x129 + (2 * count)] = (byte)((sector.imgDataCRC & 0xFF00) >> 8); count++; } writer.Write(buffer, 0, 0x180); } for (int i = 0; i < 2; i++) { int track = (block + i) / numSides; int side = (block + i) % numSides; TrackSide ts = _contents.tracks[track].sides[side]; int byteCount = 0; foreach (SectorInfo sector in ts.sectors) { writer.Write(sector.contents, 0, sector.contents.Length); byteCount += sector.contents.Length; } WriteBytes(writer, 0xF7, (0x1400 - byteCount)); } } }
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); }