// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : Read.cs // Author(s) : Natalia Portillo // // Component : Disc image plugins. // // --[ Description ] ---------------------------------------------------------- // // Reads Alcohol 120% disc images. // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2023 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Decoders.DVD; using Aaru.Helpers; using DMI = Aaru.Decoders.Xbox.DMI; using Sector = Aaru.Decoders.CD.Sector; namespace Aaru.Images; public sealed partial class Alcohol120 { #region IWritableOpticalImage Members /// public ErrorNumber Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); if(stream.Length < 88) return ErrorNumber.InvalidArgument; _isDvd = false; var hdr = new byte[88]; stream.EnsureRead(hdr, 0, 88); _header = Marshal.ByteArrayToStructureLittleEndian
(hdr); AaruConsole.DebugWriteLine(MODULE_NAME, "header.signature = {0}", Encoding.ASCII.GetString(_header.signature)); AaruConsole.DebugWriteLine(MODULE_NAME, "header.version = {0}.{1}", _header.version[0], _header.version[1]); AaruConsole.DebugWriteLine(MODULE_NAME, "header.type = {0}", _header.type); AaruConsole.DebugWriteLine(MODULE_NAME, "header.sessions = {0}", _header.sessions); for(var i = 0; i < _header.unknown1.Length; i++) AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown1[{1}] = 0x{0:X4}", _header.unknown1[i], i); AaruConsole.DebugWriteLine(MODULE_NAME, "header.bcaLength = {0}", _header.bcaLength); for(var i = 0; i < _header.unknown2.Length; i++) AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown2[{1}] = 0x{0:X8}", _header.unknown2[i], i); AaruConsole.DebugWriteLine(MODULE_NAME, "header.bcaOffset = {0}", _header.bcaOffset); for(var i = 0; i < _header.unknown3.Length; i++) AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown3[{1}] = 0x{0:X8}", _header.unknown3[i], i); AaruConsole.DebugWriteLine(MODULE_NAME, "header.structuresOffset = {0}", _header.structuresOffset); for(var i = 0; i < _header.unknown4.Length; i++) AaruConsole.DebugWriteLine(MODULE_NAME, "header.unknown4[{1}] = 0x{0:X8}", _header.unknown4[i], i); AaruConsole.DebugWriteLine(MODULE_NAME, "header.sessionOffset = {0}", _header.sessionOffset); AaruConsole.DebugWriteLine(MODULE_NAME, "header.dpmOffset = {0}", _header.dpmOffset); if(_header.version[0] > MAXIMUM_SUPPORTED_VERSION) return ErrorNumber.NotSupported; stream.Seek(_header.sessionOffset, SeekOrigin.Begin); _alcSessions = new Dictionary(); for(var i = 0; i < _header.sessions; i++) { var sesHdr = new byte[24]; stream.EnsureRead(sesHdr, 0, 24); Session session = Marshal.SpanToStructureLittleEndian(sesHdr); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].sessionStart = {0}", session.sessionStart, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].sessionEnd = {0}", session.sessionEnd, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].sessionSequence = {0}", session.sessionSequence, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].allBlocks = {0}", session.allBlocks, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].nonTrackBlocks = {0}", session.nonTrackBlocks, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].firstTrack = {0}", session.firstTrack, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].lastTrack = {0}", session.lastTrack, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].unknown = 0x{0:X8}", session.unknown, i); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{1}].trackOffset = {0}", session.trackOffset, i); _alcSessions.Add(session.sessionSequence, session); } long footerOff = 0; var oldIncorrectImage = false; _alcTracks = new Dictionary(); _alcToc = new Dictionary>(); uint track1Index1 = 0; foreach(Session session in _alcSessions.Values) { stream.Seek(session.trackOffset, SeekOrigin.Begin); Dictionary sesToc = new(); for(var i = 0; i < session.allBlocks; i++) { var trkHdr = new byte[80]; stream.EnsureRead(trkHdr, 0, 80); Track track = Marshal.ByteArrayToStructureLittleEndian(trkHdr); if(track.mode is TrackMode.Mode2F1Alt or TrackMode.Mode2F1Alt) oldIncorrectImage = true; // Solve our own mistake here, sorry, but anyway seems Alcohol doesn't support DDCD if(track is { zero: > 0, point: >= 1 and <= 99 }) { track.pmin += (byte)(track.zero * 60); track.zero = 0; oldIncorrectImage = true; } AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].mode = {0}", track.mode, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].subMode = {0}", track.subMode, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].adrCtl = {0}", track.adrCtl, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].tno = {0}", track.tno, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].point = {0:X2}", track.point, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].min = {0}", track.min, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].sec = {0}", track.sec, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].frame = {0}", track.frame, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].zero = {0}", track.zero, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].pmin = {0}", track.pmin, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].psec = {0}", track.psec, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].pframe = {0}", track.pframe, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].extraOffset = {0}", track.extraOffset, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].sectorSize = {0}", track.sectorSize, track.point, session.sessionSequence); //for(int j = 0; j < track.unknown.Length; j++) // AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].unknown[{2}] = {0}", track.unknown[j], i, j, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].startLba = {0}", track.startLba, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].startOffset = {0}", track.startOffset, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].files = {0}", track.files, track.point, session.sessionSequence); AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].footerOffset = {0}", track.footerOffset, track.point, session.sessionSequence); //for(int j = 0; j < track.unknown2.Length; j++) // AaruConsole.DebugWriteLine(MODULE_NAME, "session[{2}].track[{1}].unknown2[{2}] = {0}", track.unknown2[j], i, j, session.sessionSequence); if(track.subMode == SubchannelMode.Interleaved) track.sectorSize -= 96; if(track is { point: 1, startLba: > 0 }) { AaruConsole.ErrorWriteLine(Localization. The_disc_this_image_represents_contained_a_hidden_track_in_the_first_pregap_that_this_image_format_cannot_store_This_dump_is_therefore_incorrect); track1Index1 = track.startLba; track.startLba = 0; } sesToc.TryAdd(track.point, track); if(track.point < 0xA0) _alcTracks.Add(track.point, track); if(footerOff == 0) footerOff = track.footerOffset; _isDvd |= track.mode == TrackMode.DVD; } _alcToc.Add(session.sessionSequence, sesToc); } _alcTrackExtras = new Dictionary(); foreach(Track track in _alcTracks.Values) { if(track.extraOffset > 0 && !_isDvd) { var extHdr = new byte[8]; stream.Seek(track.extraOffset, SeekOrigin.Begin); stream.EnsureRead(extHdr, 0, 8); TrackExtra extra = Marshal.SpanToStructureLittleEndian(extHdr); AaruConsole.DebugWriteLine(MODULE_NAME, "track[{1}].extra.pregap = {0}", extra.pregap, track.point); AaruConsole.DebugWriteLine(MODULE_NAME, "track[{1}].extra.sectors = {0}", extra.sectors, track.point); if(track.point == 1) { extra.pregap = track1Index1 + 150; // Needed because faulty UltraISO implementation extra.sectors += extra.pregap - 150; } _alcTrackExtras.Add(track.point, extra); } else if(_isDvd) { var extra = new TrackExtra { sectors = track.extraOffset }; _alcTrackExtras.Add(track.point, extra); } } if(footerOff > 0) { var footer = new byte[16]; stream.Seek(footerOff, SeekOrigin.Begin); stream.EnsureRead(footer, 0, 16); _alcFooter = Marshal.SpanToStructureLittleEndian