mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Refactor image classes and split them to smaller files.
This commit is contained in:
84
DiscImageChef.DiscImages/CloneCD/CloneCD.cs
Normal file
84
DiscImageChef.DiscImages/CloneCD/CloneCD.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CloneCD.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages CloneCD 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: CloneCD stores subchannel deinterleaved
|
||||
public partial class CloneCd : IWritableImage
|
||||
{
|
||||
string catalog; // TODO: Use it
|
||||
IFilter ccdFilter;
|
||||
byte[] cdtext;
|
||||
StreamReader cueStream;
|
||||
IFilter dataFilter;
|
||||
Stream dataStream;
|
||||
StreamWriter descriptorStream;
|
||||
byte[] fulltoc;
|
||||
ImageInfo imageInfo;
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
bool scrambled;
|
||||
IFilter subFilter;
|
||||
Stream subStream;
|
||||
Dictionary<byte, byte> trackFlags;
|
||||
string writingBaseName;
|
||||
|
||||
public CloneCd()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
ApplicationVersion = null,
|
||||
MediaTitle = null,
|
||||
Creator = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
68
DiscImageChef.DiscImages/CloneCD/Constants.cs
Normal file
68
DiscImageChef.DiscImages/CloneCD/Constants.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for CloneCD 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CloneCd
|
||||
{
|
||||
const string CCD_IDENTIFIER = @"^\s*\[CloneCD\]";
|
||||
const string DISC_IDENTIFIER = @"^\s*\[Disc\]";
|
||||
const string SESSION_IDENTIFIER = @"^\s*\[Session\s*(?<number>\d+)\]";
|
||||
const string ENTRY_IDENTIFIER = @"^\s*\[Entry\s*(?<number>\d+)\]";
|
||||
const string TRACK_IDENTIFIER = @"^\s*\[TRACK\s*(?<number>\d+)\]";
|
||||
const string CDTEXT_IDENTIFIER = @"^\s*\[CDText\]";
|
||||
const string CCD_VERSION = @"^\s*Version\s*=\s*(?<value>\d+)";
|
||||
const string DISC_ENTRIES = @"^\s*TocEntries\s*=\s*(?<value>\d+)";
|
||||
const string DISC_SESSIONS = @"^\s*Sessions\s*=\s*(?<value>\d+)";
|
||||
const string DISC_SCRAMBLED = @"^\s*DataTracksScrambled\s*=\s*(?<value>\d+)";
|
||||
const string CDTEXT_LENGTH = @"^\s*CDTextLength\s*=\s*(?<value>\d+)";
|
||||
const string DISC_CATALOG = @"^\s*CATALOG\s*=\s*(?<value>[\x21-\x7F]{13})";
|
||||
const string SESSION_PREGAP = @"^\s*PreGapMode\s*=\s*(?<value>\d+)";
|
||||
const string SESSION_SUBCHANNEL = @"^\s*PreGapSubC\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_SESSION = @"^\s*Session\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_POINT = @"^\s*Point\s*=\s*(?<value>[\w+]+)";
|
||||
const string ENTRY_ADR = @"^\s*ADR\s*=\s*(?<value>\w+)";
|
||||
const string ENTRY_CONTROL = @"^\s*Control\s*=\s*(?<value>\w+)";
|
||||
const string ENTRY_TRACKNO = @"^\s*TrackNo\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_AMIN = @"^\s*AMin\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_ASEC = @"^\s*ASec\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_AFRAME = @"^\s*AFrame\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_ALBA = @"^\s*ALBA\s*=\s*(?<value>-?\d+)";
|
||||
const string ENTRY_ZERO = @"^\s*Zero\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_PMIN = @"^\s*PMin\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_PSEC = @"^\s*PSec\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_PFRAME = @"^\s*PFrame\s*=\s*(?<value>\d+)";
|
||||
const string ENTRY_PLBA = @"^\s*PLBA\s*=\s*(?<value>\d+)";
|
||||
const string CDTEXT_ENTRIES = @"^\s*Entries\s*=\s*(?<value>\d+)";
|
||||
const string CDTEXT_ENTRY = @"^\s*Entry\s*(?<number>\d+)\s*=\s*(?<value>([0-9a-fA-F]+\s*)+)";
|
||||
}
|
||||
}
|
||||
52
DiscImageChef.DiscImages/CloneCD/Helpers.cs
Normal file
52
DiscImageChef.DiscImages/CloneCD/Helpers.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for CloneCD 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CloneCd
|
||||
{
|
||||
static ulong GetLba(int minute, int second, int frame)
|
||||
{
|
||||
return (ulong)(minute * 60 * 75 + second * 75 + frame - 150);
|
||||
}
|
||||
|
||||
static long MsfToLba((byte minute, byte second, byte frame) msf)
|
||||
{
|
||||
return msf.minute * 60 * 75 + msf.second * 75 + msf.frame - 150;
|
||||
}
|
||||
|
||||
static (byte minute, byte second, byte frame) LbaToMsf(ulong sector)
|
||||
{
|
||||
return ((byte)((sector + 150) / 75 / 60), (byte)((sector + 150) / 75 % 60), (byte)((sector + 150) % 75));
|
||||
}
|
||||
}
|
||||
}
|
||||
90
DiscImageChef.DiscImages/CloneCD/Identify.cs
Normal file
90
DiscImageChef.DiscImages/CloneCD/Identify.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies CloneCD 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CloneCd
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
ccdFilter = imageFilter;
|
||||
|
||||
try
|
||||
{
|
||||
imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin);
|
||||
byte[] testArray = new byte[512];
|
||||
imageFilter.GetDataForkStream().Read(testArray, 0, 512);
|
||||
imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin);
|
||||
// Check for unexpected control characters that shouldn't be present in a text file and can crash this plugin
|
||||
bool twoConsecutiveNulls = false;
|
||||
for(int i = 0; i < 512; i++)
|
||||
{
|
||||
if(i >= imageFilter.GetDataForkStream().Length) break;
|
||||
|
||||
if(testArray[i] == 0)
|
||||
{
|
||||
if(twoConsecutiveNulls) return false;
|
||||
|
||||
twoConsecutiveNulls = true;
|
||||
}
|
||||
else twoConsecutiveNulls = false;
|
||||
|
||||
if(testArray[i] < 0x20 && testArray[i] != 0x0A && testArray[i] != 0x0D && testArray[i] != 0x00)
|
||||
return false;
|
||||
}
|
||||
|
||||
cueStream = new StreamReader(ccdFilter.GetDataForkStream());
|
||||
|
||||
string line = cueStream.ReadLine();
|
||||
|
||||
Regex hdr = new Regex(CCD_IDENTIFIER);
|
||||
|
||||
Match hdm = hdr.Match(line ?? throw new InvalidOperationException());
|
||||
|
||||
return hdm.Success;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", ccdFilter);
|
||||
DicConsole.ErrorWriteLine("Exception: {0}", ex.Message);
|
||||
DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
DiscImageChef.DiscImages/CloneCD/Properties.cs
Normal file
76
DiscImageChef.DiscImages/CloneCD/Properties.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for CloneCD 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CloneCd
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
public string Name => "CloneCD";
|
||||
public Guid Id => new Guid("EE9C2975-2E79-427A-8EE9-F86F19165784");
|
||||
public string Format => "CloneCD";
|
||||
public List<Partition> Partitions { get; private set; }
|
||||
public List<Track> Tracks { get; private set; }
|
||||
public List<Session> Sessions { get; private set; }
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new[] {MediaTagType.CD_MCN, MediaTagType.CD_FullTOC};
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags =>
|
||||
new[]
|
||||
{
|
||||
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ,
|
||||
SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubHeader,
|
||||
SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags, SectorTagType.CdSectorSubchannel
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI,
|
||||
MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.CDRW,
|
||||
MediaType.CDV, MediaType.DTSCD, MediaType.JaguarCD, MediaType.MEGACD, MediaType.PS1CD, MediaType.PS2CD,
|
||||
MediaType.SuperCDROM2, MediaType.SVCD, MediaType.SATURNCD, MediaType.ThreeDO, MediaType.VCD,
|
||||
MediaType.VCDHD, MediaType.NeoGeoCD, MediaType.PCFX
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".ccd"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
1236
DiscImageChef.DiscImages/CloneCD/Read.cs
Normal file
1236
DiscImageChef.DiscImages/CloneCD/Read.cs
Normal file
File diff suppressed because it is too large
Load Diff
42
DiscImageChef.DiscImages/CloneCD/Unsupported.cs
Normal file
42
DiscImageChef.DiscImages/CloneCD/Unsupported.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by CloneCD 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CloneCd
|
||||
{
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
602
DiscImageChef.DiscImages/CloneCD/Write.cs
Normal file
602
DiscImageChef.DiscImages/CloneCD/Write.cs
Normal file
@@ -0,0 +1,602 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes CloneCD 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Decoders.CD;
|
||||
using Schemas;
|
||||
using TrackType = DiscImageChef.CommonTypes.Enums.TrackType;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CloneCd
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try
|
||||
{
|
||||
writingBaseName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path));
|
||||
descriptorStream = new StreamWriter(path, false, Encoding.ASCII);
|
||||
dataStream = new FileStream(writingBaseName + ".img", FileMode.OpenOrCreate, FileAccess.ReadWrite,
|
||||
FileShare.None);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo.MediaType = mediaType;
|
||||
|
||||
trackFlags = new Dictionary<byte, byte>();
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case MediaTagType.CD_MCN:
|
||||
catalog = Encoding.ASCII.GetString(data);
|
||||
return true;
|
||||
case MediaTagType.CD_FullTOC:
|
||||
fulltoc = new byte[data.Length + 2];
|
||||
Array.Copy(data, 0, fulltoc, 2, data.Length);
|
||||
fulltoc[0] = (byte)((data.Length & 0xFF00) >> 8);
|
||||
fulltoc[1] = (byte)(data.Length & 0xFF);
|
||||
return true;
|
||||
default:
|
||||
ErrorMessage = $"Unsupported media tag {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Implement ECC generation
|
||||
ErrorMessage = "This format requires sectors to be raw. Generating ECC is not yet implemented";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Implement ECC generation
|
||||
ErrorMessage = "This format requires sectors to be raw. Generating ECC is not yet implemented";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
Tracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
dataStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
dataStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
Tracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > track.TrackEndSector + 1)
|
||||
{
|
||||
ErrorMessage = "Can't cross tracks";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % track.TrackRawBytesPerSector != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
dataStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
dataStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ulong currentDataOffset = 0;
|
||||
ulong currentSubchannelOffset = 0;
|
||||
|
||||
Tracks = new List<Track>();
|
||||
foreach(Track track in tracks.OrderBy(t => t.TrackSequence))
|
||||
{
|
||||
Track newTrack = track;
|
||||
uint subchannelSize;
|
||||
switch(track.TrackSubchannelType)
|
||||
{
|
||||
case TrackSubchannelType.None:
|
||||
subchannelSize = 0;
|
||||
break;
|
||||
case TrackSubchannelType.Raw:
|
||||
case TrackSubchannelType.RawInterleaved:
|
||||
subchannelSize = 96;
|
||||
break;
|
||||
default:
|
||||
ErrorMessage = $"Unsupported subchannel type {track.TrackSubchannelType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
newTrack.TrackFileOffset = currentDataOffset;
|
||||
newTrack.TrackSubchannelOffset = currentSubchannelOffset;
|
||||
|
||||
currentDataOffset += (ulong)newTrack.TrackRawBytesPerSector *
|
||||
(newTrack.TrackEndSector - newTrack.TrackStartSector + 1);
|
||||
currentSubchannelOffset += subchannelSize * (newTrack.TrackEndSector - newTrack.TrackStartSector + 1);
|
||||
|
||||
Tracks.Add(newTrack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
dataStream.Flush();
|
||||
dataStream.Close();
|
||||
|
||||
subStream?.Flush();
|
||||
subStream?.Close();
|
||||
|
||||
FullTOC.CDFullTOC? nullableToc = null;
|
||||
FullTOC.CDFullTOC toc;
|
||||
|
||||
// Easy, just decode the real toc
|
||||
if(fulltoc != null) nullableToc = FullTOC.Decode(fulltoc);
|
||||
|
||||
// Not easy, create a toc from scratch
|
||||
if(nullableToc == null)
|
||||
{
|
||||
toc = new FullTOC.CDFullTOC();
|
||||
Dictionary<byte, byte> sessionEndingTrack = new Dictionary<byte, byte>();
|
||||
toc.FirstCompleteSession = byte.MaxValue;
|
||||
toc.LastCompleteSession = byte.MinValue;
|
||||
List<FullTOC.TrackDataDescriptor> trackDescriptors = new List<FullTOC.TrackDataDescriptor>();
|
||||
byte currentTrack = 0;
|
||||
|
||||
foreach(Track track in Tracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence))
|
||||
{
|
||||
if(track.TrackSession < toc.FirstCompleteSession)
|
||||
toc.FirstCompleteSession = (byte)track.TrackSession;
|
||||
|
||||
if(track.TrackSession <= toc.LastCompleteSession)
|
||||
{
|
||||
currentTrack = (byte)track.TrackSequence;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(toc.LastCompleteSession > 0) sessionEndingTrack.Add(toc.LastCompleteSession, currentTrack);
|
||||
|
||||
toc.LastCompleteSession = (byte)track.TrackSession;
|
||||
}
|
||||
|
||||
byte currentSession = 0;
|
||||
|
||||
foreach(Track track in Tracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence))
|
||||
{
|
||||
trackFlags.TryGetValue((byte)track.TrackSequence, out byte trackControl);
|
||||
|
||||
if(trackControl == 0 && track.TrackType != TrackType.Audio) trackControl = (byte)CdFlags.DataTrack;
|
||||
|
||||
// Lead-Out
|
||||
if(track.TrackSession > currentSession && currentSession != 0)
|
||||
{
|
||||
(byte minute, byte second, byte frame) leadoutAmsf = LbaToMsf(track.TrackStartSector - 150);
|
||||
(byte minute, byte second, byte frame) leadoutPmsf =
|
||||
LbaToMsf(Tracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).Last()
|
||||
.TrackStartSector);
|
||||
|
||||
// Lead-out
|
||||
trackDescriptors.Add(new FullTOC.TrackDataDescriptor
|
||||
{
|
||||
SessionNumber = currentSession,
|
||||
POINT = 0xB0,
|
||||
ADR = 5,
|
||||
CONTROL = 0,
|
||||
HOUR = 0,
|
||||
Min = leadoutAmsf.minute,
|
||||
Sec = leadoutAmsf.second,
|
||||
Frame = leadoutAmsf.frame,
|
||||
PHOUR = 2,
|
||||
PMIN = leadoutPmsf.minute,
|
||||
PSEC = leadoutPmsf.second,
|
||||
PFRAME = leadoutPmsf.frame
|
||||
});
|
||||
|
||||
// This seems to be constant? It should not exist on CD-ROM but CloneCD creates them anyway
|
||||
// Format seems like ATIP, but ATIP should not be as 0xC0 in TOC...
|
||||
trackDescriptors.Add(new FullTOC.TrackDataDescriptor
|
||||
{
|
||||
SessionNumber = currentSession,
|
||||
POINT = 0xC0,
|
||||
ADR = 5,
|
||||
CONTROL = 0,
|
||||
Min = 128,
|
||||
PMIN = 97,
|
||||
PSEC = 25
|
||||
});
|
||||
}
|
||||
|
||||
// Lead-in
|
||||
if(track.TrackSession > currentSession)
|
||||
{
|
||||
currentSession = (byte)track.TrackSession;
|
||||
sessionEndingTrack.TryGetValue(currentSession, out byte endingTrackNumber);
|
||||
(byte minute, byte second, byte frame) leadinPmsf =
|
||||
LbaToMsf(Tracks.FirstOrDefault(t => t.TrackSequence == endingTrackNumber).TrackEndSector +
|
||||
1);
|
||||
|
||||
// Starting track
|
||||
trackDescriptors.Add(new FullTOC.TrackDataDescriptor
|
||||
{
|
||||
SessionNumber = currentSession,
|
||||
POINT = 0xA0,
|
||||
ADR = 1,
|
||||
CONTROL = trackControl,
|
||||
PMIN = (byte)track.TrackSequence
|
||||
});
|
||||
|
||||
// Ending track
|
||||
trackDescriptors.Add(new FullTOC.TrackDataDescriptor
|
||||
{
|
||||
SessionNumber = currentSession,
|
||||
POINT = 0xA1,
|
||||
ADR = 1,
|
||||
CONTROL = trackControl,
|
||||
PMIN = endingTrackNumber
|
||||
});
|
||||
|
||||
// Lead-out start
|
||||
trackDescriptors.Add(new FullTOC.TrackDataDescriptor
|
||||
{
|
||||
SessionNumber = currentSession,
|
||||
POINT = 0xA2,
|
||||
ADR = 1,
|
||||
CONTROL = trackControl,
|
||||
PHOUR = 0,
|
||||
PMIN = leadinPmsf.minute,
|
||||
PSEC = leadinPmsf.second,
|
||||
PFRAME = leadinPmsf.frame
|
||||
});
|
||||
}
|
||||
|
||||
(byte minute, byte second, byte frame) pmsf = LbaToMsf(track.TrackStartSector);
|
||||
|
||||
// Track
|
||||
trackDescriptors.Add(new FullTOC.TrackDataDescriptor
|
||||
{
|
||||
SessionNumber = (byte)track.TrackSession,
|
||||
POINT = (byte)track.TrackSequence,
|
||||
ADR = 1,
|
||||
CONTROL = trackControl,
|
||||
PHOUR = 0,
|
||||
PMIN = pmsf.minute,
|
||||
PSEC = pmsf.second,
|
||||
PFRAME = pmsf.frame
|
||||
});
|
||||
}
|
||||
|
||||
toc.TrackDescriptors = trackDescriptors.ToArray();
|
||||
}
|
||||
else toc = nullableToc.Value;
|
||||
|
||||
descriptorStream.WriteLine("[CloneCD]");
|
||||
descriptorStream.WriteLine("Version=2");
|
||||
descriptorStream.WriteLine("[Disc]");
|
||||
descriptorStream.WriteLine("TocEntries={0}", toc.TrackDescriptors.Length);
|
||||
descriptorStream.WriteLine("Sessions={0}", toc.LastCompleteSession);
|
||||
descriptorStream.WriteLine("DataTracksScrambled=0");
|
||||
descriptorStream.WriteLine("CDTextLength=0");
|
||||
if(!string.IsNullOrEmpty(catalog)) descriptorStream.WriteLine("CATALOG={0}", catalog);
|
||||
for(int i = 1; i <= toc.LastCompleteSession; i++)
|
||||
{
|
||||
// TODO: Use first track of session info
|
||||
descriptorStream.WriteLine("[Session {0}]", i);
|
||||
descriptorStream.WriteLine("PreGapMode=0");
|
||||
descriptorStream.WriteLine("PreGapSubC=0");
|
||||
}
|
||||
|
||||
for(int i = 0; i < toc.TrackDescriptors.Length; i++)
|
||||
{
|
||||
long alba = MsfToLba((toc.TrackDescriptors[i].Min, toc.TrackDescriptors[i].Sec,
|
||||
toc.TrackDescriptors[i].Frame));
|
||||
long plba = MsfToLba((toc.TrackDescriptors[i].PMIN, toc.TrackDescriptors[i].PSEC,
|
||||
toc.TrackDescriptors[i].PFRAME));
|
||||
|
||||
if(alba > 405000) alba = (alba - 405000 + 300) * -1;
|
||||
if(plba > 405000) plba = (plba - 405000 + 300) * -1;
|
||||
|
||||
descriptorStream.WriteLine("[Entry {0}]", i);
|
||||
descriptorStream.WriteLine("Session={0}", toc.TrackDescriptors[i].SessionNumber);
|
||||
descriptorStream.WriteLine("Point=0x{0:x2}", toc.TrackDescriptors[i].POINT);
|
||||
descriptorStream.WriteLine("ADR=0x{0:x2}", toc.TrackDescriptors[i].ADR);
|
||||
descriptorStream.WriteLine("Control=0x{0:x2}", toc.TrackDescriptors[i].CONTROL);
|
||||
descriptorStream.WriteLine("TrackNo={0}", toc.TrackDescriptors[i].TNO);
|
||||
descriptorStream.WriteLine("AMin={0}", toc.TrackDescriptors[i].Min);
|
||||
descriptorStream.WriteLine("ASec={0}", toc.TrackDescriptors[i].Sec);
|
||||
descriptorStream.WriteLine("AFrame={0}", toc.TrackDescriptors[i].Frame);
|
||||
descriptorStream.WriteLine("ALBA={0}", alba);
|
||||
descriptorStream.WriteLine("Zero={0}",
|
||||
((toc.TrackDescriptors[i].HOUR & 0x0F) << 4) +
|
||||
(toc.TrackDescriptors[i].PHOUR & 0x0F));
|
||||
descriptorStream.WriteLine("PMin={0}", toc.TrackDescriptors[i].PMIN);
|
||||
descriptorStream.WriteLine("PSec={0}", toc.TrackDescriptors[i].PSEC);
|
||||
descriptorStream.WriteLine("PFrame={0}", toc.TrackDescriptors[i].PFRAME);
|
||||
descriptorStream.WriteLine("PLBA={0}", plba);
|
||||
}
|
||||
|
||||
descriptorStream.Flush();
|
||||
descriptorStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
Tracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
{
|
||||
if(data.Length != 1)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for track flags";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackFlags.Add((byte)track.TrackSequence, data[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
if(track.TrackSubchannelType == 0)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != 96)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(subStream == null)
|
||||
try
|
||||
{
|
||||
subStream = new FileStream(writingBaseName + ".sub", FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite, FileShare.None);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create subchannel file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
subStream.Seek((long)(track.TrackSubchannelOffset + (sectorAddress - track.TrackStartSector) * 96),
|
||||
SeekOrigin.Begin);
|
||||
subStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
ErrorMessage = $"Unsupported tag type {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
Tracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
case SectorTagType.CdTrackIsrc: return WriteSectorTag(data, sectorAddress, tag);
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
if(track.TrackSubchannelType == 0)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % 96 != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(subStream == null)
|
||||
try
|
||||
{
|
||||
subStream = new FileStream(writingBaseName + ".sub", FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite, FileShare.None);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create subchannel file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
subStream.Seek((long)(track.TrackSubchannelOffset + (sectorAddress - track.TrackStartSector) * 96),
|
||||
SeekOrigin.Begin);
|
||||
subStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
ErrorMessage = $"Unsupported tag type {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user