diff --git a/IPA.Tests/IPA.Tests.csproj b/IPA.Tests/IPA.Tests.csproj
new file mode 100644
index 0000000..f437fab
--- /dev/null
+++ b/IPA.Tests/IPA.Tests.csproj
@@ -0,0 +1,93 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+ {C66092B0-5C1E-44E9-B524-E0E8E1425379}
+ Library
+ Properties
+ IPA.Tests
+ IPA.Tests
+ v4.5.2
+ 512
+
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+ ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll
+ True
+
+
+ ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll
+ True
+
+
+ ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll
+ True
+
+
+ ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+ {14092533-98bb-40a4-9afc-27bb75672a70}
+ IPA
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/IPA.Tests/ProgramTest.cs b/IPA.Tests/ProgramTest.cs
new file mode 100644
index 0000000..1d78af8
--- /dev/null
+++ b/IPA.Tests/ProgramTest.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace IPA.Tests
+{
+ public class ProgramTest
+ {
+ [Theory]
+ // Unrelated path
+ [InlineData("test/from.dll", "test/to.dll", "native", false, new string[] { "test/to.dll" })]
+
+ // Flat -> Not-Flat
+ [InlineData("native/from.dll", "native/to.dll", "native", false, new string[] { "native/x86/to.dll", "native/x86_64/to.dll" })]
+
+ // Flat -> Flat
+ [InlineData("native/from.dll", "native/to.dll", "native", true, new string[] { "native/to.dll" })]
+
+ // Not-Flat -> Flat
+ [InlineData("native/x86/from.dll", "native/x86/to.dll", "native", true, new string[] { })]
+ [InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", true, new string[] { "native/to.dll" })]
+
+ // Not-flat -> Not-Flat
+ [InlineData("native/x86/from.dll", "native/x86/to.dll", "native", false, new string[] { "native/x86/to.dll" })]
+ [InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", false, new string[] { "native/x86_64/to.dll" })]
+
+ public void CopiesCorrectly(string from, string to, string nativeFolder, bool isFlat, string[] expected)
+ {
+ var outcome = Program.NativePluginInterceptor(new FileInfo(from), new FileInfo(to), new DirectoryInfo(nativeFolder), isFlat).Select(f => f.FullName).ToList();
+
+ var expectedPaths = expected.Select(e => new FileInfo(e)).Select(f => f.FullName).ToList();
+ Assert.Equal(expectedPaths, outcome);
+ }
+ }
+}
diff --git a/IPA.Tests/Properties/AssemblyInfo.cs b/IPA.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..07343ad
--- /dev/null
+++ b/IPA.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("IPA.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("IPA.Tests")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c66092b0-5c1e-44e9-b524-e0e8e1425379")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/IPA.Tests/ShortcutTest.cs b/IPA.Tests/ShortcutTest.cs
new file mode 100644
index 0000000..3229153
--- /dev/null
+++ b/IPA.Tests/ShortcutTest.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace IPA.Tests
+{
+ public class ShortcutTest
+ {
+ [Fact]
+ public void CanDealWithEmptyFiles()
+ {
+ Shortcut.Create(".lnk", "", "", "", "", "", "");
+ }
+
+ [Fact]
+ public void CanDealWithLongFiles()
+ {
+ Shortcut.Create(".lnk", Path.Combine(Path.GetTempPath(), string.Join("_", new string[500])), "", "", "", "", "");
+ }
+
+ [Fact]
+ public void CantDealWithNull()
+ {
+ Assert.Throws(() => Shortcut.Create(".lnk", null, "", "", "", "", ""));
+ }
+
+ [Fact]
+ public void CanDealWithWeirdCharacters()
+ {
+ Shortcut.Create(".lnk", "äöü", "", "", "", "", "");
+ }
+ }
+}
diff --git a/IPA.Tests/packages.config b/IPA.Tests/packages.config
new file mode 100644
index 0000000..30b6958
--- /dev/null
+++ b/IPA.Tests/packages.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/IPA.sln b/IPA.sln
index edd3f93..32a6edf 100644
--- a/IPA.sln
+++ b/IPA.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA", "IPA\IPA.csproj", "{14092533-98BB-40A4-9AFC-27BB75672A70}"
ProjectSection(ProjectDependencies) = postProject
@@ -16,6 +16,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IllusionPlugin", "IllusionP
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IllusionInjector", "IllusionInjector\IllusionInjector.csproj", "{D1C61AF5-0D2D-4752-8203-1C6929025F7C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA.Tests", "IPA.Tests\IPA.Tests.csproj", "{C66092B0-5C1E-44E9-B524-E0E8E1425379}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -38,6 +40,10 @@ Global
{D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/IPA/Program.cs b/IPA/Program.cs
index ea392e3..4da0f66 100644
--- a/IPA/Program.cs
+++ b/IPA/Program.cs
@@ -13,7 +13,7 @@ using System.Windows.Forms;
namespace IPA
{
- class Program
+ public class Program
{
static void Main(string[] args)
@@ -59,8 +59,11 @@ namespace IPA
try
{
// Copying
- Console.Write("Updating files... ");
- CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst));
+ Console.WriteLine("Updating files... ");
+ var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins");
+ bool isFlat = Directory.Exists(nativePluginFolder) && Directory.GetFiles(nativePluginFolder).Any(f => f.EndsWith(".dll"));
+ CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst), (from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat) );
+
Console.WriteLine("Successfully updated files!");
if (!Directory.Exists(context.PluginsFolder))
@@ -165,18 +168,65 @@ namespace IPA
}
}
- public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
+ public static IEnumerable NativePluginInterceptor(FileInfo from, FileInfo to, DirectoryInfo nativePluginFolder, bool isFlat)
{
+ if (to.FullName.StartsWith(nativePluginFolder.FullName))
+ {
+ var relevantBit = to.FullName.Substring(nativePluginFolder.FullName.Length + 1);
+ // Goes into the plugin folder!
+ bool isFileFlat = !relevantBit.StartsWith("x86");
+ if (isFlat && !isFileFlat)
+ {
+ // Flatten structure
+ if (relevantBit.StartsWith("x86_64"))
+ {
+ yield return new FileInfo(Path.Combine(nativePluginFolder.FullName, relevantBit.Substring("x86_64".Length + 1)));
+ }
+ else
+ {
+ // Throw away
+ yield break;
+ }
+ }
+ else if (!isFlat && isFileFlat)
+ {
+ // Deepen structure
+ yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86"), relevantBit));
+ yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86_64"), relevantBit));
+ }
+ else
+ {
+ yield return to;
+ }
+ }
+ else
+ {
+ yield return to;
+ }
+ }
+ private static IEnumerable PassThroughInterceptor(FileInfo from, FileInfo to)
+ {
+ yield return to;
+ }
+
+ public static void CopyAll(DirectoryInfo source, DirectoryInfo target, Func> interceptor = null)
+ {
+ if(interceptor == null)
+ {
+ interceptor = PassThroughInterceptor;
+ }
+
Directory.CreateDirectory(target.FullName);
// Copy each file into the new directory.
foreach (FileInfo fi in source.GetFiles())
{
- string targetFile = Path.Combine(target.FullName, fi.Name);
- if (!File.Exists(targetFile) || File.GetLastWriteTimeUtc(targetFile) < fi.LastWriteTimeUtc)
- {
- Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name);
- fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
+ foreach(var targetFile in interceptor(fi, new FileInfo(Path.Combine(target.FullName, fi.Name)))) {
+ if (!targetFile.Exists || targetFile.LastWriteTimeUtc < fi.LastWriteTimeUtc)
+ {
+ Console.WriteLine(@"Copying {0}", targetFile.FullName);
+ fi.CopyTo(targetFile.FullName, true);
+ }
}
}
@@ -185,7 +235,7 @@ namespace IPA
{
DirectoryInfo nextTargetSubDir =
target.CreateSubdirectory(diSourceSubDir.Name);
- CopyAll(diSourceSubDir, nextTargetSubDir);
+ CopyAll(diSourceSubDir, nextTargetSubDir, interceptor);
}
}