mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-04-21 21:54:13 +00:00
Add PLJ builders/wrappers/printing
This commit is contained in:
328
BurnOutSharp.Builders/PlayJ.cs
Normal file
328
BurnOutSharp.Builders/PlayJ.cs
Normal file
@@ -0,0 +1,328 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Models.PlayJ;
|
||||
using BurnOutSharp.Utilities;
|
||||
using static BurnOutSharp.Models.PlayJ.Constants;
|
||||
|
||||
namespace BurnOutSharp.Builders
|
||||
{
|
||||
public class PlayJ
|
||||
{
|
||||
#region Byte Data
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a PlayJ playlist
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled playlist on success, null on error</returns>
|
||||
public static Playlist ParsePlaylist(byte[] data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and parse that
|
||||
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return ParsePlaylist(dataStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a PlayJ audio file
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled audio file on success, null on error</returns>
|
||||
public static AudioFile ParseAudioFile(byte[] data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and parse that
|
||||
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return ParseAudioFile(dataStream);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Data
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a PlayJ playlist
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled playlist on success, null on error</returns>
|
||||
public static Playlist ParsePlaylist(Stream data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (data.Position < 0 || data.Position >= data.Length)
|
||||
return null;
|
||||
|
||||
// Cache the current offset
|
||||
int initialOffset = (int)data.Position;
|
||||
|
||||
// Create a new playlist to fill
|
||||
var playlist = new Playlist();
|
||||
|
||||
#region Playlist Header
|
||||
|
||||
// Try to parse the playlist header
|
||||
var playlistHeader = ParsePlaylistHeader(data);
|
||||
if (playlistHeader == null)
|
||||
return null;
|
||||
|
||||
// Set the playlist header
|
||||
playlist.Header = playlistHeader;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Audio Files
|
||||
|
||||
// Create the audio files array
|
||||
playlist.AudioFiles = new AudioFile[playlistHeader.TrackCount];
|
||||
|
||||
// Try to parse the audio files
|
||||
for (int i = 0; i < playlist.AudioFiles.Length; i++)
|
||||
{
|
||||
long currentOffset = data.Position;
|
||||
var entryHeader = ParseAudioFile(data, currentOffset);
|
||||
if (entryHeader == null)
|
||||
return null;
|
||||
|
||||
playlist.AudioFiles[i] = entryHeader;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
return playlist;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a PlayJ audio file
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="adjust">Offset to adjust all seeking by</param>
|
||||
/// <returns>Filled audio file on success, null on error</returns>
|
||||
public static AudioFile ParseAudioFile(Stream data, long adjust = 0)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (data.Position < 0 || data.Position >= data.Length)
|
||||
return null;
|
||||
|
||||
// Cache the current offset
|
||||
int initialOffset = (int)data.Position;
|
||||
|
||||
// Create a new audio file to fill
|
||||
var audioFile = new AudioFile();
|
||||
|
||||
#region Entry Header
|
||||
|
||||
// Try to parse the entry header
|
||||
var entryHeader = ParseEntryHeader(data);
|
||||
if (entryHeader == null)
|
||||
return null;
|
||||
|
||||
// Set the entry header
|
||||
audioFile.Header = entryHeader;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unknown Block 1
|
||||
|
||||
// Get the unknown block 1 offset
|
||||
long offset = entryHeader.UnknownOffset1 + adjust;
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Seek to the unknown block 1
|
||||
data.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
// Try to parse the unknown block 1
|
||||
var unknownBlock1 = ParseUnknownBlock1(data);
|
||||
if (unknownBlock1 == null)
|
||||
return null;
|
||||
|
||||
// Set the unknown block 1
|
||||
audioFile.UnknownBlock1 = unknownBlock1;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unknown Value 2
|
||||
|
||||
// Get the unknown value 2 offset
|
||||
offset = entryHeader.UnknownOffset2 + adjust;
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Seek to the unknown value 2
|
||||
data.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
// Set the unknown value 2
|
||||
audioFile.UnknownValue2 = data.ReadUInt32();;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unknown Block 3
|
||||
|
||||
// Get the unknown block 3 offset
|
||||
offset = entryHeader.UnknownOffset3 + adjust;
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Seek to the unknown block 3
|
||||
data.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
// Try to parse the unknown block 3
|
||||
var unknownBlock3 = ParseUnknownBlock3(data);
|
||||
if (unknownBlock3 == null)
|
||||
return null;
|
||||
|
||||
// Set the unknown block 3
|
||||
audioFile.UnknownBlock3 = unknownBlock3;
|
||||
|
||||
#endregion
|
||||
|
||||
return audioFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a playlist header
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled playlist header on success, null on error</returns>
|
||||
private static PlaylistHeader ParsePlaylistHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
PlaylistHeader playlistHeader = new PlaylistHeader();
|
||||
|
||||
playlistHeader.TrackCount = data.ReadUInt32();
|
||||
playlistHeader.Data = data.ReadBytes(52);
|
||||
|
||||
return playlistHeader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an entry header
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled entry header on success, null on error</returns>
|
||||
private static EntryHeader ParseEntryHeader(Stream data)
|
||||
{
|
||||
// Cache the current offset
|
||||
long initialOffset = data.Position;
|
||||
|
||||
// TODO: Use marshalling here instead of building
|
||||
EntryHeader entryHeader = new EntryHeader();
|
||||
|
||||
entryHeader.Signature = data.ReadUInt32();
|
||||
if (entryHeader.Signature != SignatureUInt32)
|
||||
return null;
|
||||
|
||||
// Only V1 is supported currently
|
||||
entryHeader.Version = data.ReadUInt32();
|
||||
if (entryHeader.Version != 0x00000000)
|
||||
return null;
|
||||
|
||||
entryHeader.TrackID = data.ReadUInt32();
|
||||
entryHeader.UnknownOffset1 = data.ReadUInt32();
|
||||
entryHeader.UnknownOffset2 = data.ReadUInt32();
|
||||
entryHeader.UnknownOffset3 = data.ReadUInt32();
|
||||
entryHeader.Unknown1 = data.ReadUInt32();
|
||||
entryHeader.Unknown2 = data.ReadUInt32();
|
||||
entryHeader.Year = data.ReadUInt32();
|
||||
entryHeader.TrackNumber = data.ReadByteValue();
|
||||
entryHeader.Subgenre = (Subgenre)data.ReadByteValue();
|
||||
entryHeader.Duration = data.ReadUInt32();
|
||||
|
||||
entryHeader.TrackLength = data.ReadUInt16();
|
||||
byte[] track = data.ReadBytes(entryHeader.TrackLength);
|
||||
if (track != null)
|
||||
entryHeader.Track = Encoding.ASCII.GetString(track);
|
||||
|
||||
entryHeader.ArtistLength = data.ReadUInt16();
|
||||
byte[] artist = data.ReadBytes(entryHeader.ArtistLength);
|
||||
if (artist != null)
|
||||
entryHeader.Artist = Encoding.ASCII.GetString(artist);
|
||||
|
||||
entryHeader.AlbumLength = data.ReadUInt16();
|
||||
byte[] album = data.ReadBytes(entryHeader.AlbumLength);
|
||||
if (album != null)
|
||||
entryHeader.Album = Encoding.ASCII.GetString(album);
|
||||
|
||||
entryHeader.WriterLength = data.ReadUInt16();
|
||||
byte[] writer = data.ReadBytes(entryHeader.WriterLength);
|
||||
if (writer != null)
|
||||
entryHeader.Writer = Encoding.ASCII.GetString(writer);
|
||||
|
||||
entryHeader.PublisherLength = data.ReadUInt16();
|
||||
byte[] publisher = data.ReadBytes(entryHeader.PublisherLength);
|
||||
if (publisher != null)
|
||||
entryHeader.Publisher = Encoding.ASCII.GetString(publisher);
|
||||
|
||||
entryHeader.LabelLength = data.ReadUInt16();
|
||||
byte[] label = data.ReadBytes(entryHeader.LabelLength);
|
||||
if (label != null)
|
||||
entryHeader.Label = Encoding.ASCII.GetString(label);
|
||||
|
||||
if (data.Position - initialOffset < entryHeader.UnknownOffset1)
|
||||
{
|
||||
entryHeader.CommentsLength = data.ReadUInt16();
|
||||
byte[] comments = data.ReadBytes(entryHeader.CommentsLength);
|
||||
if (comments != null)
|
||||
entryHeader.Comments = Encoding.ASCII.GetString(comments);
|
||||
}
|
||||
|
||||
return entryHeader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an unknown block 1
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled unknown block 1 on success, null on error</returns>
|
||||
private static UnknownBlock1 ParseUnknownBlock1(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
UnknownBlock1 unknownBlock1 = new UnknownBlock1();
|
||||
|
||||
unknownBlock1.Length = data.ReadUInt16();
|
||||
unknownBlock1.Data = data.ReadBytes(unknownBlock1.Length);
|
||||
|
||||
return unknownBlock1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an unknown block 3
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled unknown block 3 on success, null on error</returns>
|
||||
private static UnknownBlock3 ParseUnknownBlock3(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
UnknownBlock3 unknownBlock3 = new UnknownBlock3();
|
||||
|
||||
// No-op because we don't even know the length
|
||||
|
||||
return unknownBlock3;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,11 @@ namespace BurnOutSharp.Models.PlayJ
|
||||
/// <summary>
|
||||
/// Playlist header
|
||||
/// </summary>
|
||||
public PlaylistHeader PlaylistHeader { get; set; }
|
||||
public PlaylistHeader Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entry headers
|
||||
/// Embedded audio files / headers
|
||||
/// </summary>
|
||||
public EntryHeader[] EntryHeaders { get; set; }
|
||||
public AudioFile[] AudioFiles { get; set; }
|
||||
}
|
||||
}
|
||||
284
BurnOutSharp.Wrappers/PlayJAudioFile.cs
Normal file
284
BurnOutSharp.Wrappers/PlayJAudioFile.cs
Normal file
@@ -0,0 +1,284 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace BurnOutSharp.Wrappers
|
||||
{
|
||||
public class PlayJAudioFile : WrapperBase
|
||||
{
|
||||
#region Pass-Through Properties
|
||||
|
||||
#region Entry Header
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Signature"/>
|
||||
public uint Signature => _audioFile.Header.Signature;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Version"/>
|
||||
public uint Version => _audioFile.Header.Version;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.TrackID"/>
|
||||
public uint TrackID => _audioFile.Header.TrackID;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.UnknownOffset1"/>
|
||||
public uint UnknownOffset1 => _audioFile.Header.UnknownOffset1;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.UnknownOffset2"/>
|
||||
public uint UnknownOffset2 => _audioFile.Header.UnknownOffset2;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.UnknownOffset3"/>
|
||||
public uint UnknownOffset3 => _audioFile.Header.UnknownOffset3;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Unknown1"/>
|
||||
public uint Unknown1 => _audioFile.Header.Unknown1;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Unknown2"/>
|
||||
public uint Unknown2 => _audioFile.Header.Unknown2;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Year"/>
|
||||
public uint Year => _audioFile.Header.Year;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.TrackNumber"/>
|
||||
public byte TrackNumber => _audioFile.Header.TrackNumber;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Subgenre"/>
|
||||
public Models.PlayJ.Subgenre Subgenre => _audioFile.Header.Subgenre;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Duration"/>
|
||||
public uint Duration => _audioFile.Header.Duration;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.TrackLength"/>
|
||||
public ushort TrackLength => _audioFile.Header.TrackLength;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Track"/>
|
||||
public string Track => _audioFile.Header.Track;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.ArtistLength"/>
|
||||
public ushort ArtistLength => _audioFile.Header.ArtistLength;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Artist"/>
|
||||
public string Artist => _audioFile.Header.Artist;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.AlbumLength"/>
|
||||
public ushort AlbumLength => _audioFile.Header.AlbumLength;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Album"/>
|
||||
public string Album => _audioFile.Header.Album;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.WriterLength"/>
|
||||
public ushort WriterLength => _audioFile.Header.WriterLength;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Writer"/>
|
||||
public string Writer => _audioFile.Header.Writer;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.PublisherLength"/>
|
||||
public ushort PublisherLength => _audioFile.Header.PublisherLength;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Publisher"/>
|
||||
public string Publisher => _audioFile.Header.Publisher;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.LabelLength"/>
|
||||
public ushort LabelLength => _audioFile.Header.LabelLength;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Label"/>
|
||||
public string Label => _audioFile.Header.Label;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.CommentsLength"/>
|
||||
public ushort CommentsLength => _audioFile.Header.CommentsLength;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.EntryHeader.Comments"/>
|
||||
public string Comments => _audioFile.Header.Comments;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unknown Block 1
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.UnknownBlock1.Length"/>
|
||||
public ushort UB1_Length => _audioFile.UnknownBlock1.Length;
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.UnknownBlock1.Data"/>
|
||||
public byte[] UB1_Data => _audioFile.UnknownBlock1.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unknown Value 2
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.AudioFile.UnknownValue2"/>
|
||||
public uint UnknownValue2 => _audioFile.UnknownValue2;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unknown Block 3
|
||||
|
||||
/// <inheritdoc cref="Models.PlayJ.UnknownBlock3.Data"/>
|
||||
public byte[] UB3_Data => _audioFile.UnknownBlock3.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Variables
|
||||
|
||||
/// <summary>
|
||||
/// Internal representation of the archive
|
||||
/// </summary>
|
||||
private Models.PlayJ.AudioFile _audioFile;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private PlayJAudioFile() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a PlayJ audio file from a byte array and offset
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the archive</param>
|
||||
/// <param name="offset">Offset within the array to parse</param>
|
||||
/// <returns>A PlayJ audio file wrapper on success, null on failure</returns>
|
||||
public static PlayJAudioFile Create(byte[] data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and use that
|
||||
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return Create(dataStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a PlayJ audio file from a Stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the archive</param>
|
||||
/// <returns>A PlayJ audio file wrapper on success, null on failure</returns>
|
||||
public static PlayJAudioFile Create(Stream data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
var audioFile = Builders.PlayJ.ParseAudioFile(data);
|
||||
if (audioFile == null)
|
||||
return null;
|
||||
|
||||
var wrapper = new PlayJAudioFile
|
||||
{
|
||||
_audioFile = audioFile,
|
||||
_dataSource = DataSource.Stream,
|
||||
_streamData = data,
|
||||
};
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Printing
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override StringBuilder PrettyPrint()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("PlayJ Audio File Information:");
|
||||
builder.AppendLine("-------------------------");
|
||||
builder.AppendLine();
|
||||
|
||||
PrintEntryHeader(builder);
|
||||
PrintUnknownBlock1(builder);
|
||||
PrintUnknownValue2(builder);
|
||||
PrintUnknownBlock3(builder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print entry header information
|
||||
/// </summary>
|
||||
/// <param name="builder">StringBuilder to append information to</param>
|
||||
private void PrintEntryHeader(StringBuilder builder)
|
||||
{
|
||||
builder.AppendLine(" Entry Header Information:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
builder.AppendLine($" Signature: {Signature} (0x{Signature:X})");
|
||||
builder.AppendLine($" Version: {Version} (0x{Version:X})");
|
||||
builder.AppendLine($" Track ID: {TrackID} (0x{TrackID:X})");
|
||||
builder.AppendLine($" Unknown offset 1: {UnknownOffset1} (0x{UnknownOffset1:X})");
|
||||
builder.AppendLine($" Unknown offset 2: {UnknownOffset2} (0x{UnknownOffset2:X})");
|
||||
builder.AppendLine($" Unknown offset 3: {UnknownOffset3} (0x{UnknownOffset3:X})");
|
||||
builder.AppendLine($" Unknown 1: {Unknown1} (0x{Unknown1:X})");
|
||||
builder.AppendLine($" Unknown 2: {Unknown2} (0x{Unknown2:X})");
|
||||
builder.AppendLine($" Year: {Year} (0x{Year:X})");
|
||||
builder.AppendLine($" Track number: {TrackNumber} (0x{TrackNumber:X})");
|
||||
builder.AppendLine($" Subgenre: {Subgenre} (0x{Subgenre:X})");
|
||||
builder.AppendLine($" Duration in seconds: {Duration} (0x{Duration:X})");
|
||||
builder.AppendLine($" Track length: {TrackLength} (0x{TrackLength:X})");
|
||||
builder.AppendLine($" Track: {Track ?? "[NULL]"}");
|
||||
builder.AppendLine($" Artist length: {ArtistLength} (0x{ArtistLength:X})");
|
||||
builder.AppendLine($" Artist: {Artist ?? "[NULL]"}");
|
||||
builder.AppendLine($" Album length: {AlbumLength} (0x{AlbumLength:X})");
|
||||
builder.AppendLine($" Album: {Album ?? "[NULL]"}");
|
||||
builder.AppendLine($" Writer length: {WriterLength} (0x{WriterLength:X})");
|
||||
builder.AppendLine($" Writer: {Writer ?? "[NULL]"}");
|
||||
builder.AppendLine($" Publisher length: {PublisherLength} (0x{PublisherLength:X})");
|
||||
builder.AppendLine($" Publisher: {Publisher ?? "[NULL]"}");
|
||||
builder.AppendLine($" Label length: {LabelLength} (0x{LabelLength:X})");
|
||||
builder.AppendLine($" Label: {Label ?? "[NULL]"}");
|
||||
builder.AppendLine($" Comments length: {CommentsLength} (0x{CommentsLength:X})");
|
||||
builder.AppendLine($" Comments: {Comments ?? "[NULL]"}");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print unknown block 1 information
|
||||
/// </summary>
|
||||
/// <param name="builder">StringBuilder to append information to</param>
|
||||
private void PrintUnknownBlock1(StringBuilder builder)
|
||||
{
|
||||
builder.AppendLine(" Unknown Block 1 Information:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
builder.AppendLine($" Length: {UB1_Length} (0x{UB1_Length:X})");
|
||||
builder.AppendLine($" Data: {BitConverter.ToString(UB1_Data ?? new byte[0]).Replace('-', ' ')}");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print unknown value 2 information
|
||||
/// </summary>
|
||||
/// <param name="builder">StringBuilder to append information to</param>
|
||||
private void PrintUnknownValue2(StringBuilder builder)
|
||||
{
|
||||
builder.AppendLine(" Unknown Value 2 Information:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
builder.AppendLine($" Value: {UnknownValue2} (0x{UnknownValue2:X})");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print unknown block 3 information
|
||||
/// </summary>
|
||||
/// <param name="builder">StringBuilder to append information to</param>
|
||||
private void PrintUnknownBlock3(StringBuilder builder)
|
||||
{
|
||||
builder.AppendLine(" Unknown Block 3 Information:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
builder.AppendLine($" Data: {BitConverter.ToString(UB3_Data ?? new byte[0]).Replace('-', ' ')}");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ExportJSON() => System.Text.Json.JsonSerializer.Serialize(_audioFile, _jsonSerializerOptions);
|
||||
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,7 @@ Below is a list of container formats that are supported in some way:
|
||||
| Nintendo CIA archive | Yes | Yes | No | |
|
||||
| Nintendo DS/DSi cart image | Yes | Yes | No | |
|
||||
| PKZIP and derived files (ZIP, etc.) | No | Yes | Yes | Via `SharpCompress` |
|
||||
| PlayJ audio file (PLJ) | No | Yes | No | |
|
||||
| PlayJ audio file (PLJ) | Yes* | Yes | No | Undocumented file format, many fields printed |
|
||||
| Portable Executable | Yes | Yes | No* | Some packed executables are supported |
|
||||
| Quantum archive (Q) | Yes | No | No | |
|
||||
| RAR archive (RAR) | No | Yes | Yes | Via `SharpCompress` |
|
||||
|
||||
@@ -195,6 +195,12 @@ namespace Test
|
||||
wrapper = PAK.Create(stream);
|
||||
break;
|
||||
|
||||
// PLJ
|
||||
case SupportedFileType.PLJ:
|
||||
wrapperName = "PlayJ audio file";
|
||||
wrapper = PlayJAudioFile.Create(stream);
|
||||
break;
|
||||
|
||||
// Quantum
|
||||
case SupportedFileType.Quantum:
|
||||
wrapperName = "Quantum archive";
|
||||
|
||||
Reference in New Issue
Block a user