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:
Matt Nadareski
2018-07-13 16:40:40 -07:00
committed by GitHub
parent 5bcde889b3
commit 564a6af9b8
30 changed files with 2172 additions and 199 deletions

View File

@@ -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);
}
}
}

View File

@@ -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,
};

View File

@@ -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>

View File

@@ -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";

View File

@@ -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";

View 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
View 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;
}
}
}

View 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
View 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
View 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
View File

@@ -0,0 +1,9 @@
namespace DICUI.External.Unshield
{
public class OffsetList
{
public uint NameOffset;
public uint DescriptorOffset;
public uint NextOffset;
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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;
}
}
}

View 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
View 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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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.

View File

@@ -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>

View File

@@ -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())
{

View File

@@ -200,7 +200,7 @@ namespace DICUI.Utilities
|| Command == DICCommand.XBOX)
{
if (Filename != null)
parameters.Add("\"" + Filename + "\"");
parameters.Add("\"" + Filename.Trim('"') + "\"");
else
return null;
}

View File

@@ -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)

View File

@@ -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>