Skip to content

Commit 3bb501c

Browse files
committed
Separate out some helper methods
1 parent d0006a4 commit 3bb501c

File tree

3 files changed

+186
-104
lines changed

3 files changed

+186
-104
lines changed

SabreTools.Serialization/Extensions/CDROM.cs

Lines changed: 141 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,106 @@
11
using System;
22
using System.IO;
33
using SabreTools.Data.Models.CDROM;
4-
using SabreTools.IO;
54
using SabreTools.IO.Extensions;
65

76
namespace SabreTools.Data.Extensions
87
{
98
public static class CDROM
109
{
10+
/// <summary>
11+
/// Get the sector mode for a CD-ROM stream
12+
/// </summary>
13+
/// <param name="stream">Stream to derive the sector mode from</param>
14+
/// <returns>Sector mode from the stream on success, <see cref="SectorMode.UNKNOWN"/> on error</returns>
15+
public static SectorMode GetSectorMode(this Stream stream)
16+
{
17+
try
18+
{
19+
byte modeByte = stream.ReadByteValue();
20+
if (modeByte == 0)
21+
{
22+
return SectorMode.MODE0;
23+
}
24+
else if (modeByte == 1)
25+
{
26+
return SectorMode.MODE1;
27+
}
28+
else if (modeByte == 2)
29+
{
30+
stream.SeekIfPossible(2, SeekOrigin.Current);
31+
byte submode = stream.ReadByteValue();
32+
if ((submode & 0x20) == 0x20)
33+
return SectorMode.MODE2_FORM2;
34+
else
35+
return SectorMode.MODE2_FORM1;
36+
}
37+
else
38+
{
39+
return SectorMode.UNKNOWN;
40+
}
41+
}
42+
catch
43+
{
44+
// Ignore the actual error
45+
return SectorMode.UNKNOWN;
46+
}
47+
48+
}
49+
50+
/// <summary>
51+
/// Get the user data size for a sector mode
52+
/// </summary>
53+
/// <param name="mode">Sector mode to get a value for</param>
54+
/// <returns>User data size, if possible</returns>
55+
public static long GetUserDataSize(this SectorMode mode)
56+
{
57+
return mode switch
58+
{
59+
SectorMode.MODE0 => Constants.Mode0DataSize,
60+
SectorMode.MODE1 => Constants.Mode1DataSize,
61+
SectorMode.MODE2 => Constants.Mode0DataSize,
62+
SectorMode.MODE2_FORM1 => Constants.Mode2Form1DataSize,
63+
SectorMode.MODE2_FORM2 => Constants.Mode2Form2DataSize,
64+
_ => Constants.Mode0DataSize,
65+
};
66+
}
67+
68+
/// <summary>
69+
/// Get the user data end offset for a sector mode
70+
/// </summary>
71+
/// <param name="mode">Sector mode to get a value for</param>
72+
/// <returns>User data end offset, if possible</returns>
73+
public static long GetUserDataEnd(this SectorMode mode)
74+
{
75+
return mode switch
76+
{
77+
SectorMode.MODE0 => Constants.Mode0UserDataEnd, // TODO: Support flexible sector length (2352)
78+
SectorMode.MODE1 => Constants.Mode1UserDataEnd,
79+
SectorMode.MODE2 => Constants.Mode0UserDataEnd, // TODO: Support flexible sector length (2352)
80+
SectorMode.MODE2_FORM1 => Constants.Mode2Form1UserDataEnd,
81+
SectorMode.MODE2_FORM2 => Constants.Mode2Form2UserDataEnd, // TODO: Support flexible sector length (2348)
82+
_ => Constants.Mode0UserDataEnd,
83+
};
84+
}
85+
86+
/// <summary>
87+
/// Get the user data start offset for a sector mode
88+
/// </summary>
89+
/// <param name="mode">Sector mode to get a value for</param>
90+
/// <returns>User data start offset, if possible</returns>
91+
public static long GetUserDataStart(this SectorMode mode)
92+
{
93+
return mode switch
94+
{
95+
SectorMode.MODE0 => Constants.Mode0UserDataStart,
96+
SectorMode.MODE1 => Constants.Mode1UserDataStart,
97+
SectorMode.MODE2 => Constants.Mode0UserDataStart,
98+
SectorMode.MODE2_FORM1 => Constants.Mode2Form1UserDataStart,
99+
SectorMode.MODE2_FORM2 => Constants.Mode2Form2UserDataStart,
100+
_ => Constants.Mode0UserDataStart,
101+
};
102+
}
103+
11104
/// <summary>
12105
/// Creates a stream that provides only the user data of a CDROM stream
13106
/// </summary>
@@ -19,26 +112,31 @@ public class ISO9660Stream : Stream
19112
// State variables
20113
private long _position = 0;
21114
private SectorMode _currentMode = SectorMode.UNKNOWN;
22-
private long _userDataStart = 16;
23-
private long _userDataEnd = 2064;
115+
private long _userDataStart = Constants.Mode1UserDataStart;
116+
private long _userDataEnd = Constants.Mode1UserDataEnd;
24117
private long _isoSectorSize = Constants.Mode1DataSize;
25118

26119
public ISO9660Stream(Stream inputStream)
27120
{
28121
if (!inputStream.CanSeek || !inputStream.CanRead)
29122
throw new ArgumentException("Stream must be readable and seekable.", nameof(inputStream));
123+
30124
_baseStream = inputStream;
31125
}
32126

33-
public override bool CanRead => true;
34-
public override bool CanSeek => true;
127+
/// <inheritdoc/>
128+
public override bool CanRead => _baseStream.CanRead;
129+
130+
/// <inheritdoc/>
131+
public override bool CanSeek => _baseStream.CanSeek;
132+
133+
/// <inheritdoc/>
35134
public override bool CanWrite => false;
36135

37-
public override void Flush()
38-
{
39-
_baseStream.Flush();
40-
}
136+
/// <inheritdoc/>
137+
public override void Flush() => _baseStream.Flush();
41138

139+
/// <inheritdoc/>
42140
public override long Length
43141
{
44142
get
@@ -47,25 +145,28 @@ public override long Length
47145
}
48146
}
49147

148+
/// <inheritdoc/>
50149
public override void SetLength(long value)
51150
{
52151
throw new NotSupportedException("Setting the length of this stream is not supported.");
53152
}
54153

154+
/// <inheritdoc/>
55155
public override void Write(byte[] buffer, int offset, int count)
56156
{
57157
throw new NotSupportedException("Writing to this stream is not supported.");
58158
}
59159

160+
/// <inheritdoc/>
60161
protected override void Dispose(bool disposing)
61162
{
62163
if (disposing)
63-
{
64164
_baseStream.Dispose();
65-
}
165+
66166
base.Dispose(disposing);
67167
}
68168

169+
/// <inheritdoc/>
69170
public override long Position
70171
{
71172
// Get the position of the underlying ISO9660 stream
@@ -93,16 +194,16 @@ public override long Position
93194
}
94195
}
95196

