diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..8c944d8
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "Fantome.Libraries.League"]
+ path = Fantome.Libraries.League
+ url = https://github.com/LoL-Fantome/Fantome.Libraries.League
diff --git a/Fantome.Libraries.League b/Fantome.Libraries.League
new file mode 160000
index 0000000..1e32695
--- /dev/null
+++ b/Fantome.Libraries.League
@@ -0,0 +1 @@
+Subproject commit 1e32695ac269d7f1eb387d37032ba56d937f5d04
diff --git a/Obsidian.sln b/Obsidian.sln
index 16c18f3..d6f6f2d 100644
--- a/Obsidian.sln
+++ b/Obsidian.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26730.15
+VisualStudioVersion = 15.0.27004.2005
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Obsidian", "Obsidian\Obsidian.csproj", "{7ABEFBE2-A68B-4D8E-A24E-7867C4AD1364}"
EndProject
diff --git a/Obsidian/App.config b/Obsidian/App.config
index 016d28f..8d23437 100644
--- a/Obsidian/App.config
+++ b/Obsidian/App.config
@@ -1,6 +1,6 @@
-
+
-
+
-
\ No newline at end of file
+
diff --git a/Obsidian/MainWindow.xaml b/Obsidian/MainWindow.xaml
index b3928dd..9a1feff 100644
--- a/Obsidian/MainWindow.xaml
+++ b/Obsidian/MainWindow.xaml
@@ -33,7 +33,7 @@
-
+
diff --git a/Obsidian/MainWindow.xaml.cs b/Obsidian/MainWindow.xaml.cs
index 66629f8..2f65886 100644
--- a/Obsidian/MainWindow.xaml.cs
+++ b/Obsidian/MainWindow.xaml.cs
@@ -1,19 +1,23 @@
-using Fantome.Libraries.League.Helpers.Cryptography;
-using Fantome.Libraries.League.Helpers.Utilities;
-using Fantome.Libraries.League.IO.BIN;
+using Fantome.Libraries.League.Helpers.Utilities;
using Fantome.Libraries.League.IO.WAD;
+using log4net;
+using log4net.Core;
using Microsoft.Win32;
+using Obsidian.Utils;
using Obsidian.Windows;
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.IO;
using System.Linq;
-using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
+using Newtonsoft.Json.Linq;
+using Fantome.Libraries.League.Helpers.Cryptography;
+using System.Text;
namespace Obsidian
{
@@ -22,13 +26,36 @@ namespace Obsidian
///
public partial class MainWindow : Window
{
+ public Dictionary Config { get; }
+ private static readonly ILog Logger = LogManager.GetLogger("MainWindow");
public WADFile Wad { get; set; }
public WADEntry CurrentlySelectedEntry { get; set; }
public static Dictionary StringDictionary { get; set; } = new Dictionary();
public MainWindow()
{
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+
+ if (File.Exists("config.json"))
+ {
+ this.Config = ConfigUtilities.ReadConfig();
+ }
+ else
+ {
+ this.Config = ConfigUtilities.DefaultConfig;
+ ConfigUtilities.WriteDefaultConfig();
+ }
+
+ Logging.InitializeLogger((string)this.Config["LoggingPattern"], this.Config["LogLevel"] as Level);
+ Logger.Info("Initialized Logger");
+
InitializeComponent();
+ Logger.Info("Initialized Window");
+ }
+
+ private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ Logging.LogFatal(Logger, "An unhandled exception was thrown, the program will now terminate", (Exception)e.ExceptionObject);
}
private void image_MouseDown(object sender, MouseButtonEventArgs e)
@@ -39,16 +66,39 @@ private void image_MouseDown(object sender, MouseButtonEventArgs e)
private void buttonOpenWadFile_Click(object sender, RoutedEventArgs e)
{
- OpenFileDialog dialog = new OpenFileDialog();
- dialog.Title = "Select the WAD File you want to open";
- dialog.Multiselect = false;
- dialog.Filter = "WAD Files (*.wad;*.wad.client)|*.wad;*.wad.client";
+ OpenFileDialog dialog = new OpenFileDialog
+ {
+ Title = "Select the WAD File you want to open",
+ Multiselect = false,
+ Filter = "WAD Files (*.wad;*.wad.client)|*.wad;*.wad.client"
+ };
if (dialog.ShowDialog() == true)
{
- this.Wad = new WADFile(dialog.FileName);
+ try
+ {
+ this.Wad?.Dispose();
+ this.Wad = new WADFile(dialog.FileName);
+ }
+ catch (Exception excp)
+ {
+ Logging.LogException(Logger, "Failed to load WAD File: " + dialog.FileName, excp);
+ return;
+ }
+
StringDictionary = new Dictionary();
- GenerateWADStrings();
+
+ if ((bool)this.Config["GenerateWadDictionary"])
+ {
+ try
+ {
+ WADHashGenerator.GenerateWADStrings(Logger, this.Wad, StringDictionary);
+ }
+ catch (Exception excp)
+ {
+ Logging.LogException(Logger, "Failed to Generate WAD String Dictionary", excp);
+ }
+ }
this.buttonSaveWadFile.IsEnabled = true;
this.buttonImportHashtable.IsEnabled = true;
@@ -57,128 +107,81 @@ private void buttonOpenWadFile_Click(object sender, RoutedEventArgs e)
this.butonAddFileRedirection.IsEnabled = true;
this.CurrentlySelectedEntry = null;
this.datagridWadEntries.ItemsSource = this.Wad.Entries;
- }
- }
- private void GenerateWADStrings()
- {
- foreach (WADEntry wadEntry in this.Wad.Entries.Where(x => x.Type == EntryType.Compressed))
- {
- byte[] entryData = wadEntry.GetContent(true);
- if (Utilities.GetLeagueFileExtensionType(entryData) == LeagueFileType.BIN)
- {
- List wadEntryStrings = new List();
- BINFile bin = new BINFile(new MemoryStream(entryData));
- foreach (BINFileEntry binEntry in bin.Entries)
- {
- foreach (BINFileValue binValue in binEntry.Values.Where(x => x.Type == BINFileValueType.String || x.Value.GetType() == typeof(BINFileValueList)))
- {
- if (binValue.Type == BINFileValueType.String)
- {
- wadEntryStrings.Add(binValue.Value as string);
- }
- else if (
- binValue.Type == BINFileValueType.DoubleTypeList ||
- binValue.Type == BINFileValueType.LargeStaticTypeList ||
- binValue.Type == BINFileValueType.List ||
- binValue.Type == BINFileValueType.List2 ||
- binValue.Type == BINFileValueType.SmallStaticTypeList)
- {
- wadEntryStrings.AddRange(GetValueStrings(binValue));
- }
- }
- }
-
- using (XXHash64 xxHash = XXHash64.Create())
- {
- wadEntryStrings.ForEach(x =>
- {
- if (x != "")
- {
- string loweredName = x.ToLower();
- ulong hash = BitConverter.ToUInt64(xxHash.ComputeHash(Encoding.ASCII.GetBytes(loweredName)), 0);
- if (!StringDictionary.ContainsKey(hash))
- {
- StringDictionary.Add(hash, x);
- }
- }
- });
- }
- }
+ Logger.Info("Opened WAD File: " + dialog.FileName);
}
}
- public IEnumerable GetValueStrings(BINFileValue value)
+ private void buttonSaveWadFile_Click(object sender, RoutedEventArgs e)
{
- List strings = new List();
- if (value.Type == BINFileValueType.String)
+ SaveFileDialog dialog = new SaveFileDialog
{
- strings.Add(value.Value as string);
- }
- else
+ Title = "Select the path to save your WAD File",
+ Filter = "WAD File (*.wad)|*.wad|WAD Client file (*.wad.client)|*.wad.client",
+ AddExtension = true
+ };
+
+ if (dialog.ShowDialog() == true)
{
- BINFileValueList valueList = value.Value as BINFileValueList;
- foreach (BINFileValue binValue in valueList.Entries)
+ try
{
- if (binValue.Type == BINFileValueType.String)
- {
- strings.Add(binValue.Value as string);
- }
- else if (
- binValue.Type == BINFileValueType.DoubleTypeList ||
- binValue.Type == BINFileValueType.LargeStaticTypeList ||
- binValue.Type == BINFileValueType.List ||
- binValue.Type == BINFileValueType.List2 ||
- binValue.Type == BINFileValueType.SmallStaticTypeList)
- {
- foreach (BINFileValue binValue2 in (binValue.Value as BINFileValueList).Entries.Where(x => x.Type == BINFileValueType.String || x.Value.GetType() == typeof(BINFileValueList)))
- {
- strings.AddRange(GetValueStrings(binValue2));
- }
- }
+ this.Wad.Write(dialog.FileName, (byte)(long)this.Config["WadSaveMajorVersion"], (byte)(long)this.Config["WadSaveMinorVersion"]);
+ }
+ catch (Exception excp)
+ {
+ Logging.LogException(Logger, "Could not write a WAD File to: " + dialog.FileName, excp);
+ return;
}
- }
-
- return strings.AsEnumerable();
- }
-
- private void buttonSaveWadFile_Click(object sender, RoutedEventArgs e)
- {
- SaveFileDialog dialog = new SaveFileDialog();
- dialog.Title = "Select the path to save your WAD File";
- dialog.Filter = "WAD File (*.wad)|*.wad|WAD Client file (*.wad.client)|*.wad.client";
- dialog.AddExtension = true;
- if (dialog.ShowDialog() == true)
- {
- string filePath = dialog.FileName;
- this.Wad.Write(filePath);
MessageBox.Show("Writing Succesful!", "", MessageBoxButton.OK, MessageBoxImage.Information);
+ Logger.Info("Successfully written a WAD File to: " + dialog.FileName);
}
}
private void buttonImportHashtable_Click(object sender, RoutedEventArgs e)
{
- OpenFileDialog dialog = new OpenFileDialog();
- dialog.Title = "Select the Hashtable files you want to load";
- dialog.Multiselect = true;
- dialog.Filter = "Hashtable Files (*.hashtable)|*.hashtable";
+ OpenFileDialog dialog = new OpenFileDialog
+ {
+ Title = "Select the Hashtable files you want to load",
+ Multiselect = true,
+ Filter = "Hashtable Files (*.hashtable)|*.hashtable"
+ };
if (dialog.ShowDialog() == true)
{
- foreach (string fileName in dialog.FileNames)
+ try
{
- foreach (string line in File.ReadAllLines(fileName))
+ foreach (string fileName in dialog.FileNames)
{
- ulong hash = 0;
- string[] lineSplit = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
-
- if (ulong.TryParse(lineSplit[0], out hash) && !StringDictionary.ContainsKey(hash))
+ foreach (string line in File.ReadAllLines(fileName))
{
- StringDictionary.Add(ulong.Parse(lineSplit[0]), lineSplit[1]);
+ string[] lineSplit = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+
+ if (ulong.TryParse(lineSplit[0], out ulong hash) && !StringDictionary.ContainsKey(hash))
+ {
+ StringDictionary.Add(ulong.Parse(lineSplit[0]), lineSplit[1]);
+ }
+ else
+ {
+ using (XXHash64 xxHash = XXHash64.Create())
+ {
+ ulong key = BitConverter.ToUInt64(xxHash.ComputeHash(Encoding.ASCII.GetBytes(lineSplit[0].ToLower())), 0);
+ if (!StringDictionary.ContainsKey(key))
+ {
+ StringDictionary.Add(key, lineSplit[0].ToLower());
+ }
+ }
+ }
}
+
+ Logger.Info("Imported Hashtable from: " + fileName);
}
}
+ catch (Exception excp)
+ {
+ Logging.LogException(Logger, "Failed to Import Hashtable", excp);
+ return;
+ }
CollectionViewSource.GetDefaultView(this.datagridWadEntries.ItemsSource).Refresh();
}
@@ -186,12 +189,12 @@ private void buttonImportHashtable_Click(object sender, RoutedEventArgs e)
private void datagridWadEntries_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
- if (this.datagridWadEntries.SelectedItem != null && this.datagridWadEntries.SelectedItem is WADEntry)
+ if (this.datagridWadEntries.SelectedItem is WADEntry)
{
this.buttonRemoveEntry.IsEnabled = true;
- if ((this.datagridWadEntries.SelectedItem as WADEntry).Type != EntryType.FileRedirection)
+ if (((WADEntry)this.datagridWadEntries.SelectedItem).Type != EntryType.FileRedirection)
{
- this.CurrentlySelectedEntry = this.datagridWadEntries.SelectedItem as WADEntry;
+ this.CurrentlySelectedEntry = (WADEntry)this.datagridWadEntries.SelectedItem;
this.buttonModifyData.IsEnabled = true;
}
else
@@ -199,30 +202,14 @@ private void datagridWadEntries_SelectedCellsChanged(object sender, SelectedCell
this.CurrentlySelectedEntry = null;
this.buttonModifyData.IsEnabled = false;
}
-
- if (StringDictionary.ContainsKey((this.datagridWadEntries.SelectedItem as WADEntry).XXHash))
- {
- this.textBlockSelectedEntryName.Text = StringDictionary[(this.datagridWadEntries.SelectedItem as WADEntry).XXHash];
- }
- else
- {
- this.textBlockSelectedEntryName.Text = "";
- }
}
- if (this.datagridWadEntries.SelectedItems != null && this.datagridWadEntries.SelectedItems.Cast().ToList().Exists(x => x.Type != EntryType.FileRedirection))
- {
- this.buttonExtract.IsEnabled = true;
- }
- else
- {
- this.buttonExtract.IsEnabled = false;
- }
+ this.buttonExtract.IsEnabled = this.datagridWadEntries.SelectedItems.Cast().ToList().Exists(x => x.Type != EntryType.FileRedirection);
}
private void datagridWadEntries_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
- if ((e.Row.DataContext as WADEntry).Type != EntryType.FileRedirection)
+ if (((WADEntry)e.Row.DataContext).Type != EntryType.FileRedirection)
{
e.Cancel = true;
}
@@ -254,14 +241,32 @@ private void buttonRemoveEntry_Click(object sender, RoutedEventArgs e)
private void buttonModifyData_Click(object sender, RoutedEventArgs e)
{
- OpenFileDialog dialog = new OpenFileDialog();
- dialog.Multiselect = false;
- dialog.Title = "Select the File by which you want to replace the current one";
+ OpenFileDialog dialog = new OpenFileDialog
+ {
+ Multiselect = false,
+ Title = "Select the File by which you want to replace the current one"
+ };
if (dialog.ShowDialog() == true)
{
- this.CurrentlySelectedEntry.EditData(File.ReadAllBytes(dialog.FileName));
- CollectionViewSource.GetDefaultView(this.datagridWadEntries.ItemsSource).Refresh();
+ try
+ {
+ this.CurrentlySelectedEntry.EditData(File.ReadAllBytes(dialog.FileName));
+ CollectionViewSource.GetDefaultView(this.datagridWadEntries.ItemsSource).Refresh();
+ }
+ catch (Exception excp)
+ {
+ string entryName = BitConverter.ToString(BitConverter.GetBytes(this.CurrentlySelectedEntry.XXHash)).Replace("-", "");
+ if (StringDictionary.ContainsKey(this.CurrentlySelectedEntry.XXHash))
+ {
+ entryName = StringDictionary[this.CurrentlySelectedEntry.XXHash];
+ }
+
+ Logging.LogException(Logger, "Failed to modify the data of Entry: " + entryName, excp);
+ return;
+ }
+
+ Logger.Info("Modified Data of Entry: " + BitConverter.ToString(BitConverter.GetBytes(this.CurrentlySelectedEntry.XXHash)).Replace("-", ""));
MessageBox.Show("Entry Modified Succesfully!", "", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
@@ -272,15 +277,46 @@ private void buttonExtract_Click(object sender, RoutedEventArgs e)
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
+ try
+ {
+ ExtractWAD(dialog.SelectedPath, this.datagridWadEntries.SelectedItems.Cast().Where(x => x.Type != EntryType.FileRedirection).ToList());
+ }
+ catch (Exception excp)
+ {
+ Logging.LogException(Logger, "Extraction of the currently opened WAD File failed", excp);
+ }
+ }
+ }
- foreach (WADEntry entry in this.datagridWadEntries.SelectedItems.Cast().Where(x => x.Type != EntryType.FileRedirection))
+ private void ExtractWAD(string selectedPath, List selectedEntries)
+ {
+ this.progressBarWadExtraction.Visibility = Visibility.Visible;
+ this.progressBarWadExtraction.Maximum = selectedEntries.Count;
+ this.IsEnabled = false;
+
+ BackgroundWorker wadExtractor = new BackgroundWorker
+ {
+ WorkerReportsProgress = true
+ };
+
+ wadExtractor.ProgressChanged += (sender, args) =>
+ {
+ this.progressBarWadExtraction.Value = args.ProgressPercentage;
+ };
+
+ wadExtractor.DoWork += (sender, e) =>
+ {
+ Dictionary entries = new Dictionary();
+ double progress = 0;
+
+ foreach (WADEntry entry in selectedEntries)
{
byte[] entryData = entry.GetContent(true);
- string entryName = "";
+ string entryName;
if (StringDictionary.ContainsKey(entry.XXHash))
{
entryName = StringDictionary[entry.XXHash];
- Directory.CreateDirectory(string.Format("{0}//{1}", dialog.SelectedPath, System.IO.Path.GetDirectoryName(entryName)));
+ Directory.CreateDirectory(string.Format("{0}//{1}", selectedPath, Path.GetDirectoryName(entryName)));
}
else
{
@@ -288,28 +324,68 @@ private void buttonExtract_Click(object sender, RoutedEventArgs e)
entryName += "." + Utilities.GetEntryExtension(Utilities.GetLeagueFileExtensionType(entryData));
}
- File.WriteAllBytes(string.Format("{0}//{1}", dialog.SelectedPath, entryName), entryData);
+ entries.Add(entryName, entryData);
+ progress += 0.5;
+ wadExtractor.ReportProgress((int)progress);
}
+ if ((bool)this.Config["ParallelExtraction"])
+ {
+ Parallel.ForEach(entries, (entry) =>
+ {
+ File.WriteAllBytes(string.Format("{0}//{1}", selectedPath, entry.Key), entry.Value);
+ progress += 0.5;
+ wadExtractor.ReportProgress((int)progress);
+ });
+ }
+ else
+ {
+ foreach (KeyValuePair entry in entries)
+ {
+ File.WriteAllBytes(string.Format("{0}//{1}", selectedPath, entry.Key), entry.Value);
+ progress += 0.5;
+ wadExtractor.ReportProgress((int)progress);
+ }
+ }
+ };
+
+ wadExtractor.RunWorkerCompleted += (sender, args) =>
+ {
+ this.IsEnabled = true;
+ this.progressBarWadExtraction.Value = 0;
+ this.progressBarWadExtraction.Visibility = Visibility.Hidden;
MessageBox.Show("Extraction Succesfull!", "", MessageBoxButton.OK, MessageBoxImage.Information);
- }
+ Logger.Info("WAD Extraction Successfull!");
+ };
+
+ wadExtractor.RunWorkerAsync();
}
private void buttonExtractHashtable_Click(object sender, RoutedEventArgs e)
{
- SaveFileDialog dialog = new SaveFileDialog();
- dialog.Title = "Select the path to save your Hashtable File";
- dialog.Filter = "Hashtable File (*.hashtable)|*.hashtable";
- dialog.AddExtension = true;
+ SaveFileDialog dialog = new SaveFileDialog
+ {
+ Title = "Select the path to save your Hashtable File",
+ Filter = "Hashtable File (*.hashtable)|*.hashtable",
+ AddExtension = true
+ };
if (dialog.ShowDialog() == true)
{
- List lines = new List();
- foreach (KeyValuePair pair in StringDictionary)
+ try
+ {
+ List lines = new List();
+ foreach (KeyValuePair pair in StringDictionary)
+ {
+ lines.Add(pair.Key.ToString() + " " + pair.Value);
+ }
+ File.WriteAllLines(dialog.FileName, lines.ToArray());
+ }
+ catch (Exception exception)
{
- lines.Add(pair.Key.ToString() + " " + pair.Value);
+ Logging.LogException(Logger, "Failed to Extract the current Hashtable", exception);
+ return;
}
- File.WriteAllLines(dialog.FileName, lines.ToArray());
MessageBox.Show("Writing Succesful!", "", MessageBoxButton.OK, MessageBoxImage.Information);
}
diff --git a/Obsidian/Obsidian.csproj b/Obsidian/Obsidian.csproj
index 121121a..a5060c4 100644
--- a/Obsidian/Obsidian.csproj
+++ b/Obsidian/Obsidian.csproj
@@ -8,11 +8,12 @@
WinExe
Obsidian
Obsidian
- v4.7
+ v4.6.2
512
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
4
true
+
AnyCPU
@@ -33,7 +34,13 @@
prompt
4
+
+ icon.ico
+
+
+ ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll
+
..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
@@ -58,6 +65,9 @@
MSBuild:Compile
Designer
+
+
+
@@ -125,8 +135,8 @@
-
- {80F5DF93-19A2-4731-8CD1-982F165D7361}
+
+ {80f5df93-19a2-4731-8cd1-982f165d7361}
Fantome.Libraries.League
diff --git a/Obsidian/Properties/AssemblyInfo.cs b/Obsidian/Properties/AssemblyInfo.cs
index 02ae738..dc68c04 100644
--- a/Obsidian/Properties/AssemblyInfo.cs
+++ b/Obsidian/Properties/AssemblyInfo.cs
@@ -51,5 +51,5 @@
// 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.3.0.1")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.4.0.0")]
+[assembly: AssemblyFileVersion("1.4.0.0")]
diff --git a/Obsidian/Properties/Resources.Designer.cs b/Obsidian/Properties/Resources.Designer.cs
index 5b99403..669fed8 100644
--- a/Obsidian/Properties/Resources.Designer.cs
+++ b/Obsidian/Properties/Resources.Designer.cs
@@ -8,10 +8,10 @@
//
//------------------------------------------------------------------------------
-namespace Obsidian.Properties
-{
-
-
+namespace Obsidian.Properties {
+ using System;
+
+
///
/// A strongly-typed resource class, for looking up localized strings, etc.
///
@@ -19,51 +19,43 @@ namespace Obsidian.Properties
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Resources
- {
-
+ internal class Resources {
+
private static global::System.Resources.ResourceManager resourceMan;
-
+
private static global::System.Globalization.CultureInfo resourceCulture;
-
+
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Resources()
- {
+ internal Resources() {
}
-
+
///
/// Returns the cached ResourceManager instance used by this class.
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager
- {
- get
- {
- if ((resourceMan == null))
- {
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Obsidian.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
-
+
///
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture
- {
- get
- {
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
return resourceCulture;
}
- set
- {
+ set {
resourceCulture = value;
}
}
diff --git a/Obsidian/Properties/Settings.Designer.cs b/Obsidian/Properties/Settings.Designer.cs
index c07635c..04e4c17 100644
--- a/Obsidian/Properties/Settings.Designer.cs
+++ b/Obsidian/Properties/Settings.Designer.cs
@@ -8,21 +8,17 @@
//
//------------------------------------------------------------------------------
-namespace Obsidian.Properties
-{
-
-
+namespace Obsidian.Properties {
+
+
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
- {
-
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.3.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default
- {
- get
- {
+
+ public static Settings Default {
+ get {
return defaultInstance;
}
}
diff --git a/Obsidian/Utils/ConfigUtilities.cs b/Obsidian/Utils/ConfigUtilities.cs
new file mode 100644
index 0000000..479bcbb
--- /dev/null
+++ b/Obsidian/Utils/ConfigUtilities.cs
@@ -0,0 +1,30 @@
+using log4net.Core;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Obsidian.Utils
+{
+ public static class ConfigUtilities
+ {
+ public static readonly Dictionary DefaultConfig = new Dictionary()
+ {
+ { "LoggingPattern", "[%utcdate{ABSOLUTE}] | [%-5level] | [%-20logger: (%-4line)] | %message%newline" },
+ { "LogLevel", Level.Info },
+ { "WadSaveMajorVersion", 2 },
+ { "WadSaveMinorVersion", 0 },
+ { "GenerateWadDictionary", true },
+ { "ParallelExtraction", true }
+ };
+
+ public static Dictionary ReadConfig()
+ {
+ return JsonConvert.DeserializeObject>(File.ReadAllText("config.json"));
+ }
+
+ public static void WriteDefaultConfig()
+ {
+ File.WriteAllText("config.json", JsonConvert.SerializeObject(DefaultConfig, Formatting.Indented));
+ }
+ }
+}
diff --git a/Obsidian/Utils/Logging.cs b/Obsidian/Utils/Logging.cs
new file mode 100644
index 0000000..98c868e
--- /dev/null
+++ b/Obsidian/Utils/Logging.cs
@@ -0,0 +1,38 @@
+using log4net;
+using log4net.Appender;
+using log4net.Config;
+using log4net.Core;
+using log4net.Layout;
+using System;
+using System.Windows;
+
+namespace Obsidian.Utils
+{
+ public static class Logging
+ {
+ public static void InitializeLogger(string loggingPattern, Level logLevel)
+ {
+ FileAppender appender = new FileAppender
+ {
+ Layout = new PatternLayout(loggingPattern),
+ File = "ObsidianLog.txt",
+ AppendToFile = true,
+ Threshold = logLevel
+ };
+ appender.ActivateOptions();
+ BasicConfigurator.Configure(appender);
+ }
+
+ public static void LogException(ILog logger, string message, Exception exception)
+ {
+ MessageBox.Show(string.Format("{0}\n{1}\n{2}", message, exception.Message, exception.StackTrace), "", MessageBoxButton.OK, MessageBoxImage.Error);
+ logger.Error(message, exception);
+ }
+
+ public static void LogFatal(ILog logger, string message, Exception exception)
+ {
+ MessageBox.Show(string.Format("{0}\n{1}\n{2}", message, exception.Message, exception.StackTrace), "", MessageBoxButton.OK, MessageBoxImage.Error);
+ logger.Fatal(message, exception);
+ }
+ }
+}
diff --git a/Obsidian/Utils/WADHashGenerator.cs b/Obsidian/Utils/WADHashGenerator.cs
new file mode 100644
index 0000000..fc6bf02
--- /dev/null
+++ b/Obsidian/Utils/WADHashGenerator.cs
@@ -0,0 +1,153 @@
+using Fantome.Libraries.League.Helpers.Cryptography;
+using Fantome.Libraries.League.Helpers.Utilities;
+using Fantome.Libraries.League.IO.BIN;
+using Fantome.Libraries.League.IO.WAD;
+using log4net;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Obsidian.Utils
+{
+ public static class WADHashGenerator
+ {
+ public static void GenerateWADStrings(ILog logger, WADFile wad, Dictionary stringDictionary)
+ {
+ foreach (WADEntry wadEntry in wad.Entries.Where(x => x.Type == EntryType.Compressed))
+ {
+ byte[] entryData = wadEntry.GetContent(true);
+ if (Utilities.GetLeagueFileExtensionType(entryData) == LeagueFileType.BIN)
+ {
+ List wadEntryStrings = new List();
+ BINFile bin = null;
+
+ try
+ {
+ bin = new BINFile(new MemoryStream(entryData));
+
+ }
+ catch
+ {
+ logger.Warn("Loading Dictionary Strings from WAD Entry: "
+ + BitConverter.ToString(BitConverter.GetBytes(wadEntry.XXHash)).Replace("-", "")
+ + " failed");
+ continue;
+ }
+
+ wadEntryStrings.AddRange(GetLinkedFileStrings(bin.LinkedFiles).Distinct());
+
+ foreach (BINFileEntry binEntry in bin.Entries)
+ {
+ foreach (BINFileValue binValue in binEntry.Values.Where(x =>
+ x.Type == BINFileValueType.String || x.Value.GetType() == typeof(BINFileValueList)))
+ {
+ switch (binValue.Type)
+ {
+ case BINFileValueType.String:
+ wadEntryStrings.Add(binValue.Value as string);
+ break;
+ case BINFileValueType.PairList:
+ case BINFileValueType.LargeStaticTypeList:
+ case BINFileValueType.List:
+ case BINFileValueType.List2:
+ case BINFileValueType.SmallStaticTypeList:
+ wadEntryStrings.AddRange(GetValueStrings(binValue));
+ break;
+ }
+ }
+ }
+
+ using (XXHash64 xxHash = XXHash64.Create())
+ {
+ wadEntryStrings.ForEach(x =>
+ {
+ if (x != "")
+ {
+ string loweredName = x.ToLower();
+ ulong hash = BitConverter.ToUInt64(xxHash.ComputeHash(Encoding.ASCII.GetBytes(loweredName)), 0);
+ if (!stringDictionary.ContainsKey(hash))
+ {
+ stringDictionary.Add(hash, x);
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ private static IEnumerable GetLinkedFileStrings(List linkedFiles)
+ {
+ List characterNames = new List();
+
+ foreach (string linkedFile in linkedFiles)
+ {
+ if (linkedFile.StartsWith("DATA/Characters"))
+ {
+ yield return linkedFile;
+ string withoutStart = linkedFile.Remove(0, 16);
+ characterNames.Add(withoutStart.Substring(0, withoutStart.IndexOf('/')));
+ continue;
+ }
+
+ string[] strings = linkedFile.Split(new char[] {'_'}, StringSplitOptions.RemoveEmptyEntries);
+ characterNames.Add(strings[0].Remove(0, 5));
+
+ string extension = strings[strings.Length - 1].Substring(strings[strings.Length - 1].IndexOf(".", StringComparison.Ordinal));
+ strings[strings.Length - 1] = strings[strings.Length - 1].Replace(extension, "");
+
+ characterNames = characterNames.Distinct().ToList();
+
+ for (int i = 0; i < characterNames.Count; i++)
+ {
+ for (int j = 1; j < strings.Length; j += 2)
+ {
+ yield return string.Format("DATA/Characters/{0}/{1}/{2}{3}", characterNames[i], strings[j], strings[j + 1], extension);
+ }
+
+ yield return string.Format("DATA/Characters/{0}/Skins/Root{1}", characterNames[i], extension);
+ }
+ }
+ }
+
+ private static IEnumerable GetValueStrings(BINFileValue value)
+ {
+ List strings = new List();
+ if (value.Type == BINFileValueType.String)
+ {
+ strings.Add(value.Value as string);
+ }
+ else
+ {
+ if (value.Value is BINFileValueList valueList)
+ {
+ foreach (BINFileValue binValue in valueList.Entries.Where(x => x is BINFileValue))
+ {
+ switch (binValue.Type)
+ {
+ case BINFileValueType.String:
+ strings.Add(binValue.Value as string);
+ break;
+ case BINFileValueType.PairList:
+ case BINFileValueType.LargeStaticTypeList:
+ case BINFileValueType.List:
+ case BINFileValueType.List2:
+ case BINFileValueType.SmallStaticTypeList:
+ foreach (BINFileValue binValue2 in ((BINFileValueList)binValue.Value).Entries.Where(x =>
+ x is BINFileValue &&
+ ((BINFileValue)x).Type == BINFileValueType.String))
+ {
+ strings.AddRange(GetValueStrings(binValue2));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return strings.AsEnumerable();
+ }
+ }
+}
diff --git a/Obsidian/ValueConverters/WadNameConverter.cs b/Obsidian/ValueConverters/WadNameConverter.cs
index 4789217..b4db573 100644
--- a/Obsidian/ValueConverters/WadNameConverter.cs
+++ b/Obsidian/ValueConverters/WadNameConverter.cs
@@ -25,9 +25,6 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
return finalName;
}
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}
}
diff --git a/Obsidian/Windows/FileAddWindow.xaml.cs b/Obsidian/Windows/FileAddWindow.xaml.cs
index 89b4deb..0d6547a 100644
--- a/Obsidian/Windows/FileAddWindow.xaml.cs
+++ b/Obsidian/Windows/FileAddWindow.xaml.cs
@@ -26,8 +26,10 @@ private void fileAddWindow_Closed(object sender, EventArgs e)
private void buttonSelectFile_Click(object sender, RoutedEventArgs e)
{
- OpenFileDialog openFileDialog = new OpenFileDialog();
- openFileDialog.Multiselect = false;
+ OpenFileDialog openFileDialog = new OpenFileDialog
+ {
+ Multiselect = false
+ };
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
@@ -42,7 +44,7 @@ private void buttonAddEntry_Click(object sender, RoutedEventArgs e)
{
this.MainWindow.Wad.AddEntry(this.textboxPath.Text, File.ReadAllBytes(this.textboxFile.Text), this.checkboxCompress.IsChecked.Value);
CollectionViewSource.GetDefaultView(this.MainWindow.datagridWadEntries.ItemsSource).Refresh();
- this.Close();
+ Close();
}
catch (Exception exception)
{
diff --git a/Obsidian/Windows/FileRedirectionAddWindow.xaml.cs b/Obsidian/Windows/FileRedirectionAddWindow.xaml.cs
index 3a33f0d..e986d0e 100644
--- a/Obsidian/Windows/FileRedirectionAddWindow.xaml.cs
+++ b/Obsidian/Windows/FileRedirectionAddWindow.xaml.cs
@@ -34,7 +34,7 @@ private void buttonAddFileRedirectionEntry_Click(object sender, RoutedEventArgs
{
this.MainWindow.Wad.AddEntry(this.textboxFile.Text, this.textboxPath.Text);
CollectionViewSource.GetDefaultView(this.MainWindow.datagridWadEntries.ItemsSource).Refresh();
- this.Close();
+ Close();
}
catch (Exception exception)
{
diff --git a/Obsidian/packages.config b/Obsidian/packages.config
index e157ba1..a3df3a8 100644
--- a/Obsidian/packages.config
+++ b/Obsidian/packages.config
@@ -1,4 +1,5 @@
+
\ No newline at end of file