//this file is part of BurnOut
//Copyright (C)2005-2010 Gernot Knippen
//Ported code with augments Copyright (C)2018 Matt Nadareski
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You can get a copy of the GNU General Public License
//by writing to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using BurnOutSharp.FileType;
using BurnOutSharp.ProtectionType;
namespace BurnOutSharp
{
public static class ProtectionFind
{
///
/// Scan a path to find any known copy protection(s)
///
/// Path to scan for protection(s)
/// True to include scanned copy protection position, false otherwise (default)
/// Optional progress indicator that will return a float in the range from 0 to 1
/// Dictionary of filename to protection mappings, if possible
public static Dictionary Scan(string path, bool includePosition = false, IProgress progress = null)
{
var protections = new Dictionary();
// Checkpoint
progress?.Report(new FileProtection(null, 0, null));
// If we have a file
if (File.Exists(path))
{
// Try using just the file first to get protection info
string fileProtection = ScanPath(path, false);
if (!string.IsNullOrWhiteSpace(fileProtection))
protections[path] = fileProtection;
// Now check to see if the file contains any additional information
string contentProtection = ScanContent(path, includePosition)?.Replace("" + (char)0x00, "");
if (!string.IsNullOrWhiteSpace(contentProtection))
{
if (protections.ContainsKey(path))
protections[path] += $", {contentProtection}";
else
protections[path] = contentProtection;
}
// Checkpoint
progress?.Report(new FileProtection(path, 1, contentProtection));
}
// If we have a directory
else if (Directory.Exists(path))
{
// Get the lists of files to be used
var files = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories);
// Try using just the path first to get protection info
string pathProtection = ScanPath(path, true);
if (!string.IsNullOrWhiteSpace(pathProtection))
protections[path] = pathProtection;
// Loop through all files and scan their contents
for (int i = 0; i < files.Count(); i++)
{
// Get the current file
string file = files.ElementAt(i);
// Try using just the file first to get protection info
string fileProtection = ScanPath(file, false);
if (!string.IsNullOrWhiteSpace(fileProtection))
protections[file] = fileProtection;
// Now check to see if the file contains any additional information
string contentProtection = ScanContent(file, includePosition)?.Replace("" + (char)0x00, "");
if (!string.IsNullOrWhiteSpace(contentProtection))
{
if (protections.ContainsKey(file))
protections[file] += $", {contentProtection}";
else
protections[file] = contentProtection;
}
// Checkpoint
progress?.Report(new FileProtection(file, i / (float)files.Count(), contentProtection));
}
}
// If we have an empty list, we need to take care of that
if (protections.Count(p => !string.IsNullOrWhiteSpace(p.Value)) == 0)
{
protections = new Dictionary();
}
return protections;
}
///
/// Scan a path for indications of copy protection
///
///
///
///
public static string ScanPath(string path, bool isDirectory)
{
List protections = new List();
string protection;
// If we have a directory, get the files in the directory for searching
IEnumerable files = null;
if (isDirectory)
files = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories);
// AACS
protection = AACS.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Alpha-DVD
protection = AlphaDVD.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Bitpool
protection = Bitpool.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// ByteShield
protection = ByteShield.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Cactus Data Shield
protection = CactusDataShield.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// CD-Cops
protection = CDCops.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// CD-Lock
protection = CDLock.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// CD-Protector
protection = CDProtector.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// CD-X
protection = CDX.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
/*
// CopyKiller
protection = CopyKiller.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
*/
// DiscGuard
protection = DiscGuard.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// DVD Crypt
protection = DVDCrypt.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// DVD-Movie-PROTECT
protection = DVDMoviePROTECT.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// FreeLock
protection = FreeLock.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Games for Windows - Live
protection = GFWL.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Hexalock AutoLock
protection = HexalockAutoLock.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Impulse Reactor
protection = ImpulseReactor.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// IndyVCD
protection = IndyVCD.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Key2Audio XS
protection = Key2AudioXS.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// LaserLock
protection = LaserLock.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// MediaCloQ
protection = MediaCloQ.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// MediaMax CD3
protection = MediaMaxCD3.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Origin
protection = Origin.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Protect DVD-Video
protection = ProtectDVDVideo.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SafeCast
protection = SafeCast.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SafeDisc
protection = SafeDisc.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SafeDisc Lite
protection = SafeDiscLite.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SafeLock
protection = SafeLock.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SecuROM
protection = SecuROM.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SmartE
protection = SmartE.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SoftLock
protection = SoftLock.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SolidShield
protection = SolidShield.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// StarForce
protection = StarForce.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Steam
protection = Steam.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// TAGES
protection = Tages.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// TZCopyProtector
protection = TZCopyProtector.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Uplay
protection = Uplay.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// VOB ProtectCD/DVD
protection = VOBProtectCDDVD.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Winlock
protection = Winlock.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// WTM CD Protect
protection = WTMCDProtect.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// XCP
protection = XCP.CheckPath(path, files, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Zzxzz
protection = Zzxzz.CheckPath(path, isDirectory);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Now combine any found protections, or null if empty
if (protections.Count() == 0)
return null;
else
return string.Join(", ", protections);
}
///
/// Scan an individual file for copy protection
///
/// File path for scanning
/// True to include scanned copy protection position, false otherwise (default)
public static string ScanContent(string file, bool includePosition = false)
{
using (FileStream fs = File.OpenRead(file))
{
return ScanContent(fs, file, includePosition);
}
}
///
/// Scan an individual stream for copy protection
///
/// Generic stream to scan
/// File path to be used for name checks (optional)
/// True to include scanned copy protection position, false otherwise (default)
public static string ScanContent(Stream stream, string file = null, bool includePosition = false)
{
// Get the extension for certain checks
string extension = Path.GetExtension(file).ToLower().TrimStart('.');
// Assume the first part of the stream is the start of a file
byte[] magic = new byte[16];
try
{
stream.Read(magic, 0, 16);
stream.Seek(-16, SeekOrigin.Current);
}
catch
{
// We don't care what the issue was, we can't read or seek the file
return null;
}
// Files can be protected in multiple ways
List protections = new List();
// 7-Zip archive
if (SevenZip.ShouldScan(magic))
protections.AddRange(SevenZip.Scan(stream, includePosition));
// BFPK archive
if (BFPK.ShouldScan(magic))
protections.AddRange(BFPK.Scan(stream, includePosition));
// BZip2
if (BZip2.ShouldScan(magic))
protections.AddRange(BZip2.Scan(stream, includePosition));
// Executable
if (Executable.ShouldScan(magic))
protections.AddRange(Executable.Scan(stream, file, includePosition));
// GZIP
if (GZIP.ShouldScan(magic))
protections.AddRange(GZIP.Scan(stream, includePosition));
// InstallShield Cabinet
if (file != null && InstallShieldCAB.ShouldScan(magic))
protections.AddRange(InstallShieldCAB.Scan(file, includePosition));
// Microsoft Cabinet
if (file != null && MicrosoftCAB.ShouldScan(magic))
protections.AddRange(MicrosoftCAB.Scan(file, includePosition));
// MPQ archive
if (file != null && MPQ.ShouldScan(magic))
protections.AddRange(MPQ.Scan(file, includePosition));
// PKZIP archive (and derivatives)
if (PKZIP.ShouldScan(magic))
protections.AddRange(PKZIP.Scan(stream, includePosition));
// RAR archive
if (RAR.ShouldScan(magic))
protections.AddRange(RAR.Scan(stream, includePosition));
// Tape Archive
if (TapeArchive.ShouldScan(magic))
protections.AddRange(TapeArchive.Scan(stream, includePosition));
// Text-based files
if (Textfile.ShouldScan(magic, extension))
protections.AddRange(Textfile.Scan(stream, includePosition));
// Valve archive formats
if (file != null && Valve.ShouldScan(magic))
protections.AddRange(Valve.Scan(file, includePosition));
// XZ
if (XZ.ShouldScan(magic))
protections.AddRange(XZ.Scan(stream, includePosition));
// Return blank if nothing found, or comma-separated list of protections
if (protections.Count() == 0)
return string.Empty;
else
return string.Join(", ", protections);
}
///
/// Scan a disc sector by sector for protection
///
///
/// https://stackoverflow.com/questions/8819188/c-sharp-classes-to-undelete-files/8820157#8820157
/// TODO: Finish implementation
///
private static string ScanSectors(char driveLetter, int sectorsize)
{
string fsName = Utilities.GetFileSystemName(driveLetter);
// Gets a handle to the physical disk
IntPtr hDisk = Utilities.CreateFile($"\\\\.\\{driveLetter}:",
FileAccess.Read,
FileShare.ReadWrite,
IntPtr.Zero,
FileMode.Open,
0,
IntPtr.Zero);
// If we have a good pointer
if (hDisk.ToInt32() != -1)
{
// Setup vars
byte[] buffer = new byte[sectorsize];
IntPtr pt = IntPtr.Zero;
NativeOverlapped no = new NativeOverlapped();
// Set initial offset
Utilities.SetFilePointerEx(
hDisk,
0,
ref pt,
Utilities.FileBegin);
// Read a whole sector
while (true)
{
buffer = new byte[sectorsize];
Utilities.ReadFileEx(
hDisk,
buffer,
(uint)sectorsize,
ref no,
null);
Utilities.SetFilePointerEx(
hDisk,
sectorsize,
ref pt,
Utilities.FileCurrent);
}
}
Utilities.CloseHandle(hDisk);
return null;
}
}
}