mirror of
https://github.com/SabreTools/MPF.git
synced 2026-07-02 17:24:48 +00:00
Protection, Progress, and (Possibly) Empty Drives (#93)
* Include but mark inactive drives (fixes #87) * Add more checks for the active flag * Force users to choose on dump * Fix quotes * Update SolidShield 1 * Select first active by default * Add TODO * Add dumping progress indicator * Clamp runtime * Add first textfile scans; EA CdKey * Slightly better executable detection * Better file type detection * Get as much into magic number checks as possible * Nicer formatting * Trailing slash * Add back for benefit of the doubt * Remove dead code * Safer cabinet scanning * Remove iXcomp; Add Unshield * Fix build, add more comments * Post-merge cleanup * Add a new log line * Make protection scan mechanics easier to see * Add a space
This commit is contained in:
@@ -9,7 +9,7 @@ namespace DICUI.Test.Utilities
|
||||
public void DriveConstructorsTest()
|
||||
{
|
||||
Assert.True(Drive.Floppy('a').IsFloppy);
|
||||
Assert.False(Drive.Optical('d', "test").IsFloppy);
|
||||
Assert.False(Drive.Optical('d', "test", true).IsFloppy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace DICUI.Test
|
||||
var env = new DumpEnvironment
|
||||
{
|
||||
DICParameters = new Parameters(parameters),
|
||||
Drive = isFloppy ? Drive.Floppy(letter) : Drive.Optical(letter, ""),
|
||||
Drive = isFloppy ? Drive.Floppy(letter) : Drive.Optical(letter, "", true),
|
||||
Type = mediaType,
|
||||
};
|
||||
|
||||
|
||||
@@ -92,6 +92,9 @@
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="zlib.net, Version=1.0.3.0, Culture=neutral, PublicKeyToken=47d7877cb3620160">
|
||||
<HintPath>..\packages\zlib.net.1.0.4.0\lib\zlib.net.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
@@ -103,7 +106,18 @@
|
||||
</Compile>
|
||||
<Compile Include="Data\Constants.cs" />
|
||||
<Compile Include="External\BurnOut\EVORE.cs" />
|
||||
<Compile Include="External\iXcomp\IXComp.cs" />
|
||||
<Compile Include="External\Unshield\CabDescriptor.cs" />
|
||||
<Compile Include="External\Unshield\CommonHeader.cs" />
|
||||
<Compile Include="External\Unshield\FileDescriptor.cs" />
|
||||
<Compile Include="External\Unshield\Header.cs" />
|
||||
<None Include="External\Unshield\LICENSE" />
|
||||
<Compile Include="External\Unshield\OffsetList.cs" />
|
||||
<Compile Include="External\Unshield\StringBuffer.cs" />
|
||||
<Compile Include="External\Unshield\UnshieldCabinet.cs" />
|
||||
<Compile Include="External\Unshield\UnshieldComponent.cs" />
|
||||
<Compile Include="External\Unshield\UnshieldFileGroup.cs" />
|
||||
<Compile Include="External\Unshield\UnshieldReader.cs" />
|
||||
<Compile Include="External\Unshield\VolumeHeader.cs" />
|
||||
<Compile Include="Options.cs" />
|
||||
<Compile Include="External\BurnOut\ProtectionFind.cs" />
|
||||
<Compile Include="UI\KnownSystemComboBoxItem.cs" />
|
||||
@@ -188,15 +202,6 @@
|
||||
<Content Include="mspack.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Programs\i3comp.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Programs\i5comp.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Programs\i6comp.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -5,6 +5,7 @@
|
||||
/// </summary>
|
||||
public static class UIElements
|
||||
{
|
||||
public const string DiscNotDetected = "Disc Not Detected";
|
||||
public const string StartDumping = "Start Dumping";
|
||||
public const string StopDumping = "Stop Dumping";
|
||||
|
||||
|
||||
168
DICUI/External/BurnOut/ProtectionFind.cs
vendored
168
DICUI/External/BurnOut/ProtectionFind.cs
vendored
@@ -21,7 +21,7 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DICUI.External.iXcomp;
|
||||
using DICUI.External.Unshield;
|
||||
using LibMSPackN;
|
||||
|
||||
namespace DICUI.External.BurnOut
|
||||
@@ -72,7 +72,7 @@ namespace DICUI.External.BurnOut
|
||||
protections[file] = mappings[Path.GetExtension(file)];
|
||||
|
||||
// Now check to see if the file contains any additional information
|
||||
string protectionname = ScanInFile(file).Replace("" + (char)0x00, "");
|
||||
string protectionname = ScanInFile(file)?.Replace("" + (char)0x00, "");
|
||||
if (!String.IsNullOrEmpty(protectionname))
|
||||
protections[file] = protectionname;
|
||||
}
|
||||
@@ -96,14 +96,28 @@ namespace DICUI.External.BurnOut
|
||||
/// </remarks>
|
||||
private static string ScanInFile(string file)
|
||||
{
|
||||
// Get the extension for certain checks
|
||||
string extension = Path.GetExtension(file).ToLower().TrimStart('.');
|
||||
|
||||
#region EXE/DLL/ICD/DAT Content Checks
|
||||
// Read the first 8 bytes to get the file type
|
||||
string magic = "";
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(file)))
|
||||
{
|
||||
magic = new String(br.ReadChars(8));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the issue was, we can't open the file
|
||||
return null;
|
||||
}
|
||||
|
||||
if (extension == "exe" || extension == "ex_"
|
||||
|| extension == "dll" || extension == "dl_"
|
||||
|| extension == "dat"
|
||||
|| extension == "icd")
|
||||
#region Executable Content Checks
|
||||
|
||||
// Windows Executable and DLL
|
||||
if (magic.StartsWith("MZ"))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -206,8 +220,8 @@ namespace DICUI.External.BurnOut
|
||||
if ((position = FileContent.IndexOf("" + (char)0xCA + (char)0xDD + (char)0xDD + (char)0xAC + (char)0x03)) > -1)
|
||||
return "SecuROM " + GetSecuROM4and5Version(file, position);
|
||||
|
||||
if (FileContent.Contains(".securom"))
|
||||
//if (FileContent.StartsWith(".securom" + (char)0xE0 + (char)0xC0))
|
||||
if (FileContent.Contains(".securom")
|
||||
|| FileContent.StartsWith(".securom" + (char)0xE0 + (char)0xC0))
|
||||
return "SecuROM " + GetSecuROM7Version(file);
|
||||
|
||||
if (FileContent.Contains("_and_play.dll" + (char)0x00 + "drm_pagui_doit"))
|
||||
@@ -220,17 +234,15 @@ namespace DICUI.External.BurnOut
|
||||
|
||||
if ((position = FileContent.IndexOf("" + (char)0xEF + (char)0xBE + (char)0xAD + (char)0xDE)) > -1)
|
||||
{
|
||||
position--; // TODO: Verify this subtract
|
||||
if (FileContent.Substring(position + 5, 3) == "" + (char)0x00 + (char)0x00 + (char)0x00
|
||||
&& FileContent.Substring(position + 16, 4) == "" + (char)0x00 + (char)0x10 + (char)0x00 + (char)0x00)
|
||||
return "SolidShield 1";
|
||||
return "SolidShield 1 (SolidShield EXE Wrapper)";
|
||||
else
|
||||
{
|
||||
string version = GetFileVersion(file);
|
||||
string desc = FileVersionInfo.GetVersionInfo(file).FileDescription.ToLower();
|
||||
if (!string.IsNullOrEmpty(version) && desc.Contains("solidshield"))
|
||||
return "SolidShield Core.dll " + version;
|
||||
//return "SolidShield EXE Wrapper";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +267,7 @@ namespace DICUI.External.BurnOut
|
||||
+ "o" + (char)0x00 + "n" + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00);
|
||||
if (position > -1)
|
||||
{
|
||||
position--;
|
||||
position--; // TODO: Verify this subtract
|
||||
return "SolidShield 2 + Tagès " + FileContent.Substring(position + 0x38, 1) + "." + FileContent.Substring(position + 0x38 + 4, 1) + "." + FileContent.Substring(position + 0x38 + 8, 1) + "." + FileContent.Substring(position + 0x38 + 12, 1);
|
||||
}
|
||||
else
|
||||
@@ -342,8 +354,25 @@ namespace DICUI.External.BurnOut
|
||||
|
||||
#region Textfile Content Checks
|
||||
|
||||
if (extension == "txt" || extension == "rtf" || extension == "doc" || extension == "docx")
|
||||
if (magic.StartsWith("{\rtf") // Rich Text File
|
||||
|| magic.StartsWith("" + (char)0xd0 + (char)0xcf + (char)0x11 + (char)0xe0 + (char)0xa1 + (char)0xb1 + (char)0x1a + (char)0xe1) // Microsoft Office File (old)
|
||||
|| extension == "txt") // Generic textfile (no header)
|
||||
{
|
||||
try
|
||||
{
|
||||
StreamReader sr = File.OpenText(file);
|
||||
string FileContent = sr.ReadToEnd().ToLower();
|
||||
sr.Close();
|
||||
|
||||
// CD-Key
|
||||
if (FileContent.Contains("a valid serial number is required")
|
||||
|| FileContent.Contains("serial number is located"))
|
||||
return "CD-Key / Serial";
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was
|
||||
}
|
||||
// No-op
|
||||
}
|
||||
|
||||
@@ -351,74 +380,90 @@ namespace DICUI.External.BurnOut
|
||||
|
||||
#region Archive Content Checks
|
||||
|
||||
if (extension == "7z" || extension == "rar" || extension == "zip")
|
||||
// 7-zip
|
||||
if (magic.StartsWith("7z" + (char)0xbc + (char)0xaf + (char)0x27 + (char)0x1c))
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
else if (extension == "cab")
|
||||
{
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// InstallShield CAB
|
||||
else if (magic.StartsWith("ISc"))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Read the first 4 bytes to get the archive type
|
||||
string magic = "";
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(file)))
|
||||
{
|
||||
magic = new String(br.ReadChars(4));
|
||||
}
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Microsoft CAB - "MSCF"
|
||||
if (magic.StartsWith("MSCF"))
|
||||
UnshieldCabinet cabfile = UnshieldCabinet.Open(file);
|
||||
for (int i = 0; i < cabfile.FileCount; i++)
|
||||
{
|
||||
MSCabinet cabfile = new MSCabinet(file);
|
||||
foreach (var sub in cabfile.GetFiles())
|
||||
string tempFileName = Path.Combine(tempPath, cabfile.FileName(i));
|
||||
if (cabfile.FileSave(i, tempFileName))
|
||||
{
|
||||
string tempfile = Path.Combine(tempPath, sub.Filename);
|
||||
sub.ExtractTo(tempfile);
|
||||
string protection = ScanInFile(tempfile);
|
||||
File.Delete(tempfile);
|
||||
|
||||
if (!String.IsNullOrEmpty(protection))
|
||||
{
|
||||
return protection;
|
||||
}
|
||||
}
|
||||
}
|
||||
// InstallShield CAB - "ISc"
|
||||
else if (magic.StartsWith("ISc"))
|
||||
{
|
||||
IXComp.ListFiles(file, out int version);
|
||||
IXComp.ExtractAll(file, tempPath, version);
|
||||
var files = Directory.GetFiles(tempPath, "*", SearchOption.AllDirectories);
|
||||
files.Select(f => (new FileInfo(f).IsReadOnly = false));
|
||||
foreach (var sub in files)
|
||||
{
|
||||
string protection = ScanInFile(sub);
|
||||
string protection = ScanInFile(tempFileName);
|
||||
try
|
||||
{
|
||||
File.Delete(sub);
|
||||
File.Delete(tempFileName);
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (!String.IsNullOrEmpty(protection))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch { }
|
||||
return protection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Microsoft CAB
|
||||
else if (magic.StartsWith("MSCF"))
|
||||
{
|
||||
try
|
||||
{
|
||||
// We had access issues so we ignore
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
MSCabinet cabfile = new MSCabinet(file);
|
||||
foreach (var sub in cabfile.GetFiles())
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
string tempfile = Path.Combine(tempPath, sub.Filename);
|
||||
sub.ExtractTo(tempfile);
|
||||
string protection = ScanInFile(tempfile);
|
||||
File.Delete(tempfile);
|
||||
|
||||
if (!String.IsNullOrEmpty(protection))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch { }
|
||||
return protection;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// PKZIP
|
||||
else if (magic.StartsWith("PK" + (char)03 + (char)04)
|
||||
|| magic.StartsWith("PK" + (char)05 + (char)06)
|
||||
|| magic.StartsWith("PK" + (char)07 + (char)08))
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
// RAR
|
||||
|
||||
else if (magic.StartsWith("Rar!"))
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1192,10 +1237,13 @@ namespace DICUI.External.BurnOut
|
||||
// dotFuscator - Not a protection
|
||||
//mapping["DotfuscatorAttribute"] = "dotFuscator";
|
||||
|
||||
// EA CdKey Registration Module
|
||||
mapping["ereg.ea-europe.com"] = "EA CdKey Registration Module";
|
||||
|
||||
// EXE Stealth
|
||||
mapping["??[[__[[_" + (char)0x00 + "{{" + (char)0x0
|
||||
+ (char)0x00 + "{{" + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0
|
||||
+ (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + "?;;??;;??"] = "EXE Stealth";
|
||||
+ (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + "?;??;??"] = "EXE Stealth";
|
||||
|
||||
// Games for Windows - Live
|
||||
mapping["xlive.dll"] = "Games for Windows - Live";
|
||||
|
||||
15
DICUI/External/Unshield/CabDescriptor.cs
vendored
Normal file
15
DICUI/External/Unshield/CabDescriptor.cs
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class CabDescriptor
|
||||
{
|
||||
public uint FileTableOffset; /* 0c */
|
||||
public uint FileTableSize; /* 14 */
|
||||
public uint FileTableSize2; /* 18 */
|
||||
public uint DirectoryCount; /* 1c */
|
||||
public uint FileCount; /* 28 */
|
||||
public uint FileTableOffset2; /* 2c */
|
||||
|
||||
public uint[] FileGroupOffsets = new uint[Constants.MAX_FILE_GROUP_COUNT]; /* 0x3e */
|
||||
public uint[] ComponentOffsets = new uint[Constants.MAX_COMPONENT_COUNT]; /* 0x15a */
|
||||
}
|
||||
}
|
||||
48
DICUI/External/Unshield/CommonHeader.cs
vendored
Normal file
48
DICUI/External/Unshield/CommonHeader.cs
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class CommonHeader
|
||||
{
|
||||
public uint Signature; // 00
|
||||
public uint Version;
|
||||
public uint VolumeInfo;
|
||||
public uint CabDescriptorOffset;
|
||||
public uint CabDescriptorSize; // 10
|
||||
|
||||
/// <summary>
|
||||
/// Populate a CommonHeader from an input buffer
|
||||
/// </summary>
|
||||
public static bool ReadCommonHeader(ref byte[] buffer, int bufferPointer, CommonHeader common)
|
||||
{
|
||||
common.Signature = BitConverter.ToUInt32(buffer, bufferPointer); bufferPointer += 4;
|
||||
|
||||
if (common.Signature != Constants.CAB_SIGNATURE)
|
||||
{
|
||||
// unshield_error("Invalid file signature");
|
||||
|
||||
if (common.Signature == Constants.MSCF_SIGNATURE)
|
||||
{
|
||||
// unshield_warning("Found Microsoft Cabinet header. Use cabextract (http://www.kyz.uklinux.net/cabextract.php) to unpack this file.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
common.Version = BitConverter.ToUInt32(buffer, bufferPointer); bufferPointer += 4;
|
||||
common.VolumeInfo = BitConverter.ToUInt32(buffer, bufferPointer); bufferPointer += 4;
|
||||
common.CabDescriptorOffset = BitConverter.ToUInt32(buffer, bufferPointer); bufferPointer += 4;
|
||||
common.CabDescriptorSize = BitConverter.ToUInt32(buffer, bufferPointer); bufferPointer += 4;
|
||||
|
||||
/*
|
||||
unshield_trace("Common header: %08x %08x %08x %08x",
|
||||
common->version,
|
||||
ommon->volume_info,
|
||||
common->cab_descriptor_offset,
|
||||
common->cab_descriptor_size);
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
DICUI/External/Unshield/FileDescriptor.cs
vendored
Normal file
17
DICUI/External/Unshield/FileDescriptor.cs
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class FileDescriptor
|
||||
{
|
||||
public uint NameOffset;
|
||||
public uint DirectoryIndex;
|
||||
public ushort Flags;
|
||||
public uint ExpandedSize;
|
||||
public uint CompressedSize;
|
||||
public uint DataOffset;
|
||||
public byte[] Md5 = new byte[16];
|
||||
public ushort Volume;
|
||||
public uint LinkPrevious;
|
||||
public uint LinkNext;
|
||||
public byte LinkFlags;
|
||||
}
|
||||
}
|
||||
240
DICUI/External/Unshield/Header.cs
vendored
Normal file
240
DICUI/External/Unshield/Header.cs
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class Header
|
||||
{
|
||||
public Header Next;
|
||||
public int Index;
|
||||
public byte[] Data;
|
||||
public int DataPointer = 0;
|
||||
public long Size;
|
||||
public int MajorVersion;
|
||||
|
||||
// Shortcuts
|
||||
public CommonHeader Common = new CommonHeader();
|
||||
public CabDescriptor Cab = new CabDescriptor();
|
||||
public uint[] FileTable;
|
||||
public int FileTablePointer;
|
||||
public FileDescriptor[] FileDescriptors;
|
||||
public int FileDescriptorsPointer;
|
||||
|
||||
public int ComponentCount;
|
||||
public UnshieldComponent[] Components;
|
||||
public int ComponentsPointer;
|
||||
|
||||
public int FileGroupCount;
|
||||
public UnshieldFileGroup[] FileGroups;
|
||||
public int FileGroupsCounter;
|
||||
|
||||
public StringBuffer StringBuffer = new StringBuffer();
|
||||
|
||||
/// <summary>
|
||||
/// Add a new StringBuffer to the existing list
|
||||
/// </summary>
|
||||
public StringBuffer AddStringBuffer()
|
||||
{
|
||||
StringBuffer result = new StringBuffer();
|
||||
result.Next = this.StringBuffer;
|
||||
this.StringBuffer = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the CabDescriptor from header data
|
||||
/// </summary>
|
||||
public bool GetCabDescriptor()
|
||||
{
|
||||
if (this.Common.CabDescriptorSize > 0)
|
||||
{
|
||||
int p = (int)(this.Common.CabDescriptorOffset);
|
||||
|
||||
p += 0xc;
|
||||
this.Cab.FileTableOffset = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
p += 4;
|
||||
this.Cab.FileTableSize = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
this.Cab.FileTableSize2 = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
this.Cab.DirectoryCount = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
p += 8;
|
||||
this.Cab.FileCount = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
this.Cab.FileTableOffset2 = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
|
||||
// assert((p - (header->data + header->common.cab_descriptor_offset)) == 0x30);
|
||||
|
||||
if (this.Cab.FileTableSize != this.Cab.FileTableSize2)
|
||||
{
|
||||
// unshield_warning("File table sizes do not match");
|
||||
}
|
||||
|
||||
/*
|
||||
unshield_trace("Cabinet descriptor: %08x %08x %08x %08x",
|
||||
header->cab.file_table_offset,
|
||||
header->cab.file_table_size,
|
||||
header->cab.file_table_size2,
|
||||
header->cab.file_table_offset2
|
||||
);
|
||||
|
||||
unshield_trace("Directory count: %i", header->cab.directory_count);
|
||||
unshield_trace("File count: %i", header->cab.file_count);
|
||||
*/
|
||||
|
||||
p += 0xe;
|
||||
|
||||
for (int i = 0; i < Constants.MAX_FILE_GROUP_COUNT; i++)
|
||||
{
|
||||
this.Cab.FileGroupOffsets[i] = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Constants.MAX_COMPONENT_COUNT; i++)
|
||||
{
|
||||
this.Cab.ComponentOffsets[i] = this.Cab.FileGroupOffsets[i] = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unshield_error("No CAB descriptor available!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the CommonHeader from header data
|
||||
/// </summary>
|
||||
public bool GetCommmonHeader()
|
||||
{
|
||||
return CommonHeader.ReadCommonHeader(ref this.Data, this.DataPointer, this.Common);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the component list from header data
|
||||
/// </summary>
|
||||
public bool GetComponents()
|
||||
{
|
||||
int count = 0;
|
||||
int available = 16;
|
||||
|
||||
this.Components = new UnshieldComponent[available];
|
||||
|
||||
for (int i = 0; i < Constants.MAX_COMPONENT_COUNT; i++)
|
||||
{
|
||||
if (this.Cab.ComponentOffsets[i] > 0)
|
||||
{
|
||||
OffsetList list = new OffsetList();
|
||||
|
||||
list.NextOffset = this.Cab.ComponentOffsets[i];
|
||||
|
||||
while (list.NextOffset > 0)
|
||||
{
|
||||
int p = GetDataOffset(list.NextOffset);
|
||||
|
||||
list.NameOffset = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
list.DescriptorOffset = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
list.NextOffset = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
|
||||
if (count == available)
|
||||
{
|
||||
available <<= 1;
|
||||
Array.Resize(ref this.Components, available);
|
||||
}
|
||||
|
||||
this.Components[count++] = UnshieldComponent.Create(this, list.DescriptorOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.ComponentCount = count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the real data offset
|
||||
/// </summary>
|
||||
public int GetDataOffset(uint offset)
|
||||
{
|
||||
if (offset > 0)
|
||||
return (int)(this.Common.CabDescriptorOffset + offset);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the file group list from header data
|
||||
/// </summary>
|
||||
public bool GetFileGroups()
|
||||
{
|
||||
int count = 0;
|
||||
int available = 16;
|
||||
|
||||
this.FileGroups = new UnshieldFileGroup[available];
|
||||
|
||||
for (int i = 0; i < Constants.MAX_FILE_GROUP_COUNT; i++)
|
||||
{
|
||||
if (this.Cab.FileGroupOffsets[i] > 0)
|
||||
{
|
||||
OffsetList list = new OffsetList();
|
||||
|
||||
list.NextOffset = this.Cab.FileGroupOffsets[i];
|
||||
|
||||
while (list.NextOffset > 0)
|
||||
{
|
||||
int p = GetDataOffset(list.NextOffset);
|
||||
|
||||
list.NameOffset = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
list.DescriptorOffset = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
list.NextOffset = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
|
||||
if (count == available)
|
||||
{
|
||||
available <<= 1;
|
||||
Array.Resize(ref this.FileGroups, available);
|
||||
}
|
||||
|
||||
this.FileGroups[count++] = UnshieldFileGroup.Create(this, list.DescriptorOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.FileGroupCount = count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the file table from header data
|
||||
/// </summary>
|
||||
public bool GetFileTable()
|
||||
{
|
||||
int p = (int)(this.Common.CabDescriptorOffset +
|
||||
this.Cab.FileTableOffset);
|
||||
int count = (int)(this.Cab.DirectoryCount + this.Cab.FileCount);
|
||||
|
||||
this.FileTable = new uint[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
this.FileTable[i] = BitConverter.ToUInt32(this.Data, p); p += 4;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the UInt32 at the given offset in the header data as a string
|
||||
/// </summary>
|
||||
public string GetString(uint offset)
|
||||
{
|
||||
return GetUTF8String(this.Data, GetDataOffset(offset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a UInt32 read from a buffer to a string
|
||||
/// </summary>
|
||||
public string GetUTF8String(byte[] buffer, int bufferPointer)
|
||||
{
|
||||
return BitConverter.ToUInt32(buffer, bufferPointer).ToString("X8");
|
||||
}
|
||||
}
|
||||
}
|
||||
24
DICUI/External/Unshield/LICENSE
vendored
Normal file
24
DICUI/External/Unshield/LICENSE
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2003 David Eriksson <twogood@users.sourceforge.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Addendum:
|
||||
|
||||
The code in this part of the project has been adapted from the original source
|
||||
by Matt Nadareski for DICUI.
|
||||
9
DICUI/External/Unshield/OffsetList.cs
vendored
Normal file
9
DICUI/External/Unshield/OffsetList.cs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class OffsetList
|
||||
{
|
||||
public uint NameOffset;
|
||||
public uint DescriptorOffset;
|
||||
public uint NextOffset;
|
||||
}
|
||||
}
|
||||
8
DICUI/External/Unshield/StringBuffer.cs
vendored
Normal file
8
DICUI/External/Unshield/StringBuffer.cs
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class StringBuffer
|
||||
{
|
||||
public StringBuffer Next;
|
||||
public string String;
|
||||
}
|
||||
}
|
||||
1180
DICUI/External/Unshield/UnshieldCabinet.cs
vendored
Normal file
1180
DICUI/External/Unshield/UnshieldCabinet.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
61
DICUI/External/Unshield/UnshieldComponent.cs
vendored
Normal file
61
DICUI/External/Unshield/UnshieldComponent.cs
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class UnshieldComponent
|
||||
{
|
||||
public string Name;
|
||||
public uint FileGroupCount;
|
||||
public string[] FileGroupNames;
|
||||
public int FileGroupNamesPointer = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new UnshieldComponent from a header and data offset
|
||||
/// </summary>
|
||||
public static UnshieldComponent Create(Header header, uint offset)
|
||||
{
|
||||
UnshieldComponent self = new UnshieldComponent();
|
||||
int bufferPointer = header.GetDataOffset(offset);
|
||||
uint fileGroupTableOffset;
|
||||
|
||||
self.Name = header.GetString((uint)bufferPointer); bufferPointer += 4;
|
||||
|
||||
switch (header.MajorVersion)
|
||||
{
|
||||
case 0:
|
||||
case 5:
|
||||
bufferPointer += 0x6c;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
default:
|
||||
bufferPointer += 0x6b;
|
||||
break;
|
||||
}
|
||||
|
||||
self.FileGroupCount = BitConverter.ToUInt16(header.Data, bufferPointer); bufferPointer += 2;
|
||||
if (self.FileGroupCount > Constants.MAX_FILE_GROUP_COUNT)
|
||||
return default(UnshieldComponent);
|
||||
|
||||
self.FileGroupNames = new string[self.FileGroupCount];
|
||||
|
||||
fileGroupTableOffset = BitConverter.ToUInt32(header.Data, bufferPointer); bufferPointer += 4;
|
||||
|
||||
bufferPointer = header.GetDataOffset(fileGroupTableOffset);
|
||||
|
||||
for (int i = 0; i < self.FileGroupCount; i++)
|
||||
{
|
||||
self.FileGroupNames[i] = header.GetString((uint)bufferPointer); bufferPointer += 4; // TODO: Verify GetString
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
DICUI/External/Unshield/UnshieldFileGroup.cs
vendored
Normal file
36
DICUI/External/Unshield/UnshieldFileGroup.cs
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class UnshieldFileGroup
|
||||
{
|
||||
public string Name;
|
||||
public uint FirstFile;
|
||||
public uint LastFile;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new UnshieldFileGroup from a header and data offset
|
||||
/// </summary>
|
||||
public static UnshieldFileGroup Create(Header header, uint offset)
|
||||
{
|
||||
UnshieldFileGroup self = new UnshieldFileGroup();
|
||||
int pPointer = header.GetDataOffset(offset);
|
||||
|
||||
// unshield_trace("File group descriptor offset: %08x", offset);
|
||||
|
||||
self.Name = header.GetString(BitConverter.ToUInt32(header.Data, pPointer)); pPointer += 4;
|
||||
|
||||
if (header.MajorVersion <= 5)
|
||||
pPointer += 0x48;
|
||||
else
|
||||
pPointer += 0x12;
|
||||
|
||||
self.FirstFile = BitConverter.ToUInt32(header.Data, pPointer); pPointer += 4;
|
||||
self.LastFile = BitConverter.ToUInt32(header.Data, pPointer); pPointer += 4;
|
||||
|
||||
// unshield_trace("File group %08x first file = %i, last file = %i", offset, self->first_file, self->last_file);
|
||||
|
||||
return self;
|
||||
}
|
||||
}
|
||||
}
|
||||
327
DICUI/External/Unshield/UnshieldReader.cs
vendored
Normal file
327
DICUI/External/Unshield/UnshieldReader.cs
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class UnshieldReader
|
||||
{
|
||||
public UnshieldCabinet Unshield;
|
||||
public uint Index;
|
||||
public FileDescriptor FileDescriptor;
|
||||
public int Volume;
|
||||
public FileStream VolumeFile;
|
||||
public VolumeHeader VolumeHeader;
|
||||
public uint VolumeBytesLeft;
|
||||
public uint ObfuscationOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new UnshieldReader from an existing cabinet, index, and file descriptor
|
||||
/// </summary>
|
||||
public static UnshieldReader Create(UnshieldCabinet unshield, int index, FileDescriptor fileDescriptor)
|
||||
{
|
||||
UnshieldReader reader = new UnshieldReader();
|
||||
if (reader == null)
|
||||
return null;
|
||||
|
||||
reader.Unshield = unshield;
|
||||
reader.Index = (uint)index;
|
||||
reader.FileDescriptor = fileDescriptor;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
if (!reader.OpenVolume(fileDescriptor.Volume))
|
||||
{
|
||||
// unshield_error("Failed to open volume %i", file_descriptor->volume);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Start with the correct volume for IS5 cabinets
|
||||
if (reader.Unshield.HeaderList.MajorVersion <= 5 &&
|
||||
index > (int)reader.VolumeHeader.LastFileIndex)
|
||||
{
|
||||
// unshield_trace("Trying next volume...");
|
||||
fileDescriptor.Volume++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of the current object
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
VolumeFile?.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the volume at the inputted index
|
||||
/// </summary>
|
||||
public bool OpenVolume(int volume)
|
||||
{
|
||||
bool success = false;
|
||||
uint dataOffset = 0;
|
||||
uint volumeBytesLeftCompressed;
|
||||
uint volumeBytesLeftExpanded;
|
||||
CommonHeader commonHeader = new CommonHeader();
|
||||
|
||||
// unshield_trace("Open volume %i", volume);
|
||||
|
||||
this.VolumeFile?.Close();
|
||||
|
||||
this.VolumeFile = this.Unshield.OpenFileForReading(volume, Constants.CABINET_SUFFIX);
|
||||
if (this.VolumeFile == null)
|
||||
{
|
||||
// unshield_error("Failed to open input cabinet file %i", volume);
|
||||
return success;
|
||||
}
|
||||
|
||||
{
|
||||
byte[] tmp = new byte[Constants.COMMON_HEADER_SIZE];
|
||||
int p = 0;
|
||||
|
||||
if (Constants.COMMON_HEADER_SIZE !=
|
||||
this.VolumeFile.Read(tmp, 0, Constants.COMMON_HEADER_SIZE))
|
||||
return success;
|
||||
|
||||
if (!CommonHeader.ReadCommonHeader(ref tmp, p, commonHeader))
|
||||
return success;
|
||||
}
|
||||
|
||||
this.VolumeHeader = new VolumeHeader();
|
||||
|
||||
switch (this.Unshield.HeaderList.MajorVersion)
|
||||
{
|
||||
case 0:
|
||||
case 5:
|
||||
{
|
||||
byte[] fiveHeader = new byte[Constants.VOLUME_HEADER_SIZE_V5];
|
||||
int p = 0;
|
||||
|
||||
if (Constants.VOLUME_HEADER_SIZE_V5 !=
|
||||
this.VolumeFile.Read(fiveHeader, 0, Constants.VOLUME_HEADER_SIZE_V5))
|
||||
return success;
|
||||
|
||||
this.VolumeHeader.DataOffset = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
|
||||
/*
|
||||
if (READ_UINT32(p))
|
||||
unshield_trace("Unknown = %08x", READ_UINT32(p));
|
||||
*/
|
||||
|
||||
/* unknown */
|
||||
p += 4;
|
||||
this.VolumeHeader.FirstFileIndex = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileIndex = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileOffset = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileSizeExpanded = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileSizeCompressed = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileOffset = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileSizeExpanded = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileSizeCompressed = BitConverter.ToUInt32(fiveHeader, p); p += 4;
|
||||
|
||||
if (this.VolumeHeader.LastFileOffset == 0)
|
||||
this.VolumeHeader.LastFileOffset = Int32.MaxValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
default:
|
||||
{
|
||||
byte[] sixHeader = new byte[Constants.VOLUME_HEADER_SIZE_V6];
|
||||
int p = 0;
|
||||
|
||||
if (Constants.VOLUME_HEADER_SIZE_V6 !=
|
||||
this.VolumeFile.Read(sixHeader, 0, Constants.VOLUME_HEADER_SIZE_V6))
|
||||
return success;
|
||||
|
||||
this.VolumeHeader.DataOffset = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.DataOffsetHigh = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileIndex = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileIndex = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileOffset = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileOffsetHigh = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileSizeExpanded = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileSizeExpandedHigh = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileSizeCompressed = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.FirstFileSizeCompressedHigh = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileOffset = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileOffsetHigh = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileSizeExpanded = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileSizeExpandedHigh = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileSizeCompressed = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
this.VolumeHeader.LastFileSizeCompressedHigh = BitConverter.ToUInt32(sixHeader, p); p += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
unshield_trace("First file index = %i, last file index = %i",
|
||||
reader->volume_header.first_file_index, reader->volume_header.last_file_index);
|
||||
unshield_trace("First file offset = %08x, last file offset = %08x",
|
||||
reader->volume_header.first_file_offset, reader->volume_header.last_file_offset);
|
||||
*/
|
||||
|
||||
// enable support for split archives for IS5
|
||||
if (this.Unshield.HeaderList.MajorVersion == 5)
|
||||
{
|
||||
if (this.Index < (this.Unshield.HeaderList.Cab.FileCount - 1) &&
|
||||
this.Index == this.VolumeHeader.LastFileIndex &&
|
||||
this.VolumeHeader.LastFileSizeCompressed != this.FileDescriptor.CompressedSize)
|
||||
{
|
||||
// unshield_trace("IS5 split file last in volume");
|
||||
this.FileDescriptor.Flags |= Constants.FILE_SPLIT;
|
||||
}
|
||||
else if (this.Index > 0 &&
|
||||
this.Index == this.VolumeHeader.FirstFileIndex &&
|
||||
this.VolumeHeader.FirstFileSizeCompressed != this.FileDescriptor.CompressedSize)
|
||||
{
|
||||
// unshield_trace("IS5 split file first in volume");
|
||||
this.FileDescriptor.Flags |= Constants.FILE_SPLIT;
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.FileDescriptor.Flags & Constants.FILE_SPLIT) != 0)
|
||||
{
|
||||
// unshield_trace(/*"Total bytes left = 0x08%x, "*/"previous data offset = 0x08%x", /*total_bytes_left, */ data_offset);
|
||||
|
||||
if (this.Index == this.VolumeHeader.LastFileIndex && this.VolumeHeader.LastFileOffset != 0x7FFFFFFF)
|
||||
{
|
||||
// can be first file too
|
||||
// unshield_trace("Index %i is last file in cabinet file %i", reader->index, volume);
|
||||
|
||||
dataOffset = this.VolumeHeader.LastFileOffset;
|
||||
volumeBytesLeftExpanded = this.VolumeHeader.LastFileSizeExpanded;
|
||||
volumeBytesLeftCompressed = this.VolumeHeader.LastFileSizeCompressed;
|
||||
}
|
||||
else if (this.Index == this.VolumeHeader.FirstFileIndex)
|
||||
{
|
||||
// unshield_trace("Index %i is first file in cabinet file %i", reader->index, volume);
|
||||
|
||||
dataOffset = this.VolumeHeader.FirstFileOffset;
|
||||
volumeBytesLeftExpanded = this.VolumeHeader.FirstFileSizeExpanded;
|
||||
volumeBytesLeftCompressed = this.VolumeHeader.FirstFileSizeCompressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
success = true;
|
||||
return success;
|
||||
}
|
||||
|
||||
// unshield_trace("Will read 0x%08x bytes from offset 0x%08x", volume_bytes_left_compressed, data_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOffset = this.FileDescriptor.DataOffset;
|
||||
volumeBytesLeftExpanded = this.FileDescriptor.ExpandedSize;
|
||||
volumeBytesLeftCompressed = this.FileDescriptor.CompressedSize;
|
||||
}
|
||||
|
||||
if ((this.FileDescriptor.Flags & Constants.FILE_COMPRESSED) != 0)
|
||||
this.VolumeBytesLeft = volumeBytesLeftCompressed;
|
||||
else
|
||||
this.VolumeBytesLeft = volumeBytesLeftExpanded;
|
||||
|
||||
this.VolumeFile.Seek(dataOffset, SeekOrigin.Begin);
|
||||
|
||||
this.Volume = volume;
|
||||
success = true;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deobfuscate a buffer
|
||||
/// </summary>
|
||||
public void Deobfuscate(ref byte[] buffer, ref int bufferPointer, int size)
|
||||
{
|
||||
this.Deobfuscate(ref buffer, ref bufferPointer, size, ref this.ObfuscationOffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a certain number of bytes from the current volume
|
||||
/// </summary>
|
||||
public bool Read(ref byte[] buffer, ref int bufferPointer, int size)
|
||||
{
|
||||
bool success = false;
|
||||
int p = bufferPointer;
|
||||
int bytesLeft = size;
|
||||
|
||||
// unshield_trace("unshield_reader_read start: bytes_left = 0x%x, volume_bytes_left = 0x%x", bytes_left, reader->volume_bytes_left);
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
// Read as much as possible from this volume
|
||||
int bytesToRead = (int)Math.Min(bytesLeft, this.VolumeBytesLeft);
|
||||
|
||||
// unshield_trace("Trying to read 0x%x bytes from offset %08x in volume %i", bytes_to_read, ftell(reader->volume_file), reader->volume);
|
||||
if (bytesToRead == 0)
|
||||
{
|
||||
// unshield_error("bytes_to_read can't be zero");
|
||||
return success;
|
||||
}
|
||||
|
||||
if (bytesToRead != this.VolumeFile.Read(buffer, p, bytesToRead))
|
||||
{
|
||||
// unshield_error("Failed to read 0x%08x bytes of file %i (%s) from volume %i. Current offset = 0x%08x", bytes_to_read, reader->index, unshield_file_name(reader->unshield, reader->index), reader->volume, ftell(reader->volume_file));
|
||||
return success;
|
||||
}
|
||||
|
||||
bytesLeft -= bytesToRead;
|
||||
this.VolumeBytesLeft -= (uint)bytesToRead;
|
||||
|
||||
// unshield_trace("bytes_left = %i, volume_bytes_left = %i", bytes_left, reader->volume_bytes_left);
|
||||
|
||||
if (bytesLeft == 0)
|
||||
break;
|
||||
|
||||
p += bytesToRead;
|
||||
|
||||
// Open next volume
|
||||
if (!this.OpenVolume(this.Volume + 1))
|
||||
{
|
||||
// unshield_error("Failed to open volume %i to read %i more bytes", reader->volume + 1, bytes_to_read);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.FileDescriptor.Flags & Constants.FILE_OBFUSCATED) != 0)
|
||||
this.Deobfuscate(ref buffer, ref bufferPointer, size);
|
||||
|
||||
success = true;
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deobfuscate a buffer with a seed value
|
||||
/// </summary>
|
||||
/// <remarks>Seed is 0 at file start</remarks>
|
||||
private void Deobfuscate(ref byte[] buffer, ref int bufferPointer, int size, ref uint seed)
|
||||
{
|
||||
uint tmpSeed = seed;
|
||||
|
||||
for (; size > 0; size--, bufferPointer++, tmpSeed++)
|
||||
{
|
||||
buffer[bufferPointer] = (byte)(ROR8(buffer[bufferPointer] ^ 0xd5, 2) - (tmpSeed % 0x47));
|
||||
}
|
||||
|
||||
seed = tmpSeed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotate Right 8
|
||||
/// </summary>
|
||||
private int ROR8(int x, int n) { return (((x) >> ((int)(n))) | ((x) << (8 - (int)(n)))); }
|
||||
}
|
||||
}
|
||||
22
DICUI/External/Unshield/VolumeHeader.cs
vendored
Normal file
22
DICUI/External/Unshield/VolumeHeader.cs
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace DICUI.External.Unshield
|
||||
{
|
||||
public class VolumeHeader
|
||||
{
|
||||
public uint DataOffset;
|
||||
public uint DataOffsetHigh;
|
||||
public uint FirstFileIndex;
|
||||
public uint LastFileIndex;
|
||||
public uint FirstFileOffset;
|
||||
public uint FirstFileOffsetHigh;
|
||||
public uint FirstFileSizeExpanded;
|
||||
public uint FirstFileSizeExpandedHigh;
|
||||
public uint FirstFileSizeCompressed;
|
||||
public uint FirstFileSizeCompressedHigh;
|
||||
public uint LastFileOffset;
|
||||
public uint LastFileOffsetHigh;
|
||||
public uint LastFileSizeExpanded;
|
||||
public uint LastFileSizeExpandedHigh;
|
||||
public uint LastFileSizeCompressed;
|
||||
public uint LastFileSizeCompressedHigh;
|
||||
}
|
||||
}
|
||||
104
DICUI/External/iXcomp/IXComp.cs
vendored
104
DICUI/External/iXcomp/IXComp.cs
vendored
@@ -1,104 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DICUI.External.iXcomp
|
||||
{
|
||||
// TODO: Replace this with a C# implementation based on Unshield
|
||||
public class IXComp
|
||||
{
|
||||
/// <summary>
|
||||
/// List all files found within an InstallShield CAB file
|
||||
/// </summary>
|
||||
/// <param name="input">CAB file to check</param>
|
||||
/// <param name="version">Output tool version</param>
|
||||
/// <returns>List of files found in the CAB</returns>
|
||||
public static List<string> ListFiles(string input, out int version)
|
||||
{
|
||||
// Version 6
|
||||
version = 6;
|
||||
Process p = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Programs", "i6comp.exe"),
|
||||
Arguments = "l -o -r -d \"" + input + "\"",
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
},
|
||||
};
|
||||
p.Start();
|
||||
p.WaitForExit(1000);
|
||||
var i6output = p.StandardOutput.ReadToEnd().Replace("\r\n", "\n").Split('\n').Where(s => s.Length > 50).Select(s => s.Substring(50)).ToList();
|
||||
|
||||
if (i6output.Count() > 0)
|
||||
return i6output;
|
||||
|
||||
// Version 5
|
||||
version = 5;
|
||||
p = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Programs", "i5comp.exe"),
|
||||
Arguments = "l -o -r -d \"" + input + "\"",
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
},
|
||||
};
|
||||
p.Start();
|
||||
p.WaitForExit(1000);
|
||||
var i5output = p.StandardOutput.ReadToEnd().Replace("\r\n", "\n").Split('\n').Where(s => s.Length > 47).Select(s => s.Substring(47)).ToList();
|
||||
|
||||
if (i5output.Count() > 0)
|
||||
return i6output;
|
||||
|
||||
version = -1;
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files found within an InstallShield CAB file
|
||||
/// </summary>
|
||||
/// <param name="cabfile">CAB file to check</param>
|
||||
/// <param name="outDir">Output directory to extract to</param>
|
||||
/// <param name="version">Tool version</param>
|
||||
/// <returns>True if the files extracted succesfully, false otherwise</returns>
|
||||
public static bool ExtractAll(string cabfile, string outDir, int version)
|
||||
{
|
||||
string exe = null;
|
||||
switch(version)
|
||||
{
|
||||
case 6:
|
||||
exe = "i6comp.exe";
|
||||
break;
|
||||
case 5:
|
||||
exe = "i5comp.exe";
|
||||
break;
|
||||
}
|
||||
|
||||
if (exe == null)
|
||||
return false;
|
||||
|
||||
Process p = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
WorkingDirectory = outDir,
|
||||
FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Programs", exe),
|
||||
Arguments = "x -r -d \"" + cabfile + "\"",
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
},
|
||||
};
|
||||
p.Start();
|
||||
p.WaitForExit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,6 +169,11 @@ namespace DICUI
|
||||
EnsureDiscInformation();
|
||||
}
|
||||
|
||||
private void ProgressUpdated(object sender, Result value)
|
||||
{
|
||||
StatusLabel.Content = value.Message;
|
||||
}
|
||||
|
||||
private void MainWindowLocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_logWindow.IsVisible)
|
||||
@@ -309,7 +314,8 @@ namespace DICUI
|
||||
|
||||
if (DriveLetterComboBox.Items.Count > 0)
|
||||
{
|
||||
DriveLetterComboBox.SelectedIndex = 0;
|
||||
int index = _drives.FindIndex(d => d.MarkedActive);
|
||||
DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0);
|
||||
StatusLabel.Content = "Valid media found! Choose your Media Type";
|
||||
StartStopButton.IsEnabled = true;
|
||||
CopyProtectScanButton.IsEnabled = true;
|
||||
@@ -385,7 +391,9 @@ namespace DICUI
|
||||
StatusLabel.Content = "Beginning dumping process";
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Starting dumping process..");
|
||||
|
||||
Result result = await _env.StartDumping();
|
||||
var progress = new Progress<Result>();
|
||||
progress.ProgressChanged += ProgressUpdated;
|
||||
Result result = await _env.StartDumping(progress);
|
||||
|
||||
StatusLabel.Content = result ? "Dumping complete!" : result.Message;
|
||||
StartStopButton.Content = UIElements.StartDumping;
|
||||
@@ -481,6 +489,8 @@ namespace DICUI
|
||||
var env = DetermineEnvironment();
|
||||
if (env.Drive.Letter != default(char))
|
||||
{
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", _env.Drive.Letter);
|
||||
|
||||
var tempContent = StatusLabel.Content;
|
||||
StatusLabel.Content = "Scanning for copy protection... this might take a while!";
|
||||
StartStopButton.IsEnabled = false;
|
||||
@@ -488,7 +498,9 @@ namespace DICUI
|
||||
CopyProtectScanButton.IsEnabled = false;
|
||||
|
||||
string protections = await Validators.RunProtectionScanOnPath(env.Drive.Letter + ":\\");
|
||||
MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
if (!ViewModels.LoggerViewModel.WindowVisible)
|
||||
MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", env.Drive.Letter, protections);
|
||||
|
||||
StatusLabel.Content = tempContent;
|
||||
StartStopButton.IsEnabled = true;
|
||||
@@ -518,7 +530,7 @@ namespace DICUI
|
||||
if (speed == -1)
|
||||
return;
|
||||
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Determined max drive speed for {0}: {0}.", _env.Drive.Letter, speed);
|
||||
ViewModels.LoggerViewModel.VerboseLogLn("Determined max drive speed for {0}: {1}.", _env.Drive.Letter, speed);
|
||||
|
||||
// Choose the lower of the two speeds between the allowed speeds and the user-defined one
|
||||
int chosenSpeed = Math.Min(
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,13 +1,9 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Data;
|
||||
using System.Reflection;
|
||||
using IMAPI2;
|
||||
using DICUI.Data;
|
||||
|
||||
|
||||
namespace DICUI.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -20,16 +20,18 @@ namespace DICUI.Utilities
|
||||
public char Letter { get; private set; }
|
||||
public bool IsFloppy { get; private set; }
|
||||
public string VolumeLabel { get; private set; }
|
||||
public bool MarkedActive { get; private set; }
|
||||
|
||||
private Drive(char letter, string volumeLabel, bool isFloppy)
|
||||
private Drive(char letter, string volumeLabel, bool isFloppy, bool markedActive)
|
||||
{
|
||||
this.Letter = letter;
|
||||
this.IsFloppy = isFloppy;
|
||||
this.VolumeLabel = volumeLabel;
|
||||
this.MarkedActive = markedActive;
|
||||
}
|
||||
|
||||
public static Drive Floppy(char letter) => new Drive(letter, null, true);
|
||||
public static Drive Optical(char letter, string volumeLabel) => new Drive(letter, volumeLabel, false);
|
||||
public static Drive Floppy(char letter) => new Drive(letter, null, true, true);
|
||||
public static Drive Optical(char letter, string volumeLabel, bool active) => new Drive(letter, volumeLabel, false, active);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -136,9 +138,13 @@ namespace DICUI.Utilities
|
||||
if (IsFloppy)
|
||||
return -1;
|
||||
|
||||
// Make sure that the current drive is active
|
||||
if (!Drive.MarkedActive)
|
||||
return -1;
|
||||
|
||||
// Get the drive speed directly
|
||||
//int speed = Validators.GetDriveSpeed(Drive.Letter);
|
||||
//int speed = Validators.GetDriveSpeedEx(Drive.Letter, _currentMediaType);
|
||||
//int speed = Validators.GetDriveSpeed(Drive);
|
||||
//int speed = Validators.GetDriveSpeedEx(Drive, _currentMediaType);
|
||||
|
||||
// Get the drive speed from DIC, if possible
|
||||
Process childProcess;
|
||||
@@ -224,7 +230,7 @@ namespace DICUI.Utilities
|
||||
/// <summary>
|
||||
/// Execute a complete dump workflow
|
||||
/// </summary>
|
||||
public async Task<Result> StartDumping()
|
||||
public async Task<Result> StartDumping(IProgress<Result> progress)
|
||||
{
|
||||
Result result = IsValidForDump();
|
||||
|
||||
@@ -234,9 +240,11 @@ namespace DICUI.Utilities
|
||||
|
||||
// execute DIC
|
||||
await Task.Run(() => ExecuteDiskImageCreator());
|
||||
progress?.Report(Result.Success("DiscImageCreator has finished!"));
|
||||
|
||||
// execute additional tools
|
||||
result = ExecuteAdditionalToolsAfterDIC();
|
||||
progress?.Report(result);
|
||||
|
||||
// is something is wrong with additional tools report and return
|
||||
// TODO: don't return, just keep generating output from DIC
|
||||
@@ -247,7 +255,8 @@ namespace DICUI.Utilities
|
||||
return;
|
||||
}*/
|
||||
|
||||
// verify dump output and save it
|
||||
// Verify dump output and save it
|
||||
progress?.Report(Result.Success("Gathering submission information..."));
|
||||
result = VerifyAndSaveDumpOutput();
|
||||
|
||||
return result;
|
||||
@@ -269,7 +278,7 @@ namespace DICUI.Utilities
|
||||
if (Type == MediaType.Floppy)
|
||||
Drive = Drive.Floppy(String.IsNullOrWhiteSpace(letter) ? new char() : letter[0]);
|
||||
else
|
||||
Drive = Drive.Optical(String.IsNullOrWhiteSpace(letter) ? new char() : letter[0], "");
|
||||
Drive = Drive.Optical(String.IsNullOrWhiteSpace(letter) ? new char() : letter[0], "", true);
|
||||
OutputDirectory = Path.GetDirectoryName(path);
|
||||
OutputFilename = Path.GetFileName(path);
|
||||
}
|
||||
@@ -1365,6 +1374,16 @@ namespace DICUI.Utilities
|
||||
if (!File.Exists(DICPath))
|
||||
return Result.Failure("Error! Could not find DiscImageCreator!");
|
||||
|
||||
// Validate that the user explicitly wants an inactive drive to be considered for dumping
|
||||
if (!Drive.MarkedActive)
|
||||
{
|
||||
MessageBoxResult result = MessageBox.Show("The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
|
||||
if (result == MessageBoxResult.No || result == MessageBoxResult.Cancel || result == MessageBoxResult.None)
|
||||
{
|
||||
return Result.Failure("Dumping aborted!");
|
||||
}
|
||||
}
|
||||
|
||||
// If a complete dump already exists
|
||||
if (FoundAllFiles())
|
||||
{
|
||||
|
||||
@@ -200,7 +200,7 @@ namespace DICUI.Utilities
|
||||
|| Command == DICCommand.XBOX)
|
||||
{
|
||||
if (Filename != null)
|
||||
parameters.Add("\"" + Filename + "\"");
|
||||
parameters.Add("\"" + Filename.Trim('"') + "\"");
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -419,8 +419,8 @@ namespace DICUI.Utilities
|
||||
|
||||
// Get the optical disc drives
|
||||
List<Drive> discDrives = DriveInfo.GetDrives()
|
||||
.Where(d => d.DriveType == DriveType.CDRom && d.IsReady)
|
||||
.Select(d => Drive.Optical(d.Name[0], d.VolumeLabel))
|
||||
.Where(d => d.DriveType == DriveType.CDRom)
|
||||
.Select(d => Drive.Optical(d.Name[0], (d.IsReady ? d.VolumeLabel : UIElements.DiscNotDetected), d.IsReady))
|
||||
.ToList();
|
||||
|
||||
// Add the two lists together and order
|
||||
@@ -516,11 +516,15 @@ namespace DICUI.Utilities
|
||||
/// capabilities of the drives (according to QPXTool)
|
||||
/// TransferRate appears to be the CURRENT transfer rate, not the maximum... basically making that flag useless
|
||||
/// </remarks>
|
||||
public static int GetDriveSpeed(char driveLetter)
|
||||
public static int GetDriveSpeed(Drive drive)
|
||||
{
|
||||
// If the current drive is not active or optical
|
||||
if (drive.IsFloppy || !drive.MarkedActive)
|
||||
return -1;
|
||||
|
||||
ManagementObjectSearcher searcher =
|
||||
new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_CDROMDrive WHERE Id = '" + driveLetter + ":\'");
|
||||
"SELECT * FROM Win32_CDROMDrive WHERE Id = '" + drive.Letter + ":\'");
|
||||
|
||||
var collection = searcher.Get();
|
||||
double? transferRate = -1;
|
||||
@@ -540,15 +544,19 @@ namespace DICUI.Utilities
|
||||
return 0;
|
||||
}
|
||||
|
||||
public unsafe static int GetDriveSpeedEx(char driveLetter, MediaType? mediaType)
|
||||
public unsafe static int GetDriveSpeedEx(Drive drive, MediaType? mediaType)
|
||||
{
|
||||
// If the current drive is not active or optical
|
||||
if (drive.IsFloppy || !drive.MarkedActive)
|
||||
return -1;
|
||||
|
||||
// Get the DeviceID from the current drive letter
|
||||
string deviceId = null;
|
||||
try
|
||||
{
|
||||
ManagementObjectSearcher searcher =
|
||||
new ManagementObjectSearcher("root\\CIMV2",
|
||||
"SELECT * FROM Win32_CDROMDrive WHERE Id = '" + driveLetter + ":\'");
|
||||
"SELECT * FROM Win32_CDROMDrive WHERE Id = '" + drive.Letter + ":\'");
|
||||
|
||||
var collection = searcher.Get();
|
||||
foreach (ManagementObject queryObj in collection)
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
<packages>
|
||||
<package id="LessIO" version="0.5.0" targetFramework="net461" />
|
||||
<package id="libmspack4n" version="0.8.0" targetFramework="net461" />
|
||||
<package id="zlib.net" version="1.0.4.0" targetFramework="net461" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user