diff --git a/Options.cs b/Helpers/Options.cs similarity index 95% rename from Options.cs rename to Helpers/Options.cs index 52af38a..61c81e7 100644 --- a/Options.cs +++ b/Helpers/Options.cs @@ -1,262 +1,258 @@ -/*Copyright 2020-2021 dan0v - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License.*/ - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; - -namespace xdelta3_cross_gui -{ - public class Options : INotifyPropertyChanged - { - private string _PatchExtention { get; set; } - private string _PatchSubdirectory { get; set; } - private string _PatchFileDestination { get; set; } - private string _XDeltaArguments { get; set; } - private string _ZipName { get; set; } - private bool _ShowFullPaths { get; set; } - private bool _CopyExecutables { get; set; } - private bool _CreateBatchFileOnly { get; set; } - private bool _ZipFilesWhenDone { get; set; } - private bool _ShowTerminal { get; set; } - - public string PatchExtention - { - get => _PatchExtention; - set - { - if (value != _PatchExtention) - { - _PatchExtention = value; - OnPropertyChanged(); - } - } - } - public string PatchSubdirectory - { - get => _PatchSubdirectory; - set - { - if (value != _PatchSubdirectory) - { - _PatchSubdirectory = value; - OnPropertyChanged(); - } - } - } - public string XDeltaArguments - { - get => _XDeltaArguments; - set - { - if (value != _XDeltaArguments) - { - _XDeltaArguments = value; - OnPropertyChanged(); - } - } - } - public string PatchFileDestination - { - get => _PatchFileDestination; - set - { - if (value != _PatchFileDestination) - { - _PatchFileDestination = value; - OnPropertyChanged(); - } - } - } - public string ZipName - { - get => _ZipName; - set - { - if (value != _ZipName) - { - _ZipName = value; - OnPropertyChanged(); - } - } - } - public bool ShowFullPaths - { - get => _ShowFullPaths; - set - { - if (value != _ShowFullPaths) - { - _ShowFullPaths = value; - OnPropertyChanged(); - } - } - } - public bool CopyExecutables - { - get => _CopyExecutables; - set - { - if (value != _CopyExecutables) - { - _CopyExecutables = value; - OnPropertyChanged(); - } - } - } - public bool CreateBatchFileOnly - { - get => _CreateBatchFileOnly; - set - { - if (value != _CreateBatchFileOnly) - { - _CreateBatchFileOnly = value; - OnPropertyChanged(); - } - } - } - public bool ZipFilesWhenDone - { - get => _ZipFilesWhenDone; - set - { - if (value != _ZipFilesWhenDone) - { - _ZipFilesWhenDone = value; - OnPropertyChanged(); - } - } - } - public bool ShowTerminal - { - get => _ShowTerminal; - set - { - if (value != _ShowTerminal) - { - _ShowTerminal = value; - OnPropertyChanged(); - } - } - } - public Options() - { - this.ResetToDefault(); - } - - public void LoadSaved() - { - try - { - string savedSettings = System.IO.File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "options.json")); - Options json = (Options)JsonConvert.DeserializeObject(savedSettings, typeof(Options)); - - this.PatchExtention = json.PatchExtention; - this.PatchSubdirectory = json.PatchSubdirectory; - this.PatchFileDestination = json.PatchFileDestination; - this.XDeltaArguments = json.XDeltaArguments; - this.ZipName = json.ZipName; - this.ShowFullPaths = json.ShowFullPaths; - this.CopyExecutables = json.CopyExecutables; - this.CreateBatchFileOnly = json.CreateBatchFileOnly; - this.ZipFilesWhenDone = json.ZipFilesWhenDone; - this.ShowTerminal = json.ShowTerminal; - - } catch (Exception e) - { - Debug.WriteLine("Failed to load saved options\n" + e); - } - } - - public async void SaveCurrent() - { - string json = JsonConvert.SerializeObject(this, Formatting.Indented); - System.IO.File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "options.json"), json); - } - - public void ResetToDefault() - { - this.PatchExtention = "vcdiff"; - this.PatchSubdirectory = "vcdiff"; - this.XDeltaArguments = "-B 1073741824 -e -9 -S djw -vfs"; - this.ZipName = "patch"; - this.PatchFileDestination = ""; - this.ShowFullPaths = false; - this.CopyExecutables = true; - this.CreateBatchFileOnly = false; - this.ZipFilesWhenDone = false; - this.ShowTerminal = false; - } - - public bool Validate() - { - bool valid = true; - if (!IsValidFilePath(this.PatchExtention)) - { - this.PatchExtention = "vcdiff"; - valid = false; - } - if (!IsValidFilePath(this.PatchSubdirectory)) - { - this.PatchSubdirectory = "vcdiff"; - valid = false; - } - //if (!Uri.IsWellFormedUriString(this.PatchExtention, UriKind.RelativeOrAbsolute)) - //{ - // this.XDeltaArguments = "-B 1073741824 -e -9 -S djw -vfs"; - //} - if (!IsValidFilePath(this.ZipName)) - { - this.ZipName = "patch"; - valid = false; - } - - return valid; - } - - private bool IsValidFilePath(string path) - { - bool valid = true; - foreach (char a in Path.GetInvalidFileNameChars()) - { - if (path.Contains(a)) - { - valid = false; - } - } - foreach (char a in Path.GetInvalidPathChars()) - { - if (path.Contains(a)) - { - valid = false; - } - } - return valid; - } - - public event PropertyChangedEventHandler PropertyChanged; - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } -} +/*Copyright 2020-2021 dan0v + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +using Newtonsoft.Json; +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; + +namespace xdelta3_cross_gui +{ + public class Options : INotifyPropertyChanged + { + private string _PatchExtention { get; set; } + private string _PatchSubdirectory { get; set; } + private string _PatchFileDestination { get; set; } + private string _XDeltaArguments { get; set; } + private string _ZipName { get; set; } + private bool _ShowFullPaths { get; set; } + private bool _CopyExecutables { get; set; } + private bool _CreateBatchFileOnly { get; set; } + private bool _ZipFilesWhenDone { get; set; } + private bool _ShowTerminal { get; set; } + + public string PatchExtention + { + get => _PatchExtention; + set + { + if (value != _PatchExtention) + { + _PatchExtention = value; + OnPropertyChanged(); + } + } + } + public string PatchSubdirectory + { + get => _PatchSubdirectory; + set + { + if (value != _PatchSubdirectory) + { + _PatchSubdirectory = value; + OnPropertyChanged(); + } + } + } + public string XDeltaArguments + { + get => _XDeltaArguments; + set + { + if (value != _XDeltaArguments) + { + _XDeltaArguments = value; + OnPropertyChanged(); + } + } + } + public string PatchFileDestination + { + get => _PatchFileDestination; + set + { + if (value != _PatchFileDestination) + { + _PatchFileDestination = value; + OnPropertyChanged(); + } + } + } + public string ZipName + { + get => _ZipName; + set + { + if (value != _ZipName) + { + _ZipName = value; + OnPropertyChanged(); + } + } + } + public bool ShowFullPaths + { + get => _ShowFullPaths; + set + { + if (value != _ShowFullPaths) + { + _ShowFullPaths = value; + OnPropertyChanged(); + } + } + } + public bool CopyExecutables + { + get => _CopyExecutables; + set + { + if (value != _CopyExecutables) + { + _CopyExecutables = value; + OnPropertyChanged(); + } + } + } + public bool CreateBatchFileOnly + { + get => _CreateBatchFileOnly; + set + { + if (value != _CreateBatchFileOnly) + { + _CreateBatchFileOnly = value; + OnPropertyChanged(); + } + } + } + public bool ZipFilesWhenDone + { + get => _ZipFilesWhenDone; + set + { + if (value != _ZipFilesWhenDone) + { + _ZipFilesWhenDone = value; + OnPropertyChanged(); + } + } + } + public bool ShowTerminal + { + get => _ShowTerminal; + set + { + if (value != _ShowTerminal) + { + _ShowTerminal = value; + OnPropertyChanged(); + } + } + } + public Options() + { + this.ResetToDefault(); + } + + public void LoadSaved() + { + try + { + string savedSettings = System.IO.File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "options.json")); + Options json = (Options)JsonConvert.DeserializeObject(savedSettings, typeof(Options)); + + this.PatchExtention = json.PatchExtention; + this.PatchSubdirectory = json.PatchSubdirectory; + this.PatchFileDestination = json.PatchFileDestination; + this.XDeltaArguments = json.XDeltaArguments; + this.ZipName = json.ZipName; + this.ShowFullPaths = json.ShowFullPaths; + this.CopyExecutables = json.CopyExecutables; + this.CreateBatchFileOnly = json.CreateBatchFileOnly; + this.ZipFilesWhenDone = json.ZipFilesWhenDone; + this.ShowTerminal = json.ShowTerminal; + + } catch (Exception e) + { + Debug.WriteLine("Failed to load saved options\n" + e); + } + } + + public async void SaveCurrent() + { + string json = JsonConvert.SerializeObject(this, Formatting.Indented); + System.IO.File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "options.json"), json); + } + + public void ResetToDefault() + { + this.PatchExtention = "vcdiff"; + this.PatchSubdirectory = "vcdiff"; + this.XDeltaArguments = "-B 1073741824 -e -9 -S djw -vfs"; + this.ZipName = "patch"; + this.PatchFileDestination = ""; + this.ShowFullPaths = false; + this.CopyExecutables = true; + this.CreateBatchFileOnly = false; + this.ZipFilesWhenDone = false; + this.ShowTerminal = false; + } + + public bool Validate() + { + bool valid = true; + if (!IsValidFilePath(this.PatchExtention)) + { + this.PatchExtention = "vcdiff"; + valid = false; + } + if (!IsValidFilePath(this.PatchSubdirectory)) + { + this.PatchSubdirectory = "vcdiff"; + valid = false; + } + //if (!Uri.IsWellFormedUriString(this.PatchExtention, UriKind.RelativeOrAbsolute)) + //{ + // this.XDeltaArguments = "-B 1073741824 -e -9 -S djw -vfs"; + //} + if (!IsValidFilePath(this.ZipName)) + { + this.ZipName = "patch"; + valid = false; + } + + return valid; + } + + private bool IsValidFilePath(string path) + { + bool valid = true; + foreach (char a in Path.GetInvalidFileNameChars()) + { + if (path.Contains(a)) + { + valid = false; + } + } + foreach (char a in Path.GetInvalidPathChars()) + { + if (path.Contains(a)) + { + valid = false; + } + } + return valid; + } + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/PatchCreator.cs b/Helpers/PatchCreator.cs similarity index 98% rename from PatchCreator.cs rename to Helpers/PatchCreator.cs index 0290075..74e4d95 100644 --- a/PatchCreator.cs +++ b/Helpers/PatchCreator.cs @@ -1,334 +1,334 @@ -/*Copyright 2020-2021 dan0v - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License.*/ - -using Avalonia.Threading; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Runtime.InteropServices; -using System.Threading; - -namespace xdelta3_cross_gui -{ - class PatchCreator - { - private MainWindow MainParent; - private double _Progress = 0; - public PatchCreator(MainWindow MainParent) - { - this.MainParent = MainParent; - } - public void CreateReadme() - { - if (!File.Exists(Path.Combine(this.MainParent.Options.PatchFileDestination, "exec"))) - { - Directory.CreateDirectory(Path.Combine(this.MainParent.Options.PatchFileDestination, "exec")); - } - if (!File.Exists(Path.Combine(this.MainParent.Options.PatchFileDestination, "original"))) - { - Directory.CreateDirectory(Path.Combine(this.MainParent.Options.PatchFileDestination, "original")); - } - StreamWriter readmeWriter = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "1.Readme.txt")); - readmeWriter.WriteLine("Created using xDelta3 Cross GUI " + MainWindow.VERSION + " by dan0v, https://github.com/dan0v/xdelta3-cross-gui"); - readmeWriter.WriteLine(""); - readmeWriter.WriteLine("Windows:"); - readmeWriter.WriteLine("1. Copy your original files into the 'original' folder with their original file names"); - readmeWriter.WriteLine("2. Double click the 2.Apply Patch-Windows.bat file and patching will begin"); - readmeWriter.WriteLine("3. Once patching is complete you will find your newly patched files in the 'output' folder"); - readmeWriter.WriteLine("4. Enjoy"); - readmeWriter.WriteLine(""); - readmeWriter.WriteLine("Linux:"); - readmeWriter.WriteLine("1. Copy your original files into the 'original' folder with their original file names"); - readmeWriter.WriteLine("2. In terminal, type: sh " + '"' + "2.Apply Patch-Linux.sh" + '"' + ". Patching should start automatically"); - readmeWriter.WriteLine("2. Alternatively, if you're using a GUI, double click 2.Apply Patch-Linux.sh and patching should start automatically (you may have to `chmod +x` to allow execution of the script)"); - readmeWriter.WriteLine("3. Once patching is complete you will find your newly patched files in the 'output' folder"); - readmeWriter.WriteLine("4. Enjoy"); - readmeWriter.WriteLine(""); - readmeWriter.WriteLine("MacOS:"); - readmeWriter.WriteLine("1. Copy your original files into the 'original' folder with their original file names"); - readmeWriter.WriteLine("2. Double click 2.Apply Patch-Mac.command and a terminal window should appear (you may have to `chmod +x` to allow execution of the script)"); - readmeWriter.WriteLine("3. Once patching is complete you will find your newly patched files in the 'output' folder"); - readmeWriter.WriteLine("4. Enjoy"); - readmeWriter.Close(); - } - - public void CreatePatchingBatchFiles() - { - this.MainParent.PatchProgress = 0; - this._Progress = 0; - - if (!File.Exists(Path.Combine(MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory)) && !this.MainParent.Options.CreateBatchFileOnly) - { - Directory.CreateDirectory(Path.Combine(MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory)); - } - - //Batch creation - Windows// - StreamWriter patchWriterWindows = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "2.Apply Patch-Windows.bat")); - patchWriterWindows.WriteLine("@echo off"); - patchWriterWindows.WriteLine("mkdir output"); - // Batch creation - Linux // - StreamWriter patchWriterLinux = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "2.Apply Patch-Linux.sh")); - patchWriterLinux.NewLine = "\n"; - patchWriterLinux.WriteLine("#!/bin/sh"); - patchWriterLinux.WriteLine("cd \"$(cd \"$(dirname \"$0\")\" && pwd)\""); - patchWriterLinux.WriteLine("mkdir ./output"); - patchWriterLinux.WriteLine("chmod +x ./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_LINUX)); - // Batch creation - Mac // - StreamWriter patchWriterMac = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "2.Apply Patch-Mac.command")); - patchWriterMac.NewLine = "\n"; - patchWriterMac.WriteLine("#!/bin/sh"); - patchWriterMac.WriteLine("cd \"$(cd \"$(dirname \"$0\")\" && pwd)\""); - patchWriterMac.WriteLine("mkdir ./output"); - patchWriterMac.WriteLine("chmod +x ./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_MACOS)); - - StreamWriter currentPatchScript = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "doNotDelete-In-Progress.bat")); - if (!this.MainParent.Options.CreateBatchFileOnly) - { - currentPatchScript.Close(); - try - { - File.Delete(Path.Combine(this.MainParent.Options.PatchFileDestination, "doNotDelete-In-Progress.bat")); - } - catch (Exception e) - { - Debug.WriteLine(e); - } - - currentPatchScript = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat")); - } - List oldFileNames = new List(); - List newFileNames = new List(); - this.MainParent.OldFilesList.ForEach(c => oldFileNames.Add(c.ShortName)); - this.MainParent.NewFilesList.ForEach(c => newFileNames.Add(c.ShortName)); - - patchWriterWindows.WriteLine("echo Place the files to be patched in the \"original\" directory with the following names:"); - patchWriterLinux.WriteLine("echo Place the files to be patched in the \\\"original\\\" directory with the following names:"); - patchWriterMac.WriteLine("echo Place the files to be patched in the \\\"original\\\" directory with the following names:"); - patchWriterWindows.WriteLine("echo --------------------"); - patchWriterLinux.WriteLine("echo --------------------"); - patchWriterMac.WriteLine("echo --------------------"); - - for (int i = 0; i < this.MainParent.OldFilesList.Count; i++) - { - patchWriterWindows.WriteLine("echo " + oldFileNames[i]); - patchWriterLinux.WriteLine("echo \"" + oldFileNames[i] + "\""); - patchWriterMac.WriteLine("echo \"" + oldFileNames[i] + "\""); - } - patchWriterWindows.WriteLine("echo --------------------"); - patchWriterLinux.WriteLine("echo --------------------"); - patchWriterMac.WriteLine("echo --------------------"); - - patchWriterWindows.WriteLine("echo Patched files will be in the \"output\" directory"); - patchWriterLinux.WriteLine("echo Patched files will be in the \\\"output\\\" directory"); - patchWriterMac.WriteLine("echo Patched files will be in the \\\"output\\\" directory"); - - patchWriterWindows.WriteLine("pause"); - patchWriterLinux.WriteLine("read -p \"Press enter to continue...\" inp"); - patchWriterMac.WriteLine("read -p \"Press enter to continue...\" inp"); - - for (int i = 0; i < this.MainParent.OldFilesList.Count; i++) - { - // Batch creation - Windows - patchWriterWindows.WriteLine("exec\\" + Path.GetFileName(MainWindow.XDELTA3_BINARY_WINDOWS) + " -v -d -s \".\\original\\{0}\" " + "\".\\" + this.MainParent.Options.PatchSubdirectory + "\\" + "{0}." + this.MainParent.Options.PatchExtention + "\" \".\\output\\{2}\"", oldFileNames[i], this.MainParent.Options.PatchSubdirectory + "\\" + (i + 1).ToString(), newFileNames[i]); - // Batch creation - Linux // - patchWriterLinux.WriteLine("./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_LINUX) + " -v -d -s \"./original/{0}\" " + '"' + this.MainParent.Options.PatchSubdirectory + '/' + "{0}." + this.MainParent.Options.PatchExtention + "\" \"./output/{2}\"", oldFileNames[i], this.MainParent.Options.PatchSubdirectory + (i + 1).ToString(), newFileNames[i]); - // Batch creation - Mac // - patchWriterMac.WriteLine("./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_MACOS) + " -v -d -s \"./original/{0}\" " + '"' + this.MainParent.Options.PatchSubdirectory + '/' + "{0}." + this.MainParent.Options.PatchExtention + "\" \"./output/{2}\"", oldFileNames[i], this.MainParent.Options.PatchSubdirectory + (i + 1).ToString(), newFileNames[i]); - - // Script for patch creation - if (!this.MainParent.Options.CreateBatchFileOnly) - { - currentPatchScript.WriteLine("\"" + MainWindow.XDELTA3_PATH + "\"" + " " + this.MainParent.Options.XDeltaArguments + " " + "\"" + this.MainParent.OldFilesList[i].FullPath + "\" \"" + this.MainParent.NewFilesList[i].FullPath + "\" \"" + Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, oldFileNames[i]) + "." + this.MainParent.Options.PatchExtention + "\""); - } - - } - patchWriterWindows.WriteLine("echo Completed!"); - patchWriterWindows.WriteLine("@pause"); - patchWriterWindows.Close(); - patchWriterLinux.Close(); - patchWriterMac.Close(); - - currentPatchScript.Close(); - - if (this.MainParent.Options.CreateBatchFileOnly) - { - try - { - File.Delete(Path.Combine(MainParent.Options.PatchFileDestination, "doNotDelete-In-Progress.bat")); - } - catch (Exception e) - { - Debug.WriteLine(e); - } - this.MainParent.PatchProgress = 0; - if (this.MainParent.Options.ZipFilesWhenDone) - { - this.ZipFiles(); - } - this.MainParent.AlreadyBusy = false; - Dispatcher.UIThread.InvokeAsync(new Action(() => - { - SuccessDialog dialog = new SuccessDialog(this.MainParent); - dialog.Show(); - dialog.Topmost = true; - dialog.Topmost = false; - })); - } - else - { - CreateNewXDeltaThread().Start(); - } - } - - private Thread CreateNewXDeltaThread() - { - return new Thread(() => - { - using (Process activeCMD = new Process()) - { - activeCMD.OutputDataReceived += HandleCMDOutput; - activeCMD.ErrorDataReceived += HandleCMDError; - - ProcessStartInfo info = new ProcessStartInfo(); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - info.FileName = Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - string args = Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat"); - string escapedArgs = "/bin/bash " + args.Replace("\"", "\\\"").Replace(" ", "\\ ").Replace("(", "\\(").Replace(")", "\\)"); - info.FileName = "/bin/bash"; - info.Arguments = $"-c \"{escapedArgs}\""; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - string args = Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat"); - string escapedArgs = "/bin/bash " + args.Replace("\"", "\\\"").Replace(" ", "\\ ").Replace("(", "\\(").Replace(")", "\\)"); - info.FileName = "/bin/bash"; - info.Arguments = $"-c \"{escapedArgs}\""; - } - - info.WindowStyle = ProcessWindowStyle.Hidden; - info.CreateNoWindow = true; - info.UseShellExecute = false; - info.RedirectStandardOutput = true; - info.RedirectStandardError = true; - - activeCMD.StartInfo = info; - activeCMD.EnableRaisingEvents = true; - - activeCMD.Start(); - activeCMD.BeginOutputReadLine(); - activeCMD.BeginErrorReadLine(); - activeCMD.WaitForExit(); - try - { - File.Delete(Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat")); - } - catch (Exception e) - { - Debug.WriteLine(e); - } - - if (this.MainParent.Options.ZipFilesWhenDone) - { - this.ZipFiles(); - } - this.MainParent.AlreadyBusy = false; - this.MainParent.PatchProgress = 0; - Dispatcher.UIThread.InvokeAsync(new Action(() => - { - SuccessDialog dialog = new SuccessDialog(this.MainParent); - dialog.Show(); - dialog.Topmost = true; - dialog.Topmost = false; - })); - } - }) - { IsBackground = true }; - } - - private void ZipFiles() - { - new Thread(() => - { - this.MainParent.PatchProgressIsIndeterminate = true; - if (File.Exists(Path.Combine(this.MainParent.Options.PatchFileDestination, "..", this.MainParent.Options.ZipName + ".zip"))) - { - File.Delete(Path.Combine(this.MainParent.Options.PatchFileDestination, "..", this.MainParent.Options.ZipName + ".zip")); - } - ZipFile.CreateFromDirectory(this.MainParent.Options.PatchFileDestination, Path.Combine(this.MainParent.Options.PatchFileDestination, "..", this.MainParent.Options.ZipName + ".zip")); - this.MainParent.PatchProgressIsIndeterminate = false; - }) - { IsBackground = true }.Start(); - } - - private void HandleCMDOutput(object sender, DataReceivedEventArgs e) - { - double prog = 0; - if (e != null && e.Data != null && (e.Data + "").Trim() != "") - { - Debug.WriteLine(e.Data); - this._Progress++; - - prog = (this._Progress / this.MainParent.OldFilesList.Count) * 100; - this.MainParent.PatchProgress = prog > 100 ? 100 : prog; - - this.MainParent.Console.AddLine(e.Data); - } - } - - private void HandleCMDError(object sender, DataReceivedEventArgs e) - { - if (e != null && e.Data != null && (e.Data + "").Trim() != "") - { - Debug.WriteLine(e.Data); - - this.MainParent.Console.AddLine(e.Data); - } - } - - public void CopyExecutables() - { - try - { - File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "exec", MainWindow.XDELTA3_BINARY_WINDOWS), Path.Combine(this.MainParent.Options.PatchFileDestination, "exec", MainWindow.XDELTA3_BINARY_WINDOWS), true); - } - catch (Exception e) - { - Debug.WriteLine(e); - } - try - { - File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "exec", MainWindow.XDELTA3_BINARY_LINUX), Path.Combine(this.MainParent.Options.PatchFileDestination, "exec", MainWindow.XDELTA3_BINARY_LINUX), true); - } - catch (Exception e) - { - Debug.WriteLine(e); - } - try - { - File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "exec", MainWindow.XDELTA3_BINARY_MACOS), Path.Combine(this.MainParent.Options.PatchFileDestination, "exec", MainWindow.XDELTA3_BINARY_MACOS), true); - } - catch (Exception e) - { - Debug.WriteLine(e); - } - } - } -} +/*Copyright 2020-2021 dan0v + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +using Avalonia.Threading; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using System.Threading; + +namespace xdelta3_cross_gui +{ + class PatchCreator + { + private MainWindow MainParent; + private double _Progress = 0; + public PatchCreator(MainWindow MainParent) + { + this.MainParent = MainParent; + } + public void CreateReadme() + { + if (!File.Exists(Path.Combine(this.MainParent.Options.PatchFileDestination, "exec"))) + { + Directory.CreateDirectory(Path.Combine(this.MainParent.Options.PatchFileDestination, "exec")); + } + if (!File.Exists(Path.Combine(this.MainParent.Options.PatchFileDestination, "original"))) + { + Directory.CreateDirectory(Path.Combine(this.MainParent.Options.PatchFileDestination, "original")); + } + StreamWriter readmeWriter = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "1.Readme.txt")); + readmeWriter.WriteLine("Created using xDelta3 Cross GUI " + MainWindow.VERSION + " by dan0v, https://github.com/dan0v/xdelta3-cross-gui"); + readmeWriter.WriteLine(""); + readmeWriter.WriteLine("Windows:"); + readmeWriter.WriteLine("1. Copy your original files into the 'original' folder with their original file names"); + readmeWriter.WriteLine("2. Double click the 2.Apply Patch-Windows.bat file and patching will begin"); + readmeWriter.WriteLine("3. Once patching is complete you will find your newly patched files in the 'output' folder"); + readmeWriter.WriteLine("4. Enjoy"); + readmeWriter.WriteLine(""); + readmeWriter.WriteLine("Linux:"); + readmeWriter.WriteLine("1. Copy your original files into the 'original' folder with their original file names"); + readmeWriter.WriteLine("2. In terminal, type: sh " + '"' + "2.Apply Patch-Linux.sh" + '"' + ". Patching should start automatically"); + readmeWriter.WriteLine("2. Alternatively, if you're using a GUI, double click 2.Apply Patch-Linux.sh and patching should start automatically (you may have to `chmod +x` to allow execution of the script)"); + readmeWriter.WriteLine("3. Once patching is complete you will find your newly patched files in the 'output' folder"); + readmeWriter.WriteLine("4. Enjoy"); + readmeWriter.WriteLine(""); + readmeWriter.WriteLine("MacOS:"); + readmeWriter.WriteLine("1. Copy your original files into the 'original' folder with their original file names"); + readmeWriter.WriteLine("2. Double click 2.Apply Patch-Mac.command and a terminal window should appear (you may have to `chmod +x` to allow execution of the script)"); + readmeWriter.WriteLine("3. Once patching is complete you will find your newly patched files in the 'output' folder"); + readmeWriter.WriteLine("4. Enjoy"); + readmeWriter.Close(); + } + + public void CreatePatchingBatchFiles() + { + this.MainParent.PatchProgress = 0; + this._Progress = 0; + + if (!File.Exists(Path.Combine(MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory)) && !this.MainParent.Options.CreateBatchFileOnly) + { + Directory.CreateDirectory(Path.Combine(MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory)); + } + + //Batch creation - Windows// + StreamWriter patchWriterWindows = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "2.Apply Patch-Windows.bat")); + patchWriterWindows.WriteLine("@echo off"); + patchWriterWindows.WriteLine("mkdir output"); + // Batch creation - Linux // + StreamWriter patchWriterLinux = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "2.Apply Patch-Linux.sh")); + patchWriterLinux.NewLine = "\n"; + patchWriterLinux.WriteLine("#!/bin/sh"); + patchWriterLinux.WriteLine("cd \"$(cd \"$(dirname \"$0\")\" && pwd)\""); + patchWriterLinux.WriteLine("mkdir ./output"); + patchWriterLinux.WriteLine("chmod +x ./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_LINUX)); + // Batch creation - Mac // + StreamWriter patchWriterMac = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "2.Apply Patch-Mac.command")); + patchWriterMac.NewLine = "\n"; + patchWriterMac.WriteLine("#!/bin/sh"); + patchWriterMac.WriteLine("cd \"$(cd \"$(dirname \"$0\")\" && pwd)\""); + patchWriterMac.WriteLine("mkdir ./output"); + patchWriterMac.WriteLine("chmod +x ./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_MACOS)); + + StreamWriter currentPatchScript = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, "doNotDelete-In-Progress.bat")); + if (!this.MainParent.Options.CreateBatchFileOnly) + { + currentPatchScript.Close(); + try + { + File.Delete(Path.Combine(this.MainParent.Options.PatchFileDestination, "doNotDelete-In-Progress.bat")); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + + currentPatchScript = new StreamWriter(Path.Combine(MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat")); + } + List oldFileNames = new List(); + List newFileNames = new List(); + this.MainParent.OldFilesList.ForEach(c => oldFileNames.Add(c.ShortName)); + this.MainParent.NewFilesList.ForEach(c => newFileNames.Add(c.ShortName)); + + patchWriterWindows.WriteLine("echo Place the files to be patched in the \"original\" directory with the following names:"); + patchWriterLinux.WriteLine("echo Place the files to be patched in the \\\"original\\\" directory with the following names:"); + patchWriterMac.WriteLine("echo Place the files to be patched in the \\\"original\\\" directory with the following names:"); + patchWriterWindows.WriteLine("echo --------------------"); + patchWriterLinux.WriteLine("echo --------------------"); + patchWriterMac.WriteLine("echo --------------------"); + + for (int i = 0; i < this.MainParent.OldFilesList.Count; i++) + { + patchWriterWindows.WriteLine("echo " + oldFileNames[i]); + patchWriterLinux.WriteLine("echo \"" + oldFileNames[i] + "\""); + patchWriterMac.WriteLine("echo \"" + oldFileNames[i] + "\""); + } + patchWriterWindows.WriteLine("echo --------------------"); + patchWriterLinux.WriteLine("echo --------------------"); + patchWriterMac.WriteLine("echo --------------------"); + + patchWriterWindows.WriteLine("echo Patched files will be in the \"output\" directory"); + patchWriterLinux.WriteLine("echo Patched files will be in the \\\"output\\\" directory"); + patchWriterMac.WriteLine("echo Patched files will be in the \\\"output\\\" directory"); + + patchWriterWindows.WriteLine("pause"); + patchWriterLinux.WriteLine("read -p \"Press enter to continue...\" inp"); + patchWriterMac.WriteLine("read -p \"Press enter to continue...\" inp"); + + for (int i = 0; i < this.MainParent.OldFilesList.Count; i++) + { + // Batch creation - Windows + patchWriterWindows.WriteLine("exec\\" + Path.GetFileName(MainWindow.XDELTA3_BINARY_WINDOWS) + " -v -d -s \".\\original\\{0}\" " + "\".\\" + this.MainParent.Options.PatchSubdirectory + "\\" + "{0}." + this.MainParent.Options.PatchExtention + "\" \".\\output\\{2}\"", oldFileNames[i], this.MainParent.Options.PatchSubdirectory + "\\" + (i + 1).ToString(), newFileNames[i]); + // Batch creation - Linux // + patchWriterLinux.WriteLine("./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_LINUX) + " -v -d -s \"./original/{0}\" " + '"' + this.MainParent.Options.PatchSubdirectory + '/' + "{0}." + this.MainParent.Options.PatchExtention + "\" \"./output/{2}\"", oldFileNames[i], this.MainParent.Options.PatchSubdirectory + (i + 1).ToString(), newFileNames[i]); + // Batch creation - Mac // + patchWriterMac.WriteLine("./exec/" + Path.GetFileName(MainWindow.XDELTA3_BINARY_MACOS) + " -v -d -s \"./original/{0}\" " + '"' + this.MainParent.Options.PatchSubdirectory + '/' + "{0}." + this.MainParent.Options.PatchExtention + "\" \"./output/{2}\"", oldFileNames[i], this.MainParent.Options.PatchSubdirectory + (i + 1).ToString(), newFileNames[i]); + + // Script for patch creation + if (!this.MainParent.Options.CreateBatchFileOnly) + { + currentPatchScript.WriteLine("\"" + MainWindow.XDELTA3_PATH + "\"" + " " + this.MainParent.Options.XDeltaArguments + " " + "\"" + this.MainParent.OldFilesList[i].FullPath + "\" \"" + this.MainParent.NewFilesList[i].FullPath + "\" \"" + Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, oldFileNames[i]) + "." + this.MainParent.Options.PatchExtention + "\""); + } + + } + patchWriterWindows.WriteLine("echo Completed!"); + patchWriterWindows.WriteLine("@pause"); + patchWriterWindows.Close(); + patchWriterLinux.Close(); + patchWriterMac.Close(); + + currentPatchScript.Close(); + + if (this.MainParent.Options.CreateBatchFileOnly) + { + try + { + File.Delete(Path.Combine(MainParent.Options.PatchFileDestination, "doNotDelete-In-Progress.bat")); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + this.MainParent.PatchProgress = 0; + if (this.MainParent.Options.ZipFilesWhenDone) + { + this.ZipFiles(); + } + this.MainParent.AlreadyBusy = false; + Dispatcher.UIThread.InvokeAsync(new Action(() => + { + SuccessDialog dialog = new SuccessDialog(this.MainParent); + dialog.Show(); + dialog.Topmost = true; + dialog.Topmost = false; + })); + } + else + { + CreateNewXDeltaThread().Start(); + } + } + + private Thread CreateNewXDeltaThread() + { + return new Thread(() => + { + using (Process activeCMD = new Process()) + { + activeCMD.OutputDataReceived += HandleCMDOutput; + activeCMD.ErrorDataReceived += HandleCMDError; + + ProcessStartInfo info = new ProcessStartInfo(); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + info.FileName = Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat"); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + string args = Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat"); + string escapedArgs = "/bin/bash " + args.Replace("\"", "\\\"").Replace(" ", "\\ ").Replace("(", "\\(").Replace(")", "\\)"); + info.FileName = "/bin/bash"; + info.Arguments = $"-c \"{escapedArgs}\""; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + string args = Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat"); + string escapedArgs = "/bin/bash " + args.Replace("\"", "\\\"").Replace(" ", "\\ ").Replace("(", "\\(").Replace(")", "\\)"); + info.FileName = "/bin/bash"; + info.Arguments = $"-c \"{escapedArgs}\""; + } + + info.WindowStyle = ProcessWindowStyle.Hidden; + info.CreateNoWindow = true; + info.UseShellExecute = false; + info.RedirectStandardOutput = true; + info.RedirectStandardError = true; + + activeCMD.StartInfo = info; + activeCMD.EnableRaisingEvents = true; + + activeCMD.Start(); + activeCMD.BeginOutputReadLine(); + activeCMD.BeginErrorReadLine(); + activeCMD.WaitForExit(); + try + { + File.Delete(Path.Combine(this.MainParent.Options.PatchFileDestination, this.MainParent.Options.PatchSubdirectory, "doNotDelete-In-Progress.bat")); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + + if (this.MainParent.Options.ZipFilesWhenDone) + { + this.ZipFiles(); + } + this.MainParent.AlreadyBusy = false; + this.MainParent.PatchProgress = 0; + Dispatcher.UIThread.InvokeAsync(new Action(() => + { + SuccessDialog dialog = new SuccessDialog(this.MainParent); + dialog.Show(); + dialog.Topmost = true; + dialog.Topmost = false; + })); + } + }) + { IsBackground = true }; + } + + private void ZipFiles() + { + new Thread(() => + { + this.MainParent.PatchProgressIsIndeterminate = true; + if (File.Exists(Path.Combine(this.MainParent.Options.PatchFileDestination, "..", this.MainParent.Options.ZipName + ".zip"))) + { + File.Delete(Path.Combine(this.MainParent.Options.PatchFileDestination, "..", this.MainParent.Options.ZipName + ".zip")); + } + ZipFile.CreateFromDirectory(this.MainParent.Options.PatchFileDestination, Path.Combine(this.MainParent.Options.PatchFileDestination, "..", this.MainParent.Options.ZipName + ".zip")); + this.MainParent.PatchProgressIsIndeterminate = false; + }) + { IsBackground = true }.Start(); + } + + private void HandleCMDOutput(object sender, DataReceivedEventArgs e) + { + double prog = 0; + if (e != null && e.Data != null && (e.Data + "").Trim() != "") + { + Debug.WriteLine(e.Data); + this._Progress++; + + prog = (this._Progress / this.MainParent.OldFilesList.Count) * 100; + this.MainParent.PatchProgress = prog > 100 ? 100 : prog; + + this.MainParent.Console.AddLine(e.Data); + } + } + + private void HandleCMDError(object sender, DataReceivedEventArgs e) + { + if (e != null && e.Data != null && (e.Data + "").Trim() != "") + { + Debug.WriteLine(e.Data); + + this.MainParent.Console.AddLine(e.Data); + } + } + + public void CopyExecutables() + { + try + { + File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "exec", MainWindow.XDELTA3_BINARY_WINDOWS), Path.Combine(this.MainParent.Options.PatchFileDestination, "exec", MainWindow.XDELTA3_BINARY_WINDOWS), true); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + try + { + File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "exec", MainWindow.XDELTA3_BINARY_LINUX), Path.Combine(this.MainParent.Options.PatchFileDestination, "exec", MainWindow.XDELTA3_BINARY_LINUX), true); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + try + { + File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "exec", MainWindow.XDELTA3_BINARY_MACOS), Path.Combine(this.MainParent.Options.PatchFileDestination, "exec", MainWindow.XDELTA3_BINARY_MACOS), true); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + } + } +} diff --git a/Publish/Linux/Appimage.sh b/Publish/Linux/Appimage.sh index 616e740..54f1a40 100644 --- a/Publish/Linux/Appimage.sh +++ b/Publish/Linux/Appimage.sh @@ -17,7 +17,7 @@ limitations under the License. ORIGIN="$(pwd)" cd "../.." -dotnet publish --configuration Release --framework netcoreapp3.1 -r linux-x64 /p:PublishTrimmed=true -o bin/Release/netcoreapp3.1/publishLinux +dotnet publish --configuration Release --framework netcoreapp3.1 -r linux-x64 --self-contained true /p:PublishTrimmed=true -o bin/Release/netcoreapp3.1/publishLinux cd "$ORIGIN" APP_NAME="xDelta3 Cross GUI" diff --git a/Publish/Linux/LooseLinux.sh b/Publish/Linux/LooseLinux.sh index b83595d..bce5d3c 100644 --- a/Publish/Linux/LooseLinux.sh +++ b/Publish/Linux/LooseLinux.sh @@ -17,7 +17,7 @@ limitations under the License. ORIGIN="$(pwd)" cd "../.." -dotnet publish --configuration Release --framework netcoreapp3.1 -r linux-x64 /p:PublishTrimmed=true -o bin/Release/netcoreapp3.1/publishLinux +dotnet publish --configuration Release --framework netcoreapp3.1 -r linux-x64 --self-contained true /p:PublishTrimmed=true -o bin/Release/netcoreapp3.1/publishLinux cd "$ORIGIN" APP_NAME="xDelta3 Cross GUI" diff --git a/Publish/MacOS/MacOS.sh b/Publish/MacOS/MacOS.sh index 97a4103..c24311d 100644 --- a/Publish/MacOS/MacOS.sh +++ b/Publish/MacOS/MacOS.sh @@ -17,7 +17,7 @@ limitations under the License. ORIGIN="$(pwd)" cd "../.." -dotnet publish --configuration Release --framework netcoreapp3.1 -r osx-x64 /p:PublishTrimmed=true -o bin/Release/netcoreapp3.1/publishMac +dotnet publish --configuration Release --framework netcoreapp3.1 -r osx-x64 --self-contained true /p:PublishTrimmed=true -o bin/Release/netcoreapp3.1/publishMac cd "$ORIGIN" APP_NAME="xDelta3 Cross GUI.app" diff --git a/Publish/Windows/Windows.sh b/Publish/Windows/Windows.sh index dec403d..4d30b47 100644 --- a/Publish/Windows/Windows.sh +++ b/Publish/Windows/Windows.sh @@ -17,7 +17,7 @@ limitations under the License. ORIGIN="$(pwd)" cd "../.." -dotnet publish --configuration Release --framework netcoreapp3.1 -r win-x86 /p:PublishTrimmed=true -o bin/Release/netcoreapp3.1/publishWin +dotnet publish --configuration Release --framework netcoreapp3.1 -r win-x86 --self-contained true /p:CopyOutputSymbolsToPublishDirectory=false /p:PublishTrimmed=true -p:PublishSingleFile=true -o bin/Release/netcoreapp3.1/publishWin cd "$ORIGIN" APP_NAME="xDelta3 Cross GUI" diff --git a/README.md b/README.md index a3eaf02..9353615 100644 --- a/README.md +++ b/README.md @@ -21,28 +21,15 @@ A cross-platform GUI for creating xDelta3 patches, inspired by [Moodkiller/xdelt 2. Run executable (`xdelta3_cross_gui.exe`) ### Linux *(x86_64)* -#### Use AppImage for a packaged, native experience -1. *Optionally install [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher) to integrate xDelta3 Cross Gui into your desktop environment* +1. *Optionally install [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher) to integrate xDelta3 Cross GUI into your desktop environment* 2. Download and unzip [latest Linux AppImage build](https://github.com/dan0v/xdelta3-cross-gui/releases/latest/) from the Releases page 3. Mark `xDelta3_Cross_Gui-x86_64.AppImage` as executable (`chmod 755 xDelta3_Cross_Gui-x86_64.AppImage`) 4. Run executable (`xDelta3_Cross_Gui-x86_64.AppImage`) -#### Or use the unpackaged version -1. Download and unzip [latest Linux build](https://github.com/dan0v/xdelta3-cross-gui/releases/latest/) from the Releases page -2. Run executable (`xdelta3_cross_gui`) - ### Mac *(x86_64)* 1. Download and unzip [latest MacOS build](https://github.com/dan0v/xdelta3-cross-gui/releases/latest/) from the Releases page 2. Run (`xDelta3 Cross GUI.app`) -#### Optionally use your own builds of xDelta3 -You may provide your own builds of xDelta3, instead of using the included versions, by replacing the binaries in the locations shown below with files with the same names, or including your own build in your System Path, with the name `xdelta3`. - -- *Windows -* unavailable -- *Linux AppImage -* unavailable -- *Linux unpackaged -* `Assets/exec` -- *Mac -* `Contents/MacOS/Assets/exec` - ## Screenshots ![GitHub Logo](Extra%20Resources/Progress-demo.png) diff --git a/PathFileComponent.axaml b/Windows/Components/PathFileComponent.axaml similarity index 98% rename from PathFileComponent.axaml rename to Windows/Components/PathFileComponent.axaml index 6d0d693..1c0faee 100644 --- a/PathFileComponent.axaml +++ b/Windows/Components/PathFileComponent.axaml @@ -1,32 +1,32 @@ - - - - - - - - - - 0 - - - - + + + + + + + + + + 0 + + + + diff --git a/PathFileComponent.axaml.cs b/Windows/Components/PathFileComponent.axaml.cs similarity index 94% rename from PathFileComponent.axaml.cs rename to Windows/Components/PathFileComponent.axaml.cs index 628ca5c..a7ce023 100644 --- a/PathFileComponent.axaml.cs +++ b/Windows/Components/PathFileComponent.axaml.cs @@ -1,107 +1,104 @@ -/*Copyright 2020-2021 dan0v - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License.*/ - -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Runtime.CompilerServices; - -namespace xdelta3_cross_gui -{ - public class PathFileComponent : UserControl - { - private MainWindow MainParent { get; set; } - public string FullPath { get; set; } - public string ShortName { get; set; } - public int Index { get; set; } - - public bool _Shifted = false; - - private MainWindow.FileCategory _FileCategory; - - private bool _IsSelected = false; - public bool IsSelected { - get => _IsSelected; - set - { - if (value != _IsSelected) - { - _IsSelected = value; - OnPropertyChanged(); - } - } - } - - TextBlock txt_blk_Index; - TextBox txt_bx_Path; - CheckBox chk_IsChecked; - - public PathFileComponent() - { - this.InitializeComponent(); - } - public PathFileComponent(MainWindow parent, string url, int index, MainWindow.FileCategory fileCategory) - { - this.InitializeComponent(); - - - this.txt_blk_Index = this.FindControl("txt_blk_Index"); - this.txt_bx_Path = this.FindControl("txt_bx_Path"); - this.chk_IsChecked = this.FindControl("chk_IsChecked"); - - this.MainParent = parent; - this.FullPath = ""; - this.ShortName = ""; - this.Index = index; - this._FileCategory = fileCategory; - - - try - { - this.FullPath = Path.GetFullPath(url); - this.ShortName = Path.GetFileName(url); - } - catch (Exception e) { Debug.WriteLine(e); } - - this.UpdateValues(); - } - - public void UpdateValues() - { - txt_blk_Index.Text = this.Index + ""; - - txt_bx_Path.Text = this.MainParent.Options.ShowFullPaths ? this.FullPath : this.ShortName; - - chk_IsChecked.IsChecked = this.IsSelected; - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - public event PropertyChangedEventHandler PropertyChanged; - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } - -} +/*Copyright 2020-2021 dan0v + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; + +namespace xdelta3_cross_gui +{ + public class PathFileComponent : UserControl + { + private MainWindow MainParent { get; set; } + public string FullPath { get; set; } + public string ShortName { get; set; } + public int Index { get; set; } + + public bool _Shifted = false; + + private MainWindow.FileCategory _FileCategory; + + private bool _IsSelected = false; + public bool IsSelected { + get => _IsSelected; + set + { + if (value != _IsSelected) + { + _IsSelected = value; + OnPropertyChanged(); + } + } + } + + TextBlock txt_blk_Index; + TextBox txt_bx_Path; + CheckBox chk_IsChecked; + + public PathFileComponent() + { + this.InitializeComponent(); + } + public PathFileComponent(MainWindow parent, string url, int index, MainWindow.FileCategory fileCategory) + { + this.InitializeComponent(); + + + this.txt_blk_Index = this.FindControl("txt_blk_Index"); + this.txt_bx_Path = this.FindControl("txt_bx_Path"); + this.chk_IsChecked = this.FindControl("chk_IsChecked"); + + this.MainParent = parent; + this.FullPath = ""; + this.ShortName = ""; + this.Index = index; + this._FileCategory = fileCategory; + + + try + { + this.FullPath = Path.GetFullPath(url); + this.ShortName = Path.GetFileName(url); + } + catch (Exception e) { Debug.WriteLine(e); } + + this.UpdateValues(); + } + + public void UpdateValues() + { + txt_blk_Index.Text = this.Index + ""; + + txt_bx_Path.Text = this.MainParent.Options.ShowFullPaths ? this.FullPath : this.ShortName; + + chk_IsChecked.IsChecked = this.IsSelected; + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + +} diff --git a/Console.axaml b/Windows/Console.axaml similarity index 97% rename from Console.axaml rename to Windows/Console.axaml index 2fa44b3..4c91864 100644 --- a/Console.axaml +++ b/Windows/Console.axaml @@ -1,33 +1,33 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/Console.axaml.cs b/Windows/Console.axaml.cs similarity index 96% rename from Console.axaml.cs rename to Windows/Console.axaml.cs index a9d6319..f2a09ca 100644 --- a/Console.axaml.cs +++ b/Windows/Console.axaml.cs @@ -1,90 +1,89 @@ -/*Copyright 2020-2021 dan0v - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License.*/ - -using Avalonia; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Markup.Xaml; -using Avalonia.Threading; -using System; -using System.ComponentModel; -using System.Diagnostics; - -namespace xdelta3_cross_gui -{ - public class Console : Window - { - private static MainWindow _Parent; - - public bool CanClose = false; - - TextBlock txt_blk_Output; - ScrollViewer sv_ScrollConsole; - public Console() - { - this.InitializeComponent(); - this.txt_blk_Output = this.FindControl("txt_blk_Output"); - this.sv_ScrollConsole = this.FindControl("sv_ScrollConsole"); - } - - public void SetParent(MainWindow parent) - { - _Parent = parent; - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - protected override void OnClosing(CancelEventArgs e) - { - e.Cancel = !this.CanClose; - - // Hide window instead of closing - if (!this.CanClose) - { - try - { - _Parent.ShowTerminal = false; - } - catch (Exception e1) - { - Debug.WriteLine(e1); - } - } - } - - protected override void OnPointerPressed(PointerPressedEventArgs e) - { - if (e.Pointer.IsPrimary) - { - this.BeginMoveDrag(e); - } - base.OnPointerPressed(e); - } - - public void AddLine(string input) - { - Dispatcher.UIThread.InvokeAsync(new Action(() => - { - if (this.txt_blk_Output.Text.Length > 20000) - { - this.txt_blk_Output.Text = this.txt_blk_Output.Text.Substring(15000, this.txt_blk_Output.Text.Length - 15000); - } - this.txt_blk_Output.Text += input + "\n\n"; - })); - } - } -} +/*Copyright 2020-2021 dan0v + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Markup.Xaml; +using Avalonia.Threading; +using System; +using System.ComponentModel; +using System.Diagnostics; + +namespace xdelta3_cross_gui +{ + public class Console : Window + { + private static MainWindow _Parent; + + public bool CanClose = false; + + TextBlock txt_blk_Output; + ScrollViewer sv_ScrollConsole; + public Console() + { + this.InitializeComponent(); + this.txt_blk_Output = this.FindControl("txt_blk_Output"); + this.sv_ScrollConsole = this.FindControl("sv_ScrollConsole"); + } + + public void SetParent(MainWindow parent) + { + _Parent = parent; + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + protected override void OnClosing(CancelEventArgs e) + { + e.Cancel = !this.CanClose; + + // Hide window instead of closing + if (!this.CanClose) + { + try + { + _Parent.ShowTerminal = false; + } + catch (Exception e1) + { + Debug.WriteLine(e1); + } + } + } + + protected override void OnPointerPressed(PointerPressedEventArgs e) + { + if (e.Pointer.IsPrimary) + { + this.BeginMoveDrag(e); + } + base.OnPointerPressed(e); + } + + public void AddLine(string input) + { + Dispatcher.UIThread.InvokeAsync(new Action(() => + { + if (this.txt_blk_Output.Text.Length > 20000) + { + this.txt_blk_Output.Text = this.txt_blk_Output.Text.Substring(15000, this.txt_blk_Output.Text.Length - 15000); + } + this.txt_blk_Output.Text += input + "\n\n"; + })); + } + } +} diff --git a/ErrorDialog.axaml b/Windows/Dialogs/ErrorDialog.axaml similarity index 93% rename from ErrorDialog.axaml rename to Windows/Dialogs/ErrorDialog.axaml index 413aff4..1276443 100644 --- a/ErrorDialog.axaml +++ b/Windows/Dialogs/ErrorDialog.axaml @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/ErrorDialog.axaml.cs b/Windows/Dialogs/ErrorDialog.axaml.cs similarity index 96% rename from ErrorDialog.axaml.cs rename to Windows/Dialogs/ErrorDialog.axaml.cs index 89d501d..ace0198 100644 --- a/ErrorDialog.axaml.cs +++ b/Windows/Dialogs/ErrorDialog.axaml.cs @@ -1,77 +1,76 @@ -/*Copyright 2020-2021 dan0v - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License.*/ - -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using System.Collections.Generic; - -namespace xdelta3_cross_gui -{ - public class ErrorDialog : Window - { - List missingOldFiles; - List missingNewFiles; - Button btn_Dismiss; - TextBlock txt_blk_MissingOld; - TextBlock txt_blk_MissingNew; - Grid grd_MissingFiles; - - public ErrorDialog() - { - this.InitializeComponent(); - } - - public ErrorDialog(List missingOldFiles, List missingNewFiles) - { - this.InitializeComponent(); - this.missingNewFiles = missingNewFiles; - this.missingOldFiles = missingOldFiles; - this.Configure(); - } - - private void Configure() - { - this.btn_Dismiss = this.FindControl - - - + + + + + + + + + + + diff --git a/SuccessDialog.axaml.cs b/Windows/Dialogs/SuccessDialog.axaml.cs similarity index 96% rename from SuccessDialog.axaml.cs rename to Windows/Dialogs/SuccessDialog.axaml.cs index 0ffef59..ad70a87 100644 --- a/SuccessDialog.axaml.cs +++ b/Windows/Dialogs/SuccessDialog.axaml.cs @@ -1,85 +1,84 @@ -/*Copyright 2020-2021 dan0v - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License.*/ - -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using System; -using System.Diagnostics; -using System.IO; - -namespace xdelta3_cross_gui -{ - public class SuccessDialog : Window - { - private MainWindow MainParent; - - Button btn_Dismiss; - Button btn_OpenDestination; - - private string _Destination = ""; - public SuccessDialog() - { - this.InitializeComponent(); - } - - public SuccessDialog(MainWindow MainParent) - { - this.InitializeComponent(); - this.MainParent = MainParent; - this.Configure(); - } - private void Configure() - { - if (this.MainParent.Options.ZipFilesWhenDone) - { - this._Destination = Path.Combine(this.MainParent.Options.PatchFileDestination, ".."); - } - else - { - this._Destination = this.MainParent.Options.PatchFileDestination; - } - this.btn_Dismiss = this.FindControl + + + diff --git a/Windows/Dialogs/UpdateDialog.axaml.cs b/Windows/Dialogs/UpdateDialog.axaml.cs new file mode 100644 index 0000000..03706c8 --- /dev/null +++ b/Windows/Dialogs/UpdateDialog.axaml.cs @@ -0,0 +1,80 @@ +/*Copyright 2020-2021 dan0v + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using System; +using System.Diagnostics; + +namespace xdelta3_cross_gui +{ + public class UpdateDialog : Window + { + private MainWindow MainParent; + private string newVersion = ""; + + TextBlock txt_blk_Prompt; + Button btn_Dismiss; + Button btn_GoToReleases; + + public UpdateDialog() + { + this.InitializeComponent(); + } + + public UpdateDialog(MainWindow MainParent, string newVersion) + { + this.InitializeComponent(); + this.MainParent = MainParent; + this.newVersion = newVersion; + this.Configure(); + } + private void Configure() + { + this.btn_Dismiss = this.FindControl - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MainWindow.axaml.cs b/Windows/MainWindow.axaml.cs similarity index 96% rename from MainWindow.axaml.cs rename to Windows/MainWindow.axaml.cs index 1476d95..4c6c4a2 100644 --- a/MainWindow.axaml.cs +++ b/Windows/MainWindow.axaml.cs @@ -12,7 +12,6 @@ You may obtain a copy of the License at See the License for the specific language governing permissions and limitations under the License.*/ -using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; @@ -22,6 +21,7 @@ limitations under the License.*/ using System.ComponentModel; using System.Diagnostics; using System.IO; +using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -38,6 +38,8 @@ public class MainWindow : Window, INotifyPropertyChanged public const string XDELTA3_BINARY_WINDOWS = "xdelta3_x86_64_win.exe"; public const string XDELTA3_BINARY_LINUX = "xdelta3_x64_linux"; public const string XDELTA3_BINARY_MACOS = "xdelta3_mac"; + public const string VERSION_CHECK_URL = "https://github.com/dan0v/xdelta3-cross-gui/releases/latest/download/version.txt"; + public const string RELEASES_PAGE = "https://github.com/dan0v/xdelta3-cross-gui/releases/latest/"; public string Credits { get { return "xDelta3 Cross-Platform GUI by dan0v, using xDelta 3.1.0\n\nHeavily inspired by xDelta GUI 2\nby Jordi Vermeulen (Modified by Brian Campbell)"; } } private bool _XDeltaOnSystemPath { get; set; } @@ -343,7 +345,7 @@ public void SaveSettingsClicked(object sender, RoutedEventArgs args) public void ResetDefaultsClicked(object sender, RoutedEventArgs args) { this.Options.ResetToDefault(); - this.Options.SaveCurrent(); + //this.Options.SaveCurrent(); } public void GoClicked(object sender, RoutedEventArgs args) @@ -481,7 +483,7 @@ private void Configure() this.sv_NewFilesDisplay.AddHandler(DragDrop.DropEvent, NewFilesDropped); this.Console.SetParent(this); - + this.CheckForUpdates(); } private void CheckFileCounts() @@ -658,6 +660,26 @@ private void ToggleAllFilesSelection(FileCategory category) } } + private async void CheckForUpdates() + { + try + { + HttpResponseMessage response = await new HttpClient().GetAsync(VERSION_CHECK_URL); + response.EnsureSuccessStatusCode(); + string newVer = await response.Content.ReadAsStringAsync(); + if (newVer.Trim() != VERSION.Trim()) + { + UpdateDialog updateDialog = new UpdateDialog(this, newVer); + updateDialog.Show(); + updateDialog.Activate(); + } + } + catch (Exception e) + { + Debug.WriteLine(e); + } + } + private static string GetVersion() { string version = ""; diff --git a/xdelta3_cross_gui.csproj b/xdelta3_cross_gui.csproj index b8eb842..efbb83a 100644 --- a/xdelta3_cross_gui.csproj +++ b/xdelta3_cross_gui.csproj @@ -6,7 +6,7 @@ dan0v A cross-platform graphical user interface for xDelta3 patching Icon.ico - 1.0.6 + 1.0.7