246 lines
10 KiB
C#
246 lines
10 KiB
C#
// Decompiled with JetBrains decompiler
|
|
// Type: GDRomExplorer.ImageFileFormat.CDI.CDITocConverter
|
|
// Assembly: CDI, Version=1.0.1.0, Culture=neutral, PublicKeyToken=611be24fdeb07e08
|
|
// MVID: B71D3BB5-2FC4-43C2-853E-907E3A458120
|
|
// Assembly location: Formats\CDI.dll
|
|
|
|
using ImageReader.DiscSectors;
|
|
using SEGATools;
|
|
using SEGATools.DiscFileSystem;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace GDRomExplorer.ImageFileFormat.CDI
|
|
{
|
|
internal class CDITocConverter
|
|
{
|
|
private static readonly Logger.ILog logger = Logger.CreateLog();
|
|
private static readonly int NUMBER_OF_SESSIONS_OFFSET = 0;
|
|
private static readonly int TRACK_INFO_LENGTH = 58;
|
|
private static readonly int TRACK_INFO_TRACK_PREGAP_OFFSET = 0;
|
|
private static readonly int TRACK_INFO_TRACK_LENGTH_OFFSET = 4;
|
|
private static readonly int TRACK_INFO_TRACK_MODE_OFFSET = 14;
|
|
private static readonly int TRACK_INFO_TRACK_LBA_OFFSET = 30;
|
|
private static readonly int TRACK_INFO_TRACK_TOTAL_LENGTH_OFFSET = 34;
|
|
private static readonly int TRACK_INFO_TRACK_SECTOR_SIZE_OFFSET = 54;
|
|
private static readonly byte[] TRACK_START_MARKER = new byte[10]
|
|
{
|
|
(byte) 0,
|
|
(byte) 0,
|
|
(byte) 1,
|
|
(byte) 0,
|
|
(byte) 0,
|
|
(byte) 0,
|
|
byte.MaxValue,
|
|
byte.MaxValue,
|
|
byte.MaxValue,
|
|
byte.MaxValue
|
|
};
|
|
private static readonly byte[] TRACK_END_MARKER = new byte[5]
|
|
{
|
|
(byte) 0,
|
|
byte.MaxValue,
|
|
byte.MaxValue,
|
|
byte.MaxValue,
|
|
byte.MaxValue
|
|
};
|
|
|
|
internal static CDIToc ToCdiToc(
|
|
CDIHeader cdiHeader,
|
|
Stream imageStream,
|
|
string imageFileName)
|
|
{
|
|
CDIToc cdiToc = new CDIToc(cdiHeader);
|
|
imageStream.Seek((long) cdiHeader.headerOffset, SeekOrigin.Begin);
|
|
cdiToc.numberOfSessions = CDITocConverter.ReadNumberOfSessions(imageStream);
|
|
cdiToc.numberOfTracks = new ushort[(int) cdiToc.numberOfSessions];
|
|
ushort num1 = 0;
|
|
uint startOffset = 0;
|
|
for (; imageStream.Position < imageStream.Length && (int) num1 < (int) cdiToc.numberOfSessions; ++num1)
|
|
{
|
|
cdiToc.numberOfTracks[(int) num1] = CDITocConverter.ReadNumberOfTracks(imageStream);
|
|
ushort trackIndex = 0;
|
|
List<IDiscTrack> tracks = new List<IDiscTrack>();
|
|
byte[] buffer = new byte[4];
|
|
for (; (int) trackIndex < (int) cdiToc.numberOfTracks[(int) num1]; ++trackIndex)
|
|
{
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
if (BitConverter.ToUInt32(buffer, 0) != 0U)
|
|
imageStream.Seek(8L, SeekOrigin.Current);
|
|
if (!CDITocConverter.HasTrackStartMarkers(imageStream))
|
|
throw new DiscFormatException("Invalid start-of-track marker");
|
|
imageStream.Seek(4L, SeekOrigin.Current);
|
|
int num2 = imageStream.ReadByte();
|
|
imageStream.Seek((long) (num2 + 1), SeekOrigin.Current);
|
|
imageStream.Seek(10L, SeekOrigin.Current);
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
uint uint32 = BitConverter.ToUInt32(buffer, 0);
|
|
if (uint32 != 2U)
|
|
throw new DiscFormatException(string.Format("Invalid marker: {0}", (object) uint32));
|
|
imageStream.Seek(4L, SeekOrigin.Current);
|
|
if (cdiHeader.cdiVersion > CDIVersion.CDI_VERSION_3)
|
|
{
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
if (BitConverter.ToUInt32(buffer, 0) == 2147483648U)
|
|
imageStream.Seek(8L, SeekOrigin.Current);
|
|
}
|
|
else
|
|
imageStream.Seek(4L, SeekOrigin.Current);
|
|
imageStream.Seek(2L, SeekOrigin.Current);
|
|
uint totalLength;
|
|
DiscTrack discTrack = CDITocConverter.ReadTrackInfo(imageStream, imageFileName, trackIndex, startOffset, out totalLength);
|
|
tracks.Add((IDiscTrack) discTrack);
|
|
startOffset += totalLength;
|
|
imageStream.Seek(25L, SeekOrigin.Current);
|
|
imageStream.Seek(4L, SeekOrigin.Current);
|
|
if (cdiHeader.cdiVersion > CDIVersion.CDI_VERSION_2)
|
|
{
|
|
if (!CDITocConverter.CheckTrackEndMarkers(imageStream))
|
|
throw new DiscFormatException("Invalid end-of-track marker");
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
if (BitConverter.ToUInt32(buffer, 0) == uint.MaxValue)
|
|
imageStream.Seek(78L, SeekOrigin.Current);
|
|
}
|
|
}
|
|
if (tracks.Count > 0)
|
|
cdiToc.sessions.Add((IDiscSession) new DiscSession((int) num1 + 1, string.Format(DiscSession.DEFAULT_SESSION_NAME_WITH_FORMAT, (object) ((int) num1 + 1)), tracks));
|
|
imageStream.Seek(12L, SeekOrigin.Current);
|
|
if (cdiHeader.cdiVersion > CDIVersion.CDI_VERSION_2)
|
|
imageStream.Seek(1L, SeekOrigin.Current);
|
|
}
|
|
return cdiToc;
|
|
}
|
|
|
|
private static ushort ReadNumberOfSessions(Stream imageStream)
|
|
{
|
|
byte[] buffer = new byte[2];
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
return BitConverter.ToUInt16(buffer, CDITocConverter.NUMBER_OF_SESSIONS_OFFSET);
|
|
}
|
|
|
|
private static ushort ReadNumberOfTracks(Stream imageStream)
|
|
{
|
|
byte[] buffer = new byte[2];
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
ushort uint16 = BitConverter.ToUInt16(buffer, 0);
|
|
return uint16 <= (ushort) 99 ? uint16 : throw new DiscFormatException(string.Format("Too many tracks: maximum is 99, got {0}", (object) uint16));
|
|
}
|
|
|
|
private static DiscTrack ReadTrackInfo(
|
|
Stream imageStream,
|
|
string imageFileName,
|
|
ushort trackIndex,
|
|
uint startOffset,
|
|
out uint totalLength)
|
|
{
|
|
byte[] buffer1 = new byte[CDITocConverter.TRACK_INFO_LENGTH];
|
|
imageStream.Read(buffer1, 0, buffer1.Length);
|
|
uint uint32_1 = BitConverter.ToUInt32(buffer1, CDITocConverter.TRACK_INFO_TRACK_PREGAP_OFFSET);
|
|
uint uint32_2 = BitConverter.ToUInt32(buffer1, CDITocConverter.TRACK_INFO_TRACK_LENGTH_OFFSET);
|
|
uint uint32_3 = BitConverter.ToUInt32(buffer1, CDITocConverter.TRACK_INFO_TRACK_MODE_OFFSET);
|
|
uint uint32_4 = BitConverter.ToUInt32(buffer1, CDITocConverter.TRACK_INFO_TRACK_LBA_OFFSET);
|
|
uint uint32_5 = BitConverter.ToUInt32(buffer1, CDITocConverter.TRACK_INFO_TRACK_TOTAL_LENGTH_OFFSET);
|
|
uint uint32_6 = BitConverter.ToUInt32(buffer1, CDITocConverter.TRACK_INFO_TRACK_SECTOR_SIZE_OFFSET);
|
|
if ((int) uint32_1 + (int) uint32_2 != (int) uint32_5)
|
|
throw new DiscFormatException(string.Format("Truncated track {0}: expected {1} bytes, got {2} bytes", (object) ((int) trackIndex + 1), (object) uint32_5, (object) (uint) ((int) uint32_1 + (int) uint32_2)));
|
|
uint trackSectorSize = CDITocConverter.GetTrackSectorSize(uint32_6);
|
|
uint num = startOffset + uint32_1 * trackSectorSize;
|
|
totalLength = uint32_5 * trackSectorSize;
|
|
TrackModeType trackModeType = CDITocConverter.ValidateTrackMode(uint32_3);
|
|
IDiscSector trackSector = (IDiscSector) null;
|
|
try
|
|
{
|
|
using (FileStream fileStream = File.Open(imageFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
{
|
|
byte[] buffer2 = new byte[DiscSectorCommon.RawSectorSize];
|
|
fileStream.Seek((long) num, SeekOrigin.Begin);
|
|
fileStream.Read(buffer2, 0, buffer2.Length);
|
|
trackSector = CDITocConverter.ValidateTrackSector(trackSectorSize, trackModeType, buffer2);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error(ex);
|
|
throw new DiscFormatException(string.Format("Unable to read the track {0} of the file {1}", (object) ((int) trackIndex + 1), (object) imageFileName));
|
|
}
|
|
return new DiscTrack(imageFileName, (long) (int) num, (long) (uint32_2 * trackSectorSize), uint32_4, (int) trackIndex + 1, trackModeType, trackSector);
|
|
}
|
|
|
|
private static TrackModeType ValidateTrackMode(uint trackMode)
|
|
{
|
|
switch (trackMode)
|
|
{
|
|
case 0:
|
|
return TrackModeType.Audio;
|
|
case 2:
|
|
return TrackModeType.Data;
|
|
default:
|
|
throw new DiscFormatException(string.Format("Invalid track mode: {0:X}", (object) trackMode));
|
|
}
|
|
}
|
|
|
|
private static uint GetTrackSectorSize(uint trackSectorType)
|
|
{
|
|
switch (trackSectorType)
|
|
{
|
|
case 0:
|
|
return 2048;
|
|
case 1:
|
|
return 2336;
|
|
case 2:
|
|
return 2352;
|
|
default:
|
|
throw new DiscFormatException(string.Format("Invalid track sector: {0:X}", (object) trackSectorType));
|
|
}
|
|
}
|
|
|
|
private static IDiscSector ValidateTrackSector(
|
|
uint trackSector,
|
|
TrackModeType trackModeType,
|
|
byte[] buffer)
|
|
{
|
|
switch (trackSector)
|
|
{
|
|
case 2048:
|
|
return (IDiscSector) new ISO9660Sector();
|
|
case 2336:
|
|
return (IDiscSector) new CDROMXAMode2Form1Sector();
|
|
case 2352:
|
|
if (trackModeType == TrackModeType.Audio)
|
|
return (IDiscSector) new RawSector();
|
|
return CDROMFrameHeaderConverter.ToCDROMFrameHeader(buffer, 0) == CDROMDataModeType.MODE1_RAW ? (IDiscSector) new CDROMMode1RawSector() : (IDiscSector) new CDROMXAMode2Form1RawSector();
|
|
default:
|
|
throw new DiscFormatException(string.Format("Invalid track sector size: {0:X}", (object) trackSector));
|
|
}
|
|
}
|
|
|
|
private static bool HasTrackStartMarkers(Stream imageStream)
|
|
{
|
|
byte[] buffer = new byte[CDITocConverter.TRACK_START_MARKER.Length];
|
|
for (ushort index1 = 0; index1 < (ushort) 2; ++index1)
|
|
{
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
for (ushort index2 = 0; (int) index2 < buffer.Length; ++index2)
|
|
{
|
|
if ((int) buffer[(int) index2] != (int) CDITocConverter.TRACK_START_MARKER[(int) index2])
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static bool CheckTrackEndMarkers(Stream imageStream)
|
|
{
|
|
byte[] buffer = new byte[CDITocConverter.TRACK_END_MARKER.Length];
|
|
imageStream.Read(buffer, 0, buffer.Length);
|
|
for (ushort index = 0; (int) index < buffer.Length; ++index)
|
|
{
|
|
if ((int) buffer[(int) index] != (int) CDITocConverter.TRACK_END_MARKER[(int) index])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|