Start adding separate header information

This commit is contained in:
Matt Nadareski
2023-01-15 12:30:22 -08:00
parent 964271b4e1
commit 8c164d776e
5 changed files with 380 additions and 30 deletions

View File

@@ -357,6 +357,130 @@ namespace BurnOutSharp.Builders
return entryHeader;
}
/// <summary>
/// Parse a Stream into an audio header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled audio header on success, null on error</returns>
private static AudioHeader ParseAudioHeader(Stream data)
{
// Cache the current offset
long initialOffset = data.Position;
// TODO: Use marshalling here instead of building
AudioHeader audioHeader;
// Get the common header pieces
uint signature = data.ReadUInt32();
if (signature != SignatureUInt32)
return null;
uint version = data.ReadUInt32();
// Build the header according to version
uint unknownOffset1;
switch (version)
{
// Version 1
case 0x00000000:
AudioHeaderV1 v1 = new AudioHeaderV1();
v1.Signature = signature;
v1.Version = version;
v1.TrackID = data.ReadUInt32();
v1.UnknownOffset1 = data.ReadUInt32();
v1.UnknownOffset2 = data.ReadUInt32();
v1.UnknownOffset3 = data.ReadUInt32();
v1.Unknown1 = data.ReadUInt32();
v1.Unknown2 = data.ReadUInt32();
v1.Year = data.ReadUInt32();
v1.TrackNumber = data.ReadByteValue();
v1.Subgenre = (Subgenre)data.ReadByteValue();
v1.Duration = data.ReadUInt32();
audioHeader = v1;
unknownOffset1 = v1.UnknownOffset1;
break;
// Version 2
case 0x0000000A:
AudioHeaderV2 v2 = new AudioHeaderV2();
v2.Signature = signature;
v2.Version = version;
v2.Unknown1 = data.ReadUInt32();
v2.Unknown2 = data.ReadUInt32();
v2.Unknown3 = data.ReadUInt32();
v2.Unknown4 = data.ReadUInt32();
v2.Unknown5 = data.ReadUInt32();
v2.Unknown6 = data.ReadUInt32();
v2.UnknownOffset1 = data.ReadUInt32();
v2.Unknown7 = data.ReadUInt32();
v2.Unknown8 = data.ReadUInt32();
v2.Unknown9 = data.ReadUInt32();
v2.UnknownOffset2 = data.ReadUInt32();
v2.Unknown10 = data.ReadUInt32();
v2.Unknown11 = data.ReadUInt32();
v2.Unknown12 = data.ReadUInt32();
v2.TrackID = data.ReadUInt32();
v2.Year = data.ReadUInt32();
v2.TrackNumber = data.ReadUInt32();
v2.Unknown13 = data.ReadUInt32();
audioHeader = v2;
unknownOffset1 = v2.UnknownOffset1 + 0x54;
break;
// No other version are recognized
default:
return null;
}
audioHeader.Signature = data.ReadUInt32();
if (audioHeader.Signature != SignatureUInt32)
return null;
audioHeader.TrackLength = data.ReadUInt16();
byte[] track = data.ReadBytes(audioHeader.TrackLength);
if (track != null)
audioHeader.Track = Encoding.ASCII.GetString(track);
audioHeader.ArtistLength = data.ReadUInt16();
byte[] artist = data.ReadBytes(audioHeader.ArtistLength);
if (artist != null)
audioHeader.Artist = Encoding.ASCII.GetString(artist);
audioHeader.AlbumLength = data.ReadUInt16();
byte[] album = data.ReadBytes(audioHeader.AlbumLength);
if (album != null)
audioHeader.Album = Encoding.ASCII.GetString(album);
audioHeader.WriterLength = data.ReadUInt16();
byte[] writer = data.ReadBytes(audioHeader.WriterLength);
if (writer != null)
audioHeader.Writer = Encoding.ASCII.GetString(writer);
audioHeader.PublisherLength = data.ReadUInt16();
byte[] publisher = data.ReadBytes(audioHeader.PublisherLength);
if (publisher != null)
audioHeader.Publisher = Encoding.ASCII.GetString(publisher);
audioHeader.LabelLength = data.ReadUInt16();
byte[] label = data.ReadBytes(audioHeader.LabelLength);
if (label != null)
audioHeader.Label = Encoding.ASCII.GetString(label);
if (data.Position - initialOffset < unknownOffset1)
{
audioHeader.CommentsLength = data.ReadUInt16();
byte[] comments = data.ReadBytes(audioHeader.CommentsLength);
if (comments != null)
audioHeader.Comments = Encoding.ASCII.GetString(comments);
}
return audioHeader;
}
/// <summary>
/// Parse a Stream into an unknown block 1
/// </summary>

View File

@@ -0,0 +1,93 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// PlayJ audio header / CDS entry header
/// </summary>
/// <remarks>V1 and V2 variants exist</remarks>
public abstract class AudioHeader
{
/// <summary>
/// Signature (0x4B539DFF)
/// </summary>
public uint Signature;
/// <summary>
/// Version
/// </summary>
public uint Version;
// Header-specific data goes here
/// <summary>
/// Length of the track name
/// </summary>
public ushort TrackLength;
/// <summary>
/// Track name (not null-terminated)
/// </summary>
public string Track;
/// <summary>
/// Length of the artist name
/// </summary>
public ushort ArtistLength;
/// <summary>
/// Artist name (not null-terminated)
/// </summary>
public string Artist;
/// <summary>
/// Length of the album name
/// </summary>
public ushort AlbumLength;
/// <summary>
/// Album name (not null-terminated)
/// </summary>
public string Album;
/// <summary>
/// Length of the writer name
/// </summary>
public ushort WriterLength;
/// <summary>
/// Writer name (not null-terminated)
/// </summary>
public string Writer;
/// <summary>
/// Length of the publisher name
/// </summary>
public ushort PublisherLength;
/// <summary>
/// Publisher name (not null-terminated)
/// </summary>
public string Publisher;
/// <summary>
/// Length of the label name
/// </summary>
public ushort LabelLength;
/// <summary>
/// Label name (not null-terminated)
/// </summary>
public string Label;
/// <summary>
/// Length of the comments
/// </summary>
/// <remarks>Optional field only in some samples</remarks>
public ushort CommentsLength;
/// <summary>
/// Comments (not null-terminated)
/// </summary>
/// <remarks>Optional field only in some samples</remarks>
public string Comments;
}
}

