public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track) { if (track == 0) { if (sectorAddress + length > _densitySeparationSectors) { throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); } return(new byte[length * 2352]); } var aaruTrack = new GdiTrack { Sequence = 0 }; foreach (GdiTrack gdiTrack in _discImage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) { aaruTrack = gdiTrack; break; } if (aaruTrack.Sequence == 0) { throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); } if (sectorAddress + length > aaruTrack.Sectors) { throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); } uint sectorOffset; uint sectorSize; uint sectorSkip; switch (aaruTrack.TrackType) { case TrackType.Audio: { sectorOffset = 0; sectorSize = 2352; sectorSkip = 0; break; } case TrackType.CdMode1: { if (aaruTrack.Bps == 2352) { sectorOffset = 0; sectorSize = 2352; sectorSkip = 0; } else { sectorOffset = 0; sectorSize = 2048; sectorSkip = 0; } break; } default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); } byte[] buffer = new byte[sectorSize * length]; ulong remainingSectors = length; if (aaruTrack.Pregap > 0 && sectorAddress < aaruTrack.Pregap) { ulong remainingPregap = aaruTrack.Pregap - sectorAddress; remainingSectors -= length > remainingPregap ? remainingPregap : length; } if (remainingSectors == 0) { return(buffer); } _imageStream = aaruTrack.TrackFilter.GetDataForkStream(); var br = new BinaryReader(_imageStream); long pos = aaruTrack.Offset + (long)((sectorAddress * (sectorOffset + sectorSize + sectorSkip)) - (aaruTrack.Pregap * aaruTrack.Bps)); if (pos < 0) { pos = 0; } br.BaseStream.Seek(pos, SeekOrigin.Begin); if (sectorOffset == 0 && sectorSkip == 0 && remainingSectors == length) { buffer = br.ReadBytes((int)(sectorSize * remainingSectors)); } else if (sectorOffset == 0 && sectorSkip == 0) { byte[] tmp = br.ReadBytes((int)(sectorSize * remainingSectors)); Array.Copy(tmp, 0, buffer, (int)((length - remainingSectors) * sectorSize), tmp.Length); } else { int bufferPos = (int)((length - remainingSectors) * sectorSize); for (ulong i = 0; i < remainingSectors; i++) { br.BaseStream.Seek(sectorOffset, SeekOrigin.Current); byte[] sector = br.ReadBytes((int)sectorSize); br.BaseStream.Seek(sectorSkip, SeekOrigin.Current); Array.Copy(sector, 0, buffer, bufferPos, sectorSize); bufferPos += (int)sectorSize; } } switch (aaruTrack.TrackType) { case TrackType.CdMode1 when aaruTrack.Bps == 2048: { byte[] fullSector = new byte[2352]; byte[] fullBuffer = new byte[2352 * length]; for (uint i = 0; i < length; i++) { Array.Copy(buffer, i * 2048, fullSector, 16, 2048); _sectorBuilder.ReconstructPrefix(ref fullSector, TrackType.CdMode1, (long)(sectorAddress + i)); _sectorBuilder.ReconstructEcc(ref fullSector, TrackType.CdMode1); Array.Copy(fullSector, 0, fullBuffer, i * 2352, 2352); } buffer = fullBuffer; break; } } return(buffer); }
public bool Open(IFilter imageFilter) { if (imageFilter == null) { return(false); } try { imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin); _gdiStream = new StreamReader(imageFilter.GetDataForkStream()); int lineNumber = 0; bool highDensity = false; // Initialize all RegExs var regexTrack = new Regex(REGEX_TRACK); // Initialize all RegEx matches // Initialize disc _discImage = new GdiDisc { Sessions = new List <Session>(), Tracks = new List <GdiTrack>() }; ulong currentStart = 0; _offsetMap = new Dictionary <uint, ulong>(); _densitySeparationSectors = 0; while (_gdiStream.Peek() >= 0) { lineNumber++; string line = _gdiStream.ReadLine(); if (lineNumber == 1) { if (!int.TryParse(line, out _)) { throw new ImageNotSupportedException("Not a correct Dreamcast GDI image"); } } else { Match trackMatch = regexTrack.Match(line ?? throw new InvalidOperationException()); if (!trackMatch.Success) { throw new ImageNotSupportedException($"Unknown line \"{line}\" at line {lineNumber}"); } AaruConsole.DebugWriteLine("GDI plugin", "Found track {0} starts at {1} flags {2} type {3} file {4} offset {5} at line {6}", trackMatch.Groups["track"].Value, trackMatch.Groups["start"].Value, trackMatch.Groups["flags"].Value, trackMatch.Groups["type"].Value, trackMatch.Groups["filename"].Value, trackMatch.Groups["offset"].Value, lineNumber); var filtersList = new FiltersList(); var currentTrack = new GdiTrack { Bps = ushort.Parse(trackMatch.Groups["type"].Value), Flags = byte.Parse(trackMatch.Groups["flags"].Value), Offset = long.Parse(trackMatch.Groups["offset"].Value), Sequence = uint.Parse(trackMatch.Groups["track"].Value), StartSector = ulong.Parse(trackMatch.Groups["start"].Value), TrackFilter = filtersList.GetFilter(Path.Combine(imageFilter.GetParentFolder(), trackMatch.Groups["filename"].Value. Replace("\\\"", "\"").Trim('"'))) }; currentTrack.TrackFile = currentTrack.TrackFilter.GetFilename(); if (currentTrack.StartSector - currentStart > 0) { if (currentTrack.StartSector == 45000) { highDensity = true; _offsetMap.Add(0, currentStart); _densitySeparationSectors = currentTrack.StartSector - currentStart; currentStart = currentTrack.StartSector; } else { currentTrack.Pregap = currentTrack.StartSector - currentStart; currentTrack.StartSector -= currentTrack.StartSector - currentStart; } } if ((currentTrack.TrackFilter.GetDataForkLength() - currentTrack.Offset) % currentTrack.Bps != 0) { throw new ImageNotSupportedException("Track size not a multiple of sector size"); } currentTrack.Sectors = (ulong)((currentTrack.TrackFilter.GetDataForkLength() - currentTrack.Offset) / currentTrack.Bps); currentTrack.Sectors += currentTrack.Pregap; currentStart += currentTrack.Sectors; currentTrack.HighDensity = highDensity; currentTrack.TrackType = (currentTrack.Flags & 0x4) == 0x4 ? TrackType.CdMode1 : TrackType.Audio; _discImage.Tracks.Add(currentTrack); } } Session[] sessions = new Session[2]; for (int s = 0; s < sessions.Length; s++) { if (s == 0) { sessions[s].SessionSequence = 1; foreach (GdiTrack trk in _discImage.Tracks.Where(trk => !trk.HighDensity)) { if (sessions[s].StartTrack == 0) { sessions[s].StartTrack = trk.Sequence; } else if (sessions[s].StartTrack > trk.Sequence) { sessions[s].StartTrack = trk.Sequence; } if (sessions[s].EndTrack < trk.Sequence) { sessions[s].EndTrack = trk.Sequence; } if (sessions[s].StartSector > trk.StartSector) { sessions[s].StartSector = trk.StartSector; } if (sessions[s].EndSector < (trk.Sectors + trk.StartSector) - 1) { sessions[s].EndSector = (trk.Sectors + trk.StartSector) - 1; } } } else { sessions[s].SessionSequence = 2; foreach (GdiTrack trk in _discImage.Tracks.Where(trk => trk.HighDensity)) { if (sessions[s].StartTrack == 0) { sessions[s].StartTrack = trk.Sequence; } else if (sessions[s].StartTrack > trk.Sequence) { sessions[s].StartTrack = trk.Sequence; } if (sessions[s].EndTrack < trk.Sequence) { sessions[s].EndTrack = trk.Sequence; } if (sessions[s].StartSector > trk.StartSector) { sessions[s].StartSector = trk.StartSector; } if (sessions[s].EndSector < (trk.Sectors + trk.StartSector) - 1) { sessions[s].EndSector = (trk.Sectors + trk.StartSector) - 1; } } } } _discImage.Sessions.Add(sessions[0]); _discImage.Sessions.Add(sessions[1]); _discImage.Disktype = MediaType.GDROM; // DEBUG information AaruConsole.DebugWriteLine("GDI plugin", "Disc image parsing results"); AaruConsole.DebugWriteLine("GDI plugin", "Session information:"); AaruConsole.DebugWriteLine("GDI plugin", "\tDisc contains {0} sessions", _discImage.Sessions.Count); for (int i = 0; i < _discImage.Sessions.Count; i++) { AaruConsole.DebugWriteLine("GDI plugin", "\tSession {0} information:", i + 1); AaruConsole.DebugWriteLine("GDI plugin", "\t\tStarting track: {0}", _discImage.Sessions[i].StartTrack); AaruConsole.DebugWriteLine("GDI plugin", "\t\tStarting sector: {0}", _discImage.Sessions[i].StartSector); AaruConsole.DebugWriteLine("GDI plugin", "\t\tEnding track: {0}", _discImage.Sessions[i].EndTrack); AaruConsole.DebugWriteLine("GDI plugin", "\t\tEnding sector: {0}", _discImage.Sessions[i].EndSector); } AaruConsole.DebugWriteLine("GDI plugin", "Track information:"); AaruConsole.DebugWriteLine("GDI plugin", "\tDisc contains {0} tracks", _discImage.Tracks.Count); for (int i = 0; i < _discImage.Tracks.Count; i++) { AaruConsole.DebugWriteLine("GDI plugin", "\tTrack {0} information:", _discImage.Tracks[i].Sequence); AaruConsole.DebugWriteLine("GDI plugin", "\t\t{0} bytes per sector", _discImage.Tracks[i].Bps); AaruConsole.DebugWriteLine("GDI plugin", "\t\tPregap: {0} sectors", _discImage.Tracks[i].Pregap); if ((_discImage.Tracks[i].Flags & 0x8) == 0x8) { AaruConsole.DebugWriteLine("GDI plugin", "\t\tTrack is flagged as quadraphonic"); } if ((_discImage.Tracks[i].Flags & 0x4) == 0x4) { AaruConsole.DebugWriteLine("GDI plugin", "\t\tTrack is data"); } if ((_discImage.Tracks[i].Flags & 0x2) == 0x2) { AaruConsole.DebugWriteLine("GDI plugin", "\t\tTrack allows digital copy"); } if ((_discImage.Tracks[i].Flags & 0x1) == 0x1) { AaruConsole.DebugWriteLine("GDI plugin", "\t\tTrack has pre-emphasis applied"); } AaruConsole.DebugWriteLine("GDI plugin", "\t\tTrack resides in file {0}, type defined as {1}, starting at byte {2}", _discImage.Tracks[i].TrackFilter, _discImage.Tracks[i].TrackType, _discImage.Tracks[i].Offset); } AaruConsole.DebugWriteLine("GDI plugin", "Building offset map"); Partitions = new List <Partition>(); ulong byteOffset = 0; for (int i = 0; i < _discImage.Tracks.Count; i++) { if (_discImage.Tracks[i].Sequence == 1 && i != 0) { throw new ImageNotSupportedException("Unordered tracks"); } // Index 01 var partition = new Partition { Description = $"Track {_discImage.Tracks[i].Sequence}.", Name = null, Start = _discImage.Tracks[i].StartSector, Size = _discImage.Tracks[i].Sectors * _discImage.Tracks[i].Bps, Length = _discImage.Tracks[i].Sectors, Sequence = _discImage.Tracks[i].Sequence, Offset = byteOffset, Type = _discImage.Tracks[i].TrackType.ToString() }; byteOffset += partition.Size; _offsetMap.Add(_discImage.Tracks[i].Sequence, partition.Start); Partitions.Add(partition); } foreach (GdiTrack track in _discImage.Tracks) { _imageInfo.ImageSize += track.Bps * track.Sectors; } foreach (GdiTrack track in _discImage.Tracks) { _imageInfo.Sectors += track.Sectors; } _imageInfo.Sectors += _densitySeparationSectors; _imageInfo.SectorSize = 2352; // All others foreach (GdiTrack unused in _discImage.Tracks.Where(track => (track.Flags & 0x4) == 0x4 && track.Bps == 2352)) { _imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync); _imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader); _imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubHeader); _imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEcc); _imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccP); _imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccQ); _imageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc); } _imageInfo.CreationTime = imageFilter.GetCreationTime(); _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); _imageInfo.MediaType = _discImage.Disktype; _imageInfo.ReadableSectorTags.Add(SectorTagType.CdTrackFlags); _imageInfo.XmlMediaType = XmlMediaType.OpticalDisc; AaruConsole.VerboseWriteLine("GDI image describes a disc of type {0}", _imageInfo.MediaType); _sectorBuilder = new SectorBuilder(); return(true); } catch (Exception ex) { AaruConsole.ErrorWriteLine("Exception trying to identify image file {0}", imageFilter.GetBasePath()); AaruConsole.ErrorWriteLine("Exception: {0}", ex.Message); AaruConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace); return(false); } }
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag) { if (tag == SectorTagType.CdTrackFlags) { track = (uint)sectorAddress; } if (track == 0) { if (sectorAddress + length > _densitySeparationSectors) { throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); } if (tag == SectorTagType.CdTrackFlags) { return new byte[] { 0x00 } } ; throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); } var aaruTrack = new GdiTrack { Sequence = 0 }; foreach (GdiTrack gdiTrack in _discImage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) { aaruTrack = gdiTrack; break; } if (aaruTrack.Sequence == 0) { throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); } if (length > aaruTrack.Sectors) { throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); } uint sectorOffset; uint sectorSize; uint sectorSkip; switch (tag) { case SectorTagType.CdSectorEcc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSync: break; case SectorTagType.CdTrackFlags: { byte[] flags = new byte[1]; flags[0] += aaruTrack.Flags; return(flags); } default: throw new ArgumentException("Unsupported tag requested", nameof(tag)); } switch (aaruTrack.TrackType) { case TrackType.Audio: throw new ArgumentException("There are no tags on audio tracks", nameof(tag)); case TrackType.CdMode1: { if (aaruTrack.Bps != 2352) { throw new FeatureNotPresentImageException("Image does not include tags for mode 1 sectors"); } switch (tag) { case SectorTagType.CdSectorSync: { sectorOffset = 0; sectorSize = 12; sectorSkip = 2340; break; } case SectorTagType.CdSectorHeader: { sectorOffset = 12; sectorSize = 4; sectorSkip = 2336; break; } case SectorTagType.CdSectorSubchannel: case SectorTagType.CdSectorSubHeader: throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); case SectorTagType.CdSectorEcc: { sectorOffset = 2076; sectorSize = 276; sectorSkip = 0; break; } case SectorTagType.CdSectorEccP: { sectorOffset = 2076; sectorSize = 172; sectorSkip = 104; break; } case SectorTagType.CdSectorEccQ: { sectorOffset = 2248; sectorSize = 104; sectorSkip = 0; break; } case SectorTagType.CdSectorEdc: { sectorOffset = 2064; sectorSize = 4; sectorSkip = 284; break; } default: throw new ArgumentException("Unsupported tag requested", nameof(tag)); } break; } default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); } byte[] buffer = new byte[sectorSize * length]; ulong remainingSectors = length; if (aaruTrack.Pregap > 0 && sectorAddress < aaruTrack.Pregap) { ulong remainingPregap = aaruTrack.Pregap - sectorAddress; remainingSectors -= length > remainingPregap ? remainingPregap : length; } if (remainingSectors == 0) { return(buffer); } _imageStream = aaruTrack.TrackFilter.GetDataForkStream(); var br = new BinaryReader(_imageStream); long pos = aaruTrack.Offset + (long)((sectorAddress * (sectorOffset + sectorSize + sectorSkip)) - (aaruTrack.Pregap * aaruTrack.Bps)); if (pos < 0) { pos = 0; } br.BaseStream.Seek(pos, SeekOrigin.Begin); if (sectorOffset == 0 && sectorSkip == 0 && remainingSectors == length) { buffer = br.ReadBytes((int)(sectorSize * remainingSectors)); } else if (sectorOffset == 0 && sectorSkip == 0) { byte[] tmp = br.ReadBytes((int)(sectorSize * remainingSectors)); Array.Copy(tmp, 0, buffer, (int)((length - remainingSectors) * sectorSize), tmp.Length); } else { int bufferPos = (int)((length - remainingSectors) * sectorSize); for (ulong i = 0; i < remainingSectors; i++) { br.BaseStream.Seek(sectorOffset, SeekOrigin.Current); byte[] sector = br.ReadBytes((int)sectorSize); br.BaseStream.Seek(sectorSkip, SeekOrigin.Current); Array.Copy(sector, 0, buffer, bufferPos, sectorSize); bufferPos += (int)sectorSize; } } return(buffer); }
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track) { if (track == 0) { if (sectorAddress + length > densitySeparationSectors) { throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); } return(new byte[length * 2352]); } GdiTrack dicTrack = new GdiTrack { Sequence = 0 }; foreach (GdiTrack gdiTrack in discimage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) { dicTrack = gdiTrack; break; } if (dicTrack.Sequence == 0) { throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); } if (sectorAddress + length > dicTrack.Sectors) { throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); } uint sectorOffset; uint sectorSize; uint sectorSkip; switch (dicTrack.Tracktype) { case TrackType.Audio: { sectorOffset = 0; sectorSize = 2352; sectorSkip = 0; break; } case TrackType.CdMode1: { if (dicTrack.Bps == 2352) { sectorOffset = 0; sectorSize = 2352; sectorSkip = 0; } else { sectorOffset = 0; sectorSize = 2048; sectorSkip = 0; } break; } default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); } byte[] buffer = new byte[sectorSize * length]; ulong remainingSectors = length; if (dicTrack.Pregap > 0 && sectorAddress < dicTrack.Pregap) { ulong remainingPregap = dicTrack.Pregap - sectorAddress; byte[] zero; if (length > remainingPregap) { zero = new byte[remainingPregap * sectorSize]; remainingSectors -= remainingPregap; } else { zero = new byte[length * sectorSize]; remainingSectors -= length; } Array.Copy(zero, 0, buffer, 0, zero.Length); } if (remainingSectors == 0) { return(buffer); } imageStream = dicTrack.Trackfilter.GetDataForkStream(); BinaryReader br = new BinaryReader(imageStream); br.BaseStream .Seek(dicTrack.Offset + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip) + dicTrack.Pregap * dicTrack.Bps), SeekOrigin.Begin); if (sectorOffset == 0 && sectorSkip == 0) { buffer = br.ReadBytes((int)(sectorSize * remainingSectors)); } else { for (ulong i = 0; i < remainingSectors; i++) { br.BaseStream.Seek(sectorOffset, SeekOrigin.Current); byte[] sector = br.ReadBytes((int)sectorSize); br.BaseStream.Seek(sectorSkip, SeekOrigin.Current); Array.Copy(sector, 0, buffer, (int)(i * sectorSize), sectorSize); } } return(buffer); }