diff --git a/SabreTools.Serialization/Wrappers/DataSource.cs b/SabreTools.Serialization/Wrappers/DataSource.cs
deleted file mode 100644
index 17745e0a..00000000
--- a/SabreTools.Serialization/Wrappers/DataSource.cs
+++ /dev/null
@@ -1,227 +0,0 @@
-using System;
-using System.IO;
-using SabreTools.IO.Extensions;
-
-namespace SabreTools.Serialization.Wrappers
-{
- ///
- /// Represents the data source backing the wrapper
- ///
- public class DataSource
- {
- #region Properties
-
- ///
- /// Filename from the source, if possible
- ///
- /// String representing the filename on success, null otherwise
- /// This only works if the source was a
- public string? Filename
- {
- get
- {
- // Only streams can have a filename
- if (_dataSourceType != DataSourceType.Stream)
- return null;
-
- // Only file streams can have a filename
- if (_streamData == null || _streamData is not FileStream fs)
- return null;
-
- // Return the name
- return fs.Name;
- }
- }
-
- ///
- /// Usable length of the underlying data
- ///
- /// The usable length on success, -1 on error
- public long Length
- {
- get
- {
- return _dataSourceType switch
- {
- DataSourceType.ByteArray => _byteArrayData!.Length - _initialPosition,
- DataSourceType.Stream => _streamData!.Length - _initialPosition,
-
- // Everything else is invalid
- _ => -1,
- };
- }
- }
-
- #endregion
-
- #region Instance Variables
-
- ///
- /// Source of the original data
- ///
- private readonly DataSourceType _dataSourceType = DataSourceType.UNKNOWN;
-
- ///
- /// Lock object for reading from the source
- ///
- private readonly object _streamDataLock = new();
-
- ///
- /// Initial position of the data source
- ///
- /// Populated for both and
- protected long _initialPosition = 0;
-
- ///
- /// Source byte array data
- ///
- /// This is only populated if is
- protected byte[]? _byteArrayData = null;
-
- ///
- /// Source Stream data
- ///
- /// This is only populated if is
- protected Stream? _streamData = null;
-
- #endregion
-
- #region Constructors
-
- ///
- /// Construct a new DataSource from a Stream
- ///
- ///
- public DataSource(Stream data)
- {
- _dataSourceType = DataSourceType.Stream;
- _initialPosition = data.Position;
- _streamData = data;
- }
-
- ///
- /// Construct a new DataSource from a byte array
- ///
- ///
- ///
- public DataSource(byte[] data, int offset)
- {
- _dataSourceType = DataSourceType.ByteArray;
- _initialPosition = offset;
- _byteArrayData = data;
- }
-
- #endregion
-
- #region Data
-
- ///
- /// Return the underlying data as a stream
- ///
- /// Stream representing the data source on success, null on error
- public Stream? AsStream()
- {
- return _dataSourceType switch
- {
- DataSourceType.ByteArray => new MemoryStream(_byteArrayData!, (int)_initialPosition, (int)Length),
- DataSourceType.Stream => _streamData, // TODO: This should be wrapped better
- _ => null,
- };
- }
-
- ///
- /// Read data from the source
- ///
- /// Position in the source to read from
- /// Length of the requested data
- /// Byte array containing the requested data, null on error
- public byte[]? Read(int position, int length)
- {
- // Validate the data source
- if (!IsValid())
- return null;
-
- // Validate the requested segment
- if (!SegmentValid(position, length))
- return null;
-
- try
- {
- // Read and return the data
- byte[]? sectionData = null;
- switch (_dataSourceType)
- {
- case DataSourceType.ByteArray:
- sectionData = new byte[length];
- Array.Copy(_byteArrayData!, _initialPosition + position, sectionData, 0, length);
- break;
-
- case DataSourceType.Stream:
- lock (_streamDataLock)
- {
- long currentLocation = _streamData!.Position;
- _streamData.Seek(_initialPosition + position, SeekOrigin.Begin);
- sectionData = _streamData.ReadBytes(length);
- _streamData.Seek(currentLocation, SeekOrigin.Begin);
- break;
- }
- }
-
- return sectionData;
-
- }
- catch
- {
- // Absorb the error
- return null;
- }
- }
-
- ///
- /// Validate the backing data source
- ///
- /// True if the data source is valid, false otherwise
- private bool IsValid()
- {
- return _dataSourceType switch
- {
- // Byte array data requires both a valid array and offset
- DataSourceType.ByteArray => _byteArrayData != null && _initialPosition >= 0,
-
- // Stream data requires both a valid stream
- DataSourceType.Stream => _streamData != null && _initialPosition >= 0 && _streamData.CanRead && _streamData.CanSeek,
-
- // Everything else is invalid
- _ => false,
- };
- }
-
- ///
- /// Check if a data segment is valid in the data source
- ///
- /// Position in the source
- /// Length of the data to check
- /// True if the positional data is valid, false otherwise
- private bool SegmentValid(int position, int length)
- {
- // Validate the data souece
- if (!IsValid())
- return false;
-
- // If we have an invalid position
- if (position < 0 || position >= Length)
- return false;
-
- return _dataSourceType switch
- {
- DataSourceType.ByteArray => _initialPosition + position + length <= _byteArrayData!.Length,
- DataSourceType.Stream => _initialPosition + position + length <= _streamData!.Length,
-
- // Everything else is invalid
- _ => false,
- };
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Wrappers/Enums.cs b/SabreTools.Serialization/Wrappers/Enums.cs
deleted file mode 100644
index 6609d876..00000000
--- a/SabreTools.Serialization/Wrappers/Enums.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace SabreTools.Serialization.Wrappers
-{
- ///
- /// Location that the data originated from
- ///
- public enum DataSourceType
- {
- ///
- /// Unknown origin / testing
- ///
- UNKNOWN = 0,
-
- ///
- /// Byte array with offset
- ///
- ByteArray = 1,
-
- ///
- /// Stream
- ///
- Stream = 2,
- }
-}
diff --git a/SabreTools.Serialization/Wrappers/ViewStream.cs b/SabreTools.Serialization/Wrappers/ViewStream.cs
new file mode 100644
index 00000000..db401d54
--- /dev/null
+++ b/SabreTools.Serialization/Wrappers/ViewStream.cs
@@ -0,0 +1,180 @@
+using System;
+using System.IO;
+
+namespace SabreTools.Serialization.Wrappers
+{
+ ///
+ /// Represents the data source backing the wrapper
+ ///
+ public class ViewStream : Stream
+ {
+ #region Properties
+
+ ///
+ /// Filename from the source, if possible
+ ///
+ /// String representing the filename on success, null otherwise
+ /// This only works if the source was a
+ public string? Filename
+ {
+ get
+ {
+ // Only file streams can have a filename
+ if (_streamData == null || _streamData is not FileStream fs)
+ return null;
+
+ // Return the name
+ return fs.Name;
+ }
+ }
+
+ ///
+ public override long Length => _length;
+
+ ///
+ public override long Position
+ {
+ get { return _streamData.Position - _initialPosition; }
+ set { _streamData.Position = value + _initialPosition; }
+ }
+
+ #endregion
+
+ #region Instance Variables
+
+ ///
+ /// Lock object for reading from the source
+ ///
+ private readonly object _streamDataLock = new();
+
+ ///
+ /// Initial position of the data source
+ ///
+ protected long _initialPosition;
+
+ ///
+ /// Usable length of the underlying data
+ ///
+ protected long _length;
+
+ ///
+ /// Source Stream data
+ ///
+ protected Stream _streamData;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Construct a new ViewStream from a Stream
+ ///
+ public ViewStream(Stream data, long offset, long length)
+ {
+ _streamData = data;
+ _initialPosition = offset;
+ _length = length;
+ }
+
+ ///
+ /// Construct a new ViewStream from a byte array
+ ///
+ public ViewStream(byte[] data, long offset, long length)
+ {
+ _streamData = new MemoryStream(data, (int)offset, (int)length);
+ _initialPosition = 0;
+ _length = length;
+ }
+
+ #endregion
+
+ #region Data
+
+ ///
+ /// Check if a data segment is valid in the data source
+ ///
+ /// Position in the source
+ /// Length of the data to check
+ /// True if the positional data is valid, false otherwise
+ public bool SegmentValid(int offset, int count)
+ {
+ // If we have an invalid position
+ if (offset < 0 || offset >= Length)
+ return false;
+
+ return _initialPosition + offset + count <= Length;
+ }
+
+ #endregion
+
+ #region Stream Implementations
+
+ ///
+ public override bool CanRead => true;
+
+ ///
+ public override bool CanWrite => false;
+
+ ///
+ public override bool CanSeek => _streamData.CanSeek;
+
+ ///
+ public override void Flush() => _streamData.Flush();
+
+ ///
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ // Validate the requested segment
+ if (!SegmentValid(offset, count))
+ return 0;
+
+ try
+ {
+ // Correct the read offset
+ offset += (int)_initialPosition;
+ lock (_streamDataLock)
+ {
+ return _streamData.Read(buffer, offset, count);
+ }
+
+ }
+ catch
+ {
+ // Absorb the error
+ return 0;
+ }
+ }
+
+ ///
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ // Handle the "seek"
+ switch (origin)
+ {
+ case SeekOrigin.Begin: Position = offset; break;
+ case SeekOrigin.Current: Position += offset; break;
+ case SeekOrigin.End: Position = _length + offset - 1; break;
+ default: throw new ArgumentException($"Invalid value for {nameof(origin)}");
+ }
+ ;
+
+ // Handle out-of-bounds seeks
+ if (Position < 0)
+ Position = 0;
+ else if (Position >= _length)
+ Position = _length - 1;
+
+ return Position;
+ }
+
+ ///
+ public override void SetLength(long value)
+ => throw new NotImplementedException();
+
+ ///
+ public override void Write(byte[] buffer, int offset, int count)
+ => throw new NotImplementedException();
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Wrappers/WrapperBase.cs b/SabreTools.Serialization/Wrappers/WrapperBase.cs
index ca93c334..abce2e33 100644
--- a/SabreTools.Serialization/Wrappers/WrapperBase.cs
+++ b/SabreTools.Serialization/Wrappers/WrapperBase.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
+using SabreTools.IO.Extensions;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Wrappers
@@ -22,13 +23,15 @@ namespace SabreTools.Serialization.Wrappers
#region Properties
- ///
- public Stream? DataSourceStream => _dataSource.AsStream();
+ ///
+ /// Data source as a stream
+ ///
+ public Stream? DataSourceStream => _dataSource;
- ///
+ ///
public string? Filename => _dataSource.Filename;
- ///
+ ///
public long Length => _dataSource.Length;
#endregion
@@ -38,7 +41,7 @@ namespace SabreTools.Serialization.Wrappers
///
/// Source of the original data
///
- private readonly DataSource _dataSource;
+ private readonly ViewStream _dataSource;
#if NETCOREAPP
///
@@ -75,7 +78,7 @@ namespace SabreTools.Serialization.Wrappers
if (offset < 0 || offset >= data.Length)
throw new ArgumentOutOfRangeException(nameof(offset));
- _dataSource = new DataSource(data, offset);
+ _dataSource = new ViewStream(data, offset, data.Length - offset);
}
///
@@ -88,7 +91,7 @@ namespace SabreTools.Serialization.Wrappers
if (!data.CanSeek || !data.CanRead)
throw new ArgumentOutOfRangeException(nameof(data));
- _dataSource = new DataSource(data);
+ _dataSource = new ViewStream(data, data.Position, data.Length - data.Position);
}
#endregion
@@ -102,7 +105,28 @@ namespace SabreTools.Serialization.Wrappers
/// Length of the requested data
/// Byte array containing the requested data, null on error
public byte[]? ReadFromDataSource(int position, int length)
- => _dataSource.Read(position, length);
+ {
+ // Validate the requested segment
+ if (!_dataSource.SegmentValid(position, length))
+ return null;
+
+ try
+ {
+ long currentLocation = _dataSource.Position;
+
+ _dataSource.Seek(position, SeekOrigin.Begin);
+ byte[] sectionData = _dataSource.ReadBytes(length);
+ _dataSource.Seek(currentLocation, SeekOrigin.Begin);
+
+ return sectionData;
+
+ }
+ catch
+ {
+ // Absorb the error
+ return null;
+ }
+ }
///
/// Read string data from the source