Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite base structure #7

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions source/Settlers.Toolbox.Infrastructure/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Reflection;

namespace Settlers.Toolbox.Infrastructure
{
public static class AssemblyInfo
{
public static string FullName => GetAssemblyName().FullName;

public static string VersionString => Version.ToString();

public static Version Version => GetAssemblyName().Version;


private static AssemblyName GetAssemblyName()
{
return Assembly.GetExecutingAssembly().GetName();
}
}
}
91 changes: 91 additions & 0 deletions source/Settlers.Toolbox.Infrastructure/Cabinet/CabContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.IO;

using Settlers.Toolbox.Infrastructure.Cabinet.Interfaces;

using UnshieldSharp;

namespace Settlers.Toolbox.Infrastructure.Cabinet
{
public class CabContainer : ICabContainer
{
private UnshieldCabinet _CabContainer;
private IReadOnlyList<CabFile> _CachedFileList;

public int FileCount => _CabContainer?.FileCount ?? -1;

public CabContainer(FileInfo cabContainerFile)
{
if (cabContainerFile == null) throw new ArgumentNullException(nameof(cabContainerFile));
if (!cabContainerFile.Exists) throw new FileNotFoundException(nameof(cabContainerFile));

_CabContainer = UnshieldCabinet.Open(cabContainerFile.FullName);
}

public IReadOnlyList<CabFile> FileList
{
get
{
if (_CabContainer == null)
return null;

if (_CachedFileList != null)
return _CachedFileList;

var fileList = new List<CabFile>();
for (int i = 0; i < FileCount; i++)
{
string fileName = _CabContainer.FileName(i);

fileList.Add(new CabFile(i, fileName));
}

_CachedFileList = fileList;
return fileList;
}
}

public void Close()
{
_CabContainer = null;
}

public bool SaveFile(CabFile file, string destinationPath)
{
if (_CabContainer == null) throw new InvalidOperationException("Unable to save file, none cab file was loaded.");
if (file.Index < 0 || file.Index > FileCount - 1) throw new IndexOutOfRangeException("Unable to save file, index of file is out of range.");

return _CabContainer.FileSave(file.Index, destinationPath);
}

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

~CabContainer()
{
Dispose(false);
}

/// <summary>
/// Release unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing">Releases managed resources, if true.</param>
private void Dispose(bool disposing)
{
if (disposing)
{
// Free managed resources here.
}

// Free unmanaged resources here.
Close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.IO;

using Settlers.Toolbox.Infrastructure.Cabinet.Interfaces;

namespace Settlers.Toolbox.Infrastructure.Cabinet
{
public class CabContainerFactory : ICabContainerFactory
{
public ICabContainer Create(FileInfo cabContainerFile)
{
if (cabContainerFile == null) throw new ArgumentNullException(nameof(cabContainerFile));

return new CabContainer(cabContainerFile);
}
}
}
25 changes: 25 additions & 0 deletions source/Settlers.Toolbox.Infrastructure/Cabinet/CabFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;

using Settlers.Toolbox.Infrastructure.Cabinet.Interfaces;

namespace Settlers.Toolbox.Infrastructure.Cabinet
{
/// <summary>
/// Represents a single file inside a <see cref="ICabContainer"/> as data transfer object.
/// </summary>
public class CabFile
{
public int Index { get; }

public string Name { get; }

public CabFile(int index, string name)
{
if (index < 0) throw new ArgumentNullException(nameof(index));
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a ArgumentNullException.

if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));

Index = index;
Name = name;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;

namespace Settlers.Toolbox.Infrastructure.Cabinet.Interfaces
{
public interface ICabContainer : IDisposable
{
int FileCount { get; }
IReadOnlyList<CabFile> FileList { get; }

bool SaveFile(CabFile file, string destinationPath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.IO;

namespace Settlers.Toolbox.Infrastructure.Cabinet.Interfaces
{
public interface ICabContainerFactory
{
ICabContainer Create(FileInfo cabContainerFile);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.IO;

namespace Settlers.Toolbox.Infrastructure.ExtensionMethods
{
public static class CompareExtensions
{
public static bool HashEquals(this FileInfo fileToHash, string expectedSha1)
{
string calculatedSha1 = fileToHash.CalculateSha1Hash();

return expectedSha1.OrdinalEquals(calculatedSha1);
}

public static bool OrdinalEquals(this string a, string b)
{
return string.Equals(a, b, StringComparison.Ordinal);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Settlers.Toolbox.Infrastructure.ExtensionMethods
{
public static class Sha1HashExtensions
{
public static string CalculateSha1Hash(this FileInfo file)
{
if (file == null) throw new ArgumentNullException(nameof(file));

using (FileStream stream = file.OpenRead())
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(stream);
var sb = new StringBuilder(hash.Length * 2);

foreach (byte b in hash)
{
sb.Append(b.ToString("X2")); // "x2" would produce a lowercase string.
}

return sb.ToString();
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Settlers.Toolbox.Infrastructure.ExtensionMethods
{
public static class UnitConversionExtensions
{
public static double AsBytesToMegabytes(this long bytes)
{
return (bytes / 1024f) / 1024f;
}
}
}
63 changes: 63 additions & 0 deletions source/Settlers.Toolbox.Infrastructure/IO/IniFileAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Runtime.InteropServices;

using Settlers.Toolbox.Infrastructure.IO.Interfaces;

namespace Settlers.Toolbox.Infrastructure.IO
{
public class IniFileAdapter : IIniFileAdapter
{
// NOTE: FireEmerald: Both methods don't like special chars - so don't use them. Example: UTF-8 file containing 'ä' can't be read!
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern int GetPrivateProfileStringW(string lpAppName, string lpKeyName, string lpDefault, string lpReturnedString, int nSize, string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern int WritePrivateProfileStringW(string lpAppName, string lpKeyName, string lpString, string lpFileName);

/// <summary>
/// Retrieves a string from the specified section in an initialization file.
/// </summary>
/// <param name="section">The name of the section containing the key name.</param>
/// <param name="key">The name of the key whose associated string is to be retrieved.</param>
/// <param name="defaultValue">A default string. If the key cannot be found in the initialization file.</param>
/// <param name="file">The name of the initialization file.</param>
/// <returns>The return value is the number of characters copied to the buffer, not including the terminating null character.</returns>
/// <remarks>The GetPrivateProfileString function searches the specified initialization file for a key that matches the name
/// specified by the lpKeyName parameter under the section heading specified by the lpAppName parameter.
/// If it finds the key, the function copies the corresponding string to the buffer. If the key does not exist,
/// the function copies the default character string specified by the lpDefault parameter.</remarks>
public string ReadValueFromFile(string section, string key, string file, string defaultValue = "")
{
if (string.IsNullOrEmpty(section)) throw new ArgumentNullException(nameof(section));
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
if (string.IsNullOrEmpty(file)) throw new ArgumentNullException(nameof(file));
if (defaultValue == null) throw new ArgumentNullException(nameof(defaultValue));

var buffer = new string(' ', 1024);
var length = GetPrivateProfileStringW(section, key, defaultValue, buffer, buffer.Length, file);

return buffer.Substring(0, length);
}

/// <summary>
/// Copies a string into the specified section of an initialization file.
/// </summary>
/// <param name="section">The name of the section to which the string will be copied. If the section does not exist, it is created.
/// The name of the section is case-independent; the string can be any combination of uppercase and lowercase letters.</param>
/// <param name="key">The name of the key to be associated with a string. If the key does not exist in the specified section, it is created.
/// If this parameter is NULL, the entire section, including all entries within the section, is deleted.</param>
/// <param name="value">A null-terminated string to be written to the file. If this parameter is NULL, the key pointed to by the key parameter is deleted.</param>
/// <param name="file">The name of the initialization file.</param>
/// <returns>If the function successfully copies the string to the initialization file, the return value is nonzero. If the function fails,
/// or if it flushes the cached version of the most recently accessed initialization file, the return value is zero.</returns>
public bool WriteValueToFile(string section, string key, string value, string file)
{
if (string.IsNullOrEmpty(section)) throw new ArgumentNullException(nameof(section));
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
if (value == null) throw new ArgumentNullException(nameof(value));
if (string.IsNullOrEmpty(file)) throw new ArgumentNullException(nameof(file));

return WritePrivateProfileStringW(section, key, " " + value, file) != 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Settlers.Toolbox.Infrastructure.IO.Interfaces
{
public interface IIniFileAdapter
{
string ReadValueFromFile(string section, string key, string file, string defaultValue = "");
bool WriteValueToFile(string section, string key, string value, string file);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.IO;

namespace Settlers.Toolbox.Infrastructure.IO.Interfaces
{
public interface IZipFileAdapter
{
void ExtractToDirectory(FileInfo fileToUnzip, DirectoryInfo destinationDirectory);
}
}
15 changes: 15 additions & 0 deletions source/Settlers.Toolbox.Infrastructure/IO/ZipFileAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.IO;
using System.IO.Compression;

using Settlers.Toolbox.Infrastructure.IO.Interfaces;

namespace Settlers.Toolbox.Infrastructure.IO
{
public class ZipFileAdapter : IZipFileAdapter
{
public void ExtractToDirectory(FileInfo fileToUnzip, DirectoryInfo destinationDirectory)
{
ZipFile.ExtractToDirectory(fileToUnzip.FullName, destinationDirectory.FullName);
}
}
}
Loading