mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-21 22:35:06 +00:00
Add QD file support
This commit is contained in:
73
SabreTools.Serialization.Test/Readers/QDTests.cs
Normal file
73
SabreTools.Serialization.Test/Readers/QDTests.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SabreTools.Serialization.Readers;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Serialization.Test.Readers
|
||||
{
|
||||
public class QDTests
|
||||
{
|
||||
[Fact]
|
||||
public void NullArray_Null()
|
||||
{
|
||||
byte[]? data = null;
|
||||
int offset = 0;
|
||||
var deserializer = new QD();
|
||||
|
||||
var actual = deserializer.Deserialize(data, offset);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyArray_Null()
|
||||
{
|
||||
byte[]? data = [];
|
||||
int offset = 0;
|
||||
var deserializer = new QD();
|
||||
|
||||
var actual = deserializer.Deserialize(data, offset);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidArray_Null()
|
||||
{
|
||||
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
|
||||
int offset = 0;
|
||||
var deserializer = new QD();
|
||||
|
||||
var actual = deserializer.Deserialize(data, offset);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullStream_Null()
|
||||
{
|
||||
Stream? data = null;
|
||||
var deserializer = new QD();
|
||||
|
||||
var actual = deserializer.Deserialize(data);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyStream_Null()
|
||||
{
|
||||
Stream? data = new MemoryStream([]);
|
||||
var deserializer = new QD();
|
||||
|
||||
var actual = deserializer.Deserialize(data);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidStream_Null()
|
||||
{
|
||||
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
|
||||
var deserializer = new QD();
|
||||
|
||||
var actual = deserializer.Deserialize(data);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
SabreTools.Serialization.Test/Wrappers/QDTests.cs
Normal file
61
SabreTools.Serialization.Test/Wrappers/QDTests.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Serialization.Test.Wrappers
|
||||
{
|
||||
public class QDTests
|
||||
{
|
||||
[Fact]
|
||||
public void NullArray_Null()
|
||||
{
|
||||
byte[]? data = null;
|
||||
int offset = 0;
|
||||
var actual = QD.Create(data, offset);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyArray_Null()
|
||||
{
|
||||
byte[]? data = [];
|
||||
int offset = 0;
|
||||
var actual = QD.Create(data, offset);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidArray_Null()
|
||||
{
|
||||
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
|
||||
int offset = 0;
|
||||
var actual = QD.Create(data, offset);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullStream_Null()
|
||||
{
|
||||
Stream? data = null;
|
||||
var actual = QD.Create(data);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyStream_Null()
|
||||
{
|
||||
Stream? data = new MemoryStream([]);
|
||||
var actual = QD.Create(data);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidStream_Null()
|
||||
{
|
||||
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
|
||||
var actual = QD.Create(data);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
SabreTools.Serialization/Models/NES/QD.cs
Normal file
14
SabreTools.Serialization/Models/NES/QD.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace SabreTools.Data.Models.NES
|
||||
{
|
||||
/// <summary>
|
||||
/// Quick Disk Famicom Disk System image
|
||||
/// </summary>
|
||||
/// <see href="https://www.nesdev.org/wiki/QD"/>
|
||||
public class QD
|
||||
{
|
||||
/// <summary>
|
||||
/// Disk data (65536 * x bytes)
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; } = [];
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ Not all of this information was able to be gathered directly from the files in q
|
||||
| [Matthew Russotto](http://www.russotto.net/quantumcomp.html) | Compression/Quantum |
|
||||
| [Microsoft Learn](https://learn.microsoft.com/en-us/) | BMP, CFB, Compression/LZX, Compression/MSZIP, MicrosoftCabinet, OLE, PortableExecutable, SecuROM, WiseInstaller |
|
||||
| [msitools](https://github.com/GNOME/msitools/) | CFB |
|
||||
| [Nesdev Wiki](https://www.nesdev.org/wiki/Nesdev_Wiki) | FDS, NESCart |
|
||||
| [Nesdev Wiki](https://www.nesdev.org/wiki/Nesdev_Wiki) | FDS, NESCart, QD |
|
||||
| [OSDev.org](https://wiki.osdev.org/Expanded_Main_Page) | MSDOS, NewExecutable |
|
||||
| [PInvoke.net](http://www.pinvoke.net/index.aspx) | MSDOS |
|
||||
| [PKWARE(?)](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT) | PKZIP |
|
||||
|
||||
39
SabreTools.Serialization/Readers/QD.cs
Normal file
39
SabreTools.Serialization/Readers/QD.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
|
||||
namespace SabreTools.Serialization.Readers
|
||||
{
|
||||
public class QD : BaseBinaryReader<Data.Models.NES.QD>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.NES.QD? Deserialize(Stream? data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data is null || !data.CanRead)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Cache the current offset
|
||||
long initialOffset = data.Position;
|
||||
|
||||
// Create a new QD file to fill
|
||||
var QD = new Data.Models.NES.QD();
|
||||
|
||||
// If the size is invalid
|
||||
if ((data.Length - data.Position) == 0 || (data.Length - data.Position) % 65536 != 0)
|
||||
return null;
|
||||
|
||||
// Read the disk data
|
||||
QD.Data = data.ReadBytes((int)(data.Length - data.Position));
|
||||
|
||||
return QD;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore the actual error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ namespace SabreTools.Serialization
|
||||
WrapperType.PKZIP => PKZIP.Create(data),
|
||||
WrapperType.PlayJAudioFile => PlayJAudioFile.Create(data),
|
||||
WrapperType.PlayJPlaylist => PlayJPlaylist.Create(data),
|
||||
WrapperType.QD => QD.Create(data),
|
||||
WrapperType.Quantum => Quantum.Create(data),
|
||||
WrapperType.RAR => RAR.Create(data),
|
||||
WrapperType.RealArcadeInstaller => RealArcadeInstaller.Create(data),
|
||||
@@ -673,6 +674,13 @@ namespace SabreTools.Serialization
|
||||
|
||||
#endregion
|
||||
|
||||
#region QD
|
||||
|
||||
if (extension.Equals("qd", StringComparison.OrdinalIgnoreCase))
|
||||
return WrapperType.QD;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Quantum
|
||||
|
||||
if (magic.StartsWith(Data.Models.Quantum.Constants.SignatureBytes))
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <inheritdoc/>
|
||||
public void PrintInformation(StringBuilder builder)
|
||||
{
|
||||
builder.AppendLine("Nintendo Entertainment System Cart Information:");
|
||||
builder.AppendLine("fwNES FDS File Information:");
|
||||
builder.AppendLine("-------------------------");
|
||||
builder.AppendLine();
|
||||
|
||||
|
||||
24
SabreTools.Serialization/Wrappers/QD.Printing.cs
Normal file
24
SabreTools.Serialization/Wrappers/QD.Printing.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Text;
|
||||
using SabreTools.Data.Extensions;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
public partial class QD : IPrintable
|
||||
{
|
||||
#if NETCOREAPP
|
||||
/// <inheritdoc/>
|
||||
public string ExportJSON() => System.Text.Json.JsonSerializer.Serialize(Model, _jsonSerializerOptions);
|
||||
#endif
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PrintInformation(StringBuilder builder)
|
||||
{
|
||||
builder.AppendLine("Quick Disk Image Information:");
|
||||
builder.AppendLine("-------------------------");
|
||||
builder.AppendLine();
|
||||
|
||||
//builder.AppendLine(Model.Data, "Disk Data");
|
||||
builder.AppendLine(Model.Data.Length, "Disk Data Length");
|
||||
}
|
||||
}
|
||||
}
|
||||
89
SabreTools.Serialization/Wrappers/QD.cs
Normal file
89
SabreTools.Serialization/Wrappers/QD.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
public partial class QD : WrapperBase<Data.Models.NES.QD>
|
||||
{
|
||||
#region Descriptive Properties
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string DescriptionString => "Quick Disk Famicom Disk System image";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public QD(Data.Models.NES.QD model, byte[] data) : base(model, data) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public QD(Data.Models.NES.QD model, byte[] data, int offset) : base(model, data, offset) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public QD(Data.Models.NES.QD model, byte[] data, int offset, int length) : base(model, data, offset, length) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public QD(Data.Models.NES.QD model, Stream data) : base(model, data) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public QD(Data.Models.NES.QD model, Stream data, long offset) : base(model, data, offset) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public QD(Data.Models.NES.QD model, Stream data, long offset, long length) : base(model, data, offset, length) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create an NES cart image from a byte array and offset
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the archive</param>
|
||||
/// <param name="offset">Offset within the array to parse</param>
|
||||
/// <returns>An NES cart image wrapper on success, null on failure</returns>
|
||||
public static QD? Create(byte[]? data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data is null || data.Length == 0)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and use that
|
||||
var dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return Create(dataStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an NES cart image from a Stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the archive</param>
|
||||
/// <returns>An NES cart image wrapper on success, null on failure</returns>
|
||||
public static QD? Create(Stream? data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data is null || !data.CanRead)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Cache the current offset
|
||||
long currentOffset = data.Position;
|
||||
|
||||
var model = new Readers.QD().Deserialize(data);
|
||||
if (model is null)
|
||||
return null;
|
||||
|
||||
return new QD(model, data, currentOffset);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// </summary>
|
||||
Quantum,
|
||||
|
||||
/// <summary>
|
||||
/// Quick Disk Famicom Disk System image
|
||||
/// </summary>
|
||||
QD,
|
||||
|
||||
/// <summary>
|
||||
/// RAR archive
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user