Create and use SeparatedValue serializer

This commit is contained in:
Matt Nadareski
2023-07-29 21:24:16 -04:00
parent 41594b7f2d
commit 9ae8036b0a
7 changed files with 679 additions and 397 deletions

View File

@@ -0,0 +1,139 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.SeparatedValue;
namespace SabreTools.Serialization
{
/// <summary>
/// Deserializer for separated-value variants
/// </summary>
public partial class SeparatedValue
{
/// <summary>
/// Deserializes a separated-value variant to the defined type
/// </summary>
/// <param name="path">Path to the file to deserialize</param>
/// <param name="delim">Character delimiter between values</param>
/// <returns>Deserialized data on success, null on failure</returns>
public static MetadataFile? Deserialize(string path, char delim)
{
try
{
using var stream = PathProcessor.OpenStream(path);
return Deserialize(stream, delim);
}
catch
{
// TODO: Handle logging the exception
return default;
}
}
/// <summary>
/// Deserializes a separated-value variant in a stream to the defined type
/// </summary>
/// <param name="stream">Stream to deserialize</param>
/// <param name="delim">Character delimiter between values</param>
/// <returns>Deserialized data on success, null on failure</returns>
public static MetadataFile? Deserialize(Stream? stream, char delim)
{
try
{
// If the stream is null
if (stream == null)
return default;
// Setup the reader and output
var reader = new SeparatedValueReader(stream, Encoding.UTF8)
{
Header = true,
Separator = delim,
VerifyFieldCount = false,
};
var dat = new MetadataFile();
// Read the header values first
if (!reader.ReadHeader())
return null;
dat.Header = reader.HeaderValues.ToArray();
// Loop through the rows and parse out values
var rows = new List<Row>();
while (!reader.EndOfStream)
{
// If we have no next line
if (!reader.ReadNextLine())
break;
// Parse the line into a row
Row? row = null;
if (reader.Line.Count < HeaderWithExtendedHashesCount)
{
row = new Row
{
FileName = reader.Line[0],
InternalName = reader.Line[1],
Description = reader.Line[2],
GameName = reader.Line[3],
GameDescription = reader.Line[4],
Type = reader.Line[5],
RomName = reader.Line[6],
DiskName = reader.Line[7],
Size = reader.Line[8],
CRC = reader.Line[9],
MD5 = reader.Line[10],
SHA1 = reader.Line[11],
SHA256 = reader.Line[12],
Status = reader.Line[13],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithoutExtendedHashesCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithoutExtendedHashesCount).ToArray();
}
else
{
row = new Row
{
FileName = reader.Line[0],
InternalName = reader.Line[1],
Description = reader.Line[2],
GameName = reader.Line[3],
GameDescription = reader.Line[4],
Type = reader.Line[5],
RomName = reader.Line[6],
DiskName = reader.Line[7],
Size = reader.Line[8],
CRC = reader.Line[9],
MD5 = reader.Line[10],
SHA1 = reader.Line[11],
SHA256 = reader.Line[12],
SHA384 = reader.Line[13],
SHA512 = reader.Line[14],
SpamSum = reader.Line[15],
Status = reader.Line[16],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithExtendedHashesCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithExtendedHashesCount).ToArray();
}
rows.Add(row);
}
// Assign the rows to the Dat and return
dat.Row = rows.ToArray();
return dat;
}
catch
{
// TODO: Handle logging the exception
return default;
}
}
}
}

View File

