mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-06 06:11:45 +00:00
Libraries
This change looks dramatic, but it's just separating out the already-split namespaces into separate top-level folders. In theory, every single one could be built into their own Nuget package. `SabreTools.Serialization` still builds the normal Nuget package that is used by all other projects and includes all namespaces.
This commit is contained in:
9
SabreTools.Serialization.Writers/ArchiveDotOrg.cs
Normal file
9
SabreTools.Serialization.Writers/ArchiveDotOrg.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using SabreTools.Data.Models.ArchiveDotOrg;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class ArchiveDotOrg : XmlFile<Files>
|
||||
{
|
||||
// All logic taken care of in the base class
|
||||
}
|
||||
}
|
||||
223
SabreTools.Serialization.Writers/AttractMode.cs
Normal file
223
SabreTools.Serialization.Writers/AttractMode.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.AttractMode;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Writers;
|
||||
|
||||
#pragma warning disable CA1822 // Mark members as static
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class AttractMode : BaseBinaryWriter<MetadataFile>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
public const string HeaderWithoutRomname = "#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons";
|
||||
|
||||
public static readonly string[] HeaderArrayWithoutRomname =
|
||||
[
|
||||
"#Name",
|
||||
"Title",
|
||||
"Emulator",
|
||||
"CloneOf",
|
||||
"Year",
|
||||
"Manufacturer",
|
||||
"Category",
|
||||
"Players",
|
||||
"Rotation",
|
||||
"Control",
|
||||
"Status",
|
||||
"DisplayCount",
|
||||
"DisplayType",
|
||||
"AltRomname",
|
||||
"AltTitle",
|
||||
"Extra",
|
||||
"Buttons"
|
||||
];
|
||||
|
||||
public const string HeaderWithRomname = "#Romname;Title;Emulator;Cloneof;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra;Buttons;Favourite;Tags;PlayedCount;PlayedTime;FileIsAvailable";
|
||||
|
||||
public static readonly string[] HeaderArrayWithRomname =
|
||||
[
|
||||
"#Romname",
|
||||
"Title",
|
||||
"Emulator",
|
||||
"Cloneof",
|
||||
"Year",
|
||||
"Manufacturer",
|
||||
"Category",
|
||||
"Players",
|
||||
"Rotation",
|
||||
"Control",
|
||||
"Status",
|
||||
"DisplayCount",
|
||||
"DisplayType",
|
||||
"AltRomname",
|
||||
"AltTitle",
|
||||
"Extra",
|
||||
"Buttons",
|
||||
"Favourite",
|
||||
"Tags",
|
||||
"PlayedCount",
|
||||
"PlayedTime",
|
||||
"FileIsAvailable"
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[]? SerializeArray(MetadataFile? obj)
|
||||
=> SerializeArray(obj, false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte[]? SerializeArray(MetadataFile? obj, bool longHeader)
|
||||
{
|
||||
using var stream = SerializeStream(obj, longHeader);
|
||||
if (stream is null)
|
||||
return null;
|
||||
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
int read = stream.Read(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SerializeFile(MetadataFile? obj, string? path)
|
||||
=> SerializeFile(obj, path, false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool SerializeFile(MetadataFile? obj, string? path, bool longHeader)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = SerializeStream(obj, longHeader);
|
||||
if (stream is null)
|
||||
return false;
|
||||
|
||||
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
fs.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(MetadataFile? obj)
|
||||
=> SerializeStream(obj, false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Stream? SerializeStream(MetadataFile? obj, bool longHeader)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new SeparatedValueWriter(stream, Encoding.UTF8)
|
||||
{
|
||||
Separator = ';',
|
||||
Quotes = false,
|
||||
VerifyFieldCount = false,
|
||||
};
|
||||
|
||||
// Write the header
|
||||
writer.WriteValues(longHeader ? HeaderArrayWithRomname : HeaderArrayWithoutRomname);
|
||||
|
||||
// Write out the rows, if they exist
|
||||
WriteRows(obj.Row, writer, longHeader);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write rows information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="rows">Array of Row objects representing the rows information</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
/// <param name="longHeader">True if the long variant of the row should be written, false otherwise</param>
|
||||
private static void WriteRows(Row[]? rows, SeparatedValueWriter writer, bool longHeader)
|
||||
{
|
||||
// If the games information is missing, we can't do anything
|
||||
if (rows is null || rows.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the rows
|
||||
foreach (var row in rows)
|
||||
{
|
||||
if (row is null)
|
||||
continue;
|
||||
|
||||
string?[] rowArray;
|
||||
if (longHeader)
|
||||
{
|
||||
rowArray =
|
||||
[
|
||||
row.Name,
|
||||
row.Title,
|
||||
row.Emulator,
|
||||
row.CloneOf,
|
||||
row.Year,
|
||||
row.Manufacturer,
|
||||
row.Category,
|
||||
row.Players,
|
||||
row.Rotation,
|
||||
row.Control,
|
||||
row.Status,
|
||||
row.DisplayCount,
|
||||
row.DisplayType,
|
||||
row.AltRomname,
|
||||
row.AltTitle,
|
||||
row.Extra,
|
||||
row.Buttons,
|
||||
row.Favorite,
|
||||
row.Tags,
|
||||
row.PlayedCount,
|
||||
row.PlayedTime,
|
||||
row.FileIsAvailable,
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
rowArray =
|
||||
[
|
||||
row.Name,
|
||||
row.Title,
|
||||
row.Emulator,
|
||||
row.CloneOf,
|
||||
row.Year,
|
||||
row.Manufacturer,
|
||||
row.Category,
|
||||
row.Players,
|
||||
row.Rotation,
|
||||
row.Control,
|
||||
row.Status,
|
||||
row.DisplayCount,
|
||||
row.DisplayType,
|
||||
row.AltRomname,
|
||||
row.AltTitle,
|
||||
row.Extra,
|
||||
row.Buttons,
|
||||
];
|
||||
}
|
||||
|
||||
writer.WriteValues(rowArray);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
65
SabreTools.Serialization.Writers/BaseBinaryWriter.cs
Normal file
65
SabreTools.Serialization.Writers/BaseBinaryWriter.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all binary serializers
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">Type of the model to serialize</typeparam>
|
||||
/// <remarks>
|
||||
/// This class allows all inheriting types to only implement <see cref="IStreamWriter<>"/>
|
||||
/// and still implicitly implement <see cref="IByteWriter<>"/> and <see cref="IFileWriter<>"/>
|
||||
/// </remarks>
|
||||
public abstract class BaseBinaryWriter<TModel> :
|
||||
IByteWriter<TModel>,
|
||||
IFileWriter<TModel>,
|
||||
IStreamWriter<TModel>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool Debug { get; set; } = false;
|
||||
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual byte[]? SerializeArray(TModel? obj)
|
||||
{
|
||||
using var stream = SerializeStream(obj);
|
||||
if (stream is null)
|
||||
return null;
|
||||
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
int read = stream.Read(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool SerializeFile(TModel? obj, string? path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = SerializeStream(obj);
|
||||
if (stream is null)
|
||||
return false;
|
||||
|
||||
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
fs.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract Stream? SerializeStream(TModel? obj);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
SabreTools.Serialization.Writers/Catalog.cs
Normal file
12
SabreTools.Serialization.Writers/Catalog.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class Catalog : JsonFile<Data.Models.Xbox.Catalog>
|
||||
{
|
||||
/// <remarks>Catalog.js file is encoded as UTF-16 LE</remarks>
|
||||
public override Stream? SerializeStream(Data.Models.Xbox.Catalog? obj)
|
||||
=> Serialize(obj, new UnicodeEncoding());
|
||||
}
|
||||
}
|
||||
529
SabreTools.Serialization.Writers/ClrMamePro.cs
Normal file
529
SabreTools.Serialization.Writers/ClrMamePro.cs
Normal file
@@ -0,0 +1,529 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.ClrMamePro;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Writers;
|
||||
|
||||
#pragma warning disable CA1822 // Mark members as static
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class ClrMamePro : BaseBinaryWriter<MetadataFile>
|
||||
{
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[]? SerializeArray(MetadataFile? obj)
|
||||
=> SerializeArray(obj, false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte[]? SerializeArray(MetadataFile? obj, bool quotes)
|
||||
{
|
||||
using var stream = SerializeStream(obj, quotes);
|
||||
if (stream is null)
|
||||
return null;
|
||||
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
int read = stream.Read(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SerializeFile(MetadataFile? obj, string? path)
|
||||
=> SerializeFile(obj, path, true);
|
||||
|
||||
/// <inheritdoc cref="SerializeFile(MetadataFile, string)"/>
|
||||
public bool SerializeFile(MetadataFile? obj, string? path, bool quotes)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = SerializeStream(obj, quotes);
|
||||
if (stream is null)
|
||||
return false;
|
||||
|
||||
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
fs.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(MetadataFile? obj)
|
||||
=> SerializeStream(obj, true);
|
||||
|
||||
/// <inheritdoc cref="SerializeStream(MetadataFile)"/>
|
||||
public Stream? SerializeStream(MetadataFile? obj, bool quotes)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new ClrMameProWriter(stream, Encoding.UTF8) { Quotes = quotes };
|
||||
|
||||
// Write the header, if it exists
|
||||
WriteHeader(obj.ClrMamePro, writer);
|
||||
|
||||
// Write out the games, if they exist
|
||||
WriteGames(obj.Game, writer);
|
||||
|
||||
// Write out the info, if it exists
|
||||
WriteInfo(obj.Info, writer);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write header information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="header">ClrMamePro representing the header information</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteHeader(Data.Models.ClrMamePro.ClrMamePro? header, ClrMameProWriter writer)
|
||||
{
|
||||
// If the header information is missing, we can't do anything
|
||||
if (header is null)
|
||||
return;
|
||||
|
||||
writer.WriteStartElement("clrmamepro");
|
||||
|
||||
writer.WriteOptionalStandalone("name", header.Name);
|
||||
writer.WriteOptionalStandalone("description", header.Description);
|
||||
writer.WriteOptionalStandalone("rootdir", header.RootDir);
|
||||
writer.WriteOptionalStandalone("category", header.Category);
|
||||
writer.WriteOptionalStandalone("version", header.Version);
|
||||
writer.WriteOptionalStandalone("date", header.Date);
|
||||
writer.WriteOptionalStandalone("author", header.Author);
|
||||
writer.WriteOptionalStandalone("homepage", header.Homepage);
|
||||
writer.WriteOptionalStandalone("url", header.Url);
|
||||
writer.WriteOptionalStandalone("comment", header.Comment);
|
||||
writer.WriteOptionalStandalone("header", header.Header);
|
||||
writer.WriteOptionalStandalone("type", header.Type);
|
||||
writer.WriteOptionalStandalone("forcemerging", header.ForceMerging);
|
||||
writer.WriteOptionalStandalone("forcezipping", header.ForceZipping);
|
||||
writer.WriteOptionalStandalone("forcepacking", header.ForcePacking);
|
||||
|
||||
writer.WriteEndElement(); // clrmamepro
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write games information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="games">Array of GameBase objects representing the games information</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteGames(GameBase[]? games, ClrMameProWriter writer)
|
||||
{
|
||||
// If the games information is missing, we can't do anything
|
||||
if (games is null || games.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the games
|
||||
foreach (var game in games)
|
||||
{
|
||||
if (game is null)
|
||||
continue;
|
||||
|
||||
WriteGame(game, writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write game information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="game">GameBase object representing the game information</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteGame(GameBase game, ClrMameProWriter writer)
|
||||
{
|
||||
// If the game information is missing, we can't do anything
|
||||
if (game is null)
|
||||
return;
|
||||
|
||||
switch (game)
|
||||
{
|
||||
case Game:
|
||||
writer.WriteStartElement("game");
|
||||
break;
|
||||
case Machine:
|
||||
writer.WriteStartElement("machine");
|
||||
break;
|
||||
case Resource:
|
||||
writer.WriteStartElement("resource");
|
||||
break;
|
||||
case Set:
|
||||
writer.WriteStartElement(name: "set");
|
||||
break;
|
||||
default:
|
||||
// TODO: Log invalid values
|
||||
break;
|
||||
}
|
||||
|
||||
// Write the standalone values
|
||||
writer.WriteRequiredStandalone("name", game.Name, throwOnError: true);
|
||||
writer.WriteOptionalStandalone("description", game.Description);
|
||||
writer.WriteOptionalStandalone("driverstatus", game.DriverStatus);
|
||||
writer.WriteOptionalStandalone("year", game.Year);
|
||||
writer.WriteOptionalStandalone("manufacturer", game.Manufacturer);
|
||||
writer.WriteOptionalStandalone("category", game.Category);
|
||||
writer.WriteOptionalStandalone("cloneof", game.CloneOf);
|
||||
writer.WriteOptionalStandalone("romof", game.RomOf);
|
||||
writer.WriteOptionalStandalone("sampleof", game.SampleOf);
|
||||
|
||||
// Write the item values
|
||||
WriteReleases(game.Release, writer);
|
||||
WriteBiosSets(game.BiosSet, writer);
|
||||
WriteRoms(game.Rom, writer);
|
||||
WriteDisks(game.Disk, writer);
|
||||
WriteMedia(game.Media, writer);
|
||||
WriteSamples(game.Sample, writer);
|
||||
WriteArchives(game.Archive, writer);
|
||||
WriteChips(game.Chip, writer);
|
||||
WriteVideos(game.Video, writer);
|
||||
WriteSound(game.Sound, writer);
|
||||
WriteInput(game.Input, writer);
|
||||
WriteDipSwitches(game.DipSwitch, writer);
|
||||
WriteDriver(game.Driver, writer);
|
||||
|
||||
writer.WriteEndElement(); // game, machine, resource, set
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write releases information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="releases">Array of Release objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteReleases(Release[]? releases, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (releases is null)
|
||||
return;
|
||||
|
||||
foreach (var release in releases)
|
||||
{
|
||||
writer.WriteStartElement("release");
|
||||
writer.WriteRequiredAttributeString("name", release.Name, throwOnError: true);
|
||||
writer.WriteRequiredAttributeString("region", release.Region, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("language", release.Language);
|
||||
writer.WriteOptionalAttributeString("date", release.Date);
|
||||
writer.WriteOptionalAttributeString("default", release.Default);
|
||||
writer.WriteEndElement(); // release
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write biossets information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="biossets">Array of BiosSet objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteBiosSets(BiosSet[]? biossets, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (biossets is null)
|
||||
return;
|
||||
|
||||
foreach (var biosset in biossets)
|
||||
{
|
||||
writer.WriteStartElement("biosset");
|
||||
writer.WriteRequiredAttributeString("name", biosset.Name, throwOnError: true);
|
||||
writer.WriteRequiredAttributeString("description", biosset.Description, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("default", biosset.Default);
|
||||
writer.WriteEndElement(); // release
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write roms information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="roms">Array of Rom objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteRoms(Rom[]? roms, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (roms is null)
|
||||
return;
|
||||
|
||||
foreach (var rom in roms)
|
||||
{
|
||||
writer.WriteStartElement("rom");
|
||||
writer.WriteRequiredAttributeString("name", rom.Name, throwOnError: true);
|
||||
writer.WriteRequiredAttributeString("size", rom.Size, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("crc16", rom.CRC16);
|
||||
writer.WriteOptionalAttributeString("crc", rom.CRC);
|
||||
writer.WriteOptionalAttributeString("crc64", rom.CRC64);
|
||||
writer.WriteOptionalAttributeString("md2", rom.MD2);
|
||||
writer.WriteOptionalAttributeString("md4", rom.MD4);
|
||||
writer.WriteOptionalAttributeString("md5", rom.MD5);
|
||||
writer.WriteOptionalAttributeString("ripemd128", rom.RIPEMD128);
|
||||
writer.WriteOptionalAttributeString("ripemd160", rom.RIPEMD160);
|
||||
writer.WriteOptionalAttributeString("sha1", rom.SHA1);
|
||||
writer.WriteOptionalAttributeString("sha256", rom.SHA256);
|
||||
writer.WriteOptionalAttributeString("sha384", rom.SHA384);
|
||||
writer.WriteOptionalAttributeString("sha512", rom.SHA512);
|
||||
writer.WriteOptionalAttributeString("spamsum", rom.SpamSum);
|
||||
writer.WriteOptionalAttributeString("xxh3_64", rom.xxHash364);
|
||||
writer.WriteOptionalAttributeString("xxh3_128", rom.xxHash3128);
|
||||
writer.WriteOptionalAttributeString("merge", rom.Merge);
|
||||
writer.WriteOptionalAttributeString("status", rom.Status);
|
||||
writer.WriteOptionalAttributeString("region", rom.Region);
|
||||
writer.WriteOptionalAttributeString("flags", rom.Flags);
|
||||
writer.WriteOptionalAttributeString("offs", rom.Offs);
|
||||
writer.WriteOptionalAttributeString("serial", rom.Serial);
|
||||
writer.WriteOptionalAttributeString("header", rom.Header);
|
||||
writer.WriteOptionalAttributeString("date", rom.Date);
|
||||
writer.WriteOptionalAttributeString("inverted", rom.Inverted);
|
||||
writer.WriteOptionalAttributeString("mia", rom.MIA);
|
||||
writer.WriteEndElement(); // rom
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write disks information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="disks">Array of Disk objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteDisks(Disk[]? disks, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (disks is null)
|
||||
return;
|
||||
|
||||
foreach (var disk in disks)
|
||||
{
|
||||
writer.WriteStartElement("disk");
|
||||
writer.WriteRequiredAttributeString("name", disk.Name, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("md5", disk.MD5);
|
||||
writer.WriteOptionalAttributeString("sha1", disk.SHA1);
|
||||
writer.WriteOptionalAttributeString("merge", disk.Merge);
|
||||
writer.WriteOptionalAttributeString("status", disk.Status);
|
||||
writer.WriteOptionalAttributeString("flags", disk.Flags);
|
||||
writer.WriteEndElement(); // disk
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write medias information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="medias">Array of Media objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteMedia(Media[]? medias, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (medias is null)
|
||||
return;
|
||||
|
||||
foreach (var media in medias)
|
||||
{
|
||||
writer.WriteStartElement("media");
|
||||
writer.WriteRequiredAttributeString("name", media.Name, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("md5", media.MD5);
|
||||
writer.WriteOptionalAttributeString("sha1", media.SHA1);
|
||||
writer.WriteOptionalAttributeString("sha256", media.SHA256);
|
||||
writer.WriteOptionalAttributeString("spamsum", media.SpamSum);
|
||||
writer.WriteEndElement(); // media
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write samples information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="samples">Array of Sample objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteSamples(Sample[]? samples, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (samples is null)
|
||||
return;
|
||||
|
||||
foreach (var sample in samples)
|
||||
{
|
||||
writer.WriteStartElement("sample");
|
||||
writer.WriteRequiredAttributeString("name", sample.Name, throwOnError: true);
|
||||
writer.WriteEndElement(); // sample
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write archives information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="archives">Array of Archive objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteArchives(Archive[]? archives, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (archives is null)
|
||||
return;
|
||||
|
||||
foreach (var archive in archives)
|
||||
{
|
||||
writer.WriteStartElement("archive");
|
||||
writer.WriteRequiredAttributeString("name", archive.Name, throwOnError: true);
|
||||
writer.WriteEndElement(); // archive
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write chips information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="chips">Array of Chip objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteChips(Chip[]? chips, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (chips is null)
|
||||
return;
|
||||
|
||||
foreach (var chip in chips)
|
||||
{
|
||||
writer.WriteStartElement("chip");
|
||||
writer.WriteRequiredAttributeString("type", chip.Type, throwOnError: true);
|
||||
writer.WriteRequiredAttributeString("name", chip.Name, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("flags", chip.Flags);
|
||||
writer.WriteOptionalAttributeString("clock", chip.Clock);
|
||||
writer.WriteEndElement(); // chip
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write video information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="videos">Array of Video objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteVideos(Video[]? videos, ClrMameProWriter writer)
|
||||
{
|
||||
// If the item is missing, we can't do anything
|
||||
if (videos is null)
|
||||
return;
|
||||
|
||||
foreach (var video in videos)
|
||||
{
|
||||
writer.WriteStartElement("video");
|
||||
writer.WriteRequiredAttributeString("screen", video.Screen, throwOnError: true);
|
||||
writer.WriteRequiredAttributeString("orientation", video.Orientation, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("x", video.X);
|
||||
writer.WriteOptionalAttributeString("y", video.Y);
|
||||
writer.WriteOptionalAttributeString("aspectx", video.AspectX);
|
||||
writer.WriteOptionalAttributeString("aspecty", video.AspectY);
|
||||
writer.WriteOptionalAttributeString("freq", video.Freq);
|
||||
writer.WriteEndElement(); // video
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write sound information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="sound">Sound object to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteSound(Sound? sound, ClrMameProWriter writer)
|
||||
{
|
||||
// If the item is missing, we can't do anything
|
||||
if (sound is null)
|
||||
return;
|
||||
|
||||
writer.WriteStartElement("sound");
|
||||
writer.WriteRequiredAttributeString("channels", sound.Channels, throwOnError: true);
|
||||
writer.WriteEndElement(); // sound
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write input information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="input">Input object to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteInput(Input? input, ClrMameProWriter writer)
|
||||
{
|
||||
// If the item is missing, we can't do anything
|
||||
if (input is null)
|
||||
return;
|
||||
|
||||
writer.WriteStartElement("input");
|
||||
writer.WriteRequiredAttributeString("players", input.Players, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("control", input.Control);
|
||||
writer.WriteRequiredAttributeString("buttons", input.Buttons, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("coins", input.Coins);
|
||||
writer.WriteOptionalAttributeString("tilt", input.Tilt);
|
||||
writer.WriteOptionalAttributeString("service", input.Service);
|
||||
writer.WriteEndElement(); // input
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write dipswitches information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="dipswitches">Array of DipSwitch objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteDipSwitches(DipSwitch[]? dipswitches, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (dipswitches is null)
|
||||
return;
|
||||
|
||||
foreach (var dipswitch in dipswitches)
|
||||
{
|
||||
writer.WriteStartElement("dipswitch");
|
||||
writer.WriteRequiredAttributeString("name", dipswitch.Name, throwOnError: true);
|
||||
foreach (var entry in dipswitch.Entry ?? [])
|
||||
{
|
||||
writer.WriteRequiredAttributeString("entry", entry);
|
||||
}
|
||||
|
||||
writer.WriteOptionalAttributeString("default", dipswitch.Default);
|
||||
writer.WriteEndElement(); // dipswitch
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write driver information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="driver">Driver object to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteDriver(Driver? driver, ClrMameProWriter writer)
|
||||
{
|
||||
// If the item is missing, we can't do anything
|
||||
if (driver is null)
|
||||
return;
|
||||
|
||||
writer.WriteStartElement("driver");
|
||||
writer.WriteRequiredAttributeString("status", driver.Status, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("color", driver.Color); // TODO: Probably actually required
|
||||
writer.WriteOptionalAttributeString("sound", driver.Sound); // TODO: Probably actually required
|
||||
writer.WriteOptionalAttributeString("palettesize", driver.PaletteSize);
|
||||
writer.WriteOptionalAttributeString("blit", driver.Blit);
|
||||
writer.WriteEndElement(); // driver
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write info information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="info">ClrMamePro representing the info information</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteInfo(Info? info, ClrMameProWriter writer)
|
||||
{
|
||||
// If the info information is missing, we can't do anything
|
||||
if (info?.Source is null)
|
||||
return;
|
||||
|
||||
writer.WriteStartElement("info");
|
||||
|
||||
foreach (var source in info.Source)
|
||||
{
|
||||
writer.WriteOptionalStandalone("source", source);
|
||||
}
|
||||
|
||||
writer.WriteEndElement(); // info
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
261
SabreTools.Serialization.Writers/CueSheet.cs
Normal file
261
SabreTools.Serialization.Writers/CueSheet.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.CueSheets;
|
||||
using SabreTools.IO.Extensions;
|
||||
|
||||
#pragma warning disable CA1510 // Use ArgumentNullException throw helper
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class CueSheet : BaseBinaryWriter<Data.Models.CueSheets.CueSheet>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(Data.Models.CueSheets.CueSheet? obj)
|
||||
{
|
||||
// If the cuesheet is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// If we don't have any files, it's invalid
|
||||
if (obj?.Files is null)
|
||||
throw new InvalidDataException(nameof(obj.Files));
|
||||
else if (obj.Files.Length == 0)
|
||||
throw new ArgumentException("No files provided to write");
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
#if NET20 || NET35 || NET40
|
||||
var writer = new StreamWriter(stream, Encoding.ASCII, 1024);
|
||||
#else
|
||||
var writer = new StreamWriter(stream, Encoding.ASCII, 1024, true);
|
||||
#endif
|
||||
|
||||
// Write the file
|
||||
WriteCueSheet(obj, writer);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the cuesheet out to a stream
|
||||
/// </summary>
|
||||
/// <param name="cueSheet">CueSheet to write</param>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
private static void WriteCueSheet(Data.Models.CueSheets.CueSheet cueSheet, StreamWriter sw)
|
||||
{
|
||||
// If we don't have any files, it's invalid
|
||||
if (cueSheet.Files is null)
|
||||
throw new InvalidDataException(nameof(cueSheet.Files));
|
||||
else if (cueSheet.Files.Length == 0)
|
||||
throw new ArgumentException("No files provided to write");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueSheet.Catalog))
|
||||
sw.WriteLine($"CATALOG {cueSheet.Catalog}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueSheet.CdTextFile))
|
||||
sw.WriteLine($"CDTEXTFILE {cueSheet.CdTextFile}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueSheet.Performer))
|
||||
sw.WriteLine($"PERFORMER {cueSheet.Performer}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueSheet.Songwriter))
|
||||
sw.WriteLine($"SONGWRITER {cueSheet.Songwriter}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueSheet.Title))
|
||||
sw.WriteLine($"TITLE {cueSheet.Title}");
|
||||
|
||||
foreach (var cueFile in cueSheet.Files)
|
||||
{
|
||||
WriteCueFile(cueFile, sw);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the FILE out to a stream
|
||||
/// </summary>
|
||||
/// <param name="cueFile">CueFile to write</param>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
private static void WriteCueFile(CueFile? cueFile, StreamWriter sw)
|
||||
{
|
||||
// If we don't have any tracks, it's invalid
|
||||
if (cueFile?.Tracks is null)
|
||||
throw new InvalidDataException(nameof(cueFile.Tracks));
|
||||
else if (cueFile.Tracks.Length == 0)
|
||||
throw new ArgumentException("No tracks provided to write");
|
||||
|
||||
sw.WriteLine($"FILE \"{cueFile.FileName}\" {FromFileType(cueFile.FileType)}");
|
||||
|
||||
foreach (var track in cueFile.Tracks)
|
||||
{
|
||||
WriteCueTrack(track, sw);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the TRACK out to a stream
|
||||
/// </summary>
|
||||
/// <param name="cueFile">CueFile to write</param>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
private static void WriteCueTrack(CueTrack? cueTrack, StreamWriter sw)
|
||||
{
|
||||
// If we don't have any indices, it's invalid
|
||||
if (cueTrack?.Indices is null)
|
||||
throw new InvalidDataException(nameof(cueTrack.Indices));
|
||||
else if (cueTrack.Indices.Length == 0)
|
||||
throw new ArgumentException("No indices provided to write");
|
||||
|
||||
sw.WriteLine($" TRACK {cueTrack.Number:D2} {FromDataType(cueTrack.DataType)}");
|
||||
|
||||
if (cueTrack.Flags != 0)
|
||||
sw.WriteLine($" FLAGS {FromFlags(cueTrack.Flags)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueTrack.ISRC))
|
||||
sw.WriteLine($" ISRC {cueTrack.ISRC}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueTrack.Performer))
|
||||
sw.WriteLine($" PERFORMER {cueTrack.Performer}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueTrack.Songwriter))
|
||||
sw.WriteLine($" SONGWRITER {cueTrack.Songwriter}");
|
||||
|
||||
if (!string.IsNullOrEmpty(cueTrack.Title))
|
||||
sw.WriteLine($" TITLE {cueTrack.Title}");
|
||||
|
||||
if (cueTrack.PreGap is not null)
|
||||
WritePreGap(cueTrack.PreGap, sw);
|
||||
|
||||
foreach (var index in cueTrack.Indices)
|
||||
{
|
||||
WriteCueIndex(index, sw);
|
||||
}
|
||||
|
||||
if (cueTrack.PostGap is not null)
|
||||
WritePostGap(cueTrack.PostGap, sw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the PREGAP out to a stream
|
||||
/// </summary>
|
||||
/// <param name="preGap">PreGap to write</param>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
private static void WritePreGap(PreGap preGap, StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" PREGAP {preGap.Minutes:D2}:{preGap.Seconds:D2}:{preGap.Frames:D2}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the INDEX out to a stream
|
||||
/// </summary>
|
||||
/// <param name="cueIndex">CueIndex to write</param>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
private static void WriteCueIndex(CueIndex? cueIndex, StreamWriter sw)
|
||||
{
|
||||
if (cueIndex is null)
|
||||
throw new ArgumentNullException(nameof(cueIndex));
|
||||
|
||||
sw.WriteLine($" INDEX {cueIndex.Index:D2} {cueIndex.Minutes:D2}:{cueIndex.Seconds:D2}:{cueIndex.Frames:D2}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the POSTGAP out to a stream
|
||||
/// </summary>
|
||||
/// <param name="postGap">PostGap to write</param>
|
||||
/// <param name="sw">StreamWriter to write to</param>
|
||||
private static void WritePostGap(PostGap postGap, StreamWriter sw)
|
||||
{
|
||||
sw.WriteLine($" POSTGAP {postGap.Minutes:D2}:{postGap.Seconds:D2}:{postGap.Frames:D2}");
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get the string from a given file type
|
||||
/// </summary>
|
||||
/// <param name="fileType">CueFileType to get value from</param>
|
||||
/// <returns>String, if possible (default BINARY)</returns>
|
||||
private static string FromFileType(CueFileType fileType)
|
||||
{
|
||||
return fileType switch
|
||||
{
|
||||
CueFileType.BINARY => "BINARY",
|
||||
CueFileType.MOTOROLA => "MOTOROLA",
|
||||
CueFileType.AIFF => "AIFF",
|
||||
CueFileType.WAVE => "WAVE",
|
||||
CueFileType.MP3 => "MP3",
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string from a given data type
|
||||
/// </summary>
|
||||
/// <param name="dataType">CueTrackDataType to get value from</param>
|
||||
/// <returns>string, if possible</returns>
|
||||
private static string FromDataType(CueTrackDataType dataType)
|
||||
{
|
||||
return dataType switch
|
||||
{
|
||||
CueTrackDataType.AUDIO => "AUDIO",
|
||||
CueTrackDataType.CDG => "CDG",
|
||||
CueTrackDataType.MODE1_2048 => "MODE1/2048",
|
||||
CueTrackDataType.MODE1_2352 => "MODE1/2352",
|
||||
CueTrackDataType.MODE2_2336 => "MODE2/2336",
|
||||
CueTrackDataType.MODE2_2352 => "MODE2/2352",
|
||||
CueTrackDataType.CDI_2336 => "CDI/2336",
|
||||
CueTrackDataType.CDI_2352 => "CDI/2352",
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for a set of track flags
|
||||
/// </summary>
|
||||
/// <param name="flags">CueTrackFlag to get value from</param>
|
||||
/// <returns>String value representing the CueTrackFlag, if possible</returns>
|
||||
private static string FromFlags(CueTrackFlag flags)
|
||||
{
|
||||
string outputFlagString = string.Empty;
|
||||
|
||||
#if NET20 || NET35
|
||||
if ((flags & CueTrackFlag.DCP) != 0)
|
||||
#else
|
||||
if (flags.HasFlag(CueTrackFlag.DCP))
|
||||
#endif
|
||||
outputFlagString += "DCP ";
|
||||
|
||||
#if NET20 || NET35
|
||||
if ((flags & CueTrackFlag.FourCH) != 0)
|
||||
#else
|
||||
if (flags.HasFlag(CueTrackFlag.FourCH))
|
||||
#endif
|
||||
outputFlagString += "4CH ";
|
||||
|
||||
#if NET20 || NET35
|
||||
if ((flags & CueTrackFlag.PRE) != 0)
|
||||
#else
|
||||
if (flags.HasFlag(CueTrackFlag.PRE))
|
||||
#endif
|
||||
outputFlagString += "PRE ";
|
||||
|
||||
#if NET20 || NET35
|
||||
if ((flags & CueTrackFlag.SCMS) != 0)
|
||||
#else
|
||||
if (flags.HasFlag(CueTrackFlag.SCMS))
|
||||
#endif
|
||||
outputFlagString += "SCMS ";
|
||||
|
||||
#if NET20 || NET35
|
||||
if ((flags & CueTrackFlag.DATA) != 0)
|
||||
#else
|
||||
if (flags.HasFlag(CueTrackFlag.DATA))
|
||||
#endif
|
||||
outputFlagString += "DATA ";
|
||||
|
||||
return outputFlagString.Trim();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
127
SabreTools.Serialization.Writers/DosCenter.cs
Normal file
127
SabreTools.Serialization.Writers/DosCenter.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.DosCenter;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Writers;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class DosCenter : BaseBinaryWriter<MetadataFile>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(MetadataFile? obj)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new ClrMameProWriter(stream, Encoding.UTF8)
|
||||
{
|
||||
Quotes = false,
|
||||
};
|
||||
|
||||
// Write the header, if it exists
|
||||
WriteHeader(obj.DosCenter, writer);
|
||||
|
||||
// Write out the games, if they exist
|
||||
WriteGames(obj.Game, writer);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write header information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="header">DosCenter representing the header information</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteHeader(Data.Models.DosCenter.DosCenter? header, ClrMameProWriter writer)
|
||||
{
|
||||
// If the header information is missing, we can't do anything
|
||||
if (header is null)
|
||||
return;
|
||||
|
||||
writer.WriteStartElement("DOSCenter");
|
||||
|
||||
writer.WriteOptionalStandalone("Name:", header.Name);
|
||||
writer.WriteOptionalStandalone("Description:", header.Description);
|
||||
writer.WriteOptionalStandalone("Version:", header.Version);
|
||||
writer.WriteOptionalStandalone("Date:", header.Date);
|
||||
writer.WriteOptionalStandalone("Author:", header.Author);
|
||||
writer.WriteOptionalStandalone("Homepage:", header.Homepage);
|
||||
writer.WriteOptionalStandalone("Comment:", header.Comment);
|
||||
|
||||
writer.WriteEndElement(); // doscenter
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write games information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="games">Array of Game objects representing the games information</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteGames(Game[]? games, ClrMameProWriter writer)
|
||||
{
|
||||
// If the games information is missing, we can't do anything
|
||||
if (games is null || games.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the games
|
||||
foreach (var game in games)
|
||||
{
|
||||
WriteGame(game, writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write game information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="game">Game object representing the game information</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteGame(Game game, ClrMameProWriter writer)
|
||||
{
|
||||
// If the game information is missing, we can't do anything
|
||||
if (game is null)
|
||||
return;
|
||||
|
||||
writer.WriteStartElement("game");
|
||||
|
||||
// Write the standalone values
|
||||
writer.WriteRequiredStandalone("name", game.Name, throwOnError: true);
|
||||
|
||||
// Write the item values
|
||||
WriteFiles(game.File, writer);
|
||||
|
||||
writer.WriteEndElement(); // game
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write files information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="files">Array of File objects to write</param>
|
||||
/// <param name="writer">ClrMameProWriter representing the output</param>
|
||||
private static void WriteFiles(Data.Models.DosCenter.File[]? files, ClrMameProWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (files is null)
|
||||
return;
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
writer.WriteStartElement("file");
|
||||
|
||||
writer.WriteRequiredAttributeString("name", file.Name, throwOnError: true);
|
||||
writer.WriteRequiredAttributeString("size", file.Size, throwOnError: true);
|
||||
writer.WriteOptionalAttributeString("date", file.Date);
|
||||
writer.WriteRequiredAttributeString("crc", file.CRC?.ToUpperInvariant(), throwOnError: true);
|
||||
writer.WriteRequiredAttributeString("sha1", file.SHA1?.ToUpperInvariant());
|
||||
|
||||
writer.WriteEndElement(); // file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
SabreTools.Serialization.Writers/EverdriveSMDB.cs
Normal file
65
SabreTools.Serialization.Writers/EverdriveSMDB.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.EverdriveSMDB;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Writers;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class EverdriveSMDB : BaseBinaryWriter<MetadataFile>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(MetadataFile? obj)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new SeparatedValueWriter(stream, Encoding.UTF8) { Separator = '\t', Quotes = false };
|
||||
|
||||
// Write out the rows, if they exist
|
||||
WriteRows(obj.Row, writer);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write rows information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="rows">Array of Row objects representing the rows information</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteRows(Row[]? rows, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the games information is missing, we can't do anything
|
||||
if (rows is null || rows.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the rows
|
||||
foreach (var row in rows)
|
||||
{
|
||||
if (row is null)
|
||||
continue;
|
||||
|
||||
var rowArray = new List<string?>
|
||||
{
|
||||
row.SHA256,
|
||||
row.Name,
|
||||
row.SHA1,
|
||||
row.MD5,
|
||||
row.CRC32,
|
||||
};
|
||||
|
||||
if (row.Size is not null)
|
||||
rowArray.Add(row.Size);
|
||||
|
||||
writer.WriteValues([.. rowArray]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
SabreTools.Serialization.Writers/ExtensionAttribute.cs
Normal file
9
SabreTools.Serialization.Writers/ExtensionAttribute.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
#if NET20
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
|
||||
internal sealed class ExtensionAttribute : Attribute {}
|
||||
}
|
||||
|
||||
#endif
|
||||
372
SabreTools.Serialization.Writers/Hashfile.cs
Normal file
372
SabreTools.Serialization.Writers/Hashfile.cs
Normal file
@@ -0,0 +1,372 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.Hashfile;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Writers;
|
||||
|
||||
#pragma warning disable CA1822 // Mark members as static
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class Hashfile : BaseBinaryWriter<Data.Models.Hashfile.Hashfile>
|
||||
{
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[]? SerializeArray(Data.Models.Hashfile.Hashfile? obj)
|
||||
=> SerializeArray(obj, HashType.CRC32);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte[]? SerializeArray(Data.Models.Hashfile.Hashfile? obj, HashType hash)
|
||||
{
|
||||
using var stream = SerializeStream(obj, hash);
|
||||
if (stream is null)
|
||||
return null;
|
||||
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
int read = stream.Read(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SerializeFile(Data.Models.Hashfile.Hashfile? obj, string? path)
|
||||
=> SerializeFile(obj, path, HashType.CRC32);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool SerializeFile(Data.Models.Hashfile.Hashfile? obj, string? path, HashType hash)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = SerializeStream(obj, hash);
|
||||
if (stream is null)
|
||||
return false;
|
||||
|
||||
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
fs.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(Data.Models.Hashfile.Hashfile? obj)
|
||||
=> SerializeStream(obj, HashType.CRC32);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Stream? SerializeStream(Data.Models.Hashfile.Hashfile? obj, HashType hash)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new SeparatedValueWriter(stream, Encoding.UTF8)
|
||||
{
|
||||
Separator = ' ',
|
||||
Quotes = false,
|
||||
VerifyFieldCount = false,
|
||||
};
|
||||
|
||||
// Write out the items, if they exist
|
||||
#pragma warning disable IDE0010
|
||||
switch (hash)
|
||||
{
|
||||
case HashType.CRC32:
|
||||
WriteSFV(obj.SFV, writer);
|
||||
break;
|
||||
case HashType.MD2:
|
||||
WriteMD2(obj.MD2, writer);
|
||||
break;
|
||||
case HashType.MD4:
|
||||
WriteMD4(obj.MD4, writer);
|
||||
break;
|
||||
case HashType.MD5:
|
||||
WriteMD5(obj.MD5, writer);
|
||||
break;
|
||||
case HashType.RIPEMD128:
|
||||
WriteRIPEMD128(obj.RIPEMD128, writer);
|
||||
break;
|
||||
case HashType.RIPEMD160:
|
||||
WriteRIPEMD160(obj.RIPEMD160, writer);
|
||||
break;
|
||||
case HashType.SHA1:
|
||||
WriteSHA1(obj.SHA1, writer);
|
||||
break;
|
||||
case HashType.SHA256:
|
||||
WriteSHA256(obj.SHA256, writer);
|
||||
break;
|
||||
case HashType.SHA384:
|
||||
WriteSHA384(obj.SHA384, writer);
|
||||
break;
|
||||
case HashType.SHA512:
|
||||
WriteSHA512(obj.SHA512, writer);
|
||||
break;
|
||||
case HashType.SpamSum:
|
||||
WriteSpamSum(obj.SpamSum, writer);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(hash));
|
||||
}
|
||||
#pragma warning restore IDE0010
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write SFV information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="sfvs">Array of SFV objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteSFV(SFV[]? sfvs, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (sfvs is null || sfvs.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var sfv in sfvs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sfv.File) || string.IsNullOrEmpty(sfv.Hash))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([sfv.File!, sfv.Hash!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write MD2 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="md2s">Array of MD2 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteMD2(MD2[]? md2s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (md2s is null || md2s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var md2 in md2s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(md2.Hash) || string.IsNullOrEmpty(md2.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([md2.Hash!, md2.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write MD4 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="md4s">Array of MD4 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteMD4(MD4[]? md4s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (md4s is null || md4s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var md4 in md4s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(md4.Hash) || string.IsNullOrEmpty(md4.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([md4.Hash!, md4.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write MD5 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="md5s">Array of MD5 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteMD5(MD5[]? md5s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (md5s is null || md5s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var md5 in md5s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(md5.Hash) || string.IsNullOrEmpty(md5.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([md5.Hash!, md5.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write RIPEMD128 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="ripemd128s">Array of RIPEMD128 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteRIPEMD128(RIPEMD128[]? ripemd128s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (ripemd128s is null || ripemd128s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var ripemd128 in ripemd128s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ripemd128.Hash) || string.IsNullOrEmpty(ripemd128.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([ripemd128.Hash!, ripemd128.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write RIPEMD160 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="ripemd160s">Array of RIPEMD160 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteRIPEMD160(RIPEMD160[]? ripemd160s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (ripemd160s is null || ripemd160s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var ripemd160 in ripemd160s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ripemd160.Hash) || string.IsNullOrEmpty(ripemd160.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([ripemd160.Hash!, ripemd160.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write SHA1 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="sha1s">Array of SHA1 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteSHA1(SHA1[]? sha1s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (sha1s is null || sha1s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var sha1 in sha1s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sha1.Hash) || string.IsNullOrEmpty(sha1.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([sha1.Hash!, sha1.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write SHA256 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="sha256s">Array of SHA256 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteSHA256(SHA256[]? sha256s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (sha256s is null || sha256s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var sha256 in sha256s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sha256.Hash) || string.IsNullOrEmpty(sha256.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([sha256.Hash!, sha256.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write SHA384 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="sha384s">Array of SHA384 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteSHA384(SHA384[]? sha384s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (sha384s is null || sha384s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var sha384 in sha384s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sha384.Hash) || string.IsNullOrEmpty(sha384.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([sha384.Hash!, sha384.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write SHA512 information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="sha512s">Array of SHA512 objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteSHA512(SHA512[]? sha512s, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (sha512s is null || sha512s.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var sha512 in sha512s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sha512.Hash) || string.IsNullOrEmpty(sha512.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([sha512.Hash!, sha512.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write SpamSum information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="spamsums">Array of SpamSum objects representing the files</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
private static void WriteSpamSum(SpamSum[]? spamsums, SeparatedValueWriter writer)
|
||||
{
|
||||
// If the item information is missing, we can't do anything
|
||||
if (spamsums is null || spamsums.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the items
|
||||
foreach (var spamsum in spamsums)
|
||||
{
|
||||
if (string.IsNullOrEmpty(spamsum.Hash) || string.IsNullOrEmpty(spamsum.File))
|
||||
continue;
|
||||
|
||||
writer.WriteValues([spamsum.Hash!, spamsum.File!]);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
21
SabreTools.Serialization.Writers/IByteWriter.cs
Normal file
21
SabreTools.Serialization.Writers/IByteWriter.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how to write to byte arrays
|
||||
/// </summary>
|
||||
public interface IByteWriter<TModel>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable outputting debug information
|
||||
/// </summary>
|
||||
public bool Debug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="TModel"/> into a byte array
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <returns>Filled object on success, null on error</returns>
|
||||
public byte[]? SerializeArray(TModel? obj);
|
||||
}
|
||||
}
|
||||
22
SabreTools.Serialization.Writers/IFileWriter.cs
Normal file
22
SabreTools.Serialization.Writers/IFileWriter.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how to write to files
|
||||
/// </summary>
|
||||
public interface IFileWriter<TModel>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable outputting debug information
|
||||
/// </summary>
|
||||
public bool Debug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="TModel"/> into a file
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <param name="path">Path to the file to serialize to</param>
|
||||
/// <returns>True on successful serialization, false otherwise</returns>
|
||||
public bool SerializeFile(TModel? obj, string? path);
|
||||
}
|
||||
}
|
||||
130
SabreTools.Serialization.Writers/IRD.cs
Normal file
130
SabreTools.Serialization.Writers/IRD.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class IRD : BaseBinaryWriter<Data.Models.IRD.File>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(Data.Models.IRD.File? obj)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (obj?.Magic is null)
|
||||
return null;
|
||||
|
||||
// If the magic doesn't match
|
||||
string magic = Encoding.ASCII.GetString(obj.Magic);
|
||||
if (magic != "3IRD")
|
||||
return null;
|
||||
|
||||
// If the version is less than the supported
|
||||
if (obj.Version < 6)
|
||||
return null;
|
||||
|
||||
// If any static-length fields aren't the correct length
|
||||
if (obj.TitleID.Length != 9)
|
||||
return null;
|
||||
if (obj.Title.Length != obj.TitleLength)
|
||||
return null;
|
||||
if (obj.SystemVersion.Length != 4)
|
||||
return null;
|
||||
if (obj.GameVersion.Length != 5)
|
||||
return null;
|
||||
if (obj.AppVersion.Length != 5)
|
||||
return null;
|
||||
if (obj.Header.Length != obj.HeaderLength)
|
||||
return null;
|
||||
if (obj.Footer.Length != obj.FooterLength)
|
||||
return null;
|
||||
if (obj.RegionHashes.Length != obj.RegionCount || !Array.TrueForAll(obj.RegionHashes, h => h is null || h.Length != 16))
|
||||
return null;
|
||||
if (obj.FileKeys.Length != obj.FileCount)
|
||||
return null;
|
||||
if (obj.FileHashes.Length != obj.FileCount || !Array.TrueForAll(obj.FileHashes, h => h is null || h.Length != 16))
|
||||
return null;
|
||||
if (obj.PIC.Length != 115)
|
||||
return null;
|
||||
if (obj.Data1Key.Length != 16)
|
||||
return null;
|
||||
if (obj.Data2Key.Length != 16)
|
||||
return null;
|
||||
|
||||
// Create the output stream
|
||||
var stream = new MemoryStream();
|
||||
|
||||
stream.Write(obj.Magic, 0, obj.Magic.Length);
|
||||
stream.WriteByte(obj.Version);
|
||||
|
||||
byte[] titleId = Encoding.ASCII.GetBytes(obj.TitleID);
|
||||
stream.Write(titleId, 0, titleId.Length);
|
||||
|
||||
stream.WriteByte(obj.TitleLength);
|
||||
byte[] title = Encoding.ASCII.GetBytes(obj.Title);
|
||||
stream.Write(title, 0, title.Length);
|
||||
|
||||
byte[] systemVersion = Encoding.ASCII.GetBytes(obj.SystemVersion);
|
||||
stream.Write(systemVersion, 0, systemVersion.Length);
|
||||
|
||||
byte[] gameVersion = Encoding.ASCII.GetBytes(obj.GameVersion);
|
||||
stream.Write(gameVersion, 0, gameVersion.Length);
|
||||
|
||||
byte[] appVersion = Encoding.ASCII.GetBytes(obj.AppVersion);
|
||||
stream.Write(appVersion, 0, appVersion.Length);
|
||||
|
||||
if (obj.Version == 7)
|
||||
{
|
||||
byte[] uid = BitConverter.GetBytes(obj.UID);
|
||||
stream.Write(uid, 0, uid.Length);
|
||||
}
|
||||
|
||||
byte[] headerLength = BitConverter.GetBytes(obj.HeaderLength);
|
||||
stream.Write(headerLength, 0, headerLength.Length);
|
||||
stream.Write(obj.Header, 0, obj.Header.Length);
|
||||
|
||||
byte[] footerLength = BitConverter.GetBytes(obj.FooterLength);
|
||||
stream.Write(footerLength, 0, footerLength.Length);
|
||||
stream.Write(obj.Footer, 0, obj.Footer.Length);
|
||||
|
||||
stream.WriteByte(obj.RegionCount);
|
||||
for (int i = 0; i < obj.RegionCount; i++)
|
||||
{
|
||||
stream.Write(obj.RegionHashes[i], 0, obj.RegionHashes[i].Length);
|
||||
}
|
||||
|
||||
byte[] fileCount = BitConverter.GetBytes(obj.FileCount);
|
||||
stream.Write(fileCount, 0, fileCount.Length);
|
||||
for (int i = 0; i < obj.FileCount; i++)
|
||||
{
|
||||
byte[] fileKey = BitConverter.GetBytes(obj.FileKeys[i]);
|
||||
stream.Write(fileKey, 0, fileKey.Length);
|
||||
stream.Write(obj.FileHashes[i], 0, obj.FileHashes[i].Length);
|
||||
}
|
||||
|
||||
byte[] extraConfig = BitConverter.GetBytes(obj.ExtraConfig);
|
||||
stream.Write(extraConfig, 0, extraConfig.Length);
|
||||
byte[] attachments = BitConverter.GetBytes(obj.Attachments);
|
||||
stream.Write(attachments, 0, attachments.Length);
|
||||
|
||||
if (obj.Version >= 9)
|
||||
stream.Write(obj.PIC, 0, obj.PIC.Length);
|
||||
|
||||
stream.Write(obj.Data1Key, 0, obj.Data1Key.Length);
|
||||
stream.Write(obj.Data2Key, 0, obj.Data2Key.Length);
|
||||
|
||||
if (obj.Version < 9)
|
||||
stream.Write(obj.PIC, 0, obj.PIC.Length);
|
||||
|
||||
if (obj.Version > 7)
|
||||
{
|
||||
byte[] uid = BitConverter.GetBytes(obj.UID);
|
||||
stream.Write(uid, 0, uid.Length);
|
||||
}
|
||||
|
||||
byte[] crc = BitConverter.GetBytes(obj.CRC);
|
||||
stream.Write(crc, 0, crc.Length);
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
SabreTools.Serialization.Writers/IStreamWriter.cs
Normal file
21
SabreTools.Serialization.Writers/IStreamWriter.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how to write to Streams
|
||||
/// </summary>
|
||||
public interface IStreamWriter<TModel>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable outputting debug information
|
||||
/// </summary>
|
||||
public bool Debug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="TModel"/> into a Stream
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <returns>Filled object on success, null on error</returns>
|
||||
public System.IO.Stream? SerializeStream(TModel? obj);
|
||||
}
|
||||
}
|
||||
21
SabreTools.Serialization.Writers/IStringWriter.cs
Normal file
21
SabreTools.Serialization.Writers/IStringWriter.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how to write to strings
|
||||
/// </summary>
|
||||
public interface IStringWriter<TModel>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable outputting debug information
|
||||
/// </summary>
|
||||
public bool Debug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="TModel"/> into a string
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <returns>Filled string on successful serialization, null otherwise</returns>
|
||||
public string? Serialize(TModel? obj);
|
||||
}
|
||||
}
|
||||
105
SabreTools.Serialization.Writers/JsonFile.cs
Normal file
105
SabreTools.Serialization.Writers/JsonFile.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.IO.Extensions;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for other JSON serializers
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class JsonFile<T> : BaseBinaryWriter<T>
|
||||
{
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[]? SerializeArray(T? obj)
|
||||
=> SerializeArray(obj, new UTF8Encoding(false));
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="T"/> into a byte array
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <param name="encoding">Encoding to parse text as</param>
|
||||
/// <returns>Filled object on success, null on error</returns>
|
||||
public byte[]? SerializeArray(T? obj, Encoding encoding)
|
||||
{
|
||||
using var stream = Serialize(obj, encoding);
|
||||
if (stream is null)
|
||||
return null;
|
||||
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
int read = stream.Read(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SerializeFile(T? obj, string? path)
|
||||
=> Serialize(obj, path, new UTF8Encoding(false));
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="T"/> into a file
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <param name="path">Path to the file to serialize to</param>
|
||||
/// <param name="encoding">Encoding to parse text as</param>
|
||||
/// <returns>True on successful serialization, false otherwise</returns>
|
||||
public bool Serialize(T? obj, string? path, Encoding encoding)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = Serialize(obj, encoding);
|
||||
if (stream is null)
|
||||
return false;
|
||||
|
||||
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
fs.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(T? obj)
|
||||
=> Serialize(obj, new UTF8Encoding(false));
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="T"/> into a Stream
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <param name="encoding"></param>
|
||||
/// <returns>Filled object on success, null on error</returns>
|
||||
public Stream? Serialize(T? obj, Encoding encoding)
|
||||
{
|
||||
// If the object is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the serializer and the writer
|
||||
var serializer = JsonSerializer.Create();
|
||||
var stream = new MemoryStream();
|
||||
var streamWriter = new StreamWriter(stream, encoding);
|
||||
var jsonWriter = new JsonTextWriter(streamWriter);
|
||||
|
||||
// Perform the deserialization and return
|
||||
serializer.Serialize(jsonWriter, obj);
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
158
SabreTools.Serialization.Writers/Listrom.cs
Normal file
158
SabreTools.Serialization.Writers/Listrom.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.Listrom;
|
||||
using SabreTools.IO.Extensions;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class Listrom : BaseBinaryWriter<MetadataFile>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(MetadataFile? obj)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream, Encoding.UTF8);
|
||||
|
||||
// Write out the sets, if they exist
|
||||
WriteSets(obj.Set, writer);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write sets information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="sets">Array of Set objects representing the sets information</param>
|
||||
/// <param name="writer">StreamWriter representing the output</param>
|
||||
private static void WriteSets(Set[]? sets, StreamWriter writer)
|
||||
{
|
||||
// If the games information is missing, we can't do anything
|
||||
if (sets is null || sets.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the games
|
||||
foreach (var set in sets)
|
||||
{
|
||||
WriteSet(set, writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write set information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="set">Set object representing the set information</param>
|
||||
/// <param name="writer">StreamWriter representing the output</param>
|
||||
private static void WriteSet(Set set, StreamWriter writer)
|
||||
{
|
||||
// If the set information is missing, we can't do anything
|
||||
if (set is null)
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrEmpty(set.Driver))
|
||||
{
|
||||
if (set.Row is not null && set.Row.Length > 0)
|
||||
{
|
||||
writer.WriteLine($"ROMs required for driver \"{set.Driver}\".");
|
||||
writer.WriteLine("Name Size Checksum");
|
||||
writer.Flush();
|
||||
|
||||
WriteRows(set.Row, writer);
|
||||
|
||||
writer.WriteLine();
|
||||
writer.Flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine($"No ROMs required for driver \"{set.Driver}\".");
|
||||
writer.WriteLine();
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(set.Device))
|
||||
{
|
||||
if (set.Row is not null && set.Row.Length > 0)
|
||||
{
|
||||
writer.WriteLine($"ROMs required for device \"{set.Device}\".");
|
||||
writer.WriteLine("Name Size Checksum");
|
||||
writer.Flush();
|
||||
|
||||
WriteRows(set.Row, writer);
|
||||
|
||||
writer.WriteLine();
|
||||
writer.Flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine($"No ROMs required for device \"{set.Device}\".");
|
||||
writer.WriteLine();
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write rows information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="rows">Array of Row objects to write</param>
|
||||
/// <param name="writer">StreamWriter representing the output</param>
|
||||
private static void WriteRows(Row[]? rows, StreamWriter writer)
|
||||
{
|
||||
// If the array is missing, we can't do anything
|
||||
if (rows is null)
|
||||
return;
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
if (string.IsNullOrEmpty(row.Name))
|
||||
continue;
|
||||
|
||||
var rowBuilder = new StringBuilder();
|
||||
|
||||
int padding = 40 - (row.Size?.Length ?? 0);
|
||||
if (padding < row.Name!.Length)
|
||||
padding = row.Name.Length + 2;
|
||||
|
||||
rowBuilder.Append($"{row.Name.PadRight(padding, ' ')}");
|
||||
if (row.Size is not null)
|
||||
rowBuilder.Append($"{row.Size} ");
|
||||
|
||||
if (row.NoGoodDumpKnown)
|
||||
{
|
||||
rowBuilder.Append("NO GOOD DUMP KNOWN");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (row.Bad)
|
||||
rowBuilder.Append("BAD ");
|
||||
|
||||
if (row.Size is not null)
|
||||
{
|
||||
rowBuilder.Append($"CRC({row.CRC}) ");
|
||||
rowBuilder.Append($"SHA1({row.SHA1}) ");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(row.MD5))
|
||||
rowBuilder.Append($"MD5({row.MD5}) ");
|
||||
else
|
||||
rowBuilder.Append($"SHA1({row.SHA1}) ");
|
||||
}
|
||||
|
||||
if (row.Bad)
|
||||
rowBuilder.Append("BAD_DUMP");
|
||||
}
|
||||
|
||||
writer.WriteLine(rowBuilder.ToString().TrimEnd());
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
SabreTools.Serialization.Writers/Listxml.cs
Normal file
9
SabreTools.Serialization.Writers/Listxml.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using SabreTools.Data.Models.Listxml;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class Listxml : XmlFile<Mame>
|
||||
{
|
||||
// All logic taken care of in the base class
|
||||
}
|
||||
}
|
||||
56
SabreTools.Serialization.Writers/Logiqx.cs
Normal file
56
SabreTools.Serialization.Writers/Logiqx.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.IO;
|
||||
using SabreTools.Data.Models.Logiqx;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class Logiqx : XmlFile<Datafile>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// name field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string DocTypeName = "datafile";
|
||||
|
||||
/// <summary>
|
||||
/// pubid field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string DocTypePubId = "-//Logiqx//DTD ROM Management Datafile//EN";
|
||||
|
||||
/// <summary>
|
||||
/// sysid field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string DocTypeSysId = "http://www.logiqx.com/Dats/datafile.dtd";
|
||||
|
||||
/// <summary>
|
||||
/// subset field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string? DocTypeSubset = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.SerializeArray(T?, string?, string?, string?, string?)" />
|
||||
public override byte[]? SerializeArray(Datafile? obj)
|
||||
=> SerializeArray(obj, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.Serialize(T?, string?, string?, string?, string?, string?)" />
|
||||
public override bool SerializeFile(Datafile? obj, string? path)
|
||||
=> Serialize(obj, path, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.Serialize(T?, string?, string?, string?, string?)" />
|
||||
public override Stream? SerializeStream(Datafile? obj)
|
||||
=> Serialize(obj, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
7
SabreTools.Serialization.Writers/M1.cs
Normal file
7
SabreTools.Serialization.Writers/M1.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class M1 : XmlFile<Data.Models.Listxml.M1>
|
||||
{
|
||||
// All logic taken care of in the base class
|
||||
}
|
||||
}
|
||||
7
SabreTools.Serialization.Writers/Mess.cs
Normal file
7
SabreTools.Serialization.Writers/Mess.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class Mess : XmlFile<Data.Models.Listxml.Mess>
|
||||
{
|
||||
// All logic taken care of in the base class
|
||||
}
|
||||
}
|
||||
9
SabreTools.Serialization.Writers/OfflineList.cs
Normal file
9
SabreTools.Serialization.Writers/OfflineList.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using SabreTools.Data.Models.OfflineList;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class OfflineList : XmlFile<Dat>
|
||||
{
|
||||
// All logic taken care of in the base class
|
||||
}
|
||||
}
|
||||
50
SabreTools.Serialization.Writers/OldDotNet.cs
Normal file
50
SabreTools.Serialization.Writers/OldDotNet.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
#if NET20 || NET35
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Derived from the mscorlib code from .NET Framework 4.0
|
||||
/// </summary>
|
||||
internal static class OldDotNet
|
||||
{
|
||||
public static void CopyTo(this Stream source, Stream destination)
|
||||
{
|
||||
if (destination is null)
|
||||
{
|
||||
throw new ArgumentNullException("destination");
|
||||
}
|
||||
|
||||
if (!source.CanRead && !source.CanWrite)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
|
||||
if (!destination.CanRead && !destination.CanWrite)
|
||||
{
|
||||
throw new ObjectDisposedException("destination");
|
||||
}
|
||||
|
||||
if (!source.CanRead)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
if (!destination.CanWrite)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
byte[] array = new byte[81920];
|
||||
int count;
|
||||
while ((count = source.Read(array, 0, array.Length)) != 0)
|
||||
{
|
||||
destination.Write(array, 0, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
56
SabreTools.Serialization.Writers/OpenMSX.cs
Normal file
56
SabreTools.Serialization.Writers/OpenMSX.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.IO;
|
||||
using SabreTools.Data.Models.OpenMSX;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class OpenMSX : XmlFile<SoftwareDb>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// name field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string DocTypeName = "softwaredb";
|
||||
|
||||
/// <summary>
|
||||
/// pubid field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string? DocTypePubId = null;
|
||||
|
||||
/// <summary>
|
||||
/// sysid field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string DocTypeSysId = "softwaredb1.dtd";
|
||||
|
||||
/// <summary>
|
||||
/// subset field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string? DocTypeSubset = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.SerializeArray(T?, string?, string?, string?, string?)" />
|
||||
public override byte[]? SerializeArray(SoftwareDb? obj)
|
||||
=> SerializeArray(obj, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.Serialize(T?, string?, string?, string?, string?, string?)" />
|
||||
public override bool SerializeFile(SoftwareDb? obj, string? path)
|
||||
=> Serialize(obj, path, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.Serialize(T?, string?, string?, string?, string?)" />
|
||||
public override Stream? SerializeStream(SoftwareDb? obj)
|
||||
=> Serialize(obj, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
SabreTools.Serialization.Writers/README.MD
Normal file
12
SabreTools.Serialization.Writers/README.MD
Normal file
@@ -0,0 +1,12 @@
|
||||
# SabreTools.Serialization.Writers
|
||||
|
||||
This library contains methods for writing out data from models that are defined in `SabreTools.Data.Models` into various output sources into.
|
||||
|
||||
Writer classes can inherit from one or more interfaces, as seen in the table below:
|
||||
|
||||
| Interface Name | Source Type | Destination Type |
|
||||
| --- | --- | --- |
|
||||
| `SabreTools.Serialization.Writers.IByteWriter<TModel>` | `TModel` | `byte[]?` |
|
||||
| `SabreTools.Serialization.Writers.IFileWriter<TModel>` | `TModel` | `string?` path |
|
||||
| `SabreTools.Serialization.Writers.IStreamWriter<TModel>` | `TModel` | `Stream?` |
|
||||
| `SabreTools.Serialization.Writers.IStringWriter<TModel>` | `TModel` | `string?` representation |
|
||||
165
SabreTools.Serialization.Writers/RomCenter.cs
Normal file
165
SabreTools.Serialization.Writers/RomCenter.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.RomCenter;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Writers;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class RomCenter : BaseBinaryWriter<MetadataFile>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(MetadataFile? obj)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new IniWriter(stream, Encoding.UTF8);
|
||||
|
||||
// Write out the credits section
|
||||
WriteCredits(obj.Credits, writer);
|
||||
|
||||
// Write out the dat section
|
||||
WriteDat(obj.Dat, writer);
|
||||
|
||||
// Write out the emulator section
|
||||
WriteEmulator(obj.Emulator, writer);
|
||||
|
||||
// Write out the games
|
||||
WriteGames(obj.Games, writer);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write credits information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="credits">Credits object representing the credits information</param>
|
||||
/// <param name="writer">IniWriter representing the output</param>
|
||||
private static void WriteCredits(Credits? credits, IniWriter writer)
|
||||
{
|
||||
// If the credits information is missing, we can't do anything
|
||||
if (credits is null)
|
||||
return;
|
||||
|
||||
writer.WriteSection("CREDITS");
|
||||
|
||||
if (credits.Author is not null)
|
||||
writer.WriteKeyValuePair("Author", credits.Author);
|
||||
if (credits.Version is not null)
|
||||
writer.WriteKeyValuePair("Version", credits.Version);
|
||||
if (credits.Email is not null)
|
||||
writer.WriteKeyValuePair("Email", credits.Email);
|
||||
if (credits.Homepage is not null)
|
||||
writer.WriteKeyValuePair("Homepage", credits.Homepage);
|
||||
if (credits.Url is not null)
|
||||
writer.WriteKeyValuePair("Url", credits.Url);
|
||||
if (credits.Date is not null)
|
||||
writer.WriteKeyValuePair("Date", credits.Date);
|
||||
if (credits.Comment is not null)
|
||||
writer.WriteKeyValuePair("Comment", credits.Comment);
|
||||
writer.WriteLine();
|
||||
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write dat information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="dat">Dat object representing the dat information</param>
|
||||
/// <param name="writer">IniWriter representing the output</param>
|
||||
private static void WriteDat(Dat? dat, IniWriter writer)
|
||||
{
|
||||
// If the dat information is missing, we can't do anything
|
||||
if (dat is null)
|
||||
return;
|
||||
|
||||
writer.WriteSection("DAT");
|
||||
|
||||
if (dat.Version is not null)
|
||||
writer.WriteKeyValuePair("Version", dat.Version);
|
||||
if (dat.Plugin is not null)
|
||||
writer.WriteKeyValuePair("Plugin", dat.Plugin);
|
||||
if (dat.Split is not null)
|
||||
writer.WriteKeyValuePair("Split", dat.Split);
|
||||
if (dat.Merge is not null)
|
||||
writer.WriteKeyValuePair("Merge", dat.Merge);
|
||||
writer.WriteLine();
|
||||
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write emulator information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="emulator">Emulator object representing the emulator information</param>
|
||||
/// <param name="writer">IniWriter representing the output</param>
|
||||
private static void WriteEmulator(Emulator? emulator, IniWriter writer)
|
||||
{
|
||||
// If the emulator information is missing, we can't do anything
|
||||
if (emulator is null)
|
||||
return;
|
||||
|
||||
writer.WriteSection("EMULATOR");
|
||||
|
||||
if (emulator.RefName is not null)
|
||||
writer.WriteKeyValuePair("refname", emulator.RefName);
|
||||
if (emulator.Version is not null)
|
||||
writer.WriteKeyValuePair("version", emulator.Version);
|
||||
writer.WriteLine();
|
||||
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write games information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="games">Games object representing the games information</param>
|
||||
/// <param name="writer">IniWriter representing the output</param>
|
||||
private static void WriteGames(Games? games, IniWriter writer)
|
||||
{
|
||||
// If the games information is missing, we can't do anything
|
||||
if (games?.Rom is null || games.Rom.Length == 0)
|
||||
return;
|
||||
|
||||
writer.WriteSection("GAMES");
|
||||
|
||||
foreach (var rom in games.Rom)
|
||||
{
|
||||
var romBuilder = new StringBuilder();
|
||||
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.ParentName);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.ParentDescription);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.GameName);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.GameDescription);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.RomName);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.RomCRC);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.RomSize);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.RomOf);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append(rom.MergeName);
|
||||
romBuilder.Append('¬');
|
||||
romBuilder.Append('\n');
|
||||
|
||||
writer.WriteString(romBuilder.ToString());
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>2.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>Convert from models to external sources</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2019-2026</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Serialization</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>serialization writer conversion models</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[1.6.1]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[1.9.1]" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.Data.Models\SabreTools.Data.Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
211
SabreTools.Serialization.Writers/SeparatedValue.cs
Normal file
211
SabreTools.Serialization.Writers/SeparatedValue.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.SeparatedValue;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Writers;
|
||||
|
||||
#pragma warning disable CA1822 // Mark members as static
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class SeparatedValue : BaseBinaryWriter<MetadataFile>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
public static readonly string[] HeaderArrayStandard =
|
||||
[
|
||||
"File Name",
|
||||
"Internal Name",
|
||||
"Description",
|
||||
"Game Name",
|
||||
"Game Description",
|
||||
"Type",
|
||||
"Rom Name",
|
||||
"Disk Name",
|
||||
"Size",
|
||||
"CRC",
|
||||
"MD5",
|
||||
"SHA1",
|
||||
"SHA256",
|
||||
"Status",
|
||||
];
|
||||
|
||||
public static readonly string[] HeaderArrayExtended =
|
||||
[
|
||||
"File Name",
|
||||
"Internal Name",
|
||||
"Description",
|
||||
"Game Name",
|
||||
"Game Description",
|
||||
"Type",
|
||||
"Rom Name",
|
||||
"Disk Name",
|
||||
"Size",
|
||||
"CRC",
|
||||
"MD5",
|
||||
"SHA1",
|
||||
"SHA256",
|
||||
"SHA384",
|
||||
"SHA512",
|
||||
"SpamSum",
|
||||
"Status",
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[]? SerializeArray(MetadataFile? obj)
|
||||
=> SerializeArray(obj, ',', false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte[]? SerializeArray(MetadataFile? obj, char delim, bool longHeader)
|
||||
{
|
||||
using var stream = SerializeStream(obj, delim, longHeader);
|
||||
if (stream is null)
|
||||
return null;
|
||||
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
int read = stream.Read(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SerializeFile(MetadataFile? obj, string? path)
|
||||
=> SerializeFile(obj, path, ',', false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool SerializeFile(MetadataFile? obj, string? path, char delim, bool longHeader)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = SerializeStream(obj, delim, longHeader);
|
||||
if (stream is null)
|
||||
return false;
|
||||
|
||||
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
fs.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(MetadataFile? obj)
|
||||
=> SerializeStream(obj, ',', false);
|
||||
|
||||
/// <inheritdoc cref="SerializeStream(MetadataFile)"/>
|
||||
public Stream? SerializeStream(MetadataFile? obj, char delim, bool longHeader)
|
||||
{
|
||||
// If the metadata file is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the writer and output
|
||||
var stream = new MemoryStream();
|
||||
var writer = new SeparatedValueWriter(stream, Encoding.UTF8)
|
||||
{
|
||||
Separator = delim,
|
||||
Quotes = true
|
||||
};
|
||||
|
||||
// Write the header
|
||||
WriteHeader(writer, longHeader);
|
||||
|
||||
// Write out the rows, if they exist
|
||||
WriteRows(obj.Row, writer, longHeader);
|
||||
|
||||
// Return the stream
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write header information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
/// <param name="longHeader">True if the long variant of the row should be written, false otherwise</param>
|
||||
private static void WriteHeader(SeparatedValueWriter writer, bool longHeader)
|
||||
{
|
||||
string[] headerArray = longHeader ? HeaderArrayExtended : HeaderArrayStandard;
|
||||
writer.WriteHeader(headerArray);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write rows information to the current writer
|
||||
/// </summary>
|
||||
/// <param name="rows">Array of Row objects representing the rows information</param>
|
||||
/// <param name="writer">SeparatedValueWriter representing the output</param>
|
||||
/// <param name="longHeader">True if the long variant of the row should be written, false otherwise</param>
|
||||
private static void WriteRows(Row[]? rows, SeparatedValueWriter writer, bool longHeader)
|
||||
{
|
||||
// If the games information is missing, we can't do anything
|
||||
if (rows is null || rows.Length == 0)
|
||||
return;
|
||||
|
||||
// Loop through and write out the rows
|
||||
foreach (var row in rows)
|
||||
{
|
||||
string?[] rowArray;
|
||||
if (longHeader)
|
||||
{
|
||||
rowArray =
|
||||
[
|
||||
row.FileName,
|
||||
row.InternalName,
|
||||
row.Description,
|
||||
row.GameName,
|
||||
row.GameDescription,
|
||||
row.Type,
|
||||
row.RomName,
|
||||
row.DiskName,
|
||||
row.Size,
|
||||
row.CRC,
|
||||
row.MD5,
|
||||
row.SHA1,
|
||||
row.SHA256,
|
||||
row.SHA384,
|
||||
row.SHA512,
|
||||
row.SpamSum,
|
||||
row.Status,
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
rowArray =
|
||||
[
|
||||
row.FileName,
|
||||
row.InternalName,
|
||||
row.Description,
|
||||
row.GameName,
|
||||
row.GameDescription,
|
||||
row.Type,
|
||||
row.RomName,
|
||||
row.DiskName,
|
||||
row.Size,
|
||||
row.CRC,
|
||||
row.MD5,
|
||||
row.SHA1,
|
||||
row.SHA256,
|
||||
row.Status,
|
||||
];
|
||||
}
|
||||
|
||||
writer.WriteValues(rowArray);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
47
SabreTools.Serialization.Writers/SoftwareList.cs
Normal file
47
SabreTools.Serialization.Writers/SoftwareList.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public class SoftwareList : XmlFile<Data.Models.SoftwareList.SoftwareList>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// name field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string DocTypeName = "softwarelist";
|
||||
|
||||
/// <summary>
|
||||
/// pubid field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string? DocTypePubId = null;
|
||||
|
||||
/// <summary>
|
||||
/// sysid field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string DocTypeSysId = "softwarelist.dtd";
|
||||
|
||||
/// <summary>
|
||||
/// subset field for DOCTYPE
|
||||
/// </summary>
|
||||
public const string? DocTypeSubset = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.Serialize(T?, string?, string?, string?, string?, string?)" />
|
||||
public override bool SerializeFile(Data.Models.SoftwareList.SoftwareList? obj, string? path)
|
||||
=> Serialize(obj, path, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc cref="XmlFile.Serialize(T?, string?, string?, string?, string?)" />
|
||||
public override Stream? SerializeStream(Data.Models.SoftwareList.SoftwareList? obj)
|
||||
=> Serialize(obj, DocTypeName, DocTypePubId, DocTypeSysId, DocTypeSysId);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Serialization.Writers/XMID.cs
Normal file
33
SabreTools.Serialization.Writers/XMID.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public partial class XMID : IStringWriter<Data.Models.Xbox.XMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool Debug { get; set; } = false;
|
||||
|
||||
/// <inheritdoc cref="IStringWriter.Serialize(T?)"/>
|
||||
public static string? SerializeString(Data.Models.Xbox.XMID? obj)
|
||||
{
|
||||
var deserializer = new XMID();
|
||||
return deserializer.Serialize(obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string? Serialize(Data.Models.Xbox.XMID? obj)
|
||||
{
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append(obj.PublisherIdentifier);
|
||||
sb.Append(obj.GameID);
|
||||
sb.Append(obj.VersionNumber);
|
||||
sb.Append(obj.RegionIdentifier);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
39
SabreTools.Serialization.Writers/XeMID.cs
Normal file
39
SabreTools.Serialization.Writers/XeMID.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
public partial class XeMID : IStringWriter<Data.Models.Xbox.XeMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public bool Debug { get; set; } = false;
|
||||
|
||||
/// <inheritdoc cref="IStringWriter.Serialize(T?)"/>
|
||||
public static string? SerializeString(Data.Models.Xbox.XeMID? obj)
|
||||
{
|
||||
var deserializer = new XeMID();
|
||||
return deserializer.Serialize(obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string? Serialize(Data.Models.Xbox.XeMID? obj)
|
||||
{
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append(obj.PublisherIdentifier);
|
||||
sb.Append(obj.PlatformIdentifier);
|
||||
sb.Append(obj.GameID);
|
||||
sb.Append(obj.SKU);
|
||||
sb.Append(obj.RegionIdentifier);
|
||||
sb.Append(obj.BaseVersion);
|
||||
sb.Append(obj.MediaSubtypeIdentifier);
|
||||
sb.Append(obj.DiscNumberIdentifier);
|
||||
if (!string.IsNullOrEmpty(obj.CertificationSubmissionIdentifier))
|
||||
sb.Append(obj.CertificationSubmissionIdentifier);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
130
SabreTools.Serialization.Writers/XmlFile.cs
Normal file
130
SabreTools.Serialization.Writers/XmlFile.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using SabreTools.IO.Extensions;
|
||||
|
||||
namespace SabreTools.Serialization.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for other XML serializers
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class XmlFile<T> : BaseBinaryWriter<T>
|
||||
{
|
||||
#region IByteWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[]? SerializeArray(T? obj)
|
||||
=> SerializeArray(obj, null, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the defined type to a byte array
|
||||
/// </summary>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <param name="name">Optional DOCTYPE name</param>
|
||||
/// <param name="pubid">Optional DOCTYPE pubid</param>
|
||||
/// <param name="sysid">Optional DOCTYPE sysid</param>
|
||||
/// <param name="subset">Optional DOCTYPE name</param>
|
||||
/// <returns>Byte array containing serialized data on success, null otherwise</returns>
|
||||
public byte[]? SerializeArray(T? obj, string? name = null, string? pubid = null, string? sysid = null, string? subset = null)
|
||||
{
|
||||
using var stream = Serialize(obj, name, pubid, sysid, subset);
|
||||
if (stream is null)
|
||||
return null;
|
||||
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
int read = stream.Read(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFileWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SerializeFile(T? obj, string? path)
|
||||
=> Serialize(obj, path, null, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the defined type to an XML file
|
||||
/// </summary>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <param name="path">Path to the file to serialize to</param>
|
||||
/// <param name="name">Optional DOCTYPE name</param>
|
||||
/// <param name="pubid">Optional DOCTYPE pubid</param>
|
||||
/// <param name="sysid">Optional DOCTYPE sysid</param>
|
||||
/// <param name="subset">Optional DOCTYPE name</param>
|
||||
/// <returns>True on successful serialization, false otherwise</returns>
|
||||
public bool Serialize(T? obj, string? path, string? name = null, string? pubid = null, string? sysid = null, string? subset = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = Serialize(obj, name, pubid, sysid, subset);
|
||||
if (stream is null)
|
||||
return false;
|
||||
|
||||
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
stream.CopyTo(fs);
|
||||
fs.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStreamWriter
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Stream? SerializeStream(T? obj)
|
||||
=> Serialize(obj, null, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the defined type to a stream
|
||||
/// </summary>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <param name="name">Optional DOCTYPE name</param>
|
||||
/// <param name="pubid">Optional DOCTYPE pubid</param>
|
||||
/// <param name="sysid">Optional DOCTYPE sysid</param>
|
||||
/// <param name="subset">Optional DOCTYPE name</param>
|
||||
/// <returns>Stream containing serialized data on success, null otherwise</returns>
|
||||
public Stream? Serialize(T? obj, string? name = null, string? pubid = null, string? sysid = null, string? subset = null)
|
||||
{
|
||||
// If the object is null
|
||||
if (obj is null)
|
||||
return null;
|
||||
|
||||
// Setup the serializer and the writer
|
||||
var serializer = new XmlSerializer(typeof(T));
|
||||
var namespaces = new XmlSerializerNamespaces();
|
||||
namespaces.Add("", "");
|
||||
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
Encoding = Encoding.UTF8,
|
||||
Indent = true,
|
||||
IndentChars = "\t",
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
NamespaceHandling = NamespaceHandling.OmitDuplicates,
|
||||
#endif
|
||||
NewLineChars = "\n",
|
||||
};
|
||||
var stream = new MemoryStream();
|
||||
var streamWriter = new StreamWriter(stream);
|
||||
var xmlWriter = XmlWriter.Create(streamWriter, settings);
|
||||
|
||||
// Write the doctype if provided
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
xmlWriter.WriteDocType(name, pubid, sysid, subset);
|
||||
|
||||
// Perform the deserialization and return
|
||||
serializer.Serialize(xmlWriter, obj, namespaces);
|
||||
stream.SeekIfPossible(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user