/// <summary> /// Attempts to parse incoming disk data /// </summary> /// <returns> /// TRUE: disk parsed /// FALSE: unable to parse disk /// </returns> public override bool ParseDisk(byte[] data) { // look for standard magic string string ident = Encoding.ASCII.GetString(data, 0, 16); if (!ident.ToUpper().Contains("MV - CPC")) { // incorrect format return(false); } // read the disk information block DiskHeader.DiskIdent = ident; DiskHeader.DiskCreatorString = Encoding.ASCII.GetString(data, 0x22, 14); DiskHeader.NumberOfTracks = data[0x30]; DiskHeader.NumberOfSides = data[0x31]; DiskHeader.TrackSizes = new int[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides]; DiskTracks = new Track[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides]; DiskData = data; int pos = 0x32; if (DiskHeader.NumberOfSides > 1) { StringBuilder sbm = new StringBuilder(); sbm.AppendLine(); sbm.AppendLine(); sbm.AppendLine("The detected disk image contains multiple sides."); sbm.AppendLine("This is NOT currently supported in CPCHawk."); sbm.AppendLine("Please find an alternate image/dump where each side has been saved as a separate *.dsk image (and use the multi-disk bundler tool to load into Bizhawk)."); throw new System.NotImplementedException(sbm.ToString()); } // standard CPC format all track sizes are the same in the image for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++) { DiskHeader.TrackSizes[i] = MediaConverter.GetWordValue(data, pos); } // move to first track information block pos = 0x100; // parse each track for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++) { // check for unformatted track if (DiskHeader.TrackSizes[i] == 0) { DiskTracks[i] = new Track { Sectors = new Sector[0] }; continue; } int p = pos; DiskTracks[i] = new Track(); // track info block DiskTracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12); p += 16; DiskTracks[i].TrackNumber = data[p++]; DiskTracks[i].SideNumber = data[p++]; p += 2; DiskTracks[i].SectorSize = data[p++]; DiskTracks[i].NumberOfSectors = data[p++]; DiskTracks[i].GAP3Length = data[p++]; DiskTracks[i].FillerByte = data[p++]; int dpos = pos + 0x100; // sector info list DiskTracks[i].Sectors = new Sector[DiskTracks[i].NumberOfSectors]; for (int s = 0; s < DiskTracks[i].NumberOfSectors; s++) { DiskTracks[i].Sectors[s] = new Sector { TrackNumber = data[p++], SideNumber = data[p++], SectorID = data[p++], SectorSize = data[p++], Status1 = data[p++], Status2 = data[p++], ActualDataByteLength = MediaConverter.GetWordValue(data, p) }; p += 2; // actualdatabytelength value is calculated now if (DiskTracks[i].Sectors[s].SectorSize == 0) { // no sectorsize specified - DTL will be used at runtime DiskTracks[i].Sectors[s].ActualDataByteLength = DiskHeader.TrackSizes[i]; } else if (DiskTracks[i].Sectors[s].SectorSize > 6) { // invalid - wrap around to 0 DiskTracks[i].Sectors[s].ActualDataByteLength = DiskHeader.TrackSizes[i]; } else if (DiskTracks[i].Sectors[s].SectorSize == 6) { // only 0x1800 bytes are stored DiskTracks[i].Sectors[s].ActualDataByteLength = 0x1800; } else { // valid sector size for this format DiskTracks[i].Sectors[s].ActualDataByteLength = 0x80 << DiskTracks[i].Sectors[s].SectorSize; } // sector data - begins at 0x100 offset from the start of the track info block (in this case dpos) DiskTracks[i].Sectors[s].SectorData = new byte[DiskTracks[i].Sectors[s].ActualDataByteLength]; // copy the data for (int b = 0; b < DiskTracks[i].Sectors[s].ActualDataByteLength; b++) { DiskTracks[i].Sectors[s].SectorData[b] = data[dpos + b]; } // move dpos to the next sector data postion dpos += DiskTracks[i].Sectors[s].ActualDataByteLength; } // move to the next track info block pos += DiskHeader.TrackSizes[i]; } // run protection scheme detector ParseProtection(); return(true); }
/// <summary> /// Attempts to parse incoming disk data /// </summary> /// <param name="diskData"></param> /// <returns> /// TRUE: disk parsed /// FALSE: unable to parse disk /// </returns> public override bool ParseDisk(byte[] data) { // look for standard magic string string ident = Encoding.ASCII.GetString(data, 0, 16); if (!ident.ToUpper().Contains("EXTENDED CPC DSK")) { // incorrect format return(false); } // read the disk information block DiskHeader.DiskIdent = ident; DiskHeader.DiskCreatorString = Encoding.ASCII.GetString(data, 0x22, 14); DiskHeader.NumberOfTracks = data[0x30]; DiskHeader.NumberOfSides = data[0x31]; DiskHeader.TrackSizes = new int[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides]; DiskTracks = new Track[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides]; DiskData = data; int pos = 0x34; if (DiskHeader.NumberOfSides > 1) { StringBuilder sbm = new StringBuilder(); sbm.AppendLine(); sbm.AppendLine(); sbm.AppendLine("The detected disk image contains multiple sides."); sbm.AppendLine("This is NOT currently supported in CPCHawk."); sbm.AppendLine("Please find an alternate image/dump where each side has been saved as a separate *.dsk image (and use the mutli-disk bundler tool to load into Bizhawk)."); throw new System.NotImplementedException(sbm.ToString()); } for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++) { DiskHeader.TrackSizes[i] = data[pos++] * 256; } // move to first track information block pos = 0x100; // parse each track for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++) { // check for unformatted track if (DiskHeader.TrackSizes[i] == 0) { DiskTracks[i] = new Track(); DiskTracks[i].Sectors = new Sector[0]; continue; } int p = pos; DiskTracks[i] = new Track(); // track info block DiskTracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12); p += 16; DiskTracks[i].TrackNumber = data[p++]; DiskTracks[i].SideNumber = data[p++]; DiskTracks[i].DataRate = data[p++]; DiskTracks[i].RecordingMode = data[p++]; DiskTracks[i].SectorSize = data[p++]; DiskTracks[i].NumberOfSectors = data[p++]; DiskTracks[i].GAP3Length = data[p++]; DiskTracks[i].FillerByte = data[p++]; int dpos = pos + 0x100; // sector info list DiskTracks[i].Sectors = new Sector[DiskTracks[i].NumberOfSectors]; for (int s = 0; s < DiskTracks[i].NumberOfSectors; s++) { DiskTracks[i].Sectors[s] = new Sector(); DiskTracks[i].Sectors[s].TrackNumber = data[p++]; DiskTracks[i].Sectors[s].SideNumber = data[p++]; DiskTracks[i].Sectors[s].SectorID = data[p++]; DiskTracks[i].Sectors[s].SectorSize = data[p++]; DiskTracks[i].Sectors[s].Status1 = data[p++]; DiskTracks[i].Sectors[s].Status2 = data[p++]; DiskTracks[i].Sectors[s].ActualDataByteLength = MediaConverter.GetWordValue(data, p); p += 2; // sector data - begins at 0x100 offset from the start of the track info block (in this case dpos) DiskTracks[i].Sectors[s].SectorData = new byte[DiskTracks[i].Sectors[s].ActualDataByteLength]; // copy the data for (int b = 0; b < DiskTracks[i].Sectors[s].ActualDataByteLength; b++) { DiskTracks[i].Sectors[s].SectorData[b] = data[dpos + b]; } // check for multiple weak/random sectors stored if (DiskTracks[i].Sectors[s].SectorSize <= 7) { // sectorsize n=8 is equivilent to n=0 - FDC will use DTL for length int specifiedSize = 0x80 << DiskTracks[i].Sectors[s].SectorSize; if (specifiedSize < DiskTracks[i].Sectors[s].ActualDataByteLength) { // more data stored than sectorsize defines // check for multiple weak/random copies if (DiskTracks[i].Sectors[s].ActualDataByteLength % specifiedSize != 0) { DiskTracks[i].Sectors[s].ContainsMultipleWeakSectors = true; } } } // move dpos to the next sector data postion dpos += DiskTracks[i].Sectors[s].ActualDataByteLength; } // move to the next track info block pos += DiskHeader.TrackSizes[i]; } // run protection scheme detector ParseProtection(); return(true); }