Browse Source

Enabled nullability checks in IPA.exe

pull/94/head
Anairkoen Schno 3 years ago
parent
commit
de51cee954
Signed by: DaNike GPG Key ID: BEFB74D5F3FC4387
5 changed files with 325 additions and 312 deletions
  1. +1
    -1
      Common.props
  2. +213
    -215
      IPA/Arguments.cs
  3. +61
    -58
      IPA/PatchContext.cs
  4. +4
    -4
      IPA/Patcher/BackupUnit.cs
  5. +46
    -34
      IPA/Program.cs

+ 1
- 1
Common.props View File

@ -5,7 +5,7 @@
<!--<PathMap>$(SolutionDir)=C:\</PathMap>--> <!--<PathMap>$(SolutionDir)=C:\</PathMap>-->
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<LangVersion>9</LangVersion> <LangVersion>9</LangVersion>
<NoWarn>CA1031</NoWarn>
<NoWarn>CA1031;CA1305</NoWarn>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
<WarningsAsErrors>$(WarningsAsErrors);nullable</WarningsAsErrors> <WarningsAsErrors>$(WarningsAsErrors);nullable</WarningsAsErrors>
<AnalysisMode>AllEnabledByDefault</AnalysisMode> <AnalysisMode>AllEnabledByDefault</AnalysisMode>


+ 213
- 215
IPA/Arguments.cs View File