@@ -0,0 +1,147 @@
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Writers;
using SabreTools.Models.SeparatedValue;
namespace SabreTools.Serialization
{
/// <summary>
/// Serializer for separated-value variants
/// </summary>
public partial class SeparatedValue
{
/// <summary>
/// Serializes the defined type to a separated-value variant
/// </summary>
/// <param name="metadataFile">Data to serialize</param>
/// <param name="path">Path to the file to serialize to</param>
/// <param name="delim">Character delimiter between values</param>
/// <returns>True on successful serialization, false otherwise</returns>
public static bool SerializeToFile(MetadataFile? metadataFile, string path, char delim)
{
try
{
using var stream = SerializeToStream(metadataFile, delim);
if (stream == null)
return false;
using var fs = File.OpenWrite(path);
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(fs);
return true;
}
catch
{
// TODO: Handle logging the exception
return false;
}
}
/// <summary>
/// Serializes the defined type to a stream
/// </summary>
/// <param name="metadataFile">Data to serialize</param>
/// <param name="delim">Character delimiter between values</param>
/// <returns>Stream containing serialized data on success, null otherwise</returns>
public static Stream? SerializeToStream(MetadataFile? metadataFile, char delim)
{
try
{
// If the metadata file is null
if (metadataFile == null)
return null;
// Setup the writer and output
var stream = new MemoryStream();
var writer = new SeparatedValueWriter(stream, Encoding.UTF8) { Separator = delim, Quotes = true };
// TODO: Include flag to write out long or short header
// Write the short header
WriteHeader(writer);
// Write out the rows, if they exist
WriteRows(metadataFile.Row, writer);
// Return the stream
return stream;
}
catch
{
// TODO: Handle logging the exception
return null;
}
}
/// <summary>
/// Write header information to the current writer
/// </summary>
/// <param name="writer">SeparatedValueWriter representing the output</param>
private static void WriteHeader(SeparatedValueWriter writer)
{
var headerArray = new string[]
{
"File Name",
"Internal Name",
"Description",
"Game Name",
"Game Description",
"Type",
"Rom Name",
"Disk Name",
"Size",
"CRC",
"MD5",
"SHA1",
"SHA256",
//"SHA384",
//"SHA512",
//"SpamSum",
"Status",
};
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>
private static void WriteRows(Row[]? rows, SeparatedValueWriter writer)
{
// If the games information is missing, we can't do anything
if (rows == null || !rows.Any())
return;
// Loop through and write out the rows
foreach (var row in rows)
{
var rowArray = new string[]
{
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,
};
writer.WriteValues(rowArray);
writer.Flush();
}
}
}
}

View File

@@ -1,143 +1,12 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.SeparatedValue;
namespace SabreTools.Serialization
{
/// <summary>
/// Serializer for separated-value variants
/// Represents separated-value variants
/// </summary>
public class SeparatedValue
public partial class SeparatedValue
{
private const int HeaderWithoutExtendedHashesCount = 14;
private const int HeaderWithExtendedHashesCount = 17;
/// <summary>
/// Deserializes a separated-value variant to the defined type
/// </summary>
/// <param name="path">Path to the file to deserialize</param>
/// <param name="delim">Character delimiter between values</param>
/// <returns>Deserialized data on success, null on failure</returns>
public static MetadataFile? Deserialize(string path, char delim)
{
try
{
using var stream = PathProcessor.OpenStream(path);
return Deserialize(stream, delim);
}
catch
{
// TODO: Handle logging the exception
return default;
}
}
/// <summary>
/// Deserializes a separated-value variant in a stream to the defined type
/// </summary>
/// <param name="stream">Stream to deserialize</param>
/// <param name="delim">Character delimiter between values</param>
/// <returns>Deserialized data on success, null on failure</returns>
public static MetadataFile? Deserialize(Stream? stream, char delim)
{
try
{
// If the stream is null
if (stream == null)
return default;
// Setup the reader and output
var reader = new SeparatedValueReader(stream, Encoding.UTF8)
{
Header = true,
Separator = delim,
VerifyFieldCount = false,
};
var dat = new MetadataFile();
// Read the header values first
if (!reader.ReadHeader())
return null;
dat.Header = reader.HeaderValues.ToArray();
// Loop through the rows and parse out values
var rows = new List<Row>();
while (!reader.EndOfStream)
{
// If we have no next line
if (!reader.ReadNextLine())
break;
// Parse the line into a row
Row? row = null;
if (reader.Line.Count < HeaderWithExtendedHashesCount)
{
row = new Row
{
FileName = reader.Line[0],
InternalName = reader.Line[1],
Description = reader.Line[2],
GameName = reader.Line[3],
GameDescription = reader.Line[4],
Type = reader.Line[5],
RomName = reader.Line[6],
DiskName = reader.Line[7],
Size = reader.Line[8],
CRC = reader.Line[9],
MD5 = reader.Line[10],
SHA1 = reader.Line[11],
SHA256 = reader.Line[12],
Nodump = reader.Line[13],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithoutExtendedHashesCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithoutExtendedHashesCount).ToArray();
}
else
{
row = new Row
{
FileName = reader.Line[0],
InternalName = reader.Line[1],
Description = reader.Line[2],
GameName = reader.Line[3],
GameDescription = reader.Line[4],
Type = reader.Line[5],
RomName = reader.Line[6],
DiskName = reader.Line[7],
Size = reader.Line[8],
CRC = reader.Line[9],
MD5 = reader.Line[10],
SHA1 = reader.Line[11],
SHA256 = reader.Line[12],
SHA384 = reader.Line[13],
SHA512 = reader.Line[14],
SpamSum = reader.Line[15],
Nodump = reader.Line[16],
};
// If we have additional fields
if (reader.Line.Count > HeaderWithExtendedHashesCount)
row.ADDITIONAL_ELEMENTS = reader.Line.Skip(HeaderWithExtendedHashesCount).ToArray();
}
rows.Add(row);
}
// Assign the rows to the Dat and return
dat.Row = rows.ToArray();
return dat;
}
catch
{
// TODO: Handle logging the exception
return default;
}
}
}
}