197+
/// <inheritdoc/>
96198
public override int Read(byte[] buffer, int offset, int count)
97199
{
98-
bool readEntireSector = false;
99200
int totalRead = 0;
100201
int remaining = count;
101202

102203
while (remaining > 0 && _position < _baseStream.Length)
103204
{
104205
// Determine location of current sector
105-
long baseStreamOffset = (_position / Constants.CDROMSectorSize) * Constants.CDROMSectorSize;
206+
long baseStreamOffset = _position - (_position % Constants.CDROMSectorSize);
106207

107208
// Set the current sector's mode and user data location
108209
SetState(baseStreamOffset);
@@ -123,28 +224,23 @@ public override int Read(byte[] buffer, int offset, int count)
123224
_position += Constants.CDROMSectorSize - _userDataEnd + _userDataStart;
124225
}
125226
else
227+
{
126228
baseStreamOffset += remainder;
229+
}
127230

128231
// Sanity check on read location before seeking
129232
if (baseStreamOffset < 0 || baseStreamOffset > _baseStream.Length)
130-
{
131233
throw new ArgumentOutOfRangeException(nameof(offset), "Attempted to seek outside the stream boundaries.");
132-
}
133234

134235
// Seek to target position in base CDROM stream
135-
_baseStream.Seek(baseStreamOffset, SeekOrigin.Begin);
236+
_baseStream.SeekIfPossible(baseStreamOffset, SeekOrigin.Begin);
136237

137238
// Read the remaining bytes, up to max of one ISO sector (2048 bytes)
138239
int bytesToRead = (int)Math.Min(remaining, _isoSectorSize - sectorOffset);
139240

140241
// Don't overshoot end of stream
141242
bytesToRead = (int)Math.Min(bytesToRead, _baseStream.Length - _position);
142243

143-
if (bytesToRead == (_isoSectorSize - sectorOffset))
144-
readEntireSector = true;
145-
else
146-
readEntireSector = false;
147-
148244
// Finish reading if no more bytes to be read
149245
if (bytesToRead <= 0)
150246
break;
@@ -154,7 +250,7 @@ public override int Read(byte[] buffer, int offset, int count)
154250

155251
// Update state for base stream
156252
_position = _baseStream.Position;
157-
if (readEntireSector)
253+
if (bytesToRead == (_isoSectorSize - sectorOffset))
158254
_position += (Constants.CDROMSectorSize - _userDataEnd) + _userDataStart;
159255

160256
// Update state for ISO stream
@@ -168,24 +264,17 @@ public override int Read(byte[] buffer, int offset, int count)
168264
return totalRead;
169265
}
170266

