mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Extract out IO namespace, Part 3
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Help;
|
||||
using SabreTools.Library.DatFiles;
|
||||
using SabreTools.Library.DatItems;
|
||||
|
||||
@@ -3,13 +3,14 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Help;
|
||||
using SabreTools.Logging;
|
||||
using SabreTools.Library.DatFiles;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.FileTypes;
|
||||
using SabreTools.Library.Tools;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
@@ -479,7 +480,7 @@ CREATE TABLE IF NOT EXISTS dat (
|
||||
if (lowerCaseDats.Contains(input.ToLowerInvariant()))
|
||||
{
|
||||
string fullpath = Path.GetFullPath(datRootDats[lowerCaseDats.IndexOf(input.ToLowerInvariant())]);
|
||||
string sha1 = Utilities.ByteArrayToString(FileExtensions.GetInfo(fullpath, hashes: Hash.SHA1).SHA1);
|
||||
string sha1 = Utilities.ByteArrayToString(BaseFile.GetInfo(fullpath, hashes: Hash.SHA1).SHA1);
|
||||
foundDats.Add(sha1, fullpath);
|
||||
}
|
||||
else
|
||||
@@ -510,7 +511,15 @@ CREATE TABLE IF NOT EXISTS dat (
|
||||
Dictionary<string, Tuple<long, bool>> depots = new Dictionary<string, Tuple<long, bool>>();
|
||||
|
||||
// Get the XML text reader for the configuration file, if possible
|
||||
XmlReader xtr = _config.GetXmlTextReader();
|
||||
XmlReader xtr = XmlReader.Create(_config, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
// Now parse the XML file for settings
|
||||
if (xtr != null)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Help;
|
||||
using SabreTools.Library.IO;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
namespace RombaSharp.Features
|
||||
@@ -29,7 +28,7 @@ namespace RombaSharp.Features
|
||||
|
||||
SqliteConnection dbc = new SqliteConnection(_connectionString);
|
||||
dbc.Open();
|
||||
StreamWriter sw = new StreamWriter(FileExtensions.TryCreate("export.csv"));
|
||||
StreamWriter sw = new StreamWriter(File.Create("export.csv"));
|
||||
|
||||
// First take care of all file hashes
|
||||
sw.WriteLine("CRC,MD5,SHA-1"); // ,Depot
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Linq;
|
||||
|
||||
using SabreTools.Help;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.IO;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
namespace RombaSharp.Features
|
||||
@@ -38,7 +37,7 @@ namespace RombaSharp.Features
|
||||
// Now, for each of these files, attempt to add the data found inside
|
||||
foreach (string input in Inputs)
|
||||
{
|
||||
StreamReader sr = new StreamReader(FileExtensions.TryOpenRead(input));
|
||||
StreamReader sr = new StreamReader(File.OpenRead(input));
|
||||
|
||||
// The first line should be the hash header
|
||||
string line = sr.ReadLine();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Help;
|
||||
using SabreTools.Library.DatFiles;
|
||||
using SabreTools.Library.DatItems;
|
||||
|
||||
@@ -2,6 +2,166 @@
|
||||
|
||||
namespace SabreTools.Data
|
||||
{
|
||||
#region DatFile
|
||||
|
||||
/// <summary>
|
||||
/// DAT output formats
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum DatFormat
|
||||
{
|
||||
#region XML Formats
|
||||
|
||||
/// <summary>
|
||||
/// Logiqx XML (using machine)
|
||||
/// </summary>
|
||||
Logiqx = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Logiqx XML (using game)
|
||||
/// </summary>
|
||||
LogiqxDeprecated = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// MAME Softare List XML
|
||||
/// </summary>
|
||||
SoftwareList = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// MAME Listxml output
|
||||
/// </summary>
|
||||
Listxml = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// OfflineList XML
|
||||
/// </summary>
|
||||
OfflineList = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// SabreDAT XML
|
||||
/// </summary>
|
||||
SabreXML = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// openMSX Software List XML
|
||||
/// </summary>
|
||||
OpenMSX = 1 << 6,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Propietary Formats
|
||||
|
||||
/// <summary>
|
||||
/// ClrMamePro custom
|
||||
/// </summary>
|
||||
ClrMamePro = 1 << 7,
|
||||
|
||||
/// <summary>
|
||||
/// RomCenter INI-based
|
||||
/// </summary>
|
||||
RomCenter = 1 << 8,
|
||||
|
||||
/// <summary>
|
||||
/// DOSCenter custom
|
||||
/// </summary>
|
||||
DOSCenter = 1 << 9,
|
||||
|
||||
/// <summary>
|
||||
/// AttractMode custom
|
||||
/// </summary>
|
||||
AttractMode = 1 << 10,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Standardized Text Formats
|
||||
|
||||
/// <summary>
|
||||
/// ClrMamePro missfile
|
||||
/// </summary>
|
||||
MissFile = 1 << 11,
|
||||
|
||||
/// <summary>
|
||||
/// Comma-Separated Values (standardized)
|
||||
/// </summary>
|
||||
CSV = 1 << 12,
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon-Separated Values (standardized)
|
||||
/// </summary>
|
||||
SSV = 1 << 13,
|
||||
|
||||
/// <summary>
|
||||
/// Tab-Separated Values (standardized)
|
||||
/// </summary>
|
||||
TSV = 1 << 14,
|
||||
|
||||
/// <summary>
|
||||
/// MAME Listrom output
|
||||
/// </summary>
|
||||
Listrom = 1 << 15,
|
||||
|
||||
/// <summary>
|
||||
/// Everdrive Packs SMDB
|
||||
/// </summary>
|
||||
EverdriveSMDB = 1 << 16,
|
||||
|
||||
/// <summary>
|
||||
/// SabreJSON
|
||||
/// </summary>
|
||||
SabreJSON = 1 << 17,
|
||||
|
||||
#endregion
|
||||
|
||||
#region SFV-similar Formats
|
||||
|
||||
/// <summary>
|
||||
/// CRC32 hash list
|
||||
/// </summary>
|
||||
RedumpSFV = 1 << 18,
|
||||
|
||||
/// <summary>
|
||||
/// MD5 hash list
|
||||
/// </summary>
|
||||
RedumpMD5 = 1 << 19,
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
/// <summary>
|
||||
/// RIPEMD160 hash list
|
||||
/// </summary>
|
||||
RedumpRIPEMD160 = 1 << 20,
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// SHA-1 hash list
|
||||
/// </summary>
|
||||
RedumpSHA1 = 1 << 21,
|
||||
|
||||
/// <summary>
|
||||
/// SHA-256 hash list
|
||||
/// </summary>
|
||||
RedumpSHA256 = 1 << 22,
|
||||
|
||||
/// <summary>
|
||||
/// SHA-384 hash list
|
||||
/// </summary>
|
||||
RedumpSHA384 = 1 << 23,
|
||||
|
||||
/// <summary>
|
||||
/// SHA-512 hash list
|
||||
/// </summary>
|
||||
RedumpSHA512 = 1 << 24,
|
||||
|
||||
/// <summary>
|
||||
/// SpamSum hash list
|
||||
/// </summary>
|
||||
RedumpSpamSum = 1 << 25,
|
||||
|
||||
#endregion
|
||||
|
||||
// Specialty combinations
|
||||
ALL = Int32.MaxValue,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Available hashing types
|
||||
/// </summary>
|
||||
@@ -29,4 +189,49 @@ namespace SabreTools.Data
|
||||
SecureHashes = MD5 | SHA1 | SHA256 | SHA384 | SHA512 | SpamSum,
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines what sort of files get externally hashed
|
||||
/// </summary>
|
||||
/// TODO: Can FileType be used instead?
|
||||
[Flags]
|
||||
public enum TreatAsFile
|
||||
{
|
||||
CHD = 1 << 0,
|
||||
Archive = 1 << 1,
|
||||
AaruFormat = 1 << 2,
|
||||
|
||||
NonArchive = CHD | AaruFormat,
|
||||
All = CHD | Archive | AaruFormat,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FileTypes
|
||||
|
||||
/// <summary>
|
||||
/// Type of file that is being looked at
|
||||
/// </summary>
|
||||
public enum FileType
|
||||
{
|
||||
// Singleton
|
||||
None = 0,
|
||||
AaruFormat,
|
||||
CHD,
|
||||
|
||||
// Can contain children
|
||||
Folder,
|
||||
SevenZipArchive,
|
||||
GZipArchive,
|
||||
LRZipArchive,
|
||||
LZ4Archive,
|
||||
RarArchive,
|
||||
TapeArchive,
|
||||
XZArchive,
|
||||
ZipArchive,
|
||||
ZPAQArchive,
|
||||
ZstdArchive,
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Logging;
|
||||
|
||||
// TODO: Figure out a reasonable way of adding logging back to this
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
@@ -20,12 +19,22 @@ namespace SabreTools.IO
|
||||
{
|
||||
foreach (string file in Directory.EnumerateFiles(dir, "*", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
FileTryDelete(file);
|
||||
try
|
||||
{
|
||||
if (File.Exists(file))
|
||||
File.Delete(file);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
foreach (string subdir in Directory.EnumerateDirectories(dir, "*", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
TryDelete(subdir);
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(subdir))
|
||||
Directory.Delete(subdir);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +99,7 @@ namespace SabreTools.IO
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerImpl.Error(ex, $"An exception occurred getting the full path for '{input}'");
|
||||
//LoggerImpl.Error(ex, $"An exception occurred getting the full path for '{input}'");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -105,11 +114,11 @@ namespace SabreTools.IO
|
||||
}
|
||||
catch (PathTooLongException ex)
|
||||
{
|
||||
LoggerImpl.Warning(ex, $"The path for '{dir}' was too long");
|
||||
//LoggerImpl.Warning(ex, $"The path for '{dir}' was too long");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerImpl.Error(ex, $"An exception occurred processing '{dir}'");
|
||||
//LoggerImpl.Error(ex, $"An exception occurred processing '{dir}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +195,7 @@ namespace SabreTools.IO
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerImpl.Error(ex, $"An exception occurred getting the full path for '{input}'");
|
||||
//LoggerImpl.Error(ex, $"An exception occurred getting the full path for '{input}'");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -201,11 +210,11 @@ namespace SabreTools.IO
|
||||
}
|
||||
catch (PathTooLongException ex)
|
||||
{
|
||||
LoggerImpl.Warning(ex, $"The path for '{file}' was too long");
|
||||
//LoggerImpl.Warning(ex, $"The path for '{file}' was too long");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerImpl.Error(ex, $"An exception occurred processing '{file}'");
|
||||
//LoggerImpl.Error(ex, $"An exception occurred processing '{file}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,11 +226,11 @@ namespace SabreTools.IO
|
||||
}
|
||||
catch (PathTooLongException ex)
|
||||
{
|
||||
LoggerImpl.Warning(ex, $"The path for '{input}' was too long");
|
||||
//LoggerImpl.Warning(ex, $"The path for '{input}' was too long");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerImpl.Error(ex, $"An exception occurred processing '{input}'");
|
||||
//LoggerImpl.Error(ex, $"An exception occurred processing '{input}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,86 +296,9 @@ namespace SabreTools.IO
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to safely delete a directory, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the directory to delete</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>True if the file didn't exist or could be deleted, false otherwise</returns>
|
||||
public static bool TryCreateDirectory(string file, bool throwOnError = false)
|
||||
{
|
||||
// Now wrap creating the directory
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(file);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to safely delete a directory, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the directory to delete</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>True if the file didn't exist or could be deleted, false otherwise</returns>
|
||||
public static bool TryDelete(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the directory exists first
|
||||
if (!Directory.Exists(file))
|
||||
return true;
|
||||
|
||||
// Now wrap deleting the directory
|
||||
try
|
||||
{
|
||||
Directory.Delete(file, true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this entire section once External and the rest of IO is in its own library (or pulled in otherwise)
|
||||
#region TEMPORARY - REMOVEME
|
||||
|
||||
/// <summary>
|
||||
/// Try to safely delete a file, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to delete</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>True if the file didn't exist or could be deleted, false otherwise</returns>
|
||||
private static bool FileTryDelete(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the file exists first
|
||||
if (!File.Exists(file))
|
||||
return true;
|
||||
|
||||
// Now wrap deleting the file
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class NaturalComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private Dictionary<string, string[]> table;
|
||||
|
||||
77
SabreTools.IO/FileExtensions.cs
Normal file
77
SabreTools.IO/FileExtensions.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions to File functionality
|
||||
/// </summary>
|
||||
public static class FileExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines a text file's encoding by analyzing its byte order mark (BOM).
|
||||
/// Defaults to ASCII when detection of the text file's endianness fails.
|
||||
/// </summary>
|
||||
/// <param name="filename">The text file to analyze.</param>
|
||||
/// <returns>The detected encoding.</returns>
|
||||
/// <link>http://stackoverflow.com/questions/3825390/effective-way-to-find-any-files-encoding</link>
|
||||
public static Encoding GetEncoding(string filename)
|
||||
{
|
||||
if (!File.Exists(filename))
|
||||
return Encoding.Default;
|
||||
|
||||
// Try to open the file
|
||||
try
|
||||
{
|
||||
FileStream file = File.OpenRead(filename);
|
||||
if (file == null)
|
||||
return Encoding.Default;
|
||||
|
||||
// Read the BOM
|
||||
var bom = new byte[4];
|
||||
file.Read(bom, 0, 4);
|
||||
file.Dispose();
|
||||
|
||||
// Analyze the BOM
|
||||
if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7;
|
||||
if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8;
|
||||
if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE
|
||||
if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE
|
||||
if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32;
|
||||
return Encoding.Default;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Encoding.Default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the first byte array starts with the second array
|
||||
/// </summary>
|
||||
/// <param name="arr1">First byte array to compare</param>
|
||||
/// <param name="arr2">Second byte array to compare</param>
|
||||
/// <param name="exact">True if the input arrays should match exactly, false otherwise (default)</param>
|
||||
/// <returns>True if the first byte array starts with the second, false otherwise</returns>
|
||||
public static bool StartsWith(this byte[] arr1, byte[] arr2, bool exact = false)
|
||||
{
|
||||
// If we have any invalid inputs, we return false
|
||||
if (arr1 == null || arr2 == null
|
||||
|| arr1.Length == 0 || arr2.Length == 0
|
||||
|| arr2.Length > arr1.Length
|
||||
|| (exact && arr1.Length != arr2.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, loop through and see
|
||||
for (int i = 0; i < arr2.Length; i++)
|
||||
{
|
||||
if (arr1[i] != arr2[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
using SabreTools.Data;
|
||||
|
||||
namespace SabreTools.Library.IO
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions to Path functionality
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.Data\SabreTools.Data.csproj" />
|
||||
<ProjectReference Include="..\SabreTools.Logging\SabreTools.Logging.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Logging;
|
||||
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
@@ -11,27 +8,6 @@ namespace SabreTools.IO
|
||||
/// </summary>
|
||||
public static class StreamExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Add an aribtrary number of bytes to the inputted stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to be appended to</param>
|
||||
/// <param name="output">Outputted stream</param>
|
||||
/// <param name="bytesToAddToHead">Bytes to be added to head of stream</param>
|
||||
/// <param name="bytesToAddToTail">Bytes to be added to tail of stream</param>
|
||||
public static void AppendBytes(Stream input, Stream output, byte[] bytesToAddToHead, byte[] bytesToAddToTail)
|
||||
{
|
||||
// Write out prepended bytes
|
||||
if (bytesToAddToHead != null && bytesToAddToHead.Count() > 0)
|
||||
output.Write(bytesToAddToHead, 0, bytesToAddToHead.Length);
|
||||
|
||||
// Now copy the existing file over
|
||||
input.CopyTo(output);
|
||||
|
||||
// Write out appended bytes
|
||||
if (bytesToAddToTail != null && bytesToAddToTail.Count() > 0)
|
||||
output.Write(bytesToAddToTail, 0, bytesToAddToTail.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seek to a specific point in the stream, if possible
|
||||
/// </summary>
|
||||
@@ -51,16 +27,10 @@ namespace SabreTools.IO
|
||||
|
||||
return input.Position;
|
||||
}
|
||||
catch (NotSupportedException ex)
|
||||
catch
|
||||
{
|
||||
LoggerImpl.Verbose(ex, "Stream does not support seeking to starting offset. Stream position not changed");
|
||||
return -1;
|
||||
}
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
LoggerImpl.Warning(ex, "Stream does not support seeking to starting offset. Stream position not changed");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
// Open a file reader
|
||||
Encoding enc = FileExtensions.GetEncoding(filename);
|
||||
SeparatedValueReader svr = new SeparatedValueReader(FileExtensions.TryOpenRead(filename), enc)
|
||||
SeparatedValueReader svr = new SeparatedValueReader(File.OpenRead(filename), enc)
|
||||
{
|
||||
Header = true,
|
||||
Quotes = false,
|
||||
@@ -134,7 +134,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
// Open a file reader
|
||||
Encoding enc = FileExtensions.GetEncoding(filename);
|
||||
ClrMameProReader cmpr = new ClrMameProReader(FileExtensions.TryOpenRead(filename), enc)
|
||||
ClrMameProReader cmpr = new ClrMameProReader(File.OpenRead(filename), enc)
|
||||
{
|
||||
DosCenter = false,
|
||||
Quotes = Quotes,
|
||||
@@ -459,7 +459,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -17,8 +17,8 @@ using SabreTools.Library.FileTypes;
|
||||
using SabreTools.Library.Filtering;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Reports;
|
||||
using SabreTools.Library.Skippers;
|
||||
using SabreTools.Library.Tools;
|
||||
using SabreTools.Skippers;
|
||||
using NaturalSort;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -1870,13 +1870,14 @@ namespace SabreTools.Library.DatFiles
|
||||
Header.FileName = (string.IsNullOrWhiteSpace(Header.FileName) ? (keepext ? Path.GetFileName(currentPath) : Path.GetFileNameWithoutExtension(currentPath)) : Header.FileName);
|
||||
|
||||
// If the output type isn't set already, get the internal output type
|
||||
Header.DatFormat = (Header.DatFormat == 0 ? currentPath.GetDatFormat() : Header.DatFormat);
|
||||
DatFormat currentPathFormat = GetDatFormat(currentPath);
|
||||
Header.DatFormat = (Header.DatFormat == 0 ? currentPathFormat : Header.DatFormat);
|
||||
Items.SetBucketedBy(Field.DatItem_CRC); // Setting this because it can reduce issues later
|
||||
|
||||
// Now parse the correct type of DAT
|
||||
try
|
||||
{
|
||||
Create(currentPath.GetDatFormat(), this, quotes)?.ParseFile(currentPath, indexId, keep, throwOnError);
|
||||
Create(currentPathFormat, this, quotes)?.ParseFile(currentPath, indexId, keep, throwOnError);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1885,6 +1886,142 @@ namespace SabreTools.Library.DatFiles
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get what type of DAT the input file is
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the file to be parsed</param>
|
||||
/// <returns>The DatFormat corresponding to the DAT</returns>
|
||||
protected DatFormat GetDatFormat(string filename)
|
||||
{
|
||||
// Limit the output formats based on extension
|
||||
if (!PathExtensions.HasValidDatExtension(filename))
|
||||
return 0;
|
||||
|
||||
// Get the extension from the filename
|
||||
string ext = PathExtensions.GetNormalizedExtension(filename);
|
||||
|
||||
// Check if file exists
|
||||
if (!File.Exists(filename))
|
||||
return 0;
|
||||
|
||||
// Some formats should only require the extension to know
|
||||
switch (ext)
|
||||
{
|
||||
case "csv":
|
||||
return DatFormat.CSV;
|
||||
case "json":
|
||||
return DatFormat.SabreJSON;
|
||||
case "md5":
|
||||
return DatFormat.RedumpMD5;
|
||||
#if NET_FRAMEWORK
|
||||
case "ripemd160":
|
||||
return DatFormat.RedumpRIPEMD160;
|
||||
#endif
|
||||
case "sfv":
|
||||
return DatFormat.RedumpSFV;
|
||||
case "sha1":
|
||||
return DatFormat.RedumpSHA1;
|
||||
case "sha256":
|
||||
return DatFormat.RedumpSHA256;
|
||||
case "sha384":
|
||||
return DatFormat.RedumpSHA384;
|
||||
case "sha512":
|
||||
return DatFormat.RedumpSHA512;
|
||||
case "spamsum":
|
||||
return DatFormat.RedumpSpamSum;
|
||||
case "ssv":
|
||||
return DatFormat.SSV;
|
||||
case "tsv":
|
||||
return DatFormat.TSV;
|
||||
}
|
||||
|
||||
// For everything else, we need to read it
|
||||
// Get the first two non-whitespace, non-comment lines to check, if possible
|
||||
string first = string.Empty, second = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamReader sr = File.OpenText(filename))
|
||||
{
|
||||
first = sr.ReadLine().ToLowerInvariant();
|
||||
while ((string.IsNullOrWhiteSpace(first) || first.StartsWith("<!--"))
|
||||
&& !sr.EndOfStream)
|
||||
{
|
||||
first = sr.ReadLine().ToLowerInvariant();
|
||||
}
|
||||
|
||||
if (!sr.EndOfStream)
|
||||
{
|
||||
second = sr.ReadLine().ToLowerInvariant();
|
||||
while (string.IsNullOrWhiteSpace(second) || second.StartsWith("<!--")
|
||||
&& !sr.EndOfStream)
|
||||
{
|
||||
second = sr.ReadLine().ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// If we have an XML-based DAT
|
||||
if (first.Contains("<?xml") && first.Contains("?>"))
|
||||
{
|
||||
if (second.StartsWith("<!doctype datafile"))
|
||||
return DatFormat.Logiqx;
|
||||
|
||||
else if (second.StartsWith("<!doctype mame")
|
||||
|| second.StartsWith("<!doctype m1")
|
||||
|| second.StartsWith("<mame")
|
||||
|| second.StartsWith("<m1"))
|
||||
return DatFormat.Listxml;
|
||||
|
||||
else if (second.StartsWith("<!doctype softwaredb"))
|
||||
return DatFormat.OpenMSX;
|
||||
|
||||
else if (second.StartsWith("<!doctype softwarelist"))
|
||||
return DatFormat.SoftwareList;
|
||||
|
||||
else if (second.StartsWith("<!doctype sabredat"))
|
||||
return DatFormat.SabreXML;
|
||||
|
||||
else if ((second.StartsWith("<dat") && !second.StartsWith("<datafile"))
|
||||
|| second.StartsWith("<?xml-stylesheet"))
|
||||
return DatFormat.OfflineList;
|
||||
|
||||
// Older and non-compliant DATs
|
||||
else
|
||||
return DatFormat.Logiqx;
|
||||
}
|
||||
|
||||
// If we have an SMDB (SHA-256, Filename, SHA-1, MD5, CRC32)
|
||||
else if (Regex.IsMatch(first, @"[0-9a-f]{64}\t.*?\t[0-9a-f]{40}\t[0-9a-f]{32}\t[0-9a-f]{8}"))
|
||||
return DatFormat.EverdriveSMDB;
|
||||
|
||||
// If we have an INI-based DAT
|
||||
else if (first.Contains("[") && first.Contains("]"))
|
||||
return DatFormat.RomCenter;
|
||||
|
||||
// If we have a listroms DAT
|
||||
else if (first.StartsWith("roms required for driver"))
|
||||
return DatFormat.Listrom;
|
||||
|
||||
// If we have a CMP-based DAT
|
||||
else if (first.Contains("clrmamepro"))
|
||||
return DatFormat.ClrMamePro;
|
||||
|
||||
else if (first.Contains("romvault"))
|
||||
return DatFormat.ClrMamePro;
|
||||
|
||||
else if (first.Contains("doscenter"))
|
||||
return DatFormat.DOSCenter;
|
||||
|
||||
else if (first.Contains("#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra"))
|
||||
return DatFormat.AttractMode;
|
||||
|
||||
else
|
||||
return DatFormat.ClrMamePro;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a rom to the Dat after checking
|
||||
/// </summary>
|
||||
@@ -2043,7 +2180,10 @@ namespace SabreTools.Library.DatFiles
|
||||
// Now that we're done, delete the temp folder (if it's not the default)
|
||||
logger.User("Cleaning temp folder");
|
||||
if (Globals.TempDir != Path.GetTempPath())
|
||||
DirectoryExtensions.TryDelete(Globals.TempDir);
|
||||
{
|
||||
if (Directory.Exists(Globals.TempDir))
|
||||
Directory.Delete(Globals.TempDir, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2247,7 +2387,7 @@ namespace SabreTools.Library.DatFiles
|
||||
private void ProcessFile(string item, string basePath, Hash hashes, TreatAsFile asFiles)
|
||||
{
|
||||
logger.Verbose($"'{Path.GetFileName(item)}' treated like a file");
|
||||
BaseFile baseFile = FileExtensions.GetInfo(item, header: Header.HeaderSkipper, hashes: hashes, asFiles: asFiles);
|
||||
BaseFile baseFile = BaseFile.GetInfo(item, header: Header.HeaderSkipper, hashes: hashes, asFiles: asFiles);
|
||||
DatItem datItem = DatItem.Create(baseFile);
|
||||
ProcessFileHelper(item, datItem, basePath, string.Empty);
|
||||
}
|
||||
@@ -2504,7 +2644,7 @@ namespace SabreTools.Library.DatFiles
|
||||
|
||||
// If we are supposed to delete the depot file, do so
|
||||
if (delete && usedInternally)
|
||||
FileExtensions.TryDelete(foundpath);
|
||||
File.Delete(foundpath);
|
||||
}
|
||||
|
||||
watch.Stop();
|
||||
@@ -2579,7 +2719,7 @@ namespace SabreTools.Library.DatFiles
|
||||
|
||||
// If we are supposed to delete the file, do so
|
||||
if (delete && rebuilt)
|
||||
FileExtensions.TryDelete(input);
|
||||
File.Delete(input);
|
||||
}
|
||||
|
||||
// If the input is a directory
|
||||
@@ -2593,7 +2733,7 @@ namespace SabreTools.Library.DatFiles
|
||||
|
||||
// If we are supposed to delete the file, do so
|
||||
if (delete && rebuilt)
|
||||
FileExtensions.TryDelete(input);
|
||||
File.Delete(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2653,7 +2793,7 @@ namespace SabreTools.Library.DatFiles
|
||||
// If the entries list is null, we encountered an error or have a file and should scan externally
|
||||
if (entries == null && File.Exists(file))
|
||||
{
|
||||
BaseFile internalFileInfo = FileExtensions.GetInfo(file, asFiles: asFiles);
|
||||
BaseFile internalFileInfo = BaseFile.GetInfo(file, asFiles: asFiles);
|
||||
|
||||
// Create the correct DatItem
|
||||
DatItem internalDatItem;
|
||||
@@ -2982,7 +3122,7 @@ namespace SabreTools.Library.DatFiles
|
||||
// Otherwise, just open the filestream
|
||||
else
|
||||
{
|
||||
stream = FileExtensions.TryOpenRead(file);
|
||||
stream = File.OpenRead(file);
|
||||
}
|
||||
|
||||
// If the stream is null, then continue
|
||||
|
||||
@@ -4,8 +4,9 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
// Open a file reader
|
||||
Encoding enc = FileExtensions.GetEncoding(filename);
|
||||
ClrMameProReader cmpr = new ClrMameProReader(FileExtensions.TryOpenRead(filename), enc)
|
||||
ClrMameProReader cmpr = new ClrMameProReader(File.OpenRead(filename), enc)
|
||||
{
|
||||
DosCenter = true
|
||||
};
|
||||
@@ -278,7 +278,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -2,164 +2,6 @@
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
/// <summary>
|
||||
/// DAT output formats
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum DatFormat
|
||||
{
|
||||
#region XML Formats
|
||||
|
||||
/// <summary>
|
||||
/// Logiqx XML (using machine)
|
||||
/// </summary>
|
||||
Logiqx = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Logiqx XML (using game)
|
||||
/// </summary>
|
||||
LogiqxDeprecated = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// MAME Softare List XML
|
||||
/// </summary>
|
||||
SoftwareList = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// MAME Listxml output
|
||||
/// </summary>
|
||||
Listxml = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// OfflineList XML
|
||||
/// </summary>
|
||||
OfflineList = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// SabreDAT XML
|
||||
/// </summary>
|
||||
SabreXML = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// openMSX Software List XML
|
||||
/// </summary>
|
||||
OpenMSX = 1 << 6,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Propietary Formats
|
||||
|
||||
/// <summary>
|
||||
/// ClrMamePro custom
|
||||
/// </summary>
|
||||
ClrMamePro = 1 << 7,
|
||||
|
||||
/// <summary>
|
||||
/// RomCenter INI-based
|
||||
/// </summary>
|
||||
RomCenter = 1 << 8,
|
||||
|
||||
/// <summary>
|
||||
/// DOSCenter custom
|
||||
/// </summary>
|
||||
DOSCenter = 1 << 9,
|
||||
|
||||
/// <summary>
|
||||
/// AttractMode custom
|
||||
/// </summary>
|
||||
AttractMode = 1 << 10,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Standardized Text Formats
|
||||
|
||||
/// <summary>
|
||||
/// ClrMamePro missfile
|
||||
/// </summary>
|
||||
MissFile = 1 << 11,
|
||||
|
||||
/// <summary>
|
||||
/// Comma-Separated Values (standardized)
|
||||
/// </summary>
|
||||
CSV = 1 << 12,
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon-Separated Values (standardized)
|
||||
/// </summary>
|
||||
SSV = 1 << 13,
|
||||
|
||||
/// <summary>
|
||||
/// Tab-Separated Values (standardized)
|
||||
/// </summary>
|
||||
TSV = 1 << 14,
|
||||
|
||||
/// <summary>
|
||||
/// MAME Listrom output
|
||||
/// </summary>
|
||||
Listrom = 1 << 15,
|
||||
|
||||
/// <summary>
|
||||
/// Everdrive Packs SMDB
|
||||
/// </summary>
|
||||
EverdriveSMDB = 1 << 16,
|
||||
|
||||
/// <summary>
|
||||
/// SabreJSON
|
||||
/// </summary>
|
||||
SabreJSON = 1 << 17,
|
||||
|
||||
#endregion
|
||||
|
||||
#region SFV-similar Formats
|
||||
|
||||
/// <summary>
|
||||
/// CRC32 hash list
|
||||
/// </summary>
|
||||
RedumpSFV = 1 << 18,
|
||||
|
||||
/// <summary>
|
||||
/// MD5 hash list
|
||||
/// </summary>
|
||||
RedumpMD5 = 1 << 19,
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
/// <summary>
|
||||
/// RIPEMD160 hash list
|
||||
/// </summary>
|
||||
RedumpRIPEMD160 = 1 << 20,
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// SHA-1 hash list
|
||||
/// </summary>
|
||||
RedumpSHA1 = 1 << 21,
|
||||
|
||||
/// <summary>
|
||||
/// SHA-256 hash list
|
||||
/// </summary>
|
||||
RedumpSHA256 = 1 << 22,
|
||||
|
||||
/// <summary>
|
||||
/// SHA-384 hash list
|
||||
/// </summary>
|
||||
RedumpSHA384 = 1 << 23,
|
||||
|
||||
/// <summary>
|
||||
/// SHA-512 hash list
|
||||
/// </summary>
|
||||
RedumpSHA512 = 1 << 24,
|
||||
|
||||
/// <summary>
|
||||
/// SpamSum hash list
|
||||
/// </summary>
|
||||
RedumpSpamSum = 1 << 25,
|
||||
|
||||
#endregion
|
||||
|
||||
// Specialty combinations
|
||||
ALL = Int32.MaxValue,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the DAT deduplication type
|
||||
/// </summary>
|
||||
@@ -244,19 +86,4 @@ namespace SabreTools.Library.DatFiles
|
||||
Archive,
|
||||
File,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines what sort of files get externally hashed
|
||||
/// </summary>
|
||||
/// TODO: Can FileType be used instead?
|
||||
[Flags]
|
||||
public enum TreatAsFile
|
||||
{
|
||||
CHD = 1 << 0,
|
||||
Archive = 1 << 1,
|
||||
AaruFormat = 1 << 2,
|
||||
|
||||
NonArchive = CHD | AaruFormat,
|
||||
All = CHD | Archive | AaruFormat,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
// Open a file reader
|
||||
Encoding enc = FileExtensions.GetEncoding(filename);
|
||||
SeparatedValueReader svr = new SeparatedValueReader(FileExtensions.TryOpenRead(filename), enc)
|
||||
SeparatedValueReader svr = new SeparatedValueReader(File.OpenRead(filename), enc)
|
||||
{
|
||||
Header = false,
|
||||
Quotes = false,
|
||||
@@ -124,7 +124,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
// Open a file reader
|
||||
Encoding enc = FileExtensions.GetEncoding(filename);
|
||||
StreamReader sr = new StreamReader(FileExtensions.TryOpenRead(filename), enc);
|
||||
StreamReader sr = new StreamReader(File.OpenRead(filename), enc);
|
||||
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
@@ -130,7 +130,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
@@ -44,7 +44,7 @@ namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
// Open a file reader
|
||||
Encoding enc = FileExtensions.GetEncoding(filename);
|
||||
StreamReader sr = new StreamReader(FileExtensions.TryOpenRead(filename), enc);
|
||||
StreamReader sr = new StreamReader(File.OpenRead(filename), enc);
|
||||
|
||||
string gamename = string.Empty;
|
||||
while (!sr.EndOfStream)
|
||||
@@ -280,7 +280,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -4,10 +4,10 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
@@ -36,7 +36,15 @@ namespace SabreTools.Library.DatFiles
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
// Prepare all internal variables
|
||||
XmlReader xtr = filename.GetXmlTextReader();
|
||||
XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
// If we got a null reader, just return
|
||||
if (xtr == null)
|
||||
@@ -1192,7 +1200,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -5,10 +5,10 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
@@ -42,7 +42,16 @@ namespace SabreTools.Library.DatFiles
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
// Prepare all internal variables
|
||||
XmlReader xtr = filename.GetXmlTextReader();
|
||||
XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
List<string> dirs = new List<string>();
|
||||
|
||||
// If we got a null reader, just return
|
||||
@@ -689,7 +698,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
@@ -47,7 +46,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
@@ -34,7 +34,15 @@ namespace SabreTools.Library.DatFiles
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
XmlReader xtr = filename.GetXmlTextReader();
|
||||
XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
// If we got a null reader, just return
|
||||
if (xtr == null)
|
||||
@@ -677,7 +685,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
@@ -35,7 +35,15 @@ namespace SabreTools.Library.DatFiles
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
// Prepare all internal variables
|
||||
XmlReader xtr = filename.GetXmlTextReader();
|
||||
XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
// If we got a null reader, just return
|
||||
if (xtr == null)
|
||||
@@ -531,7 +539,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace SabreTools.Library.DatFiles
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
// Prepare all intenral variables
|
||||
IniReader ir = filename.GetIniReader(false);
|
||||
IniReader ir = new IniReader(filename) { ValidateRows = false };
|
||||
|
||||
// If we got a null reader, just return
|
||||
if (ir == null)
|
||||
@@ -384,7 +384,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -3,8 +3,8 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -35,7 +35,7 @@ namespace SabreTools.Library.DatFiles
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
// Prepare all internal variables
|
||||
StreamReader sr = new StreamReader(FileExtensions.TryOpenRead(filename), new UTF8Encoding(false));
|
||||
StreamReader sr = new StreamReader(File.OpenRead(filename), new UTF8Encoding(false));
|
||||
JsonTextReader jtr = new JsonTextReader(sr);
|
||||
|
||||
// If we got a null reader, just return
|
||||
@@ -342,7 +342,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
|
||||
namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
@@ -34,7 +34,15 @@ namespace SabreTools.Library.DatFiles
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
// Prepare all internal variables
|
||||
XmlReader xtr = filename.GetXmlTextReader();
|
||||
XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
// If we got a null reader, just return
|
||||
if (xtr == null)
|
||||
@@ -190,7 +198,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace SabreTools.Library.DatFiles
|
||||
{
|
||||
// Open a file reader
|
||||
Encoding enc = FileExtensions.GetEncoding(filename);
|
||||
SeparatedValueReader svr = new SeparatedValueReader(FileExtensions.TryOpenRead(filename), enc)
|
||||
SeparatedValueReader svr = new SeparatedValueReader(File.OpenRead(filename), enc)
|
||||
{
|
||||
Header = true,
|
||||
Quotes = true,
|
||||
@@ -121,7 +121,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -4,10 +4,10 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
|
||||
// TODO: Use softwarelist.dtd and *try* to make this write more correctly
|
||||
@@ -37,7 +37,15 @@ namespace SabreTools.Library.DatFiles
|
||||
protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false)
|
||||
{
|
||||
// Prepare all internal variables
|
||||
XmlReader xtr = filename.GetXmlTextReader();
|
||||
XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
// If we got a null reader, just return
|
||||
if (xtr == null)
|
||||
@@ -531,7 +539,7 @@ namespace SabreTools.Library.DatFiles
|
||||
try
|
||||
{
|
||||
logger.User($"Opening file for writing: {outfile}");
|
||||
FileStream fs = FileExtensions.TryCreate(outfile);
|
||||
FileStream fs = File.Create(outfile);
|
||||
|
||||
// If we get back null for some reason, just log and return
|
||||
if (fs == null)
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace SabreTools.Library.FileTypes
|
||||
/// <param name="filename">Filename respresenting the AaruFormat file</param>
|
||||
public static AaruFormat Create(string filename)
|
||||
{
|
||||
using (FileStream fs = FileExtensions.TryOpenRead(filename))
|
||||
using (FileStream fs = File.OpenRead(filename))
|
||||
{
|
||||
return Create(fs);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
{
|
||||
@@ -55,7 +56,7 @@ namespace SabreTools.Library.FileTypes
|
||||
BaseArchive archive = null;
|
||||
|
||||
// First get the archive type
|
||||
FileType? at = input.GetFileType();
|
||||
FileType? at = GetFileType(input);
|
||||
|
||||
// If we got back null, then it's not an archive, so we we return
|
||||
if (at == null)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -110,7 +111,7 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
if (getHashes)
|
||||
{
|
||||
BaseFile temp = FileExtensions.GetInfo(this.Filename, hashes: this.AvailableHashes);
|
||||
BaseFile temp = GetInfo(this.Filename, hashes: this.AvailableHashes);
|
||||
if (temp != null)
|
||||
{
|
||||
this.Parent = temp.Parent;
|
||||
@@ -165,6 +166,141 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
#region Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file type of an input file
|
||||
/// </summary>
|
||||
/// <param name="input">Input file to check</param>
|
||||
/// <returns>FileType of inputted file (null on error)</returns>
|
||||
public static FileType? GetFileType(string input)
|
||||
{
|
||||
FileType? outFileType = null;
|
||||
|
||||
// If the file is null, then we have no archive type
|
||||
if (input == null)
|
||||
return outFileType;
|
||||
|
||||
// First line of defense is going to be the extension, for better or worse
|
||||
if (!PathExtensions.HasValidArchiveExtension(input))
|
||||
return outFileType;
|
||||
|
||||
// Read the first bytes of the file and get the magic number
|
||||
BinaryReader br = new BinaryReader(File.OpenRead(input));
|
||||
byte[] magic = br.ReadBytes(8);
|
||||
br.Dispose();
|
||||
|
||||
// Now try to match it to a known signature
|
||||
if (magic.StartsWith(Constants.SevenZipSignature))
|
||||
{
|
||||
outFileType = FileType.SevenZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.AaruFormatSignature))
|
||||
{
|
||||
outFileType = FileType.AaruFormat;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.CHDSignature))
|
||||
{
|
||||
outFileType = FileType.CHD;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.GzSignature))
|
||||
{
|
||||
outFileType = FileType.GZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.LRZipSignature))
|
||||
{
|
||||
outFileType = FileType.LRZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.LZ4Signature)
|
||||
|| magic.StartsWith(Constants.LZ4SkippableMinSignature)
|
||||
|| magic.StartsWith(Constants.LZ4SkippableMaxSignature))
|
||||
{
|
||||
outFileType = FileType.LZ4Archive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.RarSignature)
|
||||
|| magic.StartsWith(Constants.RarFiveSignature))
|
||||
{
|
||||
outFileType = FileType.RarArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.TarSignature)
|
||||
|| magic.StartsWith(Constants.TarZeroSignature))
|
||||
{
|
||||
outFileType = FileType.TapeArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.XZSignature))
|
||||
{
|
||||
outFileType = FileType.XZArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZipSignature)
|
||||
|| magic.StartsWith(Constants.ZipSignatureEmpty)
|
||||
|| magic.StartsWith(Constants.ZipSignatureSpanned))
|
||||
{
|
||||
outFileType = FileType.ZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZPAQSignature))
|
||||
{
|
||||
outFileType = FileType.ZPAQArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZstdSignature))
|
||||
{
|
||||
outFileType = FileType.ZstdArchive;
|
||||
}
|
||||
|
||||
return outFileType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve file information for a single file
|
||||
/// </summary>
|
||||
/// <param name="input">Filename to get information from</param>
|
||||
/// <param name="header">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
|
||||
/// <param name="hashes">Hashes to include in the information</param>
|
||||
/// <param name="asFiles">TreatAsFiles representing special format scanning</param>
|
||||
/// <returns>Populated BaseFile object if success, empty one on error</returns>
|
||||
public static BaseFile GetInfo(string input, string header = null, Hash hashes = Hash.Standard, TreatAsFile asFiles = 0x00)
|
||||
{
|
||||
// Add safeguard if file doesn't exist
|
||||
if (!File.Exists(input))
|
||||
return null;
|
||||
|
||||
// Get input information
|
||||
var fileType = GetFileType(input);
|
||||
Stream inputStream = File.OpenRead(input);
|
||||
|
||||
// Try to match the supplied header skipper
|
||||
if (header != null)
|
||||
{
|
||||
var rule = Transform.GetMatchingRule(input, Path.GetFileNameWithoutExtension(header));
|
||||
|
||||
// If there's a match, transform the stream before getting info
|
||||
if (rule.Tests != null && rule.Tests.Count != 0)
|
||||
{
|
||||
// Create the output stream
|
||||
MemoryStream outputStream = new MemoryStream();
|
||||
|
||||
// Transform the stream and get the information from it
|
||||
rule.TransformStream(inputStream, outputStream, keepReadOpen: false, keepWriteOpen: true);
|
||||
inputStream = outputStream;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the info in the proper manner
|
||||
BaseFile baseFile;
|
||||
if (fileType == FileType.AaruFormat && !asFiles.HasFlag(TreatAsFile.AaruFormat))
|
||||
baseFile = AaruFormat.Create(inputStream);
|
||||
else if (fileType == FileType.CHD && !asFiles.HasFlag(TreatAsFile.CHD))
|
||||
baseFile = CHDFile.Create(inputStream);
|
||||
else
|
||||
baseFile = GetInfo(inputStream, hashes: hashes, keepReadOpen: false);
|
||||
|
||||
// Dispose of the input stream
|
||||
inputStream?.Dispose();
|
||||
|
||||
// Add unique data from the file
|
||||
baseFile.Filename = Path.GetFileName(input);
|
||||
baseFile.Date = new FileInfo(input).LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss");
|
||||
|
||||
return baseFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve file information for a single file
|
||||
/// </summary>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.FileTypes.CHD;
|
||||
using SabreTools.Library.IO;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace SabreTools.Library.FileTypes
|
||||
/// <param name="filename">Filename respresenting the CHD file</param>
|
||||
public static CHDFile Create(string filename)
|
||||
{
|
||||
using (FileStream fs = FileExtensions.TryOpenRead(filename))
|
||||
using (FileStream fs = File.OpenRead(filename))
|
||||
{
|
||||
return Create(fs);
|
||||
}
|
||||
|
||||
@@ -1252,30 +1252,6 @@ namespace SabreTools.Library.FileTypes
|
||||
PPMdVersionIRev1 = 98,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of file that is being looked at
|
||||
/// </summary>
|
||||
public enum FileType
|
||||
{
|
||||
// Singleton
|
||||
None = 0,
|
||||
AaruFormat,
|
||||
CHD,
|
||||
|
||||
// Can contain children
|
||||
Folder,
|
||||
SevenZipArchive,
|
||||
GZipArchive,
|
||||
LRZipArchive,
|
||||
LZ4Archive,
|
||||
RarArchive,
|
||||
TapeArchive,
|
||||
XZArchive,
|
||||
ZipArchive,
|
||||
ZPAQArchive,
|
||||
ZstdArchive,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output format for rebuilt files
|
||||
/// </summary>
|
||||
|
||||
@@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Logging;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
@@ -249,7 +249,7 @@ namespace SabreTools.Library.FileTypes
|
||||
// If we had a file, copy that over to the new name
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
{
|
||||
FileExtensions.TryOpenRead(match).CopyTo(ms);
|
||||
File.OpenRead(match).CopyTo(ms);
|
||||
realentry = match;
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ namespace SabreTools.Library.FileTypes
|
||||
_children = new List<BaseFile>();
|
||||
foreach (string file in Directory.EnumerateFiles(this.Filename, "*", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
BaseFile nf = FileExtensions.GetInfo(file, hashes: this.AvailableHashes);
|
||||
BaseFile nf = GetInfo(file, hashes: this.AvailableHashes);
|
||||
_children.Add(nf);
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ namespace SabreTools.Library.FileTypes
|
||||
/// <remarks>This works for now, but it can be sped up by using Ionic.Zip or another zlib wrapper that allows for header values built-in. See edc's code.</remarks>
|
||||
public virtual bool Write(string inputFile, string outDir, Rom rom)
|
||||
{
|
||||
FileStream fs = FileExtensions.TryOpenRead(inputFile);
|
||||
FileStream fs = File.OpenRead(inputFile);
|
||||
return Write(fs, outDir, rom);
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
|
||||
|
||||
// Overwrite output files by default
|
||||
outputStream = FileExtensions.TryCreate(fileName);
|
||||
outputStream = File.Create(fileName);
|
||||
|
||||
// If the output stream isn't null
|
||||
if (outputStream != null)
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
// Decompress the _filename stream
|
||||
FileStream outstream = FileExtensions.TryCreate(Path.Combine(outDir, Path.GetFileNameWithoutExtension(this.Filename)));
|
||||
FileStream outstream = File.Create(Path.Combine(outDir, Path.GetFileNameWithoutExtension(this.Filename)));
|
||||
var gz = new gZip();
|
||||
ZipReturn ret = gz.ZipFileOpen(this.Filename);
|
||||
ret = gz.ZipFileOpenReadStream(0, out Stream gzstream, out ulong streamSize);
|
||||
@@ -124,7 +124,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
|
||||
|
||||
// Now open and write the file if possible
|
||||
FileStream fs = FileExtensions.TryCreate(realEntry);
|
||||
FileStream fs = File.Create(realEntry);
|
||||
if (fs != null)
|
||||
{
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
@@ -226,7 +226,7 @@ namespace SabreTools.Library.FileTypes
|
||||
if (this.AvailableHashes == Hash.CRC)
|
||||
{
|
||||
gzipEntryRom.Filename = gamename;
|
||||
using (BinaryReader br = new BinaryReader(FileExtensions.TryOpenRead(this.Filename)))
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(this.Filename)))
|
||||
{
|
||||
br.BaseStream.Seek(-8, SeekOrigin.End);
|
||||
gzipEntryRom.CRC = br.ReadBytesBigEndian(4);
|
||||
@@ -306,7 +306,7 @@ namespace SabreTools.Library.FileTypes
|
||||
}
|
||||
|
||||
// Get the Romba-specific header data
|
||||
BinaryReader br = new BinaryReader(FileExtensions.TryOpenRead(this.Filename));
|
||||
BinaryReader br = new BinaryReader(File.OpenRead(this.Filename));
|
||||
byte[] header = br.ReadBytes(12); // Get preamble header for checking
|
||||
br.ReadBytes(16); // headermd5
|
||||
br.ReadBytes(4); // headercrc
|
||||
@@ -371,7 +371,7 @@ namespace SabreTools.Library.FileTypes
|
||||
byte[] headermd5; // MD5
|
||||
byte[] headercrc; // CRC
|
||||
ulong headersz; // Int64 size
|
||||
BinaryReader br = new BinaryReader(FileExtensions.TryOpenRead(this.Filename));
|
||||
BinaryReader br = new BinaryReader(File.OpenRead(this.Filename));
|
||||
header = br.ReadBytes(12);
|
||||
headermd5 = br.ReadBytes(16);
|
||||
headercrc = br.ReadBytes(4);
|
||||
@@ -435,7 +435,7 @@ namespace SabreTools.Library.FileTypes
|
||||
inputFile = Path.GetFullPath(inputFile);
|
||||
|
||||
// Get the file stream for the file and write out
|
||||
return Write(FileExtensions.TryOpenRead(inputFile), outDir, rom);
|
||||
return Write(File.OpenRead(inputFile), outDir, rom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -474,7 +474,7 @@ namespace SabreTools.Library.FileTypes
|
||||
if (!File.Exists(outfile))
|
||||
{
|
||||
// Compress the input stream
|
||||
FileStream outputStream = FileExtensions.TryCreate(outfile);
|
||||
FileStream outputStream = File.Create(outfile);
|
||||
|
||||
// Open the output file for writing
|
||||
BinaryWriter sw = new BinaryWriter(outputStream);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Library.DatItems;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Library.DatItems;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Rar;
|
||||
using SharpCompress.Readers;
|
||||
@@ -106,7 +106,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
|
||||
|
||||
// Now open and write the file if possible
|
||||
FileStream fs = FileExtensions.TryCreate(realEntry);
|
||||
FileStream fs = File.Create(realEntry);
|
||||
if (fs != null)
|
||||
{
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
@@ -182,7 +182,7 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
try
|
||||
{
|
||||
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(FileExtensions.TryOpenRead(this.Filename));
|
||||
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(File.OpenRead(this.Filename));
|
||||
foreach (RarArchiveEntry entry in ra.Entries.Where(e => e != null && !e.IsDirectory))
|
||||
{
|
||||
// Create a blank item for the entry
|
||||
@@ -284,7 +284,7 @@ namespace SabreTools.Library.FileTypes
|
||||
public override bool Write(string inputFile, string outDir, Rom rom)
|
||||
{
|
||||
// Get the file stream for the file and write out
|
||||
return Write(FileExtensions.TryOpenRead(inputFile), outDir, rom);
|
||||
return Write(File.OpenRead(inputFile), outDir, rom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
using Compress;
|
||||
using Compress.SevenZip;
|
||||
@@ -86,7 +86,7 @@ namespace SabreTools.Library.FileTypes
|
||||
continue;
|
||||
}
|
||||
|
||||
FileStream writeStream = FileExtensions.TryCreate(Path.Combine(outDir, zf.Filename(i)));
|
||||
FileStream writeStream = File.Create(Path.Combine(outDir, zf.Filename(i)));
|
||||
|
||||
// If the stream is smaller than the buffer, just run one loop through to avoid issues
|
||||
if (streamsize < _bufferSize)
|
||||
@@ -155,7 +155,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
|
||||
|
||||
// Now open and write the file if possible
|
||||
FileStream fs = FileExtensions.TryCreate(realEntry);
|
||||
FileStream fs = File.Create(realEntry);
|
||||
if (fs != null)
|
||||
{
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
@@ -410,7 +410,7 @@ namespace SabreTools.Library.FileTypes
|
||||
public override bool Write(string inputFile, string outDir, Rom rom)
|
||||
{
|
||||
// Get the file stream for the file and write out
|
||||
return Write(FileExtensions.TryOpenRead(inputFile), outDir, rom);
|
||||
return Write(File.OpenRead(inputFile), outDir, rom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -597,7 +597,7 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
// If the old file exists, delete it and replace
|
||||
if (File.Exists(archiveFileName))
|
||||
FileExtensions.TryDelete(archiveFileName);
|
||||
File.Delete(archiveFileName);
|
||||
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
@@ -677,7 +677,7 @@ namespace SabreTools.Library.FileTypes
|
||||
int index = inputIndexMap[key];
|
||||
|
||||
// Open the input file for reading
|
||||
Stream freadStream = FileExtensions.TryOpenRead(inputFiles[index]);
|
||||
Stream freadStream = File.OpenRead(inputFiles[index]);
|
||||
ulong istreamSize = (ulong)(new FileInfo(inputFiles[index]).Length);
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
@@ -760,7 +760,7 @@ namespace SabreTools.Library.FileTypes
|
||||
if (index < 0)
|
||||
{
|
||||
// Open the input file for reading
|
||||
Stream freadStream = FileExtensions.TryOpenRead(inputFiles[-index - 1]);
|
||||
Stream freadStream = File.OpenRead(inputFiles[-index - 1]);
|
||||
ulong istreamSize = (ulong)(new FileInfo(inputFiles[-index - 1]).Length);
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
@@ -822,7 +822,7 @@ namespace SabreTools.Library.FileTypes
|
||||
// If the old file exists, delete it and replace
|
||||
if (File.Exists(archiveFileName))
|
||||
{
|
||||
FileExtensions.TryDelete(archiveFileName);
|
||||
File.Delete(archiveFileName);
|
||||
}
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
using Compress.ZipFile;
|
||||
using SharpCompress.Archives;
|
||||
@@ -111,7 +111,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
|
||||
|
||||
// Now open and write the file if possible
|
||||
FileStream fs = FileExtensions.TryCreate(realEntry);
|
||||
FileStream fs = File.Create(realEntry);
|
||||
if (fs != null)
|
||||
{
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
@@ -187,7 +187,7 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
try
|
||||
{
|
||||
TarArchive ta = TarArchive.Open(FileExtensions.TryOpenRead(this.Filename));
|
||||
TarArchive ta = TarArchive.Open(File.OpenRead(this.Filename));
|
||||
foreach (TarArchiveEntry entry in ta.Entries.Where(e => e != null && !e.IsDirectory))
|
||||
{
|
||||
// Create a blank item for the entry
|
||||
@@ -289,7 +289,7 @@ namespace SabreTools.Library.FileTypes
|
||||
public override bool Write(string inputFile, string outDir, Rom rom)
|
||||
{
|
||||
// Get the file stream for the file and write out
|
||||
return Write(FileExtensions.TryOpenRead(inputFile), outDir, rom);
|
||||
return Write(File.OpenRead(inputFile), outDir, rom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -422,7 +422,7 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
// If the old file exists, delete it and replace
|
||||
if (File.Exists(archiveFileName))
|
||||
FileExtensions.TryDelete(archiveFileName);
|
||||
File.Delete(archiveFileName);
|
||||
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
@@ -503,7 +503,7 @@ namespace SabreTools.Library.FileTypes
|
||||
usableDate = dt;
|
||||
|
||||
// Copy the input stream to the output
|
||||
tarFile.AddEntry(roms[index].Name, FileExtensions.TryOpenRead(inputFiles[index]), size: roms[index].Size ?? 0, modified: usableDate);
|
||||
tarFile.AddEntry(roms[index].Name, File.OpenRead(inputFiles[index]), size: roms[index].Size ?? 0, modified: usableDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ namespace SabreTools.Library.FileTypes
|
||||
usableDate = dt;
|
||||
|
||||
// Copy the input file to the output
|
||||
tarFile.AddEntry(roms[-index - 1].Name, FileExtensions.TryOpenRead(inputFiles[-index - 1]), size: roms[-index - 1].Size ?? 0, modified: usableDate);
|
||||
tarFile.AddEntry(roms[-index - 1].Name, File.OpenRead(inputFiles[-index - 1]), size: roms[-index - 1].Size ?? 0, modified: usableDate);
|
||||
}
|
||||
|
||||
// Otherwise, copy the file from the old archive
|
||||
@@ -597,7 +597,7 @@ namespace SabreTools.Library.FileTypes
|
||||
// If the old file exists, delete it and replace
|
||||
if (File.Exists(archiveFileName))
|
||||
{
|
||||
FileExtensions.TryDelete(archiveFileName);
|
||||
File.Delete(archiveFileName);
|
||||
}
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
// Decompress the _filename stream
|
||||
FileStream outstream = FileExtensions.TryCreate(Path.Combine(outDir, Path.GetFileNameWithoutExtension(this.Filename)));
|
||||
FileStream outstream = File.Create(Path.Combine(outDir, Path.GetFileNameWithoutExtension(this.Filename)));
|
||||
var xz = new XZStream(File.OpenRead(this.Filename));
|
||||
xz.CopyTo(outstream);
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
|
||||
|
||||
// Now open and write the file if possible
|
||||
FileStream fs = FileExtensions.TryCreate(realEntry);
|
||||
FileStream fs = File.Create(realEntry);
|
||||
if (fs != null)
|
||||
{
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
@@ -218,7 +218,7 @@ namespace SabreTools.Library.FileTypes
|
||||
if (this.AvailableHashes == Hash.CRC)
|
||||
{
|
||||
xzEntryRom.Filename = gamename;
|
||||
using (BinaryReader br = new BinaryReader(FileExtensions.TryOpenRead(this.Filename)))
|
||||
using (BinaryReader br = new BinaryReader(File.OpenRead(this.Filename)))
|
||||
{
|
||||
br.BaseStream.Seek(-8, SeekOrigin.End);
|
||||
xzEntryRom.CRC = br.ReadBytesBigEndian(4);
|
||||
@@ -335,7 +335,7 @@ namespace SabreTools.Library.FileTypes
|
||||
inputFile = Path.GetFullPath(inputFile);
|
||||
|
||||
// Get the file stream for the file and write out
|
||||
return Write(FileExtensions.TryOpenRead(inputFile), outDir, rom);
|
||||
return Write(File.OpenRead(inputFile), outDir, rom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -374,7 +374,7 @@ namespace SabreTools.Library.FileTypes
|
||||
if (!File.Exists(outfile))
|
||||
{
|
||||
// Compress the input stream
|
||||
XZStream outputStream = new XZStream(FileExtensions.TryCreate(outfile));
|
||||
XZStream outputStream = new XZStream(File.Create(outfile));
|
||||
inputStream.CopyTo(outputStream);
|
||||
|
||||
// Dispose of everything
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Library.DatItems;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Tools;
|
||||
using Compress;
|
||||
using Compress.ZipFile;
|
||||
@@ -87,7 +87,7 @@ namespace SabreTools.Library.FileTypes
|
||||
continue;
|
||||
}
|
||||
|
||||
FileStream writeStream = FileExtensions.TryCreate(Path.Combine(outDir, zf.Filename(i)));
|
||||
FileStream writeStream = File.Create(Path.Combine(outDir, zf.Filename(i)));
|
||||
|
||||
// If the stream is smaller than the buffer, just run one loop through to avoid issues
|
||||
if (streamsize < _bufferSize)
|
||||
@@ -156,7 +156,7 @@ namespace SabreTools.Library.FileTypes
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
|
||||
|
||||
// Now open and write the file if possible
|
||||
FileStream fs = FileExtensions.TryCreate(realEntry);
|
||||
FileStream fs = File.Create(realEntry);
|
||||
if (fs != null)
|
||||
{
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
@@ -412,7 +412,7 @@ namespace SabreTools.Library.FileTypes
|
||||
public override bool Write(string inputFile, string outDir, Rom rom)
|
||||
{
|
||||
// Get the file stream for the file and write out
|
||||
return Write(FileExtensions.TryOpenRead(inputFile), outDir, rom);
|
||||
return Write(File.OpenRead(inputFile), outDir, rom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -598,7 +598,7 @@ namespace SabreTools.Library.FileTypes
|
||||
|
||||
// If the old file exists, delete it and replace
|
||||
if (File.Exists(archiveFileName))
|
||||
FileExtensions.TryDelete(archiveFileName);
|
||||
File.Delete(archiveFileName);
|
||||
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
@@ -678,7 +678,7 @@ namespace SabreTools.Library.FileTypes
|
||||
int index = inputIndexMap[key];
|
||||
|
||||
// Open the input file for reading
|
||||
Stream freadStream = FileExtensions.TryOpenRead(inputFiles[index]);
|
||||
Stream freadStream = File.OpenRead(inputFiles[index]);
|
||||
ulong istreamSize = (ulong)(new FileInfo(inputFiles[index]).Length);
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
@@ -761,7 +761,7 @@ namespace SabreTools.Library.FileTypes
|
||||
if (index < 0)
|
||||
{
|
||||
// Open the input file for reading
|
||||
Stream freadStream = FileExtensions.TryOpenRead(inputFiles[-index - 1]);
|
||||
Stream freadStream = File.OpenRead(inputFiles[-index - 1]);
|
||||
ulong istreamSize = (ulong)(new FileInfo(inputFiles[-index - 1]).Length);
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
@@ -824,7 +824,7 @@ namespace SabreTools.Library.FileTypes
|
||||
// If the old file exists, delete it and replace
|
||||
if (File.Exists(archiveFileName))
|
||||
{
|
||||
FileExtensions.TryDelete(archiveFileName);
|
||||
File.Delete(archiveFileName);
|
||||
}
|
||||
File.Move(tempFile, archiveFileName);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Library.DatItems;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace SabreTools.Library.Filtering
|
||||
public bool PopulateFromFile(string ini)
|
||||
{
|
||||
// Prepare all intenral variables
|
||||
IniReader ir = ini.GetIniReader(false);
|
||||
IniReader ir = new IniReader(ini) { ValidateRows = false };
|
||||
bool foundRootFolder = false;
|
||||
|
||||
// If we got a null reader, just return
|
||||
|
||||
@@ -1,586 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Logging;
|
||||
using SabreTools.Library.DatFiles;
|
||||
using SabreTools.Library.FileTypes;
|
||||
|
||||
namespace SabreTools.Library.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions to File functionality
|
||||
/// </summary>
|
||||
public static class FileExtensions
|
||||
{
|
||||
#region Logging
|
||||
|
||||
/// <summary>
|
||||
/// Logging object
|
||||
/// </summary>
|
||||
private static readonly Logger logger = new Logger();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Add an aribtrary number of bytes to the inputted file
|
||||
/// </summary>
|
||||
/// <param name="input">File to be appended to</param>
|
||||
/// <param name="output">Outputted file</param>
|
||||
/// <param name="bytesToAddToHead">Bytes to be added to head of file</param>
|
||||
/// <param name="bytesToAddToTail">Bytes to be added to tail of file</param>
|
||||
public static void AppendBytes(string input, string output, byte[] bytesToAddToHead, byte[] bytesToAddToTail)
|
||||
{
|
||||
// If any of the inputs are invalid, skip
|
||||
if (!File.Exists(input))
|
||||
return;
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
using (FileStream fsr = TryOpenRead(input))
|
||||
using (FileStream fsw = TryOpenWrite(output))
|
||||
{
|
||||
#else
|
||||
using FileStream fsr = TryOpenRead(input);
|
||||
using FileStream fsw = TryOpenWrite(output);
|
||||
#endif
|
||||
StreamExtensions.AppendBytes(fsr, fsw, bytesToAddToHead, bytesToAddToTail);
|
||||
#if NET_FRAMEWORK
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get what type of DAT the input file is
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the file to be parsed</param>
|
||||
/// <returns>The DatFormat corresponding to the DAT</returns>
|
||||
public static DatFormat GetDatFormat(this string filename)
|
||||
{
|
||||
// Limit the output formats based on extension
|
||||
if (!PathExtensions.HasValidDatExtension(filename))
|
||||
return 0;
|
||||
|
||||
// Get the extension from the filename
|
||||
string ext = PathExtensions.GetNormalizedExtension(filename);
|
||||
|
||||
// Read the input file, if possible
|
||||
logger.Verbose($"Attempting to read file to get format: {filename}");
|
||||
|
||||
// Check if file exists
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
logger.Warning($"File '{filename}' could not read from!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Some formats should only require the extension to know
|
||||
switch (ext)
|
||||
{
|
||||
case "csv":
|
||||
return DatFormat.CSV;
|
||||
case "json":
|
||||
return DatFormat.SabreJSON;
|
||||
case "md5":
|
||||
return DatFormat.RedumpMD5;
|
||||
#if NET_FRAMEWORK
|
||||
case "ripemd160":
|
||||
return DatFormat.RedumpRIPEMD160;
|
||||
#endif
|
||||
case "sfv":
|
||||
return DatFormat.RedumpSFV;
|
||||
case "sha1":
|
||||
return DatFormat.RedumpSHA1;
|
||||
case "sha256":
|
||||
return DatFormat.RedumpSHA256;
|
||||
case "sha384":
|
||||
return DatFormat.RedumpSHA384;
|
||||
case "sha512":
|
||||
return DatFormat.RedumpSHA512;
|
||||
case "spamsum":
|
||||
return DatFormat.RedumpSpamSum;
|
||||
case "ssv":
|
||||
return DatFormat.SSV;
|
||||
case "tsv":
|
||||
return DatFormat.TSV;
|
||||
}
|
||||
|
||||
// For everything else, we need to read it
|
||||
try
|
||||
{
|
||||
// Get the first two non-whitespace, non-comment lines to check, if possible
|
||||
string first = string.Empty, second = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamReader sr = File.OpenText(filename))
|
||||
{
|
||||
first = sr.ReadLine().ToLowerInvariant();
|
||||
while ((string.IsNullOrWhiteSpace(first) || first.StartsWith("<!--"))
|
||||
&& !sr.EndOfStream)
|
||||
{
|
||||
first = sr.ReadLine().ToLowerInvariant();
|
||||
}
|
||||
|
||||
if (!sr.EndOfStream)
|
||||
{
|
||||
second = sr.ReadLine().ToLowerInvariant();
|
||||
while (string.IsNullOrWhiteSpace(second) || second.StartsWith("<!--")
|
||||
&& !sr.EndOfStream)
|
||||
{
|
||||
second = sr.ReadLine().ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// If we have an XML-based DAT
|
||||
if (first.Contains("<?xml") && first.Contains("?>"))
|
||||
{
|
||||
if (second.StartsWith("<!doctype datafile"))
|
||||
return DatFormat.Logiqx;
|
||||
|
||||
else if (second.StartsWith("<!doctype mame")
|
||||
|| second.StartsWith("<!doctype m1")
|
||||
|| second.StartsWith("<mame")
|
||||
|| second.StartsWith("<m1"))
|
||||
return DatFormat.Listxml;
|
||||
|
||||
else if (second.StartsWith("<!doctype softwaredb"))
|
||||
return DatFormat.OpenMSX;
|
||||
|
||||
else if (second.StartsWith("<!doctype softwarelist"))
|
||||
return DatFormat.SoftwareList;
|
||||
|
||||
else if (second.StartsWith("<!doctype sabredat"))
|
||||
return DatFormat.SabreXML;
|
||||
|
||||
else if ((second.StartsWith("<dat") && !second.StartsWith("<datafile"))
|
||||
|| second.StartsWith("<?xml-stylesheet"))
|
||||
return DatFormat.OfflineList;
|
||||
|
||||
// Older and non-compliant DATs
|
||||
else
|
||||
return DatFormat.Logiqx;
|
||||
}
|
||||
|
||||
// If we have an SMDB (SHA-256, Filename, SHA-1, MD5, CRC32)
|
||||
else if (Regex.IsMatch(first, @"[0-9a-f]{64}\t.*?\t[0-9a-f]{40}\t[0-9a-f]{32}\t[0-9a-f]{8}"))
|
||||
return DatFormat.EverdriveSMDB;
|
||||
|
||||
// If we have an INI-based DAT
|
||||
else if (first.Contains("[") && first.Contains("]"))
|
||||
return DatFormat.RomCenter;
|
||||
|
||||
// If we have a listroms DAT
|
||||
else if (first.StartsWith("roms required for driver"))
|
||||
return DatFormat.Listrom;
|
||||
|
||||
// If we have a CMP-based DAT
|
||||
else if (first.Contains("clrmamepro"))
|
||||
return DatFormat.ClrMamePro;
|
||||
|
||||
else if (first.Contains("romvault"))
|
||||
return DatFormat.ClrMamePro;
|
||||
|
||||
else if (first.Contains("doscenter"))
|
||||
return DatFormat.DOSCenter;
|
||||
|
||||
else if (first.Contains("#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra"))
|
||||
return DatFormat.AttractMode;
|
||||
|
||||
else
|
||||
return DatFormat.ClrMamePro;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Warning(ex, $"An exception occurred trying to figure out the format of '{filename}'");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines a text file's encoding by analyzing its byte order mark (BOM).
|
||||
/// Defaults to ASCII when detection of the text file's endianness fails.
|
||||
/// </summary>
|
||||
/// <param name="filename">The text file to analyze.</param>
|
||||
/// <returns>The detected encoding.</returns>
|
||||
/// <link>http://stackoverflow.com/questions/3825390/effective-way-to-find-any-files-encoding</link>
|
||||
public static Encoding GetEncoding(string filename)
|
||||
{
|
||||
// Try to open the file
|
||||
FileStream file = TryOpenRead(filename);
|
||||
if (file == null)
|
||||
return Encoding.Default;
|
||||
|
||||
// Read the BOM
|
||||
var bom = new byte[4];
|
||||
file.Read(bom, 0, 4);
|
||||
file.Dispose();
|
||||
|
||||
// Analyze the BOM
|
||||
if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7;
|
||||
if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8;
|
||||
if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE
|
||||
if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE
|
||||
if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32;
|
||||
return Encoding.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file type of an input file
|
||||
/// </summary>
|
||||
/// <param name="input">Input file to check</param>
|
||||
/// <returns>FileType of inputted file (null on error)</returns>
|
||||
public static FileType? GetFileType(this string input)
|
||||
{
|
||||
FileType? outFileType = null;
|
||||
|
||||
// If the file is null, then we have no archive type
|
||||
if (input == null)
|
||||
return outFileType;
|
||||
|
||||
// First line of defense is going to be the extension, for better or worse
|
||||
if (!PathExtensions.HasValidArchiveExtension(input))
|
||||
return outFileType;
|
||||
|
||||
// Read the first bytes of the file and get the magic number
|
||||
try
|
||||
{
|
||||
byte[] magic = new byte[8];
|
||||
BinaryReader br = new BinaryReader(TryOpenRead(input));
|
||||
magic = br.ReadBytes(8);
|
||||
br.Dispose();
|
||||
|
||||
// Now try to match it to a known signature
|
||||
if (magic.StartsWith(Constants.SevenZipSignature))
|
||||
{
|
||||
outFileType = FileType.SevenZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.AaruFormatSignature))
|
||||
{
|
||||
outFileType = FileType.AaruFormat;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.CHDSignature))
|
||||
{
|
||||
outFileType = FileType.CHD;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.GzSignature))
|
||||
{
|
||||
outFileType = FileType.GZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.LRZipSignature))
|
||||
{
|
||||
outFileType = FileType.LRZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.LZ4Signature)
|
||||
|| magic.StartsWith(Constants.LZ4SkippableMinSignature)
|
||||
|| magic.StartsWith(Constants.LZ4SkippableMaxSignature))
|
||||
{
|
||||
outFileType = FileType.LZ4Archive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.RarSignature)
|
||||
|| magic.StartsWith(Constants.RarFiveSignature))
|
||||
{
|
||||
outFileType = FileType.RarArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.TarSignature)
|
||||
|| magic.StartsWith(Constants.TarZeroSignature))
|
||||
{
|
||||
outFileType = FileType.TapeArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.XZSignature))
|
||||
{
|
||||
outFileType = FileType.XZArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZipSignature)
|
||||
|| magic.StartsWith(Constants.ZipSignatureEmpty)
|
||||
|| magic.StartsWith(Constants.ZipSignatureSpanned))
|
||||
{
|
||||
outFileType = FileType.ZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZPAQSignature))
|
||||
{
|
||||
outFileType = FileType.ZPAQArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZstdSignature))
|
||||
{
|
||||
outFileType = FileType.ZstdArchive;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Warning(ex, $"An exception occurred determining file type of '{input}'");
|
||||
}
|
||||
|
||||
return outFileType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the first byte array starts with the second array
|
||||
/// </summary>
|
||||
/// <param name="arr1">First byte array to compare</param>
|
||||
/// <param name="arr2">Second byte array to compare</param>
|
||||
/// <param name="exact">True if the input arrays should match exactly, false otherwise (default)</param>
|
||||
/// <returns>True if the first byte array starts with the second, false otherwise</returns>
|
||||
public static bool StartsWith(this byte[] arr1, byte[] arr2, bool exact = false)
|
||||
{
|
||||
// If we have any invalid inputs, we return false
|
||||
if (arr1 == null || arr2 == null
|
||||
|| arr1.Length == 0 || arr2.Length == 0
|
||||
|| arr2.Length > arr1.Length
|
||||
|| (exact && arr1.Length != arr2.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, loop through and see
|
||||
for (int i = 0; i < arr2.Length; i++)
|
||||
{
|
||||
if (arr1[i] != arr2[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve file information for a single file
|
||||
/// </summary>
|
||||
/// <param name="input">Filename to get information from</param>
|
||||
/// <param name="header">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
|
||||
/// <param name="hashes">Hashes to include in the information</param>
|
||||
/// <param name="asFiles">TreatAsFiles representing special format scanning</param>
|
||||
/// <returns>Populated BaseFile object if success, empty one on error</returns>
|
||||
public static BaseFile GetInfo(string input, string header = null, Hash hashes = Hash.Standard, TreatAsFile asFiles = 0x00)
|
||||
{
|
||||
// Add safeguard if file doesn't exist
|
||||
if (!File.Exists(input))
|
||||
return null;
|
||||
|
||||
// Get input information
|
||||
var fileType = input.GetFileType();
|
||||
Stream inputStream = TryOpenRead(input);
|
||||
|
||||
// Try to match the supplied header skipper
|
||||
if (header != null)
|
||||
{
|
||||
var rule = Transform.GetMatchingRule(input, Path.GetFileNameWithoutExtension(header));
|
||||
|
||||
// If there's a match, transform the stream before getting info
|
||||
if (rule.Tests != null && rule.Tests.Count != 0)
|
||||
{
|
||||
// Create the output stream
|
||||
MemoryStream outputStream = new MemoryStream();
|
||||
|
||||
// Transform the stream and get the information from it
|
||||
rule.TransformStream(inputStream, outputStream, keepReadOpen: false, keepWriteOpen: true);
|
||||
inputStream = outputStream;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the info in the proper manner
|
||||
BaseFile baseFile;
|
||||
if (fileType == FileType.AaruFormat && !asFiles.HasFlag(TreatAsFile.AaruFormat))
|
||||
baseFile = AaruFormat.Create(inputStream);
|
||||
else if (fileType == FileType.CHD && !asFiles.HasFlag(TreatAsFile.CHD))
|
||||
baseFile = CHDFile.Create(inputStream);
|
||||
else
|
||||
baseFile = BaseFile.GetInfo(inputStream, hashes: hashes, keepReadOpen: false);
|
||||
|
||||
// Dispose of the input stream
|
||||
inputStream?.Dispose();
|
||||
|
||||
// Add unique data from the file
|
||||
baseFile.Filename = Path.GetFileName(input);
|
||||
baseFile.Date = new FileInfo(input).LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss");
|
||||
|
||||
return baseFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the IniReader associated with a file, if possible
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the file to be parsed</param>
|
||||
/// <param name="validateRows">True if rows should be in a proper format, false if invalid is okay</param>
|
||||
/// <returns>The IniReader representing the (possibly converted) file, null otherwise</returns>
|
||||
public static IniReader GetIniReader(this string filename, bool validateRows)
|
||||
{
|
||||
logger.Verbose($"Attempting to read file: {filename}");
|
||||
|
||||
// Check if file exists
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
logger.Warning($"File '{filename}' could not read from!");
|
||||
return null;
|
||||
}
|
||||
|
||||
IniReader ir = new IniReader(filename)
|
||||
{
|
||||
ValidateRows = validateRows
|
||||
};
|
||||
return ir;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the XmlTextReader associated with a file, if possible
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the file to be parsed</param>
|
||||
/// <returns>The XmlTextReader representing the (possibly converted) file, null otherwise</returns>
|
||||
public static XmlReader GetXmlTextReader(this string filename)
|
||||
{
|
||||
logger.Verbose($"Attempting to read file: {filename}");
|
||||
|
||||
// Check if file exists
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
logger.Warning($"File '{filename}' could not read from!");
|
||||
return null;
|
||||
}
|
||||
|
||||
XmlReader xtr = XmlReader.Create(filename, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
DtdProcessing = DtdProcessing.Ignore,
|
||||
IgnoreComments = true,
|
||||
IgnoreWhitespace = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
ValidationType = ValidationType.None,
|
||||
});
|
||||
|
||||
return xtr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to create a file for write, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to create</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>An opened stream representing the file on success, null otherwise</returns>
|
||||
public static FileStream TryCreate(string file, bool throwOnError = false)
|
||||
{
|
||||
// Now wrap opening the file
|
||||
try
|
||||
{
|
||||
return File.Open(file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to safely delete a file, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to delete</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>True if the file didn't exist or could be deleted, false otherwise</returns>
|
||||
public static bool TryDelete(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the file exists first
|
||||
if (!File.Exists(file))
|
||||
return true;
|
||||
|
||||
// Now wrap deleting the file
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to open a file for read, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to open</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>An opened stream representing the file on success, null otherwise</returns>
|
||||
public static FileStream TryOpenRead(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the file exists first
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
// Now wrap opening the file
|
||||
try
|
||||
{
|
||||
return File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to open a file for read/write, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to open</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>An opened stream representing the file on success, null otherwise</returns>
|
||||
public static FileStream TryOpenReadWrite(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the file exists first
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
// Now wrap opening the file
|
||||
try
|
||||
{
|
||||
return File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to open an existing file for write, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to open</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>An opened stream representing the file on success, null otherwise</returns>
|
||||
public static FileStream TryOpenWrite(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the file exists first
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
// Now wrap opening the file
|
||||
try
|
||||
{
|
||||
return File.Open(file, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Logging;
|
||||
using SabreTools.Library.DatFiles;
|
||||
using SabreTools.Library.FileTypes;
|
||||
using SabreTools.Library.Skippers;
|
||||
using SabreTools.Library.Tools;
|
||||
using SabreTools.Skippers;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
namespace SabreTools.Library.IO
|
||||
{
|
||||
@@ -83,7 +83,8 @@ namespace SabreTools.Library.IO
|
||||
public static bool DetectTransformStore(string file, string outDir, bool nostore)
|
||||
{
|
||||
// Create the output directory if it doesn't exist
|
||||
DirectoryExtensions.Ensure(outDir, create: true);
|
||||
if (!Directory.Exists(outDir))
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
logger.User($"\nGetting skipper information for '{file}'");
|
||||
|
||||
@@ -102,10 +103,10 @@ namespace SabreTools.Library.IO
|
||||
{
|
||||
// Extract the header as a string for the database
|
||||
#if NET_FRAMEWORK
|
||||
using (var fs = FileExtensions.TryOpenRead(file))
|
||||
using (var fs = File.OpenRead(file))
|
||||
{
|
||||
#else
|
||||
using var fs = FileExtensions.TryOpenRead(file);
|
||||
using var fs = File.OpenRead(file);
|
||||
#endif
|
||||
byte[] hbin = new byte[(int)rule.StartOffset];
|
||||
fs.Read(hbin, 0, (int)rule.StartOffset);
|
||||
@@ -130,8 +131,8 @@ namespace SabreTools.Library.IO
|
||||
// Now add the information to the database if it's not already there
|
||||
if (!nostore)
|
||||
{
|
||||
BaseFile baseFile = FileExtensions.GetInfo(newfile, hashes: Hash.SHA1, asFiles: TreatAsFile.NonArchive);
|
||||
DatabaseTools.AddHeaderToDatabase(hstr, Utilities.ByteArrayToString(baseFile.SHA1), rule.SourceFile);
|
||||
BaseFile baseFile = BaseFile.GetInfo(newfile, hashes: Hash.SHA1, asFiles: TreatAsFile.NonArchive);
|
||||
AddHeaderToDatabase(hstr, Utilities.ByteArrayToString(baseFile.SHA1), rule.SourceFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -150,10 +151,10 @@ namespace SabreTools.Library.IO
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
// First, get the SHA-1 hash of the file
|
||||
BaseFile baseFile = FileExtensions.GetInfo(file, hashes: Hash.SHA1, asFiles: TreatAsFile.NonArchive);
|
||||
BaseFile baseFile = BaseFile.GetInfo(file, hashes: Hash.SHA1, asFiles: TreatAsFile.NonArchive);
|
||||
|
||||
// Retrieve a list of all related headers from the database
|
||||
List<string> headers = DatabaseTools.RetrieveHeadersFromDatabase(Utilities.ByteArrayToString(baseFile.SHA1));
|
||||
List<string> headers = RetrieveHeadersFromDatabase(Utilities.ByteArrayToString(baseFile.SHA1));
|
||||
|
||||
// If we have nothing retrieved, we return false
|
||||
if (headers.Count == 0)
|
||||
@@ -164,7 +165,7 @@ namespace SabreTools.Library.IO
|
||||
{
|
||||
string outputFile = (string.IsNullOrWhiteSpace(outDir) ? $"{Path.GetFullPath(file)}.new" : Path.Combine(outDir, Path.GetFileName(file))) + i;
|
||||
logger.User($"Creating reheadered file: {outputFile}");
|
||||
FileExtensions.AppendBytes(file, outputFile, Utilities.StringToByteArray(headers[i]), null);
|
||||
AppendBytes(file, outputFile, Utilities.StringToByteArray(headers[i]), null);
|
||||
logger.User("Reheadered file created!");
|
||||
}
|
||||
|
||||
@@ -187,7 +188,7 @@ namespace SabreTools.Library.IO
|
||||
return new SkipperRule();
|
||||
}
|
||||
|
||||
return GetMatchingRule(FileExtensions.TryOpenRead(input), skipperName);
|
||||
return GetMatchingRule(File.OpenRead(input), skipperName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -234,5 +235,171 @@ namespace SabreTools.Library.IO
|
||||
|
||||
return skipperRule;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an aribtrary number of bytes to the inputted file
|
||||
/// </summary>
|
||||
/// <param name="input">File to be appended to</param>
|
||||
/// <param name="output">Outputted file</param>
|
||||
/// <param name="bytesToAddToHead">Bytes to be added to head of file</param>
|
||||
/// <param name="bytesToAddToTail">Bytes to be added to tail of file</param>
|
||||
private static void AppendBytes(string input, string output, byte[] bytesToAddToHead, byte[] bytesToAddToTail)
|
||||
{
|
||||
// If any of the inputs are invalid, skip
|
||||
if (!File.Exists(input))
|
||||
return;
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
using (FileStream fsr = File.OpenRead(input))
|
||||
using (FileStream fsw = File.OpenWrite(output))
|
||||
{
|
||||
#else
|
||||
using FileStream fsr = File.OpenRead(input);
|
||||
using FileStream fsw = File.OpenWrite(output);
|
||||
#endif
|
||||
AppendBytes(fsr, fsw, bytesToAddToHead, bytesToAddToTail);
|
||||
#if NET_FRAMEWORK
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an aribtrary number of bytes to the inputted stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to be appended to</param>
|
||||
/// <param name="output">Outputted stream</param>
|
||||
/// <param name="bytesToAddToHead">Bytes to be added to head of stream</param>
|
||||
/// <param name="bytesToAddToTail">Bytes to be added to tail of stream</param>
|
||||
private static void AppendBytes(Stream input, Stream output, byte[] bytesToAddToHead, byte[] bytesToAddToTail)
|
||||
{
|
||||
// Write out prepended bytes
|
||||
if (bytesToAddToHead != null && bytesToAddToHead.Length > 0)
|
||||
output.Write(bytesToAddToHead, 0, bytesToAddToHead.Length);
|
||||
|
||||
// Now copy the existing file over
|
||||
input.CopyTo(output);
|
||||
|
||||
// Write out appended bytes
|
||||
if (bytesToAddToTail != null && bytesToAddToTail.Length > 0)
|
||||
output.Write(bytesToAddToTail, 0, bytesToAddToTail.Length);
|
||||
}
|
||||
|
||||
#region Database Operations
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that the databse exists and has the proper schema
|
||||
/// </summary>
|
||||
/// <param name="db">Name of the databse</param>
|
||||
/// <param name="connectionString">Connection string for SQLite</param>
|
||||
private static void EnsureDatabase(string db, string connectionString)
|
||||
{
|
||||
// Make sure the file exists
|
||||
if (!File.Exists(db))
|
||||
File.Create(db);
|
||||
|
||||
// Open the database connection
|
||||
SqliteConnection dbc = new SqliteConnection(connectionString);
|
||||
dbc.Open();
|
||||
|
||||
// Make sure the database has the correct schema
|
||||
try
|
||||
{
|
||||
string query = @"
|
||||
CREATE TABLE IF NOT EXISTS data (
|
||||
'sha1' TEXT NOT NULL,
|
||||
'header' TEXT NOT NULL,
|
||||
'type' TEXT NOT NULL,
|
||||
PRIMARY KEY (sha1, header, type)
|
||||
)";
|
||||
SqliteCommand slc = new SqliteCommand(query, dbc);
|
||||
slc.ExecuteNonQuery();
|
||||
slc.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
dbc.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a header to the database
|
||||
/// </summary>
|
||||
/// <param name="header">String representing the header bytes</param>
|
||||
/// <param name="SHA1">SHA-1 of the deheadered file</param>
|
||||
/// <param name="type">Name of the source skipper file</param>
|
||||
private static void AddHeaderToDatabase(string header, string SHA1, string source)
|
||||
{
|
||||
// Ensure the database exists
|
||||
EnsureDatabase(Constants.HeadererFileName, Constants.HeadererConnectionString);
|
||||
|
||||
// Open the database connection
|
||||
SqliteConnection dbc = new SqliteConnection(Constants.HeadererConnectionString);
|
||||
dbc.Open();
|
||||
|
||||
string query = $"SELECT * FROM data WHERE sha1='{SHA1}' AND header='{header}'";
|
||||
SqliteCommand slc = new SqliteCommand(query, dbc);
|
||||
SqliteDataReader sldr = slc.ExecuteReader();
|
||||
bool exists = sldr.HasRows;
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
query = $"INSERT INTO data (sha1, header, type) VALUES ('{SHA1}', '{header}', '{source}')";
|
||||
slc = new SqliteCommand(query, dbc);
|
||||
logger.Verbose($"Result of inserting header: {slc.ExecuteNonQuery()}");
|
||||
}
|
||||
|
||||
// Dispose of database objects
|
||||
slc.Dispose();
|
||||
sldr.Dispose();
|
||||
dbc.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve headers from the database
|
||||
/// </summary>
|
||||
/// <param name="SHA1">SHA-1 of the deheadered file</param>
|
||||
/// <returns>List of strings representing the headers to add</returns>
|
||||
private static List<string> RetrieveHeadersFromDatabase(string SHA1)
|
||||
{
|
||||
// Ensure the database exists
|
||||
EnsureDatabase(Constants.HeadererFileName, Constants.HeadererConnectionString);
|
||||
|
||||
// Open the database connection
|
||||
SqliteConnection dbc = new SqliteConnection(Constants.HeadererConnectionString);
|
||||
dbc.Open();
|
||||
|
||||
// Create the output list of headers
|
||||
List<string> headers = new List<string>();
|
||||
|
||||
string query = $"SELECT header, type FROM data WHERE sha1='{SHA1}'";
|
||||
SqliteCommand slc = new SqliteCommand(query, dbc);
|
||||
SqliteDataReader sldr = slc.ExecuteReader();
|
||||
|
||||
if (sldr.HasRows)
|
||||
{
|
||||
while (sldr.Read())
|
||||
{
|
||||
logger.Verbose($"Found match with rom type '{sldr.GetString(1)}'");
|
||||
headers.Add(sldr.GetString(0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warning("No matching header could be found!");
|
||||
}
|
||||
|
||||
// Dispose of database objects
|
||||
slc.Dispose();
|
||||
sldr.Dispose();
|
||||
dbc.Dispose();
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatFiles;
|
||||
using SabreTools.Library.IO;
|
||||
|
||||
namespace SabreTools.Library.Reports
|
||||
{
|
||||
@@ -28,7 +28,7 @@ namespace SabreTools.Library.Reports
|
||||
/// <param name="nodumpCol">True if nodumps should be included in output, false otherwise</param>
|
||||
public BaseReport(string filename, bool baddumpCol = false, bool nodumpCol = false)
|
||||
{
|
||||
var fs = FileExtensions.TryCreate(filename);
|
||||
var fs = File.Create(filename);
|
||||
if (fs != null)
|
||||
_writer = new StreamWriter(fs);
|
||||
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Logging;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
namespace SabreTools.Library.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// All general database operations
|
||||
/// </summary>
|
||||
public static class DatabaseTools
|
||||
{
|
||||
#region Logging
|
||||
|
||||
/// <summary>
|
||||
/// Logging object
|
||||
/// </summary>
|
||||
private static readonly Logger logger = new Logger();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Add a header to the database
|
||||
/// </summary>
|
||||
/// <param name="header">String representing the header bytes</param>
|
||||
/// <param name="SHA1">SHA-1 of the deheadered file</param>
|
||||
/// <param name="type">Name of the source skipper file</param>
|
||||
public static void AddHeaderToDatabase(string header, string SHA1, string source)
|
||||
{
|
||||
// Ensure the database exists
|
||||
EnsureDatabase(Constants.HeadererFileName, Constants.HeadererConnectionString);
|
||||
|
||||
// Open the database connection
|
||||
SqliteConnection dbc = new SqliteConnection(Constants.HeadererConnectionString);
|
||||
dbc.Open();
|
||||
|
||||
string query = $"SELECT * FROM data WHERE sha1='{SHA1}' AND header='{header}'";
|
||||
SqliteCommand slc = new SqliteCommand(query, dbc);
|
||||
SqliteDataReader sldr = slc.ExecuteReader();
|
||||
bool exists = sldr.HasRows;
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
query = $"INSERT INTO data (sha1, header, type) VALUES ('{SHA1}', '{header}', '{source}')";
|
||||
slc = new SqliteCommand(query, dbc);
|
||||
logger.Verbose($"Result of inserting header: {slc.ExecuteNonQuery()}");
|
||||
}
|
||||
|
||||
// Dispose of database objects
|
||||
slc.Dispose();
|
||||
sldr.Dispose();
|
||||
dbc.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that the databse exists and has the proper schema
|
||||
/// </summary>
|
||||
/// <param name="db">Name of the databse</param>
|
||||
/// <param name="connectionString">Connection string for SQLite</param>
|
||||
public static void EnsureDatabase(string db, string connectionString)
|
||||
{
|
||||
// Make sure the file exists
|
||||
if (!File.Exists(db))
|
||||
File.Create(db);
|
||||
|
||||
// Open the database connection
|
||||
SqliteConnection dbc = new SqliteConnection(connectionString);
|
||||
dbc.Open();
|
||||
|
||||
// Make sure the database has the correct schema
|
||||
try
|
||||
{
|
||||
string query = @"
|
||||
CREATE TABLE IF NOT EXISTS data (
|
||||
'sha1' TEXT NOT NULL,
|
||||
'header' TEXT NOT NULL,
|
||||
'type' TEXT NOT NULL,
|
||||
PRIMARY KEY (sha1, header, type)
|
||||
)";
|
||||
SqliteCommand slc = new SqliteCommand(query, dbc);
|
||||
slc.ExecuteNonQuery();
|
||||
slc.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
dbc.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve headers from the database
|
||||
/// </summary>
|
||||
/// <param name="SHA1">SHA-1 of the deheadered file</param>
|
||||
/// <returns>List of strings representing the headers to add</returns>
|
||||
public static List<string> RetrieveHeadersFromDatabase(string SHA1)
|
||||
{
|
||||
// Ensure the database exists
|
||||
EnsureDatabase(Constants.HeadererFileName, Constants.HeadererConnectionString);
|
||||
|
||||
// Open the database connection
|
||||
SqliteConnection dbc = new SqliteConnection(Constants.HeadererConnectionString);
|
||||
dbc.Open();
|
||||
|
||||
// Create the output list of headers
|
||||
List<string> headers = new List<string>();
|
||||
|
||||
string query = $"SELECT header, type FROM data WHERE sha1='{SHA1}'";
|
||||
SqliteCommand slc = new SqliteCommand(query, dbc);
|
||||
SqliteDataReader sldr = slc.ExecuteReader();
|
||||
|
||||
if (sldr.HasRows)
|
||||
{
|
||||
while (sldr.Read())
|
||||
{
|
||||
logger.Verbose($"Found match with rom type '{sldr.GetString(1)}'");
|
||||
headers.Add(sldr.GetString(0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warning("No matching header could be found!");
|
||||
}
|
||||
|
||||
// Dispose of database objects
|
||||
slc.Dispose();
|
||||
sldr.Dispose();
|
||||
dbc.Dispose();
|
||||
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.IO;
|
||||
|
||||
namespace SabreTools.Logging
|
||||
{
|
||||
@@ -86,7 +87,7 @@ namespace SabreTools.Logging
|
||||
{
|
||||
// Set and create the output
|
||||
if (addDate)
|
||||
Filename = $"{Path.GetFileNameWithoutExtension(filename)} ({DateTime.Now:yyyy-MM-dd HH-mm-ss}).{GetNormalizedExtension(filename)}";
|
||||
Filename = $"{Path.GetFileNameWithoutExtension(filename)} ({DateTime.Now:yyyy-MM-dd HH-mm-ss}).{PathExtensions.GetNormalizedExtension(filename)}";
|
||||
else
|
||||
Filename = filename;
|
||||
}
|
||||
@@ -111,7 +112,7 @@ namespace SabreTools.Logging
|
||||
if (!string.IsNullOrEmpty(LogDirectory) && !Directory.Exists(LogDirectory))
|
||||
Directory.CreateDirectory(LogDirectory);
|
||||
|
||||
FileStream logfile = TryCreate(Path.Combine(LogDirectory, Filename));
|
||||
FileStream logfile = File.Create(Path.Combine(LogDirectory, Filename));
|
||||
_log = new StreamWriter(logfile, Encoding.UTF8, (int)(4 * Constants.KibiByte), true)
|
||||
{
|
||||
AutoFlush = true
|
||||
@@ -415,56 +416,5 @@ namespace SabreTools.Logging
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Remove this region once IO namespace is separated out properly
|
||||
#region TEMPORARY - REMOVEME
|
||||
|
||||
/// <summary>
|
||||
/// Get the extension from the path, if possible
|
||||
/// </summary>
|
||||
/// <param name="path">Path to get extension from</param>
|
||||
/// <returns>Extension, if possible</returns>
|
||||
public static string GetNormalizedExtension(string path)
|
||||
{
|
||||
// Check null or empty first
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
// Get the extension from the path, if possible
|
||||
string ext = Path.GetExtension(path)?.ToLowerInvariant();
|
||||
|
||||
// Check if the extension is null or empty
|
||||
if (string.IsNullOrWhiteSpace(ext))
|
||||
return null;
|
||||
|
||||
// Make sure that extensions are valid
|
||||
ext = ext.TrimStart('.');
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to create a file for write, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to create</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>An opened stream representing the file on success, null otherwise</returns>
|
||||
public static FileStream TryCreate(string file, bool throwOnError = false)
|
||||
{
|
||||
// Now wrap opening the file
|
||||
try
|
||||
{
|
||||
return File.Open(file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win10-x64;win7-x86</RuntimeIdentifiers>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<DefineConstants>NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.Data\SabreTools.Data.csproj" />
|
||||
<ProjectReference Include="..\SabreTools.IO\SabreTools.IO.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace SabreTools.Library.Skippers
|
||||
namespace SabreTools.Skippers
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the header skip operation
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace SabreTools.Library.Skippers
|
||||
namespace SabreTools.Skippers
|
||||
{
|
||||
/// <remarks>
|
||||
/// It is well worth considering just moving the XML files to code, similar to how RV does it
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.IO;
|
||||
|
||||
using SabreTools.Logging;
|
||||
|
||||
namespace SabreTools.Library.Skippers
|
||||
namespace SabreTools.Skippers
|
||||
{
|
||||
public class SkipperRule
|
||||
{
|
||||
@@ -94,12 +94,12 @@ namespace SabreTools.Library.Skippers
|
||||
Ensure(Path.GetDirectoryName(output));
|
||||
|
||||
//logger.User($"Attempting to apply rule to '{input}'");
|
||||
bool success = TransformStream(TryOpenRead(input), TryCreate(output));
|
||||
bool success = TransformStream(File.OpenRead(input), File.Create(output));
|
||||
|
||||
// If the output file has size 0, delete it
|
||||
if (new FileInfo(output).Length == 0)
|
||||
{
|
||||
TryDelete(output);
|
||||
File.Delete(output);
|
||||
success = false;
|
||||
}
|
||||
|
||||
@@ -269,81 +269,6 @@ namespace SabreTools.Library.Skippers
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to create a file for write, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to create</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>An opened stream representing the file on success, null otherwise</returns>
|
||||
public static FileStream TryCreate(string file, bool throwOnError = false)
|
||||
{
|
||||
// Now wrap opening the file
|
||||
try
|
||||
{
|
||||
return File.Open(file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to safely delete a file, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to delete</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>True if the file didn't exist or could be deleted, false otherwise</returns>
|
||||
public static bool TryDelete(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the file exists first
|
||||
if (!File.Exists(file))
|
||||
return true;
|
||||
|
||||
// Now wrap deleting the file
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to open a file for read, optionally throwing the error
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the file to open</param>
|
||||
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
|
||||
/// <returns>An opened stream representing the file on success, null otherwise</returns>
|
||||
public static FileStream TryOpenRead(string file, bool throwOnError = false)
|
||||
{
|
||||
// Check if the file exists first
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
// Now wrap opening the file
|
||||
try
|
||||
{
|
||||
return File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw ex;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.Library.Skippers
|
||||
namespace SabreTools.Skippers
|
||||
{
|
||||
/// <summary>
|
||||
/// Individual test that applies to a SkipperRule
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Help;
|
||||
using SabreTools.Library.DatFiles;
|
||||
using SabreTools.Library.DatItems;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Data;
|
||||
using SabreTools.Help;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.DatFiles;
|
||||
|
||||
Reference in New Issue
Block a user