diff --git a/BinaryObjectScanner.Protection/BinaryObjectScanner.Protection.csproj b/BinaryObjectScanner.Protection/BinaryObjectScanner.Protection.csproj
index e9d50e9a..a6022398 100644
--- a/BinaryObjectScanner.Protection/BinaryObjectScanner.Protection.csproj
+++ b/BinaryObjectScanner.Protection/BinaryObjectScanner.Protection.csproj
@@ -26,4 +26,8 @@
+
+
+
+
diff --git a/BinaryObjectScanner.Protection/XCP.cs b/BinaryObjectScanner.Protection/XCP.cs
index c3e82a9c..012e8146 100644
--- a/BinaryObjectScanner.Protection/XCP.cs
+++ b/BinaryObjectScanner.Protection/XCP.cs
@@ -4,8 +4,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
-using BinaryObjectScanner.Utilities;
using BinaryObjectScanner.Wrappers;
+using SabreTools.IO;
namespace BinaryObjectScanner.Protection
{
diff --git a/BinaryObjectScanner.Utilities/IniFile.cs b/BinaryObjectScanner.Utilities/IniFile.cs
deleted file mode 100644
index d96f351c..00000000
--- a/BinaryObjectScanner.Utilities/IniFile.cs
+++ /dev/null
@@ -1,299 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace BinaryObjectScanner.Utilities
-{
- ///
- /// Key-value pair INI file
- ///
- public class IniFile : IDictionary
- {
- private Dictionary _keyValuePairs = new Dictionary();
-
- public string this[string key]
- {
- get
- {
- if (_keyValuePairs == null)
- _keyValuePairs = new Dictionary();
-
- key = key.ToLowerInvariant();
- if (_keyValuePairs.ContainsKey(key))
- return _keyValuePairs[key];
-
- return null;
- }
- set
- {
- if (_keyValuePairs == null)
- _keyValuePairs = new Dictionary();
-
- key = key.ToLowerInvariant();
- _keyValuePairs[key] = value;
- }
- }
-
- ///
- /// Create an empty INI file
- ///
- public IniFile()
- {
- }
-
- ///
- /// Populate an INI file from path
- ///
- public IniFile(string path)
- {
- this.Parse(path);
- }
-
- ///
- /// Populate an INI file from stream
- ///
- public IniFile(Stream stream)
- {
- this.Parse(stream);
- }
-
- ///
- /// Add or update a key and value to the INI file
- ///
- public void AddOrUpdate(string key, string value)
- {
- _keyValuePairs[key.ToLowerInvariant()] = value;
- }
-
- ///
- /// Remove a key from the INI file
- ///
- public void Remove(string key)
- {
- _keyValuePairs.Remove(key.ToLowerInvariant());
- }
-
- ///
- /// Read an INI file based on the path
- ///
- public bool Parse(string path)
- {
- // If we don't have a file, we can't read it
- if (!File.Exists(path))
- return false;
-
- using (var fileStream = File.OpenRead(path))
- {
- return Parse(fileStream);
- }
- }
-
- ///
- /// Read an INI file from a stream
- ///
- public bool Parse(Stream stream)
- {
- // If the stream is invalid or unreadable, we can't process it
- if (stream == null || !stream.CanRead || stream.Position >= stream.Length - 1)
- return false;
-
- // Keys are case-insensitive by default
- try
- {
- using (StreamReader sr = new StreamReader(stream))
- {
- string section = string.Empty;
- while (!sr.EndOfStream)
- {
- string line = sr.ReadLine().Trim();
-
- // Comments start with ';'
- if (line.StartsWith(";"))
- {
- // No-op, we don't process comments
- }
-
- // Section titles are surrounded by square brackets
- else if (line.StartsWith("["))
- {
- section = line.TrimStart('[').TrimEnd(']');
- }
-
- // Valid INI lines are in the format key=value
- else if (line.Contains("="))
- {
- // Split the line by '=' for key-value pairs
- string[] data = line.Split('=');
-
- // If the value field contains an '=', we need to put them back in
- string key = data[0].Trim();
- string value = string.Join("=", data.Skip(1)).Trim();
-
- // Section names are prepended to the key with a '.' separating
- if (!string.IsNullOrEmpty(section))
- key = $"{section}.{key}";
-
- // Set or overwrite keys in the returned dictionary
- _keyValuePairs[key.ToLowerInvariant()] = value;
- }
-
- // All other lines are ignored
- }
- }
- }
- catch
- {
- // We don't care what the error was, just catch and return
- return false;
- }
-
- return true;
- }
-
- ///
- /// Write an INI file to a path
- ///
- public bool Write(string path)
- {
- // If we don't have a valid dictionary with values, we can't write out
- if (_keyValuePairs == null || _keyValuePairs.Count == 0)
- return false;
-
- using (var fileStream = File.OpenWrite(path))
- {
- return Write(fileStream);
- }
- }
-
- ///
- /// Write an INI file to a stream
- ///
- public bool Write(Stream stream)
- {
- // If we don't have a valid dictionary with values, we can't write out
- if (_keyValuePairs == null || _keyValuePairs.Count == 0)
- return false;
-
- // If the stream is invalid or unwritable, we can't output to it
- if (stream == null || !stream.CanWrite || stream.Position >= stream.Length - 1)
- return false;
-
- try
- {
- using (StreamWriter sw = new StreamWriter(stream))
- {
- // Order the dictionary by keys to link sections together
- var orderedKeyValuePairs = _keyValuePairs.OrderBy(kvp => kvp.Key);
-
- string section = string.Empty;
- foreach (var keyValuePair in orderedKeyValuePairs)
- {
- // Extract the key and value
- string key = keyValuePair.Key;
- string value = keyValuePair.Value;
-
- // We assume '.' is a section name separator
- if (key.Contains('.'))
- {
- // Split the key by '.'
- string[] data = keyValuePair.Key.Split('.');
-
- // If the key contains an '.', we need to put them back in
- string newSection = data[0].Trim();
- key = string.Join(".", data.Skip(1)).Trim();
-
- // If we have a new section, write it out
- if (!string.Equals(newSection, section, StringComparison.OrdinalIgnoreCase))
- {
- sw.WriteLine($"[{newSection}]");
- section = newSection;
- }
- }
-
- // Now write out the key and value in a standardized way
- sw.WriteLine($"{key}={value}");
- }
- }
- }
- catch
- {
- // We don't care what the error was, just catch and return
- return false;
- }
-
- return true;
- }
-
- #region IDictionary Impelementations
-
- public ICollection Keys => ((IDictionary)_keyValuePairs).Keys;
-
- public ICollection Values => ((IDictionary)_keyValuePairs).Values;
-
- public int Count => ((ICollection>)_keyValuePairs).Count;
-
- public bool IsReadOnly => ((ICollection>)_keyValuePairs).IsReadOnly;
-
- public void Add(string key, string value)
- {
- ((IDictionary)_keyValuePairs).Add(key.ToLowerInvariant(), value);
- }
-
- bool IDictionary.Remove(string key)
- {
- return ((IDictionary)_keyValuePairs).Remove(key.ToLowerInvariant());
- }
-
- public bool TryGetValue(string key, out string value)
- {
- return ((IDictionary)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out value);
- }
-
- public void Add(KeyValuePair item)
- {
- var newItem = new KeyValuePair(item.Key.ToLowerInvariant(), item.Value);
- ((ICollection>)_keyValuePairs).Add(newItem);
- }
-
- public void Clear()
- {
- ((ICollection>)_keyValuePairs).Clear();
- }
-
- public bool Contains(KeyValuePair item)
- {
- var newItem = new KeyValuePair(item.Key.ToLowerInvariant(), item.Value);
- return ((ICollection>)_keyValuePairs).Contains(newItem);
- }
-
- public bool ContainsKey(string key)
- {
- return _keyValuePairs.ContainsKey(key.ToLowerInvariant());
- }
-
- public void CopyTo(KeyValuePair[] array, int arrayIndex)
- {
- ((ICollection>)_keyValuePairs).CopyTo(array, arrayIndex);
- }
-
- public bool Remove(KeyValuePair item)
- {
- var newItem = new KeyValuePair(item.Key.ToLowerInvariant(), item.Value);
- return ((ICollection>)_keyValuePairs).Remove(newItem);
- }
-
- public IEnumerator> GetEnumerator()
- {
- return ((IEnumerable>)_keyValuePairs).GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return ((IEnumerable)_keyValuePairs).GetEnumerator();
- }
-
- #endregion
- }
-}