diff --git a/BinaryObjectScanner/Protection/CopyX.cs b/BinaryObjectScanner/Protection/CopyX.cs
index 968a1f62..16066d3d 100644
--- a/BinaryObjectScanner/Protection/CopyX.cs
+++ b/BinaryObjectScanner/Protection/CopyX.cs
@@ -21,7 +21,7 @@ public class CopyX : IPathCheck, IPortableExecutableCheck
{
// Previous check 'Tivola Ring Protect' removed because it was found to actually be copy-x.
// The checks were for ZDAT/webmast.dxx and ZDAT/webmast.dxx, for Redump IDs 81628 and 116418.
-
+
// https://web.archive.org/web/20011016234742/http://www.optimal-online.de:80/product/copy_x.htm
// There are four kinds of copy-X; Light, Profesisonal, audio, and Trial Maker.
// Audio is for Audio CDs. Might be scannable, might not. Samples needed to confirm.
@@ -37,14 +37,15 @@ public class CopyX : IPathCheck, IPortableExecutableCheck
// Both Light and Professional have a directory at the end of the image. The files within this directory are
// intersected by the physical ring.
// This file is usually called ZDAT, but not always. At least one instance of Light calls it ZDATA. At least one
- // instance of Professional calls it System.
+ // instance of Light calls it System.
// Seemingly it can be anything. It doesn't help that most known samples are specifically from one company's
// games, Tivola. Still, most use ZDAT.
// Professional:
// All instances of professional contain a disc check, performed via optgraph.dll.
- // All instances of professional contain in the directory at the end of the image 3 files. gov_[something].x64,
- // iofile.x64, and sound.x64.
+ // All instances of professional contain in a directory usually (but not always, German Emergency 2 Deluxe has a
+ // Videos folder as well, which isn't involved in rings/protection) at the end of the image, 3 files:
+ // gov_[something].x64, iofile.x64, and sound.x64. So far, they have always been in a directory called "System".
// Due to gov's minor name variance, sound.x64 sometimes being intersected by a ring at the start, and
// iofile.x64 being referenced directly in optgraph.x64, only iofile.x64 is being checked for now.
// TODO: optgraph.dll also contains DRM to prevent kernel debugger SoftICE from being used, via a process called
@@ -53,10 +54,11 @@ public class CopyX : IPathCheck, IPortableExecutableCheck
// It has none here since it wouldn't be necessary.
// Light:
- // All instances of light contain 1 or more files in the directory at the end of the image. They all consist of
- // either 0x00, or some data that matches between entries (and also is present in the 3 Professional files),
- // except for the parts with the rings running through them.
- // TODO: Check the last directory alphabetically and not just ZDAT*
+ // All instances of light contain 1 or more files in the directory usually (but not always; Kenny's Adventure has
+ // uses a System folder, and then has a non-protection Xtras folder on the disc as well) at the end of the image.
+ // They all consist of either 0x00, or some data that matches between entries (and also is present in the 3
+ // Professional files), except for the parts with the rings running through them.
+ // Find a viable way to check the last directory alphabetically and not just ZDAT*
///
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -114,22 +116,32 @@ public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable !f.EndsWith(".x64", StringComparison.OrdinalIgnoreCase))
- .Where(f =>
- {
- // TODO: Compensate for the check being run a directory or more higher
- f = f.Remove(0, path.Length);
- f = f.TrimStart('/', '\\');
- return f.StartsWith("ZDAT", StringComparison.OrdinalIgnoreCase);
- })
- .OrderBy(f => f)
- .ToList();
-
- if (fileList.Count > 0)
+
+ // Kenny's Adventure uses System instead of ZDAT.
+ string[] dirs = ["ZDAT", "ZDATA", "System"];
+ List? lightFiles = null;
+
+ // TODO: Compensate for the check being run a directory or more higher
+ var fileList = files.Where(f => !f.EndsWith(".x64", StringComparison.OrdinalIgnoreCase));
+ foreach (var dir in dirs)
+ {
+ lightFiles = fileList.Where(f =>
+ {
+ f = f.Remove(0, path.Length);
+ f = f.TrimStart('/', '\\');
+ return f.StartsWith(dir + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase);
+ })
+ .OrderBy(f => f)
+ .ToList();
+ if (lightFiles.Count() > 0)
+ break;
+ }
+
+ if ((lightFiles != null) && (lightFiles.Count > 0))
{
try
{
- using var stream = File.OpenRead(fileList[0]);
+ using var stream = File.OpenRead(lightFiles[0]);
byte[] block = stream.ReadBytes(1024);
var matchers = new List
@@ -153,7 +165,7 @@ public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable CheckDirectoryPath(string path, IEnumerable