@ -1,215 +1,213 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace IPA
{
public class Arguments
{
public static readonly Arguments CmdLine = new Arguments(Environment.GetCommandLineArgs());
private readonly List<string> positional = new List<string>();
private readonly Dictionary<string, string> longFlags = new Dictionary<string, string>();
private readonly Dictionary<char, string> flags = new Dictionary<char, string>();
private readonly List<ArgumentFlag> flagObjects = new List<ArgumentFlag>();
private string[] toParse;
private Arguments(string[] args)
{
toParse = args.Skip(1).ToArray();
}
public Arguments Flags(params ArgumentFlag[] toAdd)
{
foreach (var f in toAdd) AddFlag(f);
return this;
}
public void AddFlag(ArgumentFlag toAdd)
{
if (toParse == null) throw new InvalidOperationException();
flagObjects.Add(toAdd);
}
public void Process()
{
foreach (var arg in toParse)
{
if (arg.StartsWith("--"))
{ // parse as a long flag
var name = arg.Substring(2); // cut off first two chars
string value = null;
if (name.Contains('='))
{
var spl = name.Split('=');
name = spl[0];
value = string.Join("=", spl, 1, spl.Length - 1);
}
longFlags.Add(name, value);
}
else if (arg.StartsWith("-"))
{ // parse as flags
var argument = arg.Substring(1); // cut off first char
var subBuildState = new StringBuilder();
var parsingValue = false;
var escaped = false;
var mainChar = ' ';
foreach (var chr in argument)
{
if (!parsingValue)
{
if (chr == '=')
{
parsingValue = true;
}
else
{
mainChar = chr;
flags.Add(chr, null);
}
}
else
{
if (!escaped)
{
if (chr == ',')
{
parsingValue = false;
flags[mainChar] = subBuildState.ToString();
subBuildState = new StringBuilder();
continue;
}
else if (chr == '\\')
{
escaped = true;
continue;
}
}
subBuildState.Append(chr);
}
}
if (parsingValue)
{
parsingValue = false;
flags[mainChar] = subBuildState.ToString();
subBuildState = new StringBuilder();
}
}
else
{ // parse as positional
positional.Add(arg);
}
}
toParse = null;
foreach (var flag in flagObjects)
{
foreach (var charFlag in flag.ShortFlags)
{
if (!(flag.exists_ = HasFlag(charFlag))) continue;
flag.value_ = GetFlagValue(charFlag);
goto FoundValue; // continue to next flagObjects item
}
foreach (var longFlag in flag.LongFlags)
{
if (!(flag.exists_ = HasLongFlag(longFlag))) continue;
flag.value_ = GetLongFlagValue(longFlag);
goto FoundValue; // continue to next flagObjects item
}
FoundValue:;
}
}
public bool HasLongFlag(string flag)
{
return longFlags.ContainsKey(flag);
}
public bool HasFlag(char flag)
{
return flags.ContainsKey(flag);
}
public string GetLongFlagValue(string flag)
{
return longFlags[flag];
}
public string GetFlagValue(char flag)
{
return flags[flag];
}
public void PrintHelp()
{
const string indent = " ";
var filename = Path.GetFileName(Environment.GetCommandLineArgs()[0]);
const string format = @"usage:
{2}{0} [FLAGS] [ARGUMENTS]
flags:
{1}";
var flagsBuilder = new StringBuilder();
foreach (var flag in flagObjects)
{
flagsBuilder.AppendFormat("{2}{0}{3}{1}",
string.Join(", ", flag.ShortFlags.Select(s => $"-{s}").Concat( flag.LongFlags.Select(s => $"--{s}")) ),
Environment.NewLine, indent, flag.ValueString != null ? "=" + flag.ValueString : "");
flagsBuilder.AppendFormat("{2}{2}{0}{1}", flag.DocString, Environment.NewLine, indent);
}
Console.Write(format, filename, flagsBuilder, indent);
}
public IReadOnlyList<string> PositionalArgs => positional;
}
public class ArgumentFlag
{
internal readonly List<char> ShortFlags = new List<char>();
internal readonly List<string> LongFlags = new List<string>();
internal string value_;
internal bool exists_;
public ArgumentFlag(params string[] flags)
{
foreach (var part in flags)
AddPart(part);
}
private void AddPart(string flagPart)
{
if (flagPart.StartsWith("--"))
LongFlags.Add(flagPart.Substring(2));
else if (flagPart.StartsWith("-"))
ShortFlags.Add(flagPart[1]);
}
public bool Exists => exists_;
public string Value => value_;
public bool HasValue => Exists && Value != null;
public string DocString { get; set; } = "";
public string ValueString { get; set; }
public static implicit operator bool(ArgumentFlag f)
{
return f.Exists;
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace IPA
{
public class Arguments
{
public static readonly Arguments CmdLine = new(Environment.GetCommandLineArgs());
private readonly List<string> positional = new();
private readonly Dictionary<string, string?> longFlags = new();
private readonly Dictionary<char, string?> flags = new();
private readonly List<ArgumentFlag> flagObjects = new();
private string[]? toParse;
private Arguments(string[] args)
{
toParse = args.Skip(1).ToArray();
}
public Arguments Flags(params ArgumentFlag[] toAdd)
{
foreach (var f in toAdd) AddFlag(f);
return this;
}
public void AddFlag(ArgumentFlag toAdd)
{
if (toParse == null) throw new InvalidOperationException();
flagObjects.Add(toAdd);
}
public void Process()
{
if (toParse == null) throw new InvalidOperationException();
foreach (var arg in toParse)
{
if (arg.StartsWith("--"))
{ // parse as a long flag
var name = arg.Substring(2); // cut off first two chars
string? value = null;
if (name.Contains('='))
{
var spl = name.Split('=');
name = spl[0];
value = string.Join("=", spl, 1, spl.Length - 1);
}
longFlags.Add(name, value);
}
else if (arg.StartsWith("-"))
{ // parse as flags
var argument = arg.Substring(1); // cut off first char
var subBuildState = new StringBuilder();
var parsingValue = false;
var escaped = false;
var mainChar = ' ';
foreach (var chr in argument)
{
if (!parsingValue)
{
if (chr == '=')
{
parsingValue = true;
}
else
{
mainChar = chr;
flags.Add(chr, null);
}
}
else
{
if (!escaped)
{
if (chr == ',')
{
parsingValue = false;
flags[mainChar] = subBuildState.ToString();
subBuildState = new StringBuilder();
continue;
}
else if (chr == '\\')
{
escaped = true;
continue;
}
}
_ = subBuildState.Append(chr);
}
}
if (parsingValue)
{
flags[mainChar] = subBuildState.ToString();
}
}
else
{ // parse as positional
positional.Add(arg);
}
}
toParse = null;
foreach (var flag in flagObjects)
{
foreach (var charFlag in flag.ShortFlags)
{
if (!(flag.exists_ = HasFlag(charFlag))) continue;
flag.value_ = GetFlagValue(charFlag);
goto FoundValue; // continue to next flagObjects item
}
foreach (var longFlag in flag.LongFlags)
{
if (!(flag.exists_ = HasLongFlag(longFlag))) continue;
flag.value_ = GetLongFlagValue(longFlag);
goto FoundValue; // continue to next flagObjects item
}
FoundValue:;
}
}
public bool HasLongFlag(string flag)
{
return longFlags.ContainsKey(flag);
}
public bool HasFlag(char flag)
{
return flags.ContainsKey(flag);
}
public string? GetLongFlagValue(string flag)
{
return longFlags[flag];
}
public string? GetFlagValue(char flag)
{
return flags[flag];
}
public void PrintHelp()
{
const string indent = " ";
var filename = Path.GetFileName(Environment.GetCommandLineArgs()[0]);
const string format = @"usage:
{2}{0} [FLAGS] [ARGUMENTS]
flags:
{1}";
var flagsBuilder = new StringBuilder();
foreach (var flag in flagObjects)
{
_ = flagsBuilder
.AppendFormat("{2}{0}{3}{1}",
string.Join(", ", flag.ShortFlags.Select(s => $"-{s}").Concat( flag.LongFlags.Select(s => $"--{s}")) ),
Environment.NewLine, indent, flag.ValueString != null ? "=" + flag.ValueString : "")
.AppendFormat("{2}{2}{0}{1}", flag.DocString, Environment.NewLine, indent);
}
Console.Write(format, filename, flagsBuilder, indent);
}
public IReadOnlyList<string> PositionalArgs => positional;
}
public class ArgumentFlag
{
internal readonly List<char> ShortFlags = new();
internal readonly List<string> LongFlags = new();
internal string? value_;
internal bool exists_;
public ArgumentFlag(params string[] flags)
{
foreach (var part in flags)
AddPart(part);
}
private void AddPart(string flagPart)
{
if (flagPart.StartsWith("--"))
LongFlags.Add(flagPart.Substring(2));
else if (flagPart.StartsWith("-"))
ShortFlags.Add(flagPart[1]);
}
public bool Exists => exists_;
public string? Value => value_;
public bool HasValue => Exists && Value != null;
public string DocString { get; set; } = "";
public string? ValueString { get; set; }
public static implicit operator bool(ArgumentFlag f) => f.Exists;
}
}

+ 61
- 58
IPA/PatchContext.cs View File

@ -1,58 +1,61 @@
using System;
using System.IO;
using System.Reflection;
namespace IPA
{
public class PatchContext
{
/// <summary>
/// Gets the filename of the executable.
/// </summary>
public string Executable { get; private set; }
public string DataPathSrc { get; private set; }
public string LibsPathSrc { get; private set; }
public string PluginsFolder { get; private set; }
public string ProjectName { get; private set; }
public string DataPathDst { get; private set; }
public string LibsPathDst { get; private set; }
public string ManagedPath { get; private set; }
public string EngineFile { get; private set; }
public string AssemblyFile { get; private set; }
public string ProjectRoot { get; private set; }
public string IPARoot { get; private set; }
public string ShortcutPath { get; private set; }
public string IPA { get; private set; }
public string BackupPath { get; private set; }
private PatchContext() { }
public static PatchContext Create(string exe)
{
var context = new PatchContext
{
Executable = exe
};
context.ProjectRoot = new FileInfo(context.Executable).Directory?.FullName;
context.IPARoot = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) ?? throw new InvalidOperationException(), "IPA");
context.IPA = Assembly.GetExecutingAssembly().Location;
context.DataPathSrc = Path.Combine(context.IPARoot, "Data");
context.LibsPathSrc = Path.Combine(context.IPARoot, "Libs");
context.PluginsFolder = Path.Combine(context.ProjectRoot ?? throw new InvalidOperationException(), "Plugins");
context.ProjectName = Path.GetFileNameWithoutExtension(context.Executable);
context.DataPathDst = Path.Combine(context.ProjectRoot, context.ProjectName + "_Data");
context.LibsPathDst = Path.Combine(context.ProjectRoot, "Libs");
context.ManagedPath = Path.Combine(context.DataPathDst, "Managed");
context.EngineFile = Path.Combine(context.ManagedPath, "UnityEngine.CoreModule.dll");
context.AssemblyFile = Path.Combine(context.ManagedPath, "Assembly-CSharp.dll");
context.BackupPath = Path.Combine(context.IPARoot, "Backups", context.ProjectName);
string shortcutName = $"{context.ProjectName} (Patch & Launch)";
context.ShortcutPath = Path.Combine(context.ProjectRoot, shortcutName) + ".lnk";
Directory.CreateDirectory(context.BackupPath);
return context;
}
}
}
using System;
using System.IO;
using System.Reflection;
namespace IPA
{
public class PatchContext
{
/// <summary>
/// Gets the filename of the executable.
/// </summary>
public string Executable { get; private set; }
public string DataPathSrc { get; private set; }
public string LibsPathSrc { get; private set; }
public string PluginsFolder { get; private set; }
public string ProjectName { get; private set; }
public string DataPathDst { get; private set; }
public string LibsPathDst { get; private set; }
public string ManagedPath { get; private set; }
public string EngineFile { get; private set; }
public string AssemblyFile { get; private set; }
public string ProjectRoot { get; private set; }
public string IPARoot { get; private set; }
public string ShortcutPath { get; private set; }
public string IPA { get; private set; }
public string BackupPath { get; private set; }
// This is only created by us; and all are assigned
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private PatchContext() { }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public static PatchContext Create(string exe)
{
var context = new PatchContext
{
Executable = exe
};
context.ProjectRoot = new FileInfo(context.Executable).Directory?.FullName ?? throw new Exception();
context.IPARoot = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) ?? throw new InvalidOperationException(), "IPA");
context.IPA = Assembly.GetExecutingAssembly().Location;
context.DataPathSrc = Path.Combine(context.IPARoot, "Data");
context.LibsPathSrc = Path.Combine(context.IPARoot, "Libs");
context.PluginsFolder = Path.Combine(context.ProjectRoot ?? throw new InvalidOperationException(), "Plugins");
context.ProjectName = Path.GetFileNameWithoutExtension(context.Executable);
context.DataPathDst = Path.Combine(context.ProjectRoot, context.ProjectName + "_Data");
context.LibsPathDst = Path.Combine(context.ProjectRoot, "Libs");
context.ManagedPath = Path.Combine(context.DataPathDst, "Managed");
context.EngineFile = Path.Combine(context.ManagedPath, "UnityEngine.CoreModule.dll");
context.AssemblyFile = Path.Combine(context.ManagedPath, "Assembly-CSharp.dll");
context.BackupPath = Path.Combine(context.IPARoot, "Backups", context.ProjectName);
string shortcutName = $"{context.ProjectName} (Patch & Launch)";
context.ShortcutPath = Path.Combine(context.ProjectRoot, shortcutName) + ".lnk";
_ = Directory.CreateDirectory(context.BackupPath);
return context;
}
}
}

