diff --git a/BinaryObjectScanner/Factory.cs b/BinaryObjectScanner/Factory.cs
index 6efcb73d..46ce7135 100644
--- a/BinaryObjectScanner/Factory.cs
+++ b/BinaryObjectScanner/Factory.cs
@@ -20,6 +20,8 @@ namespace BinaryObjectScanner
//case SupportedFileType.N3DS: return new FileType.N3DS();
//case SupportedFileType.Nitro: return new FileType.Nitro();
case SupportedFileType.PLJ: return new FileType.PLJ();
+ case SupportedFileType.RealArcadeInstaller: return new FileType.RealArcadeInstaller();
+ case SupportedFileType.RealArcadeMezzanine: return new FileType.RealArcadeMezzanine();
case SupportedFileType.SFFS: return new FileType.SFFS();
case SupportedFileType.Textfile: return new FileType.Textfile();
default: return null;
diff --git a/BinaryObjectScanner/FileType/RealArcadeInstaller.cs b/BinaryObjectScanner/FileType/RealArcadeInstaller.cs
new file mode 100644
index 00000000..5033ac6d
--- /dev/null
+++ b/BinaryObjectScanner/FileType/RealArcadeInstaller.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using BinaryObjectScanner.Interfaces;
+using SabreTools.Matching;
+
+namespace BinaryObjectScanner.FileType
+{
+ ///
+ /// RealArcade Installer. Known to use the ".rgs" file extension.
+ ///
+ /// TODO: Add further parsing, game ID and name should be possible to parse.
+ ///
+ public class RealArcadeInstaller : IDetectable
+ {
+ ///
+ public string? Detect(string file, bool includeDebug)
+ {
+ if (!File.Exists(file))
+ return null;
+
+ using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ {
+ return Detect(fs, file, includeDebug);
+ }
+ }
+
+ ///
+ public string? Detect(Stream stream, string file, bool includeDebug)
+ {
+ try
+ {
+ byte[] magic = new byte[16];
+ stream.Read(magic, 0, 16);
+
+ // RASGI2.0
+ // Found in the ".rgs" files in IA item "Nova_RealArcadeCD_USA".
+ if (magic.StartsWith(new byte?[] { 0x52, 0x41, 0x53, 0x47, 0x49, 0x32, 0x2E, 0x30 }))
+ return "RealArcade Installer";
+ }
+ catch (Exception ex)
+ {
+ if (includeDebug) Console.WriteLine(ex);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/BinaryObjectScanner/FileType/RealArcadeMezzanine.cs b/BinaryObjectScanner/FileType/RealArcadeMezzanine.cs
new file mode 100644
index 00000000..9b5a7ff3
--- /dev/null
+++ b/BinaryObjectScanner/FileType/RealArcadeMezzanine.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using BinaryObjectScanner.Interfaces;
+using SabreTools.Matching;
+
+namespace BinaryObjectScanner.FileType
+{
+ ///
+ /// RealArcade Mezzanine files, which contain metadata. Known to use the ".mez" file extension.
+ ///
+ /// TODO: Add further parsing, game ID should be possible to parse.
+ ///
+ public class RealArcadeMezzanine : IDetectable
+ {
+ ///
+ public string? Detect(string file, bool includeDebug)
+ {
+ if (!File.Exists(file))
+ return null;
+
+ using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ {
+ return Detect(fs, file, includeDebug);
+ }
+ }
+
+ ///
+ public string? Detect(Stream stream, string file, bool includeDebug)
+ {
+ try
+ {
+ byte[] magic = new byte[16];
+ stream.Read(magic, 0, 16);
+
+ // XZip2.0
+ // Found in the ".mez" files in IA item "Nova_RealArcadeCD_USA".
+ if (magic.StartsWith(new byte?[] { 0x58, 0x5A, 0x69, 0x70, 0x32, 0x2E, 0x30 }))
+ return "RealArcade Mezzanine";
+ }
+ catch (Exception ex)
+ {
+ if (includeDebug) Console.WriteLine(ex);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/BinaryObjectScanner/Protection/RealArcade.cs b/BinaryObjectScanner/Protection/RealArcade.cs
new file mode 100644
index 00000000..3a355670
--- /dev/null
+++ b/BinaryObjectScanner/Protection/RealArcade.cs
@@ -0,0 +1,75 @@
+using System;
+#if NET40_OR_GREATER || NETCOREAPP
+using System.Collections.Concurrent;
+#endif
+using System.Collections.Generic;
+using System.Linq;
+using BinaryObjectScanner.Interfaces;
+using SabreTools.Matching;
+using SabreTools.Serialization.Wrappers;
+
+namespace BinaryObjectScanner.Protection
+{
+ ///
+ /// RealArcade was a game platform that allowed users to play timed demos of games, and then prompted them to purchase the game in order to play the game without a limit.
+ /// Although the servers are long dead, there is a community project actively being developed to allow users to properly download and play these games.
+ /// Links:
+ /// https://github.com/lightbulbatelier/RealArcade-DGA
+ /// https://archive.org/details/realrcade-games-preservation-project
+ ///
+ public class RealArcade : IPathCheck, IPortableExecutableCheck
+ {
+ ///
+ public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
+ {
+ // Get the sections from the executable, if possible
+ var sections = pex.Model.SectionTable;
+ if (sections == null)
+ return null;
+
+ // Get the .data section strings, if they exist
+ var strs = pex.GetFirstSectionStrings(".data");
+ if (strs != null)
+ {
+ // Found in "rebound.exe" in the installation directory for "Rebound" in IA item "Nova_RealArcadeCD_USA".
+ if (strs.Any(s => s.Contains("RngInterstitialDLL")))
+ return "RealArcade";
+ }
+
+ // Found in "RngInterstitial.dll" in the RealArcade installation directory in IA item "Nova_RealArcadeCD_USA".
+ var name = pex.FileDescription;
+ if (name?.Contains("RngInterstitial") == true)
+ return "RealArcade";
+
+ return null;
+ }
+
+ ///
+#if NET20 || NET35
+ public Queue CheckDirectoryPath(string path, IEnumerable? files)
+#else
+ public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable? files)
+#endif
+ {
+ var matchers = new List
+ {
+ // ".rgs" and ".mez" files are also associated with RealArcade.
+ new(new FilePathMatch("RngInterstitial.dll"), "RealArcade"),
+ };
+
+ return MatchUtil.GetAllMatches(files, matchers, any: true);
+ }
+
+ ///
+ public string? CheckFilePath(string path)
+ {
+ var matchers = new List
+ {
+ // ".rgs" and ".mez" files are also associated with RealArcade.
+ new(new FilePathMatch("RngInterstitial.dll"), "RealArcade"),
+ };
+
+ return MatchUtil.GetFirstMatch(path, matchers, any: true);
+ }
+ }
+}
diff --git a/BinaryObjectScanner/Utilities/Enums.cs b/BinaryObjectScanner/Utilities/Enums.cs
index 7ae80b5d..ffe29922 100644
--- a/BinaryObjectScanner/Utilities/Enums.cs
+++ b/BinaryObjectScanner/Utilities/Enums.cs
@@ -140,6 +140,16 @@
///
RAR,
+ ///
+ /// RealArcade Installer
+ ///
+ RealArcadeInstaller,
+
+ ///
+ /// RealArcade Mezzanine
+ ///
+ RealArcadeMezzanine,
+
///
/// 7-zip archive
///
diff --git a/BinaryObjectScanner/Utilities/FileTypes.cs b/BinaryObjectScanner/Utilities/FileTypes.cs
index 98455851..e49cad4a 100644
--- a/BinaryObjectScanner/Utilities/FileTypes.cs
+++ b/BinaryObjectScanner/Utilities/FileTypes.cs
@@ -259,6 +259,20 @@ namespace BinaryObjectScanner.Utilities
#endregion
+ #region RealArcade
+
+ // RASGI2.0
+ // Found in the ".rgs files in IA item "Nova_RealArcadeCD_USA".
+ if (magic.StartsWith(new byte?[] { 0x52, 0x41, 0x53, 0x47, 0x49, 0x32, 0x2E, 0x30 }))
+ return SupportedFileType.RealArcadeInstaller;
+
+ // XZip2.0
+ // Found in the ".mez" files in IA item "Nova_RealArcadeCD_USA".
+ if (magic.StartsWith(new byte?[] { 0x58, 0x5A, 0x69, 0x70, 0x32, 0x2E, 0x30 }))
+ return SupportedFileType.RealArcadeMezzanine;
+
+ #endregion
+
#region SevenZip
if (magic.StartsWith(new byte?[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c }))
diff --git a/README.md b/README.md
index 455b53e7..9df435da 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,7 @@ Below is a list of protections detected by BinaryObjectScanner. The two columns
| Protect DVD-Video | False | True | Unconfirmed¹ |
| PlayStation Anti-modchip | True | False | En/Jp, not "Red Hand"; PSX executables only |
| Rainbow Sentinel | True | True | |
+| RealArcade | True | True | |
| Ring PROTECH / ProRing | True | True | Partially unconfirmed² |
| RipGuard | True | True | Partially unconfirmed² |
| Roxxe | True | False | |