mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-07-08 18:06:41 +00:00
Separate out some helper methods
This commit is contained in:
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the sector mode for a CD-ROM stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream to derive the sector mode from</param>
|
||||
/// <returns>Sector mode from the stream on success, <see cref="SectorMode.UNKNOWN"/> on error</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the user data size for a sector mode
|
||||
/// </summary>
|
||||
/// <param name="mode">Sector mode to get a value for</param>
|
||||
/// <returns>User data size, if possible</returns>
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the user data end offset for a sector mode
|
||||
/// </summary>
|
||||
/// <param name="mode">Sector mode to get a value for</param>
|
||||
/// <returns>User data end offset, if possible</returns>
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the user data start offset for a sector mode
|
||||
/// </summary>
|
||||
/// <param name="mode">Sector mode to get a value for</param>
|
||||
/// <returns>User data start offset, if possible</returns>
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stream that provides only the user data of a CDROM stream
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
/// <inheritdoc/>
|
||||
public override bool CanRead => _baseStream.CanRead;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanSeek => _baseStream.CanSeek;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
_baseStream.Flush();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void Flush() => _baseStream.Flush();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
@@ -47,25 +145,28 @@ namespace SabreTools.Data.Extensions
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("Setting the length of this stream is not supported.");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException("Writing to this stream is not supported.");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_baseStream.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override long Position
|
||||
{
|
||||
// Get the position of the underlying ISO9660 stream
|
||||
@@ -93,16 +194,16 @@ namespace SabreTools.Data.Extensions
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the current stream state based on the location
|
||||
/// </summary>
|
||||
/// <param name="sectorLocation">Sector location to update from</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,58 @@ namespace SabreTools.Data.Models.CDROM
|
||||
public const long Mode0DataSize = 2336;
|
||||
|
||||
/// <summary>
|
||||
/// Size of user data length for Mode1 / Mode2 Form1
|
||||
/// Offset in a Mode0 sector where user data starts
|
||||
/// </summary>
|
||||
public const long Mode0UserDataStart = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in a Mode0 sector where user data ends
|
||||
/// </summary>
|
||||
public const long Mode0UserDataEnd = 2064;
|
||||
|
||||
/// <summary>
|
||||
/// Size of user data length for Mode1
|
||||
/// </summary>
|
||||
public const long Mode1DataSize = 2048;
|
||||
|
||||
/// <summary>
|
||||
/// Size of user data length for Mode1 / Mode2 Form1
|
||||
/// Offset in a Mode1 sector where user data starts
|
||||
/// </summary>
|
||||
public const long Form1DataSize = 2048;
|
||||
public const long Mode1UserDataStart = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in a Mode1 sector where user data ends
|
||||
/// </summary>
|
||||
public const long Mode1UserDataEnd = 2064;
|
||||
|
||||
/// <summary>
|
||||
/// Size of user data length for Mode2 Form1
|
||||
/// </summary>
|
||||
public const long Mode2Form1DataSize = 2048;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in a Mode2 Form1 sector where user data starts
|
||||
/// </summary>
|
||||
public const long Mode2Form1UserDataStart = 24;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in a Mode2 Form1 sector where user data ends
|
||||
/// </summary>
|
||||
public const long Mode2Form1UserDataEnd = 2072;
|
||||
|
||||
/// <summary>
|
||||
/// Size of user data length for Mode2 Form2
|
||||
/// </summary>
|
||||
public const long Form2DataSize = 2324;
|
||||
public const long Mode2Form2DataSize = 2324;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in a Mode2 Form2 sector where user data starts
|
||||
/// </summary>
|
||||
public const long Mode2Form2UserDataStart = 24;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in a Mode2 Form2 sector where user data ends
|
||||
/// </summary>
|
||||
public const long Mode2Form2UserDataEnd = 2072;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user