View File

@@ -0,0 +1,62 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// PlayJ audio header / CDS entry header (V1)
/// </summary>
public sealed class AudioHeaderV1 : AudioHeader
{
/// <summary>
/// Download track ID
/// </summary>
/// <remarks>0xFFFFFFFF if unset</remarks>
public uint TrackID;
/// <summary>
/// Offset to unknown data block 1
/// </summary>
public uint UnknownOffset1;
/// <summary>
/// Offset to unknown data block 2
/// </summary>
public uint UnknownOffset2;
/// <summary>
/// Offset to unknown data block 3
/// </summary>
public uint UnknownOffset3;
/// <summary>
/// Unknown
/// </summary>
/// <remarks>Always 0x00000001</remarks>
public uint Unknown1;
/// <summary>
/// Unknown
/// </summary>
/// <remarks>Typically 0x00000001 in download titles</remarks>
public uint Unknown2;
/// <summary>
/// Track year
/// </summary>
/// <remarks>0xFFFFFFFF if unset</remarks>
public uint Year;
/// <summary>
/// Track number
/// </summary>
public byte TrackNumber;
/// <summary>
/// Subgenre
/// </summary>
public Subgenre Subgenre;
/// <summary>
/// Track duration in seconds
/// </summary>
public uint Duration;
}
}

View File

@@ -0,0 +1,101 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// PlayJ audio header / CDS entry header (V2)
/// </summary>
public sealed class AudioHeaderV2 : AudioHeader
{
/// <summary>
/// Unknown (Always 0x00000001)
/// </summary>
public uint Unknown1;
/// <summary>
/// Unknown (Always 0x00000001)
/// </summary>
public uint Unknown2;
/// <summary>
/// Unknown (Always 0x00000000)
/// </summary>
public uint Unknown3;
/// <summary>
/// Unknown (Always 0x00000003)
/// </summary>
public uint Unknown4;
/// <summary>
/// Unknown (Always 0x00000001)
/// </summary>
public uint Unknown5;
/// <summary>
/// Unknown (Always 0x00000000)
/// </summary>
public uint Unknown6;
/// <summary>
/// Offset to unknown block 1, relative to the track ID
/// </summary>
public uint UnknownOffset1;
/// <summary>
/// Unknown
/// </summary>
public uint Unknown7;
/// <summary>
/// Unknown (Always 0x00000004)
/// </summary>
public uint Unknown8;
/// <summary>
/// Unknown (Always 0x00000002)
/// </summary>
public uint Unknown9;
/// <summary>
/// Offset to unknown block 1, relative to the track ID
/// </summary>
/// <remarks>Always identical to <see cref="UnknownOffset1"/>?</remarks>
public uint UnknownOffset2;
/// <summary>
/// Unknown
/// </summary>
public uint Unknown10;
/// <summary>
/// Unknown (Always 0x00000000)
/// </summary>
public uint Unknown11;
/// <summary>
/// Unknown (Always 0x00000007)
/// </summary>
public uint Unknown12;
/// <summary>
/// Download track ID
/// </summary>
/// <remarks>0xFFFFFFFF if unset</remarks>
public uint TrackID;
/// <summary>
/// Track year -- UNCONFIRMED
/// </summary>
/// <remarks>0xFFFFFFFF if unset</remarks>
public uint Year;
/// <summary>
/// Track number
/// </summary>
public uint TrackNumber;
/// <summary>
/// Unknown
/// </summary>
public uint Unknown13;
}
}

View File

@@ -142,35 +142,5 @@ namespace BurnOutSharp.Models.PlayJ
/// </summary>
/// <remarks>Optional field only in some samples</remarks>
public string Comments;
#region V2 Notes
// Unknown V2 data block
// ---------------------------
// 0x08 0x00000001 Unknown [Common]
// 0x0C 0x00000001 Unknown [Common]
// 0x10 0x00000000 Unknown [Common]
// 0x14 0x00000003 Unknown [Common]
// 0x18 0x00000001 Unknown [Common]
// 0x1C 0x00000000 Unknown [Common]
// 0x20 0x00000066 Unknown [Varies]
// 0x24 0xF02F4372 Unknown [Varies]
// 0x28 0x00000004 Unknown [Common]
// 0x2C 0x00000002 Unknown [Common]
// 0x30 0x00000066 Unknown [Varies]
// 0x34 0x00005933 Unknown [Varies]
// 0x38 0xB462688A Unknown [Varies]
// 0x3C 0x00000005 Unknown [Common]
// 0x40 0x00000009 Unknown [Common]
// 0x44 0x00005999 Unknown [Varies]
// 0x48 0x0032FF38 Unknown [Varies]
// 0x4C 0x00000000 Unknown [Common]
// 0x50 0x00000007 Unknown [Common]
// 0x54 0x0001897D Track ID
// 0x58 0xFFFFFFFF Unknown (Year?)
// 0x5C 0x00000005 Track Number
// 0x60 0x00033068 Unknown [Varies]
#endregion
}
}