mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-05 22:01:33 +00:00
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.
262 lines
9.1 KiB
C#
262 lines
9.1 KiB
C#
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
|
|
}
|
|
}
|