mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-02-06 05:35:35 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0790fc93b6 | ||
|
|
7f6c128521 | ||
|
|
87df6b3ebd | ||
|
|
2ca7326074 | ||
|
|
3b90af7b3a | ||
|
|
6eda2f2541 | ||
|
|
defe1c53aa | ||
|
|
e5fe0a71ef | ||
|
|
83450f693f | ||
|
|
1f70e1f544 | ||
|
|
4bfc83d5d4 | ||
|
|
7364661900 | ||
|
|
1cafc4079d | ||
|
|
0d62cbd1e9 | ||
|
|
bf753262a5 | ||
|
|
5510b5d19d |
28
Bytes/IRD.Deserializer.cs
Normal file
28
Bytes/IRD.Deserializer.cs
Normal 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
20
Files/IRD.Deserializer.cs
Normal 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
30
Files/IRD.Serializer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Files
|
||||
{
|
||||
public partial class XMID : IFileSerializer<Models.Xbox.XMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>This treats the input path like a parseable string</remarks>
|
||||
#if NET48
|
||||
public Models.Xbox.XMID Deserialize(string path)
|
||||
#else
|
||||
public Models.Xbox.XMID? Deserialize(string? path)
|
||||
#endif
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
string xmid = path.TrimEnd('\0');
|
||||
if (string.IsNullOrWhiteSpace(xmid))
|
||||
return null;
|
||||
|
||||
return ParseXMID(xmid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD2/3 XMID string
|
||||
/// </summary>
|
||||
/// <param name="xmidString">XMID string to attempt to parse</param>
|
||||
/// <returns>Filled XMID on success, null on error</returns>
|
||||
#if NET48
|
||||
private static Models.Xbox.XMID ParseXMID(string xmidString)
|
||||
#else
|
||||
private static Models.Xbox.XMID? ParseXMID(string? xmidString)
|
||||
#endif
|
||||
{
|
||||
if (xmidString == null || xmidString.Length != 8)
|
||||
return null;
|
||||
|
||||
var xmid = new Models.Xbox.XMID();
|
||||
|
||||
xmid.PublisherIdentifier = xmidString.Substring(0, 2);
|
||||
if (string.IsNullOrEmpty(PublisherName(xmid)))
|
||||
return null;
|
||||
|
||||
xmid.GameID = xmidString.Substring(2, 3);
|
||||
xmid.VersionNumber = xmidString.Substring(5, 2);
|
||||
xmid.RegionIdentifier = xmidString[7];
|
||||
if (InternalRegion(xmid) == null)
|
||||
return null;
|
||||
|
||||
return xmid;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable name derived from the publisher identifier
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static string PublisherName(Models.Xbox.XMID xmid) => GetPublisher(xmid.PublisherIdentifier);
|
||||
#else
|
||||
public static string? PublisherName(Models.Xbox.XMID xmid) => GetPublisher(xmid.PublisherIdentifier);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Internally represented region
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static string InternalRegion(Models.Xbox.XMID xmid) => GetRegion(xmid.RegionIdentifier);
|
||||
#else
|
||||
public static string? InternalRegion(Models.Xbox.XMID xmid) => GetRegion(xmid.RegionIdentifier);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get the full name of the publisher from the 2-character identifier
|
||||
/// </summary>
|
||||
/// <param name="publisherIdentifier">Case-sensitive 2-character identifier</param>
|
||||
/// <returns>Publisher name, if possible</returns>
|
||||
/// <see cref="https://xboxdevwiki.net/Xbe#Title_ID"/>
|
||||
#if NET48
|
||||
private static string GetPublisher(string publisherIdentifier)
|
||||
#else
|
||||
private static string? GetPublisher(string? publisherIdentifier)
|
||||
#endif
|
||||
{
|
||||
switch (publisherIdentifier)
|
||||
{
|
||||
case "AC": return "Acclaim Entertainment";
|
||||
case "AH": return "ARUSH Entertainment";
|
||||
case "AQ": return "Aqua System";
|
||||
case "AS": return "ASK";
|
||||
case "AT": return "Atlus";
|
||||
case "AV": return "Activision";
|
||||
case "AY": return "Aspyr Media";
|
||||
case "BA": return "Bandai";
|
||||
case "BL": return "Black Box";
|
||||
case "BM": return "BAM! Entertainment";
|
||||
case "BR": return "Broccoli Co.";
|
||||
case "BS": return "Bethesda Softworks";
|
||||
case "BU": return "Bunkasha Co.";
|
||||
case "BV": return "Buena Vista Games";
|
||||
case "BW": return "BBC Multimedia";
|
||||
case "BZ": return "Blizzard";
|
||||
case "CC": return "Capcom";
|
||||
case "CK": return "Kemco Corporation"; // TODO: Confirm
|
||||
case "CM": return "Codemasters";
|
||||
case "CV": return "Crave Entertainment";
|
||||
case "DC": return "DreamCatcher Interactive";
|
||||
case "DX": return "Davilex";
|
||||
case "EA": return "Electronic Arts (EA)";
|
||||
case "EC": return "Encore inc";
|
||||
case "EL": return "Enlight Software";
|
||||
case "EM": return "Empire Interactive";
|
||||
case "ES": return "Eidos Interactive";
|
||||
case "FI": return "Fox Interactive";
|
||||
case "FS": return "From Software";
|
||||
case "GE": return "Genki Co.";
|
||||
case "GV": return "Groove Games";
|
||||
case "HE": return "Tru Blu (Entertainment division of Home Entertainment Suppliers)";
|
||||
case "HP": return "Hip games";
|
||||
case "HU": return "Hudson Soft";
|
||||
case "HW": return "Highwaystar";
|
||||
case "IA": return "Mad Catz Interactive";
|
||||
case "IF": return "Idea Factory";
|
||||
case "IG": return "Infogrames";
|
||||
case "IL": return "Interlex Corporation";
|
||||
case "IM": return "Imagine Media";
|
||||
case "IO": return "Ignition Entertainment";
|
||||
case "IP": return "Interplay Entertainment";
|
||||
case "IX": return "InXile Entertainment"; // TODO: Confirm
|
||||
case "JA": return "Jaleco";
|
||||
case "JW": return "JoWooD";
|
||||
case "KB": return "Kemco"; // TODO: Confirm
|
||||
case "KI": return "Kids Station Inc."; // TODO: Confirm
|
||||
case "KN": return "Konami";
|
||||
case "KO": return "KOEI";
|
||||
case "KU": return "Kobi and / or GAE (formerly Global A Entertainment)"; // TODO: Confirm
|
||||
case "LA": return "LucasArts";
|
||||
case "LS": return "Black Bean Games (publishing arm of Leader S.p.A.)";
|
||||
case "MD": return "Metro3D";
|
||||
case "ME": return "Medix";
|
||||
case "MI": return "Microïds";
|
||||
case "MJ": return "Majesco Entertainment";
|
||||
case "MM": return "Myelin Media";
|
||||
case "MP": return "MediaQuest"; // TODO: Confirm
|
||||
case "MS": return "Microsoft Game Studios";
|
||||
case "MW": return "Midway Games";
|
||||
case "MX": return "Empire Interactive"; // TODO: Confirm
|
||||
case "NK": return "NewKidCo";
|
||||
case "NL": return "NovaLogic";
|
||||
case "NM": return "Namco";
|
||||
case "OX": return "Oxygen Interactive";
|
||||
case "PC": return "Playlogic Entertainment";
|
||||
case "PL": return "Phantagram Co., Ltd.";
|
||||
case "RA": return "Rage";
|
||||
case "SA": return "Sammy";
|
||||
case "SC": return "SCi Games";
|
||||
case "SE": return "SEGA";
|
||||
case "SN": return "SNK";
|
||||
case "SS": return "Simon & Schuster";
|
||||
case "SU": return "Success Corporation";
|
||||
case "SW": return "Swing! Deutschland";
|
||||
case "TA": return "Takara";
|
||||
case "TC": return "Tecmo";
|
||||
case "TD": return "The 3DO Company (or just 3DO)";
|
||||
case "TK": return "Takuyo";
|
||||
case "TM": return "TDK Mediactive";
|
||||
case "TQ": return "THQ";
|
||||
case "TS": return "Titus Interactive";
|
||||
case "TT": return "Take-Two Interactive Software";
|
||||
case "US": return "Ubisoft";
|
||||
case "VC": return "Victor Interactive Software";
|
||||
case "VN": return "Vivendi Universal (just took Interplays publishing rights)"; // TODO: Confirm
|
||||
case "VU": return "Vivendi Universal Games";
|
||||
case "VV": return "Vivendi Universal Games"; // TODO: Confirm
|
||||
case "WE": return "Wanadoo Edition";
|
||||
case "WR": return "Warner Bros. Interactive Entertainment"; // TODO: Confirm
|
||||
case "XI": return "XPEC Entertainment and Idea Factory";
|
||||
case "XK": return "Xbox kiosk disk?"; // TODO: Confirm
|
||||
case "XL": return "Xbox special bundled or live demo disk?"; // TODO: Confirm
|
||||
case "XM": return "Evolved Games"; // TODO: Confirm
|
||||
case "XP": return "XPEC Entertainment";
|
||||
case "XR": return "Panorama";
|
||||
case "YB": return "YBM Sisa (South-Korea)";
|
||||
case "ZD": return "Zushi Games (formerly Zoo Digital Publishing)";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the XGD serial character
|
||||
/// </summary>
|
||||
/// <param name="region">Character denoting the region</param>
|
||||
/// <returns>Region, if possible</returns>
|
||||
#if NET48
|
||||
private static string GetRegion(char region)
|
||||
#else
|
||||
private static string? GetRegion(char region)
|
||||
#endif
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W': return "World";
|
||||
case 'A': return "USA";
|
||||
case 'J': return "Japan / Asia";
|
||||
case 'E': return "Europe";
|
||||
case 'K': return "USA / Japan";
|
||||
case 'L': return "USA / Europe";
|
||||
case 'H': return "Japan / Europe";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Files
|
||||
{
|
||||
public partial class XMID : IFileSerializer<Models.Xbox.XMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public bool Serialize(Models.Xbox.XMID obj, string path) => throw new NotImplementedException();
|
||||
#else
|
||||
public bool Serialize(Models.Xbox.XMID? obj, string? path) => throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Files
|
||||
{
|
||||
public partial class XeMID : IFileSerializer<Models.Xbox.XeMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>This treats the input path like a parseable string</remarks>
|
||||
#if NET48
|
||||
public Models.Xbox.XeMID Deserialize(string path)
|
||||
#else
|
||||
public Models.Xbox.XeMID? Deserialize(string? path)
|
||||
#endif
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
string xemid = path.TrimEnd('\0');
|
||||
if (string.IsNullOrWhiteSpace(xemid))
|
||||
return null;
|
||||
|
||||
return ParseXeMID(xemid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD2/3 XeMID string
|
||||
/// </summary>
|
||||
/// <param name="xemidString">XeMID string to attempt to parse</param>
|
||||
/// <returns>Filled XeMID on success, null on error</returns>
|
||||
#if NET48
|
||||
private static Models.Xbox.XeMID ParseXeMID(string xemidString)
|
||||
#else
|
||||
private static Models.Xbox.XeMID? ParseXeMID(string? xemidString)
|
||||
#endif
|
||||
{
|
||||
if (xemidString == null
|
||||
|| (xemidString.Length != 13 && xemidString.Length != 14
|
||||
&& xemidString.Length != 21 && xemidString.Length != 22))
|
||||
return null;
|
||||
|
||||
var xemid = new Models.Xbox.XeMID();
|
||||
|
||||
xemid.PublisherIdentifier = xemidString.Substring(0, 2);
|
||||
if (string.IsNullOrEmpty(PublisherName(xemid)))
|
||||
return null;
|
||||
|
||||
xemid.PlatformIdentifier = xemidString[2];
|
||||
if (xemid.PlatformIdentifier != '2')
|
||||
return null;
|
||||
|
||||
xemid.GameID = xemidString.Substring(3, 3);
|
||||
xemid.SKU = xemidString.Substring(6, 2);
|
||||
xemid.RegionIdentifier = xemidString[8];
|
||||
if (InternalRegion(xemid) == null)
|
||||
return null;
|
||||
|
||||
if (xemidString.Length == 13 || xemidString.Length == 21)
|
||||
{
|
||||
xemid.BaseVersion = xemidString.Substring(9, 1);
|
||||
xemid.MediaSubtypeIdentifier = xemidString[10];
|
||||
if (string.IsNullOrEmpty(MediaSubtype(xemid)))
|
||||
return null;
|
||||
|
||||
xemid.DiscNumberIdentifier = xemidString.Substring(11, 2);
|
||||
}
|
||||
else if (xemidString.Length == 14 || xemidString.Length == 22)
|
||||
{
|
||||
xemid.BaseVersion = xemidString.Substring(9, 2);
|
||||
xemid.MediaSubtypeIdentifier = xemidString[11];
|
||||
if (string.IsNullOrEmpty(MediaSubtype(xemid)))
|
||||
return null;
|
||||
|
||||
xemid.DiscNumberIdentifier = xemidString.Substring(12, 2);
|
||||
}
|
||||
|
||||
if (xemidString.Length == 21)
|
||||
xemid.CertificationSubmissionIdentifier = xemidString.Substring(13);
|
||||
else if (xemidString.Length == 22)
|
||||
xemid.CertificationSubmissionIdentifier = xemidString.Substring(14);
|
||||
|
||||
return xemid;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable name derived from the publisher identifier
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static string PublisherName(Models.Xbox.XeMID xemid) => GetPublisher(xemid.PublisherIdentifier);
|
||||
#else
|
||||
public static string? PublisherName(Models.Xbox.XeMID xemid) => GetPublisher(xemid.PublisherIdentifier);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Internally represented region
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static string InternalRegion(Models.Xbox.XeMID xemid) => GetRegion(xemid.RegionIdentifier);
|
||||
#else
|
||||
public static string? InternalRegion(Models.Xbox.XeMID xemid) => GetRegion(xemid.RegionIdentifier);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable subtype derived from the media identifier
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static string MediaSubtype(Models.Xbox.XeMID xemid) => GetMediaSubtype(xemid.MediaSubtypeIdentifier);
|
||||
#else
|
||||
public static string? MediaSubtype(Models.Xbox.XeMID xemid) => GetMediaSubtype(xemid.MediaSubtypeIdentifier);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Determine the XGD type based on the XGD2/3 media type identifier character
|
||||
/// </summary>
|
||||
/// <param name="mediaTypeIdentifier">Character denoting the media type</param>
|
||||
/// <returns>Media subtype as a string, if possible</returns>
|
||||
#if NET48
|
||||
private static string GetMediaSubtype(char mediaTypeIdentifier)
|
||||
#else
|
||||
private static string? GetMediaSubtype(char mediaTypeIdentifier)
|
||||
#endif
|
||||
{
|
||||
switch (mediaTypeIdentifier)
|
||||
{
|
||||
case 'F': return "XGD3";
|
||||
case 'X': return "XGD2";
|
||||
case 'Z': return "Games on Demand / Marketplace Demo";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the full name of the publisher from the 2-character identifier
|
||||
/// </summary>
|
||||
/// <param name="publisherIdentifier">Case-sensitive 2-character identifier</param>
|
||||
/// <returns>Publisher name, if possible</returns>
|
||||
/// <see cref="https://xboxdevwiki.net/Xbe#Title_ID"/>
|
||||
#if NET48
|
||||
private static string GetPublisher(string publisherIdentifier)
|
||||
#else
|
||||
private static string? GetPublisher(string? publisherIdentifier)
|
||||
#endif
|
||||
{
|
||||
switch (publisherIdentifier)
|
||||
{
|
||||
case "AC": return "Acclaim Entertainment";
|
||||
case "AH": return "ARUSH Entertainment";
|
||||
case "AQ": return "Aqua System";
|
||||
case "AS": return "ASK";
|
||||
case "AT": return "Atlus";
|
||||
case "AV": return "Activision";
|
||||
case "AY": return "Aspyr Media";
|
||||
case "BA": return "Bandai";
|
||||
case "BL": return "Black Box";
|
||||
case "BM": return "BAM! Entertainment";
|
||||
case "BR": return "Broccoli Co.";
|
||||
case "BS": return "Bethesda Softworks";
|
||||
case "BU": return "Bunkasha Co.";
|
||||
case "BV": return "Buena Vista Games";
|
||||
case "BW": return "BBC Multimedia";
|
||||
case "BZ": return "Blizzard";
|
||||
case "CC": return "Capcom";
|
||||
case "CK": return "Kemco Corporation"; // TODO: Confirm
|
||||
case "CM": return "Codemasters";
|
||||
case "CV": return "Crave Entertainment";
|
||||
case "DC": return "DreamCatcher Interactive";
|
||||
case "DX": return "Davilex";
|
||||
case "EA": return "Electronic Arts (EA)";
|
||||
case "EC": return "Encore inc";
|
||||
case "EL": return "Enlight Software";
|
||||
case "EM": return "Empire Interactive";
|
||||
case "ES": return "Eidos Interactive";
|
||||
case "FI": return "Fox Interactive";
|
||||
case "FS": return "From Software";
|
||||
case "GE": return "Genki Co.";
|
||||
case "GV": return "Groove Games";
|
||||
case "HE": return "Tru Blu (Entertainment division of Home Entertainment Suppliers)";
|
||||
case "HP": return "Hip games";
|
||||
case "HU": return "Hudson Soft";
|
||||
case "HW": return "Highwaystar";
|
||||
case "IA": return "Mad Catz Interactive";
|
||||
case "IF": return "Idea Factory";
|
||||
case "IG": return "Infogrames";
|
||||
case "IL": return "Interlex Corporation";
|
||||
case "IM": return "Imagine Media";
|
||||
case "IO": return "Ignition Entertainment";
|
||||
case "IP": return "Interplay Entertainment";
|
||||
case "IX": return "InXile Entertainment"; // TODO: Confirm
|
||||
case "JA": return "Jaleco";
|
||||
case "JW": return "JoWooD";
|
||||
case "KB": return "Kemco"; // TODO: Confirm
|
||||
case "KI": return "Kids Station Inc."; // TODO: Confirm
|
||||
case "KN": return "Konami";
|
||||
case "KO": return "KOEI";
|
||||
case "KU": return "Kobi and / or GAE (formerly Global A Entertainment)"; // TODO: Confirm
|
||||
case "LA": return "LucasArts";
|
||||
case "LS": return "Black Bean Games (publishing arm of Leader S.p.A.)";
|
||||
case "MD": return "Metro3D";
|
||||
case "ME": return "Medix";
|
||||
case "MI": return "Microïds";
|
||||
case "MJ": return "Majesco Entertainment";
|
||||
case "MM": return "Myelin Media";
|
||||
case "MP": return "MediaQuest"; // TODO: Confirm
|
||||
case "MS": return "Microsoft Game Studios";
|
||||
case "MW": return "Midway Games";
|
||||
case "MX": return "Empire Interactive"; // TODO: Confirm
|
||||
case "NK": return "NewKidCo";
|
||||
case "NL": return "NovaLogic";
|
||||
case "NM": return "Namco";
|
||||
case "OX": return "Oxygen Interactive";
|
||||
case "PC": return "Playlogic Entertainment";
|
||||
case "PL": return "Phantagram Co., Ltd.";
|
||||
case "RA": return "Rage";
|
||||
case "SA": return "Sammy";
|
||||
case "SC": return "SCi Games";
|
||||
case "SE": return "SEGA";
|
||||
case "SN": return "SNK";
|
||||
case "SS": return "Simon & Schuster";
|
||||
case "SU": return "Success Corporation";
|
||||
case "SW": return "Swing! Deutschland";
|
||||
case "TA": return "Takara";
|
||||
case "TC": return "Tecmo";
|
||||
case "TD": return "The 3DO Company (or just 3DO)";
|
||||
case "TK": return "Takuyo";
|
||||
case "TM": return "TDK Mediactive";
|
||||
case "TQ": return "THQ";
|
||||
case "TS": return "Titus Interactive";
|
||||
case "TT": return "Take-Two Interactive Software";
|
||||
case "US": return "Ubisoft";
|
||||
case "VC": return "Victor Interactive Software";
|
||||
case "VN": return "Vivendi Universal (just took Interplays publishing rights)"; // TODO: Confirm
|
||||
case "VU": return "Vivendi Universal Games";
|
||||
case "VV": return "Vivendi Universal Games"; // TODO: Confirm
|
||||
case "WE": return "Wanadoo Edition";
|
||||
case "WR": return "Warner Bros. Interactive Entertainment"; // TODO: Confirm
|
||||
case "XI": return "XPEC Entertainment and Idea Factory";
|
||||
case "XK": return "Xbox kiosk disk?"; // TODO: Confirm
|
||||
case "XL": return "Xbox special bundled or live demo disk?"; // TODO: Confirm
|
||||
case "XM": return "Evolved Games"; // TODO: Confirm
|
||||
case "XP": return "XPEC Entertainment";
|
||||
case "XR": return "Panorama";
|
||||
case "YB": return "YBM Sisa (South-Korea)";
|
||||
case "ZD": return "Zushi Games (formerly Zoo Digital Publishing)";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the region based on the XGD serial character
|
||||
/// </summary>
|
||||
/// <param name="region">Character denoting the region</param>
|
||||
/// <returns>Region, if possible</returns>
|
||||
#if NET48
|
||||
private static string GetRegion(char region)
|
||||
#else
|
||||
private static string? GetRegion(char region)
|
||||
#endif
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case 'W': return "World";
|
||||
case 'A': return "USA";
|
||||
case 'J': return "Japan / Asia";
|
||||
case 'E': return "Europe";
|
||||
case 'K': return "USA / Japan";
|
||||
case 'L': return "USA / Europe";
|
||||
case 'H': return "Japan / Europe";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Files
|
||||
{
|
||||
public partial class XeMID : IFileSerializer<Models.Xbox.XeMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public bool Serialize(Models.Xbox.XeMID obj, string path) => throw new NotImplementedException();
|
||||
#else
|
||||
public bool Serialize(Models.Xbox.XeMID? obj, string? path) => throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace SabreTools.Serialization.Interfaces
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Sserialize a <typeparamref name="T"/> into a file
|
||||
/// Serialize a <typeparamref name="T"/> into a file
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
|
||||
32
Interfaces/IStringSerializer.cs
Normal file
32
Interfaces/IStringSerializer.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace SabreTools.Serialization.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how to serialize to and from strings
|
||||
/// </summary>
|
||||
public interface IStringSerializer<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Deserialize a string into <typeparamref name="T"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to deserialize to</typeparam>
|
||||
/// <param name="str">String to deserialize from</param>
|
||||
/// <returns>Filled object on success, null on error</returns>
|
||||
#if NET48
|
||||
T Deserialize(string str);
|
||||
#else
|
||||
T? Deserialize(string? str);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Serialize a <typeparamref name="T"/> into a string
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object to serialize from</typeparam>
|
||||
/// <param name="obj">Data to serialize</param>
|
||||
/// <returns>Filled string on successful serialization, null otherwise</returns>
|
||||
#if NET48
|
||||
string Serialize(T obj);
|
||||
#else
|
||||
string? Serialize(T? obj);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,10 @@ This namespace comprises of serializers and deserializers that can convert to an
|
||||
|
||||
This namespace comprises of serializers and deserializers that can convert to and from any type of stream. Most of the serializers are symmetric, but this is not guaranteed. Unimplemented methods will throw `NotImplementedException`.
|
||||
|
||||
## `SabreTools.Serialization.Strings`
|
||||
|
||||
This namespace comprises of serializers and deserializers that can convert to and from strings. Most of the serializers are symmetric, but this is not guaranteed. Unimplemented methods will throw `NotImplementedException`.
|
||||
|
||||
## `SabreTools.Serialization.Wrappers`
|
||||
|
||||
This namespace comrpises of wrapping classes that include keeping a reference to the source of each serializable model. Some of the wrappers may also include what are referred to as "extension properties", which are generated properties derived from either parts of the model or the underlying source.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net48;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Version>1.1.4</Version>
|
||||
<Version>1.1.7</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<!-- Package Properties -->
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.IO" Version="1.1.1" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.1.2" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.1.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
119
Streams/IRD.Deserializer.cs
Normal file
119
Streams/IRD.Deserializer.cs
Normal 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
136
Streams/IRD.Serializer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,6 +171,7 @@ namespace SabreTools.Serialization.Streams
|
||||
{
|
||||
case DiscTypeIdentifierROM:
|
||||
case DiscTypeIdentifierROMUltra:
|
||||
case DiscTypeIdentifierXGD4:
|
||||
body.FormatDependentContents = data.ReadBytes(52);
|
||||
break;
|
||||
case DiscTypeIdentifierReWritable:
|
||||
|
||||
48
Strings/XMID.Deserializer.cs
Normal file
48
Strings/XMID.Deserializer.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Strings
|
||||
{
|
||||
public partial class XMID : IStringSerializer<Models.Xbox.XMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public Models.Xbox.XMID Deserialize(string path)
|
||||
#else
|
||||
public Models.Xbox.XMID? Deserialize(string? path)
|
||||
#endif
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
string xmid = path.TrimEnd('\0');
|
||||
if (string.IsNullOrWhiteSpace(xmid))
|
||||
return null;
|
||||
|
||||
return ParseXMID(xmid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD2/3 XMID string
|
||||
/// </summary>
|
||||
/// <param name="xmidString">XMID string to attempt to parse</param>
|
||||
/// <returns>Filled XMID on success, null on error</returns>
|
||||
#if NET48
|
||||
private static Models.Xbox.XMID ParseXMID(string xmidString)
|
||||
#else
|
||||
private static Models.Xbox.XMID? ParseXMID(string? xmidString)
|
||||
#endif
|
||||
{
|
||||
if (xmidString == null || xmidString.Length != 8)
|
||||
return null;
|
||||
|
||||
var xmid = new Models.Xbox.XMID();
|
||||
|
||||
xmid.PublisherIdentifier = xmidString.Substring(0, 2);
|
||||
xmid.GameID = xmidString.Substring(2, 3);
|
||||
xmid.VersionNumber = xmidString.Substring(5, 2);
|
||||
xmid.RegionIdentifier = xmidString[7];
|
||||
|
||||
return xmid;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Strings/XMID.Serializer.cs
Normal file
28
Strings/XMID.Serializer.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Text;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Strings
|
||||
{
|
||||
public partial class XMID : IStringSerializer<Models.Xbox.XMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Serialize(Models.Xbox.XMID obj)
|
||||
#else
|
||||
public string? Serialize(Models.Xbox.XMID? obj)
|
||||
#endif
|
||||
{
|
||||
if (obj == null)
|
||||
return null;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append(obj.PublisherIdentifier);
|
||||
sb.Append(obj.GameID);
|
||||
sb.Append(obj.VersionNumber);
|
||||
sb.Append(obj.RegionIdentifier);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Strings/XeMID.Deserializer.cs
Normal file
72
Strings/XeMID.Deserializer.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Strings
|
||||
{
|
||||
public partial class XeMID : IStringSerializer<Models.Xbox.XeMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public Models.Xbox.XeMID Deserialize(string path)
|
||||
#else
|
||||
public Models.Xbox.XeMID? Deserialize(string? path)
|
||||
#endif
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
string xemid = path.TrimEnd('\0');
|
||||
if (string.IsNullOrWhiteSpace(xemid))
|
||||
return null;
|
||||
|
||||
return ParseXeMID(xemid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an XGD2/3 XeMID string
|
||||
/// </summary>
|
||||
/// <param name="xemidString">XeMID string to attempt to parse</param>
|
||||
/// <returns>Filled XeMID on success, null on error</returns>
|
||||
#if NET48
|
||||
private static Models.Xbox.XeMID ParseXeMID(string xemidString)
|
||||
#else
|
||||
private static Models.Xbox.XeMID? ParseXeMID(string? xemidString)
|
||||
#endif
|
||||
{
|
||||
if (xemidString == null)
|
||||
return null;
|
||||
if (!(xemidString.Length == 13 || xemidString.Length == 14 || xemidString.Length == 21 || xemidString.Length == 22))
|
||||
return null;
|
||||
|
||||
var xemid = new Models.Xbox.XeMID();
|
||||
|
||||
xemid.PublisherIdentifier = xemidString.Substring(0, 2);
|
||||
xemid.PlatformIdentifier = xemidString[2];
|
||||
if (xemid.PlatformIdentifier != '2')
|
||||
return null;
|
||||
|
||||
xemid.GameID = xemidString.Substring(3, 3);
|
||||
xemid.SKU = xemidString.Substring(6, 2);
|
||||
xemid.RegionIdentifier = xemidString[8];
|
||||
|
||||
if (xemidString.Length == 13 || xemidString.Length == 21)
|
||||
{
|
||||
xemid.BaseVersion = xemidString.Substring(9, 1);
|
||||
xemid.MediaSubtypeIdentifier = xemidString[10];
|
||||
xemid.DiscNumberIdentifier = xemidString.Substring(11, 2);
|
||||
}
|
||||
else if (xemidString.Length == 14 || xemidString.Length == 22)
|
||||
{
|
||||
xemid.BaseVersion = xemidString.Substring(9, 2);
|
||||
xemid.MediaSubtypeIdentifier = xemidString[11];
|
||||
xemid.DiscNumberIdentifier = xemidString.Substring(12, 2);
|
||||
}
|
||||
|
||||
if (xemidString.Length == 21)
|
||||
xemid.CertificationSubmissionIdentifier = xemidString.Substring(13);
|
||||
else if (xemidString.Length == 22)
|
||||
xemid.CertificationSubmissionIdentifier = xemidString.Substring(14);
|
||||
|
||||
return xemid;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Strings/XeMID.Serializer.cs
Normal file
34
Strings/XeMID.Serializer.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Text;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Strings
|
||||
{
|
||||
public partial class XeMID : IStringSerializer<Models.Xbox.XeMID>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Serialize(Models.Xbox.XeMID obj)
|
||||
#else
|
||||
public string? Serialize(Models.Xbox.XeMID? obj)
|
||||
#endif
|
||||
{
|
||||
if (obj == null)
|
||||
return null;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append(obj.PublisherIdentifier);
|
||||
sb.Append(obj.PlatformIdentifier);
|
||||
sb.Append(obj.GameID);
|
||||
sb.Append(obj.SKU);
|
||||
sb.Append(obj.RegionIdentifier);
|
||||
sb.Append(obj.BaseVersion);
|
||||
sb.Append(obj.MediaSubtypeIdentifier);
|
||||
sb.Append(obj.DiscNumberIdentifier);
|
||||
if (!string.IsNullOrWhiteSpace(obj.CertificationSubmissionIdentifier))
|
||||
sb.Append(obj.CertificationSubmissionIdentifier);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Wrappers/IRD.cs
Normal file
94
Wrappers/IRD.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
public class IRD : WrapperBase<Models.IRD.IRD>
|
||||
{
|
||||
#region Descriptive Properties
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string DescriptionString => "PS3 IRD file";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public IRD(Models.IRD.IRD model, byte[] data, int offset)
|
||||
#else
|
||||
public IRD(Models.IRD.IRD? model, byte[]? data, int offset)
|
||||
#endif
|
||||
: base(model, data, offset)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public IRD(Models.IRD.IRD model, Stream data)
|
||||
#else
|
||||
public IRD(Models.IRD.IRD? model, Stream? data)
|
||||
#endif
|
||||
: base(model, data)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an IRD 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>An IRD wrapper on success, null on failure</returns>
|
||||
#if NET48
|
||||
public static IRD Create(byte[] data, int offset)
|
||||
#else
|
||||
public static IRD? Create(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 use that
|
||||
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return Create(dataStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an IRD from a Stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the archive</param>
|
||||
/// <returns>An IRD wrapper on success, null on failure</returns>
|
||||
#if NET48
|
||||
public static IRD Create(Stream data)
|
||||
#else
|
||||
public static IRD? Create(Stream? data)
|
||||
#endif
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
var ird = new Streams.IRD().Deserialize(data);
|
||||
if (ird == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return new IRD(ird, data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
#if NET48
|
||||
public byte[] ReadFromDataSource(int position, int length)
|
||||
#else
|
||||
protected byte[]? ReadFromDataSource(int position, int length)
|
||||
public byte[]? ReadFromDataSource(int position, int length)
|
||||
#endif
|
||||
{
|
||||
// Validate the data source
|
||||
@@ -262,7 +262,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
#if NET48
|
||||
public List<string> ReadStringsFromDataSource(int position, int length, int charLimit = 5)
|
||||
#else
|
||||
protected List<string>? ReadStringsFromDataSource(int position, int length, int charLimit = 5)
|
||||
public List<string>? ReadStringsFromDataSource(int position, int length, int charLimit = 5)
|
||||
#endif
|
||||
{
|
||||
// Read the data as a byte array first
|
||||
|
||||
119
Wrappers/XMID.cs
Normal file
119
Wrappers/XMID.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using static SabreTools.Models.Xbox.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
public class XMID : WrapperBase<Models.Xbox.XMID>
|
||||
{
|
||||
#region Descriptive Properties
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string DescriptionString => "Xbox Media Identifier";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extension Properties
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable publisher string
|
||||
/// </summary>
|
||||
public string Publisher
|
||||
{
|
||||
get
|
||||
{
|
||||
var publisherIdentifier = this.Model.PublisherIdentifier;
|
||||
if (string.IsNullOrWhiteSpace(publisherIdentifier))
|
||||
return "Unknown";
|
||||
|
||||
if (Publishers.ContainsKey(publisherIdentifier))
|
||||
return Publishers[publisherIdentifier];
|
||||
|
||||
return $"Unknown ({publisherIdentifier})";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable region string
|
||||
/// </summary>
|
||||
public string Region
|
||||
{
|
||||
get
|
||||
{
|
||||
var regionIdentifier = this.Model.RegionIdentifier;
|
||||
if (Regions.ContainsKey(regionIdentifier))
|
||||
return Regions[regionIdentifier];
|
||||
|
||||
return $"Unknown ({regionIdentifier})";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable serial string
|
||||
/// </summary>
|
||||
public string Serial => $"{this.Model.PublisherIdentifier}-{this.Model.GameID}";
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable version string
|
||||
/// </summary>
|
||||
public string Version => $"1.{this.Model.VersionNumber}";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public XMID(Models.Xbox.XMID model, byte[] data, int offset)
|
||||
#else
|
||||
public XMID(Models.Xbox.XMID? model, byte[]? data, int offset)
|
||||
#endif
|
||||
: base(model, data, offset)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public XMID(Models.Xbox.XMID model, Stream data)
|
||||
#else
|
||||
public XMID(Models.Xbox.XMID? model, Stream? data)
|
||||
#endif
|
||||
: base(model, data)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a XMID from a string
|
||||
/// </summary>
|
||||
/// <param name="data">String representing the data</param>
|
||||
/// <returns>A XMID wrapper on success, null on failure</returns>
|
||||
#if NET48
|
||||
public static XMID Create(string data)
|
||||
#else
|
||||
public static XMID? Create(string? data)
|
||||
#endif
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0)
|
||||
return null;
|
||||
|
||||
var binary = new Strings.XMID().Deserialize(data);
|
||||
if (binary == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var ms = new MemoryStream(Encoding.ASCII.GetBytes(data));
|
||||
return new XMID(binary, ms);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
134
Wrappers/XeMID.cs
Normal file
134
Wrappers/XeMID.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using static SabreTools.Models.Xbox.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
public class XeMID : WrapperBase<Models.Xbox.XeMID>
|
||||
{
|
||||
#region Descriptive Properties
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string DescriptionString => "Xbox 360 Media Identifier";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extension Properties
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable media subtype string
|
||||
/// </summary>
|
||||
public string MediaSubtype
|
||||
{
|
||||
get
|
||||
{
|
||||
char mediaSubtype = this.Model.MediaSubtypeIdentifier;
|
||||
if (MediaSubtypes.ContainsKey(mediaSubtype))
|
||||
return MediaSubtypes[mediaSubtype];
|
||||
|
||||
return $"Unknown ({mediaSubtype})";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable publisher string
|
||||
/// </summary>
|
||||
public string Publisher
|
||||
{
|
||||
get
|
||||
{
|
||||
var publisherIdentifier = this.Model.PublisherIdentifier;
|
||||
if (string.IsNullOrWhiteSpace(publisherIdentifier))
|
||||
return "Unknown";
|
||||
|
||||
if (Publishers.ContainsKey(publisherIdentifier))
|
||||
return Publishers[publisherIdentifier];
|
||||
|
||||
return $"Unknown ({publisherIdentifier})";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable region string
|
||||
/// </summary>
|
||||
public string Region
|
||||
{
|
||||
get
|
||||
{
|
||||
var regionIdentifier = this.Model.RegionIdentifier;
|
||||
if (Regions.ContainsKey(regionIdentifier))
|
||||
return Regions[regionIdentifier];
|
||||
|
||||
return $"Unknown ({regionIdentifier})";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable serial string
|
||||
/// </summary>
|
||||
public string Serial => $"{this.Model.PublisherIdentifier}-{this.Model.PlatformIdentifier}{this.Model.GameID}";
|
||||
|
||||
/// <summary>
|
||||
/// Get the human-readable version string
|
||||
/// </summary>
|
||||
public string Version => $"1.{this.Model.SKU}";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public XeMID(Models.Xbox.XeMID model, byte[] data, int offset)
|
||||
#else
|
||||
public XeMID(Models.Xbox.XeMID? model, byte[]? data, int offset)
|
||||
#endif
|
||||
: base(model, data, offset)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public XeMID(Models.Xbox.XeMID model, Stream data)
|
||||
#else
|
||||
public XeMID(Models.Xbox.XeMID? model, Stream? data)
|
||||
#endif
|
||||
: base(model, data)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a XeMID from a string
|
||||
/// </summary>
|
||||
/// <param name="data">String representing the data</param>
|
||||
/// <returns>A XeMID wrapper on success, null on failure</returns>
|
||||
#if NET48
|
||||
public static XeMID Create(string data)
|
||||
#else
|
||||
public static XeMID? Create(string? data)
|
||||
#endif
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0)
|
||||
return null;
|
||||
|
||||
var binary = new Strings.XeMID().Deserialize(data);
|
||||
if (binary == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var ms = new MemoryStream(Encoding.ASCII.GetBytes(data));
|
||||
return new XeMID(binary, ms);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user