267+
/// <inheritdoc/>
171268
public override long Seek(long offset, SeekOrigin origin)
172269
{
173270
// Get the intended position for the ISO9660 stream
174-
long targetPosition;
175-
switch (origin)
271+
var targetPosition = origin switch
176272
{
177-
case SeekOrigin.Begin:
178-
targetPosition = offset;
179-
break;
180-
case SeekOrigin.Current:
181-
targetPosition = Position + offset;
182-
break;
183-
case SeekOrigin.End:
184-
targetPosition = Length + offset;
185-
break;
186-
default:
187-
throw new ArgumentException("Invalid SeekOrigin.", nameof(origin));
188-
}
273+
SeekOrigin.Begin => offset,
274+
SeekOrigin.Current => Position + offset,
275+
SeekOrigin.End => Length + offset,
276+
_ => throw new ArgumentException("Invalid SeekOrigin.", nameof(origin)),
277+
};
189278

190279
// Get the number of ISO sectors before current position
191280
long newPosition = (targetPosition / _isoSectorSize) * Constants.CDROMSectorSize;
@@ -195,80 +284,33 @@ public override long Seek(long offset, SeekOrigin origin)
195284

196285
// Add the within-sector position
197286
newPosition += _userDataStart + (targetPosition % _isoSectorSize);
198-
199287
if (newPosition < 0 || newPosition > _baseStream.Length)
200-
{
201288
throw new ArgumentOutOfRangeException(nameof(offset), "Attempted to seek outside the stream boundaries.");
202-
}
203289

204-
_position = _baseStream.Seek(newPosition, SeekOrigin.Begin);
290+
_position = _baseStream.SeekIfPossible(newPosition, SeekOrigin.Begin);
205291
return Position;
206292
}
207293

294+
/// <summary>
295+
/// Update the current stream state based on the location
296+
/// </summary>
297+
/// <param name="sectorLocation">Sector location to update from</param>
208298
private void SetState(long sectorLocation)
209299
{
210-
long oldPosition = _baseStream.Position;
211-
long modePosition = (sectorLocation - sectorLocation % Constants.CDROMSectorSize) + 15;
212-
_baseStream.Seek(modePosition, SeekOrigin.Begin);
213-
byte modeByte = _baseStream.ReadByteValue();
214-
if (modeByte == 0)
215-
_currentMode = SectorMode.MODE0;
216-
else if (modeByte == 1)
217-
_currentMode = SectorMode.MODE1;
218-
else if (modeByte == 2)
219-
{
220-
_baseStream.Seek(modePosition + 3, SeekOrigin.Begin);
221-
byte submode = _baseStream.ReadByteValue();
222-
if ((submode & 0x20) == 0x20)
223-
_currentMode = SectorMode.MODE2_FORM2;
224-
else
225-
_currentMode = SectorMode.MODE2_FORM1;
226-
}
227-
else
228-
_currentMode = SectorMode.UNKNOWN;
300+
long current = _baseStream.Position;
301+
long modePosition = sectorLocation - (sectorLocation % Constants.CDROMSectorSize) + 15;
229302

230-
// Set the user data location variables
231-
switch (_currentMode)
232-
{
233-
case SectorMode.MODE1:
234-
_userDataStart = 16;
235-
_userDataEnd = 2064;
236-
//_isoSectorSize = Constants.Mode1DataSize;
237-
break;
303+
// Get the current sector mode
304+
_baseStream.SeekIfPossible(modePosition, SeekOrigin.Begin);
305+
_currentMode = _baseStream.GetSectorMode();
238306

239-
case SectorMode.MODE2_FORM1:
240-
_userDataStart = 24;
241-
_userDataEnd = 2072;
242-
//_isoSectorSize = Constants.Form1DataSize;
243-
break;
244-
245-
case SectorMode.MODE2_FORM2:
246-
_userDataStart = 24;
247-
_userDataEnd = 2072;
248-
// TODO: Support flexible sector length
249-
//_userDataEnd = 2348;
250-
//_isoSectorSize = Constants.Form2DataSize;
251-
break;
252-
253-
case SectorMode.MODE0:
254-
case SectorMode.MODE2:
255-
_userDataStart = 16;
256-
_userDataEnd = 2064;
257-
// TODO: Support flexible sector length
258-
//_userDataEnd = 2352;
259-
//_isoSectorSize = Constants.Mode0DataSize;
260-
break;
261-
262-
case SectorMode.UNKNOWN:
263-
_userDataStart = 16;
264-
_userDataEnd = 2064;
265-
//_isoSectorSize = Constants.Mode1DataSize;
266-
break;
267-
}
268-
269-
_baseStream.Seek(oldPosition, SeekOrigin.Begin);
307+
// Set the user data location variables
308+
_userDataStart = _currentMode.GetUserDataStart();
309+
_userDataEnd = _currentMode.GetUserDataEnd();
310+
// _isoSectorSize = _currentMode.GetUserDataSize();
270311

271-
return;
312+
// Reset the stream position
313+
_baseStream.SeekIfPossible(current, SeekOrigin.Begin);
272314
}
273315
}
274316
}

0 commit comments

Comments
 (0)