Compare commits

..

18 Commits
1.1.0 ... 1.1.6

Author SHA1 Message Date
Matt Nadareski
0d62cbd1e9 Add XGD4 PIC reading 2023-09-28 23:25:25 -04:00
Matt Nadareski
bf753262a5 Update Models version 2023-09-22 16:05:20 -04:00
Matt Nadareski
5510b5d19d Fix inconsistent access issue 2023-09-16 00:55:31 -04:00
Matt Nadareski
d0f0ade757 Bump version 2023-09-16 00:44:35 -04:00
Matt Nadareski
26b03d8256 Make some base functionality public 2023-09-16 00:15:44 -04:00
Matt Nadareski
97f685512a Port Wrapper Functionality
* Add core Wrapper code as a test

* Port all but printing and extraction

This also removes the couple of extensions that were ported

* Update README with subsection

* Add all namespaces to README

* Bump version
2023-09-15 20:31:51 -07:00
Matt Nadareski
0f790869d8 Move things around for nullability checks 2023-09-15 22:48:37 -04:00
Matt Nadareski
608edeb630 Port some extensions from BOS
This omits anything that relies on caching, at the moment. There is no easy way of creating a cache for the required pieces in the static context of the extensions.
2023-09-15 22:46:06 -04:00
Matt Nadareski
56066877b1 Split Extensions into multiple files 2023-09-15 22:38:47 -04:00
Matt Nadareski
a530f271d0 Move interfaces to Interfaces namespace 2023-09-15 22:34:47 -04:00
Matt Nadareski
327fd68f04 Bump version 2023-09-13 15:31:24 -04:00
Matt Nadareski
f12d48861f Port XMID/XeMID serialization from MPF 2023-09-13 15:30:32 -04:00
Matt Nadareski
5a613be9bf Port PIC serialization from MPF 2023-09-13 15:11:44 -04:00
Matt Nadareski
226031f3bd Port cuesheet serialization from MPF 2023-09-13 14:55:52 -04:00
Matt Nadareski
e5edf43624 Update Models to 1.1.2 2023-09-13 13:58:42 -04:00
Matt Nadareski
f2019b7ac4 Bump version 2023-09-11 01:23:34 -04:00
Matt Nadareski
0efb6d08e7 Fix serialization issues 2023-09-11 01:23:29 -04:00
Matt Nadareski
7ed1717f56 Add Nuget link 2023-09-10 23:33:41 -04:00
196 changed files with 7836 additions and 196 deletions

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.AACS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.BDPlus;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.BFPK;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.CFB;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.InstallShieldCabinet;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.LinearExecutable;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.MSDOS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.MicrosoftCabinet;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.MoPaQ;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.N3DS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.NewExecutable;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.Nitro;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.PFF;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.PlayJ;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.PlayJ;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.PortableExecutable;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.Quantum;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Bytes
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Linq;
using SabreTools.Models.ArchiveDotOrg;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,4 +1,5 @@
using System.Linq;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Linq;
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.ClrMamePro;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.ClrMamePro;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.DosCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.DosCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Linq;
using SabreTools.Models.EverdriveSMDB;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.EverdriveSMDB;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.Hashfile;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.Hashfile;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.Listrom;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.Listrom;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.Listxml;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.Listxml;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,6 @@
using System;
using System.Linq;
using SabreTools.Models.Logiqx;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.Logiqx;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,4 +1,5 @@
using System.Linq;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,4 +1,5 @@
using System.Linq;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.OfflineList;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.OfflineList;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.OpenMSX;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.OpenMSX;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Linq;
using SabreTools.Models.RomCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.RomCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using SabreTools.Models.SeparatedValue;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.SeparatedValue;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.SoftwareList;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -1,5 +1,6 @@
using System.Linq;
using SabreTools.Models.SoftwareList;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.CrossModel
{

View File

@@ -0,0 +1,60 @@
using SabreTools.Models.NewExecutable;
namespace SabreTools.Serialization
{
public static partial class Extensions
{
/// <summary>
/// Determine if a resource type information entry is an integer or offset
/// </summary>
/// <param name="entry">Resource type information entry to check</param>
/// <returns>True if the entry is an integer type, false if an offset, null on error</returns>
public static bool? IsIntegerType(this ResourceTypeInformationEntry entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return null;
// If the highest order bit is set, it's an integer type
return (entry.TypeID & 0x8000) != 0;
}
/// <summary>
/// Determine if a resource type resource entry is an integer or offset
/// </summary>
/// <param name="entry">Resource type resource entry to check</param>
/// <returns>True if the entry is an integer type, false if an offset, null on error</returns>
public static bool? IsIntegerType(this ResourceTypeResourceEntry entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return null;
// If the highest order bit is set, it's an integer type
return (entry.ResourceID & 0x8000) != 0;
}
/// <summary>
/// Get the segment entry type for an entry table bundle
/// </summary>
/// <param name="entry">Entry table bundle to check</param>
/// <returns>SegmentEntryType corresponding to the type</returns>
public static SegmentEntryType GetEntryType(this EntryTableBundle entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return SegmentEntryType.Unused;
// Determine the entry type based on segment indicator
if (entry.SegmentIndicator == 0x00)
return SegmentEntryType.Unused;
else if (entry.SegmentIndicator >= 0x01 && entry.SegmentIndicator <= 0xFE)
return SegmentEntryType.FixedSegment;
else if (entry.SegmentIndicator == 0xFF)
return SegmentEntryType.MoveableSegment;
// We should never get here
return SegmentEntryType.Unused;
}
}
}

View File

@@ -5,70 +5,12 @@ using System.Linq;
using System.Text;
using System.Xml.Serialization;
using SabreTools.IO;
using SabreTools.Models.PortableExecutable;
namespace SabreTools.Serialization
{
public static class Extensions
public static partial class Extensions
{
#region New Executable
/// <summary>
/// Determine if a resource type information entry is an integer or offset
/// </summary>
/// <param name="entry">Resource type information entry to check</param>
/// <returns>True if the entry is an integer type, false if an offset, null on error</returns>
public static bool? IsIntegerType(this Models.NewExecutable.ResourceTypeInformationEntry entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return null;
// If the highest order bit is set, it's an integer type
return (entry.TypeID & 0x8000) != 0;
}
/// <summary>
/// Determine if a resource type resource entry is an integer or offset
/// </summary>
/// <param name="entry">Resource type resource entry to check</param>
/// <returns>True if the entry is an integer type, false if an offset, null on error</returns>
public static bool? IsIntegerType(this Models.NewExecutable.ResourceTypeResourceEntry entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return null;
// If the highest order bit is set, it's an integer type
return (entry.ResourceID & 0x8000) != 0;
}
/// <summary>
/// Get the segment entry type for an entry table bundle
/// </summary>
/// <param name="entry">Entry table bundle to check</param>
/// <returns>SegmentEntryType corresponding to the type</returns>
public static Models.NewExecutable.SegmentEntryType GetEntryType(this Models.NewExecutable.EntryTableBundle entry)
{
// We can't do anything with an invalid entry
if (entry == null)
return Models.NewExecutable.SegmentEntryType.Unused;
// Determine the entry type based on segment indicator
if (entry.SegmentIndicator == 0x00)
return Models.NewExecutable.SegmentEntryType.Unused;
else if (entry.SegmentIndicator >= 0x01 && entry.SegmentIndicator <= 0xFE)
return Models.NewExecutable.SegmentEntryType.FixedSegment;
else if (entry.SegmentIndicator == 0xFF)
return Models.NewExecutable.SegmentEntryType.MoveableSegment;
// We should never get here
return Models.NewExecutable.SegmentEntryType.Unused;
}
#endregion
#region Portable Executable
/// <summary>
/// Convert a relative virtual address to a physical one
/// </summary>
@@ -76,9 +18,9 @@ namespace SabreTools.Serialization
/// <param name="sections">Array of sections to check against</param>
/// <returns>Physical address, 0 on error</returns>
#if NET48
public static uint ConvertVirtualAddress(this uint rva, Models.PortableExecutable.SectionHeader[] sections)
public static uint ConvertVirtualAddress(this uint rva, SectionHeader[] sections)
#else
public static uint ConvertVirtualAddress(this uint rva, Models.PortableExecutable.SectionHeader?[] sections)
public static uint ConvertVirtualAddress(this uint rva, SectionHeader?[]? sections)
#endif
{
// If we have an invalid section table, we can't do anything
@@ -130,7 +72,11 @@ namespace SabreTools.Serialization
/// <param name="rva">Relative virtual address to convert</param>
/// <param name="sections">Array of sections to check against</param>
/// <returns>Section index, null on error</returns>
public static int ContainingSectionIndex(this uint rva, Models.PortableExecutable.SectionHeader[] sections)
#if NET48
public static int ContainingSectionIndex(this uint rva, SectionHeader[] sections)
#else
public static int ContainingSectionIndex(this uint rva, SectionHeader?[]? sections)
#endif
{
// If we have an invalid section table, we can't do anything
if (sections == null || sections.Length == 0)
@@ -144,15 +90,15 @@ namespace SabreTools.Serialization
for (int i = 0; i < sections.Length; i++)
{
// If the section is invalid, just skip it
if (sections[i] == null)
var section = sections[i];
if (section == null)
continue;
// If the section "starts" at 0, just skip it
if (sections[i].PointerToRawData == 0)
if (section.PointerToRawData == 0)
continue;
// Attempt to derive the physical address from the current section
var section = sections[i];
if (rva >= section.VirtualAddress && section.VirtualSize != 0 && rva <= section.VirtualAddress + section.VirtualSize)
return i;
else if (rva >= section.VirtualAddress && section.SizeOfRawData != 0 && rva <= section.VirtualAddress + section.SizeOfRawData)
@@ -169,9 +115,9 @@ namespace SabreTools.Serialization
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled SecuROM AddD overlay data on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.SecuROMAddD AsSecuROMAddD(this byte[] data, ref int offset)
public static SecuROMAddD AsSecuROMAddD(this byte[] data, ref int offset)
#else
public static Models.PortableExecutable.SecuROMAddD? AsSecuROMAddD(this byte[]? data, ref int offset)
public static SecuROMAddD? AsSecuROMAddD(this byte[]? data, ref int offset)
#endif
{
// If we have data that's invalid, we can't do anything
@@ -179,7 +125,7 @@ namespace SabreTools.Serialization
return null;
// Read in the table
var addD = new Models.PortableExecutable.SecuROMAddD();
var addD = new SecuROMAddD();
addD.Signature = data.ReadUInt32(ref offset);
if (addD.Signature != 0x44646441)
@@ -205,10 +151,10 @@ namespace SabreTools.Serialization
addD.Unknown14h = data.ReadBytes(ref offset, bytesToRead);
addD.Entries = new Models.PortableExecutable.SecuROMAddDEntry[addD.EntryCount];
addD.Entries = new SecuROMAddDEntry[addD.EntryCount];
for (int i = 0; i < addD.EntryCount; i++)
{
var addDEntry = new Models.PortableExecutable.SecuROMAddDEntry();
var addDEntry = new SecuROMAddDEntry();
addDEntry.PhysicalOffset = data.ReadUInt32(ref offset);
addDEntry.Length = data.ReadUInt32(ref offset);
@@ -236,16 +182,16 @@ namespace SabreTools.Serialization
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled NB10 Program Database on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.NB10ProgramDatabase AsNB10ProgramDatabase(this byte[] data, ref int offset)
public static NB10ProgramDatabase AsNB10ProgramDatabase(this byte[] data, ref int offset)
#else
public static Models.PortableExecutable.NB10ProgramDatabase? AsNB10ProgramDatabase(this byte[] data, ref int offset)
public static NB10ProgramDatabase? AsNB10ProgramDatabase(this byte[] data, ref int offset)
#endif
{
// If we have data that's invalid, we can't do anything
if (data == null)
return null;
var nb10ProgramDatabase = new Models.PortableExecutable.NB10ProgramDatabase();
var nb10ProgramDatabase = new NB10ProgramDatabase();
nb10ProgramDatabase.Signature = data.ReadUInt32(ref offset);
if (nb10ProgramDatabase.Signature != 0x3031424E)
@@ -266,16 +212,16 @@ namespace SabreTools.Serialization
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled RSDS Program Database on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.RSDSProgramDatabase AsRSDSProgramDatabase(this byte[] data, ref int offset)
public static RSDSProgramDatabase AsRSDSProgramDatabase(this byte[] data, ref int offset)
#else
public static Models.PortableExecutable.RSDSProgramDatabase? AsRSDSProgramDatabase(this byte[]? data, ref int offset)
public static RSDSProgramDatabase? AsRSDSProgramDatabase(this byte[]? data, ref int offset)
#endif
{
// If we have data that's invalid, we can't do anything
if (data == null)
return null;
var rsdsProgramDatabase = new Models.PortableExecutable.RSDSProgramDatabase();
var rsdsProgramDatabase = new RSDSProgramDatabase();
rsdsProgramDatabase.Signature = data.ReadUInt32(ref offset);
if (rsdsProgramDatabase.Signature != 0x53445352)
@@ -302,9 +248,9 @@ namespace SabreTools.Serialization
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled resource header on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.ResourceHeader AsResourceHeader(this byte[] data, ref int offset)
public static ResourceHeader AsResourceHeader(this byte[] data, ref int offset)
#else
public static Models.PortableExecutable.ResourceHeader? AsResourceHeader(this byte[]? data, ref int offset)
public static ResourceHeader? AsResourceHeader(this byte[]? data, ref int offset)
#endif
{
// If we have data that's invalid, we can't do anything
@@ -312,13 +258,13 @@ namespace SabreTools.Serialization
return null;
// Read in the table
var header = new Models.PortableExecutable.ResourceHeader();
var header = new ResourceHeader();
header.DataSize = data.ReadUInt32(ref offset);
header.HeaderSize = data.ReadUInt32(ref offset);
header.ResourceType = (Models.PortableExecutable.ResourceType)data.ReadUInt32(ref offset); // TODO: Could be a string too
header.ResourceType = (ResourceType)data.ReadUInt32(ref offset); // TODO: Could be a string too
header.Name = data.ReadUInt32(ref offset); // TODO: Could be a string too
header.DataVersion = data.ReadUInt32(ref offset);
header.MemoryFlags = (Models.PortableExecutable.MemoryFlags)data.ReadUInt16(ref offset);
header.MemoryFlags = (MemoryFlags)data.ReadUInt16(ref offset);
header.LanguageId = data.ReadUInt16(ref offset);
header.Version = data.ReadUInt32(ref offset);
header.Characteristics = data.ReadUInt32(ref offset);
@@ -332,9 +278,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into an accelerator table resource</param>
/// <returns>A filled accelerator table resource on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.AcceleratorTableEntry[] AsAcceleratorTableResource(this Models.PortableExecutable.ResourceDataEntry entry)
public static AcceleratorTableEntry[] AsAcceleratorTableResource(this ResourceDataEntry entry)
#else
public static Models.PortableExecutable.AcceleratorTableEntry[]? AsAcceleratorTableResource(this Models.PortableExecutable.ResourceDataEntry? entry)
public static AcceleratorTableEntry[]? AsAcceleratorTableResource(this ResourceDataEntry? entry)
#endif
{
// If we have data that's invalid for this resource type, we can't do anything
@@ -348,14 +294,14 @@ namespace SabreTools.Serialization
int offset = 0;
// Create the output object
var table = new Models.PortableExecutable.AcceleratorTableEntry[count];
var table = new AcceleratorTableEntry[count];
// Read in the table
for (int i = 0; i < count; i++)
{
var acceleratorTableEntry = new Models.PortableExecutable.AcceleratorTableEntry();
var acceleratorTableEntry = new AcceleratorTableEntry();
acceleratorTableEntry.Flags = (Models.PortableExecutable.AcceleratorTableFlags)entry.Data.ReadUInt16(ref offset);
acceleratorTableEntry.Flags = (AcceleratorTableFlags)entry.Data.ReadUInt16(ref offset);
acceleratorTableEntry.Ansi = entry.Data.ReadUInt16(ref offset);
acceleratorTableEntry.Id = entry.Data.ReadUInt16(ref offset);
acceleratorTableEntry.Padding = entry.Data.ReadUInt16(ref offset);
@@ -372,9 +318,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into a side-by-side assembly manifest</param>
/// <returns>A filled side-by-side assembly manifest on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.AssemblyManifest AsAssemblyManifest(this Models.PortableExecutable.ResourceDataEntry entry)
public static AssemblyManifest AsAssemblyManifest(this ResourceDataEntry entry)
#else
public static Models.PortableExecutable.AssemblyManifest? AsAssemblyManifest(this Models.PortableExecutable.ResourceDataEntry? entry)
public static AssemblyManifest? AsAssemblyManifest(this ResourceDataEntry? entry)
#endif
{
// If we have an invalid entry, just skip
@@ -383,8 +329,8 @@ namespace SabreTools.Serialization
try
{
XmlSerializer serializer = new XmlSerializer(typeof(Models.PortableExecutable.AssemblyManifest));
return serializer.Deserialize(new MemoryStream(entry.Data)) as Models.PortableExecutable.AssemblyManifest;
XmlSerializer serializer = new XmlSerializer(typeof(AssemblyManifest));
return serializer.Deserialize(new MemoryStream(entry.Data)) as AssemblyManifest;
}
catch
{
@@ -398,9 +344,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into a dialog box</param>
/// <returns>A filled dialog box on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.DialogBoxResource AsDialogBox(this Models.PortableExecutable.ResourceDataEntry entry)
public static DialogBoxResource AsDialogBox(this ResourceDataEntry entry)
#else
public static Models.PortableExecutable.DialogBoxResource? AsDialogBox(this Models.PortableExecutable.ResourceDataEntry? entry)
public static DialogBoxResource? AsDialogBox(this ResourceDataEntry? entry)
#endif
{
// If we have an invalid entry, just skip
@@ -411,7 +357,7 @@ namespace SabreTools.Serialization
int offset = 0;
// Create the output object
var dialogBoxResource = new Models.PortableExecutable.DialogBoxResource();
var dialogBoxResource = new DialogBoxResource();
// Try to read the signature for an extended dialog box template
int signatureOffset = sizeof(ushort);
@@ -420,13 +366,13 @@ namespace SabreTools.Serialization
{
#region Extended dialog template
var dialogTemplateExtended = new Models.PortableExecutable.DialogTemplateExtended();
var dialogTemplateExtended = new DialogTemplateExtended();
dialogTemplateExtended.Version = entry.Data.ReadUInt16(ref offset);
dialogTemplateExtended.Signature = entry.Data.ReadUInt16(ref offset);
dialogTemplateExtended.HelpID = entry.Data.ReadUInt32(ref offset);
dialogTemplateExtended.ExtendedStyle = (Models.PortableExecutable.ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplateExtended.Style = (Models.PortableExecutable.WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplateExtended.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplateExtended.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplateExtended.DialogItems = entry.Data.ReadUInt16(ref offset);
dialogTemplateExtended.PositionX = entry.Data.ReadInt16(ref offset);
dialogTemplateExtended.PositionY = entry.Data.ReadInt16(ref offset);
@@ -535,7 +481,7 @@ namespace SabreTools.Serialization
#region Point size and typeface
// Only if DS_SETFONT is set are the values here used
if (dialogTemplateExtended.Style.HasFlag(Models.PortableExecutable.WindowStyles.DS_SETFONT))
if (dialogTemplateExtended.Style.HasFlag(WindowStyles.DS_SETFONT))
{
dialogTemplateExtended.PointSize = entry.Data.ReadUInt16(ref offset);
dialogTemplateExtended.Weight = entry.Data.ReadUInt16(ref offset);
@@ -559,15 +505,15 @@ namespace SabreTools.Serialization
#region Extended dialog item templates
var dialogItemExtendedTemplates = new List<Models.PortableExecutable.DialogItemTemplateExtended>();
var dialogItemExtendedTemplates = new List<DialogItemTemplateExtended>();
for (int i = 0; i < dialogTemplateExtended.DialogItems; i++)
{
var dialogItemTemplate = new Models.PortableExecutable.DialogItemTemplateExtended();
var dialogItemTemplate = new DialogItemTemplateExtended();
dialogItemTemplate.HelpID = entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.ExtendedStyle = (Models.PortableExecutable.ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.Style = (Models.PortableExecutable.WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.PositionX = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.PositionY = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.WidthX = entry.Data.ReadInt16(ref offset);
@@ -587,7 +533,7 @@ namespace SabreTools.Serialization
_ = entry.Data.ReadUInt16(ref offset);
// Read the ordinal
dialogItemTemplate.ClassResourceOrdinal = (Models.PortableExecutable.DialogItemTemplateOrdinal)entry.Data.ReadUInt16(ref offset);
dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16(ref offset);
}
else
{
@@ -665,10 +611,10 @@ namespace SabreTools.Serialization
{
#region Dialog template
var dialogTemplate = new Models.PortableExecutable.DialogTemplate();
var dialogTemplate = new DialogTemplate();
dialogTemplate.Style = (Models.PortableExecutable.WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplate.ExtendedStyle = (Models.PortableExecutable.ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplate.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogTemplate.ItemCount = entry.Data.ReadUInt16(ref offset);
dialogTemplate.PositionX = entry.Data.ReadInt16(ref offset);
dialogTemplate.PositionY = entry.Data.ReadInt16(ref offset);
@@ -777,7 +723,7 @@ namespace SabreTools.Serialization
#region Point size and typeface
// Only if DS_SETFONT is set are the values here used
if (dialogTemplate.Style.HasFlag(Models.PortableExecutable.WindowStyles.DS_SETFONT))
if (dialogTemplate.Style.HasFlag(WindowStyles.DS_SETFONT))
{
dialogTemplate.PointSizeValue = entry.Data.ReadUInt16(ref offset);
@@ -800,14 +746,14 @@ namespace SabreTools.Serialization
#region Dialog item templates
var dialogItemTemplates = new List<Models.PortableExecutable.DialogItemTemplate>();
var dialogItemTemplates = new List<DialogItemTemplate>();
for (int i = 0; i < dialogTemplate.ItemCount; i++)
{
var dialogItemTemplate = new Models.PortableExecutable.DialogItemTemplate();
var dialogItemTemplate = new DialogItemTemplate();
dialogItemTemplate.Style = (Models.PortableExecutable.WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.ExtendedStyle = (Models.PortableExecutable.ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.PositionX = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.PositionY = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.WidthX = entry.Data.ReadInt16(ref offset);
@@ -827,7 +773,7 @@ namespace SabreTools.Serialization
_ = entry.Data.ReadUInt16(ref offset);
// Read the ordinal
dialogItemTemplate.ClassResourceOrdinal = (Models.PortableExecutable.DialogItemTemplateOrdinal)entry.Data.ReadUInt16(ref offset);
dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16(ref offset);
}
else
{
@@ -911,9 +857,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into a font group</param>
/// <returns>A filled font group on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.FontGroupHeader AsFontGroup(this Models.PortableExecutable.ResourceDataEntry entry)
public static FontGroupHeader AsFontGroup(this ResourceDataEntry entry)
#else
public static Models.PortableExecutable.FontGroupHeader? AsFontGroup(this Models.PortableExecutable.ResourceDataEntry? entry)
public static FontGroupHeader? AsFontGroup(this ResourceDataEntry? entry)
#endif
{
// If we have an invalid entry, just skip
@@ -924,19 +870,19 @@ namespace SabreTools.Serialization
int offset = 0;
// Create the output object
var fontGroupHeader = new Models.PortableExecutable.FontGroupHeader();
var fontGroupHeader = new FontGroupHeader();
fontGroupHeader.NumberOfFonts = entry.Data.ReadUInt16(ref offset);
if (fontGroupHeader.NumberOfFonts > 0)
{
fontGroupHeader.DE = new Models.PortableExecutable.DirEntry[fontGroupHeader.NumberOfFonts];
fontGroupHeader.DE = new DirEntry[fontGroupHeader.NumberOfFonts];
for (int i = 0; i < fontGroupHeader.NumberOfFonts; i++)
{
var dirEntry = new Models.PortableExecutable.DirEntry();
var dirEntry = new DirEntry();
dirEntry.FontOrdinal = entry.Data.ReadUInt16(ref offset);
dirEntry.Entry = new Models.PortableExecutable.FontDirEntry();
dirEntry.Entry = new FontDirEntry();
dirEntry.Entry.Version = entry.Data.ReadUInt16(ref offset);
dirEntry.Entry.Size = entry.Data.ReadUInt32(ref offset);
dirEntry.Entry.Copyright = entry.Data.ReadBytes(ref offset, 60);
@@ -984,9 +930,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into a menu</param>
/// <returns>A filled menu on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.MenuResource AsMenu(this Models.PortableExecutable.ResourceDataEntry entry)
public static MenuResource AsMenu(this ResourceDataEntry entry)
#else
public static Models.PortableExecutable.MenuResource? AsMenu(this Models.PortableExecutable.ResourceDataEntry? entry)
public static MenuResource? AsMenu(this ResourceDataEntry? entry)
#endif
{
// If we have an invalid entry, just skip
@@ -997,7 +943,7 @@ namespace SabreTools.Serialization
int offset = 0;
// Create the output object
var menuResource = new Models.PortableExecutable.MenuResource();
var menuResource = new MenuResource();
// Try to read the version for an extended header
int versionOffset = 0;
@@ -1006,7 +952,7 @@ namespace SabreTools.Serialization
{
#region Extended menu header
var menuHeaderExtended = new Models.PortableExecutable.MenuHeaderExtended();
var menuHeaderExtended = new MenuHeaderExtended();
menuHeaderExtended.Version = entry.Data.ReadUInt16(ref offset);
menuHeaderExtended.Offset = entry.Data.ReadUInt16(ref offset);
@@ -1018,7 +964,7 @@ namespace SabreTools.Serialization
#region Extended dialog item templates
var extendedMenuItems = new List<Models.PortableExecutable.MenuItemExtended>();
var extendedMenuItems = new List<MenuItemExtended>();
if (offset != 0)
{
@@ -1026,12 +972,12 @@ namespace SabreTools.Serialization
while (offset < entry.Data.Length)
{
var extendedMenuItem = new Models.PortableExecutable.MenuItemExtended();
var extendedMenuItem = new MenuItemExtended();
extendedMenuItem.ItemType = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.State = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.ItemType = (MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.State = (MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.ID = entry.Data.ReadUInt32(ref offset);
extendedMenuItem.Flags = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.Flags = (MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.MenuText = entry.Data.ReadString(ref offset, Encoding.Unicode);
// Align to the DWORD boundary if we're not at the end
@@ -1053,7 +999,7 @@ namespace SabreTools.Serialization
{
#region Menu header
var menuHeader = new Models.PortableExecutable.MenuHeader();
var menuHeader = new MenuHeader();
menuHeader.Version = entry.Data.ReadUInt16(ref offset);
menuHeader.HeaderSize = entry.Data.ReadUInt16(ref offset);
@@ -1064,26 +1010,26 @@ namespace SabreTools.Serialization
#region Menu items
var menuItems = new List<Models.PortableExecutable.MenuItem>();
var menuItems = new List<MenuItem>();
while (offset < entry.Data.Length)
{
var menuItem = new Models.PortableExecutable.MenuItem();
var menuItem = new MenuItem();
// Determine if this is a popup
int flagsOffset = offset;
var initialFlags = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt16(ref flagsOffset);
if (initialFlags.HasFlag(Models.PortableExecutable.MenuFlags.MF_POPUP))
var initialFlags = (MenuFlags)entry.Data.ReadUInt16(ref flagsOffset);
if (initialFlags.HasFlag(MenuFlags.MF_POPUP))
{
menuItem.PopupItemType = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt32(ref offset);
menuItem.PopupState = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt32(ref offset);
menuItem.PopupItemType = (MenuFlags)entry.Data.ReadUInt32(ref offset);
menuItem.PopupState = (MenuFlags)entry.Data.ReadUInt32(ref offset);
menuItem.PopupID = entry.Data.ReadUInt32(ref offset);
menuItem.PopupResInfo = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt32(ref offset);
menuItem.PopupResInfo = (MenuFlags)entry.Data.ReadUInt32(ref offset);
menuItem.PopupMenuText = entry.Data.ReadString(ref offset, Encoding.Unicode);
}
else
{
menuItem.NormalResInfo = (Models.PortableExecutable.MenuFlags)entry.Data.ReadUInt16(ref offset);
menuItem.NormalResInfo = (MenuFlags)entry.Data.ReadUInt16(ref offset);
menuItem.NormalMenuText = entry.Data.ReadString(ref offset, Encoding.Unicode);
}
@@ -1111,9 +1057,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into a message table resource</param>
/// <returns>A filled message table resource on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.MessageResourceData AsMessageResourceData(this Models.PortableExecutable.ResourceDataEntry entry)
public static MessageResourceData AsMessageResourceData(this ResourceDataEntry entry)
#else
public static Models.PortableExecutable.MessageResourceData? AsMessageResourceData(this Models.PortableExecutable.ResourceDataEntry? entry)
public static MessageResourceData? AsMessageResourceData(this ResourceDataEntry? entry)
#endif
{
// If we have an invalid entry, just skip
@@ -1124,17 +1070,17 @@ namespace SabreTools.Serialization
int offset = 0;
// Create the output object
var messageResourceData = new Models.PortableExecutable.MessageResourceData();
var messageResourceData = new MessageResourceData();
// Message resource blocks
messageResourceData.NumberOfBlocks = entry.Data.ReadUInt32(ref offset);
if (messageResourceData.NumberOfBlocks > 0)
{
var messageResourceBlocks = new List<Models.PortableExecutable.MessageResourceBlock>();
var messageResourceBlocks = new List<MessageResourceBlock>();
for (int i = 0; i < messageResourceData.NumberOfBlocks; i++)
{
var messageResourceBlock = new Models.PortableExecutable.MessageResourceBlock();
var messageResourceBlock = new MessageResourceBlock();
messageResourceBlock.LowId = entry.Data.ReadUInt32(ref offset);
messageResourceBlock.HighId = entry.Data.ReadUInt32(ref offset);
@@ -1150,9 +1096,9 @@ namespace SabreTools.Serialization
if (messageResourceData.Blocks != null && messageResourceData.Blocks.Length != 0)
{
#if NET48
var messageResourceEntries = new Dictionary<uint, Models.PortableExecutable.MessageResourceEntry>();
var messageResourceEntries = new Dictionary<uint, MessageResourceEntry>();
#else
var messageResourceEntries = new Dictionary<uint, Models.PortableExecutable.MessageResourceEntry?>();
var messageResourceEntries = new Dictionary<uint, MessageResourceEntry?>();
#endif
for (int i = 0; i < messageResourceData.Blocks.Length; i++)
@@ -1165,7 +1111,7 @@ namespace SabreTools.Serialization
for (uint j = messageResourceBlock.LowId; j <= messageResourceBlock.HighId; j++)
{
var messageResourceEntry = new Models.PortableExecutable.MessageResourceEntry();
var messageResourceEntry = new MessageResourceEntry();
messageResourceEntry.Length = entry.Data.ReadUInt16(ref offset);
messageResourceEntry.Flags = entry.Data.ReadUInt16(ref offset);
@@ -1195,9 +1141,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into a string table resource</param>
/// <returns>A filled string table resource on success, null on error</returns>
#if NET48
public static Dictionary<int, string> AsStringTable(this Models.PortableExecutable.ResourceDataEntry entry)
public static Dictionary<int, string> AsStringTable(this ResourceDataEntry entry)
#else
public static Dictionary<int, string?>? AsStringTable(this Models.PortableExecutable.ResourceDataEntry? entry)
public static Dictionary<int, string?>? AsStringTable(this ResourceDataEntry? entry)
#endif
{
// If we have an invalid entry, just skip
@@ -1246,9 +1192,9 @@ namespace SabreTools.Serialization
/// <param name="entry">Resource data entry to parse into a version info resource</param>
/// <returns>A filled version info resource on success, null on error</returns>
#if NET48
public static Models.PortableExecutable.VersionInfo AsVersionInfo(this Models.PortableExecutable.ResourceDataEntry entry)
public static VersionInfo AsVersionInfo(this ResourceDataEntry entry)
#else
public static Models.PortableExecutable.VersionInfo? AsVersionInfo(this Models.PortableExecutable.ResourceDataEntry? entry)
public static VersionInfo? AsVersionInfo(this ResourceDataEntry? entry)
#endif
{
// If we have an invalid entry, just skip
@@ -1259,11 +1205,11 @@ namespace SabreTools.Serialization
int offset = 0;
// Create the output object
var versionInfo = new Models.PortableExecutable.VersionInfo();
var versionInfo = new VersionInfo();
versionInfo.Length = entry.Data.ReadUInt16(ref offset);
versionInfo.ValueLength = entry.Data.ReadUInt16(ref offset);
versionInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset);
versionInfo.ResourceType = (VersionResourceType)entry.Data.ReadUInt16(ref offset);
versionInfo.Key = entry.Data.ReadString(ref offset, Encoding.Unicode);
if (versionInfo.Key != "VS_VERSION_INFO")
return null;
@@ -1274,7 +1220,7 @@ namespace SabreTools.Serialization
// Read fixed file info
if (versionInfo.ValueLength > 0)
{
var fixedFileInfo = new Models.PortableExecutable.FixedFileInfo();
var fixedFileInfo = new FixedFileInfo();
fixedFileInfo.Signature = entry.Data.ReadUInt32(ref offset);
if (fixedFileInfo.Signature != 0xFEEF04BD)
return null;
@@ -1285,10 +1231,10 @@ namespace SabreTools.Serialization
fixedFileInfo.ProductVersionMS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.ProductVersionLS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileFlagsMask = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileFlags = (Models.PortableExecutable.FixedFileInfoFlags)(entry.Data.ReadUInt32(ref offset) & fixedFileInfo.FileFlagsMask);
fixedFileInfo.FileOS = (Models.PortableExecutable.FixedFileInfoOS)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileType = (Models.PortableExecutable.FixedFileInfoFileType)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileSubtype = (Models.PortableExecutable.FixedFileInfoFileSubtype)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileFlags = (FixedFileInfoFlags)(entry.Data.ReadUInt32(ref offset) & fixedFileInfo.FileFlagsMask);
fixedFileInfo.FileOS = (FixedFileInfoOS)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileType = (FixedFileInfoFileType)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileSubtype = (FixedFileInfoFileSubtype)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileDateMS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileDateLS = entry.Data.ReadUInt32(ref offset);
versionInfo.Value = fixedFileInfo;
@@ -1361,19 +1307,19 @@ namespace SabreTools.Serialization
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled string file info resource on success, null on error</returns>
#if NET48
private static Models.PortableExecutable.StringFileInfo AsStringFileInfo(byte[] data, ref int offset)
private static StringFileInfo AsStringFileInfo(byte[] data, ref int offset)
#else
private static Models.PortableExecutable.StringFileInfo? AsStringFileInfo(byte[] data, ref int offset)
private static StringFileInfo? AsStringFileInfo(byte[] data, ref int offset)
#endif
{
var stringFileInfo = new Models.PortableExecutable.StringFileInfo();
var stringFileInfo = new StringFileInfo();
// Cache the initial offset
int currentOffset = offset;
stringFileInfo.Length = data.ReadUInt16(ref offset);
stringFileInfo.ValueLength = data.ReadUInt16(ref offset);
stringFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset);
stringFileInfo.ResourceType = (VersionResourceType)data.ReadUInt16(ref offset);
stringFileInfo.Key = data.ReadString(ref offset, Encoding.Unicode);
if (stringFileInfo.Key != "StringFileInfo")
{
@@ -1388,14 +1334,14 @@ namespace SabreTools.Serialization
stringFileInfo.Padding = data.ReadByte(ref offset);
}
var stringFileInfoChildren = new List<Models.PortableExecutable.StringTable>();
var stringFileInfoChildren = new List<StringTable>();
while ((offset - currentOffset) < stringFileInfo.Length)
{
var stringTable = new Models.PortableExecutable.StringTable();
var stringTable = new StringTable();
stringTable.Length = data.ReadUInt16(ref offset);
stringTable.ValueLength = data.ReadUInt16(ref offset);
stringTable.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset);
stringTable.ResourceType = (VersionResourceType)data.ReadUInt16(ref offset);
stringTable.Key = data.ReadString(ref offset, Encoding.Unicode);
// Align to the DWORD boundary if we're not at the end
@@ -1405,14 +1351,14 @@ namespace SabreTools.Serialization
stringTable.Padding = data.ReadByte(ref offset);
}
var stringTableChildren = new List<Models.PortableExecutable.StringData>();
var stringTableChildren = new List<StringData>();
while ((offset - currentOffset) < stringTable.Length)
{
var stringData = new Models.PortableExecutable.StringData();
var stringData = new StringData();
stringData.Length = data.ReadUInt16(ref offset);
stringData.ValueLength = data.ReadUInt16(ref offset);
stringData.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset);
stringData.ResourceType = (VersionResourceType)data.ReadUInt16(ref offset);
stringData.Key = data.ReadString(ref offset, Encoding.Unicode);
// Align to the DWORD boundary if we're not at the end
@@ -1460,19 +1406,19 @@ namespace SabreTools.Serialization
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled var file info resource on success, null on error</returns>
#if NET48
private static Models.PortableExecutable.VarFileInfo AsVarFileInfo(byte[] data, ref int offset)
private static VarFileInfo AsVarFileInfo(byte[] data, ref int offset)
#else
private static Models.PortableExecutable.VarFileInfo? AsVarFileInfo(byte[] data, ref int offset)
private static VarFileInfo? AsVarFileInfo(byte[] data, ref int offset)
#endif
{
var varFileInfo = new Models.PortableExecutable.VarFileInfo();
var varFileInfo = new VarFileInfo();
// Cache the initial offset
int initialOffset = offset;
varFileInfo.Length = data.ReadUInt16(ref offset);
varFileInfo.ValueLength = data.ReadUInt16(ref offset);
varFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset);
varFileInfo.ResourceType = (VersionResourceType)data.ReadUInt16(ref offset);
varFileInfo.Key = data.ReadString(ref offset, Encoding.Unicode);
if (varFileInfo.Key != "VarFileInfo")
return null;
@@ -1484,14 +1430,14 @@ namespace SabreTools.Serialization
varFileInfo.Padding = data.ReadByte(ref offset);
}
var varFileInfoChildren = new List<Models.PortableExecutable.VarData>();
var varFileInfoChildren = new List<VarData>();
while ((offset - initialOffset) < varFileInfo.Length)
{
var varData = new Models.PortableExecutable.VarData();
var varData = new VarData();
varData.Length = data.ReadUInt16(ref offset);
varData.ValueLength = data.ReadUInt16(ref offset);
varData.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset);
varData.ResourceType = (VersionResourceType)data.ReadUInt16(ref offset);
varData.Key = data.ReadString(ref offset, Encoding.Unicode);
if (varData.Key != "Translation")
{
@@ -1527,7 +1473,5 @@ namespace SabreTools.Serialization
}
#endregion
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.ClrMamePro;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
@@ -6,14 +7,21 @@ namespace SabreTools.Serialization.Files
{
/// <inheritdoc/>
#if NET48
public MetadataFile Deserialize(string path)
public MetadataFile Deserialize(string path) => Deserialize(path, true);
#else
public MetadataFile? Deserialize(string? path)
public MetadataFile? Deserialize(string? path) => Deserialize(path, true);
#endif
/// <inheritdoc/>
#if NET48
public MetadataFile Deserialize(string path, bool quotes)
#else
public MetadataFile? Deserialize(string? path, bool quotes)
#endif
{
using (var stream = PathProcessor.OpenStream(path))
{
return new Streams.ClrMamePro().Deserialize(stream);
return new Streams.ClrMamePro().Deserialize(stream, quotes);
}
}
}

View File

@@ -1,5 +1,6 @@
using System.IO;
using SabreTools.Models.ClrMamePro;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -0,0 +1,626 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using SabreTools.Models.CueSheets;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
public partial class CueSheet : IFileSerializer<Models.CueSheets.CueSheet>
{
/// <inheritdoc/>
#if NET48
public Models.CueSheets.CueSheet Deserialize(string path)
#else
public Models.CueSheets.CueSheet? Deserialize(string? path)
#endif
{
// Check that the file exists
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
return null;
// Check the extension
string ext = Path.GetExtension(path).TrimStart('.');
if (!string.Equals(ext, "cue", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(ext, "txt", StringComparison.OrdinalIgnoreCase))
{
return null;
}
// Create the holding objects
var cueSheet = new Models.CueSheets.CueSheet();
var cueFiles = new List<CueFile>();
// Open the file and begin reading
string[] cueLines = File.ReadAllLines(path);
for (int i = 0; i < cueLines.Length; i++)
{
string line = cueLines[i].Trim();
// http://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes
string[] splitLine = Regex
.Matches(line, @"[^\s""]+|""[^""]*""")
.Cast<Match>()
.Select(m => m.Groups[0].Value)
.ToArray();
// If we have an empty line, we skip
if (string.IsNullOrWhiteSpace(line))
continue;
switch (splitLine[0])
{
// Read comments
case "REM":
// We ignore all comments for now
break;
// Read MCN
case "CATALOG":
if (splitLine.Length < 2)
throw new FormatException($"CATALOG line malformed: {line}");
cueSheet.Catalog = splitLine[1];
break;
// Read external CD-Text file path
case "CDTEXTFILE":
if (splitLine.Length < 2)
throw new FormatException($"CDTEXTFILE line malformed: {line}");
cueSheet.CdTextFile = splitLine[1];
break;
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
throw new FormatException($"PERFORMER line malformed: {line}");
cueSheet.Performer = splitLine[1];
break;
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
throw new FormatException($"SONGWRITER line malformed: {line}");
cueSheet.Songwriter = splitLine[1];
break;
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
throw new FormatException($"TITLE line malformed: {line}");
cueSheet.Title = splitLine[1];
break;
// Read file information
case "FILE":
if (splitLine.Length < 3)
throw new FormatException($"FILE line malformed: {line}");
var file = CreateCueFile(splitLine[1], splitLine[2], cueLines, ref i);
if (file == default)
throw new FormatException($"FILE line malformed: {line}");
cueFiles.Add(file);
break;
}
}
cueSheet.Files = cueFiles.ToArray();
return cueSheet;
}
/// <summary>
/// Fill a FILE from an array of lines
/// </summary>
/// <param name="fileName">File name to set</param>
/// <param name="fileType">File type to set</param>
/// <param name="cueLines">Lines array to pull from</param>
/// <param name="i">Reference to index in array</param>
#if NET48
private static CueFile CreateCueFile(string fileName, string fileType, string[] cueLines, ref int i)
#else
private static CueFile? CreateCueFile(string fileName, string fileType, string[]? cueLines, ref int i)
#endif
{
// Check the required parameters
if (cueLines == null)
throw new ArgumentNullException(nameof(cueLines));
else if (i < 0 || i > cueLines.Length)
throw new IndexOutOfRangeException();
// Create the holding objects
var cueFile = new CueFile();
var cueTracks = new List<CueTrack>();
// Set the current fields
cueFile.FileName = fileName.Trim('"');
cueFile.FileType = GetFileType(fileType);
// Increment to start
i++;
for (; i < cueLines.Length; i++)
{
string line = cueLines[i].Trim();
string[] splitLine = line.Split(' ');
// If we have an empty line, we skip
if (string.IsNullOrWhiteSpace(line))
continue;
switch (splitLine[0])
{
// Read comments
case "REM":
// We ignore all comments for now
break;
// Read track information
case "TRACK":
if (splitLine.Length < 3)
throw new FormatException($"TRACK line malformed: {line}");
var track = CreateCueTrack(splitLine[1], splitLine[2], cueLines, ref i);
if (track == default)
throw new FormatException($"TRACK line malformed: {line}");
cueTracks.Add(track);
break;
// Default means return
default:
i--;
return null;
}
}
cueFile.Tracks = cueTracks.ToArray();
return cueFile;
}
/// <summary>
/// Fill a TRACK from an array of lines
/// </summary>
/// <param name="number">Number to set</param>
/// <param name="dataType">Data type to set</param>
/// <param name="cueLines">Lines array to pull from</param>
/// <param name="i">Reference to index in array</param>
#if NET48
private static CueTrack CreateCueTrack(string number, string dataType, string[] cueLines, ref int i)
#else
private static CueTrack? CreateCueTrack(string number, string dataType, string[]? cueLines, ref int i)
#endif
{
// Check the required parameters
if (cueLines == null)
throw new ArgumentNullException(nameof(cueLines));
else if (i < 0 || i > cueLines.Length)
throw new IndexOutOfRangeException();
// Set the current fields
if (!int.TryParse(number, out int parsedNumber))
throw new ArgumentException($"Number was not a number: {number}");
else if (parsedNumber < 1 || parsedNumber > 99)
throw new IndexOutOfRangeException($"Index must be between 1 and 99: {parsedNumber}");
// Create the holding objects
var cueTrack = new CueTrack();
var cueIndices = new List<CueIndex>();
cueTrack.Number = parsedNumber;
cueTrack.DataType = GetDataType(dataType);
// Increment to start
i++;
for (; i < cueLines.Length; i++)
{
string line = cueLines[i].Trim();
string[] splitLine = line.Split(' ');
// If we have an empty line, we skip
if (string.IsNullOrWhiteSpace(line))
continue;
switch (splitLine[0])
{
// Read comments
case "REM":
// We ignore all comments for now
break;
// Read flag information
case "FLAGS":
if (splitLine.Length < 2)
throw new FormatException($"FLAGS line malformed: {line}");
cueTrack.Flags = GetFlags(splitLine);
break;
// Read International Standard Recording Code
case "ISRC":
if (splitLine.Length < 2)
throw new FormatException($"ISRC line malformed: {line}");
cueTrack.ISRC = splitLine[1];
break;
// Read CD-Text enhanced performer
case "PERFORMER":
if (splitLine.Length < 2)
throw new FormatException($"PERFORMER line malformed: {line}");
cueTrack.Performer = splitLine[1];
break;
// Read CD-Text enhanced songwriter
case "SONGWRITER":
if (splitLine.Length < 2)
throw new FormatException($"SONGWRITER line malformed: {line}");
cueTrack.Songwriter = splitLine[1];
break;
// Read CD-Text enhanced title
case "TITLE":
if (splitLine.Length < 2)
throw new FormatException($"TITLE line malformed: {line}");
cueTrack.Title = splitLine[1];
break;
// Read pregap information
case "PREGAP":
if (splitLine.Length < 2)
throw new FormatException($"PREGAP line malformed: {line}");
var pregap = CreatePreGap(splitLine[1]);
if (pregap == default)
throw new FormatException($"PREGAP line malformed: {line}");
cueTrack.PreGap = pregap;
break;
// Read index information
case "INDEX":
if (splitLine.Length < 3)
throw new FormatException($"INDEX line malformed: {line}");
var index = CreateCueIndex(splitLine[1], splitLine[2]);
if (index == default)
throw new FormatException($"INDEX line malformed: {line}");
cueIndices.Add(index);
break;
// Read postgap information
case "POSTGAP":
if (splitLine.Length < 2)
throw new FormatException($"POSTGAP line malformed: {line}");
var postgap = CreatePostGap(splitLine[1]);
if (postgap == default)
throw new FormatException($"POSTGAP line malformed: {line}");
cueTrack.PostGap = postgap;
break;
// Default means return
default:
i--;
return null;
}
}
cueTrack.Indices = cueIndices.ToArray();
return cueTrack;
}
/// <summary>
/// Create a PREGAP from a mm:ss:ff length
/// </summary>
/// <param name="length">String to get length information from</param>
#if NET48
private static PreGap CreatePreGap(string length)
#else
private static PreGap CreatePreGap(string? length)
#endif
{
// Ignore empty lines
if (string.IsNullOrWhiteSpace(length))
throw new ArgumentException("Length was null or whitespace");
// Ignore lines that don't contain the correct information
if (length.Length != 8 || length.Count(c => c == ':') != 2)
throw new FormatException($"Length was not in a recognized format: {length}");
// Split the line
string[] splitLength = length.Split(':');
if (splitLength.Length != 3)
throw new FormatException($"Length was not in a recognized format: {length}");
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
else if (lengthSegments[0] < 0)
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
// Seconds
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
// Frames
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
// Set the values
var preGap = new PreGap
{
Minutes = lengthSegments[0],
Seconds = lengthSegments[1],
Frames = lengthSegments[2],
};
return preGap;
}
/// <summary>
/// Fill a INDEX from an array of lines
/// </summary>
/// <param name="index">Index to set</param>
/// <param name="startTime">Start time to set</param>
#if NET48
private static CueIndex CreateCueIndex(string index, string startTime)
#else
private static CueIndex CreateCueIndex(string? index, string? startTime)
#endif
{
// Set the current fields
if (!int.TryParse(index, out int parsedIndex))
throw new ArgumentException($"Index was not a number: {index}");
else if (parsedIndex < 0 || parsedIndex > 99)
throw new IndexOutOfRangeException($"Index must be between 0 and 99: {parsedIndex}");
// Ignore empty lines
if (string.IsNullOrWhiteSpace(startTime))
throw new ArgumentException("Start time was null or whitespace");
// Ignore lines that don't contain the correct information
if (startTime.Length != 8 || startTime.Count(c => c == ':') != 2)
throw new FormatException($"Start time was not in a recognized format: {startTime}");
// Split the line
string[] splitTime = startTime.Split(':');
if (splitTime.Length != 3)
throw new FormatException($"Start time was not in a recognized format: {startTime}");
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitTime[0], out lengthSegments[0]))
throw new FormatException($"Minutes segment was not a number: {splitTime[0]}");
else if (lengthSegments[0] < 0)
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
// Seconds
if (!int.TryParse(splitTime[1], out lengthSegments[1]))
throw new FormatException($"Seconds segment was not a number: {splitTime[1]}");
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
// Frames
if (!int.TryParse(splitTime[2], out lengthSegments[2]))
throw new FormatException($"Frames segment was not a number: {splitTime[2]}");
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
// Set the values
var cueIndex = new CueIndex
{
Index = parsedIndex,
Minutes = lengthSegments[0],
Seconds = lengthSegments[1],
Frames = lengthSegments[2],
};
return cueIndex;
}
/// <summary>
/// Create a POSTGAP from a mm:ss:ff length
/// </summary>
/// <param name="length">String to get length information from</param>
#if NET48
private static PostGap CreatePostGap(string length)
#else
private static PostGap CreatePostGap(string? length)
#endif
{
// Ignore empty lines
if (string.IsNullOrWhiteSpace(length))
throw new ArgumentException("Length was null or whitespace");
// Ignore lines that don't contain the correct information
if (length.Length != 8 || length.Count(c => c == ':') != 2)
throw new FormatException($"Length was not in a recognized format: {length}");
// Split the line
string[] splitLength = length.Split(':');
if (splitLength.Length != 3)
throw new FormatException($"Length was not in a recognized format: {length}");
// Parse the lengths
int[] lengthSegments = new int[3];
// Minutes
if (!int.TryParse(splitLength[0], out lengthSegments[0]))
throw new FormatException($"Minutes segment was not a number: {splitLength[0]}");
else if (lengthSegments[0] < 0)
throw new IndexOutOfRangeException($"Minutes segment must be 0 or greater: {lengthSegments[0]}");
// Seconds
if (!int.TryParse(splitLength[1], out lengthSegments[1]))
throw new FormatException($"Seconds segment was not a number: {splitLength[1]}");
else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
throw new IndexOutOfRangeException($"Seconds segment must be between 0 and 60: {lengthSegments[1]}");
// Frames
if (!int.TryParse(splitLength[2], out lengthSegments[2]))
throw new FormatException($"Frames segment was not a number: {splitLength[2]}");
else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
throw new IndexOutOfRangeException($"Frames segment must be between 0 and 75: {lengthSegments[2]}");
// Set the values
var postGap = new PostGap
{
Minutes = lengthSegments[0],
Seconds = lengthSegments[1],
Frames = lengthSegments[2],
};
return postGap;
}
#region Helpers
/// <summary>
/// Get the file type from a given string
/// </summary>
/// <param name="fileType">String to get value from</param>
/// <returns>CueFileType, if possible</returns>
#if NET48
private static CueFileType GetFileType(string fileType)
#else
private static CueFileType GetFileType(string? fileType)
#endif
{
switch (fileType?.ToLowerInvariant())
{
case "binary":
return CueFileType.BINARY;
case "motorola":
return CueFileType.MOTOROLA;
case "aiff":
return CueFileType.AIFF;
case "wave":
return CueFileType.WAVE;
case "mp3":
return CueFileType.MP3;
default:
return CueFileType.BINARY;
}
}
/// <summary>
/// Get the data type from a given string
/// </summary>
/// <param name="dataType">String to get value from</param>
/// <returns>CueTrackDataType, if possible (default AUDIO)</returns>
#if NET48
private static CueTrackDataType GetDataType(string dataType)
#else
private static CueTrackDataType GetDataType(string? dataType)
#endif
{
switch (dataType?.ToLowerInvariant())
{
case "audio":
return CueTrackDataType.AUDIO;
case "cdg":
return CueTrackDataType.CDG;
case "mode1/2048":
return CueTrackDataType.MODE1_2048;
case "mode1/2352":
return CueTrackDataType.MODE1_2352;
case "mode2/2336":
return CueTrackDataType.MODE2_2336;
case "mode2/2352":
return CueTrackDataType.MODE2_2352;
case "cdi/2336":
return CueTrackDataType.CDI_2336;
case "cdi/2352":
return CueTrackDataType.CDI_2352;
default:
return CueTrackDataType.AUDIO;
}
}
/// <summary>
/// Get the flag value for an array of strings
/// </summary>
/// <param name="flagStrings">Possible flags as strings</param>
/// <returns>CueTrackFlag value representing the strings, if possible</returns>
#if NET48
private static CueTrackFlag GetFlags(string[] flagStrings)
#else
private static CueTrackFlag GetFlags(string?[]? flagStrings)
#endif
{
CueTrackFlag flag = 0;
if (flagStrings == null)
return flag;
#if NET48
foreach (string flagString in flagStrings)
#else
foreach (string? flagString in flagStrings)
#endif
{
switch (flagString?.ToLowerInvariant())
{
case "flags":
// No-op since this is the start of the line
break;
case "dcp":
flag |= CueTrackFlag.DCP;
break;
case "4ch":
flag |= CueTrackFlag.FourCH;
break;
case "pre":
flag |= CueTrackFlag.PRE;
break;
case "scms":
flag |= CueTrackFlag.SCMS;
break;
case "data":
flag |= CueTrackFlag.DATA;
break;
}
}
return flag;
}
#endregion
}
}

View File

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

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.DosCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.DosCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.EverdriveSMDB;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.EverdriveSMDB;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

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

View File

@@ -1,18 +1,27 @@
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
public partial class Hashfile : IFileSerializer<Models.Hashfile.Hashfile>
{
/// <inheritdoc/>
#if NET48
public bool Serialize(Models.Hashfile.Hashfile obj, string path)
public bool Serialize(Models.Hashfile.Hashfile obj, string path) => Serialize(obj, path, Hash.CRC);
#else
public bool Serialize(Models.Hashfile.Hashfile? obj, string? path)
public bool Serialize(Models.Hashfile.Hashfile? obj, string? path) => Serialize(obj, path, Hash.CRC);
#endif
/// <inheritdoc/>
#if NET48
public bool Serialize(Models.Hashfile.Hashfile obj, string path, Hash hash)
#else
public bool Serialize(Models.Hashfile.Hashfile? obj, string? path, Hash hash)
#endif
{
if (string.IsNullOrWhiteSpace(path))
return false;
using (var stream = new Streams.Hashfile().Serialize(obj))
using (var stream = new Streams.Hashfile().Serialize(obj, hash))
{
if (stream == null)
return false;

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.Listrom;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.Listrom;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

21
Files/PIC.Deserializer.cs Normal file
View File

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

31
Files/PIC.Serializer.cs Normal file
View File

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

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.RomCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.RomCenter;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.SeparatedValue;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
@@ -6,14 +7,21 @@ namespace SabreTools.Serialization.Files
{
/// <inheritdoc/>
#if NET48
public MetadataFile Deserialize(string path)
public MetadataFile Deserialize(string path) => Deserialize(path, ',');
#else
public MetadataFile? Deserialize(string? path)
public MetadataFile? Deserialize(string? path) => Deserialize(path, ',');
#endif
/// <inheritdoc/>
#if NET48
public MetadataFile Deserialize(string path, char delim)
#else
public MetadataFile? Deserialize(string? path, char delim)
#endif
{
using (var stream = PathProcessor.OpenStream(path))
{
return new Streams.SeparatedValue().Deserialize(stream);
return new Streams.SeparatedValue().Deserialize(stream, delim);
}
}
}

View File

@@ -1,4 +1,5 @@
using SabreTools.Models.SeparatedValue;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
@@ -6,15 +7,22 @@ namespace SabreTools.Serialization.Files
{
/// <inheritdoc/>
#if NET48
public bool Serialize(MetadataFile obj, string path)
public bool Serialize(MetadataFile obj, string path) => Serialize(obj, path, ',');
#else
public bool Serialize(MetadataFile? obj, string? path)
public bool Serialize(MetadataFile? obj, string? path) => Serialize(obj, path, ',');
#endif
/// <inheritdoc/>
#if NET48
public bool Serialize(MetadataFile obj, string path, char delim)
#else
public bool Serialize(MetadataFile? obj, string? path, char delim)
#endif
{
if (string.IsNullOrWhiteSpace(path))
return false;
using (var stream = new Streams.SeparatedValue().Serialize(obj))
using (var stream = new Streams.SeparatedValue().Serialize(obj, delim))
{
if (stream == null)
return false;

216
Files/XMID.Deserializer.cs Normal file
View File

@@ -0,0 +1,216 @@
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
}
}

15
Files/XMID.Serializer.cs Normal file
View File

@@ -0,0 +1,15 @@
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
}
}

275
Files/XeMID.Deserializer.cs Normal file
View File

@@ -0,0 +1,275 @@
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
}
}

15
Files/XeMID.Serializer.cs Normal file
View File

@@ -0,0 +1,15 @@
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
}
}

View File

@@ -1,3 +1,5 @@
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{
/// <summary>

View File

@@ -1,4 +1,5 @@
using System.IO;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Files
{

View File

@@ -1,4 +1,4 @@
namespace SabreTools.Serialization
namespace SabreTools.Serialization.Interfaces
{
/// <summary>
/// Defines how to serialize to and from byte arrays

View File

@@ -1,4 +1,4 @@
namespace SabreTools.Serialization
namespace SabreTools.Serialization.Interfaces
{
/// <summary>
/// Defines how to serialize to and from files

View File

@@ -1,4 +1,4 @@
namespace SabreTools.Serialization
namespace SabreTools.Serialization.Interfaces
{
/// <summary>
/// Defines how to serialize to and from models

View File

@@ -1,6 +1,6 @@
using System.IO;
namespace SabreTools.Serialization
namespace SabreTools.Serialization.Interfaces
{
/// <summary>
/// Defines how to serialize to and from Streams

17
Interfaces/IWrapper.cs Normal file
View File

@@ -0,0 +1,17 @@
namespace SabreTools.Serialization.Interfaces
{
public interface IWrapper
{
/// <summary>
/// Get a human-readable description of the wrapper
/// </summary>
string Description();
#if NET6_0_OR_GREATER
/// <summary>
/// Export the item information as JSON
/// </summary>
string ExportJSON();
#endif
}
}

View File

@@ -1,3 +1,25 @@
# SabreTools.Serialization
This library comprises of serializers that both read and write from files and streams to the dedicated models as well as convert to and from the common internal models. This library is partially used by the current parsing and writing code but none of the internal model serialization is used.
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Serialization).
## `SabreTools.Serialization.Bytes`
This namespace comprises of deserializers that take byte arrays to convert into models.
## `SabreTools.Serialization.CrossModel`
This namespace comprises of serializers and deserializers that convert models to other common ones. This is mainly used for metadata files converting to and from a common, `Dictionary`-based model.
## `SabreTools.Serialization.Files`
This namespace comprises of serializers and deserializers that can convert to and from files on disk. Most of the serializers are symmetric, but this is not guaranteed. Unimplemented methods will throw `NotImplementedException`.
## `SabreTools.Serialization.Streams`
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.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.

View File

@@ -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.0</Version>
<Version>1.1.6</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.1" />
<PackageReference Include="SabreTools.Models" Version="1.1.4" />
</ItemGroup>
</Project>

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Text;
using SabreTools.IO;
using SabreTools.Models.AACS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using SabreTools.Models.AACS;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using SabreTools.IO.Readers;
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{

View File

@@ -3,6 +3,7 @@ using System.Linq;
using System.Text;
using SabreTools.IO.Writers;
using SabreTools.Models.AttractMode;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{

View File

@@ -2,6 +2,7 @@ using System.IO;
using System.Text;
using SabreTools.IO;
using SabreTools.Models.BDPlus;
using SabreTools.Serialization.Interfaces;
using static SabreTools.Models.BDPlus.Constants;
namespace SabreTools.Serialization.Streams

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using SabreTools.Models.BDPlus;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{

View File

@@ -2,6 +2,7 @@ using System.IO;
using System.Text;
using SabreTools.IO;
using SabreTools.Models.BFPK;
using SabreTools.Serialization.Interfaces;
using static SabreTools.Models.BFPK.Constants;
namespace SabreTools.Serialization.Streams

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using SabreTools.Models.BFPK;
using SabreTools.Serialization.Interfaces;
namespace SabreTools.Serialization.Streams
{

Some files were not shown because too many files have changed in this diff Show More