Implement IRD serializers

This commit is contained in:
Matt Nadareski
2023-10-25 14:43:43 -04:00
parent 3b90af7b3a
commit 2ca7326074
5 changed files with 333 additions and 0 deletions

28
Bytes/IRD.Deserializer.cs Normal file
View File

@@ -0,0 +1,28 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{
public partial class IRD : IByteSerializer<Models.IRD.IRD>
{
/// <inheritdoc/>
#if NET48
public Models.IRD.IRD Deserialize(byte[] data, int offset)
#else
public Models.IRD.IRD? Deserialize(byte[]? data, int offset)
#endif
{
// 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 new Streams.IRD().Deserialize(dataStream);
}
}
}

20
Files/IRD.Deserializer.cs Normal file
View File

@@ -0,0 +1,20 @@
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
public partial class IRD : IFileSerializer<Models.IRD.IRD>
{
/// <inheritdoc/>
#if NET48
public Models.IRD.IRD Deserialize(string path)
#else
public Models.IRD.IRD? Deserialize(string? path)
#endif
{
using (var stream = PathProcessor.OpenStream(path))
{
return new Streams.IRD().Deserialize(stream);
}
}
}
}

30
Files/IRD.Serializer.cs Normal file
View File

@@ -0,0 +1,30 @@
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
public partial class IRD : IFileSerializer<Models.IRD.IRD>
{
/// <inheritdoc/>
#if NET48
public bool Serialize(Models.IRD.IRD obj, string path)
#else
public bool Serialize(Models.IRD.IRD? obj, string? path)
#endif
{
if (string.IsNullOrWhiteSpace(path))
return false;
using (var stream = new Streams.IRD().Serialize(obj))
{
if (stream == null)
return false;
using (var fs = System.IO.File.OpenWrite(path))
{
stream.CopyTo(fs);
return true;
}
}
}
}
}

119
Streams/IRD.Deserializer.cs Normal file
View File

@@ -0,0 +1,119 @@
using System;
using System.IO;
using System.Text;
using SabreTools.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{
public partial class IRD : IStreamSerializer<Models.IRD.IRD>
{
/// <inheritdoc/>
#if NET48
public Models.IRD.IRD Deserialize(Stream data)
#else
public Models.IRD.IRD? Deserialize(Stream? data)
#endif
{
// 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 media key block to fill
var ird = new Models.IRD.IRD();
ird.Magic = data.ReadBytes(4);
if (ird.Magic == null)
return null;
string magic = Encoding.ASCII.GetString(ird.Magic);
if (magic != "3IRD")
return null;
ird.Version = data.ReadByteValue();
if (ird.Version < 6)
return null;
var titleId = data.ReadBytes(9);
if (titleId == null)
return null;
ird.TitleID = Encoding.ASCII.GetString(titleId);
ird.TitleLength = data.ReadByteValue();
var title = data.ReadBytes(ird.TitleLength);
if (title == null)
return null;
ird.Title = Encoding.ASCII.GetString(title);
var systemVersion = data.ReadBytes(4);
if (systemVersion == null)
return null;
ird.SystemVersion = Encoding.ASCII.GetString(systemVersion);
var gameVersion = data.ReadBytes(5);
if (gameVersion == null)
return null;
ird.GameVersion = Encoding.ASCII.GetString(gameVersion);
var appVersion = data.ReadBytes(5);
if (appVersion == null)
return null;
ird.AppVersion = Encoding.ASCII.GetString(appVersion);
if (ird.Version == 7)
ird.UID = data.ReadUInt32();
ird.HeaderLength = data.ReadByteValue();
ird.Header = data.ReadBytes((int)ird.HeaderLength);
ird.FooterLength = data.ReadByteValue();
ird.Footer = data.ReadBytes((int)ird.FooterLength);
ird.RegionCount = data.ReadByteValue();
ird.RegionHashes = new byte[ird.RegionCount][];
for (int i = 0; i < ird.RegionCount; i++)
{
ird.RegionHashes[i] = data.ReadBytes(16) ?? Array.Empty<byte>();
}
ird.FileCount = data.ReadByteValue();
ird.FileKeys = new ulong[ird.FileCount];
ird.FileHashes = new byte[ird.FileCount][];
for (int i = 0; i < ird.FileCount; i++)
{
ird.FileKeys[i] = data.ReadUInt64();
ird.FileHashes[i] = data.ReadBytes(16) ?? Array.Empty<byte>();
}
ird.ExtraConfig = data.ReadUInt16();
ird.Attachments = data.ReadUInt16();
if (ird.Version >= 9)
ird.PIC = data.ReadBytes(115);
ird.Data1Key = data.ReadBytes(16);
ird.Data2Key = data.ReadBytes(16);
if (ird.Version < 9)
ird.PIC = data.ReadBytes(115);
if (ird.Version > 7)
ird.UID = data.ReadUInt32();
ird.CRC = data.ReadUInt32();
return ird;
}
}
}

136
Streams/IRD.Serializer.cs Normal file
View File

@@ -0,0 +1,136 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{
public partial class IRD : IStreamSerializer<Models.IRD.IRD>
{
/// <inheritdoc/>
#if NET48
public Stream Serialize(Models.IRD.IRD obj)
#else
public Stream? Serialize(Models.IRD.IRD? obj)
#endif
{
// If the data is invalid
if (obj?.Magic == 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 == null || obj.TitleID.Length != 9)
return null;
if (obj.Title == null || obj.Title.Length != obj.TitleLength)
return null;
if (obj.SystemVersion == null || obj.SystemVersion.Length != 4)
return null;
if (obj.GameVersion == null || obj.GameVersion.Length != 5)
return null;
if (obj.AppVersion == null || obj.AppVersion.Length != 5)
return null;
if (obj.Header == null || obj.Header.Length != obj.HeaderLength)
return null;
if (obj.Footer == null || obj.Footer.Length != obj.FooterLength)
return null;
if (obj.RegionHashes == null || obj.RegionHashes.Length != obj.RegionCount || obj.RegionHashes.Any(h => h == null || h.Length != 16))
return null;
if (obj.FileKeys == null || obj.FileKeys.Length != obj.FileCount)
return null;
if (obj.FileHashes == null || obj.FileHashes.Length != obj.FileCount || obj.FileHashes.Any(h => h == null || h.Length != 16))
return null;
if (obj.PIC == null || obj.PIC.Length != 115)
return null;
if (obj.Data1Key == null || obj.Data1Key.Length != 16)
return null;
if (obj.Data2Key == null || 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;
}
}
}