+ 4
- 4
IPA/Patcher/BackupUnit.cs View File

@ -13,9 +13,9 @@ namespace IPA.Patcher
private readonly DirectoryInfo _backupPath; private readonly DirectoryInfo _backupPath;
private readonly PatchContext _context; private readonly PatchContext _context;
private readonly List<string> _files = new List<string>();
private readonly List<string> _files = new();
private readonly FileInfo _manifestFile; private readonly FileInfo _manifestFile;
private static string _ManifestFileName = "$manifest$.txt";
private static readonly string _ManifestFileName = "$manifest$.txt";
public BackupUnit(PatchContext context) : this(context, DateTime.Now.ToString("yyyy-MM-dd_h-mm-ss")) public BackupUnit(PatchContext context) : this(context, DateTime.Now.ToString("yyyy-MM-dd_h-mm-ss"))
{ {
@ -88,7 +88,7 @@ namespace IPA.Patcher
backupPath.Directory?.Create(); backupPath.Directory?.Create();
if (file.Exists) if (file.Exists)
{ {
file.CopyTo(backupPath.FullName);
_ = file.CopyTo(backupPath.FullName);
} }
else else
{ {
@ -123,7 +123,7 @@ namespace IPA.Patcher
{ {
Console.WriteLine(" {0} => {1}", backupFile.FullName, target.FullName); Console.WriteLine(" {0} => {1}", backupFile.FullName, target.FullName);
target.Directory?.Create(); target.Directory?.Create();
backupFile.CopyTo(target.FullName, true);
_ = backupFile.CopyTo(target.FullName, true);
} }
else else
{ {


+ 46
- 34
IPA/Program.cs View File

@ -12,10 +12,8 @@ using IPA.Patcher;
namespace IPA namespace IPA
{ {
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
public static class Program public static class Program
{ {
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum Architecture public enum Architecture
{ {
x86, x86,
@ -25,17 +23,17 @@ namespace IPA
public const string FileVersion = "4.1.6.0"; public const string FileVersion = "4.1.6.0";
public static Version Version => Assembly.GetEntryAssembly().GetName().Version;
public static Version Version => Assembly.GetEntryAssembly()!.GetName().Version!;
public static readonly ArgumentFlag ArgHelp = new ArgumentFlag("--help", "-h") { DocString = "prints this message" };
public static readonly ArgumentFlag ArgVersion = new ArgumentFlag("--version", "-v") { DocString = "prints the version that will be installed and is currently installed" };
public static readonly ArgumentFlag ArgWaitFor = new ArgumentFlag("--waitfor", "-w") { DocString = "waits for the specified PID to exit", ValueString = "PID" };
public static readonly ArgumentFlag ArgForce = new ArgumentFlag("--force", "-f") { DocString = "forces the operation to go through" };
public static readonly ArgumentFlag ArgRevert = new ArgumentFlag("--revert", "-r") { DocString = "reverts the IPA installation" };
public static readonly ArgumentFlag ArgNoRevert = new ArgumentFlag("--no-revert", "-R") { DocString = "prevents a normal installation from first reverting" };
public static readonly ArgumentFlag ArgNoWait = new ArgumentFlag("--nowait", "-n") { DocString = "doesn't wait for user input after the operation" };
public static readonly ArgumentFlag ArgStart = new ArgumentFlag("--start", "-s") { DocString = "uses the specified arguments to start the game after the patch/unpatch", ValueString = "ARGUMENTS" };
public static readonly ArgumentFlag ArgLaunch = new ArgumentFlag("--launch", "-l") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" };
public static readonly ArgumentFlag ArgHelp = new("--help", "-h") { DocString = "prints this message" };
public static readonly ArgumentFlag ArgVersion = new("--version", "-v") { DocString = "prints the version that will be installed and is currently installed" };
public static readonly ArgumentFlag ArgWaitFor = new("--waitfor", "-w") { DocString = "waits for the specified PID to exit", ValueString = "PID" };
public static readonly ArgumentFlag ArgForce = new("--force", "-f") { DocString = "forces the operation to go through" };
public static readonly ArgumentFlag ArgRevert = new("--revert", "-r") { DocString = "reverts the IPA installation" };
public static readonly ArgumentFlag ArgNoRevert = new("--no-revert", "-R") { DocString = "prevents a normal installation from first reverting" };
public static readonly ArgumentFlag ArgNoWait = new("--nowait", "-n") { DocString = "doesn't wait for user input after the operation" };
public static readonly ArgumentFlag ArgStart = new("--start", "-s") { DocString = "uses the specified arguments to start the game after the patch/unpatch", ValueString = "ARGUMENTS" };
public static readonly ArgumentFlag ArgLaunch = new("--launch", "-l") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" };
[STAThread] [STAThread]
public static void Main() public static void Main()
@ -57,7 +55,7 @@ namespace IPA
{ {
if (ArgWaitFor.HasValue && !ArgVersion) if (ArgWaitFor.HasValue && !ArgVersion)
{ // wait for process if necessary { // wait for process if necessary
var pid = int.Parse(ArgWaitFor.Value);
var pid = int.Parse(ArgWaitFor.Value!);
try try
{ // wait for beat saber to exit (ensures we can modify the file) { // wait for beat saber to exit (ensures we can modify the file)
@ -73,12 +71,12 @@ namespace IPA
} }
} }
PatchContext context = null;
PatchContext? context = null;
Assembly AssemblyLibLoader(object source, ResolveEventArgs e)
Assembly? AssemblyLibLoader(object? source, ResolveEventArgs e)
{ {
// ReSharper disable AccessToModifiedClosure // ReSharper disable AccessToModifiedClosure
if (context == null) return null;
if (context == null || e.Name == null) return null;
var libsDir = context.LibsPathSrc; var libsDir = context.LibsPathSrc;
// ReSharper enable AccessToModifiedClosure // ReSharper enable AccessToModifiedClosure
@ -96,14 +94,16 @@ namespace IPA
var argExeName = Arguments.CmdLine.PositionalArgs.FirstOrDefault(s => s.EndsWith(".exe")); var argExeName = Arguments.CmdLine.PositionalArgs.FirstOrDefault(s => s.EndsWith(".exe"));
argExeName ??= new DirectoryInfo(Directory.GetCurrentDirectory()).GetFiles() argExeName ??= new DirectoryInfo(Directory.GetCurrentDirectory()).GetFiles()
.FirstOrDefault(o => o.Extension == ".exe" && o.FullName != Assembly.GetEntryAssembly().Location)
.FirstOrDefault(o => o.Extension == ".exe" && o.FullName != Assembly.GetEntryAssembly()!.Location)
?.FullName; ?.FullName;
if (argExeName == null) if (argExeName == null)
{ {
Fail("Could not locate game executable"); Fail("Could not locate game executable");
} }
else else
{
context = PatchContext.Create(argExeName); context = PatchContext.Create(argExeName);
}
if (ArgVersion) if (ArgVersion)
{ {
@ -120,7 +120,9 @@ namespace IPA
Validate(context); Validate(context);
if (ArgRevert /*|| Keyboard.IsKeyDown(Keys.LMenu)*/) if (ArgRevert /*|| Keyboard.IsKeyDown(Keys.LMenu)*/)
{
Revert(context); Revert(context);
}
else else
{ {
Install(context); Install(context);
@ -147,7 +149,7 @@ namespace IPA
Console.ForegroundColor = ConsoleColor.DarkYellow; Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("[Press any key to continue]"); Console.WriteLine("[Press any key to continue]");
Console.ResetColor(); Console.ResetColor();
Console.ReadKey();
_ = Console.ReadKey();
} }
} }
@ -161,7 +163,7 @@ namespace IPA
} }
} }
private static Version GetInstalledVersion(PatchContext context)
private static Version? GetInstalledVersion(PatchContext context)
{ {
// first, check currently installed version, if any // first, check currently installed version, if any
if (File.Exists(Path.Combine(context.ProjectRoot, "winhttp.dll"))) if (File.Exists(Path.Combine(context.ProjectRoot, "winhttp.dll")))
@ -199,7 +201,7 @@ namespace IPA
Console.ForegroundColor = ConsoleColor.Cyan; Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Restoring old version... "); Console.WriteLine("Restoring old version... ");
if (BackupManager.HasBackup(context)) if (BackupManager.HasBackup(context))
BackupManager.Restore(context);
_ = BackupManager.Restore(context);
} }
var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins"); var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins");
@ -231,7 +233,7 @@ namespace IPA
{ {
Console.ForegroundColor = ConsoleColor.DarkYellow; Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("Creating plugins folder... "); Console.WriteLine("Creating plugins folder... ");
Directory.CreateDirectory(context.PluginsFolder);
_ = Directory.CreateDirectory(context.PluginsFolder);
Console.ResetColor(); Console.ResetColor();
} }
@ -277,17 +279,17 @@ namespace IPA
{ {
if (ArgStart.HasValue) if (ArgStart.HasValue)
{ {
Process.Start(context.Executable, ArgStart.Value);
_ = Process.Start(context.Executable, ArgStart.Value);
} }
else else
{ {
var argList = Arguments.CmdLine.PositionalArgs.ToList(); var argList = Arguments.CmdLine.PositionalArgs.ToList();
argList.Remove(context.Executable);
_ = argList.Remove(context.Executable);
if (ArgLaunch) if (ArgLaunch)
{ {
Process.Start(context.Executable, Args(argList.ToArray()));
_ = Process.Start(context.Executable, Args(argList.ToArray()));
} }
} }
} }
@ -309,7 +311,7 @@ namespace IPA
} }
public static void CopyAll(DirectoryInfo source, DirectoryInfo target, bool aggressive, BackupUnit backup, public static void CopyAll(DirectoryInfo source, DirectoryInfo target, bool aggressive, BackupUnit backup,
Func<FileInfo, FileInfo, IEnumerable<FileInfo>> interceptor = null, bool recurse = true)
Func<FileInfo, FileInfo, IEnumerable<FileInfo>>? interceptor = null, bool recurse = true)
{ {
if (interceptor == null) if (interceptor == null)
{ {
@ -331,7 +333,7 @@ namespace IPA
ClearLine(); ClearLine();
Console.WriteLine(@"Copying {0}", targetFile.FullName); Console.WriteLine(@"Copying {0}", targetFile.FullName);
backup.Add(targetFile); backup.Add(targetFile);
fi.CopyTo(targetFile.FullName, true);
_ = fi.CopyTo(targetFile.FullName, true);
} }
} }
@ -351,13 +353,14 @@ namespace IPA
WaitForEnd(); WaitForEnd();
// This is needed because in Framework, this is not marked DoesNotReturn
#pragma warning disable CS8763 // A method marked [DoesNotReturn] should not return.
Environment.Exit(1); Environment.Exit(1);
} }
#pragma warning restore CS8763 // A method marked [DoesNotReturn] should not return.
public static string Args(params string[] args) public static string Args(params string[] args)
{
return string.Join(" ", args.Select(EncodeParameterArgument).ToArray());
}
=> string.Join(" ", args.Select(EncodeParameterArgument).ToArray());
/// <summary> /// <summary>
/// Encodes an argument for passing into a program /// Encodes an argument for passing into a program
@ -381,19 +384,28 @@ namespace IPA
var header = reader.ReadUInt16(); var header = reader.ReadUInt16();
if (header == 0x5a4d) if (header == 0x5a4d)
{ {
reader.BaseStream.Seek(60, SeekOrigin.Begin); // this location contains the offset for the PE header
_ = reader.BaseStream.Seek(60, SeekOrigin.Begin); // this location contains the offset for the PE header
var peOffset = reader.ReadUInt32(); var peOffset = reader.ReadUInt32();
reader.BaseStream.Seek(peOffset + 4, SeekOrigin.Begin);
_ = reader.BaseStream.Seek(peOffset + 4, SeekOrigin.Begin);
var machine = reader.ReadUInt16(); var machine = reader.ReadUInt16();
if (machine == 0x8664) // IMAGE_FILE_MACHINE_AMD64 if (machine == 0x8664) // IMAGE_FILE_MACHINE_AMD64
{
return Architecture.x64; return Architecture.x64;
if (machine == 0x014c) // IMAGE_FILE_MACHINE_I386
}
else if (machine == 0x014c) // IMAGE_FILE_MACHINE_I386
{
return Architecture.x86; return Architecture.x86;
if (machine == 0x0200) // IMAGE_FILE_MACHINE_IA64
}
else if (machine == 0x0200) // IMAGE_FILE_MACHINE_IA64
{
return Architecture.x64; return Architecture.x64;
return Architecture.Unknown;
}
else
{
return Architecture.Unknown;
}
} }
// Not a supported binary // Not a supported binary


Loading…
Cancel
Save