예제 #1
0
파일: DSKImage.cs 프로젝트: tcm1998/Dis
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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));
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
 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);
     }
 }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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;
                }
            }
        }
예제 #12
0
        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
        }
예제 #13
0
        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));
                }
            }
        }
예제 #14
0
        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);
        }
예제 #15
0
        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);
        }