Move things to base classes

This commit is contained in:
Matt Nadareski
2025-08-23 12:58:09 -04:00
parent 456bb1e95b
commit c87a456a46
10 changed files with 368 additions and 362 deletions

View File

@@ -19,41 +19,20 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region Instance Variables
/// <summary>
/// Source filename for the wrapper
/// </summary>
private readonly string? _filename;
/// <summary>
/// Source stream for the wrapper
/// </summary>
private readonly Stream _stream;
#endregion
#region Constructors
/// <summary>
/// Construct a new instance of the wrapper from a file path
/// </summary>
public BZip2(string filename)
/// <inheritdoc/>
public BZip2(byte[]? data, int offset)
: base(data, offset)
{
_filename = filename;
_stream = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// All logic is handled by the base class
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
public BZip2(Stream stream)
/// <inheritdoc/>
public BZip2(Stream? data)
: base(data)
{
_filename = null;
_stream = stream;
if (stream is FileStream fs)
_filename = fs.Name;
// All logic is handled by the base class
}
/// <summary>
@@ -108,13 +87,13 @@ namespace SabreTools.Serialization.Wrappers
/// <inheritdoc/>
public bool Extract(string outputDirectory, bool includeDebug)
{
if (_stream == null || !_stream.CanRead)
if (DataSourceStream == null || !DataSourceStream.CanRead)
return false;
try
{
// Try opening the stream
using var bz2File = new BZip2InputStream(_stream, true);
using var bz2File = new BZip2InputStream(DataSourceStream, true);
// Ensure directory separators are consistent
string filename = Guid.NewGuid().ToString();

View File

@@ -115,6 +115,20 @@ namespace SabreTools.Serialization.Wrappers
#region Data
/// <summary>
/// Return the underlying data as a stream
/// </summary>
/// <returns>Stream representing the data source on success, null on error</returns>
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,
};
}
/// <summary>
/// Read data from the source
/// </summary>

View File

@@ -19,41 +19,20 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region Instance Variables
/// <summary>
/// Source filename for the wrapper
/// </summary>
private readonly string? _filename;
/// <summary>
/// Source stream for the wrapper
/// </summary>
private readonly Stream _stream;
#endregion
#region Constructors
/// <summary>
/// Construct a new instance of the wrapper from a file path
/// </summary>
public GZip(string filename)
/// <inheritdoc/>
public GZip(byte[]? data, int offset)
: base(data, offset)
{
_filename = filename;
_stream = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// All logic is handled by the base class
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
public GZip(Stream stream)
/// <inheritdoc/>
public GZip(Stream? data)
: base(data)
{
_filename = null;
_stream = stream;
if (stream is FileStream fs)
_filename = fs.Name;
// All logic is handled by the base class
}
/// <summary>
@@ -107,13 +86,13 @@ namespace SabreTools.Serialization.Wrappers
/// <inheritdoc/>
public bool Extract(string outputDirectory, bool includeDebug)
{
if (_stream == null || !_stream.CanRead)
if (DataSourceStream == null || !DataSourceStream.CanRead)
return false;
try
{
// Try opening the stream
using var gzipFile = new GZipStream(_stream, CompressionMode.Decompress, true);
using var gzipFile = new GZipStream(DataSourceStream, CompressionMode.Decompress, true);
// Ensure directory separators are consistent
string filename = Guid.NewGuid().ToString();

View File

@@ -1,9 +1,15 @@
using System.IO;
using SabreTools.Models.PKZIP;
using SabreTools.Serialization.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
using SharpCompress.Readers;
#endif
namespace SabreTools.Serialization.Wrappers
{
public class PKZIP : WrapperBase<Archive>
public class PKZIP : WrapperBase<Archive>, IExtractable
{
#region Descriptive Properties
@@ -75,5 +81,78 @@ namespace SabreTools.Serialization.Wrappers
}
#endregion
#region Extraction
/// <inheritdoc/>
public bool Extract(string outputDirectory, bool includeDebug)
=> Extract(outputDirectory, lookForHeader: false, includeDebug);
/// <inheritdoc cref="Extract(string, bool)"/>
public bool Extract(string outputDirectory, bool lookForHeader, bool includeDebug)
{
if (DataSourceStream == null || !DataSourceStream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
var zipFile = ZipArchive.Open(DataSourceStream, readerOptions);
// Try to read the file path if no entries are found
if (zipFile.Entries.Count == 0 && !string.IsNullOrEmpty(Filename) && File.Exists(Filename!))
zipFile = ZipArchive.Open(Filename!, readerOptions);
foreach (var entry in zipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry is partial due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
// Ensure directory separators are consistent
string filename = entry.Key;
if (Path.DirectorySeparatorChar == '\\')
filename = filename.Replace('/', '\\');
else if (Path.DirectorySeparatorChar == '/')
filename = filename.Replace('\\', '/');
// Ensure the full output directory exists
filename = Path.Combine(outputDirectory, filename);
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(filename);
}
catch (System.Exception ex)
{
if (includeDebug) System.Console.Error.WriteLine(ex);
}
}
return true;
}
catch (System.Exception ex)
{
if (includeDebug) System.Console.Error.WriteLine(ex);
return false;
}
#else
return false;
#endif
}
#endregion
}
}

View File

@@ -23,41 +23,20 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region Instance Variables
/// <summary>
/// Source filename for the wrapper
/// </summary>
private readonly string? _filename;
/// <summary>
/// Source stream for the wrapper
/// </summary>
private readonly Stream _stream;
#endregion
#region Constructors
/// <summary>
/// Construct a new instance of the wrapper from a file path
/// </summary>
public RAR(string filename)
/// <inheritdoc/>
public RAR(byte[]? data, int offset)
: base(data, offset)
{
_filename = filename;
_stream = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// All logic is handled by the base class
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
public RAR(Stream stream)
/// <inheritdoc/>
public RAR(Stream? data)
: base(data)
{
_filename = null;
_stream = stream;
if (stream is FileStream fs)
_filename = fs.Name;
// All logic is handled by the base class
}
/// <summary>
@@ -115,18 +94,18 @@ namespace SabreTools.Serialization.Wrappers
/// <inheritdoc cref="Extract(string, bool)"/>
public bool Extract(string outputDirectory, bool lookForHeader, bool includeDebug)
{
if (_stream == null || !_stream.CanRead)
if (DataSourceStream == null || !DataSourceStream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
RarArchive rarFile = RarArchive.Open(_stream, readerOptions);
RarArchive rarFile = RarArchive.Open(DataSourceStream, readerOptions);
// Try to read the file path if no entries are found
if (rarFile.Entries.Count == 0 && !string.IsNullOrEmpty(_filename) && File.Exists(_filename))
rarFile = RarArchive.Open(_filename, readerOptions);
if (rarFile.Entries.Count == 0 && !string.IsNullOrEmpty(Filename) && File.Exists(Filename!))
rarFile = RarArchive.Open(Filename!, readerOptions);
if (!rarFile.IsComplete)
return false;

View File

@@ -23,41 +23,20 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region Instance Variables
/// <summary>
/// Source filename for the wrapper
/// </summary>
private readonly string? _filename;
/// <summary>
/// Source stream for the wrapper
/// </summary>
private readonly Stream _stream;
#endregion
#region Constructors
/// <summary>
/// Construct a new instance of the wrapper from a file path
/// </summary>
public SevenZip(string filename)
/// <inheritdoc/>
public SevenZip(byte[]? data, int offset)
: base(data, offset)
{
_filename = filename;
_stream = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// All logic is handled by the base class
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
public SevenZip(Stream stream)
/// <inheritdoc/>
public SevenZip(Stream? data)
: base(data)
{
_filename = null;
_stream = stream;
if (stream is FileStream fs)
_filename = fs.Name;
// All logic is handled by the base class
}
/// <summary>
@@ -115,17 +94,17 @@ namespace SabreTools.Serialization.Wrappers
/// <inheritdoc cref="Extract(string, bool)"/>
public bool Extract(string outputDirectory, bool lookForHeader, bool includeDebug)
{
if (_stream == null || !_stream.CanRead)
if (DataSourceStream == null || !DataSourceStream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
var sevenZip = SevenZipArchive.Open(_stream, readerOptions);
var sevenZip = SevenZipArchive.Open(DataSourceStream, readerOptions);
// Try to read the file path if no entries are found
if (sevenZip.Entries.Count == 0 && !string.IsNullOrEmpty(_filename) && File.Exists(_filename))
sevenZip = SevenZipArchive.Open(_filename, readerOptions);
if (sevenZip.Entries.Count == 0 && !string.IsNullOrEmpty(Filename) && File.Exists(Filename!))
sevenZip = SevenZipArchive.Open(Filename!, readerOptions);
// Currently doesn't flag solid 7z archives with only 1 solid block as solid, but practically speaking
// this is not much of a concern.

View File

@@ -21,41 +21,20 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region Instance Variables
/// <summary>
/// Source filename for the wrapper
/// </summary>
private readonly string? _filename;
/// <summary>
/// Source stream for the wrapper
/// </summary>
private readonly Stream _stream;
#endregion
#region Constructors
/// <summary>
/// Construct a new instance of the wrapper from a file path
/// </summary>
public TapeArchive(string filename)
//// <inheritdoc/>
public TapeArchive(byte[]? data, int offset)
: base(data, offset)
{
_filename = filename;
_stream = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// All logic is handled by the base class
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
public TapeArchive(Stream stream)
/// <inheritdoc/>
public TapeArchive(Stream? data)
: base(data)
{
_filename = null;
_stream = stream;
if (stream is FileStream fs)
_filename = fs.Name;
// All logic is handled by the base class
}
/// <summary>
@@ -109,17 +88,17 @@ namespace SabreTools.Serialization.Wrappers
/// <inheritdoc/>
public bool Extract(string outputDirectory, bool includeDebug)
{
if (_stream == null || !_stream.CanRead)
if (DataSourceStream == null || !DataSourceStream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
var tarFile = TarArchive.Open(_stream);
var tarFile = TarArchive.Open(DataSourceStream);
// Try to read the file path if no entries are found
if (tarFile.Entries.Count == 0 && !string.IsNullOrEmpty(_filename) && File.Exists(_filename))
tarFile = TarArchive.Open(_filename);
if (tarFile.Entries.Count == 0 && !string.IsNullOrEmpty(Filename) && File.Exists(Filename!))
tarFile = TarArchive.Open(Filename!);
foreach (var entry in tarFile.Entries)
{

View File

@@ -1,3 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Wrappers
@@ -16,6 +20,208 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region Properties
/// <inheritdoc cref="DataSource.AsStream"/>
public Stream? DataSourceStream => _dataSource.AsStream();
/// <inheritdoc cref="DataSource.Filename"/>
public string? Filename => _dataSource.Filename;
/// <inheritdoc cref="DataSource.Length"/>
public long Length => _dataSource.Length;
#endregion
#region Instance Variables
/// <summary>
/// Source of the original data
/// </summary>
private readonly DataSource _dataSource;
#if NETCOREAPP
/// <summary>
/// JSON serializer options for output printing
/// </summary>
protected System.Text.Json.JsonSerializerOptions _jsonSerializerOptions
{
get
{
#if NETCOREAPP3_1
var serializer = new System.Text.Json.JsonSerializerOptions { WriteIndented = true };
#else
var serializer = new System.Text.Json.JsonSerializerOptions { IncludeFields = true, WriteIndented = true };
#endif
serializer.Converters.Add(new ConcreteAbstractSerializer());
serializer.Converters.Add(new ConcreteInterfaceSerializer());
serializer.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
return serializer;
}
}
#endif
#endregion
#region Constructors
/// <summary>
/// Construct a new instance of the wrapper from a byte array
/// </summary>
protected WrapperBase(byte[]? data, int offset)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
if (offset < 0 || offset >= data.Length)
throw new ArgumentOutOfRangeException(nameof(offset));
_dataSource = new DataSource(data, offset);
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
protected WrapperBase(Stream? data)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
if (!data.CanSeek || !data.CanRead)
throw new ArgumentOutOfRangeException(nameof(data));
_dataSource = new DataSource(data);
}
#endregion
#region Data
/// <summary>
/// Read data from the source
/// </summary>
/// <param name="position">Position in the source to read from</param>
/// <param name="length">Length of the requested data</param>
/// <returns>Byte array containing the requested data, null on error</returns>
public byte[]? ReadFromDataSource(int position, int length)
=> _dataSource.Read(position, length);
/// <summary>
/// Read string data from the source
/// </summary>
/// <param name="position">Position in the source to read from</param>
/// <param name="length">Length of the requested data</param>
/// <param name="charLimit">Number of characters needed to be a valid string</param>
/// <returns>String list containing the requested data, null on error</returns>
public List<string>? ReadStringsFromDataSource(int position, int length, int charLimit = 5)
{
// Read the data as a byte array first
byte[]? sourceData = ReadFromDataSource(position, length);
if (sourceData == null)
return null;
// Check for ASCII strings
var asciiStrings = ReadStringsWithEncoding(sourceData, charLimit, Encoding.ASCII);
// Check for UTF-8 strings
// We are limiting the check for Unicode characters with a second byte of 0x00 for now
var utf8Strings = ReadStringsWithEncoding(sourceData, charLimit, Encoding.UTF8);
// Check for Unicode strings
// We are limiting the check for Unicode characters with a second byte of 0x00 for now
var unicodeStrings = ReadStringsWithEncoding(sourceData, charLimit, Encoding.Unicode);
// Ignore duplicate strings across encodings
List<string> sourceStrings = [.. asciiStrings, .. utf8Strings, .. unicodeStrings];
// Sort the strings and return
sourceStrings.Sort();
return sourceStrings;
}
/// <summary>
/// Read string data from the source with an encoding
/// </summary>
/// <param name="sourceData">Byte array representing the source data</param>
/// <param name="charLimit">Number of characters needed to be a valid string</param>
/// <param name="encoding">Character encoding to use for checking</param>
/// <returns>String list containing the requested data, empty on error</returns>
/// <remarks>TODO: Move to IO?</remarks>
#if NET20
private static List<string> ReadStringsWithEncoding(byte[] sourceData, int charLimit, Encoding encoding)
#else
private static HashSet<string> ReadStringsWithEncoding(byte[] sourceData, int charLimit, Encoding encoding)
#endif
{
// If we have an invalid character limit, default to 5
if (charLimit <= 0)
charLimit = 5;
// Create the string hash set to return
#if NET20
var sourceStrings = new List<string>();
#else
var sourceStrings = new HashSet<string>();
#endif
// Setup cached data
int sourceDataIndex = 0;
List<char> cachedChars = [];
// Check for strings
while (sourceDataIndex < sourceData.Length)
{
// Read the next character
char ch = encoding.GetChars(sourceData, sourceDataIndex, 1)[0];
// If we have a control character or an invalid byte
bool isValid = !char.IsControl(ch) && (ch & 0xFF00) == 0;
if (!isValid)
{
// If we have no cached string
if (cachedChars.Count == 0)
{
sourceDataIndex++;
continue;
}
// If we have a cached string greater than the limit
if (cachedChars.Count >= charLimit)
sourceStrings.Add(new string([.. cachedChars]));
cachedChars.Clear();
sourceDataIndex++;
continue;
}
// If a long repeating string is found, discard it
if (cachedChars.Count >= 64 && cachedChars.TrueForAll(c => c == cachedChars[0]))
{
cachedChars.Clear();
sourceDataIndex++;
continue;
}
// Append the character to the cached string
cachedChars.Add(ch);
sourceDataIndex++;
}
// If we have a cached string greater than the limit
if (cachedChars.Count >= charLimit)
{
// Get the string from the cached characters
string cachedString = new([.. cachedChars]);
cachedString = cachedString.Trim();
// Only include trimmed strings over the limit
if (cachedString.Length >= charLimit)
sourceStrings.Add(cachedString);
}
return sourceStrings;
}
#endregion
#region JSON Export
#if NETCOREAPP

View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Wrappers
@@ -18,42 +16,6 @@ namespace SabreTools.Serialization.Wrappers
/// </summary>
public T Model { get; }
/// <inheritdoc cref="DataSource.Filename"/>
public string? Filename => _dataSource.Filename;
/// <inheritdoc cref="DataSource.Length"/>
public long Length => _dataSource.Length;
#endregion
#region Instance Variables
/// <summary>
/// Source of the original data
/// </summary>
private readonly DataSource _dataSource;
#if NETCOREAPP
/// <summary>
/// JSON serializer options for output printing
/// </summary>
private System.Text.Json.JsonSerializerOptions _jsonSerializerOptions
{
get
{
#if NETCOREAPP3_1
var serializer = new System.Text.Json.JsonSerializerOptions { WriteIndented = true };
#else
var serializer = new System.Text.Json.JsonSerializerOptions { IncludeFields = true, WriteIndented = true };
#endif
serializer.Converters.Add(new ConcreteAbstractSerializer());
serializer.Converters.Add(new ConcreteInterfaceSerializer());
serializer.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
return serializer;
}
}
#endif
#endregion
#region Constructors
@@ -62,6 +24,7 @@ namespace SabreTools.Serialization.Wrappers
/// Construct a new instance of the wrapper from a byte array
/// </summary>
protected WrapperBase(T? model, byte[]? data, int offset)
: base(data, offset)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
@@ -71,13 +34,13 @@ namespace SabreTools.Serialization.Wrappers
throw new ArgumentOutOfRangeException(nameof(offset));
Model = model;
_dataSource = new DataSource(data, offset);
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
protected WrapperBase(T? model, Stream? data)
: base(data)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
@@ -87,136 +50,6 @@ namespace SabreTools.Serialization.Wrappers
throw new ArgumentOutOfRangeException(nameof(data));
Model = model;
_dataSource = new DataSource(data);
}
#endregion
#region Data
/// <summary>
/// Read data from the source
/// </summary>
/// <param name="position">Position in the source to read from</param>
/// <param name="length">Length of the requested data</param>
/// <returns>Byte array containing the requested data, null on error</returns>
public byte[]? ReadFromDataSource(int position, int length)
=> _dataSource.Read(position, length);
/// <summary>
/// Read string data from the source
/// </summary>
/// <param name="position">Position in the source to read from</param>
/// <param name="length">Length of the requested data</param>
/// <param name="charLimit">Number of characters needed to be a valid string</param>
/// <returns>String list containing the requested data, null on error</returns>
public List<string>? ReadStringsFromDataSource(int position, int length, int charLimit = 5)
{
// Read the data as a byte array first
byte[]? sourceData = ReadFromDataSource(position, length);
if (sourceData == null)
return null;
// Check for ASCII strings
var asciiStrings = ReadStringsWithEncoding(sourceData, charLimit, Encoding.ASCII);
// Check for UTF-8 strings
// We are limiting the check for Unicode characters with a second byte of 0x00 for now
var utf8Strings = ReadStringsWithEncoding(sourceData, charLimit, Encoding.UTF8);
// Check for Unicode strings
// We are limiting the check for Unicode characters with a second byte of 0x00 for now
var unicodeStrings = ReadStringsWithEncoding(sourceData, charLimit, Encoding.Unicode);
// Ignore duplicate strings across encodings
List<string> sourceStrings = [.. asciiStrings, .. utf8Strings, .. unicodeStrings];
// Sort the strings and return
sourceStrings.Sort();
return sourceStrings;
}
/// <summary>
/// Read string data from the source with an encoding
/// </summary>
/// <param name="sourceData">Byte array representing the source data</param>
/// <param name="charLimit">Number of characters needed to be a valid string</param>
/// <param name="encoding">Character encoding to use for checking</param>
/// <returns>String list containing the requested data, empty on error</returns>
/// <remarks>TODO: Move to IO?</remarks>
#if NET20
private static List<string> ReadStringsWithEncoding(byte[] sourceData, int charLimit, Encoding encoding)
#else
private static HashSet<string> ReadStringsWithEncoding(byte[] sourceData, int charLimit, Encoding encoding)
#endif
{
// If we have an invalid character limit, default to 5
if (charLimit <= 0)
charLimit = 5;
// Create the string hash set to return
#if NET20
var sourceStrings = new List<string>();
#else
var sourceStrings = new HashSet<string>();
#endif
// Setup cached data
int sourceDataIndex = 0;
List<char> cachedChars = [];
// Check for strings
while (sourceDataIndex < sourceData.Length)
{
// Read the next character
char ch = encoding.GetChars(sourceData, sourceDataIndex, 1)[0];
// If we have a control character or an invalid byte
bool isValid = !char.IsControl(ch) && (ch & 0xFF00) == 0;
if (!isValid)
{
// If we have no cached string
if (cachedChars.Count == 0)
{
sourceDataIndex++;
continue;
}
// If we have a cached string greater than the limit
if (cachedChars.Count >= charLimit)
sourceStrings.Add(new string([.. cachedChars]));
cachedChars.Clear();
sourceDataIndex++;
continue;
}
// If a long repeating string is found, discard it
if (cachedChars.Count >= 64 && cachedChars.TrueForAll(c => c == cachedChars[0]))
{
cachedChars.Clear();
sourceDataIndex++;
continue;
}
// Append the character to the cached string
cachedChars.Add(ch);
sourceDataIndex++;
}
// If we have a cached string greater than the limit
if (cachedChars.Count >= charLimit)
{
// Get the string from the cached characters
string cachedString = new([.. cachedChars]);
cachedString = cachedString.Trim();
// Only include trimmed strings over the limit
if (cachedString.Length >= charLimit)
sourceStrings.Add(cachedString);
}
return sourceStrings;
}
#endregion

View File

@@ -20,41 +20,20 @@ namespace SabreTools.Serialization.Wrappers
#endregion
#region Instance Variables
/// <summary>
/// Source filename for the wrapper
/// </summary>
private readonly string? _filename;
/// <summary>
/// Source stream for the wrapper
/// </summary>
private readonly Stream _stream;
#endregion
#region Constructors
/// <summary>
/// Construct a new instance of the wrapper from a file path
/// </summary>
public XZ(string filename)
/// <inheritdoc/>
public XZ(byte[]? data, int offset)
: base(data, offset)
{
_filename = filename;
_stream = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// All logic is handled by the base class
}
/// <summary>
/// Construct a new instance of the wrapper from a Stream
/// </summary>
public XZ(Stream stream)
/// <inheritdoc/>
public XZ(Stream? data)
: base(data)
{
_filename = null;
_stream = stream;
if (stream is FileStream fs)
_filename = fs.Name;
// All logic is handled by the base class
}
/// <summary>
@@ -109,13 +88,13 @@ namespace SabreTools.Serialization.Wrappers
public bool Extract(string outDir, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP
if (_stream == null || !_stream.CanRead)
if (DataSourceStream == null || !DataSourceStream.CanRead)
return false;
try
{
// Try opening the stream
using var xzFile = new XZStream(_stream);
using var xzFile = new XZStream(DataSourceStream);
// Ensure directory separators are consistent
string filename = System.Guid.NewGuid().ToString();