diff --git a/SabreTools.Serialization/Extensions/CDROM.cs b/SabreTools.Serialization/Extensions/CDROM.cs
index bbe6e882..2e05b2e9 100644
--- a/SabreTools.Serialization/Extensions/CDROM.cs
+++ b/SabreTools.Serialization/Extensions/CDROM.cs
@@ -1,13 +1,106 @@
using System;
using System.IO;
using SabreTools.Data.Models.CDROM;
-using SabreTools.IO;
using SabreTools.IO.Extensions;
namespace SabreTools.Data.Extensions
{
public static class CDROM
{
+ ///
+ /// Get the sector mode for a CD-ROM stream
+ ///
+ /// Stream to derive the sector mode from
+ /// Sector mode from the stream on success, on error
+ public static SectorMode GetSectorMode(this Stream stream)
+ {
+ try
+ {
+ byte modeByte = stream.ReadByteValue();
+ if (modeByte == 0)
+ {
+ return SectorMode.MODE0;
+ }
+ else if (modeByte == 1)
+ {
+ return SectorMode.MODE1;
+ }
+ else if (modeByte == 2)
+ {
+ stream.SeekIfPossible(2, SeekOrigin.Current);
+ byte submode = stream.ReadByteValue();
+ if ((submode & 0x20) == 0x20)
+ return SectorMode.MODE2_FORM2;
+ else
+ return SectorMode.MODE2_FORM1;
+ }
+ else
+ {
+ return SectorMode.UNKNOWN;
+ }
+ }
+ catch
+ {
+ // Ignore the actual error
+ return SectorMode.UNKNOWN;
+ }
+
+ }
+
+ ///
+ /// Get the user data size for a sector mode
+ ///
+ /// Sector mode to get a value for
+ /// User data size, if possible
+ public static long GetUserDataSize(this SectorMode mode)
+ {
+ return mode switch
+ {
+ SectorMode.MODE0 => Constants.Mode0DataSize,
+ SectorMode.MODE1 => Constants.Mode1DataSize,
+ SectorMode.MODE2 => Constants.Mode0DataSize,
+ SectorMode.MODE2_FORM1 => Constants.Mode2Form1DataSize,
+ SectorMode.MODE2_FORM2 => Constants.Mode2Form2DataSize,
+ _ => Constants.Mode0DataSize,
+ };
+ }
+
+ ///
+ /// Get the user data end offset for a sector mode
+ ///
+ /// Sector mode to get a value for
+ /// User data end offset, if possible
+ public static long GetUserDataEnd(this SectorMode mode)
+ {
+ return mode switch
+ {
+ SectorMode.MODE0 => Constants.Mode0UserDataEnd, // TODO: Support flexible sector length (2352)
+ SectorMode.MODE1 => Constants.Mode1UserDataEnd,
+ SectorMode.MODE2 => Constants.Mode0UserDataEnd, // TODO: Support flexible sector length (2352)
+ SectorMode.MODE2_FORM1 => Constants.Mode2Form1UserDataEnd,
+ SectorMode.MODE2_FORM2 => Constants.Mode2Form2UserDataEnd, // TODO: Support flexible sector length (2348)
+ _ => Constants.Mode0UserDataEnd,
+ };
+ }
+
+ ///
+ /// Get the user data start offset for a sector mode
+ ///
+ /// Sector mode to get a value for
+ /// User data start offset, if possible
+ public static long GetUserDataStart(this SectorMode mode)
+ {
+ return mode switch
+ {
+ SectorMode.MODE0 => Constants.Mode0UserDataStart,
+ SectorMode.MODE1 => Constants.Mode1UserDataStart,
+ SectorMode.MODE2 => Constants.Mode0UserDataStart,
+ SectorMode.MODE2_FORM1 => Constants.Mode2Form1UserDataStart,
+ SectorMode.MODE2_FORM2 => Constants.Mode2Form2UserDataStart,
+ _ => Constants.Mode0UserDataStart,
+ };
+ }
+
///
/// Creates a stream that provides only the user data of a CDROM stream
///
@@ -19,26 +112,31 @@ namespace SabreTools.Data.Extensions
// State variables
private long _position = 0;
private SectorMode _currentMode = SectorMode.UNKNOWN;
- private long _userDataStart = 16;
- private long _userDataEnd = 2064;
+ private long _userDataStart = Constants.Mode1UserDataStart;
+ private long _userDataEnd = Constants.Mode1UserDataEnd;
private long _isoSectorSize = Constants.Mode1DataSize;
public ISO9660Stream(Stream inputStream)
{
if (!inputStream.CanSeek || !inputStream.CanRead)
throw new ArgumentException("Stream must be readable and seekable.", nameof(inputStream));
+
_baseStream = inputStream;
}
- public override bool CanRead => true;
- public override bool CanSeek => true;
+ ///
+ public override bool CanRead => _baseStream.CanRead;
+
+ ///
+ public override bool CanSeek => _baseStream.CanSeek;
+
+ ///
public override bool CanWrite => false;
- public override void Flush()
- {
- _baseStream.Flush();
- }
+ ///
+ public override void Flush() => _baseStream.Flush();
+ ///
public override long Length
{
get
@@ -47,25 +145,28 @@ namespace SabreTools.Data.Extensions
}
}
+ ///
public override void SetLength(long value)
{
throw new NotSupportedException("Setting the length of this stream is not supported.");
}
+ ///
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException("Writing to this stream is not supported.");
}
+ ///
protected override void Dispose(bool disposing)
{
if (disposing)
- {
_baseStream.Dispose();
- }
+
base.Dispose(disposing);
}
+ ///
public override long Position
{
// Get the position of the underlying ISO9660 stream
@@ -93,16 +194,16 @@ namespace SabreTools.Data.Extensions
}
}
+ ///
public override int Read(byte[] buffer, int offset, int count)
{
- bool readEntireSector = false;
int totalRead = 0;
int remaining = count;
while (remaining > 0 && _position < _baseStream.Length)
{
// Determine location of current sector
- long baseStreamOffset = (_position / Constants.CDROMSectorSize) * Constants.CDROMSectorSize;
+ long baseStreamOffset = _position - (_position % Constants.CDROMSectorSize);
// Set the current sector's mode and user data location
SetState(baseStreamOffset);
@@ -123,16 +224,16 @@ namespace SabreTools.Data.Extensions
_position += Constants.CDROMSectorSize - _userDataEnd + _userDataStart;
}
else
+ {
baseStreamOffset += remainder;
+ }
// Sanity check on read location before seeking
if (baseStreamOffset < 0 || baseStreamOffset > _baseStream.Length)
- {
throw new ArgumentOutOfRangeException(nameof(offset), "Attempted to seek outside the stream boundaries.");
- }
// Seek to target position in base CDROM stream
- _baseStream.Seek(baseStreamOffset, SeekOrigin.Begin);
+ _baseStream.SeekIfPossible(baseStreamOffset, SeekOrigin.Begin);
// Read the remaining bytes, up to max of one ISO sector (2048 bytes)
int bytesToRead = (int)Math.Min(remaining, _isoSectorSize - sectorOffset);
@@ -140,11 +241,6 @@ namespace SabreTools.Data.Extensions
// Don't overshoot end of stream
bytesToRead = (int)Math.Min(bytesToRead, _baseStream.Length - _position);
- if (bytesToRead == (_isoSectorSize - sectorOffset))
- readEntireSector = true;
- else
- readEntireSector = false;
-
// Finish reading if no more bytes to be read
if (bytesToRead <= 0)
break;
@@ -154,7 +250,7 @@ namespace SabreTools.Data.Extensions
// Update state for base stream
_position = _baseStream.Position;
- if (readEntireSector)
+ if (bytesToRead == (_isoSectorSize - sectorOffset))
_position += (Constants.CDROMSectorSize - _userDataEnd) + _userDataStart;
// Update state for ISO stream
@@ -168,24 +264,17 @@ namespace SabreTools.Data.Extensions
return totalRead;
}
+ ///
public override long Seek(long offset, SeekOrigin origin)
{
// Get the intended position for the ISO9660 stream
- long targetPosition;
- switch (origin)
+ var targetPosition = origin switch
{
- case SeekOrigin.Begin:
- targetPosition = offset;
- break;
- case SeekOrigin.Current:
- targetPosition = Position + offset;
- break;
- case SeekOrigin.End:
- targetPosition = Length + offset;
- break;
- default:
- throw new ArgumentException("Invalid SeekOrigin.", nameof(origin));
- }
+ SeekOrigin.Begin => offset,
+ SeekOrigin.Current => Position + offset,
+ SeekOrigin.End => Length + offset,
+ _ => throw new ArgumentException("Invalid SeekOrigin.", nameof(origin)),
+ };
// Get the number of ISO sectors before current position
long newPosition = (targetPosition / _isoSectorSize) * Constants.CDROMSectorSize;
@@ -195,80 +284,33 @@ namespace SabreTools.Data.Extensions
// Add the within-sector position
newPosition += _userDataStart + (targetPosition % _isoSectorSize);
-
if (newPosition < 0 || newPosition > _baseStream.Length)
- {
throw new ArgumentOutOfRangeException(nameof(offset), "Attempted to seek outside the stream boundaries.");
- }
- _position = _baseStream.Seek(newPosition, SeekOrigin.Begin);
+ _position = _baseStream.SeekIfPossible(newPosition, SeekOrigin.Begin);
return Position;
}
+ ///
+ /// Update the current stream state based on the location
+ ///
+ /// Sector location to update from
private void SetState(long sectorLocation)
{
- long oldPosition = _baseStream.Position;
- long modePosition = (sectorLocation - sectorLocation % Constants.CDROMSectorSize) + 15;
- _baseStream.Seek(modePosition, SeekOrigin.Begin);
- byte modeByte = _baseStream.ReadByteValue();
- if (modeByte == 0)
- _currentMode = SectorMode.MODE0;
- else if (modeByte == 1)
- _currentMode = SectorMode.MODE1;
- else if (modeByte == 2)
- {
- _baseStream.Seek(modePosition + 3, SeekOrigin.Begin);
- byte submode = _baseStream.ReadByteValue();
- if ((submode & 0x20) == 0x20)
- _currentMode = SectorMode.MODE2_FORM2;
- else
- _currentMode = SectorMode.MODE2_FORM1;
- }
- else
- _currentMode = SectorMode.UNKNOWN;
+ long current = _baseStream.Position;
+ long modePosition = sectorLocation - (sectorLocation % Constants.CDROMSectorSize) + 15;
+
+ // Get the current sector mode
+ _baseStream.SeekIfPossible(modePosition, SeekOrigin.Begin);
+ _currentMode = _baseStream.GetSectorMode();
// Set the user data location variables
- switch (_currentMode)
- {
- case SectorMode.MODE1:
- _userDataStart = 16;
- _userDataEnd = 2064;
- //_isoSectorSize = Constants.Mode1DataSize;
- break;
+ _userDataStart = _currentMode.GetUserDataStart();
+ _userDataEnd = _currentMode.GetUserDataEnd();
+ // _isoSectorSize = _currentMode.GetUserDataSize();
- case SectorMode.MODE2_FORM1:
- _userDataStart = 24;
- _userDataEnd = 2072;
- //_isoSectorSize = Constants.Form1DataSize;
- break;
-
- case SectorMode.MODE2_FORM2:
- _userDataStart = 24;
- _userDataEnd = 2072;
- // TODO: Support flexible sector length
- //_userDataEnd = 2348;
- //_isoSectorSize = Constants.Form2DataSize;
- break;
-
- case SectorMode.MODE0:
- case SectorMode.MODE2:
- _userDataStart = 16;
- _userDataEnd = 2064;
- // TODO: Support flexible sector length
- //_userDataEnd = 2352;
- //_isoSectorSize = Constants.Mode0DataSize;
- break;
-
- case SectorMode.UNKNOWN:
- _userDataStart = 16;
- _userDataEnd = 2064;
- //_isoSectorSize = Constants.Mode1DataSize;
- break;
- }
-
- _baseStream.Seek(oldPosition, SeekOrigin.Begin);
-
- return;
+ // Reset the stream position
+ _baseStream.SeekIfPossible(current, SeekOrigin.Begin);
}
}
}
diff --git a/SabreTools.Serialization/Models/CDROM/Constants.cs b/SabreTools.Serialization/Models/CDROM/Constants.cs
index 3b3a677c..7d1724fd 100644
--- a/SabreTools.Serialization/Models/CDROM/Constants.cs
+++ b/SabreTools.Serialization/Models/CDROM/Constants.cs
@@ -17,18 +17,58 @@ namespace SabreTools.Data.Models.CDROM
public const long Mode0DataSize = 2336;
///
- /// Size of user data length for Mode1 / Mode2 Form1
+ /// Offset in a Mode0 sector where user data starts
+ ///
+ public const long Mode0UserDataStart = 16;
+
+ ///
+ /// Offset in a Mode0 sector where user data ends
+ ///
+ public const long Mode0UserDataEnd = 2064;
+
+ ///
+ /// Size of user data length for Mode1
///
public const long Mode1DataSize = 2048;
///
- /// Size of user data length for Mode1 / Mode2 Form1
+ /// Offset in a Mode1 sector where user data starts
///
- public const long Form1DataSize = 2048;
+ public const long Mode1UserDataStart = 16;
+
+ ///
+ /// Offset in a Mode1 sector where user data ends
+ ///
+ public const long Mode1UserDataEnd = 2064;
+
+ ///
+ /// Size of user data length for Mode2 Form1
+ ///
+ public const long Mode2Form1DataSize = 2048;
+
+ ///
+ /// Offset in a Mode2 Form1 sector where user data starts
+ ///
+ public const long Mode2Form1UserDataStart = 24;
+
+ ///
+ /// Offset in a Mode2 Form1 sector where user data ends
+ ///
+ public const long Mode2Form1UserDataEnd = 2072;
///
/// Size of user data length for Mode2 Form2
///
- public const long Form2DataSize = 2324;
+ public const long Mode2Form2DataSize = 2324;
+
+ ///
+ /// Offset in a Mode2 Form2 sector where user data starts
+ ///
+ public const long Mode2Form2UserDataStart = 24;
+
+ ///
+ /// Offset in a Mode2 Form2 sector where user data ends
+ ///
+ public const long Mode2Form2UserDataEnd = 2072;
}
}
diff --git a/SabreTools.Serialization/Wrappers/CDROM.cs b/SabreTools.Serialization/Wrappers/CDROM.cs
index 76070d47..d9a9c2dc 100644
--- a/SabreTools.Serialization/Wrappers/CDROM.cs
+++ b/SabreTools.Serialization/Wrappers/CDROM.cs
@@ -71,7 +71,7 @@ namespace SabreTools.Serialization.Wrappers
try
{
// Create user data sub-stream
- SabreTools.Data.Extensions.CDROM.ISO9660Stream userData = new(data);
+ var userData = new Data.Extensions.CDROM.ISO9660Stream(data);
// Cache the current offset
long currentOffset = userData.Position;