Full code refactor and clean-up.

This commit is contained in:
2024-11-09 01:37:59 +00:00
parent 1ebc273ff7
commit 9a429ce439
108 changed files with 12878 additions and 12195 deletions

View File

@@ -35,201 +35,227 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
namespace RomRepoMgr.Core.Aaru
namespace RomRepoMgr.Core.Aaru;
// TODO: This should be taken from Aaru as a nuget package in the future
public static class FAT
{
// TODO: This should be taken from Aaru as a nuget package in the future
public static class FAT
static int CountBits(uint number)
{
static int CountBits(uint number)
{
number -= (number >> 1) & 0x55555555;
number = (number & 0x33333333) + ((number >> 2) & 0x33333333);
number -= number >> 1 & 0x55555555;
number = (number & 0x33333333) + (number >> 2 & 0x33333333);
return (int)((((number + (number >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
return (int)((number + (number >> 4) & 0x0F0F0F0F) * 0x01010101 >> 24);
}
public static bool Identify(string path)
{
try
{
return Identify(new FileStream(path, FileMode.Open, FileAccess.Read));
}
public static bool Identify(string path)
catch(Exception e)
{
try
{
return Identify(new FileStream(path, FileMode.Open, FileAccess.Read));
}
catch(Exception e)
{
return false;
}
}
[SuppressMessage("ReSharper", "JoinDeclarationAndInitializer")]
static bool Identify(Stream imageStream)
{
ushort bps;
byte spc;
byte numberOfFats;
ushort reservedSecs;
ushort rootEntries;
ushort sectors;
ushort fatSectors;
uint bigSectors;
byte bpbSignature;
byte fat32Signature;
ulong hugeSectors;
byte[] fat32Id = new byte[8];
byte[] msxId = new byte[6];
byte[] dosOem = new byte[8];
byte[] atariOem = new byte[6];
ushort bootable = 0;
byte[] bpbSector = new byte[512];
byte[] fatSector = new byte[512];
imageStream.Position = 0;
imageStream.Read(bpbSector, 0, 512);
imageStream.Read(fatSector, 0, 512);
Array.Copy(bpbSector, 0x02, atariOem, 0, 6);
Array.Copy(bpbSector, 0x03, dosOem, 0, 8);
bps = BitConverter.ToUInt16(bpbSector, 0x00B);
spc = bpbSector[0x00D];
reservedSecs = BitConverter.ToUInt16(bpbSector, 0x00E);
numberOfFats = bpbSector[0x010];
rootEntries = BitConverter.ToUInt16(bpbSector, 0x011);
sectors = BitConverter.ToUInt16(bpbSector, 0x013);
fatSectors = BitConverter.ToUInt16(bpbSector, 0x016);
Array.Copy(bpbSector, 0x052, msxId, 0, 6);
bigSectors = BitConverter.ToUInt32(bpbSector, 0x020);
bpbSignature = bpbSector[0x026];
fat32Signature = bpbSector[0x042];
Array.Copy(bpbSector, 0x052, fat32Id, 0, 8);
hugeSectors = BitConverter.ToUInt64(bpbSector, 0x052);
int bitsInBps = CountBits(bps);
bootable = BitConverter.ToUInt16(bpbSector, 0x1FE);
bool correctSpc = spc == 1 || spc == 2 || spc == 4 || spc == 8 || spc == 16 || spc == 32 || spc == 64;
string msxString = Encoding.ASCII.GetString(msxId);
string fat32String = Encoding.ASCII.GetString(fat32Id);
string oemString = Encoding.ASCII.GetString(dosOem);
ushort apricotBps = BitConverter.ToUInt16(bpbSector, 0x50);
byte apricotSpc = bpbSector[0x52];
ushort apricotReservedSecs = BitConverter.ToUInt16(bpbSector, 0x53);
byte apricotFatsNo = bpbSector[0x55];
ushort apricotRootEntries = BitConverter.ToUInt16(bpbSector, 0x56);
ushort apricotSectors = BitConverter.ToUInt16(bpbSector, 0x58);
ushort apricotFatSectors = BitConverter.ToUInt16(bpbSector, 0x5B);
bool apricotCorrectSpc = apricotSpc == 1 || apricotSpc == 2 || apricotSpc == 4 || apricotSpc == 8 ||
apricotSpc == 16 || apricotSpc == 32 || apricotSpc == 64;
int bitsInApricotBps = CountBits(apricotBps);
byte apricotPartitions = bpbSector[0x0C];
switch(oemString)
{
// exFAT
case "EXFAT ": return false;
// NTFS
case "NTFS " when bootable == 0xAA55 && numberOfFats == 0 && fatSectors == 0: return false;
// QNX4
case "FQNX4FS ": return false;
}
ulong imageSectors = (ulong)imageStream.Length / 512;
switch(bitsInBps)
{
// FAT32 for sure
case 1 when correctSpc && numberOfFats <= 2 && sectors == 0 && fatSectors == 0 &&
fat32Signature == 0x29 && fat32String == "FAT32 ": return true;
// short FAT32
case 1
when correctSpc && numberOfFats <= 2 && sectors == 0 && fatSectors == 0 && fat32Signature == 0x28:
return bigSectors == 0 ? hugeSectors <= imageSectors : bigSectors <= imageSectors;
// MSX-DOS FAT12
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && sectors <= imageSectors &&
fatSectors > 0 && msxString == "VOL_ID": return true;
// EBPB
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && fatSectors > 0 &&
(bpbSignature == 0x28 || bpbSignature == 0x29):
return sectors == 0 ? bigSectors <= imageSectors : sectors <= imageSectors;
// BPB
case 1 when correctSpc && reservedSecs < imageSectors - 1 && numberOfFats <= 2 && rootEntries > 0 &&
fatSectors > 0: return sectors == 0 ? bigSectors <= imageSectors : sectors <= imageSectors;
}
// Apricot BPB
if(bitsInApricotBps == 1 &&
apricotCorrectSpc &&
apricotReservedSecs < imageSectors - 1 &&
apricotFatsNo <= 2 &&
apricotRootEntries > 0 &&
apricotFatSectors > 0 &&
apricotSectors <= imageSectors &&
apricotPartitions == 0)
return true;
// DEC Rainbow, lacks a BPB but has a very concrete structure...
if(imageSectors != 800)
return false;
// DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts)
byte z80Di = bpbSector[0];
// First FAT1 sector resides at LBA 0x14
byte[] fat1Sector0 = new byte[512];
imageStream.Position = 0x14 * 512;
imageStream.Read(fat1Sector0, 0, 512);
// First FAT2 sector resides at LBA 0x1A
byte[] fat2Sector0 = new byte[512];
imageStream.Position = 0x1A * 512;
imageStream.Read(fat2Sector0, 0, 512);
bool equalFatIds = fat1Sector0[0] == fat2Sector0[0] && fat1Sector0[1] == fat2Sector0[1];
// Volume is software interleaved 2:1
var rootMs = new MemoryStream();
byte[] tmp = new byte[512];
foreach(long position in new long[]
{
0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20
})
{
imageStream.Position = position * 512;
imageStream.Read(tmp, 0, 512);
rootMs.Write(tmp, 0, tmp.Length);
}
byte[] rootDir = rootMs.ToArray();
bool validRootDir = true;
// Iterate all root directory
for(int e = 0; e < 96 * 32; e += 32)
{
for(int c = 0; c < 11; c++)
if((rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05) ||
rootDir[c + e] == 0xFF ||
rootDir[c + e] == 0x2E)
{
validRootDir = false;
break;
}
if(!validRootDir)
break;
}
return z80Di == 0xF3 && equalFatIds && (fat1Sector0[0] & 0xF0) == 0xF0 && fat1Sector0[1] == 0xFF &&
validRootDir;
return false;
}
}
[SuppressMessage("ReSharper", "JoinDeclarationAndInitializer")]
static bool Identify(Stream imageStream)
{
ushort bps;
byte spc;
byte numberOfFats;
ushort reservedSecs;
ushort rootEntries;
ushort sectors;
ushort fatSectors;
uint bigSectors;
byte bpbSignature;
byte fat32Signature;
ulong hugeSectors;
var fat32Id = new byte[8];
var msxId = new byte[6];
var dosOem = new byte[8];
var atariOem = new byte[6];
ushort bootable = 0;
var bpbSector = new byte[512];
var fatSector = new byte[512];
imageStream.Position = 0;
imageStream.Read(bpbSector, 0, 512);
imageStream.Read(fatSector, 0, 512);
Array.Copy(bpbSector, 0x02, atariOem, 0, 6);
Array.Copy(bpbSector, 0x03, dosOem, 0, 8);
bps = BitConverter.ToUInt16(bpbSector, 0x00B);
spc = bpbSector[0x00D];
reservedSecs = BitConverter.ToUInt16(bpbSector, 0x00E);
numberOfFats = bpbSector[0x010];
rootEntries = BitConverter.ToUInt16(bpbSector, 0x011);
sectors = BitConverter.ToUInt16(bpbSector, 0x013);
fatSectors = BitConverter.ToUInt16(bpbSector, 0x016);
Array.Copy(bpbSector, 0x052, msxId, 0, 6);
bigSectors = BitConverter.ToUInt32(bpbSector, 0x020);
bpbSignature = bpbSector[0x026];
fat32Signature = bpbSector[0x042];
Array.Copy(bpbSector, 0x052, fat32Id, 0, 8);
hugeSectors = BitConverter.ToUInt64(bpbSector, 0x052);
int bitsInBps = CountBits(bps);
bootable = BitConverter.ToUInt16(bpbSector, 0x1FE);
bool correctSpc = spc == 1 || spc == 2 || spc == 4 || spc == 8 || spc == 16 || spc == 32 || spc == 64;
string msxString = Encoding.ASCII.GetString(msxId);
string fat32String = Encoding.ASCII.GetString(fat32Id);
string oemString = Encoding.ASCII.GetString(dosOem);
var apricotBps = BitConverter.ToUInt16(bpbSector, 0x50);
byte apricotSpc = bpbSector[0x52];
var apricotReservedSecs = BitConverter.ToUInt16(bpbSector, 0x53);
byte apricotFatsNo = bpbSector[0x55];
var apricotRootEntries = BitConverter.ToUInt16(bpbSector, 0x56);
var apricotSectors = BitConverter.ToUInt16(bpbSector, 0x58);
var apricotFatSectors = BitConverter.ToUInt16(bpbSector, 0x5B);
bool apricotCorrectSpc = apricotSpc == 1 ||
apricotSpc == 2 ||
apricotSpc == 4 ||
apricotSpc == 8 ||
apricotSpc == 16 ||
apricotSpc == 32 ||
apricotSpc == 64;
int bitsInApricotBps = CountBits(apricotBps);
byte apricotPartitions = bpbSector[0x0C];
switch(oemString)
{
// exFAT
case "EXFAT ":
return false;
// NTFS
case "NTFS " when bootable == 0xAA55 && numberOfFats == 0 && fatSectors == 0:
return false;
// QNX4
case "FQNX4FS ":
return false;
}
ulong imageSectors = (ulong)imageStream.Length / 512;
switch(bitsInBps)
{
// FAT32 for sure
case 1 when correctSpc &&
numberOfFats <= 2 &&
sectors == 0 &&
fatSectors == 0 &&
fat32Signature == 0x29 &&
fat32String == "FAT32 ":
return true;
// short FAT32
case 1 when correctSpc && numberOfFats <= 2 && sectors == 0 && fatSectors == 0 && fat32Signature == 0x28:
return bigSectors == 0 ? hugeSectors <= imageSectors : bigSectors <= imageSectors;
// MSX-DOS FAT12
case 1 when correctSpc &&
numberOfFats <= 2 &&
rootEntries > 0 &&
sectors <= imageSectors &&
fatSectors > 0 &&
msxString == "VOL_ID":
return true;
// EBPB
case 1 when correctSpc &&
numberOfFats <= 2 &&
rootEntries > 0 &&
fatSectors > 0 &&
(bpbSignature == 0x28 || bpbSignature == 0x29):
return sectors == 0 ? bigSectors <= imageSectors : sectors <= imageSectors;
// BPB
case 1 when correctSpc &&
reservedSecs < imageSectors - 1 &&
numberOfFats <= 2 &&
rootEntries > 0 &&
fatSectors > 0:
return sectors == 0 ? bigSectors <= imageSectors : sectors <= imageSectors;
}
// Apricot BPB
if(bitsInApricotBps == 1 &&
apricotCorrectSpc &&
apricotReservedSecs < imageSectors - 1 &&
apricotFatsNo <= 2 &&
apricotRootEntries > 0 &&
apricotFatSectors > 0 &&
apricotSectors <= imageSectors &&
apricotPartitions == 0)
return true;
// DEC Rainbow, lacks a BPB but has a very concrete structure...
if(imageSectors != 800) return false;
// DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts)
byte z80Di = bpbSector[0];
// First FAT1 sector resides at LBA 0x14
var fat1Sector0 = new byte[512];
imageStream.Position = 0x14 * 512;
imageStream.Read(fat1Sector0, 0, 512);
// First FAT2 sector resides at LBA 0x1A
var fat2Sector0 = new byte[512];
imageStream.Position = 0x1A * 512;
imageStream.Read(fat2Sector0, 0, 512);
bool equalFatIds = fat1Sector0[0] == fat2Sector0[0] && fat1Sector0[1] == fat2Sector0[1];
// Volume is software interleaved 2:1
var rootMs = new MemoryStream();
var tmp = new byte[512];
foreach(long position in new long[]
{
0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20
})
{
imageStream.Position = position * 512;
imageStream.Read(tmp, 0, 512);
rootMs.Write(tmp, 0, tmp.Length);
}
byte[] rootDir = rootMs.ToArray();
var validRootDir = true;
// Iterate all root directory
for(var e = 0; e < 96 * 32; e += 32)
{
for(var c = 0; c < 11; c++)
{
if(rootDir[c + e] < 0x20 && rootDir[c + e] != 0x00 && rootDir[c + e] != 0x05 ||
rootDir[c + e] == 0xFF ||
rootDir[c + e] == 0x2E)
{
validRootDir = false;
break;
}
}
if(!validRootDir) break;
}
return z80Di == 0xF3 &&
equalFatIds &&
(fat1Sector0[0] & 0xF0) == 0xF0 &&
fat1Sector0[1] == 0xFF &&
validRootDir;
}
}

View File

@@ -8,98 +8,76 @@ using System;
using System.Text;
using RomRepoMgr.Core.Resources;
namespace RomRepoMgr.Core
namespace RomRepoMgr.Core;
/// <summary>Class used for conversion between byte array and Base32 notation</summary>
public sealed class Base32
{
/// <summary>Class used for conversion between byte array and Base32 notation</summary>
public sealed class Base32
/// <summary>Size of the regular byte in bits</summary>
const int _inByteSize = 8;
/// <summary>Size of converted byte in bits</summary>
const int _outByteSize = 5;
/// <summary>Alphabet</summary>
const string _base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
/// <summary>Convert byte array to Base32 format</summary>
/// <param name="bytes">An array of bytes to convert to Base32 format</param>
/// <returns>Returns a string representing byte array</returns>
public static string ToBase32String(byte[] bytes)
{
/// <summary>Size of the regular byte in bits</summary>
const int _inByteSize = 8;
// Check if byte array is null
if(bytes == null) return null;
/// <summary>Size of converted byte in bits</summary>
const int _outByteSize = 5;
// Check if empty
/// <summary>Alphabet</summary>
const string _base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
if(bytes.Length == 0) return string.Empty;
/// <summary>Convert byte array to Base32 format</summary>
/// <param name="bytes">An array of bytes to convert to Base32 format</param>
/// <returns>Returns a string representing byte array</returns>
public static string ToBase32String(byte[] bytes)
// Prepare container for the final value
var builder = new StringBuilder(bytes.Length * _inByteSize / _outByteSize);
// Position in the input buffer
var bytesPosition = 0;
// Offset inside a single byte that <bytesPosition> points to (from left to right)
// 0 - highest bit, 7 - lowest bit
var bytesSubPosition = 0;
// Byte to look up in the dictionary
byte outputBase32Byte = 0;
// The number of bits filled in the current output byte
var outputBase32BytePosition = 0;
// Iterate through input buffer until we reach past the end of it
while(bytesPosition < bytes.Length)
{
// Check if byte array is null
if(bytes == null)
return null;
// Calculate the number of bits we can extract out of current input byte to fill missing bits in the output byte
int bitsAvailableInByte = Math.Min(_inByteSize - bytesSubPosition, _outByteSize - outputBase32BytePosition);
// Check if empty
// Make space in the output byte
outputBase32Byte <<= bitsAvailableInByte;
if(bytes.Length == 0)
return string.Empty;
// Extract the part of the input byte and move it to the output byte
outputBase32Byte |= (byte)(bytes[bytesPosition] >> _inByteSize - (bytesSubPosition + bitsAvailableInByte));
// Prepare container for the final value
var builder = new StringBuilder((bytes.Length * _inByteSize) / _outByteSize);
// Update current sub-byte position
bytesSubPosition += bitsAvailableInByte;
// Position in the input buffer
int bytesPosition = 0;
// Offset inside a single byte that <bytesPosition> points to (from left to right)
// 0 - highest bit, 7 - lowest bit
int bytesSubPosition = 0;
// Byte to look up in the dictionary
byte outputBase32Byte = 0;
// The number of bits filled in the current output byte
int outputBase32BytePosition = 0;
// Iterate through input buffer until we reach past the end of it
while(bytesPosition < bytes.Length)
// Check overflow
if(bytesSubPosition >= _inByteSize)
{
// Calculate the number of bits we can extract out of current input byte to fill missing bits in the output byte
int bitsAvailableInByte =
Math.Min(_inByteSize - bytesSubPosition, _outByteSize - outputBase32BytePosition);
// Make space in the output byte
outputBase32Byte <<= bitsAvailableInByte;
// Extract the part of the input byte and move it to the output byte
outputBase32Byte |=
(byte)(bytes[bytesPosition] >> (_inByteSize - (bytesSubPosition + bitsAvailableInByte)));
// Update current sub-byte position
bytesSubPosition += bitsAvailableInByte;
// Check overflow
if(bytesSubPosition >= _inByteSize)
{
// Move to the next byte
bytesPosition++;
bytesSubPosition = 0;
}
// Update current base32 byte completion
outputBase32BytePosition += bitsAvailableInByte;
// Check overflow or end of input array
if(outputBase32BytePosition < _outByteSize)
continue;
// Drop the overflow bits
outputBase32Byte &= 0x1F; // 0x1F = 00011111 in binary
// Add current Base32 byte and convert it to character
builder.Append(_base32Alphabet[outputBase32Byte]);
// Move to the next byte
outputBase32BytePosition = 0;
bytesPosition++;
bytesSubPosition = 0;
}
// Check if we have a remainder
if(outputBase32BytePosition <= 0)
return builder.ToString();
// Update current base32 byte completion
outputBase32BytePosition += bitsAvailableInByte;
// Move to the right bits
outputBase32Byte <<= _outByteSize - outputBase32BytePosition;
// Check overflow or end of input array
if(outputBase32BytePosition < _outByteSize) continue;
// Drop the overflow bits
outputBase32Byte &= 0x1F; // 0x1F = 00011111 in binary
@@ -107,91 +85,103 @@ namespace RomRepoMgr.Core
// Add current Base32 byte and convert it to character
builder.Append(_base32Alphabet[outputBase32Byte]);
return builder.ToString();
// Move to the next byte
outputBase32BytePosition = 0;
}
/// <summary>Convert base32 string to array of bytes</summary>
/// <param name="base32String">Base32 string to convert</param>
/// <returns>Returns a byte array converted from the string</returns>
public static byte[] FromBase32String(string base32String)
// Check if we have a remainder
if(outputBase32BytePosition <= 0) return builder.ToString();
// Move to the right bits
outputBase32Byte <<= _outByteSize - outputBase32BytePosition;
// Drop the overflow bits
outputBase32Byte &= 0x1F; // 0x1F = 00011111 in binary
// Add current Base32 byte and convert it to character
builder.Append(_base32Alphabet[outputBase32Byte]);
return builder.ToString();
}
/// <summary>Convert base32 string to array of bytes</summary>
/// <param name="base32String">Base32 string to convert</param>
/// <returns>Returns a byte array converted from the string</returns>
public static byte[] FromBase32String(string base32String)
{
// Check if string is null
if(base32String == null) return null;
// Check if empty
if(base32String == string.Empty) return new byte[0];
// Convert to upper-case
string base32StringUpperCase = base32String.ToUpperInvariant();
// Prepare output byte array
var outputBytes = new byte[base32StringUpperCase.Length * _outByteSize / _inByteSize];
// Check the size
if(outputBytes.Length == 0) throw new ArgumentException(Localization.Base32_Not_enought_data);
// Position in the string
var base32Position = 0;
// Offset inside the character in the string
var base32SubPosition = 0;
// Position within outputBytes array
var outputBytePosition = 0;
// The number of bits filled in the current output byte
var outputByteSubPosition = 0;
// Normally we would iterate on the input array but in this case we actually iterate on the output array
// We do it because output array doesn't have overflow bits, while input does and it will cause output array overflow if we don''t stop in time
while(outputBytePosition < outputBytes.Length)
{
// Check if string is null
if(base32String == null)
return null;
// Look up current character in the dictionary to convert it to byte
int currentBase32Byte = _base32Alphabet.IndexOf(base32StringUpperCase[base32Position]);
// Check if empty
if(base32String == string.Empty)
return new byte[0];
// Convert to upper-case
string base32StringUpperCase = base32String.ToUpperInvariant();
// Prepare output byte array
byte[] outputBytes = new byte[(base32StringUpperCase.Length * _outByteSize) / _inByteSize];
// Check the size
if(outputBytes.Length == 0)
throw new ArgumentException(Localization.Base32_Not_enought_data);
// Position in the string
int base32Position = 0;
// Offset inside the character in the string
int base32SubPosition = 0;
// Position within outputBytes array
int outputBytePosition = 0;
// The number of bits filled in the current output byte
int outputByteSubPosition = 0;
// Normally we would iterate on the input array but in this case we actually iterate on the output array
// We do it because output array doesn't have overflow bits, while input does and it will cause output array overflow if we don''t stop in time
while(outputBytePosition < outputBytes.Length)
// Check if found
if(currentBase32Byte < 0)
{
// Look up current character in the dictionary to convert it to byte
int currentBase32Byte = _base32Alphabet.IndexOf(base32StringUpperCase[base32Position]);
// Check if found
if(currentBase32Byte < 0)
throw new ArgumentException(string.Format(Localization.Base32_Invalid_format,
base32String[base32Position]));
// Calculate the number of bits we can extract out of current input character to fill missing bits in the output byte
int bitsAvailableInByte =
Math.Min(_outByteSize - base32SubPosition, _inByteSize - outputByteSubPosition);
// Make space in the output byte
outputBytes[outputBytePosition] <<= bitsAvailableInByte;
// Extract the part of the input character and move it to the output byte
outputBytes[outputBytePosition] |=
(byte)(currentBase32Byte >> (_outByteSize - (base32SubPosition + bitsAvailableInByte)));
// Update current sub-byte position
outputByteSubPosition += bitsAvailableInByte;
// Check overflow
if(outputByteSubPosition >= _inByteSize)
{
// Move to the next byte
outputBytePosition++;
outputByteSubPosition = 0;
}
// Update current base32 byte completion
base32SubPosition += bitsAvailableInByte;
// Check overflow or end of input array
if(base32SubPosition < _outByteSize)
continue;
// Move to the next character
base32Position++;
base32SubPosition = 0;
throw new ArgumentException(string.Format(Localization.Base32_Invalid_format,
base32String[base32Position]));
}
return outputBytes;
// Calculate the number of bits we can extract out of current input character to fill missing bits in the output byte
int bitsAvailableInByte = Math.Min(_outByteSize - base32SubPosition, _inByteSize - outputByteSubPosition);
// Make space in the output byte
outputBytes[outputBytePosition] <<= bitsAvailableInByte;
// Extract the part of the input character and move it to the output byte
outputBytes[outputBytePosition] |=
(byte)(currentBase32Byte >> _outByteSize - (base32SubPosition + bitsAvailableInByte));
// Update current sub-byte position
outputByteSubPosition += bitsAvailableInByte;
// Check overflow
if(outputByteSubPosition >= _inByteSize)
{
// Move to the next byte
outputBytePosition++;
outputByteSubPosition = 0;
}
// Update current base32 byte completion
base32SubPosition += bitsAvailableInByte;
// Check overflow or end of input array
if(base32SubPosition < _outByteSize) continue;
// Move to the next character
base32Position++;
base32SubPosition = 0;
}
return outputBytes;
}
}

View File

@@ -33,288 +33,287 @@
using System;
using System.Linq;
namespace Aaru.Helpers
namespace Aaru.Helpers;
/// <summary>
/// Converts base data types to an array of bytes, and an array of bytes to base data types. All info taken from
/// the meta data of System.BitConverter. This implementation allows for Endianness consideration.
/// </summary>
public static class BigEndianBitConverter
{
/// <summary>Converts the specified double-precision floating point number to a 64-bit signed integer.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
/// <exception cref="NotImplementedException">It is not currently implemented</exception>
public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
/// <summary>Returns the specified Boolean value as an array of bytes.</summary>
/// <param name="value">A Boolean value.</param>
/// <returns>An array of bytes with length 1.</returns>
public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified Unicode character value as an array of bytes.</summary>
/// <param name="value">A character to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified double-precision floating point value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified single-precision floating point value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 32-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 64-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 16-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 32-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 64-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 16-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Converts the specified 64-bit signed integer to a double-precision floating point number.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
/// <summary>Returns a Boolean value converted from one byte at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>true if the byte at <see cref="startIndex" /> in value is nonzero; otherwise, false.</returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>Returns a Unicode character converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">An array.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A character formed by two bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>
/// Converts base data types to an array of bytes, and an array of bytes to base data types. All info taken from
/// the meta data of System.BitConverter. This implementation allows for Endianness consideration.
/// Returns a double-precision floating point number converted from eight bytes at a specified position in a byte
/// array.
/// </summary>
public static class BigEndianBitConverter
{
/// <summary>Converts the specified double-precision floating point number to a 64-bit signed integer.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
/// <exception cref="NotImplementedException">It is not currently implemented</exception>
public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A double precision floating point number formed by eight bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 7, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>Returns the specified Boolean value as an array of bytes.</summary>
/// <param name="value">A Boolean value.</param>
/// <returns>An array of bytes with length 1.</returns>
public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit signed integer formed by two bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static short ToInt16(byte[] value, int startIndex) =>
BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
/// <summary>Returns the specified Unicode character value as an array of bytes.</summary>
/// <param name="value">A character to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit signed integer formed by four bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 3, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static int ToInt32(byte[] value, int startIndex) =>
BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
/// <summary>Returns the specified double-precision floating point value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit signed integer formed by eight bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 7, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static long ToInt64(byte[] value, int startIndex) =>
BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
/// <summary>Returns the specified single-precision floating point value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>
/// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
/// array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A single-precision floating point number formed by four bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 3, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static float ToSingle(byte[] value, int startIndex) =>
BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
/// <summary>Returns the specified 32-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>
/// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
/// representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
/// <summary>Returns the specified 64-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
/// string representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in a subarray of value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static string ToString(byte[] value, int startIndex) =>
BitConverter.ToString(value.Reverse().ToArray(), startIndex);
/// <summary>Returns the specified 16-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
/// string representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <param name="length">The number of array elements in value to convert.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in a subarray of value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex or length is less than zero. -or- startIndex is greater
/// than zero and is greater than or equal to the length of value.
/// </exception>
/// <exception cref="System.ArgumentException">
/// The combination of startIndex and length does not specify a position within
/// value; that is, the startIndex parameter is greater than the length of value minus the length parameter.
/// </exception>
public static string ToString(byte[] value, int startIndex, int length) =>
BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
/// <summary>Returns the specified 32-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">The array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">startIndex equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static ushort ToUInt16(byte[] value, int startIndex) =>
BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
/// <summary>Returns the specified 64-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">
/// startIndex is greater than or equal to the length of value minus 3, and is
/// less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static uint ToUInt32(byte[] value, int startIndex) =>
BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
/// <summary>Returns the specified 16-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">
/// startIndex is greater than or equal to the length of value minus 7, and is
/// less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static ulong ToUInt64(byte[] value, int startIndex) =>
BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(ulong) - startIndex);
/// <summary>Converts the specified 64-bit signed integer to a double-precision floating point number.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
/// <summary>Returns a Boolean value converted from one byte at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>true if the byte at <see cref="startIndex" /> in value is nonzero; otherwise, false.</returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>Returns a Unicode character converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">An array.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A character formed by two bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>
/// Returns a double-precision floating point number converted from eight bytes at a specified position in a byte
/// array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A double precision floating point number formed by eight bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 7, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit signed integer formed by two bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static short ToInt16(byte[] value, int startIndex) =>
BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
/// <summary>Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit signed integer formed by four bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 3, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static int ToInt32(byte[] value, int startIndex) =>
BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
/// <summary>Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit signed integer formed by eight bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 7, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static long ToInt64(byte[] value, int startIndex) =>
BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
/// <summary>
/// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
/// array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A single-precision floating point number formed by four bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 3, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static float ToSingle(byte[] value, int startIndex) =>
BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
/// <summary>
/// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
/// representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
/// string representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in a subarray of value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static string ToString(byte[] value, int startIndex) =>
BitConverter.ToString(value.Reverse().ToArray(), startIndex);
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
/// string representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <param name="length">The number of array elements in value to convert.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in a subarray of value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex or length is less than zero. -or- startIndex is greater
/// than zero and is greater than or equal to the length of value.
/// </exception>
/// <exception cref="System.ArgumentException">
/// The combination of startIndex and length does not specify a position within
/// value; that is, the startIndex parameter is greater than the length of value minus the length parameter.
/// </exception>
public static string ToString(byte[] value, int startIndex, int length) =>
BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
/// <summary>Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">The array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">startIndex equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static ushort ToUInt16(byte[] value, int startIndex) =>
BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
/// <summary>Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">
/// startIndex is greater than or equal to the length of value minus 3, and is
/// less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static uint ToUInt32(byte[] value, int startIndex) =>
BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
/// <summary>Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">
/// startIndex is greater than or equal to the length of value minus 7, and is
/// less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static ulong ToUInt64(byte[] value, int startIndex) =>
BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(ulong) - startIndex);
public static Guid ToGuid(byte[] value, int startIndex) => new Guid(ToUInt32(value, 0 + startIndex),
ToUInt16(value, 4 + startIndex),
ToUInt16(value, 6 + startIndex),
value[8 + startIndex + 0],
value[8 + startIndex + 1],
value[8 + startIndex + 2],
value[8 + startIndex + 3],
value[8 + startIndex + 5],
value[8 + startIndex + 5],
value[8 + startIndex + 6],
value[8 + startIndex + 7]);
}
public static Guid ToGuid(byte[] value, int startIndex) => new(ToUInt32(value, 0 + startIndex),
ToUInt16(value, 4 + startIndex),
ToUInt16(value, 6 + startIndex),
value[8 + startIndex + 0],
value[8 + startIndex + 1],
value[8 + startIndex + 2],
value[8 + startIndex + 3],
value[8 + startIndex + 5],
value[8 + startIndex + 5],
value[8 + startIndex + 6],
value[8 + startIndex + 7]);
}

View File

@@ -35,199 +35,202 @@ using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Implements a CRC32 algorithm</summary>
public sealed class Crc32Context : IChecksum
{
/// <summary>Implements a CRC32 algorithm</summary>
public sealed class Crc32Context : IChecksum
const uint CRC32_ISO_POLY = 0xEDB88320;
const uint CRC32_ISO_SEED = 0xFFFFFFFF;
readonly uint _finalSeed;
readonly uint[] _table;
uint _hashInt;
/// <summary>Initializes the CRC32 table and seed as CRC32-ISO</summary>
public Crc32Context()
{
const uint CRC32_ISO_POLY = 0xEDB88320;
const uint CRC32_ISO_SEED = 0xFFFFFFFF;
_hashInt = CRC32_ISO_SEED;
_finalSeed = CRC32_ISO_SEED;
readonly uint _finalSeed;
readonly uint[] _table;
uint _hashInt;
_table = new uint[256];
/// <summary>Initializes the CRC32 table and seed as CRC32-ISO</summary>
public Crc32Context()
for(var i = 0; i < 256; i++)
{
_hashInt = CRC32_ISO_SEED;
_finalSeed = CRC32_ISO_SEED;
var entry = (uint)i;
_table = new uint[256];
for(int i = 0; i < 256; i++)
for(var j = 0; j < 8; j++)
{
uint entry = (uint)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ CRC32_ISO_POLY;
else
entry = entry >> 1;
_table[i] = entry;
}
}
/// <summary>Initializes the CRC32 table with a custom polynomial and seed</summary>
public Crc32Context(uint polynomial, uint seed)
{
_hashInt = seed;
_finalSeed = seed;
_table = new uint[256];
for(int i = 0; i < 256; i++)
{
uint entry = (uint)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry = entry >> 1;
_table[i] = entry;
}
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
for(int i = 0; i < len; i++)
_hashInt = (_hashInt >> 8) ^ _table[data[i] ^ (_hashInt & 0xff)];
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed);
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var crc32Output = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed).Length; i++)
crc32Output.Append(BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed)[i].ToString("x2"));
return crc32Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string File(string filename, out byte[] hash, uint polynomial, uint seed)
{
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
uint localhashInt = seed;
uint[] localTable = new uint[256];
for(int i = 0; i < 256; i++)
{
uint entry = (uint)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry = entry >> 1;
localTable[i] = entry;
if((entry & 1) == 1)
entry = entry >> 1 ^ CRC32_ISO_POLY;
else
entry = entry >> 1;
}
for(int i = 0; i < fileStream.Length; i++)
localhashInt = (localhashInt >> 8) ^ localTable[fileStream.ReadByte() ^ (localhashInt & 0xff)];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc32Output = new StringBuilder();
foreach(byte h in hash)
crc32Output.Append(h.ToString("x2"));
fileStream.Close();
return crc32Output.ToString();
_table[i] = entry;
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string Data(byte[] data, uint len, out byte[] hash, uint polynomial, uint seed)
{
uint localhashInt = seed;
uint[] localTable = new uint[256];
for(int i = 0; i < 256; i++)
{
uint entry = (uint)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry = entry >> 1;
localTable[i] = entry;
}
for(int i = 0; i < len; i++)
localhashInt = (localhashInt >> 8) ^ localTable[data[i] ^ (localhashInt & 0xff)];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc32Output = new StringBuilder();
foreach(byte h in hash)
crc32Output.Append(h.ToString("x2"));
return crc32Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
/// <summary>Initializes the CRC32 table with a custom polynomial and seed</summary>
public Crc32Context(uint polynomial, uint seed)
{
_hashInt = seed;
_finalSeed = seed;
_table = new uint[256];
for(var i = 0; i < 256; i++)
{
var entry = (uint)i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry = entry >> 1;
}
_table[i] = entry;
}
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
for(var i = 0; i < len; i++) _hashInt = _hashInt >> 8 ^ _table[data[i] ^ _hashInt & 0xff];
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed);
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var crc32Output = new StringBuilder();
for(var i = 0; i < BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed).Length; i++)
crc32Output.Append(BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed)[i].ToString("x2"));
return crc32Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string File(string filename, out byte[] hash, uint polynomial, uint seed)
{
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
uint localhashInt = seed;
var localTable = new uint[256];
for(var i = 0; i < 256; i++)
{
var entry = (uint)i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry = entry >> 1;
}
localTable[i] = entry;
}
for(var i = 0; i < fileStream.Length; i++)
localhashInt = localhashInt >> 8 ^ localTable[fileStream.ReadByte() ^ localhashInt & 0xff];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc32Output = new StringBuilder();
foreach(byte h in hash) crc32Output.Append(h.ToString("x2"));
fileStream.Close();
return crc32Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string Data(byte[] data, uint len, out byte[] hash, uint polynomial, uint seed)
{
uint localhashInt = seed;
var localTable = new uint[256];
for(var i = 0; i < 256; i++)
{
var entry = (uint)i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry = entry >> 1;
}
localTable[i] = entry;
}
for(var i = 0; i < len; i++) localhashInt = localhashInt >> 8 ^ localTable[data[i] ^ localhashInt & 0xff];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc32Output = new StringBuilder();
foreach(byte h in hash) crc32Output.Append(h.ToString("x2"));
return crc32Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -35,201 +35,204 @@ using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Implements a CRC64 algorithm</summary>
public sealed class Crc64Context : IChecksum
{
/// <summary>Implements a CRC64 algorithm</summary>
public sealed class Crc64Context : IChecksum
public const ulong CRC64_ECMA_POLY = 0xC96C5795D7870F42;
public const ulong CRC64_ECMA_SEED = 0xFFFFFFFFFFFFFFFF;
readonly ulong _finalSeed;
readonly ulong[] _table;
ulong _hashInt;
/// <summary>Initializes the CRC64 table and seed as CRC64-ECMA</summary>
public Crc64Context()
{
public const ulong CRC64_ECMA_POLY = 0xC96C5795D7870F42;
public const ulong CRC64_ECMA_SEED = 0xFFFFFFFFFFFFFFFF;
_hashInt = CRC64_ECMA_SEED;
readonly ulong _finalSeed;
readonly ulong[] _table;
ulong _hashInt;
_table = new ulong[256];
/// <summary>Initializes the CRC64 table and seed as CRC64-ECMA</summary>
public Crc64Context()
for(var i = 0; i < 256; i++)
{
_hashInt = CRC64_ECMA_SEED;
var entry = (ulong)i;
_table = new ulong[256];
for(int i = 0; i < 256; i++)
for(var j = 0; j < 8; j++)
{
ulong entry = (ulong)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ CRC64_ECMA_POLY;
else
entry = entry >> 1;
_table[i] = entry;
if((entry & 1) == 1)
entry = entry >> 1 ^ CRC64_ECMA_POLY;
else
entry = entry >> 1;
}
_finalSeed = CRC64_ECMA_SEED;
_table[i] = entry;
}
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
public Crc64Context(ulong polynomial, ulong seed)
{
_hashInt = seed;
_table = new ulong[256];
for(int i = 0; i < 256; i++)
{
ulong entry = (ulong)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry = entry >> 1;
_table[i] = entry;
}
_finalSeed = seed;
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
for(int i = 0; i < len; i++)
_hashInt = (_hashInt >> 8) ^ _table[data[i] ^ (_hashInt & 0xff)];
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed);
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var crc64Output = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed).Length; i++)
crc64Output.Append(BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed)[i].ToString("x2"));
return crc64Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] localHash);
return localHash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string File(string filename, out byte[] hash, ulong polynomial, ulong seed)
{
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
ulong localhashInt = seed;
ulong[] localTable = new ulong[256];
for(int i = 0; i < 256; i++)
{
ulong entry = (ulong)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry = entry >> 1;
localTable[i] = entry;
}
for(int i = 0; i < fileStream.Length; i++)
localhashInt = (localhashInt >> 8) ^ localTable[(ulong)fileStream.ReadByte() ^ (localhashInt & 0xffL)];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc64Output = new StringBuilder();
foreach(byte h in hash)
crc64Output.Append(h.ToString("x2"));
fileStream.Close();
return crc64Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed)
{
ulong localhashInt = seed;
ulong[] localTable = new ulong[256];
for(int i = 0; i < 256; i++)
{
ulong entry = (ulong)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry = entry >> 1;
localTable[i] = entry;
}
for(int i = 0; i < len; i++)
localhashInt = (localhashInt >> 8) ^ localTable[data[i] ^ (localhashInt & 0xff)];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc64Output = new StringBuilder();
foreach(byte h in hash)
crc64Output.Append(h.ToString("x2"));
return crc64Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
_finalSeed = CRC64_ECMA_SEED;
}
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
public Crc64Context(ulong polynomial, ulong seed)
{
_hashInt = seed;
_table = new ulong[256];
for(var i = 0; i < 256; i++)
{
var entry = (ulong)i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry = entry >> 1;
}
_table[i] = entry;
}
_finalSeed = seed;
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
for(var i = 0; i < len; i++) _hashInt = _hashInt >> 8 ^ _table[data[i] ^ _hashInt & 0xff];
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed);
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var crc64Output = new StringBuilder();
for(var i = 0; i < BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed).Length; i++)
crc64Output.Append(BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed)[i].ToString("x2"));
return crc64Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] localHash);
return localHash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string File(string filename, out byte[] hash, ulong polynomial, ulong seed)
{
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
ulong localhashInt = seed;
var localTable = new ulong[256];
for(var i = 0; i < 256; i++)
{
var entry = (ulong)i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry = entry >> 1;
}
localTable[i] = entry;
}
for(var i = 0; i < fileStream.Length; i++)
localhashInt = localhashInt >> 8 ^ localTable[(ulong)fileStream.ReadByte() ^ localhashInt & 0xffL];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc64Output = new StringBuilder();
foreach(byte h in hash) crc64Output.Append(h.ToString("x2"));
fileStream.Close();
return crc64Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed)
{
ulong localhashInt = seed;
var localTable = new ulong[256];
for(var i = 0; i < 256; i++)
{
var entry = (ulong)i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry = entry >> 1;
}
localTable[i] = entry;
}
for(var i = 0; i < len; i++) localhashInt = localhashInt >> 8 ^ localTable[data[i] ^ localhashInt & 0xff];
localhashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localhashInt);
var crc64Output = new StringBuilder();
foreach(byte h in hash) crc64Output.Append(h.ToString("x2"));
return crc64Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -36,23 +36,22 @@
// Copyright © 2011-2024 Natalia Portillo
// ****************************************************************************/
namespace Aaru.CommonTypes.Interfaces
namespace Aaru.CommonTypes.Interfaces;
public interface IChecksum
{
public interface IChecksum
{
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
void Update(byte[] data, uint len);
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
void Update(byte[] data, uint len);
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
void Update(byte[] data);
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
void Update(byte[] data);
/// <summary>Returns a byte array of the hash value.</summary>
byte[] Final();
/// <summary>Returns a byte array of the hash value.</summary>
byte[] Final();
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
string End();
}
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
string End();
}

View File

@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Wraps up .NET MD5 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Md5Context : IChecksum
{
/// <summary>Wraps up .NET MD5 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Md5Context : IChecksum
readonly MD5 _provider;
/// <summary>Initializes the MD5 hash provider</summary>
public Md5Context() => _provider = MD5.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
readonly MD5 _provider;
_provider.TransformFinalBlock(new byte[0], 0, 0);
/// <summary>Initializes the MD5 hash provider</summary>
public Md5Context() => _provider = MD5.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var md5Output = new StringBuilder();
foreach(byte h in _provider.Hash)
md5Output.Append(h.ToString("x2"));
return md5Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localMd5Provider = MD5.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localMd5Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localMd5Provider = MD5.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localMd5Provider.ComputeHash(fileStream);
var md5Output = new StringBuilder();
foreach(byte h in hash)
md5Output.Append(h.ToString("x2"));
fileStream.Close();
return md5Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localMd5Provider = MD5.Create();
hash = localMd5Provider.ComputeHash(data, 0, (int)len);
var md5Output = new StringBuilder();
foreach(byte h in hash)
md5Output.Append(h.ToString("x2"));
return md5Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var md5Output = new StringBuilder();
foreach(byte h in _provider.Hash) md5Output.Append(h.ToString("x2"));
return md5Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localMd5Provider = MD5.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localMd5Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localMd5Provider = MD5.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localMd5Provider.ComputeHash(fileStream);
var md5Output = new StringBuilder();
foreach(byte h in hash) md5Output.Append(h.ToString("x2"));
fileStream.Close();
return md5Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localMd5Provider = MD5.Create();
hash = localMd5Provider.ComputeHash(data, 0, (int)len);
var md5Output = new StringBuilder();
foreach(byte h in hash) md5Output.Append(h.ToString("x2"));
return md5Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha1Context : IChecksum
{
/// <summary>Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha1Context : IChecksum
readonly SHA1 _provider;
/// <summary>Initializes the SHA1 hash provider</summary>
public Sha1Context() => _provider = SHA1.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
readonly SHA1 _provider;
_provider.TransformFinalBlock(new byte[0], 0, 0);
/// <summary>Initializes the SHA1 hash provider</summary>
public Sha1Context() => _provider = SHA1.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha1Output = new StringBuilder();
foreach(byte h in _provider.Hash)
sha1Output.Append(h.ToString("x2"));
return sha1Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha1Provider = SHA1.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha1Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha1Provider = SHA1.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha1Provider.ComputeHash(fileStream);
var sha1Output = new StringBuilder();
foreach(byte h in hash)
sha1Output.Append(h.ToString("x2"));
fileStream.Close();
return sha1Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha1Provider = SHA1.Create();
hash = localSha1Provider.ComputeHash(data, 0, (int)len);
var sha1Output = new StringBuilder();
foreach(byte h in hash)
sha1Output.Append(h.ToString("x2"));
return sha1Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha1Output = new StringBuilder();
foreach(byte h in _provider.Hash) sha1Output.Append(h.ToString("x2"));
return sha1Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha1Provider = SHA1.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha1Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha1Provider = SHA1.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha1Provider.ComputeHash(fileStream);
var sha1Output = new StringBuilder();
foreach(byte h in hash) sha1Output.Append(h.ToString("x2"));
fileStream.Close();
return sha1Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha1Provider = SHA1.Create();
hash = localSha1Provider.ComputeHash(data, 0, (int)len);
var sha1Output = new StringBuilder();
foreach(byte h in hash) sha1Output.Append(h.ToString("x2"));
return sha1Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha256Context : IChecksum
{
/// <summary>Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha256Context : IChecksum
readonly SHA256 _provider;
/// <summary>Initializes the SHA256 hash provider</summary>
public Sha256Context() => _provider = SHA256.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
readonly SHA256 _provider;
_provider.TransformFinalBlock(new byte[0], 0, 0);
/// <summary>Initializes the SHA256 hash provider</summary>
public Sha256Context() => _provider = SHA256.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha256Output = new StringBuilder();
foreach(byte h in _provider.Hash)
sha256Output.Append(h.ToString("x2"));
return sha256Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha256Provider = SHA256.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha256Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha256Provider = SHA256.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha256Provider.ComputeHash(fileStream);
var sha256Output = new StringBuilder();
foreach(byte h in hash)
sha256Output.Append(h.ToString("x2"));
fileStream.Close();
return sha256Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha256Provider = SHA256.Create();
hash = localSha256Provider.ComputeHash(data, 0, (int)len);
var sha256Output = new StringBuilder();
foreach(byte h in hash)
sha256Output.Append(h.ToString("x2"));
return sha256Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha256Output = new StringBuilder();
foreach(byte h in _provider.Hash) sha256Output.Append(h.ToString("x2"));
return sha256Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha256Provider = SHA256.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha256Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha256Provider = SHA256.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha256Provider.ComputeHash(fileStream);
var sha256Output = new StringBuilder();
foreach(byte h in hash) sha256Output.Append(h.ToString("x2"));
fileStream.Close();
return sha256Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha256Provider = SHA256.Create();
hash = localSha256Provider.ComputeHash(data, 0, (int)len);
var sha256Output = new StringBuilder();
foreach(byte h in hash) sha256Output.Append(h.ToString("x2"));
return sha256Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha384Context : IChecksum
{
/// <summary>Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha384Context : IChecksum
readonly SHA384 _provider;
/// <summary>Initializes the SHA384 hash provider</summary>
public Sha384Context() => _provider = SHA384.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
readonly SHA384 _provider;
_provider.TransformFinalBlock(new byte[0], 0, 0);
/// <summary>Initializes the SHA384 hash provider</summary>
public Sha384Context() => _provider = SHA384.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha384Output = new StringBuilder();
foreach(byte h in _provider.Hash)
sha384Output.Append(h.ToString("x2"));
return sha384Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha384Provider = SHA384.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha384Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha384Provider = SHA384.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha384Provider.ComputeHash(fileStream);
var sha384Output = new StringBuilder();
foreach(byte h in hash)
sha384Output.Append(h.ToString("x2"));
fileStream.Close();
return sha384Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha384Provider = SHA384.Create();
hash = localSha384Provider.ComputeHash(data, 0, (int)len);
var sha384Output = new StringBuilder();
foreach(byte h in hash)
sha384Output.Append(h.ToString("x2"));
return sha384Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha384Output = new StringBuilder();
foreach(byte h in _provider.Hash) sha384Output.Append(h.ToString("x2"));
return sha384Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha384Provider = SHA384.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha384Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha384Provider = SHA384.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha384Provider.ComputeHash(fileStream);
var sha384Output = new StringBuilder();
foreach(byte h in hash) sha384Output.Append(h.ToString("x2"));
fileStream.Close();
return sha384Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha384Provider = SHA384.Create();
hash = localSha384Provider.ComputeHash(data, 0, (int)len);
var sha384Output = new StringBuilder();
foreach(byte h in hash) sha384Output.Append(h.ToString("x2"));
return sha384Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha512Context : IChecksum
{
/// <summary>Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context.</summary>
public sealed class Sha512Context : IChecksum
readonly SHA512 _provider;
/// <summary>Initializes the SHA512 hash provider</summary>
public Sha512Context() => _provider = SHA512.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
readonly SHA512 _provider;
_provider.TransformFinalBlock(new byte[0], 0, 0);
/// <summary>Initializes the SHA512 hash provider</summary>
public Sha512Context() => _provider = SHA512.Create();
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha512Output = new StringBuilder();
foreach(byte h in _provider.Hash)
sha512Output.Append(h.ToString("x2"));
return sha512Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha512Provider = SHA512.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha512Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha512Provider = SHA512.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha512Provider.ComputeHash(fileStream);
var sha512Output = new StringBuilder();
foreach(byte h in hash)
sha512Output.Append(h.ToString("x2"));
fileStream.Close();
return sha512Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha512Provider = SHA512.Create();
hash = localSha512Provider.ComputeHash(data, 0, (int)len);
var sha512Output = new StringBuilder();
foreach(byte h in hash)
sha512Output.Append(h.ToString("x2"));
return sha512Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
return _provider.Hash;
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
_provider.TransformFinalBlock(new byte[0], 0, 0);
var sha512Output = new StringBuilder();
foreach(byte h in _provider.Hash) sha512Output.Append(h.ToString("x2"));
return sha512Output.ToString();
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
var localSha512Provider = SHA512.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
byte[] result = localSha512Provider.ComputeHash(fileStream);
fileStream.Close();
return result;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
var localSha512Provider = SHA512.Create();
var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
hash = localSha512Provider.ComputeHash(fileStream);
var sha512Output = new StringBuilder();
foreach(byte h in hash) sha512Output.Append(h.ToString("x2"));
fileStream.Close();
return sha512Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var localSha512Provider = SHA512.Create();
hash = localSha512Provider.ComputeHash(data, 0, (int)len);
var sha512Output = new StringBuilder();
foreach(byte h in hash) sha512Output.Append(h.ToString("x2"));
return sha512Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -45,283 +45,316 @@ using System.Text;
using Aaru.CommonTypes.Interfaces;
using RomRepoMgr.Core.Resources;
namespace Aaru.Checksums
namespace Aaru.Checksums;
/// <summary>Implements the SpamSum fuzzy hashing algorithm.</summary>
public sealed class SpamSumContext : IChecksum
{
/// <summary>Implements the SpamSum fuzzy hashing algorithm.</summary>
public sealed class SpamSumContext : IChecksum
const uint ROLLING_WINDOW = 7;
const uint MIN_BLOCKSIZE = 3;
const uint HASH_PRIME = 0x01000193;
const uint HASH_INIT = 0x28021967;
const uint NUM_BLOCKHASHES = 31;
const uint SPAMSUM_LENGTH = 64;
const uint FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20;
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
readonly byte[] _b64 =
{
const uint ROLLING_WINDOW = 7;
const uint MIN_BLOCKSIZE = 3;
const uint HASH_PRIME = 0x01000193;
const uint HASH_INIT = 0x28021967;
const uint NUM_BLOCKHASHES = 31;
const uint SPAMSUM_LENGTH = 64;
const uint FUZZY_MAX_RESULT = (2 * SPAMSUM_LENGTH) + 20;
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31,
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F
};
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
readonly byte[] _b64 =
FuzzyState _self;
/// <summary>Initializes the SpamSum structures</summary>
public SpamSumContext()
{
_self = new FuzzyState
{
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31,
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F
Bh = new BlockhashContext[NUM_BLOCKHASHES]
};
FuzzyState _self;
for(var i = 0; i < NUM_BLOCKHASHES; i++) _self.Bh[i].Digest = new byte[SPAMSUM_LENGTH];
/// <summary>Initializes the SpamSum structures</summary>
public SpamSumContext()
_self.Bhstart = 0;
_self.Bhend = 1;
_self.Bh[0].H = HASH_INIT;
_self.Bh[0].Halfh = HASH_INIT;
_self.Bh[0].Digest[0] = 0;
_self.Bh[0].Halfdigest = 0;
_self.Bh[0].Dlen = 0;
_self.TotalSize = 0;
roll_init();
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
_self.TotalSize += len;
for(var i = 0; i < len; i++) fuzzy_engine_step(data[i]);
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final() => throw new NotImplementedException(Localization.Spamsum_no_binary);
/// <inheritdoc />
/// <summary>Returns a base64 representation of the hash value.</summary>
public string End()
{
FuzzyDigest(out byte[] result);
return CToString(result);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void roll_init() => _self.Roll = new RollState
{
Window = new byte[ROLLING_WINDOW]
};
/*
* a rolling hash, based on the Adler checksum. By using a rolling hash
* we can perform auto resynchronisation after inserts/deletes
* internally, h1 is the sum of the bytes in the window and h2
* is the sum of the bytes times the index
* h3 is a shift/xor based rolling hash, and is mostly needed to ensure that
* we can cope with large blocksize values
*/
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void roll_hash(byte c)
{
_self.Roll.H2 -= _self.Roll.H1;
_self.Roll.H2 += ROLLING_WINDOW * c;
_self.Roll.H1 += c;
_self.Roll.H1 -= _self.Roll.Window[_self.Roll.N % ROLLING_WINDOW];
_self.Roll.Window[_self.Roll.N % ROLLING_WINDOW] = c;
_self.Roll.N++;
/* The original spamsum AND'ed this value with 0xFFFFFFFF which
* in theory should have no effect. This AND has been removed
* for performance (jk) */
_self.Roll.H3 <<= 5;
_self.Roll.H3 ^= c;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
uint roll_sum() => _self.Roll.H1 + _self.Roll.H2 + _self.Roll.H3;
/* A simple non-rolling hash, based on the FNV hash. */
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint sum_hash(byte c, uint h) => h * HASH_PRIME ^ c;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_try_fork_blockhash()
{
if(_self.Bhend >= NUM_BLOCKHASHES) return;
if(_self.Bhend == 0) // assert
throw new Exception(Localization.Assertion_failed);
uint obh = _self.Bhend - 1;
uint nbh = _self.Bhend;
_self.Bh[nbh].H = _self.Bh[obh].H;
_self.Bh[nbh].Halfh = _self.Bh[obh].Halfh;
_self.Bh[nbh].Digest[0] = 0;
_self.Bh[nbh].Halfdigest = 0;
_self.Bh[nbh].Dlen = 0;
++_self.Bhend;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_try_reduce_blockhash()
{
if(_self.Bhstart >= _self.Bhend) throw new Exception(Localization.Assertion_failed);
if(_self.Bhend - _self.Bhstart < 2)
/* Need at least two working hashes. */
return;
if((ulong)SSDEEP_BS(_self.Bhstart) * SPAMSUM_LENGTH >= _self.TotalSize)
/* Initial blocksize estimate would select this or a smaller
* blocksize. */
return;
if(_self.Bh[_self.Bhstart + 1].Dlen < SPAMSUM_LENGTH / 2)
/* Estimate adjustment would select this blocksize. */
return;
/* At this point we are clearly no longer interested in the
* start_blocksize. Get rid of it. */
++_self.Bhstart;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_engine_step(byte c)
{
uint i;
/* At each character we update the rolling hash and the normal hashes.
* When the rolling hash hits a reset value then we emit a normal hash
* as a element of the signature and reset the normal hash. */
roll_hash(c);
ulong h = roll_sum();
for(i = _self.Bhstart; i < _self.Bhend; ++i)
{
_self = new FuzzyState
_self.Bh[i].H = sum_hash(c, _self.Bh[i].H);
_self.Bh[i].Halfh = sum_hash(c, _self.Bh[i].Halfh);
}
for(i = _self.Bhstart; i < _self.Bhend; ++i)
{
/* With growing blocksize almost no runs fail the next test. */
if(h % SSDEEP_BS(i) != SSDEEP_BS(i) - 1)
/* Once this condition is false for one bs, it is
* automatically false for all further bs. I.e. if
* h === -1 (mod 2*bs) then h === -1 (mod bs). */
break;
/* We have hit a reset point. We now emit hashes which are
* based on all characters in the piece of the message between
* the last reset point and this one */
if(0 == _self.Bh[i].Dlen) fuzzy_try_fork_blockhash();
_self.Bh[i].Digest[_self.Bh[i].Dlen] = _b64[_self.Bh[i].H % 64];
_self.Bh[i].Halfdigest = _b64[_self.Bh[i].Halfh % 64];
if(_self.Bh[i].Dlen < SPAMSUM_LENGTH - 1)
{
Bh = new BlockhashContext[NUM_BLOCKHASHES]
};
/* We can have a problem with the tail overflowing. The
* easiest way to cope with this is to only reset the
* normal hash if we have room for more characters in
* our signature. This has the effect of combining the
* last few pieces of the message into a single piece
* */
_self.Bh[i].Digest[++_self.Bh[i].Dlen] = 0;
_self.Bh[i].H = HASH_INIT;
for(int i = 0; i < NUM_BLOCKHASHES; i++)
_self.Bh[i].Digest = new byte[SPAMSUM_LENGTH];
if(_self.Bh[i].Dlen >= SPAMSUM_LENGTH / 2) continue;
_self.Bhstart = 0;
_self.Bhend = 1;
_self.Bh[0].H = HASH_INIT;
_self.Bh[0].Halfh = HASH_INIT;
_self.Bh[0].Digest[0] = 0;
_self.Bh[0].Halfdigest = 0;
_self.Bh[0].Dlen = 0;
_self.TotalSize = 0;
roll_init();
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
_self.TotalSize += len;
for(int i = 0; i < len; i++)
fuzzy_engine_step(data[i]);
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final() => throw new NotImplementedException(Localization.Spamsum_no_binary);
/// <inheritdoc />
/// <summary>Returns a base64 representation of the hash value.</summary>
public string End()
{
FuzzyDigest(out byte[] result);
return CToString(result);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void roll_init() => _self.Roll = new RollState
{
Window = new byte[ROLLING_WINDOW]
};
/*
* a rolling hash, based on the Adler checksum. By using a rolling hash
* we can perform auto resynchronisation after inserts/deletes
* internally, h1 is the sum of the bytes in the window and h2
* is the sum of the bytes times the index
* h3 is a shift/xor based rolling hash, and is mostly needed to ensure that
* we can cope with large blocksize values
*/
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void roll_hash(byte c)
{
_self.Roll.H2 -= _self.Roll.H1;
_self.Roll.H2 += ROLLING_WINDOW * c;
_self.Roll.H1 += c;
_self.Roll.H1 -= _self.Roll.Window[_self.Roll.N % ROLLING_WINDOW];
_self.Roll.Window[_self.Roll.N % ROLLING_WINDOW] = c;
_self.Roll.N++;
/* The original spamsum AND'ed this value with 0xFFFFFFFF which
* in theory should have no effect. This AND has been removed
* for performance (jk) */
_self.Roll.H3 <<= 5;
_self.Roll.H3 ^= c;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
uint roll_sum() => _self.Roll.H1 + _self.Roll.H2 + _self.Roll.H3;
/* A simple non-rolling hash, based on the FNV hash. */
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint sum_hash(byte c, uint h) => (h * HASH_PRIME) ^ c;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_try_fork_blockhash()
{
if(_self.Bhend >= NUM_BLOCKHASHES)
return;
if(_self.Bhend == 0) // assert
throw new Exception(Localization.Assertion_failed);
uint obh = _self.Bhend - 1;
uint nbh = _self.Bhend;
_self.Bh[nbh].H = _self.Bh[obh].H;
_self.Bh[nbh].Halfh = _self.Bh[obh].Halfh;
_self.Bh[nbh].Digest[0] = 0;
_self.Bh[nbh].Halfdigest = 0;
_self.Bh[nbh].Dlen = 0;
++_self.Bhend;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_try_reduce_blockhash()
{
if(_self.Bhstart >= _self.Bhend)
throw new Exception(Localization.Assertion_failed);
if(_self.Bhend - _self.Bhstart < 2)
/* Need at least two working hashes. */
return;
if((ulong)SSDEEP_BS(_self.Bhstart) * SPAMSUM_LENGTH >= _self.TotalSize)
/* Initial blocksize estimate would select this or a smaller
* blocksize. */
return;
if(_self.Bh[_self.Bhstart + 1].Dlen < SPAMSUM_LENGTH / 2)
/* Estimate adjustment would select this blocksize. */
return;
/* At this point we are clearly no longer interested in the
* start_blocksize. Get rid of it. */
++_self.Bhstart;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_engine_step(byte c)
{
uint i;
/* At each character we update the rolling hash and the normal hashes.
* When the rolling hash hits a reset value then we emit a normal hash
* as a element of the signature and reset the normal hash. */
roll_hash(c);
ulong h = roll_sum();
for(i = _self.Bhstart; i < _self.Bhend; ++i)
{
_self.Bh[i].H = sum_hash(c, _self.Bh[i].H);
_self.Bh[i].Halfh = sum_hash(c, _self.Bh[i].Halfh);
_self.Bh[i].Halfh = HASH_INIT;
_self.Bh[i].Halfdigest = 0;
}
else
fuzzy_try_reduce_blockhash();
}
}
for(i = _self.Bhstart; i < _self.Bhend; ++i)
// CLAUNIA: Flags seems to never be used in ssdeep, so I just removed it for code simplicity
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void FuzzyDigest(out byte[] result)
{
var sb = new StringBuilder();
uint bi = _self.Bhstart;
uint h = roll_sum();
var remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */
result = new byte[FUZZY_MAX_RESULT];
/* Verify that our elimination was not overeager. */
if(!(bi == 0 || (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH < _self.TotalSize))
throw new Exception(Localization.Assertion_failed);
var resultOff = 0;
/* Initial blocksize guess. */
while((ulong)SSDEEP_BS(bi) * SPAMSUM_LENGTH < _self.TotalSize)
{
++bi;
if(bi >= NUM_BLOCKHASHES) throw new OverflowException(Localization.Spamsum_Input_exceeds_data);
}
/* Adapt blocksize guess to actual digest length. */
while(bi >= _self.Bhend) --bi;
while(bi > _self.Bhstart && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2) --bi;
if(bi > 0 && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2) throw new Exception(Localization.Assertion_failed);
sb.AppendFormat("{0}:", SSDEEP_BS(bi));
int i = Encoding.ASCII.GetBytes(sb.ToString()).Length;
if(i <= 0)
/* Maybe snprintf has set errno here? */
throw new OverflowException(Localization.Spamsum_Input_exceeds_data);
if(i >= remain) throw new Exception(Localization.Assertion_failed);
remain -= i;
Array.Copy(Encoding.ASCII.GetBytes(sb.ToString()), 0, result, 0, i);
resultOff = i;
i = (int)_self.Bh[bi].Dlen;
if(i > remain) throw new Exception(Localization.Assertion_failed);
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
resultOff += i;
remain -= i;
if(h != 0)
{
if(remain <= 0) throw new Exception(Localization.Assertion_failed);
result[resultOff] = _b64[_self.Bh[bi].H % 64];
if(i < 3 ||
result[resultOff] != result[resultOff - 1] ||
result[resultOff] != result[resultOff - 2] ||
result[resultOff] != result[resultOff - 3])
{
/* With growing blocksize almost no runs fail the next test. */
if(h % SSDEEP_BS(i) != SSDEEP_BS(i) - 1)
/* Once this condition is false for one bs, it is
* automatically false for all further bs. I.e. if
* h === -1 (mod 2*bs) then h === -1 (mod bs). */
break;
++resultOff;
--remain;
}
}
else if(_self.Bh[bi].Digest[i] != 0)
{
if(remain <= 0) throw new Exception(Localization.Assertion_failed);
/* We have hit a reset point. We now emit hashes which are
* based on all characters in the piece of the message between
* the last reset point and this one */
if(0 == _self.Bh[i].Dlen)
fuzzy_try_fork_blockhash();
result[resultOff] = _self.Bh[bi].Digest[i];
_self.Bh[i].Digest[_self.Bh[i].Dlen] = _b64[_self.Bh[i].H % 64];
_self.Bh[i].Halfdigest = _b64[_self.Bh[i].Halfh % 64];
if(_self.Bh[i].Dlen < SPAMSUM_LENGTH - 1)
{
/* We can have a problem with the tail overflowing. The
* easiest way to cope with this is to only reset the
* normal hash if we have room for more characters in
* our signature. This has the effect of combining the
* last few pieces of the message into a single piece
* */
_self.Bh[i].Digest[++_self.Bh[i].Dlen] = 0;
_self.Bh[i].H = HASH_INIT;
if(_self.Bh[i].Dlen >= SPAMSUM_LENGTH / 2)
continue;
_self.Bh[i].Halfh = HASH_INIT;
_self.Bh[i].Halfdigest = 0;
}
else
fuzzy_try_reduce_blockhash();
if(i < 3 ||
result[resultOff] != result[resultOff - 1] ||
result[resultOff] != result[resultOff - 2] ||
result[resultOff] != result[resultOff - 3])
{
++resultOff;
--remain;
}
}
// CLAUNIA: Flags seems to never be used in ssdeep, so I just removed it for code simplicity
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void FuzzyDigest(out byte[] result)
if(remain <= 0) throw new Exception(Localization.Assertion_failed);
result[resultOff++] = 0x3A; // ':'
--remain;
if(bi < _self.Bhend - 1)
{
var sb = new StringBuilder();
uint bi = _self.Bhstart;
uint h = roll_sum();
int remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */
result = new byte[FUZZY_MAX_RESULT];
/* Verify that our elimination was not overeager. */
if(!(bi == 0 || ((ulong)SSDEEP_BS(bi) / 2) * SPAMSUM_LENGTH < _self.TotalSize))
throw new Exception(Localization.Assertion_failed);
int resultOff = 0;
/* Initial blocksize guess. */
while((ulong)SSDEEP_BS(bi) * SPAMSUM_LENGTH < _self.TotalSize)
{
++bi;
if(bi >= NUM_BLOCKHASHES)
throw new OverflowException(Localization.Spamsum_Input_exceeds_data);
}
/* Adapt blocksize guess to actual digest length. */
while(bi >= _self.Bhend)
--bi;
while(bi > _self.Bhstart &&
_self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
--bi;
if(bi > 0 &&
_self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
throw new Exception(Localization.Assertion_failed);
sb.AppendFormat("{0}:", SSDEEP_BS(bi));
int i = Encoding.ASCII.GetBytes(sb.ToString()).Length;
if(i <= 0)
/* Maybe snprintf has set errno here? */
throw new OverflowException(Localization.Spamsum_Input_exceeds_data);
if(i >= remain)
throw new Exception(Localization.Assertion_failed);
remain -= i;
Array.Copy(Encoding.ASCII.GetBytes(sb.ToString()), 0, result, 0, i);
resultOff = i;
++bi;
i = (int)_self.Bh[bi].Dlen;
if(i > remain)
throw new Exception(Localization.Assertion_failed);
if(i > remain) throw new Exception(Localization.Assertion_failed);
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
resultOff += i;
@@ -329,10 +362,10 @@ namespace Aaru.Checksums
if(h != 0)
{
if(remain <= 0)
throw new Exception(Localization.Assertion_failed);
if(remain <= 0) throw new Exception(Localization.Assertion_failed);
result[resultOff] = _b64[_self.Bh[bi].H % 64];
h = _self.Bh[bi].Halfh;
result[resultOff] = _b64[h % 64];
if(i < 3 ||
result[resultOff] != result[resultOff - 1] ||
@@ -343,48 +376,15 @@ namespace Aaru.Checksums
--remain;
}
}
else if(_self.Bh[bi].Digest[i] != 0)
else
{
if(remain <= 0)
throw new Exception(Localization.Assertion_failed);
i = _self.Bh[bi].Halfdigest;
result[resultOff] = _self.Bh[bi].Digest[i];
if(i < 3 ||
result[resultOff] != result[resultOff - 1] ||
result[resultOff] != result[resultOff - 2] ||
result[resultOff] != result[resultOff - 3])
if(i != 0)
{
++resultOff;
--remain;
}
}
if(remain <= 0) throw new Exception(Localization.Assertion_failed);
if(remain <= 0)
throw new Exception(Localization.Assertion_failed);
result[resultOff++] = 0x3A; // ':'
--remain;
if(bi < _self.Bhend - 1)
{
++bi;
i = (int)_self.Bh[bi].Dlen;
if(i > remain)
throw new Exception(Localization.Assertion_failed);
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
resultOff += i;
remain -= i;
if(h != 0)
{
if(remain <= 0)
throw new Exception(Localization.Assertion_failed);
h = _self.Bh[bi].Halfh;
result[resultOff] = _b64[h % 64];
result[resultOff] = (byte)i;
if(i < 3 ||
result[resultOff] != result[resultOff - 1] ||
@@ -395,132 +395,108 @@ namespace Aaru.Checksums
--remain;
}
}
else
{
i = _self.Bh[bi].Halfdigest;
if(i != 0)
{
if(remain <= 0)
throw new Exception(Localization.Assertion_failed);
result[resultOff] = (byte)i;
if(i < 3 ||
result[resultOff] != result[resultOff - 1] ||
result[resultOff] != result[resultOff - 2] ||
result[resultOff] != result[resultOff - 3])
{
++resultOff;
--remain;
}
}
}
}
else if(h != 0)
{
if(_self.Bh[bi].Dlen != 0)
throw new Exception(Localization.Assertion_failed);
if(remain <= 0)
throw new Exception(Localization.Assertion_failed);
result[resultOff++] = _b64[_self.Bh[bi].H % 64];
/* No need to bother with FUZZY_FLAG_ELIMSEQ, because this
* digest has length 1. */
--remain;
}
result[resultOff] = 0;
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename) => throw new NotImplementedException(Localization.Spamsum_no_binary);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
throw new NotImplementedException(Localization.Not_yet_implemented);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">null</param>
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
public static string Data(byte[] data, uint len, out byte[] hash)
else if(h != 0)
{
var fuzzyContext = new SpamSumContext();
if(_self.Bh[bi].Dlen != 0) throw new Exception(Localization.Assertion_failed);
fuzzyContext.Update(data, len);
if(remain <= 0) throw new Exception(Localization.Assertion_failed);
hash = null;
return fuzzyContext.End();
result[resultOff++] = _b64[_self.Bh[bi].H % 64];
/* No need to bother with FUZZY_FLAG_ELIMSEQ, because this
* digest has length 1. */
--remain;
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">null</param>
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
result[resultOff] = 0;
}
// Converts an ASCII null-terminated string to .NET string
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static string CToString(byte[] cString)
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename) => throw new NotImplementedException(Localization.Spamsum_no_binary);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
throw new NotImplementedException(Localization.Not_yet_implemented);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">null</param>
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
public static string Data(byte[] data, uint len, out byte[] hash)
{
var fuzzyContext = new SpamSumContext();
fuzzyContext.Update(data, len);
hash = null;
return fuzzyContext.End();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">null</param>
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
// Converts an ASCII null-terminated string to .NET string
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static string CToString(byte[] cString)
{
var count = 0;
// ReSharper disable once LoopCanBeConvertedToQuery
// LINQ is six times slower
foreach(byte c in cString)
{
int count = 0;
if(c == 0) break;
// ReSharper disable once LoopCanBeConvertedToQuery
// LINQ is six times slower
foreach(byte c in cString)
{
if(c == 0)
break;
count++;
}
return Encoding.ASCII.GetString(cString, 0, count);
count++;
}
struct RollState
{
public byte[] Window;
return Encoding.ASCII.GetString(cString, 0, count);
}
// ROLLING_WINDOW
public uint H1;
public uint H2;
public uint H3;
public uint N;
}
struct RollState
{
public byte[] Window;
/* A blockhash contains a signature state for a specific (implicit) blocksize.
* The blocksize is given by SSDEEP_BS(index). The h and halfh members are the
* FNV hashes, where halfh stops to be reset after digest is SPAMSUM_LENGTH/2
* long. The halfh hash is needed be able to truncate digest for the second
* output hash to stay compatible with ssdeep output. */
struct BlockhashContext
{
public uint H;
public uint Halfh;
public byte[] Digest;
// ROLLING_WINDOW
public uint H1;
public uint H2;
public uint H3;
public uint N;
}
// SPAMSUM_LENGTH
public byte Halfdigest;
public uint Dlen;
}
/* A blockhash contains a signature state for a specific (implicit) blocksize.
* The blocksize is given by SSDEEP_BS(index). The h and halfh members are the
* FNV hashes, where halfh stops to be reset after digest is SPAMSUM_LENGTH/2
* long. The halfh hash is needed be able to truncate digest for the second
* output hash to stay compatible with ssdeep output. */
struct BlockhashContext
{
public uint H;
public uint Halfh;
public byte[] Digest;
struct FuzzyState
{
public uint Bhstart;
public uint Bhend;
public BlockhashContext[] Bh;
// SPAMSUM_LENGTH
public byte Halfdigest;
public uint Dlen;
}
//NUM_BLOCKHASHES
public ulong TotalSize;
public RollState Roll;
}
struct FuzzyState
{
public uint Bhstart;
public uint Bhend;
public BlockhashContext[] Bh;
//NUM_BLOCKHASHES
public ulong TotalSize;
public RollState Roll;
}
}

View File

@@ -23,10 +23,9 @@
// Copyright © 2020-2024 Natalia Portillo
*******************************************************************************/
namespace RomRepoMgr.Core.EventArgs
namespace RomRepoMgr.Core.EventArgs;
public sealed class ErrorEventArgs : System.EventArgs
{
public sealed class ErrorEventArgs : System.EventArgs
{
public string Message { get; set; }
}
public string Message { get; set; }
}

View File

@@ -25,10 +25,9 @@
using RomRepoMgr.Core.Models;
namespace RomRepoMgr.Core.EventArgs
namespace RomRepoMgr.Core.EventArgs;
public sealed class ImportedRomItemEventArgs : System.EventArgs
{
public sealed class ImportedRomItemEventArgs : System.EventArgs
{
public ImportRomItem Item { get; set; }
}
public ImportRomItem Item { get; set; }
}

View File

@@ -23,10 +23,9 @@
// Copyright © 2020-2024 Natalia Portillo
*******************************************************************************/
namespace RomRepoMgr.Core.EventArgs
namespace RomRepoMgr.Core.EventArgs;
public sealed class MessageEventArgs : System.EventArgs
{
public sealed class MessageEventArgs : System.EventArgs
{
public string Message { get; set; }
}
public string Message { get; set; }
}

View File

@@ -23,11 +23,10 @@
// Copyright © 2020-2024 Natalia Portillo
*******************************************************************************/
namespace RomRepoMgr.Core.EventArgs
namespace RomRepoMgr.Core.EventArgs;
public sealed class ProgressBoundsEventArgs : System.EventArgs
{
public sealed class ProgressBoundsEventArgs : System.EventArgs
{
public double Minimum { get; set; }
public double Maximum { get; set; }
}
public double Minimum { get; set; }
public double Maximum { get; set; }
}

View File

@@ -23,10 +23,9 @@
// Copyright © 2020-2024 Natalia Portillo
*******************************************************************************/
namespace RomRepoMgr.Core.EventArgs
namespace RomRepoMgr.Core.EventArgs;
public sealed class ProgressEventArgs : System.EventArgs
{
public sealed class ProgressEventArgs : System.EventArgs
{
public double Value { get; set; }
}
public double Value { get; set; }
}

View File

@@ -25,10 +25,9 @@
using RomRepoMgr.Core.Models;
namespace RomRepoMgr.Core.EventArgs
namespace RomRepoMgr.Core.EventArgs;
public sealed class RomSetEventArgs : System.EventArgs
{
public sealed class RomSetEventArgs : System.EventArgs
{
public RomSetModel RomSet { get; set; }
}
public RomSetModel RomSet { get; set; }
}

View File

@@ -26,10 +26,9 @@
using System.Collections.Generic;
using RomRepoMgr.Core.Models;
namespace RomRepoMgr.Core.EventArgs
namespace RomRepoMgr.Core.EventArgs;
public sealed class RomSetsEventArgs : System.EventArgs
{
public sealed class RomSetsEventArgs : System.EventArgs
{
public List<RomSetModel> RomSets { get; set; }
}
public List<RomSetModel> RomSets { get; set; }
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -34,173 +34,165 @@ using System;
using System.IO;
using RomRepoMgr.Core.Resources;
namespace RomRepoMgr.Core
namespace RomRepoMgr.Core;
/// <inheritdoc />
/// <summary>
/// ForcedSeekStream allows to seek a forward-readable stream (like System.IO.Compression streams) by doing the
/// slow and known trick of rewinding and forward reading until arriving the desired position.
/// </summary>
internal sealed class ForcedSeekStream<T> : Stream where T : Stream
{
const int BUFFER_LEN = 1048576;
readonly string _backFile;
readonly FileStream _backStream;
readonly T _baseStream;
long _streamLength;
/// <inheritdoc />
/// <summary>
/// ForcedSeekStream allows to seek a forward-readable stream (like System.IO.Compression streams) by doing the
/// slow and known trick of rewinding and forward reading until arriving the desired position.
/// </summary>
internal sealed class ForcedSeekStream<T> : Stream where T : Stream
/// <summary>Initializes a new instance of the <see cref="T:RomRepoMgr.Core.ForcedSeekStream`1" /> class.</summary>
/// <param name="length">The real (uncompressed) length of the stream.</param>
/// <param name="args">Parameters that are used to create the base stream.</param>
public ForcedSeekStream(long length, params object[] args)
{
const int BUFFER_LEN = 1048576;
readonly string _backFile;
readonly FileStream _backStream;
readonly T _baseStream;
long _streamLength;
_streamLength = length;
_baseStream = (T)Activator.CreateInstance(typeof(T), args);
_backFile = Path.GetTempFileName();
_backStream = new FileStream(_backFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
/// <inheritdoc />
/// <summary>Initializes a new instance of the <see cref="T:RomRepoMgr.Core.ForcedSeekStream`1" /> class.</summary>
/// <param name="length">The real (uncompressed) length of the stream.</param>
/// <param name="args">Parameters that are used to create the base stream.</param>
public ForcedSeekStream(long length, params object[] args)
if(length == 0) CalculateLength();
}
public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => true;
public override bool CanWrite => false;
public override long Length => _streamLength;
public override long Position
{
get => _backStream.Position;
set => SetPosition(value);
}
/// <summary>
/// Calculates the real (uncompressed) length of the stream. It basically reads (decompresses) the whole stream to
/// memory discarding its contents, so it should be used as a last resort.
/// </summary>
/// <returns>The length.</returns>
void CalculateLength()
{
int read;
do
{
_streamLength = length;
_baseStream = (T)Activator.CreateInstance(typeof(T), args);
_backFile = Path.GetTempFileName();
_backStream = new FileStream(_backFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
var buffer = new byte[BUFFER_LEN];
read = _baseStream.Read(buffer, 0, BUFFER_LEN);
_backStream.Write(buffer, 0, read);
} while(read == BUFFER_LEN);
if(length == 0)
CalculateLength();
_streamLength = _backStream.Length;
_backStream.Position = 0;
}
void SetPosition(long position)
{
if(position == _backStream.Position) return;
if(position < _backStream.Length)
{
_backStream.Position = position;
return;
}
public override bool CanRead => _baseStream.CanRead;
_backStream.Position = _backStream.Length;
long toPosition = position - _backStream.Position;
var fullBufferReads = (int)(toPosition / BUFFER_LEN);
var restToRead = (int)(toPosition % BUFFER_LEN);
byte[] buffer;
public override bool CanSeek => true;
public override bool CanWrite => false;
public override long Length => _streamLength;
public override long Position
for(var i = 0; i < fullBufferReads; i++)
{
get => _backStream.Position;
set => SetPosition(value);
buffer = new byte[BUFFER_LEN];
_baseStream.Read(buffer, 0, BUFFER_LEN);
_backStream.Write(buffer, 0, BUFFER_LEN);
}
/// <summary>
/// Calculates the real (uncompressed) length of the stream. It basically reads (decompresses) the whole stream to
/// memory discarding its contents, so it should be used as a last resort.
/// </summary>
/// <returns>The length.</returns>
void CalculateLength()
buffer = new byte[restToRead];
_baseStream.Read(buffer, 0, restToRead);
_backStream.Write(buffer, 0, restToRead);
}
public override void Flush()
{
_baseStream.Flush();
_backStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
if(_backStream.Position + count <= _backStream.Length) return _backStream.Read(buffer, offset, count);
SetPosition(_backStream.Position + count);
SetPosition(_backStream.Position - count);
return _backStream.Read(buffer, offset, count);
}
public override int ReadByte()
{
if(_backStream.Position + 1 <= _backStream.Length) return _backStream.ReadByte();
SetPosition(_backStream.Position + 1);
SetPosition(_backStream.Position - 1);
return _backStream.ReadByte();
}
public override long Seek(long offset, SeekOrigin origin)
{
switch(origin)
{
int read;
case SeekOrigin.Begin:
if(offset < 0) throw new IOException(Localization.Cannot_seek_before_start);
do
{
byte[] buffer = new byte[BUFFER_LEN];
read = _baseStream.Read(buffer, 0, BUFFER_LEN);
_backStream.Write(buffer, 0, read);
} while(read == BUFFER_LEN);
SetPosition(offset);
_streamLength = _backStream.Length;
_backStream.Position = 0;
break;
case SeekOrigin.End:
if(offset > 0) throw new IOException(Localization.Cannot_seek_after_end);
if(_streamLength == 0) CalculateLength();
SetPosition(_streamLength + offset);
break;
default:
SetPosition(_backStream.Position + offset);
break;
}
void SetPosition(long position)
{
if(position == _backStream.Position)
return;
return _backStream.Position;
}
if(position < _backStream.Length)
{
_backStream.Position = position;
public override void SetLength(long value) => throw new NotSupportedException();
return;
}
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
_backStream.Position = _backStream.Length;
long toPosition = position - _backStream.Position;
int fullBufferReads = (int)(toPosition / BUFFER_LEN);
int restToRead = (int)(toPosition % BUFFER_LEN);
byte[] buffer;
public override void Close()
{
_backStream?.Close();
File.Delete(_backFile);
}
for(int i = 0; i < fullBufferReads; i++)
{
buffer = new byte[BUFFER_LEN];
_baseStream.Read(buffer, 0, BUFFER_LEN);
_backStream.Write(buffer, 0, BUFFER_LEN);
}
buffer = new byte[restToRead];
_baseStream.Read(buffer, 0, restToRead);
_backStream.Write(buffer, 0, restToRead);
}
public override void Flush()
{
_baseStream.Flush();
_backStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
if(_backStream.Position + count <= _backStream.Length)
return _backStream.Read(buffer, offset, count);
SetPosition(_backStream.Position + count);
SetPosition(_backStream.Position - count);
return _backStream.Read(buffer, offset, count);
}
public override int ReadByte()
{
if(_backStream.Position + 1 <= _backStream.Length)
return _backStream.ReadByte();
SetPosition(_backStream.Position + 1);
SetPosition(_backStream.Position - 1);
return _backStream.ReadByte();
}
public override long Seek(long offset, SeekOrigin origin)
{
switch(origin)
{
case SeekOrigin.Begin:
if(offset < 0)
throw new IOException(Localization.Cannot_seek_before_start);
SetPosition(offset);
break;
case SeekOrigin.End:
if(offset > 0)
throw new IOException(Localization.Cannot_seek_after_end);
if(_streamLength == 0)
CalculateLength();
SetPosition(_streamLength + offset);
break;
default:
SetPosition(_backStream.Position + offset);
break;
}
return _backStream.Position;
}
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override void Close()
{
_backStream?.Close();
File.Delete(_backFile);
}
~ForcedSeekStream()
{
_backStream?.Close();
File.Delete(_backFile);
}
~ForcedSeekStream()
{
_backStream?.Close();
File.Delete(_backFile);
}
}

View File

@@ -23,11 +23,10 @@
// Copyright © 2020-2024 Natalia Portillo
*******************************************************************************/
namespace RomRepoMgr.Core.Models
namespace RomRepoMgr.Core.Models;
public sealed class AssemblyModel
{
public sealed class AssemblyModel
{
public string Name { get; set; }
public string Version { get; set; }
}
public string Name { get; set; }
public string Version { get; set; }
}

View File

@@ -23,11 +23,10 @@
// Copyright © 2020-2024 Natalia Portillo
*******************************************************************************/
namespace RomRepoMgr.Core.Models
namespace RomRepoMgr.Core.Models;
public sealed class ImportRomItem
{
public sealed class ImportRomItem
{
public string Filename { get; set; }
public string Status { get; set; }
}
public string Filename { get; set; }
public string Status { get; set; }
}

View File

@@ -23,26 +23,25 @@
// Copyright © 2020-2024 Natalia Portillo
*******************************************************************************/
namespace RomRepoMgr.Core.Models
namespace RomRepoMgr.Core.Models;
public class RomSetModel
{
public class RomSetModel
{
public string Author { get; set; }
public string Comment { get; set; }
public string Date { get; set; }
public string Description { get; set; }
public string Homepage { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public string Filename { get; set; }
public string Sha384 { get; set; }
public long TotalMachines { get; set; }
public long CompleteMachines { get; set; }
public long IncompleteMachines { get; set; }
public long TotalRoms { get; set; }
public long HaveRoms { get; set; }
public long MissRoms { get; set; }
public long Id { get; set; }
public string Category { get; set; }
}
public string Author { get; set; }
public string Comment { get; set; }
public string Date { get; set; }
public string Description { get; set; }
public string Homepage { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public string Filename { get; set; }
public string Sha384 { get; set; }
public long TotalMachines { get; set; }
public long CompleteMachines { get; set; }
public long IncompleteMachines { get; set; }
public long TotalRoms { get; set; }
public long HaveRoms { get; set; }
public long MissRoms { get; set; }
public long Id { get; set; }
public string Category { get; set; }
}

View File

@@ -11,32 +11,46 @@ namespace RomRepoMgr.Core.Resources {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Localization {
private static System.Resources.ResourceManager resourceMan;
private static global::System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
private static global::System.Globalization.CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Localization() {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager {
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("RomRepoMgr.Core.Resources.Localization", typeof(Localization).Assembly);
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RomRepoMgr.Core.Resources.Localization", typeof(Localization).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture {
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
@@ -45,351 +59,525 @@ namespace RomRepoMgr.Core.Resources {
}
}
internal static string Base32_Not_enought_data {
get {
return ResourceManager.GetString("Base32_Not_enought_data", resourceCulture);
}
}
internal static string Base32_Invalid_format {
get {
return ResourceManager.GetString("Base32_Invalid_format", resourceCulture);
}
}
internal static string Cannot_seek_before_start {
get {
return ResourceManager.GetString("Cannot_seek_before_start", resourceCulture);
}
}
internal static string Cannot_seek_after_end {
get {
return ResourceManager.GetString("Cannot_seek_after_end", resourceCulture);
}
}
internal static string Spamsum_no_binary {
get {
return ResourceManager.GetString("Spamsum_no_binary", resourceCulture);
}
}
internal static string Assertion_failed {
get {
return ResourceManager.GetString("Assertion_failed", resourceCulture);
}
}
internal static string Spamsum_Input_exceeds_data {
get {
return ResourceManager.GetString("Spamsum_Input_exceeds_data", resourceCulture);
}
}
internal static string Not_yet_implemented {
get {
return ResourceManager.GetString("Not_yet_implemented", resourceCulture);
}
}
internal static string DatabaseFileExistsMsgBoxTitle {
get {
return ResourceManager.GetString("DatabaseFileExistsMsgBoxTitle", resourceCulture);
}
}
internal static string UnArPathNotSet {
get {
return ResourceManager.GetString("UnArPathNotSet", resourceCulture);
}
}
internal static string CannotFindUnArAtPath {
get {
return ResourceManager.GetString("CannotFindUnArAtPath", resourceCulture);
}
}
internal static string CannotFindLsAr {
get {
return ResourceManager.GetString("CannotFindLsAr", resourceCulture);
}
}
internal static string CannotRunUnAr {
get {
return ResourceManager.GetString("CannotRunUnAr", resourceCulture);
}
}
internal static string CannotRunLsAr {
get {
return ResourceManager.GetString("CannotRunLsAr", resourceCulture);
}
}
internal static string NotCorrectUnAr {
get {
return ResourceManager.GetString("NotCorrectUnAr", resourceCulture);
}
}
internal static string NotCorrectLsAr {
get {
return ResourceManager.GetString("NotCorrectLsAr", resourceCulture);
}
}
internal static string ParsinDatFile {
get {
return ResourceManager.GetString("ParsinDatFile", resourceCulture);
}
}
internal static string HashingDatFile {
get {
return ResourceManager.GetString("HashingDatFile", resourceCulture);
}
}
internal static string DatAlreadyInDatabase {
get {
return ResourceManager.GetString("DatAlreadyInDatabase", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Adding DAT to database....
/// </summary>
internal static string AddingDatToDatabase {
get {
return ResourceManager.GetString("AddingDatToDatabase", resourceCulture);
}
}
internal static string CompressingDatFile {
get {
return ResourceManager.GetString("CompressingDatFile", resourceCulture);
}
}
internal static string GettingMachineNames {
get {
return ResourceManager.GetString("GettingMachineNames", resourceCulture);
}
}
internal static string AddingMachines {
get {
return ResourceManager.GetString("AddingMachines", resourceCulture);
}
}
internal static string SavingChangesToDatabase {
get {
return ResourceManager.GetString("SavingChangesToDatabase", resourceCulture);
}
}
internal static string RetrievingRomsAndDisks {
get {
return ResourceManager.GetString("RetrievingRomsAndDisks", resourceCulture);
}
}
internal static string AddingRoms {
get {
return ResourceManager.GetString("AddingRoms", resourceCulture);
}
}
internal static string FoundRomWithoutMachine {
get {
return ResourceManager.GetString("FoundRomWithoutMachine", resourceCulture);
}
}
internal static string UnhandledException {
get {
return ResourceManager.GetString("UnhandledException", resourceCulture);
}
}
internal static string RetrievingRomSetFromDatabase {
get {
return ResourceManager.GetString("RetrievingRomSetFromDatabase", resourceCulture);
}
}
internal static string CouldNotFindRomSetInDatabase {
get {
return ResourceManager.GetString("CouldNotFindRomSetInDatabase", resourceCulture);
}
}
internal static string ExportingRoms {
get {
return ResourceManager.GetString("ExportingRoms", resourceCulture);
}
}
internal static string Finished {
get {
return ResourceManager.GetString("Finished", resourceCulture);
}
}
internal static string CannotFindZipEntryInDictionary {
get {
return ResourceManager.GetString("CannotFindZipEntryInDictionary", resourceCulture);
}
}
internal static string CannotFindHashInRepository {
get {
return ResourceManager.GetString("CannotFindHashInRepository", resourceCulture);
}
}
internal static string Compressing {
get {
return ResourceManager.GetString("Compressing", resourceCulture);
}
}
internal static string EnumeratingFiles {
get {
return ResourceManager.GetString("EnumeratingFiles", resourceCulture);
}
}
internal static string Importing {
get {
return ResourceManager.GetString("Importing", resourceCulture);
}
}
internal static string CheckingIfFIleIsAnArchive {
get {
return ResourceManager.GetString("CheckingIfFIleIsAnArchive", resourceCulture);
}
}
internal static string OK {
get {
return ResourceManager.GetString("OK", resourceCulture);
}
}
internal static string ErrorWithMessage {
get {
return ResourceManager.GetString("ErrorWithMessage", resourceCulture);
}
}
internal static string ExtractingArchive {
get {
return ResourceManager.GetString("ExtractingArchive", resourceCulture);
}
}
internal static string RemovingTemporaryPath {
get {
return ResourceManager.GetString("RemovingTemporaryPath", resourceCulture);
}
}
internal static string ExtractedContents {
get {
return ResourceManager.GetString("ExtractedContents", resourceCulture);
}
}
internal static string HashingFile {
get {
return ResourceManager.GetString("HashingFile", resourceCulture);
}
}
internal static string UnknownFile {
get {
return ResourceManager.GetString("UnknownFile", resourceCulture);
}
}
internal static string CompressingFile {
get {
return ResourceManager.GetString("CompressingFile", resourceCulture);
}
}
internal static string Finishing {
get {
return ResourceManager.GetString("Finishing", resourceCulture);
}
}
internal static string UnhandledExceptionWhenImporting {
get {
return ResourceManager.GetString("UnhandledExceptionWhenImporting", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Adding disks....
/// </summary>
internal static string AddingDisks {
get {
return ResourceManager.GetString("AddingDisks", resourceCulture);
}
}
internal static string FoundDiskWithoutMachine {
/// <summary>
/// Looks up a localized string similar to Adding machines (games)....
/// </summary>
internal static string AddingMachines {
get {
return ResourceManager.GetString("FoundDiskWithoutMachine", resourceCulture);
}
}
internal static string NotAChdFile {
get {
return ResourceManager.GetString("NotAChdFile", resourceCulture);
}
}
internal static string NoChecksumsFound {
get {
return ResourceManager.GetString("NoChecksumsFound", resourceCulture);
}
}
internal static string Copying {
get {
return ResourceManager.GetString("Copying", resourceCulture);
}
}
internal static string CopyingFile {
get {
return ResourceManager.GetString("CopyingFile", resourceCulture);
return ResourceManager.GetString("AddingMachines", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Adding medias....
/// </summary>
internal static string AddingMedias {
get {
return ResourceManager.GetString("AddingMedias", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Adding ROMs....
/// </summary>
internal static string AddingRoms {
get {
return ResourceManager.GetString("AddingRoms", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Assertion failed.
/// </summary>
internal static string Assertion_failed {
get {
return ResourceManager.GetString("Assertion_failed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Specified string is not valid Base32 format because character &quot;{0}&quot; does not exist in Base32 alphabet.
/// </summary>
internal static string Base32_Invalid_format {
get {
return ResourceManager.GetString("Base32_Invalid_format", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Specified string is not valid Base32 format because it doesn&apos;t have enough data to construct a complete byte array.
/// </summary>
internal static string Base32_Not_enought_data {
get {
return ResourceManager.GetString("Base32_Not_enought_data", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot seek after stream end..
/// </summary>
internal static string Cannot_seek_after_end {
get {
return ResourceManager.GetString("Cannot_seek_after_end", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot seek before stream start..
/// </summary>
internal static string Cannot_seek_before_start {
get {
return ResourceManager.GetString("Cannot_seek_before_start", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot find file with hash {0} in the repository.
/// </summary>
internal static string CannotFindHashInRepository {
get {
return ResourceManager.GetString("CannotFindHashInRepository", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot find lsar executable..
/// </summary>
internal static string CannotFindLsAr {
get {
return ResourceManager.GetString("CannotFindLsAr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot find unar executable at {0}..
/// </summary>
internal static string CannotFindUnArAtPath {
get {
return ResourceManager.GetString("CannotFindUnArAtPath", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot find requested zip entry in hashes dictionary.
/// </summary>
internal static string CannotFindZipEntryInDictionary {
get {
return ResourceManager.GetString("CannotFindZipEntryInDictionary", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot run lsar..
/// </summary>
internal static string CannotRunLsAr {
get {
return ResourceManager.GetString("CannotRunLsAr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot run unar..
/// </summary>
internal static string CannotRunUnAr {
get {
return ResourceManager.GetString("CannotRunUnAr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Checking if file is an archive....
/// </summary>
internal static string CheckingIfFIleIsAnArchive {
get {
return ResourceManager.GetString("CheckingIfFIleIsAnArchive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Compressing {0}....
/// </summary>
internal static string Compressing {
get {
return ResourceManager.GetString("Compressing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Compressing DAT file....
/// </summary>
internal static string CompressingDatFile {
get {
return ResourceManager.GetString("CompressingDatFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Compressing file....
/// </summary>
internal static string CompressingFile {
get {
return ResourceManager.GetString("CompressingFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copying {0}....
/// </summary>
internal static string Copying {
get {
return ResourceManager.GetString("Copying", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copying file....
/// </summary>
internal static string CopyingFile {
get {
return ResourceManager.GetString("CopyingFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not find ROM set in database..
/// </summary>
internal static string CouldNotFindRomSetInDatabase {
get {
return ResourceManager.GetString("CouldNotFindRomSetInDatabase", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to File exists.
/// </summary>
internal static string DatabaseFileExistsMsgBoxTitle {
get {
return ResourceManager.GetString("DatabaseFileExistsMsgBoxTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to DAT file is already in database, not importing duplicates..
/// </summary>
internal static string DatAlreadyInDatabase {
get {
return ResourceManager.GetString("DatAlreadyInDatabase", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Imported {0} machines with {1} ROMs..
/// </summary>
internal static string DatImportSuccess {
get {
return ResourceManager.GetString("DatImportSuccess", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Enumerating files....
/// </summary>
internal static string EnumeratingFiles {
get {
return ResourceManager.GetString("EnumeratingFiles", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: {0}.
/// </summary>
internal static string ErrorWithMessage {
get {
return ResourceManager.GetString("ErrorWithMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Exporting ROMs....
/// </summary>
internal static string ExportingRoms {
get {
return ResourceManager.GetString("ExportingRoms", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extracted contents.
/// </summary>
internal static string ExtractedContents {
get {
return ResourceManager.GetString("ExtractedContents", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extracting archive contents....
/// </summary>
internal static string ExtractingArchive {
get {
return ResourceManager.GetString("ExtractingArchive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Finished.
/// </summary>
internal static string Finished {
get {
return ResourceManager.GetString("Finished", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Finishing....
/// </summary>
internal static string Finishing {
get {
return ResourceManager.GetString("Finishing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Found a disk with an unknown machine, this should not happen..
/// </summary>
internal static string FoundDiskWithoutMachine {
get {
return ResourceManager.GetString("FoundDiskWithoutMachine", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Found media with an unknown machine, this should not happen..
/// </summary>
internal static string FoundMediaWithoutMachine {
get {
return ResourceManager.GetString("FoundMediaWithoutMachine", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Found a ROM with an unknown machine, this should not happen..
/// </summary>
internal static string FoundRomWithoutMachine {
get {
return ResourceManager.GetString("FoundRomWithoutMachine", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Getting machine (game) names....
/// </summary>
internal static string GettingMachineNames {
get {
return ResourceManager.GetString("GettingMachineNames", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Hashing DAT file....
/// </summary>
internal static string HashingDatFile {
get {
return ResourceManager.GetString("HashingDatFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Hashing file....
/// </summary>
internal static string HashingFile {
get {
return ResourceManager.GetString("HashingFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Importing {0}....
/// </summary>
internal static string Importing {
get {
return ResourceManager.GetString("Importing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No checksums found..
/// </summary>
internal static string NoChecksumsFound {
get {
return ResourceManager.GetString("NoChecksumsFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not yet implemented..
/// </summary>
internal static string Not_yet_implemented {
get {
return ResourceManager.GetString("Not_yet_implemented", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not a CHD file..
/// </summary>
internal static string NotAChdFile {
get {
return ResourceManager.GetString("NotAChdFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not an AaruFormat file..
/// </summary>
internal static string NotAnAaruFormatFile {
get {
return ResourceManager.GetString("NotAnAaruFormatFile", resourceCulture);
}
}
internal static string DatImportSuccess {
/// <summary>
/// Looks up a localized string similar to Not the correct lsar executable.
/// </summary>
internal static string NotCorrectLsAr {
get {
return ResourceManager.GetString("DatImportSuccess", resourceCulture);
return ResourceManager.GetString("NotCorrectLsAr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not the correct unar executable.
/// </summary>
internal static string NotCorrectUnAr {
get {
return ResourceManager.GetString("NotCorrectUnAr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OK.
/// </summary>
internal static string OK {
get {
return ResourceManager.GetString("OK", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Parsing DAT file....
/// </summary>
internal static string ParsinDatFile {
get {
return ResourceManager.GetString("ParsinDatFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Removing temporary path....
/// </summary>
internal static string RemovingTemporaryPath {
get {
return ResourceManager.GetString("RemovingTemporaryPath", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Retrieving ROMs and disks....
/// </summary>
internal static string RetrievingRomsAndDisks {
get {
return ResourceManager.GetString("RetrievingRomsAndDisks", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Retrieving ROM set from database..
/// </summary>
internal static string RetrievingRomSetFromDatabase {
get {
return ResourceManager.GetString("RetrievingRomSetFromDatabase", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Saving changes to database....
/// </summary>
internal static string SavingChangesToDatabase {
get {
return ResourceManager.GetString("SavingChangesToDatabase", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The input exceeds data types..
/// </summary>
internal static string Spamsum_Input_exceeds_data {
get {
return ResourceManager.GetString("Spamsum_Input_exceeds_data", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to SpamSum does not have a binary representation..
/// </summary>
internal static string Spamsum_no_binary {
get {
return ResourceManager.GetString("Spamsum_no_binary", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to unar path is not set..
/// </summary>
internal static string UnArPathNotSet {
get {
return ResourceManager.GetString("UnArPathNotSet", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unhandled exception occurred..
/// </summary>
internal static string UnhandledException {
get {
return ResourceManager.GetString("UnhandledException", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unhandled exception when importing file..
/// </summary>
internal static string UnhandledExceptionWhenImporting {
get {
return ResourceManager.GetString("UnhandledExceptionWhenImporting", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unknown file..
/// </summary>
internal static string UnknownFile {
get {
return ResourceManager.GetString("UnknownFile", resourceCulture);
}
}
}

View File

@@ -1,185 +1,189 @@
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AddingDatToDatabase" xml:space="preserve">
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="AddingDatToDatabase" xml:space="preserve">
<value>Añadiendo DAT a la base de datos...</value>
</data>
<data name="AddingMachines" xml:space="preserve">
<data name="AddingMachines" xml:space="preserve">
<value>Añadiendo máquinas (juegos)...</value>
</data>
<data name="AddingRoms" xml:space="preserve">
<data name="AddingRoms" xml:space="preserve">
<value>Añadiendo ROMs...</value>
</data>
<data name="Assertion_failed" xml:space="preserve">
<data name="Assertion_failed" xml:space="preserve">
<value>Aserción fallida</value>
</data>
<data name="Base32_Invalid_format" xml:space="preserve">
<data name="Base32_Invalid_format" xml:space="preserve">
<value>El texto especificado no tiene un formato Base32 válido porque el caracter "{0}" no existe en el alfabeto Base32</value>
</data>
<data name="Base32_Not_enought_data" xml:space="preserve">
<data name="Base32_Not_enought_data" xml:space="preserve">
<value>El texto especificado no tiene un formato Base32 válido porque no tiene datos suficientes para completar una ristra de bytes</value>
</data>
<data name="CannotFindHashInRepository" xml:space="preserve">
<data name="CannotFindHashInRepository" xml:space="preserve">
<value>No se puede encontrar el archivo con hash {0} en el repositorio</value>
</data>
<data name="CannotFindLsAr" xml:space="preserve">
<data name="CannotFindLsAr" xml:space="preserve">
<value>No se puede encontrar el ejecutable lsar.</value>
</data>
<data name="CannotFindUnArAtPath" xml:space="preserve">
<data name="CannotFindUnArAtPath" xml:space="preserve">
<value>No se puede encontrar el ejecutable unar en {0}.</value>
</data>
<data name="CannotFindZipEntryInDictionary" xml:space="preserve">
<data name="CannotFindZipEntryInDictionary" xml:space="preserve">
<value>No se puede encontrar la entrada zip solicitada en el diccionari de hashes</value>
</data>
<data name="CannotRunLsAr" xml:space="preserve">
<data name="CannotRunLsAr" xml:space="preserve">
<value>No se puede ejecutar lsar.</value>
</data>
<data name="CannotRunUnAr" xml:space="preserve">
<data name="CannotRunUnAr" xml:space="preserve">
<value>No se puede ejecutar unar.</value>
</data>
<data name="Cannot_seek_after_end" xml:space="preserve">
<data name="Cannot_seek_after_end" xml:space="preserve">
<value>No se puede posicionar antes del comienzo.</value>
</data>
<data name="Cannot_seek_before_start" xml:space="preserve">
<data name="Cannot_seek_before_start" xml:space="preserve">
<value>No se puede posicionar después del comienzo.</value>
</data>
<data name="CheckingIfFIleIsAnArchive" xml:space="preserve">
<data name="CheckingIfFIleIsAnArchive" xml:space="preserve">
<value>Comprobando si el fichero es un archivo comprimido...</value>
</data>
<data name="Compressing" xml:space="preserve">
<data name="Compressing" xml:space="preserve">
<value>Comprimiendo {0}...</value>
</data>
<data name="CompressingDatFile" xml:space="preserve">
<data name="CompressingDatFile" xml:space="preserve">
<value>Comprimiendo archivo DAT...</value>
</data>
<data name="CompressingFile" xml:space="preserve">
<data name="CompressingFile" xml:space="preserve">
<value>Comprimiendo archivo...</value>
</data>
<data name="CouldNotFindRomSetInDatabase" xml:space="preserve">
<data name="CouldNotFindRomSetInDatabase" xml:space="preserve">
<value>No se pudo encontrar el set de ROMs en la base de datos.</value>
</data>
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<value>El archivo existe</value>
</data>
<data name="DatAlreadyInDatabase" xml:space="preserve">
<data name="DatAlreadyInDatabase" xml:space="preserve">
<value>El archivo DAT ya está en la base de datos, no importaré duplicados.</value>
</data>
<data name="EnumeratingFiles" xml:space="preserve">
<data name="EnumeratingFiles" xml:space="preserve">
<value>Enumerando archivos...</value>
</data>
<data name="ErrorWithMessage" xml:space="preserve">
<data name="ErrorWithMessage" xml:space="preserve">
<value>Error: {0}</value>
</data>
<data name="ExportingRoms" xml:space="preserve">
<data name="ExportingRoms" xml:space="preserve">
<value>Exportando ROMs...</value>
</data>
<data name="ExtractedContents" xml:space="preserve">
<data name="ExtractedContents" xml:space="preserve">
<value>Contenidos extraídos</value>
</data>
<data name="ExtractingArchive" xml:space="preserve">
<data name="ExtractingArchive" xml:space="preserve">
<value>Extrayendo contenidos del archivo...</value>
</data>
<data name="Finished" xml:space="preserve">
<data name="Finished" xml:space="preserve">
<value>Terminado</value>
</data>
<data name="Finishing" xml:space="preserve">
<data name="Finishing" xml:space="preserve">
<value>Terminando...</value>
</data>
<data name="FoundRomWithoutMachine" xml:space="preserve">
<data name="FoundRomWithoutMachine" xml:space="preserve">
<value>Se encontró una ROM sin máquina, esto no debería pasar.</value>
</data>
<data name="GettingMachineNames" xml:space="preserve">
<data name="GettingMachineNames" xml:space="preserve">
<value>Obteniendo nombre de las máquinas (juegos)...</value>
</data>
<data name="HashingDatFile" xml:space="preserve">
<data name="HashingDatFile" xml:space="preserve">
<value>Calculando hash del archivo DAT...</value>
</data>
<data name="HashingFile" xml:space="preserve">
<data name="HashingFile" xml:space="preserve">
<value>Calculando hash del archivo...</value>
</data>
<data name="Importing" xml:space="preserve">
<data name="Importing" xml:space="preserve">
<value>Importando {0}...</value>
</data>
<data name="NotCorrectLsAr" xml:space="preserve">
<data name="NotCorrectLsAr" xml:space="preserve">
<value>No es el ejecutable correcto de lsar</value>
</data>
<data name="NotCorrectUnAr" xml:space="preserve">
<data name="NotCorrectUnAr" xml:space="preserve">
<value>No es el ejecutable corrector de unar</value>
</data>
<data name="Not_yet_implemented" xml:space="preserve">
<data name="Not_yet_implemented" xml:space="preserve">
<value>Aún no implementado.</value>
</data>
<data name="OK" xml:space="preserve">
<data name="OK" xml:space="preserve">
<value>OK</value>
</data>
<data name="ParsinDatFile" xml:space="preserve">
<data name="ParsinDatFile" xml:space="preserve">
<value>Analizando archivo DAT...</value>
</data>
<data name="RemovingTemporaryPath" xml:space="preserve">
<data name="RemovingTemporaryPath" xml:space="preserve">
<value>Eliminando ruta remporal...</value>
</data>
<data name="RetrievingRomsAndDisks" xml:space="preserve">
<data name="RetrievingRomsAndDisks" xml:space="preserve">
<value>Recuperando ROMs y discos...</value>
</data>
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<value>Recuperando set de ROMs de la base de datos...</value>
</data>
<data name="SavingChangesToDatabase" xml:space="preserve">
<data name="SavingChangesToDatabase" xml:space="preserve">
<value>Guardando cambios en la base de datos...</value>
</data>
<data name="Spamsum_Input_exceeds_data" xml:space="preserve">
<data name="Spamsum_Input_exceeds_data" xml:space="preserve">
<value>La entrada excede los tipos de datos.</value>
</data>
<data name="Spamsum_no_binary" xml:space="preserve">
<data name="Spamsum_no_binary" xml:space="preserve">
<value>SpamSum no posee una representación binaria.</value>
</data>
<data name="UnArPathNotSet" xml:space="preserve">
<data name="UnArPathNotSet" xml:space="preserve">
<value>La ruta a unar no está establecida.</value>
</data>
<data name="UnhandledException" xml:space="preserve">
<data name="UnhandledException" xml:space="preserve">
<value>Ocurrió una excepción no controlada.</value>
</data>
<data name="UnhandledExceptionWhenImporting" xml:space="preserve">
<data name="UnhandledExceptionWhenImporting" xml:space="preserve">
<value>Excepción no controlada al importar archivo.</value>
</data>
<data name="UnknownFile" xml:space="preserve">
<data name="UnknownFile" xml:space="preserve">
<value>Archivo desconocido.</value>
</data>
<data name="AddingDisks" xml:space="preserve">
<data name="AddingDisks" xml:space="preserve">
<value>Añadiendo discos...</value>
</data>
<data name="FoundDiskWithoutMachine" xml:space="preserve">
<data name="FoundDiskWithoutMachine" xml:space="preserve">
<value>Se encontró un disco sin máquina, esto no debería pasar.</value>
</data>
<data name="NoChecksumsFound" xml:space="preserve">
<data name="NoChecksumsFound" xml:space="preserve">
<value>No se encontraron hashes.</value>
</data>
<data name="NotAChdFile" xml:space="preserve">
<data name="NotAChdFile" xml:space="preserve">
<value>No es un CHD.</value>
</data>
<data name="Copying" xml:space="preserve">
<data name="Copying" xml:space="preserve">
<value>Copiando {0}...</value>
</data>
<data name="CopyingFile" xml:space="preserve">
<data name="CopyingFile" xml:space="preserve">
<value>Copiando archivo...</value>
</data>
<data name="FoundMediaWithoutMachine" xml:space="preserve">
<data name="FoundMediaWithoutMachine" xml:space="preserve">
<value>Se encontró un medio sin máquina, esto no debería pasar.</value>
</data>
<data name="NotAnAaruFormatFile" xml:space="preserve">
<data name="NotAnAaruFormatFile" xml:space="preserve">
<value>No es un archivo AaruFormat.</value>
</data>
<data name="AddingMedias" xml:space="preserve">
<data name="AddingMedias" xml:space="preserve">
<value>Añadiendo medios...</value>
</data>
</root>

View File

@@ -1,193 +1,198 @@
<?xml version="1.0" encoding="utf-8" ?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Base32_Not_enought_data" xml:space="preserve">
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root"
xmlns="">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="Base32_Not_enought_data" xml:space="preserve">
<value>Specified string is not valid Base32 format because it doesn't have enough data to construct a complete byte array</value>
</data>
<data name="Base32_Invalid_format" xml:space="preserve">
<data name="Base32_Invalid_format" xml:space="preserve">
<value>Specified string is not valid Base32 format because character "{0}" does not exist in Base32 alphabet</value>
</data>
<data name="Cannot_seek_before_start" xml:space="preserve">
<data name="Cannot_seek_before_start" xml:space="preserve">
<value>Cannot seek before stream start.</value>
</data>
<data name="Cannot_seek_after_end" xml:space="preserve">
<data name="Cannot_seek_after_end" xml:space="preserve">
<value>Cannot seek after stream end.</value>
</data>
<data name="Spamsum_no_binary" xml:space="preserve">
<data name="Spamsum_no_binary" xml:space="preserve">
<value>SpamSum does not have a binary representation.</value>
</data>
<data name="Assertion_failed" xml:space="preserve">
<data name="Assertion_failed" xml:space="preserve">
<value>Assertion failed</value>
</data>
<data name="Spamsum_Input_exceeds_data" xml:space="preserve">
<data name="Spamsum_Input_exceeds_data" xml:space="preserve">
<value>The input exceeds data types.</value>
</data>
<data name="Not_yet_implemented" xml:space="preserve">
<data name="Not_yet_implemented" xml:space="preserve">
<value>Not yet implemented.</value>
</data>
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<value>File exists</value>
</data>
<data name="UnArPathNotSet" xml:space="preserve">
<data name="UnArPathNotSet" xml:space="preserve">
<value>unar path is not set.</value>
</data>
<data name="CannotFindUnArAtPath" xml:space="preserve">
<data name="CannotFindUnArAtPath" xml:space="preserve">
<value>Cannot find unar executable at {0}.</value>
</data>
<data name="CannotFindLsAr" xml:space="preserve">
<data name="CannotFindLsAr" xml:space="preserve">
<value>Cannot find lsar executable.</value>
</data>
<data name="CannotRunUnAr" xml:space="preserve">
<data name="CannotRunUnAr" xml:space="preserve">
<value>Cannot run unar.</value>
</data>
<data name="CannotRunLsAr" xml:space="preserve">
<data name="CannotRunLsAr" xml:space="preserve">
<value>Cannot run lsar.</value>
</data>
<data name="NotCorrectUnAr" xml:space="preserve">
<data name="NotCorrectUnAr" xml:space="preserve">
<value>Not the correct unar executable</value>
</data>
<data name="NotCorrectLsAr" xml:space="preserve">
<data name="NotCorrectLsAr" xml:space="preserve">
<value>Not the correct lsar executable</value>
</data>
<data name="ParsinDatFile" xml:space="preserve">
<data name="ParsinDatFile" xml:space="preserve">
<value>Parsing DAT file...</value>
</data>
<data name="HashingDatFile" xml:space="preserve">
<data name="HashingDatFile" xml:space="preserve">
<value>Hashing DAT file...</value>
</data>
<data name="DatAlreadyInDatabase" xml:space="preserve">
<data name="DatAlreadyInDatabase" xml:space="preserve">
<value>DAT file is already in database, not importing duplicates.</value>
</data>
<data name="AddingDatToDatabase" xml:space="preserve">
<data name="AddingDatToDatabase" xml:space="preserve">
<value>Adding DAT to database...</value>
</data>
<data name="CompressingDatFile" xml:space="preserve">
<data name="CompressingDatFile" xml:space="preserve">
<value>Compressing DAT file...</value>
</data>
<data name="GettingMachineNames" xml:space="preserve">
<data name="GettingMachineNames" xml:space="preserve">
<value>Getting machine (game) names...</value>
</data>
<data name="AddingMachines" xml:space="preserve">
<data name="AddingMachines" xml:space="preserve">
<value>Adding machines (games)...</value>
</data>
<data name="SavingChangesToDatabase" xml:space="preserve">
<data name="SavingChangesToDatabase" xml:space="preserve">
<value>Saving changes to database...</value>
</data>
<data name="RetrievingRomsAndDisks" xml:space="preserve">
<data name="RetrievingRomsAndDisks" xml:space="preserve">
<value>Retrieving ROMs and disks...</value>
</data>
<data name="AddingRoms" xml:space="preserve">
<data name="AddingRoms" xml:space="preserve">
<value>Adding ROMs...</value>
</data>
<data name="FoundRomWithoutMachine" xml:space="preserve">
<data name="FoundRomWithoutMachine" xml:space="preserve">
<value>Found a ROM with an unknown machine, this should not happen.</value>
</data>
<data name="UnhandledException" xml:space="preserve">
<data name="UnhandledException" xml:space="preserve">
<value>Unhandled exception occurred.</value>
</data>
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<value>Retrieving ROM set from database.</value>
</data>
<data name="CouldNotFindRomSetInDatabase" xml:space="preserve">
<data name="CouldNotFindRomSetInDatabase" xml:space="preserve">
<value>Could not find ROM set in database.</value>
</data>
<data name="ExportingRoms" xml:space="preserve">
<data name="ExportingRoms" xml:space="preserve">
<value>Exporting ROMs...</value>
</data>
<data name="Finished" xml:space="preserve">
<data name="Finished" xml:space="preserve">
<value>Finished</value>
</data>
<data name="CannotFindZipEntryInDictionary" xml:space="preserve">
<data name="CannotFindZipEntryInDictionary" xml:space="preserve">
<value>Cannot find requested zip entry in hashes dictionary</value>
</data>
<data name="CannotFindHashInRepository" xml:space="preserve">
<data name="CannotFindHashInRepository" xml:space="preserve">
<value>Cannot find file with hash {0} in the repository</value>
</data>
<data name="Compressing" xml:space="preserve">
<data name="Compressing" xml:space="preserve">
<value>Compressing {0}...</value>
</data>
<data name="EnumeratingFiles" xml:space="preserve">
<data name="EnumeratingFiles" xml:space="preserve">
<value>Enumerating files...</value>
</data>
<data name="Importing" xml:space="preserve">
<data name="Importing" xml:space="preserve">
<value>Importing {0}...</value>
</data>
<data name="CheckingIfFIleIsAnArchive" xml:space="preserve">
<data name="CheckingIfFIleIsAnArchive" xml:space="preserve">
<value>Checking if file is an archive...</value>
</data>
<data name="OK" xml:space="preserve">
<data name="OK" xml:space="preserve">
<value>OK</value>
</data>
<data name="ErrorWithMessage" xml:space="preserve">
<data name="ErrorWithMessage" xml:space="preserve">
<value>Error: {0}</value>
</data>
<data name="ExtractingArchive" xml:space="preserve">
<data name="ExtractingArchive" xml:space="preserve">
<value>Extracting archive contents...</value>
</data>
<data name="RemovingTemporaryPath" xml:space="preserve">
<data name="RemovingTemporaryPath" xml:space="preserve">
<value>Removing temporary path...</value>
</data>
<data name="ExtractedContents" xml:space="preserve">
<data name="ExtractedContents" xml:space="preserve">
<value>Extracted contents</value>
</data>
<data name="HashingFile" xml:space="preserve">
<data name="HashingFile" xml:space="preserve">
<value>Hashing file...</value>
</data>
<data name="UnknownFile" xml:space="preserve">
<data name="UnknownFile" xml:space="preserve">
<value>Unknown file.</value>
</data>
<data name="CompressingFile" xml:space="preserve">
<data name="CompressingFile" xml:space="preserve">
<value>Compressing file...</value>
</data>
<data name="Finishing" xml:space="preserve">
<data name="Finishing" xml:space="preserve">
<value>Finishing...</value>
</data>
<data name="UnhandledExceptionWhenImporting" xml:space="preserve">
<data name="UnhandledExceptionWhenImporting" xml:space="preserve">
<value>Unhandled exception when importing file.</value>
</data>
<data name="AddingDisks" xml:space="preserve">
<data name="AddingDisks" xml:space="preserve">
<value>Adding disks...</value>
</data>
<data name="FoundDiskWithoutMachine" xml:space="preserve">
<data name="FoundDiskWithoutMachine" xml:space="preserve">
<value>Found a disk with an unknown machine, this should not happen.</value>
</data>
<data name="NotAChdFile" xml:space="preserve">
<data name="NotAChdFile" xml:space="preserve">
<value>Not a CHD file.</value>
</data>
<data name="NoChecksumsFound" xml:space="preserve">
<data name="NoChecksumsFound" xml:space="preserve">
<value>No checksums found.</value>
</data>
<data name="Copying" xml:space="preserve">
<data name="Copying" xml:space="preserve">
<value>Copying {0}...</value>
</data>
<data name="CopyingFile" xml:space="preserve">
<data name="CopyingFile" xml:space="preserve">
<value>Copying file...</value>
</data>
<data name="AddingMedias" xml:space="preserve">
<data name="AddingMedias" xml:space="preserve">
<value>Adding medias...</value>
</data>
<data name="FoundMediaWithoutMachine" xml:space="preserve">
<data name="FoundMediaWithoutMachine" xml:space="preserve">
<value>Found media with an unknown machine, this should not happen.</value>
</data>
<data name="NotAnAaruFormatFile" xml:space="preserve">
<data name="NotAnAaruFormatFile" xml:space="preserve">
<value>Not an AaruFormat file.</value>
</data>
<data name="DatImportSuccess" xml:space="preserve">
<data name="DatImportSuccess" xml:space="preserve">
<value>Imported {0} machines with {1} ROMs.</value>
</data>
</root>

View File

@@ -1,39 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<NeutralLanguage>en</NeutralLanguage>
<LangVersion>default</LangVersion>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<NeutralLanguage>en</NeutralLanguage>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNetZip" Version="1.15.0" />
<PackageReference Include="EFCore.BulkExtensions" Version="3.2.7" />
<PackageReference Include="Mono.Fuse.NETStandard" Version="1.1.0" />
<PackageReference Include="SharpCompress" Version="0.26.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DotNetZip" Version="1.15.0"/>
<PackageReference Include="EFCore.BulkExtensions" Version="3.2.7"/>
<PackageReference Include="Mono.Fuse.NETStandard" Version="1.1.0"/>
<PackageReference Include="SharpCompress" Version="0.26.0"/>
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RomRepoMgr.Database\RomRepoMgr.Database.csproj" />
<ProjectReference Include="..\RomRepoMgr.Settings\RomRepoMgr.Settings.csproj" />
<ProjectReference Include="..\SabreTools\SabreTools.DatFiles\SabreTools.DatFiles.csproj" />
<ProjectReference Include="..\winfsp-netcore\winfsp-netcore.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RomRepoMgr.Database\RomRepoMgr.Database.csproj"/>
<ProjectReference Include="..\RomRepoMgr.Settings\RomRepoMgr.Settings.csproj"/>
<ProjectReference Include="..\SabreTools\SabreTools.DatFiles\SabreTools.DatFiles.csproj"/>
<ProjectReference Include="..\winfsp-netcore\winfsp-netcore.csproj"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Language.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Language.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@@ -1,43 +1,42 @@
using System;
using System.IO;
namespace RomRepoMgr.Core
namespace RomRepoMgr.Core;
internal sealed class StreamWithLength : Stream
{
internal sealed class StreamWithLength : Stream
readonly Stream _baseStream;
public StreamWithLength(Stream baseStream, long length)
{
readonly Stream _baseStream;
_baseStream = baseStream;
Length = length;
}
public StreamWithLength(Stream baseStream, long length)
{
_baseStream = baseStream;
Length = length;
}
public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => _baseStream.CanSeek;
public override bool CanWrite => _baseStream.CanWrite;
public override long Length { get; }
public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => _baseStream.CanSeek;
public override bool CanWrite => _baseStream.CanWrite;
public override long Length { get; }
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
public override void Flush() => _baseStream.Flush();
public override void Flush() => _baseStream.Flush();
public override int Read(byte[] buffer, int offset, int count) => _baseStream.Read(buffer, offset, count);
public override int Read(byte[] buffer, int offset, int count) => _baseStream.Read(buffer, offset, count);
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override void Close()
{
_baseStream.Close();
base.Close();
}
public override void Close()
{
_baseStream.Close();
base.Close();
}
}

View File

@@ -34,154 +34,159 @@ using System.Collections.Generic;
using System.Threading;
using Aaru.Checksums;
namespace RomRepoMgr.Core.Workers
namespace RomRepoMgr.Core.Workers;
internal enum ChecksumType
{
internal enum ChecksumType
Crc32,
Md5,
Sha1,
Sha256,
Sha384,
Sha512
}
internal sealed class Checksum
{
readonly Crc32Context _crc32Ctx;
readonly Md5Context _md5Ctx;
readonly Sha1Context _sha1Ctx;
readonly Sha256Context _sha256Ctx;
readonly Sha384Context _sha384Ctx;
readonly Sha512Context _sha512Ctx;
Crc32Packet _crc32Pkt;
Thread _crc32Thread;
Md5Packet _md5Pkt;
Thread _md5Thread;
Sha1Packet _sha1Pkt;
Thread _sha1Thread;
Sha256Packet _sha256Pkt;
Thread _sha256Thread;
Sha384Packet _sha384Pkt;
Thread _sha384Thread;
Sha512Packet _sha512Pkt;
Thread _sha512Thread;
internal Checksum()
{
Crc32, Md5, Sha1,
Sha256, Sha384, Sha512
_crc32Ctx = new Crc32Context();
_md5Ctx = new Md5Context();
_sha1Ctx = new Sha1Context();
_sha256Ctx = new Sha256Context();
_sha384Ctx = new Sha384Context();
_sha512Ctx = new Sha512Context();
_crc32Thread = new Thread(UpdateCrc32);
_md5Thread = new Thread(UpdateMd5);
_sha1Thread = new Thread(UpdateSha1);
_sha256Thread = new Thread(UpdateSha256);
_sha384Thread = new Thread(UpdateSha384);
_sha512Thread = new Thread(UpdateSha512);
_crc32Pkt = new Crc32Packet();
_md5Pkt = new Md5Packet();
_sha1Pkt = new Sha1Packet();
_sha256Pkt = new Sha256Packet();
_sha384Pkt = new Sha384Packet();
_sha512Pkt = new Sha512Packet();
_crc32Pkt.context = _crc32Ctx;
_md5Pkt.context = _md5Ctx;
_sha1Pkt.context = _sha1Ctx;
_sha256Pkt.context = _sha256Ctx;
_sha384Pkt.context = _sha384Ctx;
_sha512Pkt.context = _sha512Ctx;
}
internal sealed class Checksum
internal void Update(byte[] data)
{
readonly Crc32Context _crc32Ctx;
readonly Md5Context _md5Ctx;
readonly Sha1Context _sha1Ctx;
readonly Sha256Context _sha256Ctx;
readonly Sha384Context _sha384Ctx;
readonly Sha512Context _sha512Ctx;
Crc32Packet _crc32Pkt;
Thread _crc32Thread;
Md5Packet _md5Pkt;
Thread _md5Thread;
Sha1Packet _sha1Pkt;
Thread _sha1Thread;
Sha256Packet _sha256Pkt;
Thread _sha256Thread;
Sha384Packet _sha384Pkt;
Thread _sha384Thread;
Sha512Packet _sha512Pkt;
Thread _sha512Thread;
_crc32Pkt.data = data;
_crc32Thread.Start(_crc32Pkt);
_md5Pkt.data = data;
_md5Thread.Start(_md5Pkt);
_sha1Pkt.data = data;
_sha1Thread.Start(_sha1Pkt);
_sha256Pkt.data = data;
_sha256Thread.Start(_sha256Pkt);
_sha384Pkt.data = data;
_sha384Thread.Start(_sha384Pkt);
_sha512Pkt.data = data;
_sha512Thread.Start(_sha512Pkt);
internal Checksum()
{
_crc32Ctx = new Crc32Context();
_md5Ctx = new Md5Context();
_sha1Ctx = new Sha1Context();
_sha256Ctx = new Sha256Context();
_sha384Ctx = new Sha384Context();
_sha512Ctx = new Sha512Context();
while(_crc32Thread.IsAlive ||
_md5Thread.IsAlive ||
_sha1Thread.IsAlive ||
_sha256Thread.IsAlive ||
_sha384Thread.IsAlive ||
_sha512Thread.IsAlive) {}
_crc32Thread = new Thread(UpdateCrc32);
_md5Thread = new Thread(UpdateMd5);
_sha1Thread = new Thread(UpdateSha1);
_sha256Thread = new Thread(UpdateSha256);
_sha384Thread = new Thread(UpdateSha384);
_sha512Thread = new Thread(UpdateSha512);
_crc32Pkt = new Crc32Packet();
_md5Pkt = new Md5Packet();
_sha1Pkt = new Sha1Packet();
_sha256Pkt = new Sha256Packet();
_sha384Pkt = new Sha384Packet();
_sha512Pkt = new Sha512Packet();
_crc32Pkt.context = _crc32Ctx;
_md5Pkt.context = _md5Ctx;
_sha1Pkt.context = _sha1Ctx;
_sha256Pkt.context = _sha256Ctx;
_sha384Pkt.context = _sha384Ctx;
_sha512Pkt.context = _sha512Ctx;
}
internal void Update(byte[] data)
{
_crc32Pkt.data = data;
_crc32Thread.Start(_crc32Pkt);
_md5Pkt.data = data;
_md5Thread.Start(_md5Pkt);
_sha1Pkt.data = data;
_sha1Thread.Start(_sha1Pkt);
_sha256Pkt.data = data;
_sha256Thread.Start(_sha256Pkt);
_sha384Pkt.data = data;
_sha384Thread.Start(_sha384Pkt);
_sha512Pkt.data = data;
_sha512Thread.Start(_sha512Pkt);
while(_crc32Thread.IsAlive ||
_md5Thread.IsAlive ||
_sha1Thread.IsAlive ||
_sha256Thread.IsAlive ||
_sha384Thread.IsAlive ||
_sha512Thread.IsAlive) {}
_crc32Thread = new Thread(UpdateCrc32);
_md5Thread = new Thread(UpdateMd5);
_sha1Thread = new Thread(UpdateSha1);
_sha256Thread = new Thread(UpdateSha256);
_sha384Thread = new Thread(UpdateSha384);
_sha512Thread = new Thread(UpdateSha512);
}
internal Dictionary<ChecksumType, string> End() => new Dictionary<ChecksumType, string>
{
[ChecksumType.Crc32] = _crc32Ctx.End(),
[ChecksumType.Md5] = _md5Ctx.End(),
[ChecksumType.Sha1] = _sha1Ctx.End(),
[ChecksumType.Sha256] = _sha256Ctx.End(),
[ChecksumType.Sha384] = _sha384Ctx.End(),
[ChecksumType.Sha512] = _sha512Ctx.End()
};
#region Threading helpers
struct Crc32Packet
{
public Crc32Context context;
public byte[] data;
}
struct Md5Packet
{
public Md5Context context;
public byte[] data;
}
struct Sha1Packet
{
public Sha1Context context;
public byte[] data;
}
struct Sha256Packet
{
public Sha256Context context;
public byte[] data;
}
struct Sha384Packet
{
public Sha384Context context;
public byte[] data;
}
struct Sha512Packet
{
public Sha512Context context;
public byte[] data;
}
static void UpdateCrc32(object packet) => ((Crc32Packet)packet).context.Update(((Crc32Packet)packet).data);
static void UpdateMd5(object packet) => ((Md5Packet)packet).context.Update(((Md5Packet)packet).data);
static void UpdateSha1(object packet) => ((Sha1Packet)packet).context.Update(((Sha1Packet)packet).data);
static void UpdateSha256(object packet) => ((Sha256Packet)packet).context.Update(((Sha256Packet)packet).data);
static void UpdateSha384(object packet) => ((Sha384Packet)packet).context.Update(((Sha384Packet)packet).data);
static void UpdateSha512(object packet) => ((Sha512Packet)packet).context.Update(((Sha512Packet)packet).data);
#endregion Threading helpers
_crc32Thread = new Thread(UpdateCrc32);
_md5Thread = new Thread(UpdateMd5);
_sha1Thread = new Thread(UpdateSha1);
_sha256Thread = new Thread(UpdateSha256);
_sha384Thread = new Thread(UpdateSha384);
_sha512Thread = new Thread(UpdateSha512);
}
internal Dictionary<ChecksumType, string> End() => new()
{
[ChecksumType.Crc32] = _crc32Ctx.End(),
[ChecksumType.Md5] = _md5Ctx.End(),
[ChecksumType.Sha1] = _sha1Ctx.End(),
[ChecksumType.Sha256] = _sha256Ctx.End(),
[ChecksumType.Sha384] = _sha384Ctx.End(),
[ChecksumType.Sha512] = _sha512Ctx.End()
};
#region Threading helpers
struct Crc32Packet
{
public Crc32Context context;
public byte[] data;
}
struct Md5Packet
{
public Md5Context context;
public byte[] data;
}
struct Sha1Packet
{
public Sha1Context context;
public byte[] data;
}
struct Sha256Packet
{
public Sha256Context context;
public byte[] data;
}
struct Sha384Packet
{
public Sha384Context context;
public byte[] data;
}
struct Sha512Packet
{
public Sha512Context context;
public byte[] data;
}
static void UpdateCrc32(object packet) => ((Crc32Packet)packet).context.Update(((Crc32Packet)packet).data);
static void UpdateMd5(object packet) => ((Md5Packet)packet).context.Update(((Md5Packet)packet).data);
static void UpdateSha1(object packet) => ((Sha1Packet)packet).context.Update(((Sha1Packet)packet).data);
static void UpdateSha256(object packet) => ((Sha256Packet)packet).context.Update(((Sha256Packet)packet).data);
static void UpdateSha384(object packet) => ((Sha384Packet)packet).context.Update(((Sha384Packet)packet).data);
static void UpdateSha512(object packet) => ((Sha512Packet)packet).context.Update(((Sha512Packet)packet).data);
#endregion Threading helpers
}

View File

@@ -32,207 +32,217 @@ using SharpCompress.Compressors;
using SharpCompress.Compressors.LZMA;
using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs;
namespace RomRepoMgr.Core.Workers
namespace RomRepoMgr.Core.Workers;
public sealed class Compression
{
public sealed class Compression
const long BUFFER_SIZE = 131072;
public event EventHandler<ProgressBoundsEventArgs> SetProgressBounds;
public event EventHandler<ProgressEventArgs> SetProgress;
public event EventHandler<MessageEventArgs> FinishedWithText;
public event EventHandler<ErrorEventArgs> FailedWithText;
public void CompressFile(string source, string destination)
{
const long BUFFER_SIZE = 131072;
var inFs = new FileStream(source, FileMode.Open, FileAccess.Read);
var outFs = new FileStream(destination, FileMode.CreateNew, FileAccess.Write);
Stream zStream = new LZipStream(outFs, CompressionMode.Compress);
public event EventHandler<ProgressBoundsEventArgs> SetProgressBounds;
public event EventHandler<ProgressEventArgs> SetProgress;
public event EventHandler<MessageEventArgs> FinishedWithText;
public event EventHandler<ErrorEventArgs> FailedWithText;
var buffer = new byte[BUFFER_SIZE];
public void CompressFile(string source, string destination)
SetProgressBounds?.Invoke(this,
new ProgressBoundsEventArgs
{
Minimum = 0,
Maximum = inFs.Length
});
while(inFs.Position + BUFFER_SIZE <= inFs.Length)
{
var inFs = new FileStream(source, FileMode.Open, FileAccess.Read);
var outFs = new FileStream(destination, FileMode.CreateNew, FileAccess.Write);
Stream zStream = new LZipStream(outFs, CompressionMode.Compress);
byte[] buffer = new byte[BUFFER_SIZE];
SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs
{
Minimum = 0,
Maximum = inFs.Length
});
while(inFs.Position + BUFFER_SIZE <= inFs.Length)
{
SetProgress?.Invoke(this, new ProgressEventArgs
{
Value = inFs.Position
});
inFs.Read(buffer, 0, buffer.Length);
zStream.Write(buffer, 0, buffer.Length);
}
buffer = new byte[inFs.Length - inFs.Position];
SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs
{
Minimum = 0,
Maximum = inFs.Length
});
SetProgress?.Invoke(this,
new ProgressEventArgs
{
Value = inFs.Position
});
inFs.Read(buffer, 0, buffer.Length);
zStream.Write(buffer, 0, buffer.Length);
inFs.Close();
zStream.Close();
outFs.Dispose();
}
public void DecompressFile(string source, string destination)
buffer = new byte[inFs.Length - inFs.Position];
SetProgressBounds?.Invoke(this,
new ProgressBoundsEventArgs
{
Minimum = 0,
Maximum = inFs.Length
});
inFs.Read(buffer, 0, buffer.Length);
zStream.Write(buffer, 0, buffer.Length);
inFs.Close();
zStream.Close();
outFs.Dispose();
}
public void DecompressFile(string source, string destination)
{
var inFs = new FileStream(source, FileMode.Open, FileAccess.Read);
var outFs = new FileStream(destination, FileMode.Create, FileAccess.Write);
Stream zStream = new LZipStream(inFs, CompressionMode.Decompress);
zStream.CopyTo(outFs);
outFs.Close();
zStream.Close();
inFs.Close();
}
public bool CheckUnAr(string unArPath)
{
if(string.IsNullOrWhiteSpace(unArPath))
{
var inFs = new FileStream(source, FileMode.Open, FileAccess.Read);
var outFs = new FileStream(destination, FileMode.Create, FileAccess.Write);
Stream zStream = new LZipStream(inFs, CompressionMode.Decompress);
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.UnArPathNotSet
});
zStream.CopyTo(outFs);
outFs.Close();
zStream.Close();
inFs.Close();
return false;
}
public bool CheckUnAr(string unArPath)
string unarFolder = Path.GetDirectoryName(unArPath);
string extension = Path.GetExtension(unArPath);
string unarfilename = Path.GetFileNameWithoutExtension(unArPath);
string lsarfilename = unarfilename.Replace("unar", "lsar");
string unarPath = Path.Combine(unarFolder, unarfilename + extension);
string lsarPath = Path.Combine(unarFolder, lsarfilename + extension);
if(!File.Exists(unarPath))
{
if(string.IsNullOrWhiteSpace(unArPath))
{
FailedWithText?.Invoke(this, new ErrorEventArgs
{
Message = Localization.UnArPathNotSet
});
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = string.Format(Localization.CannotFindUnArAtPath, unarPath)
});
return false;
}
return false;
}
string unarFolder = Path.GetDirectoryName(unArPath);
string extension = Path.GetExtension(unArPath);
string unarfilename = Path.GetFileNameWithoutExtension(unArPath);
string lsarfilename = unarfilename.Replace("unar", "lsar");
string unarPath = Path.Combine(unarFolder, unarfilename + extension);
string lsarPath = Path.Combine(unarFolder, lsarfilename + extension);
if(!File.Exists(lsarPath))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.CannotFindLsAr
});
if(!File.Exists(unarPath))
{
FailedWithText?.Invoke(this, new ErrorEventArgs
{
Message = string.Format(Localization.CannotFindUnArAtPath, unarPath)
});
return false;
}
return false;
}
string unarOut, lsarOut;
if(!File.Exists(lsarPath))
{
FailedWithText?.Invoke(this, new ErrorEventArgs
{
Message = Localization.CannotFindLsAr
});
return false;
}
string unarOut, lsarOut;
try
{
var unarProcess = new Process
{
StartInfo =
{
FileName = unarPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
}
};
unarProcess.Start();
unarProcess.WaitForExit();
unarOut = unarProcess.StandardOutput.ReadToEnd();
}
catch
{
FailedWithText?.Invoke(this, new ErrorEventArgs
{
Message = Localization.CannotRunUnAr
});
return false;
}
try
{
var lsarProcess = new Process
{
StartInfo =
{
FileName = lsarPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
}
};
lsarProcess.Start();
lsarProcess.WaitForExit();
lsarOut = lsarProcess.StandardOutput.ReadToEnd();
}
catch
{
FailedWithText?.Invoke(this, new ErrorEventArgs
{
Message = Localization.CannotRunLsAr
});
return false;
}
if(!unarOut.StartsWith("unar ", StringComparison.CurrentCulture))
{
FailedWithText?.Invoke(this, new ErrorEventArgs
{
Message = Localization.NotCorrectUnAr
});
return false;
}
if(!lsarOut.StartsWith("lsar ", StringComparison.CurrentCulture))
{
FailedWithText?.Invoke(this, new ErrorEventArgs
{
Message = Localization.NotCorrectLsAr
});
return false;
}
var versionProcess = new Process
try
{
var unarProcess = new Process
{
StartInfo =
{
FileName = unarPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false,
Arguments = "-v"
UseShellExecute = false
}
};
versionProcess.Start();
versionProcess.WaitForExit();
FinishedWithText?.Invoke(this, new MessageEventArgs
{
Message = versionProcess.StandardOutput.ReadToEnd().TrimEnd('\n')
});
return true;
unarProcess.Start();
unarProcess.WaitForExit();
unarOut = unarProcess.StandardOutput.ReadToEnd();
}
catch
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.CannotRunUnAr
});
return false;
}
try
{
var lsarProcess = new Process
{
StartInfo =
{
FileName = lsarPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
}
};
lsarProcess.Start();
lsarProcess.WaitForExit();
lsarOut = lsarProcess.StandardOutput.ReadToEnd();
}
catch
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.CannotRunLsAr
});
return false;
}
if(!unarOut.StartsWith("unar ", StringComparison.CurrentCulture))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.NotCorrectUnAr
});
return false;
}
if(!lsarOut.StartsWith("lsar ", StringComparison.CurrentCulture))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.NotCorrectLsAr
});
return false;
}
var versionProcess = new Process
{
StartInfo =
{
FileName = unarPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false,
Arguments = "-v"
}
};
versionProcess.Start();
versionProcess.WaitForExit();
FinishedWithText?.Invoke(this,
new MessageEventArgs
{
Message = versionProcess.StandardOutput.ReadToEnd().TrimEnd('\n')
});
return true;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -27,181 +27,177 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using RomRepoMgr.Database.Models;
namespace RomRepoMgr.Database
namespace RomRepoMgr.Database;
public sealed class Context : DbContext
{
public sealed class Context : DbContext
public Context(DbContextOptions options) : base(options) {}
public DbSet<DbFile> Files { get; set; }
public DbSet<RomSet> RomSets { get; set; }
public DbSet<Machine> Machines { get; set; }
public DbSet<FileByMachine> FilesByMachines { get; set; }
public DbSet<DbDisk> Disks { get; set; }
public DbSet<DiskByMachine> DisksByMachines { get; set; }
public DbSet<DbMedia> Medias { get; set; }
public DbSet<MediaByMachine> MediasByMachines { get; set; }
public DbSet<RomSetStat> RomSetStats { get; set; }
public static Context Create(string dbPath)
{
public Context(DbContextOptions options) : base(options) {}
var optionsBuilder = new DbContextOptionsBuilder();
public DbSet<DbFile> Files { get; set; }
public DbSet<RomSet> RomSets { get; set; }
public DbSet<Machine> Machines { get; set; }
public DbSet<FileByMachine> FilesByMachines { get; set; }
public DbSet<DbDisk> Disks { get; set; }
public DbSet<DiskByMachine> DisksByMachines { get; set; }
public DbSet<DbMedia> Medias { get; set; }
public DbSet<MediaByMachine> MediasByMachines { get; set; }
public DbSet<RomSetStat> RomSetStats { get; set; }
optionsBuilder.UseLazyLoadingProxies()
#if DEBUG
.UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()))
#endif
.UseSqlite($"Data Source={dbPath}");
public static Context Create(string dbPath)
return new Context(optionsBuilder.Options);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<DbFile>(entity =>
{
var optionsBuilder = new DbContextOptionsBuilder();
entity.HasIndex(e => e.Crc32);
optionsBuilder.UseLazyLoadingProxies()
#if DEBUG
.UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()))
#endif
.UseSqlite($"Data Source={dbPath}");
entity.HasIndex(e => e.Md5);
return new Context(optionsBuilder.Options);
}
entity.HasIndex(e => e.Sha1);
protected override void OnModelCreating(ModelBuilder modelBuilder)
entity.HasIndex(e => e.Sha256);
entity.HasIndex(e => e.Sha384);
entity.HasIndex(e => e.Sha512);
entity.HasIndex(e => e.Size);
entity.HasIndex(e => e.IsInRepo);
entity.HasIndex(e => new
{
e.Crc32,
e.Size
});
entity.HasIndex(e => new
{
e.Md5,
e.Size
});
entity.HasIndex(e => new
{
e.Sha1,
e.Size
});
entity.HasIndex(e => new
{
e.Sha256,
e.Size
});
entity.HasIndex(e => new
{
e.Sha384,
e.Size
});
entity.HasIndex(e => new
{
e.Sha512,
e.Size
});
});
modelBuilder.Entity<RomSet>(entity =>
{
base.OnModelCreating(modelBuilder);
entity.HasIndex(e => e.Author);
modelBuilder.Entity<DbFile>(entity =>
{
entity.HasIndex(e => e.Crc32);
entity.HasIndex(e => e.Comment);
entity.HasIndex(e => e.Md5);
entity.HasIndex(e => e.Date);
entity.HasIndex(e => e.Sha1);
entity.HasIndex(e => e.Description);
entity.HasIndex(e => e.Sha256);
entity.HasIndex(e => e.Homepage);
entity.HasIndex(e => e.Sha384);
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.Sha512);
entity.HasIndex(e => e.Version);
entity.HasIndex(e => e.Size);
entity.HasIndex(e => e.Filename);
entity.HasIndex(e => e.IsInRepo);
entity.HasIndex(e => e.Sha384);
entity.HasIndex(e => new
{
e.Crc32,
e.Size
});
entity.HasIndex(e => e.Category);
});
entity.HasIndex(e => new
{
e.Md5,
e.Size
});
modelBuilder.Entity<Machine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasIndex(e => new
{
e.Sha1,
e.Size
});
entity.HasOne(e => e.RomSet).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
entity.HasIndex(e => new
{
e.Sha256,
e.Size
});
modelBuilder.Entity<FileByMachine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasIndex(e => new
{
e.Sha384,
e.Size
});
entity.HasOne(e => e.Machine).WithMany(e => e.Files).OnDelete(DeleteBehavior.Cascade);
entity.HasIndex(e => new
{
e.Sha512,
e.Size
});
});
entity.HasOne(e => e.File).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<RomSet>(entity =>
{
entity.HasIndex(e => e.Author);
modelBuilder.Entity<DbDisk>(entity =>
{
entity.HasIndex(e => e.Md5);
entity.HasIndex(e => e.Comment);
entity.HasIndex(e => e.Sha1);
entity.HasIndex(e => e.Date);
entity.HasIndex(e => e.Size);
entity.HasIndex(e => e.Description);
entity.HasIndex(e => e.IsInRepo);
});
entity.HasIndex(e => e.Homepage);
modelBuilder.Entity<DiskByMachine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.Name);
entity.HasOne(e => e.Machine).WithMany(e => e.Disks).OnDelete(DeleteBehavior.Cascade);
entity.HasIndex(e => e.Version);
entity.HasOne(e => e.Disk).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
entity.HasIndex(e => e.Filename);
modelBuilder.Entity<DbMedia>(entity =>
{
entity.HasIndex(e => e.Md5);
entity.HasIndex(e => e.Sha384);
entity.HasIndex(e => e.Sha1);
entity.HasIndex(e => e.Category);
});
entity.HasIndex(e => e.Sha256);
modelBuilder.Entity<Machine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.SpamSum);
entity.HasOne(e => e.RomSet).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
entity.HasIndex(e => e.Size);
modelBuilder.Entity<FileByMachine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.IsInRepo);
});
entity.HasOne(e => e.Machine).WithMany(e => e.Files).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<MediaByMachine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasOne(e => e.File).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
entity.HasOne(e => e.Machine).WithMany(e => e.Medias).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<DbDisk>(entity =>
{
entity.HasIndex(e => e.Md5);
entity.HasOne(e => e.Media).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
entity.HasIndex(e => e.Sha1);
entity.HasIndex(e => e.Size);
entity.HasIndex(e => e.IsInRepo);
});
modelBuilder.Entity<DiskByMachine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasOne(e => e.Machine).WithMany(e => e.Disks).OnDelete(DeleteBehavior.Cascade);
entity.HasOne(e => e.Disk).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<DbMedia>(entity =>
{
entity.HasIndex(e => e.Md5);
entity.HasIndex(e => e.Sha1);
entity.HasIndex(e => e.Sha256);
entity.HasIndex(e => e.SpamSum);
entity.HasIndex(e => e.Size);
entity.HasIndex(e => e.IsInRepo);
});
modelBuilder.Entity<MediaByMachine>(entity =>
{
entity.HasIndex(e => e.Name);
entity.HasOne(e => e.Machine).WithMany(e => e.Medias).OnDelete(DeleteBehavior.Cascade);
entity.HasOne(e => e.Media).WithMany(e => e.Machines).OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<RomSetStat>(entity =>
{
entity.HasOne(e => e.RomSet).WithOne(e => e.Statistics);
});
}
modelBuilder.Entity<RomSetStat>(entity => { entity.HasOne(e => e.RomSet).WithOne(e => e.Statistics); });
}
}

View File

@@ -25,10 +25,9 @@
using Microsoft.EntityFrameworkCore.Design;
namespace RomRepoMgr.Database
namespace RomRepoMgr.Database;
public class ContextFactory : IDesignTimeDbContextFactory<Context>
{
public class ContextFactory : IDesignTimeDbContextFactory<Context>
{
public Context CreateDbContext(string[] args) => Context.Create("romrepo.db");
}
public Context CreateDbContext(string[] args) => Context.Create("romrepo.db");
}

View File

@@ -25,13 +25,12 @@
using System;
namespace RomRepoMgr.Database.Models
{
public abstract class BaseModel<TKey>
{
public TKey Id { get; set; }
namespace RomRepoMgr.Database.Models;
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public abstract class BaseModel<TKey>
{
public TKey Id { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}

View File

@@ -27,18 +27,17 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class DbDisk : BaseModel<ulong>
{
public class DbDisk : BaseModel<ulong>
{
public ulong? Size { get; set; }
[StringLength(32, MinimumLength = 32)]
public string Md5 { get; set; }
[StringLength(40, MinimumLength = 40)]
public string Sha1 { get; set; }
[DefaultValue(false)]
public bool IsInRepo { get; set; }
public string OriginalFileName { get; set; }
public virtual ICollection<DiskByMachine> Machines { get; set; }
}
public ulong? Size { get; set; }
[StringLength(32, MinimumLength = 32)]
public string Md5 { get; set; }
[StringLength(40, MinimumLength = 40)]
public string Sha1 { get; set; }
[DefaultValue(false)]
public bool IsInRepo { get; set; }
public string OriginalFileName { get; set; }
public virtual ICollection<DiskByMachine> Machines { get; set; }
}

View File

@@ -27,27 +27,26 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class DbFile : BaseModel<ulong>
{
public class DbFile : BaseModel<ulong>
{
[Required]
public ulong Size { get; set; }
[StringLength(8, MinimumLength = 8)]
public string Crc32 { get; set; }
[StringLength(32, MinimumLength = 32)]
public string Md5 { get; set; }
[StringLength(40, MinimumLength = 40)]
public string Sha1 { get; set; }
[StringLength(64, MinimumLength = 64)]
public string Sha256 { get; set; }
[StringLength(96, MinimumLength = 96)]
public string Sha384 { get; set; }
[StringLength(128, MinimumLength = 128)]
public string Sha512 { get; set; }
[DefaultValue(false)]
public bool IsInRepo { get; set; }
public string OriginalFileName { get; set; }
public virtual ICollection<FileByMachine> Machines { get; set; }
}
[Required]
public ulong Size { get; set; }
[StringLength(8, MinimumLength = 8)]
public string Crc32 { get; set; }
[StringLength(32, MinimumLength = 32)]
public string Md5 { get; set; }
[StringLength(40, MinimumLength = 40)]
public string Sha1 { get; set; }
[StringLength(64, MinimumLength = 64)]
public string Sha256 { get; set; }
[StringLength(96, MinimumLength = 96)]
public string Sha384 { get; set; }
[StringLength(128, MinimumLength = 128)]
public string Sha512 { get; set; }
[DefaultValue(false)]
public bool IsInRepo { get; set; }
public string OriginalFileName { get; set; }
public virtual ICollection<FileByMachine> Machines { get; set; }
}

View File

@@ -27,21 +27,20 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class DbMedia : BaseModel<ulong>
{
public class DbMedia : BaseModel<ulong>
{
public ulong? Size { get; set; }
[StringLength(32, MinimumLength = 32)]
public string Md5 { get; set; }
[StringLength(40, MinimumLength = 40)]
public string Sha1 { get; set; }
[StringLength(64, MinimumLength = 64)]
public string Sha256 { get; set; }
public string SpamSum { get; set; }
[DefaultValue(false)]
public bool IsInRepo { get; set; }
public string OriginalFileName { get; set; }
public virtual IEnumerable<MediaByMachine> Machines { get; set; }
}
public ulong? Size { get; set; }
[StringLength(32, MinimumLength = 32)]
public string Md5 { get; set; }
[StringLength(40, MinimumLength = 40)]
public string Sha1 { get; set; }
[StringLength(64, MinimumLength = 64)]
public string Sha256 { get; set; }
public string SpamSum { get; set; }
[DefaultValue(false)]
public bool IsInRepo { get; set; }
public string OriginalFileName { get; set; }
public virtual IEnumerable<MediaByMachine> Machines { get; set; }
}

View File

@@ -25,19 +25,18 @@
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class DiskByMachine
{
public class DiskByMachine
{
[Key]
public ulong Id { get; set; }
[Required]
public virtual DbDisk Disk { get; set; }
[Required]
public virtual Machine Machine { get; set; }
[Required]
public string Name { get; set; }
public ulong DiskId { get; set; }
public ulong MachineId { get; set; }
}
[Key]
public ulong Id { get; set; }
[Required]
public virtual DbDisk Disk { get; set; }
[Required]
public virtual Machine Machine { get; set; }
[Required]
public string Name { get; set; }
public ulong DiskId { get; set; }
public ulong MachineId { get; set; }
}

View File

@@ -26,22 +26,21 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class FileByMachine
{
public class FileByMachine
{
[Key]
public ulong Id { get; set; }
[Required]
public virtual DbFile File { get; set; }
[Required]
public virtual Machine Machine { get; set; }
[Required]
public string Name { get; set; }
public ulong FileId { get; set; }
public ulong MachineId { get; set; }
public DateTime? FileLastModification { get; set; }
[StringLength(4096)]
public string Path { get; set; }
}
[Key]
public ulong Id { get; set; }
[Required]
public virtual DbFile File { get; set; }
[Required]
public virtual Machine Machine { get; set; }
[Required]
public string Name { get; set; }
public ulong FileId { get; set; }
public ulong MachineId { get; set; }
public DateTime? FileLastModification { get; set; }
[StringLength(4096)]
public string Path { get; set; }
}

View File

@@ -26,17 +26,16 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class Machine : BaseModel<ulong>
{
public class Machine : BaseModel<ulong>
{
[Required]
public string Name { get; set; }
[Required]
public virtual RomSet RomSet { get; set; }
public virtual ICollection<FileByMachine> Files { get; set; }
public virtual ICollection<DiskByMachine> Disks { get; set; }
public virtual ICollection<MediaByMachine> Medias { get; set; }
public long RomSetId { get; set; }
}
[Required]
public string Name { get; set; }
[Required]
public virtual RomSet RomSet { get; set; }
public virtual ICollection<FileByMachine> Files { get; set; }
public virtual ICollection<DiskByMachine> Disks { get; set; }
public virtual ICollection<MediaByMachine> Medias { get; set; }
public long RomSetId { get; set; }
}

View File

@@ -25,19 +25,18 @@
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class MediaByMachine
{
public class MediaByMachine
{
[Key]
public ulong Id { get; set; }
[Required]
public virtual DbMedia Media { get; set; }
[Required]
public virtual Machine Machine { get; set; }
[Required]
public string Name { get; set; }
public ulong MediaId { get; set; }
public ulong MachineId { get; set; }
}
[Key]
public ulong Id { get; set; }
[Required]
public virtual DbMedia Media { get; set; }
[Required]
public virtual Machine Machine { get; set; }
[Required]
public string Name { get; set; }
public ulong MediaId { get; set; }
public ulong MachineId { get; set; }
}

View File

@@ -26,24 +26,24 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
{
public class RomSet : BaseModel<long>
{
public string Author { get; set; }
public string Comment { get; set; }
public string Date { get; set; }
public string Description { get; set; }
public string Homepage { get; set; }
public string Name { get; set; }
public string Version { get; set; }
[Required]
public string Filename { get; set; }
[Required, StringLength(96, MinimumLength = 96)]
public string Sha384 { get; set; }
public string Category { get; set; }
public virtual RomSetStat Statistics { get; set; }
namespace RomRepoMgr.Database.Models;
public virtual ICollection<Machine> Machines { get; set; }
}
public class RomSet : BaseModel<long>
{
public string Author { get; set; }
public string Comment { get; set; }
public string Date { get; set; }
public string Description { get; set; }
public string Homepage { get; set; }
public string Name { get; set; }
public string Version { get; set; }
[Required]
public string Filename { get; set; }
[Required]
[StringLength(96, MinimumLength = 96)]
public string Sha384 { get; set; }
public string Category { get; set; }
public virtual RomSetStat Statistics { get; set; }
public virtual ICollection<Machine> Machines { get; set; }
}

View File

@@ -1,17 +1,16 @@
using System.ComponentModel.DataAnnotations;
namespace RomRepoMgr.Database.Models
namespace RomRepoMgr.Database.Models;
public class RomSetStat
{
public class RomSetStat
{
public long TotalMachines { get; set; }
public long CompleteMachines { get; set; }
public long IncompleteMachines { get; set; }
public long TotalRoms { get; set; }
public long HaveRoms { get; set; }
public long MissRoms { get; set; }
public virtual RomSet RomSet { get; set; }
[Key]
public long RomSetId { get; set; }
}
public long TotalMachines { get; set; }
public long CompleteMachines { get; set; }
public long IncompleteMachines { get; set; }
public long TotalRoms { get; set; }
public long HaveRoms { get; set; }
public long MissRoms { get; set; }
public virtual RomSet RomSet { get; set; }
[Key]
public long RomSetId { get; set; }
}

View File

@@ -11,32 +11,46 @@ namespace RomRepoMgr.Database.Resources {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Localization {
private static System.Resources.ResourceManager resourceMan;
private static global::System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
private static global::System.Globalization.CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Localization() {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager {
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("RomRepoMgr.Database.Resources.Localization", typeof(Localization).Assembly);
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RomRepoMgr.Database.Resources.Localization", typeof(Localization).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture {
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
@@ -45,6 +59,9 @@ namespace RomRepoMgr.Database.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Settings are not initialized!.
/// </summary>
internal static string Settings_not_initialized {
get {
return ResourceManager.GetString("Settings_not_initialized", resourceCulture);

View File

@@ -1,17 +1,21 @@
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Settings_not_initialized" xml:space="preserve">
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="Settings_not_initialized" xml:space="preserve">
<value>¡Las preferencias no están inicializadas!</value>
</data>
</root>

View File

@@ -1,22 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Settings_not_initialized" xml:space="preserve">
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root"
xmlns="">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="Settings_not_initialized" xml:space="preserve">
<value>Settings are not initialized!</value>
</data>
</root>

View File

@@ -1,42 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>default</LangVersion>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-rc.2.24474.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0-rc.2.24474.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-rc.2.24474.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="2.0.0-preview1-final" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0-rc.2.24473.5" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-rc.2.24474.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0-rc.2.24474.1"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-rc.2.24474.1"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="2.0.0-preview1-final"/>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0-rc.2.24473.5"/>
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations" />
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RomRepoMgr.Settings\RomRepoMgr.Settings.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RomRepoMgr.Settings\RomRepoMgr.Settings.csproj"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Language.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Language.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@@ -43,344 +43,380 @@ using System.Runtime.InteropServices;
using System.Security.Principal;
using RomRepoMgr.Settings.Resources;
namespace Aaru.CommonTypes.Interop
namespace Aaru.CommonTypes.Interop;
public static class DetectOS
{
public static class DetectOS
public static readonly bool IsMono =
RuntimeInformation.FrameworkDescription.StartsWith("Mono", StringComparison.Ordinal);
public static readonly bool IsNetFramework =
RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.Ordinal);
public static readonly bool IsNetCore =
RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.Ordinal);
public static readonly bool IsNetNative =
RuntimeInformation.FrameworkDescription.StartsWith(".NET Native", StringComparison.Ordinal);
/// <summary>Checks if the underlying runtime runs in 64-bit mode</summary>
public static readonly bool Is64Bit = IntPtr.Size == 8;
/// <summary>Checks if the underlying runtime runs in 32-bit mode</summary>
public static readonly bool Is32Bit = IntPtr.Size == 4;
public static bool IsWindows => GetRealPlatformID() == PlatformID.Win32NT ||
GetRealPlatformID() == PlatformID.Win32S ||
GetRealPlatformID() == PlatformID.Win32Windows ||
GetRealPlatformID() == PlatformID.WinCE ||
GetRealPlatformID() == PlatformID.WindowsPhone ||
GetRealPlatformID() == PlatformID.Xbox;
public static bool IsAdmin
{
public static readonly bool IsMono =
RuntimeInformation.FrameworkDescription.StartsWith("Mono", StringComparison.Ordinal);
public static readonly bool IsNetFramework =
RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.Ordinal);
public static readonly bool IsNetCore =
RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.Ordinal);
public static readonly bool IsNetNative =
RuntimeInformation.FrameworkDescription.StartsWith(".NET Native", StringComparison.Ordinal);
/// <summary>Checks if the underlying runtime runs in 64-bit mode</summary>
public static readonly bool Is64Bit = IntPtr.Size == 8;
/// <summary>Checks if the underlying runtime runs in 32-bit mode</summary>
public static readonly bool Is32Bit = IntPtr.Size == 4;
public static bool IsWindows => GetRealPlatformID() == PlatformID.Win32NT ||
GetRealPlatformID() == PlatformID.Win32S ||
GetRealPlatformID() == PlatformID.Win32Windows ||
GetRealPlatformID() == PlatformID.WinCE ||
GetRealPlatformID() == PlatformID.WindowsPhone ||
GetRealPlatformID() == PlatformID.Xbox;
public static bool IsAdmin
get
{
get
if(!OperatingSystem.IsWindows()) return Environment.UserName == "root";
bool isAdmin;
WindowsIdentity user = null;
try
{
if(!OperatingSystem.IsWindows())
return Environment.UserName == "root";
bool isAdmin;
WindowsIdentity user = null;
try
{
user = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(user);
isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch(UnauthorizedAccessException)
{
isAdmin = false;
}
catch(Exception)
{
isAdmin = false;
}
finally
{
user?.Dispose();
}
return isAdmin;
user = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(user);
isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
[DllImport("libc", SetLastError = true)]
static extern int uname(out utsname name);
[DllImport("libc", SetLastError = true, EntryPoint = "sysctlbyname", CharSet = CharSet.Ansi)]
static extern int OSX_sysctlbyname(string name, IntPtr oldp, IntPtr oldlenp, IntPtr newp, uint newlen);
/// <summary>Gets the real platform ID, not the incomplete .NET framework one</summary>
/// <returns>Platform ID</returns>
/// <exception cref="Exception">Unhandled exception</exception>
public static PlatformID GetRealPlatformID()
{
if((int)Environment.OSVersion.Platform < 4 ||
(int)Environment.OSVersion.Platform == 5)
return (PlatformID)(int)Environment.OSVersion.Platform;
int error = uname(out utsname unixname);
if(error != 0)
throw new Exception(string.Format(Localization.Unhandled_exception_uname, Marshal.GetLastWin32Error()));
switch(unixname.sysname)
catch(UnauthorizedAccessException)
{
// TODO: Differentiate Linux, Android, Tizen
case "Linux":
{
#if __ANDROID__
isAdmin = false;
}
catch(Exception)
{
isAdmin = false;
}
finally
{
user?.Dispose();
}
return isAdmin;
}
}
[DllImport("libc", SetLastError = true)]
static extern int uname(out utsname name);
[DllImport("libc", SetLastError = true, EntryPoint = "sysctlbyname", CharSet = CharSet.Ansi)]
static extern int OSX_sysctlbyname(string name, IntPtr oldp, IntPtr oldlenp, IntPtr newp, uint newlen);
/// <summary>Gets the real platform ID, not the incomplete .NET framework one</summary>
/// <returns>Platform ID</returns>
/// <exception cref="Exception">Unhandled exception</exception>
public static PlatformID GetRealPlatformID()
{
if((int)Environment.OSVersion.Platform < 4 || (int)Environment.OSVersion.Platform == 5)
return (PlatformID)(int)Environment.OSVersion.Platform;
int error = uname(out utsname unixname);
if(error != 0)
throw new Exception(string.Format(Localization.Unhandled_exception_uname, Marshal.GetLastWin32Error()));
switch(unixname.sysname)
{
// TODO: Differentiate Linux, Android, Tizen
case "Linux":
{
#if __ANDROID__
return PlatformID.Android;
#else
return PlatformID.Linux;
#endif
#else
return PlatformID.Linux;
#endif
}
case "Darwin":
{
IntPtr pLen = Marshal.AllocHGlobal(sizeof(int));
int osxError = OSX_sysctlbyname("hw.machine", IntPtr.Zero, pLen, IntPtr.Zero, 0);
if(osxError != 0)
{
Marshal.FreeHGlobal(pLen);
throw new Exception(string.Format(Localization.Unhandled_exception_uname,
Marshal.GetLastWin32Error()));
}
case "Darwin":
int length = Marshal.ReadInt32(pLen);
IntPtr pStr = Marshal.AllocHGlobal(length);
osxError = OSX_sysctlbyname("hw.machine", pStr, pLen, IntPtr.Zero, 0);
if(osxError != 0)
{
IntPtr pLen = Marshal.AllocHGlobal(sizeof(int));
int osxError = OSX_sysctlbyname("hw.machine", IntPtr.Zero, pLen, IntPtr.Zero, 0);
if(osxError != 0)
{
Marshal.FreeHGlobal(pLen);
throw new Exception(string.Format(Localization.Unhandled_exception_uname,
Marshal.GetLastWin32Error()));
}
int length = Marshal.ReadInt32(pLen);
IntPtr pStr = Marshal.AllocHGlobal(length);
osxError = OSX_sysctlbyname("hw.machine", pStr, pLen, IntPtr.Zero, 0);
if(osxError != 0)
{
Marshal.FreeHGlobal(pStr);
Marshal.FreeHGlobal(pLen);
throw new Exception(string.Format(Localization.Unhandled_exception_uname,
Marshal.GetLastWin32Error()));
}
string machine = Marshal.PtrToStringAnsi(pStr);
Marshal.FreeHGlobal(pStr);
Marshal.FreeHGlobal(pLen);
if(machine != null &&
(machine.StartsWith("iPad", StringComparison.Ordinal) ||
machine.StartsWith("iPod", StringComparison.Ordinal) ||
machine.StartsWith("iPhone", StringComparison.Ordinal)))
return PlatformID.iOS;
return PlatformID.MacOSX;
throw new Exception(string.Format(Localization.Unhandled_exception_uname,
Marshal.GetLastWin32Error()));
}
case "GNU": return PlatformID.Hurd;
case "FreeBSD":
case "GNU/kFreeBSD": return PlatformID.FreeBSD;
case "DragonFly": return PlatformID.DragonFly;
case "Haiku": return PlatformID.Haiku;
case "HP-UX": return PlatformID.HPUX;
case "AIX": return PlatformID.AIX;
case "OS400": return PlatformID.OS400;
case "IRIX":
case "IRIX64": return PlatformID.IRIX;
case "Minix": return PlatformID.Minix;
case "NetBSD": return PlatformID.NetBSD;
case "NONSTOP_KERNEL": return PlatformID.NonStop;
case "OpenBSD": return PlatformID.OpenBSD;
case "QNX": return PlatformID.QNX;
case "SINIX-Y": return PlatformID.SINIX;
case "SunOS": return PlatformID.Solaris;
case "OSF1": return PlatformID.Tru64;
case "ULTRIX": return PlatformID.Ultrix;
case "SCO_SV": return PlatformID.OpenServer;
case "UnixWare": return PlatformID.UnixWare;
case "Interix":
case "UWIN-W7": return PlatformID.Win32NT;
default:
{
if(unixname.sysname.StartsWith("CYGWIN_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("MINGW32_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("MSYS_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("UWIN", StringComparison.Ordinal))
return PlatformID.Win32NT;
string machine = Marshal.PtrToStringAnsi(pStr);
return PlatformID.Unknown;
}
Marshal.FreeHGlobal(pStr);
Marshal.FreeHGlobal(pLen);
if(machine != null &&
(machine.StartsWith("iPad", StringComparison.Ordinal) ||
machine.StartsWith("iPod", StringComparison.Ordinal) ||
machine.StartsWith("iPhone", StringComparison.Ordinal)))
return PlatformID.iOS;
return PlatformID.MacOSX;
}
}
/// <summary>Gets a string for the current operating system REAL version (handles Darwin 1.4 and Windows 10 falsifying)</summary>
/// <returns>Current operating system version</returns>
public static string GetVersion()
{
string environ = Environment.OSVersion.Version.ToString();
switch(GetRealPlatformID())
case "GNU":
return PlatformID.Hurd;
case "FreeBSD":
case "GNU/kFreeBSD":
return PlatformID.FreeBSD;
case "DragonFly":
return PlatformID.DragonFly;
case "Haiku":
return PlatformID.Haiku;
case "HP-UX":
return PlatformID.HPUX;
case "AIX":
return PlatformID.AIX;
case "OS400":
return PlatformID.OS400;
case "IRIX":
case "IRIX64":
return PlatformID.IRIX;
case "Minix":
return PlatformID.Minix;
case "NetBSD":
return PlatformID.NetBSD;
case "NONSTOP_KERNEL":
return PlatformID.NonStop;
case "OpenBSD":
return PlatformID.OpenBSD;
case "QNX":
return PlatformID.QNX;
case "SINIX-Y":
return PlatformID.SINIX;
case "SunOS":
return PlatformID.Solaris;
case "OSF1":
return PlatformID.Tru64;
case "ULTRIX":
return PlatformID.Ultrix;
case "SCO_SV":
return PlatformID.OpenServer;
case "UnixWare":
return PlatformID.UnixWare;
case "Interix":
case "UWIN-W7":
return PlatformID.Win32NT;
default:
{
case PlatformID.MacOSX:
if(Environment.OSVersion.Version.Major != 1)
return $"10.{Environment.OSVersion.Version.Major - 4}.{Environment.OSVersion.Version.Minor}";
if(unixname.sysname.StartsWith("CYGWIN_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("MINGW32_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("MSYS_NT", StringComparison.Ordinal) ||
unixname.sysname.StartsWith("UWIN", StringComparison.Ordinal))
return PlatformID.Win32NT;
switch(Environment.OSVersion.Version.Minor)
{
case 3: return "10.0";
case 4: return "10.1";
}
goto default;
case PlatformID.Win32NT:
// From Windows 8.1 the reported version is simply falsified...
if((Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Major >= 2) ||
Environment.OSVersion.Version.Major > 6)
return FileVersionInfo.
GetVersionInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),
"KERNEL32.DLL")).ProductVersion;
return environ;
default: return environ;
return PlatformID.Unknown;
}
}
/// <summary>From a platform ID and version returns a human-readable version</summary>
/// <param name="id">Platform ID</param>
/// <param name="version">Version number</param>
/// <returns>Operating system name</returns>
public static string GetPlatformName(PlatformID id, string version = null)
{
switch(id)
{
case PlatformID.AIX: return "AIX";
case PlatformID.Android: return "Android";
case PlatformID.DragonFly: return "DragonFly BSD";
case PlatformID.FreeBSD: return "FreeBSD";
case PlatformID.Haiku: return "Haiku";
case PlatformID.HPUX: return "HP/UX";
case PlatformID.Hurd: return "Hurd";
case PlatformID.iOS: return "iOS";
case PlatformID.IRIX: return "IRIX";
case PlatformID.Linux:
if(!File.Exists("/proc/version"))
return "Linux";
string s = File.ReadAllText("/proc/version");
return s.Contains("Microsoft") || s.Contains("WSL") ? "Windows Subsystem for Linux" : "Linux";
case PlatformID.MacOSX:
if(string.IsNullOrEmpty(version))
return "macOS";
string[] pieces = version.Split('.');
if(pieces.Length < 2 ||
!int.TryParse(pieces[1], out int minor))
return "macOS";
if(minor >= 12)
return "macOS";
if(minor >= 8)
return "OS X";
return "Mac OS X";
case PlatformID.Minix: return "MINIX";
case PlatformID.NetBSD: return "NetBSD";
case PlatformID.NonStop: return "NonStop OS";
case PlatformID.OpenBSD: return "OpenBSD";
case PlatformID.OpenServer: return "SCO OpenServer";
case PlatformID.OS400: return "OS/400";
case PlatformID.PlayStation3: return "Sony CellOS";
case PlatformID.PlayStation4: return "Sony Orbis OS";
case PlatformID.QNX: return "QNX";
case PlatformID.SINIX: return "SINIX";
case PlatformID.Solaris: return "Sun Solaris";
case PlatformID.Tizen: return "Samsung Tizen";
case PlatformID.Tru64: return "Tru64 UNIX";
case PlatformID.Ultrix: return "Ultrix";
case PlatformID.Unix: return "UNIX";
case PlatformID.UnixWare: return "SCO UnixWare";
case PlatformID.Wii: return "Nintendo Wii";
case PlatformID.WiiU: return "Nintendo Wii U";
case PlatformID.Win32NT:
if(string.IsNullOrEmpty(version))
return "Windows NT/2000/XP/Vista/7/10";
if(version.StartsWith("3.", StringComparison.Ordinal) ||
version.StartsWith("4.", StringComparison.Ordinal))
return "Windows NT";
if(version.StartsWith("5.0", StringComparison.Ordinal))
return "Windows 2000";
if(version.StartsWith("5.1", StringComparison.Ordinal))
return "Windows XP";
if(version.StartsWith("5.2", StringComparison.Ordinal))
return "Windows 2003";
if(version.StartsWith("6.0", StringComparison.Ordinal))
return "Windows Vista";
if(version.StartsWith("6.1", StringComparison.Ordinal))
return "Windows 7";
if(version.StartsWith("6.2", StringComparison.Ordinal))
return "Windows 8";
if(version.StartsWith("6.3", StringComparison.Ordinal))
return "Windows 8.1";
if(version.StartsWith("10.0", StringComparison.Ordinal))
return "Windows 10";
return "Windows NT/2000/XP/Vista/7/10";
case PlatformID.Win32S: return "Windows 3.x with win32s";
case PlatformID.Win32Windows:
if(string.IsNullOrEmpty(version))
return "Windows 9x/Me";
if(version.StartsWith("4.0", StringComparison.Ordinal))
return "Windows 95";
if(version.StartsWith("4.10.2222", StringComparison.Ordinal))
return "Windows 98 SE";
if(version.StartsWith("4.1", StringComparison.Ordinal))
return "Windows 98";
if(version.StartsWith("4.9", StringComparison.Ordinal))
return "Windows Me";
return "Windows 9x/Me";
case PlatformID.WinCE: return "Windows CE/Mobile";
case PlatformID.WindowsPhone: return "Windows Phone";
case PlatformID.Xbox: return "Xbox OS";
case PlatformID.zOS: return "z/OS";
default: return id.ToString();
}
}
/// <summary>POSIX uname structure, size from OSX, big enough to handle extra fields</summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct utsname
{
/// <summary>System name</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string sysname;
/// <summary>Node name</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string nodename;
/// <summary>Release level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string release;
/// <summary>Version level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string version;
/// <summary>Hardware level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string machine;
}
}
/// <summary>Gets a string for the current operating system REAL version (handles Darwin 1.4 and Windows 10 falsifying)</summary>
/// <returns>Current operating system version</returns>
public static string GetVersion()
{
var environ = Environment.OSVersion.Version.ToString();
switch(GetRealPlatformID())
{
case PlatformID.MacOSX:
if(Environment.OSVersion.Version.Major != 1)
return $"10.{Environment.OSVersion.Version.Major - 4}.{Environment.OSVersion.Version.Minor}";
switch(Environment.OSVersion.Version.Minor)
{
case 3:
return "10.0";
case 4:
return "10.1";
}
goto default;
case PlatformID.Win32NT:
// From Windows 8.1 the reported version is simply falsified...
if(Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Major >= 2 ||
Environment.OSVersion.Version.Major > 6)
{
return FileVersionInfo
.GetVersionInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),
"KERNEL32.DLL"))
.ProductVersion;
}
return environ;
default:
return environ;
}
}
/// <summary>From a platform ID and version returns a human-readable version</summary>
/// <param name="id">Platform ID</param>
/// <param name="version">Version number</param>
/// <returns>Operating system name</returns>
public static string GetPlatformName(PlatformID id, string version = null)
{
switch(id)
{
case PlatformID.AIX:
return "AIX";
case PlatformID.Android:
return "Android";
case PlatformID.DragonFly:
return "DragonFly BSD";
case PlatformID.FreeBSD:
return "FreeBSD";
case PlatformID.Haiku:
return "Haiku";
case PlatformID.HPUX:
return "HP/UX";
case PlatformID.Hurd:
return "Hurd";
case PlatformID.iOS:
return "iOS";
case PlatformID.IRIX:
return "IRIX";
case PlatformID.Linux:
if(!File.Exists("/proc/version")) return "Linux";
string s = File.ReadAllText("/proc/version");
return s.Contains("Microsoft") || s.Contains("WSL") ? "Windows Subsystem for Linux" : "Linux";
case PlatformID.MacOSX:
if(string.IsNullOrEmpty(version)) return "macOS";
string[] pieces = version.Split('.');
if(pieces.Length < 2 || !int.TryParse(pieces[1], out int minor)) return "macOS";
if(minor >= 12) return "macOS";
if(minor >= 8) return "OS X";
return "Mac OS X";
case PlatformID.Minix:
return "MINIX";
case PlatformID.NetBSD:
return "NetBSD";
case PlatformID.NonStop:
return "NonStop OS";
case PlatformID.OpenBSD:
return "OpenBSD";
case PlatformID.OpenServer:
return "SCO OpenServer";
case PlatformID.OS400:
return "OS/400";
case PlatformID.PlayStation3:
return "Sony CellOS";
case PlatformID.PlayStation4:
return "Sony Orbis OS";
case PlatformID.QNX:
return "QNX";
case PlatformID.SINIX:
return "SINIX";
case PlatformID.Solaris:
return "Sun Solaris";
case PlatformID.Tizen:
return "Samsung Tizen";
case PlatformID.Tru64:
return "Tru64 UNIX";
case PlatformID.Ultrix:
return "Ultrix";
case PlatformID.Unix:
return "UNIX";
case PlatformID.UnixWare:
return "SCO UnixWare";
case PlatformID.Wii:
return "Nintendo Wii";
case PlatformID.WiiU:
return "Nintendo Wii U";
case PlatformID.Win32NT:
if(string.IsNullOrEmpty(version)) return "Windows NT/2000/XP/Vista/7/10";
if(version.StartsWith("3.", StringComparison.Ordinal) ||
version.StartsWith("4.", StringComparison.Ordinal))
return "Windows NT";
if(version.StartsWith("5.0", StringComparison.Ordinal)) return "Windows 2000";
if(version.StartsWith("5.1", StringComparison.Ordinal)) return "Windows XP";
if(version.StartsWith("5.2", StringComparison.Ordinal)) return "Windows 2003";
if(version.StartsWith("6.0", StringComparison.Ordinal)) return "Windows Vista";
if(version.StartsWith("6.1", StringComparison.Ordinal)) return "Windows 7";
if(version.StartsWith("6.2", StringComparison.Ordinal)) return "Windows 8";
if(version.StartsWith("6.3", StringComparison.Ordinal)) return "Windows 8.1";
if(version.StartsWith("10.0", StringComparison.Ordinal)) return "Windows 10";
return "Windows NT/2000/XP/Vista/7/10";
case PlatformID.Win32S:
return "Windows 3.x with win32s";
case PlatformID.Win32Windows:
if(string.IsNullOrEmpty(version)) return "Windows 9x/Me";
if(version.StartsWith("4.0", StringComparison.Ordinal)) return "Windows 95";
if(version.StartsWith("4.10.2222", StringComparison.Ordinal)) return "Windows 98 SE";
if(version.StartsWith("4.1", StringComparison.Ordinal)) return "Windows 98";
if(version.StartsWith("4.9", StringComparison.Ordinal)) return "Windows Me";
return "Windows 9x/Me";
case PlatformID.WinCE:
return "Windows CE/Mobile";
case PlatformID.WindowsPhone:
return "Windows Phone";
case PlatformID.Xbox:
return "Xbox OS";
case PlatformID.zOS:
return "z/OS";
default:
return id.ToString();
}
}
/// <summary>POSIX uname structure, size from OSX, big enough to handle extra fields</summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct utsname
{
/// <summary>System name</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string sysname;
/// <summary>Node name</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string nodename;
/// <summary>Release level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string release;
/// <summary>Version level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string version;
/// <summary>Hardware level</summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public readonly string machine;
}
}

View File

@@ -38,83 +38,83 @@
using System.Diagnostics.CodeAnalysis;
namespace Aaru.CommonTypes.Interop
namespace Aaru.CommonTypes.Interop;
/// <summary>Contains an arbitrary list of OSes, even if .NET does not run on them</summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum PlatformID
{
/// <summary>Contains an arbitrary list of OSes, even if .NET does not run on them</summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum PlatformID
{
/// <summary>Win32s</summary>
Win32S = 0,
/// <summary>Win32 (Windows 9x)</summary>
Win32Windows = 1,
/// <summary>Windows NT</summary>
Win32NT = 2,
/// <summary>Windows Mobile</summary>
WinCE = 3,
/// <summary>UNIX (do not use, too generic)</summary>
Unix = 4,
/// <summary>Xbox 360</summary>
Xbox = 5,
/// <summary>OS X</summary>
MacOSX = 6,
/// <summary>iOS is not OS X</summary>
iOS = 7,
/// <summary>Linux</summary>
Linux = 8,
/// <summary>Sun Solaris</summary>
Solaris = 9,
/// <summary>NetBSD</summary>
NetBSD = 10,
/// <summary>OpenBSD</summary>
OpenBSD = 11,
/// <summary>FreeBSD</summary>
FreeBSD = 12,
/// <summary>DragonFly BSD</summary>
DragonFly = 13,
/// <summary>Nintendo Wii</summary>
Wii = 14,
/// <summary>Nintendo Wii U</summary>
WiiU = 15,
/// <summary>Sony PlayStation 3</summary>
PlayStation3 = 16,
/// <summary>Sony Playstation 4</summary>
PlayStation4 = 17,
/// <summary>Google Android</summary>
Android = 18,
/// <summary>Samsung Tizen</summary>
Tizen = 19,
/// <summary>Windows Phone</summary>
WindowsPhone = 20,
/// <summary>GNU/Hurd</summary>
Hurd = 21,
/// <summary>Haiku</summary>
Haiku = 22,
/// <summary>HP-UX</summary>
HPUX = 23,
/// <summary>AIX</summary>
AIX = 24,
/// <summary>OS/400</summary>
OS400 = 25,
/// <summary>IRIX</summary>
IRIX = 26,
/// <summary>Minix</summary>
Minix = 27,
/// <summary>NonStop</summary>
NonStop = 28,
/// <summary>QNX</summary>
QNX = 29,
/// <summary>SINIX</summary>
SINIX = 30,
/// <summary>Tru64 UNIX</summary>
Tru64 = 31,
/// <summary>Ultrix</summary>
Ultrix = 32,
/// <summary>SCO OpenServer / SCO UNIX</summary>
OpenServer = 33,
/// <summary>SCO UnixWare</summary>
UnixWare = 34,
/// <summary>IBM z/OS</summary>
zOS = 35, Unknown = -1
}
/// <summary>Win32s</summary>
Win32S = 0,
/// <summary>Win32 (Windows 9x)</summary>
Win32Windows = 1,
/// <summary>Windows NT</summary>
Win32NT = 2,
/// <summary>Windows Mobile</summary>
WinCE = 3,
/// <summary>UNIX (do not use, too generic)</summary>
Unix = 4,
/// <summary>Xbox 360</summary>
Xbox = 5,
/// <summary>OS X</summary>
MacOSX = 6,
/// <summary>iOS is not OS X</summary>
iOS = 7,
/// <summary>Linux</summary>
Linux = 8,
/// <summary>Sun Solaris</summary>
Solaris = 9,
/// <summary>NetBSD</summary>
NetBSD = 10,
/// <summary>OpenBSD</summary>
OpenBSD = 11,
/// <summary>FreeBSD</summary>
FreeBSD = 12,
/// <summary>DragonFly BSD</summary>
DragonFly = 13,
/// <summary>Nintendo Wii</summary>
Wii = 14,
/// <summary>Nintendo Wii U</summary>
WiiU = 15,
/// <summary>Sony PlayStation 3</summary>
PlayStation3 = 16,
/// <summary>Sony Playstation 4</summary>
PlayStation4 = 17,
/// <summary>Google Android</summary>
Android = 18,
/// <summary>Samsung Tizen</summary>
Tizen = 19,
/// <summary>Windows Phone</summary>
WindowsPhone = 20,
/// <summary>GNU/Hurd</summary>
Hurd = 21,
/// <summary>Haiku</summary>
Haiku = 22,
/// <summary>HP-UX</summary>
HPUX = 23,
/// <summary>AIX</summary>
AIX = 24,
/// <summary>OS/400</summary>
OS400 = 25,
/// <summary>IRIX</summary>
IRIX = 26,
/// <summary>Minix</summary>
Minix = 27,
/// <summary>NonStop</summary>
NonStop = 28,
/// <summary>QNX</summary>
QNX = 29,
/// <summary>SINIX</summary>
SINIX = 30,
/// <summary>Tru64 UNIX</summary>
Tru64 = 31,
/// <summary>Ultrix</summary>
Ultrix = 32,
/// <summary>SCO OpenServer / SCO UNIX</summary>
OpenServer = 33,
/// <summary>SCO UnixWare</summary>
UnixWare = 34,
/// <summary>IBM z/OS</summary>
zOS = 35,
Unknown = -1
}

View File

@@ -40,44 +40,40 @@ using System;
using System.Reflection;
using System.Runtime;
namespace Aaru.CommonTypes.Interop
namespace Aaru.CommonTypes.Interop;
public static class Version
{
public static class Version
/// <summary>Gets version string</summary>
/// <returns>Version</returns>
public static string GetVersion() => typeof(Version).Assembly.GetName().Version?.ToString();
public static string GetNetCoreVersion()
{
/// <summary>Gets version string</summary>
/// <returns>Version</returns>
public static string GetVersion() => typeof(Version).Assembly.GetName().Version?.ToString();
Assembly assembly = typeof(GCSettings).Assembly;
public static string GetNetCoreVersion()
{
Assembly assembly = typeof(GCSettings).Assembly;
string[] assemblyPath = assembly.Location.Split(new[]
{
'/', '\\'
},
StringSplitOptions.RemoveEmptyEntries);
string[] assemblyPath = assembly.Location.Split(new[]
{
'/', '\\'
}, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if(netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2) return assemblyPath[netCoreAppIndex + 1];
if(netCoreAppIndex > 0 &&
netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];
return null;
}
return null;
}
public static string GetMonoVersion()
{
if(!DetectOS.IsMono) return null;
public static string GetMonoVersion()
{
if(!DetectOS.IsMono)
return null;
MethodInfo monoDisplayName = Type.GetType("Mono.Runtime")
?.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo monoDisplayName = Type.GetType("Mono.Runtime")?.
GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if(monoDisplayName != null) return (string)monoDisplayName.Invoke(null, null);
if(monoDisplayName != null)
return (string)monoDisplayName.Invoke(null, null);
return null;
}
return null;
}
}

View File

@@ -11,32 +11,46 @@ namespace RomRepoMgr.Settings.Resources {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Localization {
private static System.Resources.ResourceManager resourceMan;
private static global::System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
private static global::System.Globalization.CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Localization() {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager {
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("RomRepoMgr.Settings.Resources.Localization", typeof(Localization).Assembly);
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RomRepoMgr.Settings.Resources.Localization", typeof(Localization).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture {
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
@@ -45,6 +59,9 @@ namespace RomRepoMgr.Settings.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Unhandled exception calling uname: {0}.
/// </summary>
internal static string Unhandled_exception_uname {
get {
return ResourceManager.GetString("Unhandled_exception_uname", resourceCulture);

View File

@@ -1,17 +1,21 @@
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Unhandled_exception_uname" xml:space="preserve">
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="Unhandled_exception_uname" xml:space="preserve">
<value>Excepción no controlada llamando a uname: {0}</value>
</data>
</root>

View File

@@ -1,22 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Unhandled_exception_uname" xml:space="preserve">
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root"
xmlns="">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="Unhandled_exception_uname" xml:space="preserve">
<value>Unhandled exception calling uname: {0}</value>
</data>
</root>

View File

@@ -1,28 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>default</LangVersion>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="plist-cil" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0"/>
<PackageReference Include="plist-cil" Version="2.1.0"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Localization.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Localization.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@@ -31,280 +31,285 @@ using Claunia.PropertyList;
using Microsoft.Win32;
using PlatformID = Aaru.CommonTypes.Interop.PlatformID;
namespace RomRepoMgr.Settings
namespace RomRepoMgr.Settings;
public sealed class SetSettings
{
public sealed class SetSettings
public string DatabasePath { get; set; }
public string RepositoryPath { get; set; }
public string TemporaryFolder { get; set; }
public string UnArchiverPath { get; set; }
}
/// <summary>Manages statistics</summary>
public static class Settings
{
const string XDG_CONFIG_HOME = "XDG_CONFIG_HOME";
const string XDG_CONFIG_HOME_RESOLVED = ".config";
/// <summary>Current statistics</summary>
public static SetSettings Current;
public static bool UnArUsable { get; set; }
/// <summary>Loads settings</summary>
public static void LoadSettings()
{
public string DatabasePath { get; set; }
public string RepositoryPath { get; set; }
public string TemporaryFolder { get; set; }
public string UnArchiverPath { get; set; }
Current = new SetSettings();
PlatformID ptId = DetectOS.GetRealPlatformID();
string homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
FileStream prefsFs = null;
StreamReader prefsSr = null;
try
{
switch(ptId)
{
// In case of macOS or iOS settings will be saved in ~/Library/Preferences/com.claunia.romrepomgr.plist
case PlatformID.MacOSX:
case PlatformID.iOS:
{
string preferencesPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Library",
"Preferences");
string preferencesFilePath = Path.Combine(preferencesPath, "com.claunia.romrepomgr.plist");
if(!File.Exists(preferencesFilePath))
{
SetDefaultSettings();
SaveSettings();
}
prefsFs = new FileStream(preferencesFilePath, FileMode.Open, FileAccess.Read);
var parsedPreferences = (NSDictionary)BinaryPropertyListParser.Parse(prefsFs);
if(parsedPreferences != null)
{
NSObject obj;
Current.DatabasePath = parsedPreferences.TryGetValue("DatabasePath", out obj)
? ((NSString)obj).ToString()
: null;
Current.RepositoryPath = parsedPreferences.TryGetValue("RepositoryPath", out obj)
? ((NSString)obj).ToString()
: null;
Current.TemporaryFolder = parsedPreferences.TryGetValue("TemporaryFolder", out obj)
? ((NSString)obj).ToString()
: null;
Current.UnArchiverPath = parsedPreferences.TryGetValue("UnArchiverPath", out obj)
? ((NSString)obj).ToString()
: null;
prefsFs.Close();
}
else
{
prefsFs.Close();
SetDefaultSettings();
SaveSettings();
}
}
break;
#if !NETSTANDARD2_0
// In case of Windows settings will be saved in the registry: HKLM/SOFTWARE/Claunia.com/RomRepoMgr
case PlatformID.Win32NT when OperatingSystem.IsWindows():
case PlatformID.Win32S when OperatingSystem.IsWindows():
case PlatformID.Win32Windows when OperatingSystem.IsWindows():
case PlatformID.WinCE when OperatingSystem.IsWindows():
case PlatformID.WindowsPhone when OperatingSystem.IsWindows():
{
RegistryKey parentKey = Registry.CurrentUser.OpenSubKey("SOFTWARE")?.OpenSubKey("Claunia.com");
if(parentKey == null)
{
SetDefaultSettings();
SaveSettings();
return;
}
RegistryKey key = parentKey.OpenSubKey("RomRepoMgr");
if(key == null)
{
SetDefaultSettings();
SaveSettings();
return;
}
Current.DatabasePath = key.GetValue("DatabasePath") as string;
Current.RepositoryPath = key.GetValue("RepositoryPath") as string;
Current.TemporaryFolder = key.GetValue("TemporaryFolder") as string;
Current.UnArchiverPath = key.GetValue("UnArchiverPath") as string;
}
break;
#endif
// Otherwise, settings will be saved in ~/.config/RomRepoMgr.json
default:
{
string xdgConfigPath = Path.Combine(homePath,
Environment.GetEnvironmentVariable(XDG_CONFIG_HOME) ??
XDG_CONFIG_HOME_RESOLVED);
string settingsPath = Path.Combine(xdgConfigPath, "RomRepoMgr.json");
if(!File.Exists(settingsPath))
{
SetDefaultSettings();
SaveSettings();
return;
}
prefsSr = new StreamReader(settingsPath);
Current = JsonSerializer.Deserialize<SetSettings>(prefsSr.ReadToEnd(),
new JsonSerializerOptions
{
AllowTrailingCommas = true,
PropertyNameCaseInsensitive = true,
ReadCommentHandling =
JsonCommentHandling.Skip,
WriteIndented = true
});
}
break;
}
}
catch
{
prefsFs?.Close();
prefsSr?.Close();
SetDefaultSettings();
SaveSettings();
}
}
/// <summary>Manages statistics</summary>
public static class Settings
public static void SaveSettings()
{
const string XDG_CONFIG_HOME = "XDG_CONFIG_HOME";
const string XDG_CONFIG_HOME_RESOLVED = ".config";
/// <summary>Current statistics</summary>
public static SetSettings Current;
public static bool UnArUsable { get; set; }
/// <summary>Loads settings</summary>
public static void LoadSettings()
try
{
Current = new SetSettings();
PlatformID ptId = DetectOS.GetRealPlatformID();
string homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
PlatformID ptId = DetectOS.GetRealPlatformID();
FileStream prefsFs = null;
StreamReader prefsSr = null;
try
switch(ptId)
{
switch(ptId)
// In case of macOS or iOS settings will be saved in ~/Library/Preferences/com.claunia.romrepomgr.plist
case PlatformID.MacOSX:
case PlatformID.iOS:
{
// In case of macOS or iOS settings will be saved in ~/Library/Preferences/com.claunia.romrepomgr.plist
case PlatformID.MacOSX:
case PlatformID.iOS:
var root = new NSDictionary
{
string preferencesPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library",
"Preferences");
string preferencesFilePath = Path.Combine(preferencesPath, "com.claunia.romrepomgr.plist");
if(!File.Exists(preferencesFilePath))
{
SetDefaultSettings();
SaveSettings();
"DatabasePath", Current.DatabasePath
},
{
"RepositoryPath", Current.RepositoryPath
},
{
"TemporaryFolder", Current.TemporaryFolder
},
{
"UnArchiverPath", Current.UnArchiverPath
}
};
prefsFs = new FileStream(preferencesFilePath, FileMode.Open, FileAccess.Read);
string preferencesPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Library",
"Preferences");
var parsedPreferences = (NSDictionary)BinaryPropertyListParser.Parse(prefsFs);
string preferencesFilePath = Path.Combine(preferencesPath, "com.claunia.romrepomgr.plist");
if(parsedPreferences != null)
{
NSObject obj;
Current.DatabasePath = parsedPreferences.TryGetValue("DatabasePath", out obj)
? ((NSString)obj).ToString() : null;
Current.RepositoryPath = parsedPreferences.TryGetValue("RepositoryPath", out obj)
? ((NSString)obj).ToString() : null;
Current.TemporaryFolder = parsedPreferences.TryGetValue("TemporaryFolder", out obj)
? ((NSString)obj).ToString() : null;
Current.UnArchiverPath = parsedPreferences.TryGetValue("UnArchiverPath", out obj)
? ((NSString)obj).ToString() : null;
prefsFs.Close();
}
else
{
prefsFs.Close();
SetDefaultSettings();
SaveSettings();
}
}
break;
#if !NETSTANDARD2_0
// In case of Windows settings will be saved in the registry: HKLM/SOFTWARE/Claunia.com/RomRepoMgr
case PlatformID.Win32NT when OperatingSystem.IsWindows():
case PlatformID.Win32S when OperatingSystem.IsWindows():
case PlatformID.Win32Windows when OperatingSystem.IsWindows():
case PlatformID.WinCE when OperatingSystem.IsWindows():
case PlatformID.WindowsPhone when OperatingSystem.IsWindows():
{
RegistryKey parentKey = Registry.CurrentUser.OpenSubKey("SOFTWARE")?.OpenSubKey("Claunia.com");
if(parentKey == null)
{
SetDefaultSettings();
SaveSettings();
return;
}
RegistryKey key = parentKey.OpenSubKey("RomRepoMgr");
if(key == null)
{
SetDefaultSettings();
SaveSettings();
return;
}
Current.DatabasePath = key.GetValue("DatabasePath") as string;
Current.RepositoryPath = key.GetValue("RepositoryPath") as string;
Current.TemporaryFolder = key.GetValue("TemporaryFolder") as string;
Current.UnArchiverPath = key.GetValue("UnArchiverPath") as string;
}
break;
#endif
// Otherwise, settings will be saved in ~/.config/RomRepoMgr.json
default:
{
string xdgConfigPath =
Path.Combine(homePath,
Environment.GetEnvironmentVariable(XDG_CONFIG_HOME) ??
XDG_CONFIG_HOME_RESOLVED);
string settingsPath = Path.Combine(xdgConfigPath, "RomRepoMgr.json");
if(!File.Exists(settingsPath))
{
SetDefaultSettings();
SaveSettings();
return;
}
prefsSr = new StreamReader(settingsPath);
Current = JsonSerializer.Deserialize<SetSettings>(prefsSr.ReadToEnd(), new JsonSerializerOptions
{
AllowTrailingCommas = true,
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true
});
}
break;
var fs = new FileStream(preferencesFilePath, FileMode.Create);
BinaryPropertyListWriter.Write(fs, root);
fs.Close();
}
}
catch
{
prefsFs?.Close();
prefsSr?.Close();
SetDefaultSettings();
SaveSettings();
}
}
public static void SaveSettings()
{
try
{
PlatformID ptId = DetectOS.GetRealPlatformID();
break;
#if !NETSTANDARD2_0
switch(ptId)
// In case of Windows settings will be saved in the registry: HKLM/SOFTWARE/Claunia.com/RomRepoMgr
case PlatformID.Win32NT when OperatingSystem.IsWindows():
case PlatformID.Win32S when OperatingSystem.IsWindows():
case PlatformID.Win32Windows when OperatingSystem.IsWindows():
case PlatformID.WinCE when OperatingSystem.IsWindows():
case PlatformID.WindowsPhone when OperatingSystem.IsWindows():
{
// In case of macOS or iOS settings will be saved in ~/Library/Preferences/com.claunia.romrepomgr.plist
case PlatformID.MacOSX:
case PlatformID.iOS:
{
var root = new NSDictionary
{
{
"DatabasePath", Current.DatabasePath
},
{
"RepositoryPath", Current.RepositoryPath
},
{
"TemporaryFolder", Current.TemporaryFolder
},
{
"UnArchiverPath", Current.UnArchiverPath
}
};
RegistryKey parentKey =
Registry.CurrentUser.OpenSubKey("SOFTWARE", true)?.CreateSubKey("Claunia.com");
string preferencesPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library",
"Preferences");
RegistryKey key = parentKey?.CreateSubKey("RomRepoMgr");
string preferencesFilePath = Path.Combine(preferencesPath, "com.claunia.romrepomgr.plist");
var fs = new FileStream(preferencesFilePath, FileMode.Create);
BinaryPropertyListWriter.Write(fs, root);
fs.Close();
}
break;
#if !NETSTANDARD2_0
// In case of Windows settings will be saved in the registry: HKLM/SOFTWARE/Claunia.com/RomRepoMgr
case PlatformID.Win32NT when OperatingSystem.IsWindows():
case PlatformID.Win32S when OperatingSystem.IsWindows():
case PlatformID.Win32Windows when OperatingSystem.IsWindows():
case PlatformID.WinCE when OperatingSystem.IsWindows():
case PlatformID.WindowsPhone when OperatingSystem.IsWindows():
{
RegistryKey parentKey = Registry.CurrentUser.OpenSubKey("SOFTWARE", true)?.
CreateSubKey("Claunia.com");
RegistryKey key = parentKey?.CreateSubKey("RomRepoMgr");
key?.SetValue("DatabasePath", Current.DatabasePath);
key?.SetValue("RepositoryPath", Current.RepositoryPath);
key?.SetValue("TemporaryFolder", Current.TemporaryFolder);
key?.SetValue("UnArchiverPath", Current.UnArchiverPath);
}
break;
#endif
// Otherwise, settings will be saved in ~/.config/RomRepoMgr.json
default:
{
string homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string xdgConfigPath =
Path.Combine(homePath,
Environment.GetEnvironmentVariable(XDG_CONFIG_HOME) ??
XDG_CONFIG_HOME_RESOLVED);
string settingsPath = Path.Combine(xdgConfigPath, "RomRepoMgr.json");
if(!Directory.Exists(xdgConfigPath))
Directory.CreateDirectory(xdgConfigPath);
var prefsSr = new StreamWriter(settingsPath);
prefsSr.Write(JsonSerializer.Serialize(Current, new JsonSerializerOptions
{
AllowTrailingCommas = true,
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true
}));
prefsSr.Close();
}
break;
key?.SetValue("DatabasePath", Current.DatabasePath);
key?.SetValue("RepositoryPath", Current.RepositoryPath);
key?.SetValue("TemporaryFolder", Current.TemporaryFolder);
key?.SetValue("UnArchiverPath", Current.UnArchiverPath);
}
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
{
// ignored
}
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
}
/// <summary>Sets default settings as all statistics, share everything</summary>
static void SetDefaultSettings()
break;
#endif
// Otherwise, settings will be saved in ~/.config/RomRepoMgr.json
default:
{
string homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string xdgConfigPath = Path.Combine(homePath,
Environment.GetEnvironmentVariable(XDG_CONFIG_HOME) ??
XDG_CONFIG_HOME_RESOLVED);
string settingsPath = Path.Combine(xdgConfigPath, "RomRepoMgr.json");
if(!Directory.Exists(xdgConfigPath)) Directory.CreateDirectory(xdgConfigPath);
var prefsSr = new StreamWriter(settingsPath);
prefsSr.Write(JsonSerializer.Serialize(Current,
new JsonSerializerOptions
{
AllowTrailingCommas = true,
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true
}));
prefsSr.Close();
}
break;
}
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
{
string docsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string dataPath = Path.Combine(docsPath, "RomRepoMgr");
Current = new SetSettings
{
DatabasePath = Path.Combine(dataPath, "romrepo.db"),
RepositoryPath = Path.Combine(dataPath, "repo"),
TemporaryFolder = Path.GetTempPath()
};
// ignored
}
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
}
/// <summary>Sets default settings as all statistics, share everything</summary>
static void SetDefaultSettings()
{
string docsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string dataPath = Path.Combine(docsPath, "RomRepoMgr");
Current = new SetSettings
{
DatabasePath = Path.Combine(dataPath, "romrepo.db"),
RepositoryPath = Path.Combine(dataPath, "repo"),
TemporaryFolder = Path.GetTempPath()
};
}
}

View File

@@ -1,5 +1,7 @@
<Application xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RomRepoMgr" x:Class="RomRepoMgr.App">
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RomRepoMgr"
x:Class="RomRepoMgr.App">
<Application.DataTemplates>
<local:ViewLocator />
</Application.DataTemplates>
@@ -10,9 +12,12 @@
</Application.Styles>
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="_About" Clicked="OnAboutClicked" />
<NativeMenuItem Header="_Preferences" Clicked="OnPreferencesClicked" />
<NativeMenuItem Header="_Quit" Clicked="OnQuitClicked" />
<NativeMenuItem Header="_About"
Clicked="OnAboutClicked" />
<NativeMenuItem Header="_Preferences"
Clicked="OnPreferencesClicked" />
<NativeMenuItem Header="_Quit"
Clicked="OnQuitClicked" />
</NativeMenu>
</NativeMenu.Menu>
</Application>

View File

@@ -34,79 +34,77 @@ using RomRepoMgr.Core.Models;
using RomRepoMgr.ViewModels;
using RomRepoMgr.Views;
namespace RomRepoMgr
namespace RomRepoMgr;
public class App : Application
{
public class App : Application
List<RomSetModel> _romSets;
public override void Initialize() => AvaloniaXamlLoader.Load(this);
public override void OnFrameworkInitializationCompleted()
{
List<RomSetModel> _romSets;
public override void Initialize() => AvaloniaXamlLoader.Load(this);
public override void OnFrameworkInitializationCompleted()
if(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
if(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
var splashWindow = new SplashWindow();
var swvm = new SplashWindowViewModel();
swvm.WorkFinished += OnSplashFinished;
swvm.GotRomSets += OnGotRomSets;
splashWindow.DataContext = swvm;
desktop.MainWindow = splashWindow;
}
base.OnFrameworkInitializationCompleted();
var splashWindow = new SplashWindow();
var swvm = new SplashWindowViewModel();
swvm.WorkFinished += OnSplashFinished;
swvm.GotRomSets += OnGotRomSets;
splashWindow.DataContext = swvm;
desktop.MainWindow = splashWindow;
}
void OnGotRomSets(object sender, RomSetsEventArgs e) => _romSets = e.RomSets;
base.OnFrameworkInitializationCompleted();
}
void OnSplashFinished(object sender, EventArgs e)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop))
return;
void OnGotRomSets(object sender, RomSetsEventArgs e) => _romSets = e.RomSets;
// Ensure not exit
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
void OnSplashFinished(object sender, EventArgs e)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)) return;
// Close splash window
desktop.MainWindow.Close();
// Ensure not exit
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
// Create and show main window
desktop.MainWindow = new MainWindow();
desktop.MainWindow.DataContext = new MainWindowViewModel(desktop.MainWindow as MainWindow, _romSets);
desktop.MainWindow.Show();
// Close splash window
desktop.MainWindow.Close();
// Now can close when all windows are closed
desktop.ShutdownMode = ShutdownMode.OnLastWindowClose;
}
// Create and show main window
desktop.MainWindow = new MainWindow();
desktop.MainWindow.DataContext = new MainWindowViewModel(desktop.MainWindow as MainWindow, _romSets);
desktop.MainWindow.Show();
void OnAboutClicked(object sender, EventArgs args)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ||
!(desktop.MainWindow is MainWindow mainWindow) ||
!(mainWindow.DataContext is MainWindowViewModel mainWindowViewModel))
return;
// Now can close when all windows are closed
desktop.ShutdownMode = ShutdownMode.OnLastWindowClose;
}
mainWindowViewModel.ExecuteAboutCommand();
}
void OnAboutClicked(object sender, EventArgs args)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ||
!(desktop.MainWindow is MainWindow mainWindow) ||
!(mainWindow.DataContext is MainWindowViewModel mainWindowViewModel))
return;
void OnQuitClicked(object sender, EventArgs args)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ||
!(desktop.MainWindow is MainWindow mainWindow) ||
!(mainWindow.DataContext is MainWindowViewModel mainWindowViewModel))
return;
mainWindowViewModel.ExecuteAboutCommand();
}
mainWindowViewModel.ExecuteExitCommand();
}
void OnQuitClicked(object sender, EventArgs args)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ||
!(desktop.MainWindow is MainWindow mainWindow) ||
!(mainWindow.DataContext is MainWindowViewModel mainWindowViewModel))
return;
void OnPreferencesClicked(object sender, EventArgs args)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ||
!(desktop.MainWindow is MainWindow mainWindow) ||
!(mainWindow.DataContext is MainWindowViewModel mainWindowViewModel))
return;
mainWindowViewModel.ExecuteExitCommand();
}
mainWindowViewModel.ExecuteSettingsCommand();
}
void OnPreferencesClicked(object sender, EventArgs args)
{
if(!(ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ||
!(desktop.MainWindow is MainWindow mainWindow) ||
!(mainWindow.DataContext is MainWindowViewModel mainWindowViewModel))
return;
mainWindowViewModel.ExecuteSettingsCommand();
}
}

View File

@@ -1,11 +1,12 @@
<svg viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg">
<style
type="text/css"
id="current-color-scheme">
.ColorScheme-PositiveText {
color:#27ae60;
}
</style>
<rect style="fill:currentColor;fill-opacity:1;stroke:none" class="ColorScheme-PositiveText" height="8" rx="1" width="8"/>
<path d="M6 2L3 5 1.5 3.5l-1 1L3 7l4-4z" fill="#fff"/>
<style
type="text/css"
id="current-color-scheme">
.ColorScheme-PositiveText {
color:#27ae60;
}
</style>
<rect style="fill:currentColor;fill-opacity:1;stroke:none" class="ColorScheme-PositiveText" height="8" rx="1"
width="8"/>
<path d="M6 2L3 5 1.5 3.5l-1 1L3 7l4-4z" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 407 B

After

Width:  |  Height:  |  Size: 387 B

View File

@@ -1,11 +1,12 @@
<svg viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg">
<style
type="text/css"
id="current-color-scheme">
.ColorScheme-NegativeText {
color:#da4453;
}
</style>
<path style="fill:currentColor;fill-opacity:1;stroke:none" class="ColorScheme-NegativeText" d="M1 0C.446 0 0 .446 0 1v6c0 .554.446 1 1 1h6c.554 0 1-.446 1-1V1c0-.554-.446-1-1-1z"/>
<path d="M2 1L1 2l2 2-2 2 1 1 2-2 2 2 1-1-2-2 2-2-1-1-2 2z" fill="#fff"/>
<style
type="text/css"
id="current-color-scheme">
.ColorScheme-NegativeText {
color:#da4453;
}
</style>
<path style="fill:currentColor;fill-opacity:1;stroke:none" class="ColorScheme-NegativeText"
d="M1 0C.446 0 0 .446 0 1v6c0 .554.446 1 1 1h6c.554 0 1-.446 1-1V1c0-.554-.446-1-1-1z"/>
<path d="M2 1L1 2l2 2-2 2 1 1 2-2 2 2 1-1-2-2 2-2-1-1-2 2z" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 485 B

After

Width:  |  Height:  |  Size: 465 B

View File

@@ -1,4 +1,6 @@
<svg viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg">
<rect fill="#9b59b6" height="8" rx="1" width="8"/>
<path d="M4 1a2 2 0 0 0-2 2h1a1 1 0 0 1 1-1 1 1 0 0 1 1 1 1 1 0 0 1-1 1H3v2h1V5a2 2 0 0 0 2-2 2 2 0 0 0-2-2zM3 7h1v1H3z" fill="#fff"/>
<rect fill="#9b59b6" height="8" rx="1" width="8"/>
<path
d="M4 1a2 2 0 0 0-2 2h1a1 1 0 0 1 1-1 1 1 0 0 1 1 1 1 1 0 0 1-1 1H3v2h1V5a2 2 0 0 0 2-2 2 2 0 0 0-2-2zM3 7h1v1H3z"
fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 268 B

View File

@@ -26,17 +26,16 @@
using Avalonia;
using Avalonia.ReactiveUI;
namespace RomRepoMgr
{
internal class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
namespace RomRepoMgr;
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp() =>
AppBuilder.Configure<App>().UsePlatformDetect().LogToDebug().UseReactiveUI();
}
internal class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp() =>
AppBuilder.Configure<App>().UsePlatformDetect().LogToDebug().UseReactiveUI();
}

View File

@@ -1,371 +1,375 @@
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutLabel" xml:space="preserve">
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="AboutLabel" xml:space="preserve">
<value>Acerca de</value>
</data>
<data name="AboutTitle" xml:space="preserve">
<data name="AboutTitle" xml:space="preserve">
<value>Acerda de ROM Repository Manager</value>
</data>
<data name="AllFilesDialogLabel" xml:space="preserve">
<data name="AllFilesDialogLabel" xml:space="preserve">
<value>Todos los archivos</value>
</data>
<data name="AllFilesLabel" xml:space="preserve">
<data name="AllFilesLabel" xml:space="preserve">
<value>Comprobar todos los archivos.</value>
</data>
<data name="AssembliesLibraryText" xml:space="preserve">
<data name="AssembliesLibraryText" xml:space="preserve">
<value>Librería</value>
</data>
<data name="AssembliesVersionText" xml:space="preserve">
<data name="AssembliesVersionText" xml:space="preserve">
<value>Versión</value>
</data>
<data name="AuthorsLabel" xml:space="preserve">
<data name="AuthorsLabel" xml:space="preserve">
<value>Autores</value>
</data>
<data name="AuthorsText" xml:space="preserve">
<data name="AuthorsText" xml:space="preserve">
<value>Desarrolladores:
Natalia Portillo</value>
</data>
<data name="CancelLabel" xml:space="preserve">
<data name="CancelLabel" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="CheckingUnArText" xml:space="preserve">
<data name="CheckingUnArText" xml:space="preserve">
<value>Comprobando The Unarchiver...</value>
</data>
<data name="ChooseDatabaseFile" xml:space="preserve">
<data name="ChooseDatabaseFile" xml:space="preserve">
<value>Elegir base de datos a abrir o crear</value>
</data>
<data name="ChooseLabel" xml:space="preserve">
<data name="ChooseLabel" xml:space="preserve">
<value>Elegir...</value>
</data>
<data name="ChooseRepositoryFolder" xml:space="preserve">
<data name="ChooseRepositoryFolder" xml:space="preserve">
<value>Elegir carpeta del repositorio</value>
</data>
<data name="ChooseTemporaryFolder" xml:space="preserve">
<data name="ChooseTemporaryFolder" xml:space="preserve">
<value>Elegir carpeta temporal</value>
</data>
<data name="ChooseUnArExecutable" xml:space="preserve">
<data name="ChooseUnArExecutable" xml:space="preserve">
<value>Elegir ejecutable de UnArchiver</value>
</data>
<data name="CloseLabel" xml:space="preserve">
<data name="CloseLabel" xml:space="preserve">
<value>Cerrar</value>
</data>
<data name="CompleteMachinesLabel" xml:space="preserve">
<data name="CompleteMachinesLabel" xml:space="preserve">
<value>Juegos completos</value>
</data>
<data name="DatabaseFileCannotDeleteCaption" xml:space="preserve">
<data name="DatabaseFileCannotDeleteCaption" xml:space="preserve">
<value>Ocurrió un error al eliminar el archivo elegido.</value>
</data>
<data name="DatabaseFileCannotDeleteTitle" xml:space="preserve">
<data name="DatabaseFileCannotDeleteTitle" xml:space="preserve">
<value>No se pudo eliminar el archivo.</value>
</data>
<data name="DatabaseFileDeleteCaption" xml:space="preserve">
<data name="DatabaseFileDeleteCaption" xml:space="preserve">
<value>¿Quieres eliminar el archivo?</value>
</data>
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<value>El archivo existe</value>
</data>
<data name="DatabaseFileLabel" xml:space="preserve">
<data name="DatabaseFileLabel" xml:space="preserve">
<value>Archivo de base de datos</value>
</data>
<data name="DatabaseFileMsgBoxTryOpen" xml:space="preserve">
<data name="DatabaseFileMsgBoxTryOpen" xml:space="preserve">
<value>¿Quieres intentar abrir el archivo existente como una base de datos?</value>
</data>
<data name="DatabaseFileTryOpenCaption" xml:space="preserve">
<data name="DatabaseFileTryOpenCaption" xml:space="preserve">
<value>¿Quieres intentar abrir el archivo existente como una base de datos?</value>
</data>
<data name="DatabaseFileUnusableDeleteMsgBoxCaption" xml:space="preserve">
<data name="DatabaseFileUnusableDeleteMsgBoxCaption" xml:space="preserve">
<value>Ocurrió un error al tratar de usar el archivo seleccionado como una base de datos.
¿Quieres eliminarlo?</value>
</data>
<data name="DatabaseFileUnusableMsgBoxCaption" xml:space="preserve">
<data name="DatabaseFileUnusableMsgBoxCaption" xml:space="preserve">
<value>Ocurrió un error al tratar de usar el archivo seleccionado como una base de datos.</value>
</data>
<data name="DatabaseFileUnusableMsgBoxTitle" xml:space="preserve">
<data name="DatabaseFileUnusableMsgBoxTitle" xml:space="preserve">
<value>No se puede usar la base de datos.</value>
</data>
<data name="DatFilesDialogLabel" xml:space="preserve">
<data name="DatFilesDialogLabel" xml:space="preserve">
<value>Archivos DAT</value>
</data>
<data name="DecompressingDat" xml:space="preserve">
<data name="DecompressingDat" xml:space="preserve">
<value>Descomprimiendo archivo DAT...</value>
</data>
<data name="DeleteRomSetMsgBoxCaption" xml:space="preserve">
<data name="DeleteRomSetMsgBoxCaption" xml:space="preserve">
<value>¿Estás seguro de eliminar el set de ROMs {0}?</value>
</data>
<data name="DeleteRomSetMsgBoxTitle" xml:space="preserve">
<data name="DeleteRomSetMsgBoxTitle" xml:space="preserve">
<value>Eliminar set de ROMs</value>
</data>
<data name="EditDatTitle" xml:space="preserve">
<data name="EditDatTitle" xml:space="preserve">
<value>Editar DAT</value>
</data>
<data name="Error" xml:space="preserve">
<data name="Error" xml:space="preserve">
<value>Error</value>
</data>
<data name="ExitButtonText" xml:space="preserve">
<data name="ExitButtonText" xml:space="preserve">
<value>Salir</value>
</data>
<data name="ExportDatTitle" xml:space="preserve">
<data name="ExportDatTitle" xml:space="preserve">
<value>Exportando archivo DAT...</value>
</data>
<data name="ExportRomsDialogTitle" xml:space="preserve">
<data name="ExportRomsDialogTitle" xml:space="preserve">
<value>Exportar ROMs a carpeta...</value>
</data>
<data name="ExportRomsTitle" xml:space="preserve">
<data name="ExportRomsTitle" xml:space="preserve">
<value>Exportando ROMs a carpeta...</value>
</data>
<data name="FileMenuExitText" xml:space="preserve">
<data name="FileMenuExitText" xml:space="preserve">
<value>_Salir</value>
</data>
<data name="FileMenuImportDatFileText" xml:space="preserve">
<data name="FileMenuImportDatFileText" xml:space="preserve">
<value>Importar _archivo DAT</value>
</data>
<data name="FileMenuImportDatFolderText" xml:space="preserve">
<data name="FileMenuImportDatFolderText" xml:space="preserve">
<value>Importar _carpeta de DATs</value>
</data>
<data name="FileMenuSettingsText" xml:space="preserve">
<data name="FileMenuSettingsText" xml:space="preserve">
<value>_Preferencias</value>
</data>
<data name="FileMenuText" xml:space="preserve">
<data name="FileMenuText" xml:space="preserve">
<value>_Archivo</value>
</data>
<data name="FilesystemMenuMountText" xml:space="preserve">
<data name="FilesystemMenuMountText" xml:space="preserve">
<value>_Montar</value>
</data>
<data name="FilesystemMenuText" xml:space="preserve">
<data name="FilesystemMenuText" xml:space="preserve">
<value>_Sistema de ficheros</value>
</data>
<data name="Finished" xml:space="preserve">
<data name="Finished" xml:space="preserve">
<value>Terminado</value>
</data>
<data name="FoundFiles" xml:space="preserve">
<data name="FoundFiles" xml:space="preserve">
<value>Encontrados {0} archivos...</value>
</data>
<data name="HaveRomsLabel" xml:space="preserve">
<data name="HaveRomsLabel" xml:space="preserve">
<value>ROMs presentes</value>
</data>
<data name="HelpMenuAboutText" xml:space="preserve">
<data name="HelpMenuAboutText" xml:space="preserve">
<value>_Acerca de</value>
</data>
<data name="HelpMenuText" xml:space="preserve">
<data name="HelpMenuText" xml:space="preserve">
<value>_Ayuda</value>
</data>
<data name="HomepageLabel" xml:space="preserve">
<data name="HomepageLabel" xml:space="preserve">
<value>Página web</value>
</data>
<data name="ImportDatFileDialogTitle" xml:space="preserve">
<data name="ImportDatFileDialogTitle" xml:space="preserve">
<value>Importar archivo DAT...</value>
</data>
<data name="ImportDatFolderDialogTitle" xml:space="preserve">
<data name="ImportDatFolderDialogTitle" xml:space="preserve">
<value>Importar DATs en carpeta...</value>
</data>
<data name="ImportDatFolderTitle" xml:space="preserve">
<data name="ImportDatFolderTitle" xml:space="preserve">
<value>Importar archivos DAT de carpeta...</value>
</data>
<data name="ImportDatTitle" xml:space="preserve">
<data name="ImportDatTitle" xml:space="preserve">
<value>Importando archivo DAT...</value>
</data>
<data name="ImportingItem" xml:space="preserve">
<data name="ImportingItem" xml:space="preserve">
<value>Importando {0}...</value>
</data>
<data name="ImportRomFolderTitle" xml:space="preserve">
<data name="ImportRomFolderTitle" xml:space="preserve">
<value>Importar ROMs de carpeta...</value>
</data>
<data name="ImportRomsFolderDialogTitle" xml:space="preserve">
<data name="ImportRomsFolderDialogTitle" xml:space="preserve">
<value>IImportar ROMs de carpeta...</value>
</data>
<data name="IncompleteMachinesLabel" xml:space="preserve">
<data name="IncompleteMachinesLabel" xml:space="preserve">
<value>Juegos incompletos</value>
</data>
<data name="KnownOnlyLabel" xml:space="preserve">
<data name="KnownOnlyLabel" xml:space="preserve">
<value>Importar solo archivos conocidos.</value>
</data>
<data name="LibrariesLabel" xml:space="preserve">
<data name="LibrariesLabel" xml:space="preserve">
<value>Librerías</value>
</data>
<data name="LicenseLabel" xml:space="preserve">
<data name="LicenseLabel" xml:space="preserve">
<value>Licencia: Licencia Pública General GNU Versión 3</value>
</data>
<data name="LoadingDatabaseText" xml:space="preserve">
<data name="LoadingDatabaseText" xml:space="preserve">
<value>Cargando base de datos...</value>
</data>
<data name="LoadingRomSetsText" xml:space="preserve">
<data name="LoadingRomSetsText" xml:space="preserve">
<value>Cargando sets de ROMs...</value>
</data>
<data name="LoadingSettingsText" xml:space="preserve">
<data name="LoadingSettingsText" xml:space="preserve">
<value>Cargando preferencias...</value>
</data>
<data name="MigratingDatabaseText" xml:space="preserve">
<data name="MigratingDatabaseText" xml:space="preserve">
<value>Migrando base de datos...</value>
</data>
<data name="MissRomsLabel" xml:space="preserve">
<data name="MissRomsLabel" xml:space="preserve">
<value>ROMs faltantes</value>
</data>
<data name="OK" xml:space="preserve">
<data name="OK" xml:space="preserve">
<value>OK</value>
</data>
<data name="PathLabel" xml:space="preserve">
<data name="PathLabel" xml:space="preserve">
<value>Ruta:</value>
</data>
<data name="RecurseArchivesLabel" xml:space="preserve">
<data name="RecurseArchivesLabel" xml:space="preserve">
<value>Intentar detectar archivos comprimiedos e importar su contenido.</value>
</data>
<data name="RecursiveLabel" xml:space="preserve">
<data name="RecursiveLabel" xml:space="preserve">
<value>Recorrer subcarpetas.</value>
</data>
<data name="RemoveDatTitle" xml:space="preserve">
<data name="RemoveDatTitle" xml:space="preserve">
<value>Eliminando set de ROM...</value>
</data>
<data name="RemoveFilesLabel" xml:space="preserve">
<data name="RemoveFilesLabel" xml:space="preserve">
<value>Eliminar archivos después de importar satisfactoriamente.</value>
</data>
<data name="RemovingDatFileFromRepo" xml:space="preserve">
<data name="RemovingDatFileFromRepo" xml:space="preserve">
<value>Eliminando archivo DAT del repositorio...</value>
</data>
<data name="RemovingRomSetFromDatabase" xml:space="preserve">
<data name="RemovingRomSetFromDatabase" xml:space="preserve">
<value>Elimiando set de ROMs de la base de datos...</value>
</data>
<data name="RepositoryFolderLabel" xml:space="preserve">
<data name="RepositoryFolderLabel" xml:space="preserve">
<value>Carpeta del repositorio</value>
</data>
<data name="ResultFilenameLabel" xml:space="preserve">
<data name="ResultFilenameLabel" xml:space="preserve">
<value>Nombre de archivo</value>
</data>
<data name="ResultStatusLabel" xml:space="preserve">
<data name="ResultStatusLabel" xml:space="preserve">
<value>Estado</value>
</data>
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<value>Recuperando set de ROMs de la base de datos...</value>
</data>
<data name="RomSetAuthorLabel" xml:space="preserve">
<data name="RomSetAuthorLabel" xml:space="preserve">
<value>Autor</value>
</data>
<data name="RomSetCommentLabel" xml:space="preserve">
<data name="RomSetCommentLabel" xml:space="preserve">
<value>Comentario</value>
</data>
<data name="RomSetCompleteMachinesLabel" xml:space="preserve">
<data name="RomSetCompleteMachinesLabel" xml:space="preserve">
<value>Completos</value>
</data>
<data name="RomSetDateLabel" xml:space="preserve">
<data name="RomSetDateLabel" xml:space="preserve">
<value>Fecha</value>
</data>
<data name="RomSetDescriptionLabel" xml:space="preserve">
<data name="RomSetDescriptionLabel" xml:space="preserve">
<value>Descripción</value>
</data>
<data name="RomSetHaveRomsLabel" xml:space="preserve">
<data name="RomSetHaveRomsLabel" xml:space="preserve">
<value>Presentes</value>
</data>
<data name="RomSetIncompleteMachinesLabel" xml:space="preserve">
<data name="RomSetIncompleteMachinesLabel" xml:space="preserve">
<value>Incompletos</value>
</data>
<data name="RomSetMissRomsLabel" xml:space="preserve">
<data name="RomSetMissRomsLabel" xml:space="preserve">
<value>Faltantes</value>
</data>
<data name="RomSetNameLabel" xml:space="preserve">
<data name="RomSetNameLabel" xml:space="preserve">
<value>Nombre</value>
</data>
<data name="RomSets" xml:space="preserve">
<data name="RomSets" xml:space="preserve">
<value>Sets de ROMs</value>
</data>
<data name="RomSetsMenuDeleteText" xml:space="preserve">
<data name="RomSetsMenuDeleteText" xml:space="preserve">
<value>Elimina_r</value>
</data>
<data name="RomSetsMenuEditText" xml:space="preserve">
<data name="RomSetsMenuEditText" xml:space="preserve">
<value>_Editar</value>
</data>
<data name="RomSetsMenuSaveDatText" xml:space="preserve">
<data name="RomSetsMenuSaveDatText" xml:space="preserve">
<value>_Guardar archivo DAT</value>
</data>
<data name="RomSetsMenuSaveRomsText" xml:space="preserve">
<data name="RomSetsMenuSaveRomsText" xml:space="preserve">
<value>Guardar ROMs en _carpeta</value>
</data>
<data name="RomSetsMenuText" xml:space="preserve">
<data name="RomSetsMenuText" xml:space="preserve">
<value>Sets de _ROMs</value>
</data>
<data name="RomSetTotalMachinesLabel" xml:space="preserve">
<data name="RomSetTotalMachinesLabel" xml:space="preserve">
<value>Juegos</value>
</data>
<data name="RomSetTotalRomsLabel" xml:space="preserve">
<data name="RomSetTotalRomsLabel" xml:space="preserve">
<value>ROMs</value>
</data>
<data name="RomSetVersionLabel" xml:space="preserve">
<data name="RomSetVersionLabel" xml:space="preserve">
<value>Versión</value>
</data>
<data name="RomsMenuImportText" xml:space="preserve">
<data name="RomsMenuImportText" xml:space="preserve">
<value>Importar _carpeta</value>
</data>
<data name="RomsMenuText" xml:space="preserve">
<data name="RomsMenuText" xml:space="preserve">
<value>_ROMs</value>
</data>
<data name="SaveLabel" xml:space="preserve">
<data name="SaveLabel" xml:space="preserve">
<value>Guardar</value>
</data>
<data name="SavingChangesToDatabase" xml:space="preserve">
<data name="SavingChangesToDatabase" xml:space="preserve">
<value>Guardando cambios en la base de datos...</value>
</data>
<data name="SearchingForFiles" xml:space="preserve">
<data name="SearchingForFiles" xml:space="preserve">
<value>Buscando archivos...</value>
</data>
<data name="SelectMountPointDialogTitle" xml:space="preserve">
<data name="SelectMountPointDialogTitle" xml:space="preserve">
<value>Elegir punto de montaje...</value>
</data>
<data name="SettingsTitle" xml:space="preserve">
<data name="SettingsTitle" xml:space="preserve">
<value>Preferencias</value>
</data>
<data name="StartLabel" xml:space="preserve">
<data name="StartLabel" xml:space="preserve">
<value>Comenzar</value>
</data>
<data name="TemporaryFolderLabel" xml:space="preserve">
<data name="TemporaryFolderLabel" xml:space="preserve">
<value>Carpeta temporal</value>
</data>
<data name="TheUnarchiverVersionLabel" xml:space="preserve">
<data name="TheUnarchiverVersionLabel" xml:space="preserve">
<value>The Unarchiver versión {0}</value>
</data>
<data name="TotalMachinesLabel" xml:space="preserve">
<data name="TotalMachinesLabel" xml:space="preserve">
<value>Total de juegos</value>
</data>
<data name="TotalRomsLabel" xml:space="preserve">
<data name="TotalRomsLabel" xml:space="preserve">
<value>Total de ROMs</value>
</data>
<data name="UnArPathLabel" xml:space="preserve">
<data name="UnArPathLabel" xml:space="preserve">
<value>Ruta a UnAr</value>
</data>
<data name="FilesystemMenuUmountText" xml:space="preserve">
<data name="FilesystemMenuUmountText" xml:space="preserve">
<value>_Desmontar</value>
</data>
<data name="RomSetCategoryLabel" xml:space="preserve">
<data name="RomSetCategoryLabel" xml:space="preserve">
<value>Categoría</value>
</data>
<data name="RetrievingRomSetsFromDatabase" xml:space="preserve">
<data name="RetrievingRomSetsFromDatabase" xml:space="preserve">
<value>Recuperando sets de ROMs de la base de datos...</value>
</data>
<data name="RemovingOldStatistics" xml:space="preserve">
<data name="RemovingOldStatistics" xml:space="preserve">
<value>Eliminando estadísticas antiguas</value>
</data>
<data name="CalculatingStatisticsForRomSet" xml:space="preserve">
<data name="CalculatingStatisticsForRomSet" xml:space="preserve">
<value>Calculando estadísticas para {0} - {1} ({2})</value>
</data>
<data name="DatabaseMenuText" xml:space="preserve">
<data name="DatabaseMenuText" xml:space="preserve">
<value>Base de datos</value>
</data>
<data name="DatabaseMenuUpdateStatsText" xml:space="preserve">
<data name="DatabaseMenuUpdateStatsText" xml:space="preserve">
<value>Actualizar estadísticas</value>
</data>
<data name="UpdateStatsConfirmationDialogText" xml:space="preserve">
<data name="UpdateStatsConfirmationDialogText" xml:space="preserve">
<value>¿Quieres actualizar las estadísticas de los sets de ROMs en la base de datos?
Tardará mucho tiempo...</value>
</data>
<data name="UpdateStatsTitle" xml:space="preserve">
<data name="UpdateStatsTitle" xml:space="preserve">
<value>Actualizando estadísticas de sets de ROMs</value>
</data>
</root>

View File

@@ -1,377 +1,382 @@
<?xml version="1.0" encoding="utf-8" ?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="FileMenuText" xml:space="preserve">
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root"
xmlns="">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="FileMenuText" xml:space="preserve">
<value>_File</value>
</data>
<data name="RomSets" xml:space="preserve">
<data name="RomSets" xml:space="preserve">
<value>ROM sets</value>
</data>
<data name="RomSetNameLabel" xml:space="preserve">
<data name="RomSetNameLabel" xml:space="preserve">
<value>Name</value>
</data>
<data name="RomSetVersionLabel" xml:space="preserve">
<data name="RomSetVersionLabel" xml:space="preserve">
<value>Version</value>
</data>
<data name="RomSetAuthorLabel" xml:space="preserve">
<data name="RomSetAuthorLabel" xml:space="preserve">
<value>Author</value>
</data>
<data name="RomSetDateLabel" xml:space="preserve">
<data name="RomSetDateLabel" xml:space="preserve">
<value>Date</value>
</data>
<data name="RomSetDescriptionLabel" xml:space="preserve">
<data name="RomSetDescriptionLabel" xml:space="preserve">
<value>Description</value>
</data>
<data name="RomSetCommentLabel" xml:space="preserve">
<data name="RomSetCommentLabel" xml:space="preserve">
<value>Comment</value>
</data>
<data name="RomSetTotalMachinesLabel" xml:space="preserve">
<data name="RomSetTotalMachinesLabel" xml:space="preserve">
<value>Games</value>
</data>
<data name="RomSetCompleteMachinesLabel" xml:space="preserve">
<data name="RomSetCompleteMachinesLabel" xml:space="preserve">
<value>Complete</value>
</data>
<data name="RomSetIncompleteMachinesLabel" xml:space="preserve">
<data name="RomSetIncompleteMachinesLabel" xml:space="preserve">
<value>Incomplete</value>
</data>
<data name="RomSetTotalRomsLabel" xml:space="preserve">
<data name="RomSetTotalRomsLabel" xml:space="preserve">
<value>ROMs</value>
</data>
<data name="RomSetHaveRomsLabel" xml:space="preserve">
<data name="RomSetHaveRomsLabel" xml:space="preserve">
<value>Have</value>
</data>
<data name="RomSetMissRomsLabel" xml:space="preserve">
<data name="RomSetMissRomsLabel" xml:space="preserve">
<value>Miss</value>
</data>
<data name="FileMenuImportDatFileText" xml:space="preserve">
<data name="FileMenuImportDatFileText" xml:space="preserve">
<value>Import DAT _file</value>
</data>
<data name="FileMenuImportDatFolderText" xml:space="preserve">
<data name="FileMenuImportDatFolderText" xml:space="preserve">
<value>Import DAT f_older</value>
</data>
<data name="FileMenuSettingsText" xml:space="preserve">
<data name="FileMenuSettingsText" xml:space="preserve">
<value>_Settings</value>
</data>
<data name="FileMenuExitText" xml:space="preserve">
<data name="FileMenuExitText" xml:space="preserve">
<value>E_xit</value>
</data>
<data name="FilesystemMenuText" xml:space="preserve">
<data name="FilesystemMenuText" xml:space="preserve">
<value>File_system</value>
</data>
<data name="FilesystemMenuMountText" xml:space="preserve">
<data name="FilesystemMenuMountText" xml:space="preserve">
<value>_Mount</value>
</data>
<data name="RomsMenuText" xml:space="preserve">
<data name="RomsMenuText" xml:space="preserve">
<value>_ROMs</value>
</data>
<data name="RomsMenuImportText" xml:space="preserve">
<data name="RomsMenuImportText" xml:space="preserve">
<value>_Import folder</value>
</data>
<data name="RomSetsMenuText" xml:space="preserve">
<data name="RomSetsMenuText" xml:space="preserve">
<value>ROM _sets</value>
</data>
<data name="RomSetsMenuSaveRomsText" xml:space="preserve">
<data name="RomSetsMenuSaveRomsText" xml:space="preserve">
<value>_Save ROMs to folder</value>
</data>
<data name="RomSetsMenuSaveDatText" xml:space="preserve">
<data name="RomSetsMenuSaveDatText" xml:space="preserve">
<value>Save DAT _file</value>
</data>
<data name="RomSetsMenuEditText" xml:space="preserve">
<data name="RomSetsMenuEditText" xml:space="preserve">
<value>_Edit</value>
</data>
<data name="RomSetsMenuDeleteText" xml:space="preserve">
<data name="RomSetsMenuDeleteText" xml:space="preserve">
<value>_Delete</value>
</data>
<data name="HelpMenuText" xml:space="preserve">
<data name="HelpMenuText" xml:space="preserve">
<value>_Help</value>
</data>
<data name="HelpMenuAboutText" xml:space="preserve">
<data name="HelpMenuAboutText" xml:space="preserve">
<value>_About</value>
</data>
<data name="AboutLabel" xml:space="preserve">
<data name="AboutLabel" xml:space="preserve">
<value>About</value>
</data>
<data name="LibrariesLabel" xml:space="preserve">
<data name="LibrariesLabel" xml:space="preserve">
<value>Libraries</value>
</data>
<data name="AuthorsLabel" xml:space="preserve">
<data name="AuthorsLabel" xml:space="preserve">
<value>Authors</value>
</data>
<data name="AboutTitle" xml:space="preserve">
<data name="AboutTitle" xml:space="preserve">
<value>About ROM Repository Manager</value>
</data>
<data name="LicenseLabel" xml:space="preserve">
<data name="LicenseLabel" xml:space="preserve">
<value>License: GNU General Public License Version 3</value>
</data>
<data name="CloseLabel" xml:space="preserve">
<data name="CloseLabel" xml:space="preserve">
<value>Close</value>
</data>
<data name="AssembliesLibraryText" xml:space="preserve">
<data name="AssembliesLibraryText" xml:space="preserve">
<value>Library</value>
</data>
<data name="AssembliesVersionText" xml:space="preserve">
<data name="AssembliesVersionText" xml:space="preserve">
<value>Version</value>
</data>
<data name="AuthorsText" xml:space="preserve">
<data name="AuthorsText" xml:space="preserve">
<value>Developers:
Natalia Portillo
</value>
</data>
<data name="HomepageLabel" xml:space="preserve">
<data name="HomepageLabel" xml:space="preserve">
<value>Homepage</value>
</data>
<data name="TotalMachinesLabel" xml:space="preserve">
<data name="TotalMachinesLabel" xml:space="preserve">
<value>Total games</value>
</data>
<data name="CompleteMachinesLabel" xml:space="preserve">
<data name="CompleteMachinesLabel" xml:space="preserve">
<value>Complete games</value>
</data>
<data name="IncompleteMachinesLabel" xml:space="preserve">
<data name="IncompleteMachinesLabel" xml:space="preserve">
<value>Incomplete games</value>
</data>
<data name="TotalRomsLabel" xml:space="preserve">
<data name="TotalRomsLabel" xml:space="preserve">
<value>Total ROMs</value>
</data>
<data name="HaveRomsLabel" xml:space="preserve">
<data name="HaveRomsLabel" xml:space="preserve">
<value>Have ROMs</value>
</data>
<data name="MissRomsLabel" xml:space="preserve">
<data name="MissRomsLabel" xml:space="preserve">
<value>Missing ROMs</value>
</data>
<data name="EditDatTitle" xml:space="preserve">
<data name="EditDatTitle" xml:space="preserve">
<value>Edit DAT</value>
</data>
<data name="SaveLabel" xml:space="preserve">
<data name="SaveLabel" xml:space="preserve">
<value>Save</value>
</data>
<data name="CancelLabel" xml:space="preserve">
<data name="CancelLabel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="ExportDatTitle" xml:space="preserve">
<data name="ExportDatTitle" xml:space="preserve">
<value>Exporting DAT file...</value>
</data>
<data name="DecompressingDat" xml:space="preserve">
<data name="DecompressingDat" xml:space="preserve">
<value>Decompressing DAT file...</value>
</data>
<data name="Finished" xml:space="preserve">
<data name="Finished" xml:space="preserve">
<value>Finished</value>
</data>
<data name="ExportRomsTitle" xml:space="preserve">
<data name="ExportRomsTitle" xml:space="preserve">
<value>Exporting ROM files to folder...</value>
</data>
<data name="PathLabel" xml:space="preserve">
<data name="PathLabel" xml:space="preserve">
<value>Path:</value>
</data>
<data name="AllFilesLabel" xml:space="preserve">
<data name="AllFilesLabel" xml:space="preserve">
<value>Check all files.</value>
</data>
<data name="RecursiveLabel" xml:space="preserve">
<data name="RecursiveLabel" xml:space="preserve">
<value>Recurse subfolders.</value>
</data>
<data name="ImportDatFolderTitle" xml:space="preserve">
<data name="ImportDatFolderTitle" xml:space="preserve">
<value>Import DAT files from folder...</value>
</data>
<data name="ResultFilenameLabel" xml:space="preserve">
<data name="ResultFilenameLabel" xml:space="preserve">
<value>Filename</value>
</data>
<data name="ResultStatusLabel" xml:space="preserve">
<data name="ResultStatusLabel" xml:space="preserve">
<value>Status</value>
</data>
<data name="StartLabel" xml:space="preserve">
<data name="StartLabel" xml:space="preserve">
<value>Start</value>
</data>
<data name="SearchingForFiles" xml:space="preserve">
<data name="SearchingForFiles" xml:space="preserve">
<value>Searching for files...</value>
</data>
<data name="FoundFiles" xml:space="preserve">
<data name="FoundFiles" xml:space="preserve">
<value>Found {0} files...</value>
</data>
<data name="ImportingItem" xml:space="preserve">
<data name="ImportingItem" xml:space="preserve">
<value>Importing {0}...</value>
</data>
<data name="OK" xml:space="preserve">
<data name="OK" xml:space="preserve">
<value>OK</value>
</data>
<data name="ImportDatTitle" xml:space="preserve">
<data name="ImportDatTitle" xml:space="preserve">
<value>Importing DAT file...</value>
</data>
<data name="RemoveFilesLabel" xml:space="preserve">
<data name="RemoveFilesLabel" xml:space="preserve">
<value>Remove files after import successful.</value>
</data>
<data name="KnownOnlyLabel" xml:space="preserve">
<data name="KnownOnlyLabel" xml:space="preserve">
<value>Only import known files.</value>
</data>
<data name="RecurseArchivesLabel" xml:space="preserve">
<data name="RecurseArchivesLabel" xml:space="preserve">
<value>Try to detect archives and import their contents.</value>
</data>
<data name="ImportRomFolderTitle" xml:space="preserve">
<data name="ImportRomFolderTitle" xml:space="preserve">
<value>Import ROM files from folder...</value>
</data>
<data name="RemoveDatTitle" xml:space="preserve">
<data name="RemoveDatTitle" xml:space="preserve">
<value>Removing ROM set...</value>
</data>
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<data name="RetrievingRomSetFromDatabase" xml:space="preserve">
<value>Retrieving ROM set from database...</value>
</data>
<data name="RemovingRomSetFromDatabase" xml:space="preserve">
<data name="RemovingRomSetFromDatabase" xml:space="preserve">
<value>Removing ROM set from database...</value>
</data>
<data name="SavingChangesToDatabase" xml:space="preserve">
<data name="SavingChangesToDatabase" xml:space="preserve">
<value>Saving changes to database...</value>
</data>
<data name="RemovingDatFileFromRepo" xml:space="preserve">
<data name="RemovingDatFileFromRepo" xml:space="preserve">
<value>Removing DAT file from repo...</value>
</data>
<data name="ChooseLabel" xml:space="preserve">
<data name="ChooseLabel" xml:space="preserve">
<value>Choose...</value>
</data>
<data name="SettingsTitle" xml:space="preserve">
<data name="SettingsTitle" xml:space="preserve">
<value>Settings</value>
</data>
<data name="DatabaseFileLabel" xml:space="preserve">
<data name="DatabaseFileLabel" xml:space="preserve">
<value>Database file</value>
</data>
<data name="RepositoryFolderLabel" xml:space="preserve">
<data name="RepositoryFolderLabel" xml:space="preserve">
<value>Repository folder</value>
</data>
<data name="TemporaryFolderLabel" xml:space="preserve">
<data name="TemporaryFolderLabel" xml:space="preserve">
<value>Temporary folder</value>
</data>
<data name="UnArPathLabel" xml:space="preserve">
<data name="UnArPathLabel" xml:space="preserve">
<value>Path to UnAr</value>
</data>
<data name="Error" xml:space="preserve">
<data name="Error" xml:space="preserve">
<value>Error</value>
</data>
<data name="TheUnarchiverVersionLabel" xml:space="preserve">
<data name="TheUnarchiverVersionLabel" xml:space="preserve">
<value>The Unarchiver version {0}</value>
</data>
<data name="ChooseUnArExecutable" xml:space="preserve">
<data name="ChooseUnArExecutable" xml:space="preserve">
<value>Choose UnArchiver executable</value>
</data>
<data name="ChooseTemporaryFolder" xml:space="preserve">
<data name="ChooseTemporaryFolder" xml:space="preserve">
<value>Choose temporary folder</value>
</data>
<data name="ChooseRepositoryFolder" xml:space="preserve">
<data name="ChooseRepositoryFolder" xml:space="preserve">
<value>Choose repository folder</value>
</data>
<data name="ChooseDatabaseFile" xml:space="preserve">
<data name="ChooseDatabaseFile" xml:space="preserve">
<value>Choose database to open / create</value>
</data>
<data name="DatabaseFileMsgBoxTryOpen" xml:space="preserve">
<data name="DatabaseFileMsgBoxTryOpen" xml:space="preserve">
<value>Do you want to try to open the existing file as a database?</value>
</data>
<data name="DatabaseFileTryOpenCaption" xml:space="preserve">
<data name="DatabaseFileTryOpenCaption" xml:space="preserve">
<value>Do you want to try to open the existing file as a database?</value>
</data>
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<data name="DatabaseFileExistsMsgBoxTitle" xml:space="preserve">
<value>File exists</value>
</data>
<data name="DatabaseFileUnusableMsgBoxTitle" xml:space="preserve">
<data name="DatabaseFileUnusableMsgBoxTitle" xml:space="preserve">
<value>Could not use database</value>
</data>
<data name="DatabaseFileUnusableDeleteMsgBoxCaption" xml:space="preserve">
<data name="DatabaseFileUnusableDeleteMsgBoxCaption" xml:space="preserve">
<value>An error occurred trying to use the chosen file as a database.
Do you want to delete the file?</value>
</data>
<data name="DatabaseFileUnusableMsgBoxCaption" xml:space="preserve">
<data name="DatabaseFileUnusableMsgBoxCaption" xml:space="preserve">
<value>An error occurred trying to use the chosen file as a database.</value>
</data>
<data name="DatabaseFileDeleteCaption" xml:space="preserve">
<data name="DatabaseFileDeleteCaption" xml:space="preserve">
<value>Do you want to delete the file?</value>
</data>
<data name="DatabaseFileCannotDeleteTitle" xml:space="preserve">
<data name="DatabaseFileCannotDeleteTitle" xml:space="preserve">
<value>Could not delete file</value>
</data>
<data name="DatabaseFileCannotDeleteCaption" xml:space="preserve">
<data name="DatabaseFileCannotDeleteCaption" xml:space="preserve">
<value>An error occurred trying to delete the chosen file.</value>
</data>
<data name="ImportDatFileDialogTitle" xml:space="preserve">
<data name="ImportDatFileDialogTitle" xml:space="preserve">
<value>Import DAT file...</value>
</data>
<data name="DatFilesDialogLabel" xml:space="preserve">
<data name="DatFilesDialogLabel" xml:space="preserve">
<value>DAT files</value>
</data>
<data name="AllFilesDialogLabel" xml:space="preserve">
<data name="AllFilesDialogLabel" xml:space="preserve">
<value>All files</value>
</data>
<data name="ImportDatFolderDialogTitle" xml:space="preserve">
<data name="ImportDatFolderDialogTitle" xml:space="preserve">
<value>Import DATs from folder...</value>
</data>
<data name="ImportRomsFolderDialogTitle" xml:space="preserve">
<data name="ImportRomsFolderDialogTitle" xml:space="preserve">
<value>Import ROMs from folder...</value>
</data>
<data name="DeleteRomSetMsgBoxTitle" xml:space="preserve">
<data name="DeleteRomSetMsgBoxTitle" xml:space="preserve">
<value>Delete ROM set</value>
</data>
<data name="DeleteRomSetMsgBoxCaption" xml:space="preserve">
<data name="DeleteRomSetMsgBoxCaption" xml:space="preserve">
<value>Are you sure you want to delete the ROM set {0}?</value>
</data>
<data name="ExportRomsDialogTitle" xml:space="preserve">
<data name="ExportRomsDialogTitle" xml:space="preserve">
<value>Export ROMs to folder...</value>
</data>
<data name="SelectMountPointDialogTitle" xml:space="preserve">
<data name="SelectMountPointDialogTitle" xml:space="preserve">
<value>Select mount point...</value>
</data>
<data name="LoadingSettingsText" xml:space="preserve">
<data name="LoadingSettingsText" xml:space="preserve">
<value>Loading settings...</value>
</data>
<data name="CheckingUnArText" xml:space="preserve">
<data name="CheckingUnArText" xml:space="preserve">
<value>Checking The Unarchiver...</value>
</data>
<data name="LoadingDatabaseText" xml:space="preserve">
<data name="LoadingDatabaseText" xml:space="preserve">
<value>Loading database...</value>
</data>
<data name="MigratingDatabaseText" xml:space="preserve">
<data name="MigratingDatabaseText" xml:space="preserve">
<value>Migrating database...</value>
</data>
<data name="LoadingRomSetsText" xml:space="preserve">
<data name="LoadingRomSetsText" xml:space="preserve">
<value>Loading ROM sets...</value>
</data>
<data name="ExitButtonText" xml:space="preserve">
<data name="ExitButtonText" xml:space="preserve">
<value>Exit</value>
</data>
<data name="FilesystemMenuUmountText" xml:space="preserve">
<data name="FilesystemMenuUmountText" xml:space="preserve">
<value>_Umount</value>
</data>
<data name="RomSetCategoryLabel" xml:space="preserve">
<data name="RomSetCategoryLabel" xml:space="preserve">
<value>Category</value>
</data>
<data name="DatabaseMenuText" xml:space="preserve">
<data name="DatabaseMenuText" xml:space="preserve">
<value>Database</value>
</data>
<data name="DatabaseMenuUpdateStatsText" xml:space="preserve">
<data name="DatabaseMenuUpdateStatsText" xml:space="preserve">
<value>Update statistics</value>
</data>
<data name="UpdateStatsConfirmationDialogText" xml:space="preserve">
<data name="UpdateStatsConfirmationDialogText" xml:space="preserve">
<value>Do you want to update ROM set statistics in database?
This will take a long time...</value>
</data>
<data name="UpdateStatsTitle" xml:space="preserve">
<data name="UpdateStatsTitle" xml:space="preserve">
<value>Updating ROM sets statistics</value>
</data>
<data name="CalculatingStatisticsForRomSet" xml:space="preserve">
<data name="CalculatingStatisticsForRomSet" xml:space="preserve">
<value>Calculating statistics for {0} - {1} ({2})</value>
</data>
<data name="RemovingOldStatistics" xml:space="preserve">
<data name="RemovingOldStatistics" xml:space="preserve">
<value>Removing old statistics</value>
</data>
<data name="RetrievingRomSetsFromDatabase" xml:space="preserve">
<data name="RetrievingRomSetsFromDatabase" xml:space="preserve">
<value>Retrieving ROM sets from database...</value>
</data>
</root>

View File

@@ -1,44 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\**" />
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Localization.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.0-rc1" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.0-rc1" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.0-rc1" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.0-rc1" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0-rc1" />
<PackageReference Include="MessageBox.Avalonia" Version="0.10.7-rc1" />
<PackageReference Include="Svg.Skia.Avalonia" Version="0.10.0-preview7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RomRepoMgr.Database\RomRepoMgr.Database.csproj" />
<ProjectReference Include="..\RomRepoMgr.Settings\RomRepoMgr.Settings.csproj" />
<ProjectReference Include="..\RomRepoMgr.Core\RomRepoMgr.Core.csproj" />
<ProjectReference Include="..\SabreTools\SabreTools.DatFiles\SabreTools.DatFiles.csproj" />
<ProjectReference Include="..\SabreTools\SabreTools.DatItems\SabreTools.DatItems.csproj" />
<ProjectReference Include="..\SabreTools\SabreTools.IO\SabreTools.IO.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\**"/>
<Compile Update="Resources\Localization.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Localization.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.0-rc1"/>
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.0-rc1"/>
<PackageReference Include="Avalonia.Desktop" Version="0.10.0-rc1"/>
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.0-rc1"/>
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0-rc1"/>
<PackageReference Include="MessageBox.Avalonia" Version="0.10.7-rc1"/>
<PackageReference Include="Svg.Skia.Avalonia" Version="0.10.0-preview7"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RomRepoMgr.Database\RomRepoMgr.Database.csproj"/>
<ProjectReference Include="..\RomRepoMgr.Settings\RomRepoMgr.Settings.csproj"/>
<ProjectReference Include="..\RomRepoMgr.Core\RomRepoMgr.Core.csproj"/>
<ProjectReference Include="..\SabreTools\SabreTools.DatFiles\SabreTools.DatFiles.csproj"/>
<ProjectReference Include="..\SabreTools\SabreTools.DatItems\SabreTools.DatItems.csproj"/>
<ProjectReference Include="..\SabreTools\SabreTools.IO\SabreTools.IO.csproj"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Localization.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Localization.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -6,23 +6,24 @@ using Avalonia.Controls;
using Avalonia.Controls.Templates;
using RomRepoMgr.ViewModels;
namespace RomRepoMgr
namespace RomRepoMgr;
public class ViewLocator : IDataTemplate
{
public class ViewLocator : IDataTemplate
public bool SupportsRecycling => false;
public IControl Build(object data)
{
public bool SupportsRecycling => false;
string name = data.GetType().FullName?.Replace("ViewModel", "View");
Type type = name is null ? null : Type.GetType(name);
public IControl Build(object data)
{
string name = data.GetType().FullName?.Replace("ViewModel", "View");
Type type = name is null ? null : Type.GetType(name);
return type is null ? new TextBlock
{
Text = "Not Found: " + name
} : (Control)Activator.CreateInstance(type);
}
public bool Match(object data) => data is ViewModelBase;
return type is null
? new TextBlock
{
Text = "Not Found: " + name
}
: (Control)Activator.CreateInstance(type);
}
public bool Match(object data) => data is ViewModelBase;
}

View File

@@ -31,136 +31,130 @@ using System.Reactive;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Avalonia.Platform;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Microsoft.DotNet.PlatformAbstractions;
using ReactiveUI;
using RomRepoMgr.Core.Models;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class AboutViewModel : ViewModelBase
{
public sealed class AboutViewModel : ViewModelBase
readonly About _view;
string _versionText;
public AboutViewModel(About view)
{
readonly About _view;
string _versionText;
_view = view;
public AboutViewModel(About view)
VersionText =
(Attribute.GetCustomAttribute(typeof(App).Assembly, typeof(AssemblyInformationalVersionAttribute)) as
AssemblyInformationalVersionAttribute)?.InformationalVersion;
WebsiteCommand = ReactiveCommand.Create(ExecuteWebsiteCommand);
LicenseCommand = ReactiveCommand.Create(ExecuteLicenseCommand);
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
Assemblies = new ObservableCollection<AssemblyModel>();
// TODO: They do not load in time
Task.Run(() =>
{
_view = view;
VersionText =
(Attribute.GetCustomAttribute(typeof(App).Assembly, typeof(AssemblyInformationalVersionAttribute)) as
AssemblyInformationalVersionAttribute)?.InformationalVersion;
WebsiteCommand = ReactiveCommand.Create(ExecuteWebsiteCommand);
LicenseCommand = ReactiveCommand.Create(ExecuteLicenseCommand);
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
Assemblies = new ObservableCollection<AssemblyModel>();
// TODO: They do not load in time
Task.Run(() =>
foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().OrderBy(a => a.FullName))
{
foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().OrderBy(a => a.FullName))
string name = assembly.GetName().Name;
string version =
(Attribute.GetCustomAttribute(assembly, typeof(AssemblyInformationalVersionAttribute)) as
AssemblyInformationalVersionAttribute)?.InformationalVersion;
if(name is null || version is null) continue;
Assemblies.Add(new AssemblyModel
{
string name = assembly.GetName().Name;
string version =
(Attribute.GetCustomAttribute(assembly, typeof(AssemblyInformationalVersionAttribute)) as
AssemblyInformationalVersionAttribute)?.InformationalVersion;
if(name is null ||
version is null)
continue;
Assemblies.Add(new AssemblyModel
{
Name = name,
Version = version
});
}
});
}
[NotNull]
public string AboutLabel => Localization.AboutLabel;
[NotNull]
public string LibrariesLabel => Localization.LibrariesLabel;
[NotNull]
public string AuthorsLabel => Localization.AuthorsLabel;
[NotNull]
public string Title => Localization.AboutTitle;
[NotNull]
public string SoftwareName => "RomRepoMgr";
[NotNull]
public string SuiteName => "ROM Repository Manager";
[NotNull]
public string Copyright => "© 2020-2024 Natalia Portillo";
[NotNull]
public string Website => "https://www.claunia.com";
[NotNull]
public string License => Localization.LicenseLabel;
[NotNull]
public string CloseLabel => Localization.CloseLabel;
[NotNull]
public string AssembliesLibraryText => Localization.AssembliesLibraryText;
[NotNull]
public string AssembliesVersionText => Localization.AssembliesVersionText;
[NotNull]
public string Authors => Localization.AuthorsText;
public ReactiveCommand<Unit, Unit> WebsiteCommand { get; }
public ReactiveCommand<Unit, Unit> LicenseCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ObservableCollection<AssemblyModel> Assemblies { get; }
public string VersionText
{
get => _versionText;
set => this.RaiseAndSetIfChanged(ref _versionText, value);
}
void ExecuteWebsiteCommand()
{
var process = new Process
{
StartInfo =
{
UseShellExecute = false,
CreateNoWindow = true,
Arguments = "https://www.claunia.com"
}
};
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
process.StartInfo.FileName = "cmd";
process.StartInfo.Arguments = $"/c start {process.StartInfo.Arguments.Replace("&", "^&")}";
Name = name,
Version = version
});
}
else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
process.StartInfo.FileName = "xdg-open";
else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
process.StartInfo.FileName = "open";
else
{
if(Debugger.IsAttached) throw new ArgumentOutOfRangeException();
return;
}
process.Start();
}
void ExecuteLicenseCommand()
{
/* var dialog = new LicenseDialog();
dialog.DataContext = new LicenseViewModel(dialog);
dialog.ShowDialog(_view);*/
}
void ExecuteCloseCommand() => _view.Close();
});
}
[NotNull]
public string AboutLabel => Localization.AboutLabel;
[NotNull]
public string LibrariesLabel => Localization.LibrariesLabel;
[NotNull]
public string AuthorsLabel => Localization.AuthorsLabel;
[NotNull]
public string Title => Localization.AboutTitle;
[NotNull]
public string SoftwareName => "RomRepoMgr";
[NotNull]
public string SuiteName => "ROM Repository Manager";
[NotNull]
public string Copyright => "© 2020-2024 Natalia Portillo";
[NotNull]
public string Website => "https://www.claunia.com";
[NotNull]
public string License => Localization.LicenseLabel;
[NotNull]
public string CloseLabel => Localization.CloseLabel;
[NotNull]
public string AssembliesLibraryText => Localization.AssembliesLibraryText;
[NotNull]
public string AssembliesVersionText => Localization.AssembliesVersionText;
[NotNull]
public string Authors => Localization.AuthorsText;
public ReactiveCommand<Unit, Unit> WebsiteCommand { get; }
public ReactiveCommand<Unit, Unit> LicenseCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ObservableCollection<AssemblyModel> Assemblies { get; }
public string VersionText
{
get => _versionText;
set => this.RaiseAndSetIfChanged(ref _versionText, value);
}
void ExecuteWebsiteCommand()
{
var process = new Process
{
StartInfo =
{
UseShellExecute = false,
CreateNoWindow = true,
Arguments = "https://www.claunia.com"
}
};
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
process.StartInfo.FileName = "cmd";
process.StartInfo.Arguments = $"/c start {process.StartInfo.Arguments.Replace("&", "^&")}";
}
else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
process.StartInfo.FileName = "xdg-open";
else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
process.StartInfo.FileName = "open";
else
{
if(Debugger.IsAttached) throw new ArgumentOutOfRangeException();
return;
}
process.Start();
}
void ExecuteLicenseCommand()
{
/* var dialog = new LicenseDialog();
dialog.DataContext = new LicenseViewModel(dialog);
dialog.ShowDialog(_view);*/
}
void ExecuteCloseCommand() => _view.Close();
}

View File

@@ -33,220 +33,211 @@ using RomRepoMgr.Database.Models;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public class EditDatViewModel : ViewModelBase
{
public class EditDatViewModel : ViewModelBase
readonly RomSetModel _romSet;
readonly EditDat _view;
string _author;
string _category;
string _comment;
string _date;
string _description;
string _homepage;
bool _modified;
string _name;
string _version;
public EditDatViewModel(EditDat view, RomSetModel romSet)
{
readonly RomSetModel _romSet;
readonly EditDat _view;
string _author;
string _category;
string _comment;
string _date;
string _description;
string _homepage;
bool _modified;
string _name;
string _version;
_view = view;
_romSet = romSet;
_name = romSet.Name;
_version = romSet.Version;
_author = romSet.Author;
_comment = romSet.Comment;
_category = romSet.Category;
_date = romSet.Date;
_description = romSet.Description;
_homepage = romSet.Homepage;
SaveCommand = ReactiveCommand.Create(ExecuteSaveCommand);
CancelCommand = ReactiveCommand.Create(ExecuteCloseCommand);
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
}
public EditDatViewModel(EditDat view, RomSetModel romSet)
public string NameLabel => Localization.RomSetNameLabel;
public string VersionLabel => Localization.RomSetVersionLabel;
public string AuthorLabel => Localization.RomSetAuthorLabel;
public string CategoryLabel => Localization.RomSetCategoryLabel;
public string CommentLabel => Localization.RomSetCommentLabel;
public string DateLabel => Localization.RomSetDateLabel;
public string DescriptionLabel => Localization.RomSetDescriptionLabel;
public string HomepageLabel => Localization.HomepageLabel;
public string TotalMachinesLabel => Localization.TotalMachinesLabel;
public string CompleteMachinesLabel => Localization.CompleteMachinesLabel;
public string IncompleteMachinesLabel => Localization.IncompleteMachinesLabel;
public string TotalRomsLabel => Localization.TotalRomsLabel;
public string HaveRomsLabel => Localization.HaveRomsLabel;
public string MissRomsLabel => Localization.MissRomsLabel;
public string Title => Localization.EditDatTitle;
public string SaveLabel => Localization.SaveLabel;
public string CancelLabel => Localization.CancelLabel;
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public ReactiveCommand<Unit, Unit> CancelCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public long TotalMachines => _romSet.TotalMachines;
public long CompleteMachines => _romSet.CompleteMachines;
public long IncompleteMachines => _romSet.IncompleteMachines;
public long TotalRoms => _romSet.TotalRoms;
public long HaveRoms => _romSet.HaveRoms;
public long MissRoms => _romSet.MissRoms;
public bool Modified
{
get => _modified;
set => this.RaiseAndSetIfChanged(ref _modified, value);
}
public string Name
{
get => _name;
set
{
_view = view;
_romSet = romSet;
_name = romSet.Name;
_version = romSet.Version;
_author = romSet.Author;
_comment = romSet.Comment;
_category = romSet.Category;
_date = romSet.Date;
_description = romSet.Description;
_homepage = romSet.Homepage;
SaveCommand = ReactiveCommand.Create(ExecuteSaveCommand);
CancelCommand = ReactiveCommand.Create(ExecuteCloseCommand);
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
}
if(value != _name) Modified = true;
public string NameLabel => Localization.RomSetNameLabel;
public string VersionLabel => Localization.RomSetVersionLabel;
public string AuthorLabel => Localization.RomSetAuthorLabel;
public string CategoryLabel => Localization.RomSetCategoryLabel;
public string CommentLabel => Localization.RomSetCommentLabel;
public string DateLabel => Localization.RomSetDateLabel;
public string DescriptionLabel => Localization.RomSetDescriptionLabel;
public string HomepageLabel => Localization.HomepageLabel;
public string TotalMachinesLabel => Localization.TotalMachinesLabel;
public string CompleteMachinesLabel => Localization.CompleteMachinesLabel;
public string IncompleteMachinesLabel => Localization.IncompleteMachinesLabel;
public string TotalRomsLabel => Localization.TotalRomsLabel;
public string HaveRomsLabel => Localization.HaveRomsLabel;
public string MissRomsLabel => Localization.MissRomsLabel;
public string Title => Localization.EditDatTitle;
public string SaveLabel => Localization.SaveLabel;
public string CancelLabel => Localization.CancelLabel;
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public ReactiveCommand<Unit, Unit> CancelCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public long TotalMachines => _romSet.TotalMachines;
public long CompleteMachines => _romSet.CompleteMachines;
public long IncompleteMachines => _romSet.IncompleteMachines;
public long TotalRoms => _romSet.TotalRoms;
public long HaveRoms => _romSet.HaveRoms;
public long MissRoms => _romSet.MissRoms;
public bool Modified
{
get => _modified;
set => this.RaiseAndSetIfChanged(ref _modified, value);
}
public string Name
{
get => _name;
set
{
if(value != _name)
Modified = true;
this.RaiseAndSetIfChanged(ref _name, value);
}
}
public string Version
{
get => _version;
set
{
if(value != _version)
Modified = true;
this.RaiseAndSetIfChanged(ref _version, value);
}
}
public string Author
{
get => _author;
set
{
if(value != _author)
Modified = true;
this.RaiseAndSetIfChanged(ref _author, value);
}
}
public string Comment
{
get => _comment;
set
{
if(value != _comment)
Modified = true;
this.RaiseAndSetIfChanged(ref _comment, value);
}
}
public string Category
{
get => _category;
set
{
if(value != _category)
Modified = true;
this.RaiseAndSetIfChanged(ref _category, value);
}
}
public string Date
{
get => _date;
set
{
if(value != _date)
Modified = true;
this.RaiseAndSetIfChanged(ref _date, value);
}
}
public string Description
{
get => _description;
set
{
if(value != _description)
Modified = true;
this.RaiseAndSetIfChanged(ref _description, value);
}
}
public string Homepage
{
get => _homepage;
set
{
if(value != _homepage)
Modified = true;
this.RaiseAndSetIfChanged(ref _homepage, value);
}
}
public EventHandler<RomSetEventArgs> RomSetModified { get; set; }
void ExecuteCloseCommand() => _view.Close();
async void ExecuteSaveCommand()
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
RomSet romSetDb = await ctx.RomSets.FindAsync(_romSet.Id);
if(romSetDb == null)
return;
romSetDb.Author = Author;
romSetDb.Comment = Comment;
romSetDb.Category = Category;
romSetDb.Date = Date;
romSetDb.Description = Description;
romSetDb.Homepage = Homepage;
romSetDb.Name = Name;
romSetDb.Version = Version;
romSetDb.UpdatedOn = DateTime.UtcNow;
await ctx.SaveChangesAsync();
RomSetModified?.Invoke(this, new RomSetEventArgs
{
RomSet = new RomSetModel
{
Author = Author,
Comment = Comment,
Category = Category,
Date = Date,
Description = Description,
Homepage = Homepage,
Name = Name,
Version = Version,
Filename = _romSet.Filename,
Sha384 = _romSet.Sha384,
TotalMachines = _romSet.TotalMachines,
CompleteMachines = _romSet.CompleteMachines,
IncompleteMachines = _romSet.IncompleteMachines,
TotalRoms = _romSet.TotalRoms,
HaveRoms = _romSet.HaveRoms,
MissRoms = _romSet.MissRoms,
Id = _romSet.Id
}
});
Modified = false;
this.RaiseAndSetIfChanged(ref _name, value);
}
}
public string Version
{
get => _version;
set
{
if(value != _version) Modified = true;
this.RaiseAndSetIfChanged(ref _version, value);
}
}
public string Author
{
get => _author;
set
{
if(value != _author) Modified = true;
this.RaiseAndSetIfChanged(ref _author, value);
}
}
public string Comment
{
get => _comment;
set
{
if(value != _comment) Modified = true;
this.RaiseAndSetIfChanged(ref _comment, value);
}
}
public string Category
{
get => _category;
set
{
if(value != _category) Modified = true;
this.RaiseAndSetIfChanged(ref _category, value);
}
}
public string Date
{
get => _date;
set
{
if(value != _date) Modified = true;
this.RaiseAndSetIfChanged(ref _date, value);
}
}
public string Description
{
get => _description;
set
{
if(value != _description) Modified = true;
this.RaiseAndSetIfChanged(ref _description, value);
}
}
public string Homepage
{
get => _homepage;
set
{
if(value != _homepage) Modified = true;
this.RaiseAndSetIfChanged(ref _homepage, value);
}
}
public EventHandler<RomSetEventArgs> RomSetModified { get; set; }
void ExecuteCloseCommand() => _view.Close();
async void ExecuteSaveCommand()
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
RomSet romSetDb = await ctx.RomSets.FindAsync(_romSet.Id);
if(romSetDb == null) return;
romSetDb.Author = Author;
romSetDb.Comment = Comment;
romSetDb.Category = Category;
romSetDb.Date = Date;
romSetDb.Description = Description;
romSetDb.Homepage = Homepage;
romSetDb.Name = Name;
romSetDb.Version = Version;
romSetDb.UpdatedOn = DateTime.UtcNow;
await ctx.SaveChangesAsync();
RomSetModified?.Invoke(this,
new RomSetEventArgs
{
RomSet = new RomSetModel
{
Author = Author,
Comment = Comment,
Category = Category,
Date = Date,
Description = Description,
Homepage = Homepage,
Name = Name,
Version = Version,
Filename = _romSet.Filename,
Sha384 = _romSet.Sha384,
TotalMachines = _romSet.TotalMachines,
CompleteMachines = _romSet.CompleteMachines,
IncompleteMachines = _romSet.IncompleteMachines,
TotalRoms = _romSet.TotalRoms,
HaveRoms = _romSet.HaveRoms,
MissRoms = _romSet.MissRoms,
Id = _romSet.Id
}
});
Modified = false;
}
}

View File

@@ -36,125 +36,117 @@ using RomRepoMgr.Resources;
using RomRepoMgr.Views;
using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class ExportDatViewModel : ViewModelBase
{
public sealed class ExportDatViewModel : ViewModelBase
readonly string _datHash;
readonly string _outPath;
readonly ExportDat _view;
readonly Compression _worker;
bool _canClose;
string _errorMessage;
bool _errorVisible;
bool _progressVisible;
string _statusMessage;
public ExportDatViewModel(ExportDat view, string datHash, string outPath)
{
readonly string _datHash;
readonly string _outPath;
readonly ExportDat _view;
readonly Compression _worker;
bool _canClose;
string _errorMessage;
bool _errorVisible;
bool _progressVisible;
string _statusMessage;
_view = view;
_datHash = datHash;
_outPath = outPath;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
ProgressVisible = false;
ErrorVisible = false;
_worker = new Compression();
_worker.FinishedWithText += OnWorkerOnFinishedWithText;
_worker.FailedWithText += OnWorkerOnFailedWithText;
}
public ExportDatViewModel(ExportDat view, string datHash, string outPath)
[NotNull]
public string Title => Localization.ExportDatTitle;
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public bool ErrorVisible
{
get => _errorVisible;
set => this.RaiseAndSetIfChanged(ref _errorVisible, value);
}
public string ErrorMessage
{
get => _errorMessage;
set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
void OnWorkerOnFinishedWithText(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.Finished;
ProgressVisible = false;
CanClose = true;
});
void OnWorkerOnFailedWithText(object sender, ErrorEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ErrorMessage = args.Message;
ProgressVisible = false;
ErrorVisible = true;
CanClose = true;
});
void ExecuteCloseCommand() => _view.Close();
internal void OnOpened()
{
ProgressVisible = true;
StatusMessage = Localization.DecompressingDat;
var sha384Bytes = new byte[48];
string sha384 = _datHash;
for(var i = 0; i < 48; i++)
{
_view = view;
_datHash = datHash;
_outPath = outPath;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
ProgressVisible = false;
ErrorVisible = false;
_worker = new Compression();
_worker.FinishedWithText += OnWorkerOnFinishedWithText;
_worker.FailedWithText += OnWorkerOnFailedWithText;
if(sha384[i * 2] >= 0x30 && sha384[i * 2] <= 0x39)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x30) * 0x10);
else if(sha384[i * 2] >= 0x41 && sha384[i * 2] <= 0x46)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x37) * 0x10);
else if(sha384[i * 2] >= 0x61 && sha384[i * 2] <= 0x66)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x57) * 0x10);
if(sha384[i * 2 + 1] >= 0x30 && sha384[i * 2 + 1] <= 0x39)
sha384Bytes[i] += (byte)(sha384[i * 2 + 1] - 0x30);
else if(sha384[i * 2 + 1] >= 0x41 && sha384[i * 2 + 1] <= 0x46)
sha384Bytes[i] += (byte)(sha384[i * 2 + 1] - 0x37);
else if(sha384[i * 2 + 1] >= 0x61 && sha384[i * 2 + 1] <= 0x66)
sha384Bytes[i] += (byte)(sha384[i * 2 + 1] - 0x57);
}
[NotNull]
public string Title => Localization.ExportDatTitle;
string datHash32 = Base32.ToBase32String(sha384Bytes);
string datFilesPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "datfiles");
string compressedDatPath = Path.Combine(datFilesPath, datHash32 + ".lz");
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
if(!File.Exists(compressedDatPath)) _view.Close();
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public bool ErrorVisible
{
get => _errorVisible;
set => this.RaiseAndSetIfChanged(ref _errorVisible, value);
}
public string ErrorMessage
{
get => _errorMessage;
set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
void OnWorkerOnFinishedWithText(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.Finished;
ProgressVisible = false;
CanClose = true;
});
void OnWorkerOnFailedWithText(object sender, ErrorEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ErrorMessage = args.Message;
ProgressVisible = false;
ErrorVisible = true;
CanClose = true;
});
void ExecuteCloseCommand() => _view.Close();
internal void OnOpened()
{
ProgressVisible = true;
StatusMessage = Localization.DecompressingDat;
byte[] sha384Bytes = new byte[48];
string sha384 = _datHash;
for(int i = 0; i < 48; i++)
{
if(sha384[i * 2] >= 0x30 &&
sha384[i * 2] <= 0x39)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x30) * 0x10);
else if(sha384[i * 2] >= 0x41 &&
sha384[i * 2] <= 0x46)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x37) * 0x10);
else if(sha384[i * 2] >= 0x61 &&
sha384[i * 2] <= 0x66)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x57) * 0x10);
if(sha384[(i * 2) + 1] >= 0x30 &&
sha384[(i * 2) + 1] <= 0x39)
sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x30);
else if(sha384[(i * 2) + 1] >= 0x41 &&
sha384[(i * 2) + 1] <= 0x46)
sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x37);
else if(sha384[(i * 2) + 1] >= 0x61 &&
sha384[(i * 2) + 1] <= 0x66)
sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x57);
}
string datHash32 = Base32.ToBase32String(sha384Bytes);
string datFilesPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "datfiles");
string compressedDatPath = Path.Combine(datFilesPath, datHash32 + ".lz");
if(!File.Exists(compressedDatPath))
_view.Close();
Task.Run(() => _worker.DecompressFile(compressedDatPath, _outPath));
}
Task.Run(() => _worker.DecompressFile(compressedDatPath, _outPath));
}
}

View File

@@ -34,237 +34,236 @@ using RomRepoMgr.Core.Workers;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class ExportRomsViewModel : ViewModelBase
{
public sealed class ExportRomsViewModel : ViewModelBase
readonly long _romSetId;
readonly ExportRoms _view;
bool _canClose;
bool _progress2IsIndeterminate;
double _progress2Maximum;
double _progress2Minimum;
double _progress2Value;
bool _progress2Visible;
bool _progress3IsIndeterminate;
double _progress3Maximum;
double _progress3Minimum;
double _progress3Value;
bool _progress3Visible;
bool _progressIsIndeterminate;
double _progressMaximum;
double _progressMinimum;
double _progressValue;
bool _progressVisible;
string _status2Message;
string _status3Message;
string _statusMessage;
public ExportRomsViewModel(ExportRoms view, string folderPath, long romSetId)
{
readonly long _romSetId;
readonly ExportRoms _view;
bool _canClose;
bool _progress2IsIndeterminate;
double _progress2Maximum;
double _progress2Minimum;
double _progress2Value;
bool _progress2Visible;
bool _progress3IsIndeterminate;
double _progress3Maximum;
double _progress3Minimum;
double _progress3Value;
bool _progress3Visible;
bool _progressIsIndeterminate;
double _progressMaximum;
double _progressMinimum;
double _progressValue;
bool _progressVisible;
string _status2Message;
string _status3Message;
string _statusMessage;
_view = view;
_romSetId = romSetId;
FolderPath = folderPath;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
CanClose = false;
}
public ExportRomsViewModel(ExportRoms view, string folderPath, long romSetId)
{
_view = view;
_romSetId = romSetId;
FolderPath = folderPath;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
CanClose = false;
}
[NotNull]
public string PathLabel => Localization.PathLabel;
public string FolderPath { get; }
[NotNull]
public string PathLabel => Localization.PathLabel;
public string FolderPath { get; }
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public double ProgressMinimum
{
get => _progressMinimum;
set => this.RaiseAndSetIfChanged(ref _progressMinimum, value);
}
public double ProgressMinimum
{
get => _progressMinimum;
set => this.RaiseAndSetIfChanged(ref _progressMinimum, value);
}
public double ProgressMaximum
{
get => _progressMaximum;
set => this.RaiseAndSetIfChanged(ref _progressMaximum, value);
}
public double ProgressMaximum
{
get => _progressMaximum;
set => this.RaiseAndSetIfChanged(ref _progressMaximum, value);
}
public double ProgressValue
{
get => _progressValue;
set => this.RaiseAndSetIfChanged(ref _progressValue, value);
}
public double ProgressValue
{
get => _progressValue;
set => this.RaiseAndSetIfChanged(ref _progressValue, value);
}
public bool ProgressIsIndeterminate
{
get => _progressIsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progressIsIndeterminate, value);
}
public bool ProgressIsIndeterminate
{
get => _progressIsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progressIsIndeterminate, value);
}
public bool Progress2Visible
{
get => _progress2Visible;
set => this.RaiseAndSetIfChanged(ref _progress2Visible, value);
}
public bool Progress2Visible
{
get => _progress2Visible;
set => this.RaiseAndSetIfChanged(ref _progress2Visible, value);
}
public string Status2Message
{
get => _status2Message;
set => this.RaiseAndSetIfChanged(ref _status2Message, value);
}
public string Status2Message
{
get => _status2Message;
set => this.RaiseAndSetIfChanged(ref _status2Message, value);
}
public double Progress2Minimum
{
get => _progress2Minimum;
set => this.RaiseAndSetIfChanged(ref _progress2Minimum, value);
}
public double Progress2Minimum
{
get => _progress2Minimum;
set => this.RaiseAndSetIfChanged(ref _progress2Minimum, value);
}
public double Progress2Maximum
{
get => _progress2Maximum;
set => this.RaiseAndSetIfChanged(ref _progress2Maximum, value);
}
public double Progress2Maximum
{
get => _progress2Maximum;
set => this.RaiseAndSetIfChanged(ref _progress2Maximum, value);
}
public double Progress2Value
{
get => _progress2Value;
set => this.RaiseAndSetIfChanged(ref _progress2Value, value);
}
public double Progress2Value
{
get => _progress2Value;
set => this.RaiseAndSetIfChanged(ref _progress2Value, value);
}
public bool Progress2IsIndeterminate
{
get => _progress2IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress2IsIndeterminate, value);
}
public bool Progress2IsIndeterminate
{
get => _progress2IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress2IsIndeterminate, value);
}
public bool Progress3Visible
{
get => _progress3Visible;
set => this.RaiseAndSetIfChanged(ref _progress3Visible, value);
}
public bool Progress3Visible
{
get => _progress3Visible;
set => this.RaiseAndSetIfChanged(ref _progress3Visible, value);
}
public string Status3Message
{
get => _status3Message;
set => this.RaiseAndSetIfChanged(ref _status3Message, value);
}
public string Status3Message
{
get => _status3Message;
set => this.RaiseAndSetIfChanged(ref _status3Message, value);
}
public double Progress3Minimum
{
get => _progress3Minimum;
set => this.RaiseAndSetIfChanged(ref _progress3Minimum, value);
}
public double Progress3Minimum
{
get => _progress3Minimum;
set => this.RaiseAndSetIfChanged(ref _progress3Minimum, value);
}
public double Progress3Maximum
{
get => _progress3Maximum;
set => this.RaiseAndSetIfChanged(ref _progress3Maximum, value);
}
public double Progress3Maximum
{
get => _progress3Maximum;
set => this.RaiseAndSetIfChanged(ref _progress3Maximum, value);
}
public double Progress3Value
{
get => _progress3Value;
set => this.RaiseAndSetIfChanged(ref _progress3Value, value);
}
public double Progress3Value
{
get => _progress3Value;
set => this.RaiseAndSetIfChanged(ref _progress3Value, value);
}
public bool Progress3IsIndeterminate
{
get => _progress3IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress3IsIndeterminate, value);
}
public bool Progress3IsIndeterminate
{
get => _progress3IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress3IsIndeterminate, value);
}
[NotNull]
public string Title => Localization.ExportRomsTitle;
[NotNull]
public string CloseLabel => Localization.CloseLabel;
[NotNull]
public string Title => Localization.ExportRomsTitle;
[NotNull]
public string CloseLabel => Localization.CloseLabel;
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
void ExecuteCloseCommand() => _view.Close();
void ExecuteCloseCommand() => _view.Close();
void OnWorkerOnFinished(object sender, EventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressVisible = false;
CanClose = true;
Progress2Visible = false;
Progress3Visible = false;
});
void OnWorkerOnFinished(object sender, EventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressVisible = false;
CanClose = true;
Progress2Visible = false;
Progress3Visible = false;
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressIsIndeterminate = false;
ProgressMaximum = args.Maximum;
ProgressMinimum = args.Minimum;
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressIsIndeterminate = false;
ProgressMaximum = args.Maximum;
ProgressMinimum = args.Minimum;
});
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressValue = args.Value);
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressValue = args.Value);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => StatusMessage = args.Message);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => StatusMessage = args.Message);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressIsIndeterminate = true);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressIsIndeterminate = true);
void OnWorkerOnSetProgressBounds2(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress2Visible = true;
Progress2IsIndeterminate = false;
Progress2Maximum = args.Maximum;
Progress2Minimum = args.Minimum;
});
void OnWorkerOnSetProgressBounds2(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress2Visible = true;
Progress2IsIndeterminate = false;
Progress2Maximum = args.Maximum;
Progress2Minimum = args.Minimum;
});
void OnWorkerOnSetProgress2(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2Value = args.Value);
void OnWorkerOnSetProgress2(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2Value = args.Value);
void OnWorkerOnSetMessage2(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status2Message = args.Message);
void OnWorkerOnSetMessage2(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status2Message = args.Message);
void OnWorkerOnSetProgressBounds3(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress3Visible = true;
Progress3IsIndeterminate = false;
Progress3Maximum = args.Maximum;
Progress3Minimum = args.Minimum;
});
void OnWorkerOnSetProgressBounds3(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress3Visible = true;
Progress3IsIndeterminate = false;
Progress3Maximum = args.Maximum;
Progress3Minimum = args.Minimum;
});
void OnWorkerOnSetProgress3(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress3Value = args.Value);
void OnWorkerOnSetProgress3(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress3Value = args.Value);
void OnWorkerOnSetMessage3(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status3Message = args.Message);
void OnWorkerOnSetMessage3(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status3Message = args.Message);
public void OnOpened()
{
var worker = new FileExporter(_romSetId, FolderPath);
worker.SetMessage += OnWorkerOnSetMessage;
worker.SetProgress += OnWorkerOnSetProgress;
worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
worker.SetMessage2 += OnWorkerOnSetMessage2;
worker.SetProgress2 += OnWorkerOnSetProgress2;
worker.SetProgress2Bounds += OnWorkerOnSetProgressBounds2;
worker.SetMessage3 += OnWorkerOnSetMessage3;
worker.SetProgress3 += OnWorkerOnSetProgress3;
worker.SetProgress3Bounds += OnWorkerOnSetProgressBounds3;
worker.WorkFinished += OnWorkerOnFinished;
public void OnOpened()
{
var worker = new FileExporter(_romSetId, FolderPath);
worker.SetMessage += OnWorkerOnSetMessage;
worker.SetProgress += OnWorkerOnSetProgress;
worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
worker.SetMessage2 += OnWorkerOnSetMessage2;
worker.SetProgress2 += OnWorkerOnSetProgress2;
worker.SetProgress2Bounds += OnWorkerOnSetProgressBounds2;
worker.SetMessage3 += OnWorkerOnSetMessage3;
worker.SetProgress3 += OnWorkerOnSetProgress3;
worker.SetProgress3Bounds += OnWorkerOnSetProgressBounds3;
worker.WorkFinished += OnWorkerOnFinished;
ProgressVisible = true;
ProgressVisible = true;
Task.Run(worker.Export);
}
Task.Run(worker.Export);
}
}

View File

@@ -38,319 +38,325 @@ using RomRepoMgr.Resources;
using RomRepoMgr.Views;
using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class ImportDatFolderViewModel : ViewModelBase
{
public sealed class ImportDatFolderViewModel : ViewModelBase
readonly ImportDatFolder _view;
bool _allFilesChecked;
bool _canClose;
bool _canStart;
string _category;
string[] _datFiles;
bool _isImporting;
bool _isReady;
int _listPosition;
bool _progress2IsIndeterminate;
double _progress2Maximum;
double _progress2Minimum;
double _progress2Value;
bool _progress2Visible;
bool _progressIsIndeterminate;
double _progressMaximum;
double _progressMinimum;
double _progressValue;
bool _progressVisible;
bool _recursiveChecked;
string _status2Message;
string _statusMessage;
public ImportDatFolderViewModel(ImportDatFolder view, string folderPath)
{
readonly ImportDatFolder _view;
bool _allFilesChecked;
bool _canClose;
bool _canStart;
string _category;
string[] _datFiles;
bool _isImporting;
bool _isReady;
int _listPosition;
bool _progress2IsIndeterminate;
double _progress2Maximum;
double _progress2Minimum;
double _progress2Value;
bool _progress2Visible;
bool _progressIsIndeterminate;
double _progressMaximum;
double _progressMinimum;
double _progressValue;
bool _progressVisible;
bool _recursiveChecked;
string _status2Message;
string _statusMessage;
_view = view;
FolderPath = folderPath;
_allFilesChecked = false;
_recursiveChecked = true;
ImportResults = new ObservableCollection<ImportDatFolderItem>();
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
StartCommand = ReactiveCommand.Create(ExecuteStartCommand);
}
public ImportDatFolderViewModel(ImportDatFolder view, string folderPath)
public string PathLabel => Localization.PathLabel;
public string CategoryLabel => Localization.RomSetCategoryLabel;
public string FolderPath { get; }
public string AllFilesLabel => Localization.AllFilesLabel;
public string RecursiveLabel => Localization.RecursiveLabel;
public bool AllFilesChecked
{
get => _allFilesChecked;
set
{
_view = view;
FolderPath = folderPath;
_allFilesChecked = false;
_recursiveChecked = true;
ImportResults = new ObservableCollection<ImportDatFolderItem>();
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
StartCommand = ReactiveCommand.Create(ExecuteStartCommand);
this.RaiseAndSetIfChanged(ref _allFilesChecked, value);
RefreshFiles();
}
}
public string PathLabel => Localization.PathLabel;
public string CategoryLabel => Localization.RomSetCategoryLabel;
public string FolderPath { get; }
public string AllFilesLabel => Localization.AllFilesLabel;
public string RecursiveLabel => Localization.RecursiveLabel;
public bool AllFilesChecked
public bool RecursiveChecked
{
get => _recursiveChecked;
set
{
get => _allFilesChecked;
set
{
this.RaiseAndSetIfChanged(ref _allFilesChecked, value);
RefreshFiles();
}
this.RaiseAndSetIfChanged(ref _recursiveChecked, value);
RefreshFiles();
}
}
public bool RecursiveChecked
public bool IsReady
{
get => _isReady;
set => this.RaiseAndSetIfChanged(ref _isReady, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public double ProgressMinimum
{
get => _progressMinimum;
set => this.RaiseAndSetIfChanged(ref _progressMinimum, value);
}
public double ProgressMaximum
{
get => _progressMaximum;
set => this.RaiseAndSetIfChanged(ref _progressMaximum, value);
}
public double ProgressValue
{
get => _progressValue;
set => this.RaiseAndSetIfChanged(ref _progressValue, value);
}
public bool ProgressIsIndeterminate
{
get => _progressIsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progressIsIndeterminate, value);
}
public bool Progress2Visible
{
get => _progress2Visible;
set => this.RaiseAndSetIfChanged(ref _progress2Visible, value);
}
public string Status2Message
{
get => _status2Message;
set => this.RaiseAndSetIfChanged(ref _status2Message, value);
}
public double Progress2Minimum
{
get => _progress2Minimum;
set => this.RaiseAndSetIfChanged(ref _progress2Minimum, value);
}
public double Progress2Maximum
{
get => _progress2Maximum;
set => this.RaiseAndSetIfChanged(ref _progress2Maximum, value);
}
public double Progress2Value
{
get => _progress2Value;
set => this.RaiseAndSetIfChanged(ref _progress2Value, value);
}
public bool Progress2IsIndeterminate
{
get => _progress2IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress2IsIndeterminate, value);
}
public bool IsImporting
{
get => _isImporting;
set => this.RaiseAndSetIfChanged(ref _isImporting, value);
}
public string Category
{
get => _category;
set => this.RaiseAndSetIfChanged(ref _category, value);
}
[NotNull]
public string Title => Localization.ImportDatFolderTitle;
public ObservableCollection<ImportDatFolderItem> ImportResults { get; }
public string ResultFilenameLabel => Localization.ResultFilenameLabel;
public string ResultStatusLabel => Localization.ResultStatusLabel;
public string CloseLabel => Localization.CloseLabel;
public string StartLabel => Localization.StartLabel;
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public bool CanStart
{
get => _canStart;
set => this.RaiseAndSetIfChanged(ref _canStart, value);
}
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> StartCommand { get; }
internal void OnOpened() => RefreshFiles();
void RefreshFiles() => Task.Run(() =>
{
Dispatcher.UIThread.Post(() =>
{
get => _recursiveChecked;
set
{
this.RaiseAndSetIfChanged(ref _recursiveChecked, value);
RefreshFiles();
}
}
public bool IsReady
{
get => _isReady;
set => this.RaiseAndSetIfChanged(ref _isReady, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public double ProgressMinimum
{
get => _progressMinimum;
set => this.RaiseAndSetIfChanged(ref _progressMinimum, value);
}
public double ProgressMaximum
{
get => _progressMaximum;
set => this.RaiseAndSetIfChanged(ref _progressMaximum, value);
}
public double ProgressValue
{
get => _progressValue;
set => this.RaiseAndSetIfChanged(ref _progressValue, value);
}
public bool ProgressIsIndeterminate
{
get => _progressIsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progressIsIndeterminate, value);
}
public bool Progress2Visible
{
get => _progress2Visible;
set => this.RaiseAndSetIfChanged(ref _progress2Visible, value);
}
public string Status2Message
{
get => _status2Message;
set => this.RaiseAndSetIfChanged(ref _status2Message, value);
}
public double Progress2Minimum
{
get => _progress2Minimum;
set => this.RaiseAndSetIfChanged(ref _progress2Minimum, value);
}
public double Progress2Maximum
{
get => _progress2Maximum;
set => this.RaiseAndSetIfChanged(ref _progress2Maximum, value);
}
public double Progress2Value
{
get => _progress2Value;
set => this.RaiseAndSetIfChanged(ref _progress2Value, value);
}
public bool Progress2IsIndeterminate
{
get => _progress2IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress2IsIndeterminate, value);
}
public bool IsImporting
{
get => _isImporting;
set => this.RaiseAndSetIfChanged(ref _isImporting, value);
}
public string Category
{
get => _category;
set => this.RaiseAndSetIfChanged(ref _category, value);
}
[NotNull]
public string Title => Localization.ImportDatFolderTitle;
public ObservableCollection<ImportDatFolderItem> ImportResults { get; }
public string ResultFilenameLabel => Localization.ResultFilenameLabel;
public string ResultStatusLabel => Localization.ResultStatusLabel;
public string CloseLabel => Localization.CloseLabel;
public string StartLabel => Localization.StartLabel;
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public bool CanStart
{
get => _canStart;
set => this.RaiseAndSetIfChanged(ref _canStart, value);
}
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> StartCommand { get; }
internal void OnOpened() => RefreshFiles();
void RefreshFiles() => Task.Run(() =>
{
Dispatcher.UIThread.Post(() =>
{
IsReady = false;
ProgressVisible = true;
Progress2Visible = false;
ProgressIsIndeterminate = true;
StatusMessage = Localization.SearchingForFiles;
});
if(_allFilesChecked)
{
_datFiles = Directory.GetFiles(FolderPath, "*.*",
_recursiveChecked ? SearchOption.AllDirectories
: SearchOption.TopDirectoryOnly).OrderBy(f => f).ToArray();
}
else
{
string[] dats = Directory.GetFiles(FolderPath, "*.dat",
_recursiveChecked ? SearchOption.AllDirectories
: SearchOption.TopDirectoryOnly);
string[] xmls = Directory.GetFiles(FolderPath, "*.xml",
_recursiveChecked ? SearchOption.AllDirectories
: SearchOption.TopDirectoryOnly);
_datFiles = dats.Concat(xmls).OrderBy(f => f).ToArray();
}
Dispatcher.UIThread.Post(() =>
{
IsReady = true;
ProgressVisible = false;
StatusMessage = string.Format(Localization.FoundFiles, _datFiles.Length);
CanClose = true;
CanStart = true;
});
});
void ExecuteCloseCommand() => _view.Close();
void ExecuteStartCommand()
{
_listPosition = 0;
ProgressMinimum = 0;
ProgressMaximum = _datFiles.Length;
ProgressValue = 0;
ProgressIsIndeterminate = false;
ProgressVisible = true;
Progress2Visible = true;
CanClose = false;
CanStart = false;
IsReady = false;
IsImporting = true;
ProgressVisible = true;
Progress2Visible = false;
ProgressIsIndeterminate = true;
StatusMessage = Localization.SearchingForFiles;
});
Import();
if(_allFilesChecked)
{
_datFiles = Directory
.GetFiles(FolderPath,
"*.*",
_recursiveChecked ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
.OrderBy(f => f)
.ToArray();
}
else
{
string[] dats = Directory.GetFiles(FolderPath,
"*.dat",
_recursiveChecked
? SearchOption.AllDirectories
: SearchOption.TopDirectoryOnly);
string[] xmls = Directory.GetFiles(FolderPath,
"*.xml",
_recursiveChecked
? SearchOption.AllDirectories
: SearchOption.TopDirectoryOnly);
_datFiles = dats.Concat(xmls).OrderBy(f => f).ToArray();
}
void Import()
Dispatcher.UIThread.Post(() =>
{
if(_listPosition >= _datFiles.Length)
{
Progress2Visible = false;
ProgressVisible = false;
StatusMessage = Localization.Finished;
CanClose = true;
CanStart = false;
IsReady = true;
return;
}
StatusMessage = string.Format(Localization.ImportingItem, Path.GetFileName(_datFiles[_listPosition]));
ProgressValue = _listPosition;
var _worker = new DatImporter(_datFiles[_listPosition], Category);
_worker.ErrorOccurred += OnWorkerOnErrorOccurred;
_worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress;
_worker.SetMessage += OnWorkerOnSetMessage;
_worker.SetProgress += OnWorkerOnSetProgress;
_worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
_worker.WorkFinished += OnWorkerOnWorkFinished;
_worker.RomSetAdded += RomSetAdded;
Task.Run(_worker.Import);
}
void OnWorkerOnWorkFinished(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ImportResults.Add(new ImportDatFolderItem
{
Filename = Path.GetFileName(_datFiles[_listPosition]),
Status = args.Message
});
_listPosition++;
Import();
IsReady = true;
ProgressVisible = false;
StatusMessage = string.Format(Localization.FoundFiles, _datFiles.Length);
CanClose = true;
CanStart = true;
});
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress2IsIndeterminate = false;
Progress2Maximum = args.Maximum;
Progress2Minimum = args.Minimum;
});
void ExecuteCloseCommand() => _view.Close();
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2Value = args.Value);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status2Message = args.Message);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2IsIndeterminate = true);
void OnWorkerOnErrorOccurred(object sender, ErrorEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ImportResults.Add(new ImportDatFolderItem
{
Filename = Path.GetFileName(_datFiles[_listPosition]),
Status = args.Message
});
_listPosition++;
Import();
});
public event EventHandler<RomSetEventArgs> RomSetAdded;
}
public sealed class ImportDatFolderItem
void ExecuteStartCommand()
{
public string Filename { get; set; }
public string Status { get; set; }
_listPosition = 0;
ProgressMinimum = 0;
ProgressMaximum = _datFiles.Length;
ProgressValue = 0;
ProgressIsIndeterminate = false;
ProgressVisible = true;
Progress2Visible = true;
CanClose = false;
CanStart = false;
IsReady = false;
IsImporting = true;
Import();
}
void Import()
{
if(_listPosition >= _datFiles.Length)
{
Progress2Visible = false;
ProgressVisible = false;
StatusMessage = Localization.Finished;
CanClose = true;
CanStart = false;
IsReady = true;
return;
}
StatusMessage = string.Format(Localization.ImportingItem, Path.GetFileName(_datFiles[_listPosition]));
ProgressValue = _listPosition;
var _worker = new DatImporter(_datFiles[_listPosition], Category);
_worker.ErrorOccurred += OnWorkerOnErrorOccurred;
_worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress;
_worker.SetMessage += OnWorkerOnSetMessage;
_worker.SetProgress += OnWorkerOnSetProgress;
_worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
_worker.WorkFinished += OnWorkerOnWorkFinished;
_worker.RomSetAdded += RomSetAdded;
Task.Run(_worker.Import);
}
void OnWorkerOnWorkFinished(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ImportResults.Add(new ImportDatFolderItem
{
Filename = Path.GetFileName(_datFiles[_listPosition]),
Status = args.Message
});
_listPosition++;
Import();
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress2IsIndeterminate = false;
Progress2Maximum = args.Maximum;
Progress2Minimum = args.Minimum;
});
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2Value = args.Value);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status2Message = args.Message);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2IsIndeterminate = true);
void OnWorkerOnErrorOccurred(object sender, ErrorEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ImportResults.Add(new ImportDatFolderItem
{
Filename = Path.GetFileName(_datFiles[_listPosition]),
Status = args.Message
});
_listPosition++;
Import();
});
public event EventHandler<RomSetEventArgs> RomSetAdded;
}
public sealed class ImportDatFolderItem
{
public string Filename { get; set; }
public string Status { get; set; }
}

View File

@@ -34,138 +34,137 @@ using RomRepoMgr.Core.Workers;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class ImportDatViewModel : ViewModelBase
{
public sealed class ImportDatViewModel : ViewModelBase
readonly ImportDat _view;
readonly DatImporter _worker;
bool _canClose;
double _currentValue;
string _errorMessage;
bool _errorVisible;
bool _indeterminateProgress;
double _maximumValue;
double _minimumValue;
bool _progressVisible;
string _statusMessage;
public ImportDatViewModel(ImportDat view, string datPath)
{
readonly ImportDat _view;
readonly DatImporter _worker;
bool _canClose;
double _currentValue;
string _errorMessage;
bool _errorVisible;
bool _indeterminateProgress;
double _maximumValue;
double _minimumValue;
bool _progressVisible;
string _statusMessage;
public ImportDatViewModel(ImportDat view, string datPath)
{
_view = view;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
IndeterminateProgress = true;
ProgressVisible = false;
ErrorVisible = false;
_worker = new DatImporter(datPath, null);
_worker.ErrorOccurred += OnWorkerOnErrorOccurred;
_worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress;
_worker.SetMessage += OnWorkerOnSetMessage;
_worker.SetProgress += OnWorkerOnSetProgress;
_worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
_worker.WorkFinished += OnWorkerOnWorkFinished;
}
[NotNull]
public string Title => Localization.ImportDatTitle;
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public bool IndeterminateProgress
{
get => _indeterminateProgress;
set => this.RaiseAndSetIfChanged(ref _indeterminateProgress, value);
}
public double MaximumValue
{
get => _maximumValue;
set => this.RaiseAndSetIfChanged(ref _maximumValue, value);
}
public double MinimumValue
{
get => _minimumValue;
set => this.RaiseAndSetIfChanged(ref _minimumValue, value);
}
public double CurrentValue
{
get => _currentValue;
set => this.RaiseAndSetIfChanged(ref _currentValue, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public bool ErrorVisible
{
get => _errorVisible;
set => this.RaiseAndSetIfChanged(ref _errorVisible, value);
}
public string ErrorMessage
{
get => _errorMessage;
set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
void OnWorkerOnWorkFinished(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
StatusMessage = args.Message;
ProgressVisible = false;
CanClose = true;
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
IndeterminateProgress = false;
MaximumValue = args.Maximum;
MinimumValue = args.Minimum;
});
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => CurrentValue = args.Value);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => StatusMessage = args.Message);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => IndeterminateProgress = true);
void OnWorkerOnErrorOccurred(object sender, ErrorEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ErrorMessage = args.Message;
ProgressVisible = false;
ErrorVisible = true;
CanClose = true;
});
void ExecuteCloseCommand() => _view.Close();
internal void OnOpened()
{
ProgressVisible = true;
_worker.RomSetAdded += RomSetAdded;
Task.Run(_worker.Import);
}
public event EventHandler<RomSetEventArgs> RomSetAdded;
_view = view;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
IndeterminateProgress = true;
ProgressVisible = false;
ErrorVisible = false;
_worker = new DatImporter(datPath, null);
_worker.ErrorOccurred += OnWorkerOnErrorOccurred;
_worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress;
_worker.SetMessage += OnWorkerOnSetMessage;
_worker.SetProgress += OnWorkerOnSetProgress;
_worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
_worker.WorkFinished += OnWorkerOnWorkFinished;
}
[NotNull]
public string Title => Localization.ImportDatTitle;
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public bool IndeterminateProgress
{
get => _indeterminateProgress;
set => this.RaiseAndSetIfChanged(ref _indeterminateProgress, value);
}
public double MaximumValue
{
get => _maximumValue;
set => this.RaiseAndSetIfChanged(ref _maximumValue, value);
}
public double MinimumValue
{
get => _minimumValue;
set => this.RaiseAndSetIfChanged(ref _minimumValue, value);
}
public double CurrentValue
{
get => _currentValue;
set => this.RaiseAndSetIfChanged(ref _currentValue, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public bool ErrorVisible
{
get => _errorVisible;
set => this.RaiseAndSetIfChanged(ref _errorVisible, value);
}
public string ErrorMessage
{
get => _errorMessage;
set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
void OnWorkerOnWorkFinished(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
StatusMessage = args.Message;
ProgressVisible = false;
CanClose = true;
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
IndeterminateProgress = false;
MaximumValue = args.Maximum;
MinimumValue = args.Minimum;
});
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => CurrentValue = args.Value);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => StatusMessage = args.Message);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => IndeterminateProgress = true);
void OnWorkerOnErrorOccurred(object sender, ErrorEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ErrorMessage = args.Message;
ProgressVisible = false;
ErrorVisible = true;
CanClose = true;
});
void ExecuteCloseCommand() => _view.Close();
internal void OnOpened()
{
ProgressVisible = true;
_worker.RomSetAdded += RomSetAdded;
Task.Run(_worker.Import);
}
public event EventHandler<RomSetEventArgs> RomSetAdded;
}

View File

@@ -36,261 +36,259 @@ using RomRepoMgr.Core.Workers;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class ImportRomFolderViewModel : ViewModelBase
{
public sealed class ImportRomFolderViewModel : ViewModelBase
readonly ImportRomFolder _view;
bool _canClose;
bool _canStart;
bool _isImporting;
bool _isReady;
bool _knownOnlyChecked;
bool _progress2IsIndeterminate;
double _progress2Maximum;
double _progress2Minimum;
double _progress2Value;
bool _progress2Visible;
bool _progressIsIndeterminate;
double _progressMaximum;
double _progressMinimum;
double _progressValue;
bool _progressVisible;
bool _recurseArchivesChecked;
bool _removeFilesChecked;
bool _removeFilesEnabled;
string _status2Message;
string _statusMessage;
public ImportRomFolderViewModel(ImportRomFolder view, string folderPath)
{
readonly ImportRomFolder _view;
bool _canClose;
bool _canStart;
bool _isImporting;
bool _isReady;
bool _knownOnlyChecked;
bool _progress2IsIndeterminate;
double _progress2Maximum;
double _progress2Minimum;
double _progress2Value;
bool _progress2Visible;
bool _progressIsIndeterminate;
double _progressMaximum;
double _progressMinimum;
double _progressValue;
bool _progressVisible;
bool _recurseArchivesChecked;
bool _removeFilesChecked;
bool _removeFilesEnabled;
string _status2Message;
string _statusMessage;
public ImportRomFolderViewModel(ImportRomFolder view, string folderPath)
{
_view = view;
FolderPath = folderPath;
_removeFilesChecked = false;
_knownOnlyChecked = true;
_recurseArchivesChecked = Settings.Settings.UnArUsable;
ImportResults = new ObservableCollection<ImportRomItem>();
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
StartCommand = ReactiveCommand.Create(ExecuteStartCommand);
IsReady = true;
CanStart = true;
CanClose = true;
_removeFilesEnabled = false;
}
public string PathLabel => Localization.PathLabel;
public string FolderPath { get; }
public string RemoveFilesLabel => Localization.RemoveFilesLabel;
public string KnownOnlyLabel => Localization.KnownOnlyLabel;
public string RecurseArchivesLabel => Localization.RecurseArchivesLabel;
public bool RecurseArchivesEnabled => Settings.Settings.UnArUsable;
public bool RemoveFilesChecked
{
get => _removeFilesChecked;
set => this.RaiseAndSetIfChanged(ref _removeFilesChecked, value);
}
public bool KnownOnlyChecked
{
get => _knownOnlyChecked;
set => this.RaiseAndSetIfChanged(ref _knownOnlyChecked, value);
}
public bool RemoveFilesEnabled
{
get => _removeFilesEnabled;
set => this.RaiseAndSetIfChanged(ref _removeFilesEnabled, value);
}
public bool RecurseArchivesChecked
{
get => _recurseArchivesChecked;
set
{
if(value)
RemoveFilesChecked = false;
RemoveFilesEnabled = !value;
this.RaiseAndSetIfChanged(ref _recurseArchivesChecked, value);
}
}
public bool IsReady
{
get => _isReady;
set => this.RaiseAndSetIfChanged(ref _isReady, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public double ProgressMinimum
{
get => _progressMinimum;
set => this.RaiseAndSetIfChanged(ref _progressMinimum, value);
}
public double ProgressMaximum
{
get => _progressMaximum;
set => this.RaiseAndSetIfChanged(ref _progressMaximum, value);
}
public double ProgressValue
{
get => _progressValue;
set => this.RaiseAndSetIfChanged(ref _progressValue, value);
}
public bool ProgressIsIndeterminate
{
get => _progressIsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progressIsIndeterminate, value);
}
public bool Progress2Visible
{
get => _progress2Visible;
set => this.RaiseAndSetIfChanged(ref _progress2Visible, value);
}
public string Status2Message
{
get => _status2Message;
set => this.RaiseAndSetIfChanged(ref _status2Message, value);
}
public double Progress2Minimum
{
get => _progress2Minimum;
set => this.RaiseAndSetIfChanged(ref _progress2Minimum, value);
}
public double Progress2Maximum
{
get => _progress2Maximum;
set => this.RaiseAndSetIfChanged(ref _progress2Maximum, value);
}
public double Progress2Value
{
get => _progress2Value;
set => this.RaiseAndSetIfChanged(ref _progress2Value, value);
}
public bool Progress2IsIndeterminate
{
get => _progress2IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress2IsIndeterminate, value);
}
public bool IsImporting
{
get => _isImporting;
set => this.RaiseAndSetIfChanged(ref _isImporting, value);
}
[NotNull]
public string Title => Localization.ImportRomFolderTitle;
public ObservableCollection<ImportRomItem> ImportResults { get; }
public string ResultFilenameLabel => Localization.ResultFilenameLabel;
public string ResultStatusLabel => Localization.ResultStatusLabel;
public string CloseLabel => Localization.CloseLabel;
public string StartLabel => Localization.StartLabel;
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public bool CanStart
{
get => _canStart;
set => this.RaiseAndSetIfChanged(ref _canStart, value);
}
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> StartCommand { get; }
void ExecuteCloseCommand() => _view.Close();
void ExecuteStartCommand()
{
IsReady = false;
ProgressVisible = true;
IsImporting = true;
CanStart = false;
CanClose = false;
Progress2Visible = true;
var worker = new FileImporter(KnownOnlyChecked, RemoveFilesChecked);
worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress;
worker.SetMessage += OnWorkerOnSetMessage;
worker.SetProgress += OnWorkerOnSetProgress;
worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
worker.SetIndeterminateProgress2 += OnWorkerOnSetIndeterminateProgress2;
worker.SetMessage2 += OnWorkerOnSetMessage2;
worker.SetProgress2 += OnWorkerOnSetProgress2;
worker.SetProgressBounds2 += OnWorkerOnSetProgressBounds2;
worker.Finished += OnWorkerOnFinished;
worker.ImportedRom += OnWorkerOnImportedRom;
Task.Run(() => worker.ProcessPath(FolderPath, true, RecurseArchivesChecked));
}
void OnWorkerOnImportedRom(object sender, ImportedRomItemEventArgs args) =>
Dispatcher.UIThread.Post(() => ImportResults.Add(args.Item));
void OnWorkerOnFinished(object sender, EventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressVisible = false;
StatusMessage = Localization.Finished;
CanClose = true;
Progress2Visible = false;
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressIsIndeterminate = false;
ProgressMaximum = args.Maximum;
ProgressMinimum = args.Minimum;
});
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressValue = args.Value);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => StatusMessage = args.Message);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressIsIndeterminate = true);
void OnWorkerOnSetProgressBounds2(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress2IsIndeterminate = false;
Progress2Maximum = args.Maximum;
Progress2Minimum = args.Minimum;
});
void OnWorkerOnSetProgress2(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2Value = args.Value);
void OnWorkerOnSetMessage2(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status2Message = args.Message);
void OnWorkerOnSetIndeterminateProgress2(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2IsIndeterminate = true);
_view = view;
FolderPath = folderPath;
_removeFilesChecked = false;
_knownOnlyChecked = true;
_recurseArchivesChecked = Settings.Settings.UnArUsable;
ImportResults = new ObservableCollection<ImportRomItem>();
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
StartCommand = ReactiveCommand.Create(ExecuteStartCommand);
IsReady = true;
CanStart = true;
CanClose = true;
_removeFilesEnabled = false;
}
public string PathLabel => Localization.PathLabel;
public string FolderPath { get; }
public string RemoveFilesLabel => Localization.RemoveFilesLabel;
public string KnownOnlyLabel => Localization.KnownOnlyLabel;
public string RecurseArchivesLabel => Localization.RecurseArchivesLabel;
public bool RecurseArchivesEnabled => Settings.Settings.UnArUsable;
public bool RemoveFilesChecked
{
get => _removeFilesChecked;
set => this.RaiseAndSetIfChanged(ref _removeFilesChecked, value);
}
public bool KnownOnlyChecked
{
get => _knownOnlyChecked;
set => this.RaiseAndSetIfChanged(ref _knownOnlyChecked, value);
}
public bool RemoveFilesEnabled
{
get => _removeFilesEnabled;
set => this.RaiseAndSetIfChanged(ref _removeFilesEnabled, value);
}
public bool RecurseArchivesChecked
{
get => _recurseArchivesChecked;
set
{
if(value) RemoveFilesChecked = false;
RemoveFilesEnabled = !value;
this.RaiseAndSetIfChanged(ref _recurseArchivesChecked, value);
}
}
public bool IsReady
{
get => _isReady;
set => this.RaiseAndSetIfChanged(ref _isReady, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public double ProgressMinimum
{
get => _progressMinimum;
set => this.RaiseAndSetIfChanged(ref _progressMinimum, value);
}
public double ProgressMaximum
{
get => _progressMaximum;
set => this.RaiseAndSetIfChanged(ref _progressMaximum, value);
}
public double ProgressValue
{
get => _progressValue;
set => this.RaiseAndSetIfChanged(ref _progressValue, value);
}
public bool ProgressIsIndeterminate
{
get => _progressIsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progressIsIndeterminate, value);
}
public bool Progress2Visible
{
get => _progress2Visible;
set => this.RaiseAndSetIfChanged(ref _progress2Visible, value);
}
public string Status2Message
{
get => _status2Message;
set => this.RaiseAndSetIfChanged(ref _status2Message, value);
}
public double Progress2Minimum
{
get => _progress2Minimum;
set => this.RaiseAndSetIfChanged(ref _progress2Minimum, value);
}
public double Progress2Maximum
{
get => _progress2Maximum;
set => this.RaiseAndSetIfChanged(ref _progress2Maximum, value);
}
public double Progress2Value
{
get => _progress2Value;
set => this.RaiseAndSetIfChanged(ref _progress2Value, value);
}
public bool Progress2IsIndeterminate
{
get => _progress2IsIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progress2IsIndeterminate, value);
}
public bool IsImporting
{
get => _isImporting;
set => this.RaiseAndSetIfChanged(ref _isImporting, value);
}
[NotNull]
public string Title => Localization.ImportRomFolderTitle;
public ObservableCollection<ImportRomItem> ImportResults { get; }
public string ResultFilenameLabel => Localization.ResultFilenameLabel;
public string ResultStatusLabel => Localization.ResultStatusLabel;
public string CloseLabel => Localization.CloseLabel;
public string StartLabel => Localization.StartLabel;
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public bool CanStart
{
get => _canStart;
set => this.RaiseAndSetIfChanged(ref _canStart, value);
}
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> StartCommand { get; }
void ExecuteCloseCommand() => _view.Close();
void ExecuteStartCommand()
{
IsReady = false;
ProgressVisible = true;
IsImporting = true;
CanStart = false;
CanClose = false;
Progress2Visible = true;
var worker = new FileImporter(KnownOnlyChecked, RemoveFilesChecked);
worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress;
worker.SetMessage += OnWorkerOnSetMessage;
worker.SetProgress += OnWorkerOnSetProgress;
worker.SetProgressBounds += OnWorkerOnSetProgressBounds;
worker.SetIndeterminateProgress2 += OnWorkerOnSetIndeterminateProgress2;
worker.SetMessage2 += OnWorkerOnSetMessage2;
worker.SetProgress2 += OnWorkerOnSetProgress2;
worker.SetProgressBounds2 += OnWorkerOnSetProgressBounds2;
worker.Finished += OnWorkerOnFinished;
worker.ImportedRom += OnWorkerOnImportedRom;
Task.Run(() => worker.ProcessPath(FolderPath, true, RecurseArchivesChecked));
}
void OnWorkerOnImportedRom(object sender, ImportedRomItemEventArgs args) =>
Dispatcher.UIThread.Post(() => ImportResults.Add(args.Item));
void OnWorkerOnFinished(object sender, EventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressVisible = false;
StatusMessage = Localization.Finished;
CanClose = true;
Progress2Visible = false;
});
void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
ProgressIsIndeterminate = false;
ProgressMaximum = args.Maximum;
ProgressMinimum = args.Minimum;
});
void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressValue = args.Value);
void OnWorkerOnSetMessage(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => StatusMessage = args.Message);
void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => ProgressIsIndeterminate = true);
void OnWorkerOnSetProgressBounds2(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() =>
{
Progress2IsIndeterminate = false;
Progress2Maximum = args.Maximum;
Progress2Minimum = args.Minimum;
});
void OnWorkerOnSetProgress2(object sender, ProgressEventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2Value = args.Value);
void OnWorkerOnSetMessage2(object sender, MessageEventArgs args) =>
Dispatcher.UIThread.Post(() => Status2Message = args.Message);
void OnWorkerOnSetIndeterminateProgress2(object sender, EventArgs args) =>
Dispatcher.UIThread.Post(() => Progress2IsIndeterminate = true);
}

View File

@@ -42,330 +42,318 @@ using RomRepoMgr.Core.Models;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public class MainWindowViewModel : ViewModelBase
{
public class MainWindowViewModel : ViewModelBase
readonly MainWindow _view;
RomSetModel _selectedRomSet;
Vfs _vfs;
public MainWindowViewModel(MainWindow view, List<RomSetModel> romSets)
{
readonly MainWindow _view;
RomSetModel _selectedRomSet;
Vfs _vfs;
_view = view;
ExitCommand = ReactiveCommand.Create(ExecuteExitCommand);
SettingsCommand = ReactiveCommand.Create(ExecuteSettingsCommand);
AboutCommand = ReactiveCommand.Create(ExecuteAboutCommand);
ImportDatCommand = ReactiveCommand.Create(ExecuteImportDatCommand);
ImportDatFolderCommand = ReactiveCommand.Create(ExecuteImportDatFolderCommand);
ImportRomFolderCommand = ReactiveCommand.Create(ExecuteImportRomFolderCommand);
DeleteRomSetCommand = ReactiveCommand.Create(ExecuteDeleteRomSetCommand);
EditRomSetCommand = ReactiveCommand.Create(ExecuteEditRomSetCommand);
ExportDatCommand = ReactiveCommand.Create(ExecuteExportDatCommand);
ExportRomsCommand = ReactiveCommand.Create(ExecuteExportRomsCommand);
MountCommand = ReactiveCommand.Create(ExecuteMountCommand);
UmountCommand = ReactiveCommand.Create(ExecuteUmountCommand);
UpdateStatsCommand = ReactiveCommand.Create(ExecuteUpdateStatsCommand);
RomSets = new ObservableCollection<RomSetModel>(romSets);
}
public MainWindowViewModel(MainWindow view, List<RomSetModel> romSets)
public ObservableCollection<RomSetModel> RomSets { get; }
public string RomSetLabel => Localization.RomSets;
public string RomSetNameLabel => Localization.RomSetNameLabel;
public string RomSetVersionLabel => Localization.RomSetVersionLabel;
public string RomSetAuthorLabel => Localization.RomSetAuthorLabel;
public string RomSetCategoryLabel => Localization.RomSetCategoryLabel;
public string RomSetDateLabel => Localization.RomSetDateLabel;
public string RomSetDescriptionLabel => Localization.RomSetDescriptionLabel;
public string RomSetCommentLabel => Localization.RomSetCommentLabel;
public string RomSetTotalMachinesLabel => Localization.RomSetTotalMachinesLabel;
public string RomSetCompleteMachinesLabel => Localization.RomSetCompleteMachinesLabel;
public string RomSetIncompleteMachinesLabel => Localization.RomSetIncompleteMachinesLabel;
public string RomSetTotalRomsLabel => Localization.RomSetTotalRomsLabel;
public string RomSetHaveRomsLabel => Localization.RomSetHaveRomsLabel;
public string RomSetMissRomsLabel => Localization.RomSetMissRomsLabel;
public bool IsVfsAvailable => Vfs.IsAvailable;
public string FileMenuText => Localization.FileMenuText;
public string FileMenuImportDatFileText => Localization.FileMenuImportDatFileText;
public string FileMenuImportDatFolderText => Localization.FileMenuImportDatFolderText;
public string FileMenuSettingsText => Localization.FileMenuSettingsText;
public string FileMenuExitText => Localization.FileMenuExitText;
public string FilesystemMenuText => Localization.FilesystemMenuText;
public string FilesystemMenuMountText => Localization.FilesystemMenuMountText;
public string RomsMenuText => Localization.RomsMenuText;
public string RomsMenuImportText => Localization.RomsMenuImportText;
public string RomSetsMenuText => Localization.RomSetsMenuText;
public string RomSetsMenuSaveRomsText => Localization.RomSetsMenuSaveRomsText;
public string RomSetsMenuSaveDatText => Localization.RomSetsMenuSaveDatText;
public string RomSetsMenuEditText => Localization.RomSetsMenuEditText;
public string RomSetsMenuDeleteText => Localization.RomSetsMenuDeleteText;
public string HelpMenuText => Localization.HelpMenuText;
public string HelpMenuAboutText => Localization.HelpMenuAboutText;
public string FilesystemMenuUmountText => Localization.FilesystemMenuUmountText;
public string DatabaseMenuText => Localization.DatabaseMenuText;
public string DatabaseMenuUpdateStatsText => Localization.DatabaseMenuUpdateStatsText;
public bool NativeMenuSupported =>
NativeMenu.GetIsNativeMenuExported((Application.Current.ApplicationLifetime as
IClassicDesktopStyleApplicationLifetime)?.MainWindow);
public ReactiveCommand<Unit, Unit> AboutCommand { get; }
public ReactiveCommand<Unit, Unit> ExitCommand { get; }
public ReactiveCommand<Unit, Unit> SettingsCommand { get; }
public ReactiveCommand<Unit, Unit> ImportDatCommand { get; }
public ReactiveCommand<Unit, Unit> ImportDatFolderCommand { get; }
public ReactiveCommand<Unit, Unit> ImportRomFolderCommand { get; }
public ReactiveCommand<Unit, Unit> DeleteRomSetCommand { get; }
public ReactiveCommand<Unit, Unit> EditRomSetCommand { get; }
public ReactiveCommand<Unit, Unit> ExportDatCommand { get; }
public ReactiveCommand<Unit, Unit> ExportRomsCommand { get; }
public ReactiveCommand<Unit, Unit> MountCommand { get; }
public ReactiveCommand<Unit, Unit> UmountCommand { get; }
public ReactiveCommand<Unit, Unit> UpdateStatsCommand { get; }
public Vfs Vfs
{
get => _vfs;
set => this.RaiseAndSetIfChanged(ref _vfs, value);
}
public RomSetModel SelectedRomSet
{
get => _selectedRomSet;
set => this.RaiseAndSetIfChanged(ref _selectedRomSet, value);
}
internal async void ExecuteSettingsCommand()
{
var dialog = new SettingsDialog();
dialog.DataContext = new SettingsViewModel(dialog);
await dialog.ShowDialog(_view);
}
internal void ExecuteExitCommand() =>
(Application.Current.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown();
internal void ExecuteAboutCommand()
{
var dialog = new About();
dialog.DataContext = new AboutViewModel(dialog);
dialog.ShowDialog(_view);
}
async void ExecuteImportDatCommand()
{
var dlgOpen = new OpenFileDialog
{
_view = view;
ExitCommand = ReactiveCommand.Create(ExecuteExitCommand);
SettingsCommand = ReactiveCommand.Create(ExecuteSettingsCommand);
AboutCommand = ReactiveCommand.Create(ExecuteAboutCommand);
ImportDatCommand = ReactiveCommand.Create(ExecuteImportDatCommand);
ImportDatFolderCommand = ReactiveCommand.Create(ExecuteImportDatFolderCommand);
ImportRomFolderCommand = ReactiveCommand.Create(ExecuteImportRomFolderCommand);
DeleteRomSetCommand = ReactiveCommand.Create(ExecuteDeleteRomSetCommand);
EditRomSetCommand = ReactiveCommand.Create(ExecuteEditRomSetCommand);
ExportDatCommand = ReactiveCommand.Create(ExecuteExportDatCommand);
ExportRomsCommand = ReactiveCommand.Create(ExecuteExportRomsCommand);
MountCommand = ReactiveCommand.Create(ExecuteMountCommand);
UmountCommand = ReactiveCommand.Create(ExecuteUmountCommand);
UpdateStatsCommand = ReactiveCommand.Create(ExecuteUpdateStatsCommand);
RomSets = new ObservableCollection<RomSetModel>(romSets);
}
AllowMultiple = false,
Title = Localization.ImportDatFileDialogTitle
};
public ObservableCollection<RomSetModel> RomSets { get; }
public string RomSetLabel => Localization.RomSets;
public string RomSetNameLabel => Localization.RomSetNameLabel;
public string RomSetVersionLabel => Localization.RomSetVersionLabel;
public string RomSetAuthorLabel => Localization.RomSetAuthorLabel;
public string RomSetCategoryLabel => Localization.RomSetCategoryLabel;
public string RomSetDateLabel => Localization.RomSetDateLabel;
public string RomSetDescriptionLabel => Localization.RomSetDescriptionLabel;
public string RomSetCommentLabel => Localization.RomSetCommentLabel;
public string RomSetTotalMachinesLabel => Localization.RomSetTotalMachinesLabel;
public string RomSetCompleteMachinesLabel => Localization.RomSetCompleteMachinesLabel;
public string RomSetIncompleteMachinesLabel => Localization.RomSetIncompleteMachinesLabel;
public string RomSetTotalRomsLabel => Localization.RomSetTotalRomsLabel;
public string RomSetHaveRomsLabel => Localization.RomSetHaveRomsLabel;
public string RomSetMissRomsLabel => Localization.RomSetMissRomsLabel;
public bool IsVfsAvailable => Vfs.IsAvailable;
public string FileMenuText => Localization.FileMenuText;
public string FileMenuImportDatFileText => Localization.FileMenuImportDatFileText;
public string FileMenuImportDatFolderText => Localization.FileMenuImportDatFolderText;
public string FileMenuSettingsText => Localization.FileMenuSettingsText;
public string FileMenuExitText => Localization.FileMenuExitText;
public string FilesystemMenuText => Localization.FilesystemMenuText;
public string FilesystemMenuMountText => Localization.FilesystemMenuMountText;
public string RomsMenuText => Localization.RomsMenuText;
public string RomsMenuImportText => Localization.RomsMenuImportText;
public string RomSetsMenuText => Localization.RomSetsMenuText;
public string RomSetsMenuSaveRomsText => Localization.RomSetsMenuSaveRomsText;
public string RomSetsMenuSaveDatText => Localization.RomSetsMenuSaveDatText;
public string RomSetsMenuEditText => Localization.RomSetsMenuEditText;
public string RomSetsMenuDeleteText => Localization.RomSetsMenuDeleteText;
public string HelpMenuText => Localization.HelpMenuText;
public string HelpMenuAboutText => Localization.HelpMenuAboutText;
public string FilesystemMenuUmountText => Localization.FilesystemMenuUmountText;
public string DatabaseMenuText => Localization.DatabaseMenuText;
public string DatabaseMenuUpdateStatsText => Localization.DatabaseMenuUpdateStatsText;
public bool NativeMenuSupported =>
NativeMenu.GetIsNativeMenuExported((Application.Current.ApplicationLifetime as
IClassicDesktopStyleApplicationLifetime)?.MainWindow);
public ReactiveCommand<Unit, Unit> AboutCommand { get; }
public ReactiveCommand<Unit, Unit> ExitCommand { get; }
public ReactiveCommand<Unit, Unit> SettingsCommand { get; }
public ReactiveCommand<Unit, Unit> ImportDatCommand { get; }
public ReactiveCommand<Unit, Unit> ImportDatFolderCommand { get; }
public ReactiveCommand<Unit, Unit> ImportRomFolderCommand { get; }
public ReactiveCommand<Unit, Unit> DeleteRomSetCommand { get; }
public ReactiveCommand<Unit, Unit> EditRomSetCommand { get; }
public ReactiveCommand<Unit, Unit> ExportDatCommand { get; }
public ReactiveCommand<Unit, Unit> ExportRomsCommand { get; }
public ReactiveCommand<Unit, Unit> MountCommand { get; }
public ReactiveCommand<Unit, Unit> UmountCommand { get; }
public ReactiveCommand<Unit, Unit> UpdateStatsCommand { get; }
public Vfs Vfs
dlgOpen.Filters.Add(new FileDialogFilter
{
get => _vfs;
set => this.RaiseAndSetIfChanged(ref _vfs, value);
}
public RomSetModel SelectedRomSet
{
get => _selectedRomSet;
set => this.RaiseAndSetIfChanged(ref _selectedRomSet, value);
}
internal async void ExecuteSettingsCommand()
{
var dialog = new SettingsDialog();
dialog.DataContext = new SettingsViewModel(dialog);
await dialog.ShowDialog(_view);
}
internal void ExecuteExitCommand() =>
(Application.Current.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown();
internal void ExecuteAboutCommand()
{
var dialog = new About();
dialog.DataContext = new AboutViewModel(dialog);
dialog.ShowDialog(_view);
}
async void ExecuteImportDatCommand()
{
var dlgOpen = new OpenFileDialog
Extensions = new List<string>
{
AllowMultiple = false,
Title = Localization.ImportDatFileDialogTitle
};
"dat",
"xml"
},
Name = Localization.DatFilesDialogLabel
});
dlgOpen.Filters.Add(new FileDialogFilter
{
Extensions = new List<string>
{
"dat",
"xml"
},
Name = Localization.DatFilesDialogLabel
});
dlgOpen.Filters.Add(new FileDialogFilter
{
Extensions = new List<string>
{
"*"
},
Name = Localization.AllFilesDialogLabel
});
string[] result = await dlgOpen.ShowAsync(_view);
if(result?.Length != 1)
return;
var dialog = new ImportDat();
var importDatViewModel = new ImportDatViewModel(dialog, result[0]);
importDatViewModel.RomSetAdded += ImportDatViewModelOnRomSetAdded;
dialog.DataContext = importDatViewModel;
await dialog.ShowDialog(_view);
}
void ImportDatViewModelOnRomSetAdded(object sender, RomSetEventArgs e) =>
Dispatcher.UIThread.Post(() => RomSets.Add(e.RomSet));
async void ExecuteImportDatFolderCommand()
dlgOpen.Filters.Add(new FileDialogFilter
{
var dlgOpen = new OpenFolderDialog
Extensions = new List<string>
{
Title = Localization.ImportDatFolderDialogTitle
};
"*"
},
Name = Localization.AllFilesDialogLabel
});
string result = await dlgOpen.ShowAsync(_view);
string[] result = await dlgOpen.ShowAsync(_view);
if(result == null)
return;
if(result?.Length != 1) return;
var dialog = new ImportDatFolder();
var importDatFolderViewModel = new ImportDatFolderViewModel(dialog, result);
importDatFolderViewModel.RomSetAdded += ImportDatViewModelOnRomSetAdded;
dialog.DataContext = importDatFolderViewModel;
await dialog.ShowDialog(_view);
}
var dialog = new ImportDat();
var importDatViewModel = new ImportDatViewModel(dialog, result[0]);
importDatViewModel.RomSetAdded += ImportDatViewModelOnRomSetAdded;
dialog.DataContext = importDatViewModel;
await dialog.ShowDialog(_view);
}
async void ExecuteImportRomFolderCommand()
void ImportDatViewModelOnRomSetAdded(object sender, RomSetEventArgs e) =>
Dispatcher.UIThread.Post(() => RomSets.Add(e.RomSet));
async void ExecuteImportDatFolderCommand()
{
var dlgOpen = new OpenFolderDialog
{
var dlgOpen = new OpenFolderDialog
{
Title = Localization.ImportRomsFolderDialogTitle
};
Title = Localization.ImportDatFolderDialogTitle
};
string result = await dlgOpen.ShowAsync(_view);
string result = await dlgOpen.ShowAsync(_view);
if(result == null)
return;
if(result == null) return;
var dialog = new ImportRomFolder();
var importRomFolderViewModel = new ImportRomFolderViewModel(dialog, result);
dialog.DataContext = importRomFolderViewModel;
await dialog.ShowDialog(_view);
}
var dialog = new ImportDatFolder();
var importDatFolderViewModel = new ImportDatFolderViewModel(dialog, result);
importDatFolderViewModel.RomSetAdded += ImportDatViewModelOnRomSetAdded;
dialog.DataContext = importDatFolderViewModel;
await dialog.ShowDialog(_view);
}
async void ExecuteDeleteRomSetCommand()
async void ExecuteImportRomFolderCommand()
{
var dlgOpen = new OpenFolderDialog
{
if(SelectedRomSet == null)
return;
Title = Localization.ImportRomsFolderDialogTitle
};
ButtonResult result = await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DeleteRomSetMsgBoxTitle,
string.
Format(Localization.DeleteRomSetMsgBoxCaption,
SelectedRomSet.Name), ButtonEnum.YesNo,
Icon.Database).ShowDialog(_view);
string result = await dlgOpen.ShowAsync(_view);
if(result == ButtonResult.No)
return;
if(result == null) return;
var dialog = new RemoveDat();
var removeDatViewModel = new RemoveDatViewModel(dialog, SelectedRomSet.Id);
dialog.DataContext = removeDatViewModel;
await dialog.ShowDialog(_view);
var dialog = new ImportRomFolder();
var importRomFolderViewModel = new ImportRomFolderViewModel(dialog, result);
dialog.DataContext = importRomFolderViewModel;
await dialog.ShowDialog(_view);
}
RomSets.Remove(SelectedRomSet);
SelectedRomSet = null;
}
async void ExecuteDeleteRomSetCommand()
{
if(SelectedRomSet == null) return;
void ExecuteEditRomSetCommand()
ButtonResult result = await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DeleteRomSetMsgBoxTitle,
string.Format(Localization.DeleteRomSetMsgBoxCaption,
SelectedRomSet.Name),
ButtonEnum.YesNo,
Icon.Database)
.ShowDialog(_view);
if(result == ButtonResult.No) return;
var dialog = new RemoveDat();
var removeDatViewModel = new RemoveDatViewModel(dialog, SelectedRomSet.Id);
dialog.DataContext = removeDatViewModel;
await dialog.ShowDialog(_view);
RomSets.Remove(SelectedRomSet);
SelectedRomSet = null;
}
void ExecuteEditRomSetCommand()
{
if(SelectedRomSet == null) return;
var window = new EditDat();
var viewModel = new EditDatViewModel(window, SelectedRomSet);
viewModel.RomSetModified += (sender, args) =>
{
if(SelectedRomSet == null)
return;
RomSetModel old = RomSets.FirstOrDefault(r => r.Id == args.RomSet.Id);
var window = new EditDat();
var viewModel = new EditDatViewModel(window, SelectedRomSet);
if(old == null) return;
viewModel.RomSetModified += (sender, args) =>
{
RomSetModel old = RomSets.FirstOrDefault(r => r.Id == args.RomSet.Id);
RomSets.Remove(old);
RomSets.Add(args.RomSet);
};
if(old == null)
return;
window.DataContext = viewModel;
RomSets.Remove(old);
RomSets.Add(args.RomSet);
};
window.Show();
}
window.DataContext = viewModel;
async void ExecuteExportDatCommand()
{
if(SelectedRomSet == null) return;
window.Show();
}
async void ExecuteExportDatCommand()
var dlgSave = new SaveFileDialog
{
if(SelectedRomSet == null)
return;
InitialFileName = SelectedRomSet.Filename
};
var dlgSave = new SaveFileDialog
{
InitialFileName = SelectedRomSet.Filename
};
string result = await dlgSave.ShowAsync(_view);
string result = await dlgSave.ShowAsync(_view);
if(result == null) return;
if(result == null)
return;
var dialog = new ExportDat();
var viewModel = new ExportDatViewModel(dialog, SelectedRomSet.Sha384, result);
dialog.DataContext = viewModel;
await dialog.ShowDialog(_view);
}
var dialog = new ExportDat();
var viewModel = new ExportDatViewModel(dialog, SelectedRomSet.Sha384, result);
dialog.DataContext = viewModel;
await dialog.ShowDialog(_view);
}
async void ExecuteExportRomsCommand()
async void ExecuteExportRomsCommand()
{
var dlgOpen = new OpenFolderDialog
{
var dlgOpen = new OpenFolderDialog
{
Title = Localization.ExportRomsDialogTitle
};
Title = Localization.ExportRomsDialogTitle
};
string result = await dlgOpen.ShowAsync(_view);
string result = await dlgOpen.ShowAsync(_view);
if(result == null)
return;
if(result == null) return;
var dialog = new ExportRoms();
var viewModel = new ExportRomsViewModel(dialog, result, SelectedRomSet.Id);
dialog.DataContext = viewModel;
await dialog.ShowDialog(_view);
}
var dialog = new ExportRoms();
var viewModel = new ExportRomsViewModel(dialog, result, SelectedRomSet.Id);
dialog.DataContext = viewModel;
await dialog.ShowDialog(_view);
}
async void ExecuteMountCommand()
async void ExecuteMountCommand()
{
if(Vfs != null) return;
var dlgOpen = new OpenFolderDialog
{
if(Vfs != null)
return;
Title = Localization.SelectMountPointDialogTitle
};
var dlgOpen = new OpenFolderDialog
{
Title = Localization.SelectMountPointDialogTitle
};
string result = await dlgOpen.ShowAsync(_view);
string result = await dlgOpen.ShowAsync(_view);
if(result == null) return;
if(result == null)
return;
try
{
Vfs = new Vfs();
Vfs.Umounted += VfsOnUmounted;
Vfs.MountTo(result);
}
catch(Exception)
{
if(Debugger.IsAttached)
throw;
Vfs = null;
}
}
void VfsOnUmounted(object sender, EventArgs e) => Vfs = null;
void ExecuteUmountCommand() => Vfs?.Umount();
async void ExecuteUpdateStatsCommand()
try
{
ButtonResult result = await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseMenuUpdateStatsText,
Localization.UpdateStatsConfirmationDialogText,
ButtonEnum.YesNo, Icon.Database).ShowDialog(_view);
Vfs = new Vfs();
Vfs.Umounted += VfsOnUmounted;
Vfs.MountTo(result);
}
catch(Exception)
{
if(Debugger.IsAttached) throw;
if(result == ButtonResult.No)
return;
var view = new UpdateStats();
var viewModel = new UpdateStatsViewModel(view);
view.DataContext = viewModel;
await view.ShowDialog(_view);
Vfs = null;
}
}
void VfsOnUmounted(object sender, EventArgs e) => Vfs = null;
void ExecuteUmountCommand() => Vfs?.Umount();
async void ExecuteUpdateStatsCommand()
{
ButtonResult result = await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DatabaseMenuUpdateStatsText,
Localization.UpdateStatsConfirmationDialogText,
ButtonEnum.YesNo,
Icon.Database)
.ShowDialog(_view);
if(result == ButtonResult.No) return;
var view = new UpdateStats();
var viewModel = new UpdateStatsViewModel(view);
view.DataContext = viewModel;
await view.ShowDialog(_view);
}
}

View File

@@ -34,84 +34,75 @@ using RomRepoMgr.Database.Models;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class RemoveDatViewModel : ViewModelBase
{
public sealed class RemoveDatViewModel : ViewModelBase
readonly long _romSetId;
readonly RemoveDat _view;
string _statusMessage;
public RemoveDatViewModel(RemoveDat view, long romSetId)
{
readonly long _romSetId;
readonly RemoveDat _view;
string _statusMessage;
public RemoveDatViewModel(RemoveDat view, long romSetId)
{
_view = view;
_romSetId = romSetId;
}
[NotNull]
public string Title => Localization.RemoveDatTitle;
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
internal void OnOpened() => Task.Run(() =>
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
Dispatcher.UIThread.Post(() => StatusMessage = Localization.RetrievingRomSetFromDatabase);
RomSet romSet = ctx.RomSets.Find(_romSetId);
if(romSet == null)
return;
Dispatcher.UIThread.Post(() => StatusMessage = Localization.RemovingRomSetFromDatabase);
ctx.RomSets.Remove(romSet);
Dispatcher.UIThread.Post(() => StatusMessage = Localization.SavingChangesToDatabase);
ctx.SaveChanges();
Dispatcher.UIThread.Post(() => StatusMessage = Localization.RemovingDatFileFromRepo);
byte[] sha384Bytes = new byte[48];
string sha384 = romSet.Sha384;
for(int i = 0; i < 48; i++)
{
if(sha384[i * 2] >= 0x30 &&
sha384[i * 2] <= 0x39)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x30) * 0x10);
else if(sha384[i * 2] >= 0x41 &&
sha384[i * 2] <= 0x46)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x37) * 0x10);
else if(sha384[i * 2] >= 0x61 &&
sha384[i * 2] <= 0x66)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x57) * 0x10);
if(sha384[(i * 2) + 1] >= 0x30 &&
sha384[(i * 2) + 1] <= 0x39)
sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x30);
else if(sha384[(i * 2) + 1] >= 0x41 &&
sha384[(i * 2) + 1] <= 0x46)
sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x37);
else if(sha384[(i * 2) + 1] >= 0x61 &&
sha384[(i * 2) + 1] <= 0x66)
sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x57);
}
string datHash32 = Base32.ToBase32String(sha384Bytes);
string datFilesPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "datfiles");
string compressedDatPath = Path.Combine(datFilesPath, datHash32 + ".lz");
if(File.Exists(compressedDatPath))
File.Delete(compressedDatPath);
Dispatcher.UIThread.Post(_view.Close);
});
_view = view;
_romSetId = romSetId;
}
[NotNull]
public string Title => Localization.RemoveDatTitle;
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
internal void OnOpened() => Task.Run(() =>
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
Dispatcher.UIThread.Post(() => StatusMessage = Localization.RetrievingRomSetFromDatabase);
RomSet romSet = ctx.RomSets.Find(_romSetId);
if(romSet == null) return;
Dispatcher.UIThread.Post(() => StatusMessage = Localization.RemovingRomSetFromDatabase);
ctx.RomSets.Remove(romSet);
Dispatcher.UIThread.Post(() => StatusMessage = Localization.SavingChangesToDatabase);
ctx.SaveChanges();
Dispatcher.UIThread.Post(() => StatusMessage = Localization.RemovingDatFileFromRepo);
var sha384Bytes = new byte[48];
string sha384 = romSet.Sha384;
for(var i = 0; i < 48; i++)
{
if(sha384[i * 2] >= 0x30 && sha384[i * 2] <= 0x39)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x30) * 0x10);
else if(sha384[i * 2] >= 0x41 && sha384[i * 2] <= 0x46)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x37) * 0x10);
else if(sha384[i * 2] >= 0x61 && sha384[i * 2] <= 0x66)
sha384Bytes[i] = (byte)((sha384[i * 2] - 0x57) * 0x10);
if(sha384[i * 2 + 1] >= 0x30 && sha384[i * 2 + 1] <= 0x39)
sha384Bytes[i] += (byte)(sha384[i * 2 + 1] - 0x30);
else if(sha384[i * 2 + 1] >= 0x41 && sha384[i * 2 + 1] <= 0x46)
sha384Bytes[i] += (byte)(sha384[i * 2 + 1] - 0x37);
else if(sha384[i * 2 + 1] >= 0x61 && sha384[i * 2 + 1] <= 0x66)
sha384Bytes[i] += (byte)(sha384[i * 2 + 1] - 0x57);
}
string datHash32 = Base32.ToBase32String(sha384Bytes);
string datFilesPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "datfiles");
string compressedDatPath = Path.Combine(datFilesPath, datHash32 + ".lz");
if(File.Exists(compressedDatPath)) File.Delete(compressedDatPath);
Dispatcher.UIThread.Post(_view.Close);
});
}

View File

@@ -41,248 +41,219 @@ using RomRepoMgr.Resources;
using RomRepoMgr.Views;
using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class SettingsViewModel : ViewModelBase
{
public sealed class SettingsViewModel : ViewModelBase
readonly SettingsDialog _view;
bool _databaseChanged;
string _databasePath;
bool _repositoryChanged;
string _repositoryPath;
bool _temporaryChanged;
string _temporaryPath;
bool _unArChanged;
string _unArPath;
string _unArVersion;
public SettingsViewModel(SettingsDialog view)
{
readonly SettingsDialog _view;
bool _databaseChanged;
string _databasePath;
bool _repositoryChanged;
string _repositoryPath;
bool _temporaryChanged;
string _temporaryPath;
bool _unArChanged;
string _unArPath;
string _unArVersion;
_view = view;
_databaseChanged = false;
_repositoryChanged = false;
_temporaryChanged = false;
_unArChanged = false;
public SettingsViewModel(SettingsDialog view)
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
UnArCommand = ReactiveCommand.Create(ExecuteUnArCommand);
TemporaryCommand = ReactiveCommand.Create(ExecuteTemporaryCommand);
RepositoryCommand = ReactiveCommand.Create(ExecuteRepositoryCommand);
DatabaseCommand = ReactiveCommand.Create(ExecuteDatabaseCommand);
SaveCommand = ReactiveCommand.Create(ExecuteSaveCommand);
DatabasePath = Settings.Settings.Current.DatabasePath;
RepositoryPath = Settings.Settings.Current.RepositoryPath;
TemporaryPath = Settings.Settings.Current.TemporaryFolder;
UnArPath = Settings.Settings.Current.UnArchiverPath;
if(!string.IsNullOrWhiteSpace(UnArPath)) CheckUnAr();
}
public string ChooseLabel => Localization.ChooseLabel;
public string Title => Localization.SettingsTitle;
public string CloseLabel => Localization.CloseLabel;
public string DatabaseLabel => Localization.DatabaseFileLabel;
public string RepositoryLabel => Localization.RepositoryFolderLabel;
public string TemporaryLabel => Localization.TemporaryFolderLabel;
public string UnArPathLabel => Localization.UnArPathLabel;
public ReactiveCommand<Unit, Unit> UnArCommand { get; }
public ReactiveCommand<Unit, Unit> TemporaryCommand { get; }
public ReactiveCommand<Unit, Unit> RepositoryCommand { get; }
public ReactiveCommand<Unit, Unit> DatabaseCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public string DatabasePath
{
get => _databasePath;
set
{
_view = view;
_databaseChanged = false;
_repositoryChanged = false;
_temporaryChanged = false;
_unArChanged = false;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
UnArCommand = ReactiveCommand.Create(ExecuteUnArCommand);
TemporaryCommand = ReactiveCommand.Create(ExecuteTemporaryCommand);
RepositoryCommand = ReactiveCommand.Create(ExecuteRepositoryCommand);
DatabaseCommand = ReactiveCommand.Create(ExecuteDatabaseCommand);
SaveCommand = ReactiveCommand.Create(ExecuteSaveCommand);
DatabasePath = Settings.Settings.Current.DatabasePath;
RepositoryPath = Settings.Settings.Current.RepositoryPath;
TemporaryPath = Settings.Settings.Current.TemporaryFolder;
UnArPath = Settings.Settings.Current.UnArchiverPath;
if(!string.IsNullOrWhiteSpace(UnArPath))
CheckUnAr();
this.RaiseAndSetIfChanged(ref _databasePath, value);
_databaseChanged = true;
}
}
public string ChooseLabel => Localization.ChooseLabel;
public string Title => Localization.SettingsTitle;
public string CloseLabel => Localization.CloseLabel;
public string DatabaseLabel => Localization.DatabaseFileLabel;
public string RepositoryLabel => Localization.RepositoryFolderLabel;
public string TemporaryLabel => Localization.TemporaryFolderLabel;
public string UnArPathLabel => Localization.UnArPathLabel;
public ReactiveCommand<Unit, Unit> UnArCommand { get; }
public ReactiveCommand<Unit, Unit> TemporaryCommand { get; }
public ReactiveCommand<Unit, Unit> RepositoryCommand { get; }
public ReactiveCommand<Unit, Unit> DatabaseCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public string DatabasePath
public string RepositoryPath
{
get => _repositoryPath;
set
{
get => _databasePath;
set
this.RaiseAndSetIfChanged(ref _repositoryPath, value);
// TODO: Refresh repository existing files
_repositoryChanged = true;
}
}
public string TemporaryPath
{
get => _temporaryPath;
set
{
this.RaiseAndSetIfChanged(ref _temporaryPath, value);
_temporaryChanged = true;
}
}
public string UnArPath
{
get => _unArPath;
set => this.RaiseAndSetIfChanged(ref _unArPath, value);
}
public string UnArVersion
{
get => _unArVersion;
set => this.RaiseAndSetIfChanged(ref _unArVersion, value);
}
public string SaveLabel => Localization.SaveLabel;
void CheckUnAr()
{
var worker = new Compression();
worker.FinishedWithText += CheckUnArFinished;
worker.FailedWithText += CheckUnArFailed;
Task.Run(() => worker.CheckUnAr(UnArPath));
}
async void CheckUnArFailed(object sender, [NotNull] ErrorEventArgs args)
{
UnArVersion = "";
UnArPath = "";
await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.Error, $"{args.Message}", ButtonEnum.Ok, Icon.Error)
.ShowDialog(_view);
}
void CheckUnArFinished(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
UnArVersion = string.Format(Localization.TheUnarchiverVersionLabel, args.Message);
_unArChanged = true;
});
void ExecuteCloseCommand() => _view.Close();
async void ExecuteUnArCommand()
{
var dlgFile = new OpenFileDialog
{
Title = Localization.ChooseUnArExecutable,
AllowMultiple = false
};
if(!string.IsNullOrWhiteSpace(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)))
dlgFile.Directory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
string[] result = await dlgFile.ShowAsync(_view);
if(result?.Length != 1) return;
UnArPath = result[0];
CheckUnAr();
}
async void ExecuteTemporaryCommand()
{
var dlgFolder = new OpenFolderDialog
{
Title = Localization.ChooseTemporaryFolder
};
string result = await dlgFolder.ShowAsync(_view);
if(result == null) return;
TemporaryPath = result;
}
async void ExecuteRepositoryCommand()
{
var dlgFolder = new OpenFolderDialog
{
Title = Localization.ChooseRepositoryFolder
};
string result = await dlgFolder.ShowAsync(_view);
if(result == null) return;
RepositoryPath = result;
}
async void ExecuteDatabaseCommand()
{
var dlgFile = new SaveFileDialog
{
InitialFileName = "romrepo.db",
Directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
Title = Localization.ChooseDatabaseFile
};
string result = await dlgFile.ShowAsync(_view);
if(result == null) return;
if(File.Exists(result))
{
ButtonResult btnResult = await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DatabaseFileExistsMsgBoxTitle,
Localization.DatabaseFileTryOpenCaption,
ButtonEnum.YesNo,
Icon.Database)
.ShowDialog(_view);
if(btnResult == ButtonResult.Yes)
{
this.RaiseAndSetIfChanged(ref _databasePath, value);
_databaseChanged = true;
}
}
public string RepositoryPath
{
get => _repositoryPath;
set
{
this.RaiseAndSetIfChanged(ref _repositoryPath, value);
// TODO: Refresh repository existing files
_repositoryChanged = true;
}
}
public string TemporaryPath
{
get => _temporaryPath;
set
{
this.RaiseAndSetIfChanged(ref _temporaryPath, value);
_temporaryChanged = true;
}
}
public string UnArPath
{
get => _unArPath;
set => this.RaiseAndSetIfChanged(ref _unArPath, value);
}
public string UnArVersion
{
get => _unArVersion;
set => this.RaiseAndSetIfChanged(ref _unArVersion, value);
}
public string SaveLabel => Localization.SaveLabel;
void CheckUnAr()
{
var worker = new Compression();
worker.FinishedWithText += CheckUnArFinished;
worker.FailedWithText += CheckUnArFailed;
Task.Run(() => worker.CheckUnAr(UnArPath));
}
async void CheckUnArFailed(object sender, [NotNull] ErrorEventArgs args)
{
UnArVersion = "";
UnArPath = "";
await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.Error, $"{args.Message}", ButtonEnum.Ok, Icon.Error).
ShowDialog(_view);
}
void CheckUnArFinished(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() =>
{
UnArVersion = string.Format(Localization.TheUnarchiverVersionLabel, args.Message);
_unArChanged = true;
});
void ExecuteCloseCommand() => _view.Close();
async void ExecuteUnArCommand()
{
var dlgFile = new OpenFileDialog
{
Title = Localization.ChooseUnArExecutable,
AllowMultiple = false
};
if(!string.IsNullOrWhiteSpace(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)))
dlgFile.Directory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
string[] result = await dlgFile.ShowAsync(_view);
if(result?.Length != 1)
return;
UnArPath = result[0];
CheckUnAr();
}
async void ExecuteTemporaryCommand()
{
var dlgFolder = new OpenFolderDialog
{
Title = Localization.ChooseTemporaryFolder
};
string result = await dlgFolder.ShowAsync(_view);
if(result == null)
return;
TemporaryPath = result;
}
async void ExecuteRepositoryCommand()
{
var dlgFolder = new OpenFolderDialog
{
Title = Localization.ChooseRepositoryFolder
};
string result = await dlgFolder.ShowAsync(_view);
if(result == null)
return;
RepositoryPath = result;
}
async void ExecuteDatabaseCommand()
{
var dlgFile = new SaveFileDialog
{
InitialFileName = "romrepo.db",
Directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
Title = Localization.ChooseDatabaseFile
};
string result = await dlgFile.ShowAsync(_view);
if(result == null)
return;
if(File.Exists(result))
{
ButtonResult btnResult = await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseFileExistsMsgBoxTitle,
Localization.DatabaseFileTryOpenCaption,
ButtonEnum.YesNo, Icon.Database).
ShowDialog(_view);
if(btnResult == ButtonResult.Yes)
try
{
try
{
var ctx = Context.Create(result);
await ctx.Database.MigrateAsync();
}
catch(Exception)
{
btnResult = await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseFileUnusableMsgBoxTitle,
Localization.
DatabaseFileUnusableDeleteMsgBoxCaption,
ButtonEnum.YesNo, Icon.Error).ShowDialog(_view);
if(btnResult == ButtonResult.No)
return;
try
{
File.Delete(result);
}
catch(Exception)
{
await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseFileCannotDeleteTitle,
Localization.DatabaseFileCannotDeleteCaption,
ButtonEnum.Ok, Icon.Error).ShowDialog(_view);
return;
}
}
var ctx = Context.Create(result);
await ctx.Database.MigrateAsync();
}
else
catch(Exception)
{
btnResult = await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseFileExistsMsgBoxTitle,
Localization.DatabaseFileDeleteCaption,
ButtonEnum.YesNo, Icon.Error).ShowDialog(_view);
btnResult = await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DatabaseFileUnusableMsgBoxTitle,
Localization.DatabaseFileUnusableDeleteMsgBoxCaption,
ButtonEnum.YesNo,
Icon.Error)
.ShowDialog(_view);
if(btnResult == ButtonResult.No)
return;
if(btnResult == ButtonResult.No) return;
try
{
@@ -290,58 +261,83 @@ namespace RomRepoMgr.ViewModels
}
catch(Exception)
{
await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseFileCannotDeleteTitle,
Localization.DatabaseFileCannotDeleteCaption, ButtonEnum.Ok,
Icon.Error).ShowDialog(_view);
await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DatabaseFileCannotDeleteTitle,
Localization.DatabaseFileCannotDeleteCaption,
ButtonEnum.Ok,
Icon.Error)
.ShowDialog(_view);
return;
}
}
}
try
else
{
var ctx = Context.Create(result);
await ctx.Database.MigrateAsync();
}
catch(Exception)
{
await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseFileUnusableMsgBoxTitle,
Localization.DatabaseFileUnusableMsgBoxCaption, ButtonEnum.Ok,
Icon.Error).ShowDialog(_view);
btnResult = await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DatabaseFileExistsMsgBoxTitle,
Localization.DatabaseFileDeleteCaption,
ButtonEnum.YesNo,
Icon.Error)
.ShowDialog(_view);
return;
}
if(btnResult == ButtonResult.No) return;
DatabasePath = result;
try
{
File.Delete(result);
}
catch(Exception)
{
await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DatabaseFileCannotDeleteTitle,
Localization.DatabaseFileCannotDeleteCaption,
ButtonEnum.Ok,
Icon.Error)
.ShowDialog(_view);
return;
}
}
}
void ExecuteSaveCommand()
try
{
if(_databaseChanged)
Settings.Settings.Current.DatabasePath = DatabasePath;
if(_repositoryChanged)
Settings.Settings.Current.RepositoryPath = RepositoryPath;
if(_temporaryChanged)
Settings.Settings.Current.TemporaryFolder = TemporaryPath;
if(_unArChanged)
{
Settings.Settings.Current.UnArchiverPath = UnArPath;
Settings.Settings.UnArUsable = true;
}
if(_databaseChanged ||
_repositoryChanged ||
_temporaryChanged ||
_unArChanged)
Settings.Settings.SaveSettings();
_view.Close();
var ctx = Context.Create(result);
await ctx.Database.MigrateAsync();
}
catch(Exception)
{
await MessageBoxManager
.GetMessageBoxStandardWindow(Localization.DatabaseFileUnusableMsgBoxTitle,
Localization.DatabaseFileUnusableMsgBoxCaption,
ButtonEnum.Ok,
Icon.Error)
.ShowDialog(_view);
return;
}
DatabasePath = result;
}
void ExecuteSaveCommand()
{
if(_databaseChanged) Settings.Settings.Current.DatabasePath = DatabasePath;
if(_repositoryChanged) Settings.Settings.Current.RepositoryPath = RepositoryPath;
if(_temporaryChanged) Settings.Settings.Current.TemporaryFolder = TemporaryPath;
if(_unArChanged)
{
Settings.Settings.Current.UnArchiverPath = UnArPath;
Settings.Settings.UnArUsable = true;
}
if(_databaseChanged || _repositoryChanged || _temporaryChanged || _unArChanged)
Settings.Settings.SaveSettings();
_view.Close();
}
}

View File

@@ -39,335 +39,339 @@ using RomRepoMgr.Core.Workers;
using RomRepoMgr.Database;
using RomRepoMgr.Resources;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class SplashWindowViewModel : ViewModelBase
{
public sealed class SplashWindowViewModel : ViewModelBase
bool _checkingUnArError;
bool _checkingUnArOk;
bool _checkingUnArUnknown;
bool _exitVisible;
bool _loadingDatabaseError;
bool _loadingDatabaseOk;
bool _loadingDatabaseUnknown;
bool _loadingRomSetsError;
bool _loadingRomSetsOk;
bool _loadingRomSetsUnknown;
bool _loadingSettingsError;
bool _loadingSettingsOk;
bool _loadingSettingsUnknown;
bool _migratingDatabaseError;
bool _migratingDatabaseOk;
bool _migratingDatabaseUnknown;
public SplashWindowViewModel()
{
bool _checkingUnArError;
bool _checkingUnArOk;
bool _checkingUnArUnknown;
bool _exitVisible;
bool _loadingDatabaseError;
bool _loadingDatabaseOk;
bool _loadingDatabaseUnknown;
bool _loadingRomSetsError;
bool _loadingRomSetsOk;
bool _loadingRomSetsUnknown;
bool _loadingSettingsError;
bool _loadingSettingsOk;
bool _loadingSettingsUnknown;
bool _migratingDatabaseError;
bool _migratingDatabaseOk;
bool _migratingDatabaseUnknown;
ExitCommand = ReactiveCommand.Create(ExecuteExitCommand);
public SplashWindowViewModel()
{
ExitCommand = ReactiveCommand.Create(ExecuteExitCommand);
LoadingSettingsOk = false;
LoadingSettingsError = false;
LoadingSettingsUnknown = true;
CheckingUnArOk = false;
CheckingUnArError = false;
CheckingUnArUnknown = true;
LoadingDatabaseOk = false;
LoadingDatabaseError = false;
LoadingDatabaseUnknown = true;
MigratingDatabaseOk = false;
MigratingDatabaseError = false;
MigratingDatabaseUnknown = true;
LoadingRomSetsOk = false;
LoadingRomSetsError = false;
LoadingRomSetsUnknown = true;
ExitVisible = false;
}
public ReactiveCommand<Unit, Unit> ExitCommand { get; }
public bool LoadingSettingsOk
{
get => _loadingSettingsOk;
set => this.RaiseAndSetIfChanged(ref _loadingSettingsOk, value);
}
public bool LoadingSettingsError
{
get => _loadingSettingsError;
set => this.RaiseAndSetIfChanged(ref _loadingSettingsError, value);
}
public bool LoadingSettingsUnknown
{
get => _loadingSettingsUnknown;
set => this.RaiseAndSetIfChanged(ref _loadingSettingsUnknown, value);
}
public bool CheckingUnArOk
{
get => _checkingUnArOk;
set => this.RaiseAndSetIfChanged(ref _checkingUnArOk, value);
}
public bool CheckingUnArError
{
get => _checkingUnArError;
set => this.RaiseAndSetIfChanged(ref _checkingUnArError, value);
}
public bool CheckingUnArUnknown
{
get => _checkingUnArUnknown;
set => this.RaiseAndSetIfChanged(ref _checkingUnArUnknown, value);
}
public bool LoadingDatabaseOk
{
get => _loadingDatabaseOk;
set => this.RaiseAndSetIfChanged(ref _loadingDatabaseOk, value);
}
public bool LoadingDatabaseError
{
get => _loadingDatabaseError;
set => this.RaiseAndSetIfChanged(ref _loadingDatabaseError, value);
}
public bool LoadingDatabaseUnknown
{
get => _loadingDatabaseUnknown;
set => this.RaiseAndSetIfChanged(ref _loadingDatabaseUnknown, value);
}
public bool MigratingDatabaseOk
{
get => _migratingDatabaseOk;
set => this.RaiseAndSetIfChanged(ref _migratingDatabaseOk, value);
}
public bool MigratingDatabaseError
{
get => _migratingDatabaseError;
set => this.RaiseAndSetIfChanged(ref _migratingDatabaseError, value);
}
public bool MigratingDatabaseUnknown
{
get => _migratingDatabaseUnknown;
set => this.RaiseAndSetIfChanged(ref _migratingDatabaseUnknown, value);
}
public bool ExitVisible
{
get => _exitVisible;
set => this.RaiseAndSetIfChanged(ref _exitVisible, value);
}
public bool LoadingRomSetsOk
{
get => _loadingRomSetsOk;
set => this.RaiseAndSetIfChanged(ref _loadingRomSetsOk, value);
}
public bool LoadingRomSetsError
{
get => _loadingRomSetsError;
set => this.RaiseAndSetIfChanged(ref _loadingRomSetsError, value);
}
public bool LoadingRomSetsUnknown
{
get => _loadingRomSetsUnknown;
set => this.RaiseAndSetIfChanged(ref _loadingRomSetsUnknown, value);
}
public string LoadingText => "ROM Repository Manager";
public string LoadingSettingsText => Localization.LoadingSettingsText;
public string CheckingUnArText => Localization.CheckingUnArText;
public string LoadingDatabaseText => Localization.LoadingDatabaseText;
public string MigratingDatabaseText => Localization.MigratingDatabaseText;
public string LoadingRomSetsText => Localization.LoadingRomSetsText;
public string ExitButtonText => Localization.ExitButtonText;
void ExecuteExitCommand() =>
(Application.Current.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown();
internal void OnOpened() => Dispatcher.UIThread.Post(LoadSettings);
void LoadSettings() => Task.Run(() =>
{
try
{
Settings.Settings.LoadSettings();
Dispatcher.UIThread.Post(CheckUnAr);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedLoadingSettings);
}
});
void FailedLoadingSettings()
{
LoadingSettingsUnknown = false;
LoadingSettingsError = true;
ExitVisible = true;
}
void CheckUnAr() => Task.Run(() =>
{
LoadingSettingsUnknown = false;
LoadingSettingsOk = true;
try
{
var worker = new Compression();
Settings.Settings.UnArUsable = worker.CheckUnAr(Settings.Settings.Current.UnArchiverPath);
Dispatcher.UIThread.Post(LoadDatabase);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedCheckUnAr);
}
});
void FailedCheckUnAr()
{
CheckingUnArUnknown = false;
CheckingUnArError = true;
ExitVisible = true;
}
void LoadDatabase()
{
CheckingUnArUnknown = false;
CheckingUnArOk = true;
Task.Run(() =>
{
try
{
string dbPathFolder = Path.GetDirectoryName(Settings.Settings.Current.DatabasePath);
if(!Directory.Exists(dbPathFolder))
Directory.CreateDirectory(dbPathFolder);
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
Dispatcher.UIThread.Post(MigrateDatabase);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedLoadingDatabase);
}
});
}
void FailedLoadingDatabase()
{
LoadingDatabaseUnknown = false;
LoadingDatabaseError = true;
ExitVisible = true;
}
void MigrateDatabase()
{
LoadingDatabaseUnknown = false;
LoadingDatabaseOk = true;
Task.Run(() =>
{
try
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
ctx.Database.Migrate();
Dispatcher.UIThread.Post(LoadRomSets);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedMigratingDatabase);
}
});
}
void FailedMigratingDatabase()
{
MigratingDatabaseUnknown = false;
MigratingDatabaseError = true;
ExitVisible = true;
}
void LoadRomSets()
{
MigratingDatabaseUnknown = false;
MigratingDatabaseOk = true;
Task.Run(() =>
{
try
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
GotRomSets?.Invoke(this, new RomSetsEventArgs
{
RomSets = ctx.RomSets.OrderBy(r => r.Name).ThenBy(r => r.Version).ThenBy(r => r.Date).
ThenBy(r => r.Description).ThenBy(r => r.Comment).ThenBy(r => r.Filename).
Select(r => new RomSetModel
{
Id = r.Id,
Author = r.Author,
Comment = r.Comment,
Date = r.Date,
Description = r.Description,
Filename = r.Filename,
Homepage = r.Homepage,
Name = r.Name,
Sha384 = r.Sha384,
Version = r.Version,
TotalMachines = r.Statistics.TotalMachines,
CompleteMachines = r.Statistics.CompleteMachines,
IncompleteMachines = r.Statistics.IncompleteMachines,
TotalRoms = r.Statistics.TotalRoms,
HaveRoms = r.Statistics.HaveRoms,
MissRoms = r.Statistics.MissRoms,
Category = r.Category
}).ToList()
});
Dispatcher.UIThread.Post(LoadMainWindow);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedLoadingRomSets);
}
});
}
void FailedLoadingRomSets()
{
LoadingRomSetsUnknown = false;
LoadingRomSetsError = true;
ExitVisible = true;
}
void LoadMainWindow()
{
LoadingRomSetsUnknown = false;
LoadingRomSetsOk = true;
WorkFinished?.Invoke(this, EventArgs.Empty);
}
internal event EventHandler WorkFinished;
internal event EventHandler<RomSetsEventArgs> GotRomSets;
LoadingSettingsOk = false;
LoadingSettingsError = false;
LoadingSettingsUnknown = true;
CheckingUnArOk = false;
CheckingUnArError = false;
CheckingUnArUnknown = true;
LoadingDatabaseOk = false;
LoadingDatabaseError = false;
LoadingDatabaseUnknown = true;
MigratingDatabaseOk = false;
MigratingDatabaseError = false;
MigratingDatabaseUnknown = true;
LoadingRomSetsOk = false;
LoadingRomSetsError = false;
LoadingRomSetsUnknown = true;
ExitVisible = false;
}
public ReactiveCommand<Unit, Unit> ExitCommand { get; }
public bool LoadingSettingsOk
{
get => _loadingSettingsOk;
set => this.RaiseAndSetIfChanged(ref _loadingSettingsOk, value);
}
public bool LoadingSettingsError
{
get => _loadingSettingsError;
set => this.RaiseAndSetIfChanged(ref _loadingSettingsError, value);
}
public bool LoadingSettingsUnknown
{
get => _loadingSettingsUnknown;
set => this.RaiseAndSetIfChanged(ref _loadingSettingsUnknown, value);
}
public bool CheckingUnArOk
{
get => _checkingUnArOk;
set => this.RaiseAndSetIfChanged(ref _checkingUnArOk, value);
}
public bool CheckingUnArError
{
get => _checkingUnArError;
set => this.RaiseAndSetIfChanged(ref _checkingUnArError, value);
}
public bool CheckingUnArUnknown
{
get => _checkingUnArUnknown;
set => this.RaiseAndSetIfChanged(ref _checkingUnArUnknown, value);
}
public bool LoadingDatabaseOk
{
get => _loadingDatabaseOk;
set => this.RaiseAndSetIfChanged(ref _loadingDatabaseOk, value);
}
public bool LoadingDatabaseError
{
get => _loadingDatabaseError;
set => this.RaiseAndSetIfChanged(ref _loadingDatabaseError, value);
}
public bool LoadingDatabaseUnknown
{
get => _loadingDatabaseUnknown;
set => this.RaiseAndSetIfChanged(ref _loadingDatabaseUnknown, value);
}
public bool MigratingDatabaseOk
{
get => _migratingDatabaseOk;
set => this.RaiseAndSetIfChanged(ref _migratingDatabaseOk, value);
}
public bool MigratingDatabaseError
{
get => _migratingDatabaseError;
set => this.RaiseAndSetIfChanged(ref _migratingDatabaseError, value);
}
public bool MigratingDatabaseUnknown
{
get => _migratingDatabaseUnknown;
set => this.RaiseAndSetIfChanged(ref _migratingDatabaseUnknown, value);
}
public bool ExitVisible
{
get => _exitVisible;
set => this.RaiseAndSetIfChanged(ref _exitVisible, value);
}
public bool LoadingRomSetsOk
{
get => _loadingRomSetsOk;
set => this.RaiseAndSetIfChanged(ref _loadingRomSetsOk, value);
}
public bool LoadingRomSetsError
{
get => _loadingRomSetsError;
set => this.RaiseAndSetIfChanged(ref _loadingRomSetsError, value);
}
public bool LoadingRomSetsUnknown
{
get => _loadingRomSetsUnknown;
set => this.RaiseAndSetIfChanged(ref _loadingRomSetsUnknown, value);
}
public string LoadingText => "ROM Repository Manager";
public string LoadingSettingsText => Localization.LoadingSettingsText;
public string CheckingUnArText => Localization.CheckingUnArText;
public string LoadingDatabaseText => Localization.LoadingDatabaseText;
public string MigratingDatabaseText => Localization.MigratingDatabaseText;
public string LoadingRomSetsText => Localization.LoadingRomSetsText;
public string ExitButtonText => Localization.ExitButtonText;
void ExecuteExitCommand() =>
(Application.Current.ApplicationLifetime as ClassicDesktopStyleApplicationLifetime)?.Shutdown();
internal void OnOpened() => Dispatcher.UIThread.Post(LoadSettings);
void LoadSettings() => Task.Run(() =>
{
try
{
Settings.Settings.LoadSettings();
Dispatcher.UIThread.Post(CheckUnAr);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedLoadingSettings);
}
});
void FailedLoadingSettings()
{
LoadingSettingsUnknown = false;
LoadingSettingsError = true;
ExitVisible = true;
}
void CheckUnAr() => Task.Run(() =>
{
LoadingSettingsUnknown = false;
LoadingSettingsOk = true;
try
{
var worker = new Compression();
Settings.Settings.UnArUsable = worker.CheckUnAr(Settings.Settings.Current.UnArchiverPath);
Dispatcher.UIThread.Post(LoadDatabase);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedCheckUnAr);
}
});
void FailedCheckUnAr()
{
CheckingUnArUnknown = false;
CheckingUnArError = true;
ExitVisible = true;
}
void LoadDatabase()
{
CheckingUnArUnknown = false;
CheckingUnArOk = true;
Task.Run(() =>
{
try
{
string dbPathFolder = Path.GetDirectoryName(Settings.Settings.Current.DatabasePath);
if(!Directory.Exists(dbPathFolder)) Directory.CreateDirectory(dbPathFolder);
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
Dispatcher.UIThread.Post(MigrateDatabase);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedLoadingDatabase);
}
});
}
void FailedLoadingDatabase()
{
LoadingDatabaseUnknown = false;
LoadingDatabaseError = true;
ExitVisible = true;
}
void MigrateDatabase()
{
LoadingDatabaseUnknown = false;
LoadingDatabaseOk = true;
Task.Run(() =>
{
try
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
ctx.Database.Migrate();
Dispatcher.UIThread.Post(LoadRomSets);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedMigratingDatabase);
}
});
}
void FailedMigratingDatabase()
{
MigratingDatabaseUnknown = false;
MigratingDatabaseError = true;
ExitVisible = true;
}
void LoadRomSets()
{
MigratingDatabaseUnknown = false;
MigratingDatabaseOk = true;
Task.Run(() =>
{
try
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
GotRomSets?.Invoke(this,
new RomSetsEventArgs
{
RomSets = ctx.RomSets.OrderBy(r => r.Name)
.ThenBy(r => r.Version)
.ThenBy(r => r.Date)
.ThenBy(r => r.Description)
.ThenBy(r => r.Comment)
.ThenBy(r => r.Filename)
.Select(r => new RomSetModel
{
Id = r.Id,
Author = r.Author,
Comment = r.Comment,
Date = r.Date,
Description = r.Description,
Filename = r.Filename,
Homepage = r.Homepage,
Name = r.Name,
Sha384 = r.Sha384,
Version = r.Version,
TotalMachines = r.Statistics.TotalMachines,
CompleteMachines = r.Statistics.CompleteMachines,
IncompleteMachines = r.Statistics.IncompleteMachines,
TotalRoms = r.Statistics.TotalRoms,
HaveRoms = r.Statistics.HaveRoms,
MissRoms = r.Statistics.MissRoms,
Category = r.Category
})
.ToList()
});
Dispatcher.UIThread.Post(LoadMainWindow);
}
catch(Exception e)
{
// TODO: Log error
Dispatcher.UIThread.Post(FailedLoadingRomSets);
}
});
}
void FailedLoadingRomSets()
{
LoadingRomSetsUnknown = false;
LoadingRomSetsError = true;
ExitVisible = true;
}
void LoadMainWindow()
{
LoadingRomSetsUnknown = false;
LoadingRomSetsOk = true;
WorkFinished?.Invoke(this, EventArgs.Empty);
}
internal event EventHandler WorkFinished;
internal event EventHandler<RomSetsEventArgs> GotRomSets;
}

View File

@@ -38,223 +38,231 @@ using RomRepoMgr.Database.Models;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
namespace RomRepoMgr.ViewModels;
public sealed class UpdateStatsViewModel : ViewModelBase
{
public sealed class UpdateStatsViewModel : ViewModelBase
readonly UpdateStats _view;
bool _canClose;
double _currentValue;
bool _indeterminateProgress;
double _maximumValue;
double _minimumValue;
bool _progressVisible;
RomSetModel _selectedRomSet;
string _statusMessage;
public UpdateStatsViewModel(UpdateStats view)
{
readonly UpdateStats _view;
bool _canClose;
double _currentValue;
bool _indeterminateProgress;
double _maximumValue;
double _minimumValue;
bool _progressVisible;
RomSetModel _selectedRomSet;
string _statusMessage;
_view = view;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
IndeterminateProgress = true;
ProgressVisible = false;
RomSets = new ObservableCollection<RomSetModel>();
}
public UpdateStatsViewModel(UpdateStats view)
[NotNull]
public string Title => Localization.UpdateStatsTitle;
public string RomSetNameLabel => Localization.RomSetNameLabel;
public string RomSetVersionLabel => Localization.RomSetVersionLabel;
public string RomSetAuthorLabel => Localization.RomSetAuthorLabel;
public string RomSetCategoryLabel => Localization.RomSetCategoryLabel;
public string RomSetDateLabel => Localization.RomSetDateLabel;
public string RomSetDescriptionLabel => Localization.RomSetDescriptionLabel;
public string RomSetCommentLabel => Localization.RomSetCommentLabel;
public string RomSetTotalMachinesLabel => Localization.RomSetTotalMachinesLabel;
public string RomSetCompleteMachinesLabel => Localization.RomSetCompleteMachinesLabel;
public string RomSetIncompleteMachinesLabel => Localization.RomSetIncompleteMachinesLabel;
public string RomSetTotalRomsLabel => Localization.RomSetTotalRomsLabel;
public string RomSetHaveRomsLabel => Localization.RomSetHaveRomsLabel;
public string RomSetMissRomsLabel => Localization.RomSetMissRomsLabel;
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public bool IndeterminateProgress
{
get => _indeterminateProgress;
set => this.RaiseAndSetIfChanged(ref _indeterminateProgress, value);
}
public double MaximumValue
{
get => _maximumValue;
set => this.RaiseAndSetIfChanged(ref _maximumValue, value);
}
public double MinimumValue
{
get => _minimumValue;
set => this.RaiseAndSetIfChanged(ref _minimumValue, value);
}
public double CurrentValue
{
get => _currentValue;
set => this.RaiseAndSetIfChanged(ref _currentValue, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public RomSetModel SelectedRomSet
{
get => _selectedRomSet;
set => this.RaiseAndSetIfChanged(ref _selectedRomSet, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public ObservableCollection<RomSetModel> RomSets { get; }
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
internal void OnOpened() => Task.Run(() =>
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
Dispatcher.UIThread.Post(() =>
{
_view = view;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
StatusMessage = Localization.RetrievingRomSetsFromDatabase;
ProgressVisible = true;
IndeterminateProgress = true;
ProgressVisible = false;
RomSets = new ObservableCollection<RomSetModel>();
}
});
[NotNull]
public string Title => Localization.UpdateStatsTitle;
public string RomSetNameLabel => Localization.RomSetNameLabel;
public string RomSetVersionLabel => Localization.RomSetVersionLabel;
public string RomSetAuthorLabel => Localization.RomSetAuthorLabel;
public string RomSetCategoryLabel => Localization.RomSetCategoryLabel;
public string RomSetDateLabel => Localization.RomSetDateLabel;
public string RomSetDescriptionLabel => Localization.RomSetDescriptionLabel;
public string RomSetCommentLabel => Localization.RomSetCommentLabel;
public string RomSetTotalMachinesLabel => Localization.RomSetTotalMachinesLabel;
public string RomSetCompleteMachinesLabel => Localization.RomSetCompleteMachinesLabel;
public string RomSetIncompleteMachinesLabel => Localization.RomSetIncompleteMachinesLabel;
public string RomSetTotalRomsLabel => Localization.RomSetTotalRomsLabel;
public string RomSetHaveRomsLabel => Localization.RomSetHaveRomsLabel;
public string RomSetMissRomsLabel => Localization.RomSetMissRomsLabel;
long romSetCount = ctx.RomSets.LongCount();
public string StatusMessage
Dispatcher.UIThread.Post(() => { StatusMessage = Localization.RemovingOldStatistics; });
ctx.Database.ExecuteSqlRaw("DELETE FROM \"RomSetStats\"");
Dispatcher.UIThread.Post(() =>
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
IndeterminateProgress = false;
MinimumValue = 0;
MaximumValue = romSetCount;
CurrentValue = 0;
});
public bool IndeterminateProgress
long pos = 0;
foreach(RomSet romSet in ctx.RomSets)
{
get => _indeterminateProgress;
set => this.RaiseAndSetIfChanged(ref _indeterminateProgress, value);
}
public double MaximumValue
{
get => _maximumValue;
set => this.RaiseAndSetIfChanged(ref _maximumValue, value);
}
public double MinimumValue
{
get => _minimumValue;
set => this.RaiseAndSetIfChanged(ref _minimumValue, value);
}
public double CurrentValue
{
get => _currentValue;
set => this.RaiseAndSetIfChanged(ref _currentValue, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public RomSetModel SelectedRomSet
{
get => _selectedRomSet;
set => this.RaiseAndSetIfChanged(ref _selectedRomSet, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public ObservableCollection<RomSetModel> RomSets { get; }
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
internal void OnOpened() => Task.Run(() =>
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
long currentPos = pos;
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.RetrievingRomSetsFromDatabase;
ProgressVisible = true;
IndeterminateProgress = true;
StatusMessage = string.Format(Localization.CalculatingStatisticsForRomSet,
romSet.Name,
romSet.Version,
romSet.Description);
CurrentValue = currentPos;
});
long romSetCount = ctx.RomSets.LongCount();
Dispatcher.UIThread.Post(() =>
try
{
StatusMessage = Localization.RemovingOldStatistics;
});
RomSetStat stats = ctx.RomSets.Where(r => r.Id == romSet.Id)
.Select(r => new RomSetStat
{
RomSetId = r.Id,
TotalMachines = r.Machines.Count,
CompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 &&
m.Disks.Count == 0 &&
m.Files.All(f => f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 &&
m.Files.Count == 0 &&
m.Disks.All(f => f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 &&
m.Disks.Count > 0 &&
m.Files.All(f => f.File.IsInRepo) &&
m.Disks.All(f => f.Disk.IsInRepo)),
IncompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 &&
m.Disks.Count == 0 &&
m.Files.Any(f => !f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 &&
m.Files.Count == 0 &&
m.Disks.Any(f => !f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 &&
m.Disks.Count > 0 &&
(m.Files.Any(f => !f.File.IsInRepo) ||
m.Disks.Any(f => !f.Disk.IsInRepo))),
TotalRoms =
r.Machines.Sum(m => m.Files.Count) +
r.Machines.Sum(m => m.Disks.Count) +
r.Machines.Sum(m => m.Medias.Count),
HaveRoms = r.Machines.Sum(m => m.Files.Count(f => f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => f.Media.IsInRepo)),
MissRoms = r.Machines.Sum(m => m.Files.Count(f => !f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => !f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => !f.Media.IsInRepo))
})
.FirstOrDefault();
ctx.Database.ExecuteSqlRaw("DELETE FROM \"RomSetStats\"");
Dispatcher.UIThread.Post(() =>
{
IndeterminateProgress = false;
MinimumValue = 0;
MaximumValue = romSetCount;
CurrentValue = 0;
});
long pos = 0;
foreach(RomSet romSet in ctx.RomSets)
{
long currentPos = pos;
ctx.RomSetStats.Add(stats);
Dispatcher.UIThread.Post(() =>
{
StatusMessage = string.Format(Localization.CalculatingStatisticsForRomSet, romSet.Name,
romSet.Version, romSet.Description);
CurrentValue = currentPos;
});
try
{
RomSetStat stats = ctx.RomSets.Where(r => r.Id == romSet.Id).Select(r => new RomSetStat
RomSets.Add(new RomSetModel
{
RomSetId = r.Id,
TotalMachines = r.Machines.Count,
CompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.All(f => f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.All(f => f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
m.Files.All(f => f.File.IsInRepo) &&
m.Disks.All(f => f.Disk.IsInRepo)),
IncompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.Any(f => !f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.Any(f => !f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
(m.Files.Any(f => !f.File.IsInRepo) ||
m.Disks.Any(f => !f.Disk.IsInRepo))),
TotalRoms = r.Machines.Sum(m => m.Files.Count) + r.Machines.Sum(m => m.Disks.Count) +
r.Machines.Sum(m => m.Medias.Count),
HaveRoms = r.Machines.Sum(m => m.Files.Count(f => f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => f.Media.IsInRepo)),
MissRoms = r.Machines.Sum(m => m.Files.Count(f => !f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => !f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => !f.Media.IsInRepo))
}).FirstOrDefault();
ctx.RomSetStats.Add(stats);
Dispatcher.UIThread.Post(() =>
{
RomSets.Add(new RomSetModel
{
Id = romSet.Id,
Author = romSet.Author,
Comment = romSet.Comment,
Date = romSet.Date,
Description = romSet.Description,
Filename = romSet.Filename,
Homepage = romSet.Homepage,
Name = romSet.Name,
Sha384 = romSet.Sha384,
Version = romSet.Version,
TotalMachines = stats.TotalMachines,
CompleteMachines = stats.CompleteMachines,
IncompleteMachines = stats.IncompleteMachines,
TotalRoms = stats.TotalRoms,
HaveRoms = stats.HaveRoms,
MissRoms = stats.MissRoms,
Category = romSet.Category
});
Id = romSet.Id,
Author = romSet.Author,
Comment = romSet.Comment,
Date = romSet.Date,
Description = romSet.Description,
Filename = romSet.Filename,
Homepage = romSet.Homepage,
Name = romSet.Name,
Sha384 = romSet.Sha384,
Version = romSet.Version,
TotalMachines = stats.TotalMachines,
CompleteMachines = stats.CompleteMachines,
IncompleteMachines = stats.IncompleteMachines,
TotalRoms = stats.TotalRoms,
HaveRoms = stats.HaveRoms,
MissRoms = stats.MissRoms,
Category = romSet.Category
});
}
catch(Exception)
{
// Ignored
}
pos++;
});
}
catch(Exception)
{
// Ignored
}
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.SavingChangesToDatabase;
ProgressVisible = true;
IndeterminateProgress = true;
});
pos++;
}
ctx.SaveChanges();
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.Finished;
ProgressVisible = false;
CanClose = true;
});
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.SavingChangesToDatabase;
ProgressVisible = true;
IndeterminateProgress = true;
});
void ExecuteCloseCommand() => _view.Close();
}
ctx.SaveChanges();
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.Finished;
ProgressVisible = false;
CanClose = true;
});
});
void ExecuteCloseCommand() => _view.Close();
}

View File

@@ -25,7 +25,6 @@
using ReactiveUI;
namespace RomRepoMgr.ViewModels
{
public class ViewModelBase : ReactiveObject {}
}
namespace RomRepoMgr.ViewModels;
public class ViewModelBase : ReactiveObject {}

View File

@@ -24,12 +24,20 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="480" Height="320" x:Class="RomRepoMgr.Views.About" Icon="/Assets/avalonia-logo.ico"
CanResize="False" Title="{Binding Title}">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="480"
Height="320"
x:Class="RomRepoMgr.Views.About"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}">
<Design.DataContext>
<vm:AboutViewModel />
</Design.DataContext>
@@ -42,20 +50,33 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderThickness="5">
<Image Source="/Assets/avalonia-logo.ico" Width="48" Height="48" />
<Border Grid.Column="0"
BorderThickness="5">
<Image Source="/Assets/avalonia-logo.ico"
Width="48"
Height="48" />
</Border>
<Grid Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center">
<Grid Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding SoftwareName}" HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="16" FontWeight="Bold" />
<TextBlock Grid.Row="1" Text="{Binding VersionText}" HorizontalAlignment="Left"
<TextBlock Grid.Row="0"
Text="{Binding SoftwareName}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold" />
<TextBlock Grid.Row="1"
Text="{Binding VersionText}"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
</Grid>
</Grid>
<TabControl Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TabControl Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TabItem>
<TabItem.Header>
<TextBlock Text="{Binding AboutLabel}" />
@@ -67,17 +88,31 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding SuiteName}" />
<TextBlock Grid.Row="2" Text="{Binding Copyright}" />
<Button Grid.Row="4" BorderThickness="0" Background="Transparent" HorizontalAlignment="Left"
VerticalAlignment="Center" Padding="0" Command="{Binding WebsiteCommand}">
<TextBlock Grid.Row="0"
Text="{Binding SuiteName}" />
<TextBlock Grid.Row="2"
Text="{Binding Copyright}" />
<Button Grid.Row="4"
BorderThickness="0"
Background="Transparent"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Padding="0"
Command="{Binding WebsiteCommand}">
<!-- TODO: TextDecorations="Underline" in next Avalonia UI version -->
<TextBlock Text="{Binding Website}" Foreground="Blue" />
<TextBlock Text="{Binding Website}"
Foreground="Blue" />
</Button>
<Button Grid.Row="5" BorderThickness="0" Background="Transparent" HorizontalAlignment="Left"
VerticalAlignment="Center" Padding="0" Command="{Binding LicenseCommand}">
<Button Grid.Row="5"
BorderThickness="0"
Background="Transparent"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Padding="0"
Command="{Binding LicenseCommand}">
<!-- TODO: TextDecorations="Underline" in next Avalonia UI version -->
<TextBlock Text="{Binding License}" Foreground="Blue" />
<TextBlock Text="{Binding License}"
Foreground="Blue" />
</Button>
</Grid>
</TabItem>
@@ -85,14 +120,19 @@
<TabItem.Header>
<TextBlock Text="{Binding LibrariesLabel}" />
</TabItem.Header>
<DataGrid Items="{Binding Assemblies}" HorizontalScrollBarVisibility="Visible">
<DataGrid Items="{Binding Assemblies}"
HorizontalScrollBarVisibility="Visible">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Name}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding AssembliesLibraryText}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Version}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Version}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding AssembliesVersionText}" />
</DataGridTextColumn.Header>
@@ -104,10 +144,13 @@
<TabItem.Header>
<TextBlock Text="{Binding AuthorsLabel}" />
</TabItem.Header>
<TextBox IsReadOnly="True" Text="{Binding Authors}" />
<TextBox IsReadOnly="True"
Text="{Binding Authors}" />
</TabItem>
</TabControl>
<Button Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Center"
<Button Grid.Row="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding CloseCommand}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>

View File

@@ -26,12 +26,11 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace RomRepoMgr.Views
{
public sealed class About : Window
{
public About() => InitializeComponent();
namespace RomRepoMgr.Views;
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}
public sealed class About : Window
{
public About() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}

View File

@@ -24,12 +24,21 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="720" Height="480" x:Class="RomRepoMgr.Views.EditDat"
Icon="/Assets/avalonia-logo.ico" CanResize="False" Title="{Binding Title}" WindowStartupLocation="CenterScreen">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="720"
Height="480"
x:Class="RomRepoMgr.Views.EditDat"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}"
WindowStartupLocation="CenterScreen">
<Design.DataContext>
<vm:EditDatViewModel />
</Design.DataContext>
@@ -46,138 +55,244 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding NameLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Text="{Binding Name}"
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding NameLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Name}"
Padding="5" />
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding VersionLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"
Text="{Binding Version}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding VersionLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Version}"
Padding="5" />
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding AuthorLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"
Text="{Binding Author}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding AuthorLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Author}"
Padding="5" />
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding CategoryLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"
Text="{Binding Category}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding CategoryLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Category}"
Padding="5" />
</Grid>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding CommentLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"
Text="{Binding Comment}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding CommentLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Comment}"
Padding="5" />
</Grid>
<Grid Grid.Row="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding DateLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Text="{Binding Date}"
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding DateLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Date}"
Padding="5" />
</Grid>
<Grid Grid.Row="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding DescriptionLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"
Text="{Binding Description}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding DescriptionLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Description}"
Padding="5" />
</Grid>
<Grid Grid.Row="7">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding HomepageLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"
Text="{Binding Homepage}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding HomepageLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Homepage}"
Padding="5" />
</Grid>
<Grid Grid.Row="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding TotalMachinesLabel}" FontWeight="Bold" Padding="5" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{Binding TotalMachines}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding TotalMachinesLabel}"
FontWeight="Bold"
Padding="5" />
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding TotalMachines}"
Padding="5" />
</Grid>
<Grid Grid.Row="9">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding CompleteMachinesLabel}" FontWeight="Bold" Padding="5" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{Binding CompleteMachines}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding CompleteMachinesLabel}"
FontWeight="Bold"
Padding="5" />
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding CompleteMachines}"
Padding="5" />
</Grid>
<Grid Grid.Row="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding IncompleteMachinesLabel}" FontWeight="Bold" Padding="5" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{Binding IncompleteMachines}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding IncompleteMachinesLabel}"
FontWeight="Bold"
Padding="5" />
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding IncompleteMachines}"
Padding="5" />
</Grid>
<Grid Grid.Row="11">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding TotalRomsLabel}" FontWeight="Bold" Padding="5" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{Binding TotalRoms}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding TotalRomsLabel}"
FontWeight="Bold"
Padding="5" />
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding TotalRoms}"
Padding="5" />
</Grid>
<Grid Grid.Row="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding HaveRomsLabel}" FontWeight="Bold" Padding="5" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{Binding HaveRoms}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding HaveRomsLabel}"
FontWeight="Bold"
Padding="5" />
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding HaveRoms}"
Padding="5" />
</Grid>
<Grid Grid.Row="13">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding MissRomsLabel}" FontWeight="Bold" Padding="5" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{Binding MissRoms}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding MissRomsLabel}"
FontWeight="Bold"
Padding="5" />
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding MissRoms}"
Padding="5" />
</Grid>
<StackPanel Grid.Row="14" Orientation="Horizontal" HorizontalAlignment="Right">
<Button HorizontalAlignment="Right" VerticalAlignment="Center" Command="{Binding SaveCommand}"
<StackPanel Grid.Row="14"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding SaveCommand}"
IsVisible="{Binding Modified}">
<TextBlock Text="{Binding SaveLabel}" />
</Button>
<Button HorizontalAlignment="Right" VerticalAlignment="Center" Command="{Binding CancelCommand}"
<Button HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding CancelCommand}"
IsVisible="{Binding Modified}">
<TextBlock Text="{Binding CancelLabel}" />
</Button>
<Button HorizontalAlignment="Right" VerticalAlignment="Center" Command="{Binding CloseCommand}"
<Button HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding CloseCommand}"
IsVisible="{Binding !Modified}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>

View File

@@ -26,12 +26,11 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace RomRepoMgr.Views
{
public sealed class EditDat : Window
{
public EditDat() => InitializeComponent();
namespace RomRepoMgr.Views;
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}
public sealed class EditDat : Window
{
public EditDat() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}

View File

@@ -24,12 +24,21 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="480" Height="90" x:Class="RomRepoMgr.Views.ExportDat"
Icon="/Assets/avalonia-logo.ico" CanResize="False" Title="{Binding Title}" WindowStartupLocation="CenterOwner">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="480"
Height="90"
x:Class="RomRepoMgr.Views.ExportDat"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}"
WindowStartupLocation="CenterOwner">
<Design.DataContext>
<vm:ExportDatViewModel />
</Design.DataContext>
@@ -39,12 +48,22 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding StatusMessage}" HorizontalAlignment="Center" />
<ProgressBar Grid.Row="1" IsIndeterminate="True" HorizontalAlignment="Stretch"
<TextBlock Grid.Row="0"
Text="{Binding StatusMessage}"
HorizontalAlignment="Center" />
<ProgressBar Grid.Row="1"
IsIndeterminate="True"
HorizontalAlignment="Stretch"
IsVisible="{Binding ProgressVisible}" />
<TextBlock Grid.Row="2" Text="{Binding ErrorMessage}" HorizontalAlignment="Center" Foreground="Red"
<TextBlock Grid.Row="2"
Text="{Binding ErrorMessage}"
HorizontalAlignment="Center"
Foreground="Red"
IsVisible="{Binding ErrorVisible}" />
<Button Grid.Row="3" HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanClose}"
<Button Grid.Row="3"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsEnabled="{Binding CanClose}"
Command="{Binding CloseCommand}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>

View File

@@ -28,18 +28,17 @@ using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using RomRepoMgr.ViewModels;
namespace RomRepoMgr.Views
namespace RomRepoMgr.Views;
public sealed class ExportDat : Window
{
public sealed class ExportDat : Window
public ExportDat() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
public ExportDat() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
(DataContext as ExportDatViewModel)?.OnOpened();
}
base.OnOpened(e);
(DataContext as ExportDatViewModel)?.OnOpened();
}
}

View File

@@ -24,12 +24,21 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="480" Height="150" x:Class="RomRepoMgr.Views.ExportRoms"
Icon="/Assets/avalonia-logo.ico" CanResize="False" Title="{Binding Title}" WindowStartupLocation="CenterOwner">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="480"
Height="150"
x:Class="RomRepoMgr.Views.ExportRoms"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}"
WindowStartupLocation="CenterOwner">
<Design.DataContext>
<vm:ExportRomsViewModel />
</Design.DataContext>
@@ -40,24 +49,43 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding PathLabel}" FontWeight="Bold" /> <TextBlock Text="{Binding FolderPath}" />
<StackPanel Grid.Row="0"
Orientation="Horizontal"
HorizontalAlignment="Stretch">
<TextBlock Text="{Binding PathLabel}"
FontWeight="Bold" />
<TextBlock Text="{Binding FolderPath}" />
</StackPanel>
<TextBlock Grid.Row="1" Text="{Binding StatusMessage}" FontWeight="Bold" HorizontalAlignment="Center" />
<ProgressBar Grid.Row="2" Minimum="{Binding ProgressMinimum}" Maximum="{Binding ProgressMaximum}"
Value="{Binding ProgressValue}" IsIndeterminate="{Binding ProgressIsIndeterminate}"
<TextBlock Grid.Row="1"
Text="{Binding StatusMessage}"
FontWeight="Bold"
HorizontalAlignment="Center" />
<ProgressBar Grid.Row="2"
Minimum="{Binding ProgressMinimum}"
Maximum="{Binding ProgressMaximum}"
Value="{Binding ProgressValue}"
IsIndeterminate="{Binding ProgressIsIndeterminate}"
IsVisible="{Binding ProgressVisible}" />
<StackPanel Grid.Row="3" IsVisible="{Binding Progress2Visible}">
<StackPanel Grid.Row="3"
IsVisible="{Binding Progress2Visible}">
<TextBlock Text="{Binding Status2Message}" />
<ProgressBar Minimum="{Binding Progress2Minimum}" Maximum="{Binding Progress2Maximum}"
Value="{Binding Progress2Value}" IsIndeterminate="{Binding Progress2IsIndeterminate}" />
<ProgressBar Minimum="{Binding Progress2Minimum}"
Maximum="{Binding Progress2Maximum}"
Value="{Binding Progress2Value}"
IsIndeterminate="{Binding Progress2IsIndeterminate}" />
</StackPanel>
<StackPanel Grid.Row="4" IsVisible="{Binding Progress3Visible}">
<StackPanel Grid.Row="4"
IsVisible="{Binding Progress3Visible}">
<TextBlock Text="{Binding Status3Message}" />
<ProgressBar Minimum="{Binding Progress3Minimum}" Maximum="{Binding Progress3Maximum}"
Value="{Binding Progress3Value}" IsIndeterminate="{Binding Progress3IsIndeterminate}" />
<ProgressBar Minimum="{Binding Progress3Minimum}"
Maximum="{Binding Progress3Maximum}"
Value="{Binding Progress3Value}"
IsIndeterminate="{Binding Progress3IsIndeterminate}" />
</StackPanel>
<Button Grid.Row="5" HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanClose}"
<Button Grid.Row="5"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsEnabled="{Binding CanClose}"
Command="{Binding CloseCommand}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>

View File

@@ -28,18 +28,17 @@ using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using RomRepoMgr.ViewModels;
namespace RomRepoMgr.Views
namespace RomRepoMgr.Views;
public sealed class ExportRoms : Window
{
public sealed class ExportRoms : Window
public ExportRoms() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
public ExportRoms() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
(DataContext as ExportRomsViewModel)?.OnOpened();
}
base.OnOpened(e);
(DataContext as ExportRomsViewModel)?.OnOpened();
}
}

View File

@@ -24,12 +24,21 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="480" Height="90" x:Class="RomRepoMgr.Views.ImportDat"
Icon="/Assets/avalonia-logo.ico" CanResize="False" Title="{Binding Title}" WindowStartupLocation="CenterOwner">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="480"
Height="90"
x:Class="RomRepoMgr.Views.ImportDat"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}"
WindowStartupLocation="CenterOwner">
<Design.DataContext>
<vm:ImportDatViewModel />
</Design.DataContext>
@@ -39,14 +48,25 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding StatusMessage}" HorizontalAlignment="Center" />
<ProgressBar Grid.Row="1" IsIndeterminate="{Binding IndeterminateProgress}"
Maximum="{Binding MaximumValue}" Minimum="{Binding MinimumValue}"
Value="{Binding CurrentValue}" HorizontalAlignment="Stretch"
<TextBlock Grid.Row="0"
Text="{Binding StatusMessage}"
HorizontalAlignment="Center" />
<ProgressBar Grid.Row="1"
IsIndeterminate="{Binding IndeterminateProgress}"
Maximum="{Binding MaximumValue}"
Minimum="{Binding MinimumValue}"
Value="{Binding CurrentValue}"
HorizontalAlignment="Stretch"
IsVisible="{Binding ProgressVisible}" />
<TextBlock Grid.Row="2" Text="{Binding ErrorMessage}" HorizontalAlignment="Center" Foreground="Red"
<TextBlock Grid.Row="2"
Text="{Binding ErrorMessage}"
HorizontalAlignment="Center"
Foreground="Red"
IsVisible="{Binding ErrorVisible}" />
<Button Grid.Row="3" HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanClose}"
<Button Grid.Row="3"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsEnabled="{Binding CanClose}"
Command="{Binding CloseCommand}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>

View File

@@ -28,18 +28,17 @@ using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using RomRepoMgr.ViewModels;
namespace RomRepoMgr.Views
namespace RomRepoMgr.Views;
public sealed class ImportDat : Window
{
public sealed class ImportDat : Window
public ImportDat() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
public ImportDat() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
(DataContext as ImportDatViewModel)?.OnOpened();
}
base.OnOpened(e);
(DataContext as ImportDatViewModel)?.OnOpened();
}
}

View File

@@ -24,12 +24,21 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="480" Height="360" x:Class="RomRepoMgr.Views.ImportDatFolder"
Icon="/Assets/avalonia-logo.ico" CanResize="False" Title="{Binding Title}" WindowStartupLocation="CenterOwner">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="480"
Height="360"
x:Class="RomRepoMgr.Views.ImportDatFolder"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}"
WindowStartupLocation="CenterOwner">
<Design.DataContext>
<vm:ImportDatFolderViewModel />
</Design.DataContext>
@@ -40,58 +49,95 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding PathLabel}" FontWeight="Bold" /> <TextBlock Text="{Binding FolderPath}" />
<StackPanel Grid.Row="0"
Orientation="Horizontal"
HorizontalAlignment="Stretch">
<TextBlock Text="{Binding PathLabel}"
FontWeight="Bold" />
<TextBlock Text="{Binding FolderPath}" />
</StackPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding CategoryLabel}" FontWeight="Bold" Padding="5" />
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"
Text="{Binding Category}" Padding="5" />
<TextBlock Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding CategoryLabel}"
FontWeight="Bold"
Padding="5" />
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Category}"
Padding="5" />
</Grid>
<CheckBox Grid.Row="2" IsChecked="{Binding AllFilesChecked}" IsEnabled="{Binding IsReady}">
<CheckBox Grid.Row="2"
IsChecked="{Binding AllFilesChecked}"
IsEnabled="{Binding IsReady}">
<CheckBox.Content>
<TextBlock Text="{Binding AllFilesLabel}" />
</CheckBox.Content>
</CheckBox>
<CheckBox Grid.Row="3" IsChecked="{Binding RecursiveChecked}" IsEnabled="{Binding IsReady}">
<CheckBox Grid.Row="3"
IsChecked="{Binding RecursiveChecked}"
IsEnabled="{Binding IsReady}">
<CheckBox.Content>
<TextBlock Text="{Binding RecursiveLabel}" />
</CheckBox.Content>
</CheckBox>
<TextBlock Grid.Row="4" Text="{Binding StatusMessage}" FontWeight="Bold" HorizontalAlignment="Center" />
<ProgressBar Grid.Row="5" Minimum="{Binding ProgressMinimum}" Maximum="{Binding ProgressMaximum}"
Value="{Binding ProgressValue}" IsIndeterminate="{Binding ProgressIsIndeterminate}"
<TextBlock Grid.Row="4"
Text="{Binding StatusMessage}"
FontWeight="Bold"
HorizontalAlignment="Center" />
<ProgressBar Grid.Row="5"
Minimum="{Binding ProgressMinimum}"
Maximum="{Binding ProgressMaximum}"
Value="{Binding ProgressValue}"
IsIndeterminate="{Binding ProgressIsIndeterminate}"
IsVisible="{Binding ProgressVisible}" />
<StackPanel Grid.Row="6" IsVisible="{Binding Progress2Visible}">
<StackPanel Grid.Row="6"
IsVisible="{Binding Progress2Visible}">
<TextBlock Text="{Binding Status2Message}" />
<ProgressBar Minimum="{Binding Progress2Minimum}" Maximum="{Binding Progress2Maximum}"
Value="{Binding Progress2Value}" IsIndeterminate="{Binding Progress2IsIndeterminate}" />
<ProgressBar Minimum="{Binding Progress2Minimum}"
Maximum="{Binding Progress2Maximum}"
Value="{Binding Progress2Value}"
IsIndeterminate="{Binding Progress2IsIndeterminate}" />
</StackPanel>
<DataGrid Grid.Row="7" Items="{Binding ImportResults}" HorizontalScrollBarVisibility="Visible"
<DataGrid Grid.Row="7"
Items="{Binding ImportResults}"
HorizontalScrollBarVisibility="Visible"
IsVisible="{Binding IsImporting}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Filename}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Filename}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding ResultFilenameLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Status}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Status}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding ResultStatusLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="8" Orientation="Horizontal" IsVisible="{Binding IsReady}" HorizontalAlignment="Right">
<Button HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanClose}"
<StackPanel Grid.Row="8"
Orientation="Horizontal"
IsVisible="{Binding IsReady}"
HorizontalAlignment="Right">
<Button HorizontalAlignment="Right"
VerticalAlignment="Center"
IsEnabled="{Binding CanClose}"
Command="{Binding CloseCommand}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>
<Button HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanStart}"
<Button HorizontalAlignment="Right"
VerticalAlignment="Center"
IsEnabled="{Binding CanStart}"
Command="{Binding StartCommand}">
<TextBlock Text="{Binding StartLabel}" />
</Button>

View File

@@ -28,18 +28,17 @@ using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using RomRepoMgr.ViewModels;
namespace RomRepoMgr.Views
namespace RomRepoMgr.Views;
public sealed class ImportDatFolder : Window
{
public sealed class ImportDatFolder : Window
public ImportDatFolder() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
public ImportDatFolder() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
(DataContext as ImportDatFolderViewModel)?.OnOpened();
}
base.OnOpened(e);
(DataContext as ImportDatFolderViewModel)?.OnOpened();
}
}

View File

@@ -24,12 +24,21 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="480" Height="360" x:Class="RomRepoMgr.Views.ImportRomFolder"
Icon="/Assets/avalonia-logo.ico" CanResize="False" Title="{Binding Title}" WindowStartupLocation="CenterOwner">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="480"
Height="360"
x:Class="RomRepoMgr.Views.ImportRomFolder"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}"
WindowStartupLocation="CenterOwner">
<Design.DataContext>
<vm:ImportRomFolderViewModel />
</Design.DataContext>
@@ -40,56 +49,87 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding PathLabel}" FontWeight="Bold" /> <TextBlock Text="{Binding FolderPath}" />
<StackPanel Grid.Row="0"
Orientation="Horizontal"
HorizontalAlignment="Stretch">
<TextBlock Text="{Binding PathLabel}"
FontWeight="Bold" />
<TextBlock Text="{Binding FolderPath}" />
</StackPanel>
<CheckBox Grid.Row="1" IsChecked="{Binding RemoveFilesChecked}" IsEnabled="{Binding RemoveFilesEnabled}"
<CheckBox Grid.Row="1"
IsChecked="{Binding RemoveFilesChecked}"
IsEnabled="{Binding RemoveFilesEnabled}"
IsVisible="{Binding IsReady}">
<CheckBox.Content>
<TextBlock Text="{Binding RemoveFilesLabel}" />
</CheckBox.Content>
</CheckBox>
<CheckBox Grid.Row="2" IsChecked="{Binding KnownOnlyChecked}" IsVisible="{Binding IsReady}">
<CheckBox Grid.Row="2"
IsChecked="{Binding KnownOnlyChecked}"
IsVisible="{Binding IsReady}">
<CheckBox.Content>
<TextBlock Text="{Binding KnownOnlyLabel}" />
</CheckBox.Content>
</CheckBox>
<CheckBox Grid.Row="3" IsChecked="{Binding RecurseArchivesChecked}"
IsEnabled="{Binding RecurseArchivesEnabled}" IsVisible="{Binding IsReady}">
<CheckBox Grid.Row="3"
IsChecked="{Binding RecurseArchivesChecked}"
IsEnabled="{Binding RecurseArchivesEnabled}"
IsVisible="{Binding IsReady}">
<CheckBox.Content>
<TextBlock Text="{Binding RecurseArchivesLabel}" />
</CheckBox.Content>
</CheckBox>
<TextBlock Grid.Row="4" Text="{Binding StatusMessage}" FontWeight="Bold" HorizontalAlignment="Center" />
<ProgressBar Grid.Row="5" Minimum="{Binding ProgressMinimum}" Maximum="{Binding ProgressMaximum}"
Value="{Binding ProgressValue}" IsIndeterminate="{Binding ProgressIsIndeterminate}"
<TextBlock Grid.Row="4"
Text="{Binding StatusMessage}"
FontWeight="Bold"
HorizontalAlignment="Center" />
<ProgressBar Grid.Row="5"
Minimum="{Binding ProgressMinimum}"
Maximum="{Binding ProgressMaximum}"
Value="{Binding ProgressValue}"
IsIndeterminate="{Binding ProgressIsIndeterminate}"
IsVisible="{Binding ProgressVisible}" />
<StackPanel Grid.Row="6" IsVisible="{Binding Progress2Visible}">
<StackPanel Grid.Row="6"
IsVisible="{Binding Progress2Visible}">
<TextBlock Text="{Binding Status2Message}" />
<ProgressBar Minimum="{Binding Progress2Minimum}" Maximum="{Binding Progress2Maximum}"
Value="{Binding Progress2Value}" IsIndeterminate="{Binding Progress2IsIndeterminate}" />
<ProgressBar Minimum="{Binding Progress2Minimum}"
Maximum="{Binding Progress2Maximum}"
Value="{Binding Progress2Value}"
IsIndeterminate="{Binding Progress2IsIndeterminate}" />
</StackPanel>
<DataGrid Grid.Row="7" Items="{Binding ImportResults}" HorizontalScrollBarVisibility="Visible"
<DataGrid Grid.Row="7"
Items="{Binding ImportResults}"
HorizontalScrollBarVisibility="Visible"
IsVisible="{Binding IsImporting}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Filename}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Filename}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding ResultFilenameLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Status}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Status}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding ResultStatusLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="8" Orientation="Horizontal" HorizontalAlignment="Right">
<Button HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanClose}"
<StackPanel Grid.Row="8"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button HorizontalAlignment="Right"
VerticalAlignment="Center"
IsEnabled="{Binding CanClose}"
Command="{Binding CloseCommand}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>
<Button HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanStart}"
<Button HorizontalAlignment="Right"
VerticalAlignment="Center"
IsEnabled="{Binding CanStart}"
Command="{Binding StartCommand}">
<TextBlock Text="{Binding StartLabel}" />
</Button>

View File

@@ -26,12 +26,11 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace RomRepoMgr.Views
{
public sealed class ImportRomFolder : Window
{
public ImportRomFolder() => InitializeComponent();
namespace RomRepoMgr.Views;
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}
public sealed class ImportRomFolder : Window
{
public ImportRomFolder() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}

View File

@@ -1,130 +1,183 @@
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" x:Class="RomRepoMgr.Views.MainWindow" Icon="/Assets/avalonia-logo.ico" Title="RomRepoMgr">
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
x:Class="RomRepoMgr.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico"
Title="RomRepoMgr">
<Design.DataContext>
<vm:MainWindowViewModel />
</Design.DataContext>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="{Binding FileMenuText}">
<MenuItem Header="{Binding FileMenuImportDatFileText}" Command="{Binding ImportDatCommand}" />
<MenuItem Header="{Binding FileMenuImportDatFileText}"
Command="{Binding ImportDatCommand}" />
<Separator />
<MenuItem Header="{Binding FileMenuImportDatFolderText}" Command="{Binding ImportDatFolderCommand}" />
<MenuItem Header="{Binding FileMenuImportDatFolderText}"
Command="{Binding ImportDatFolderCommand}" />
<Separator />
<MenuItem Header="{Binding FileMenuSettingsText}" IsVisible="{Binding !NativeMenuSupported}"
<MenuItem Header="{Binding FileMenuSettingsText}"
IsVisible="{Binding !NativeMenuSupported}"
Command="{Binding SettingsCommand}" />
<Separator />
<MenuItem Header="{Binding FileMenuExitText}" IsVisible="{Binding !NativeMenuSupported}"
<MenuItem Header="{Binding FileMenuExitText}"
IsVisible="{Binding !NativeMenuSupported}"
Command="{Binding ExitCommand}" />
</MenuItem>
<MenuItem Header="{Binding FilesystemMenuText}" IsEnabled="{Binding IsVfsAvailable}">
<MenuItem Header="{Binding FilesystemMenuMountText}" Command="{Binding MountCommand}"
<MenuItem Header="{Binding FilesystemMenuText}"
IsEnabled="{Binding IsVfsAvailable}">
<MenuItem Header="{Binding FilesystemMenuMountText}"
Command="{Binding MountCommand}"
IsEnabled="{Binding Vfs, Converter={x:Static ObjectConverters.IsNull}}" />
<Separator />
<MenuItem Header="{Binding FilesystemMenuUmountText}" Command="{Binding UmountCommand}"
<MenuItem Header="{Binding FilesystemMenuUmountText}"
Command="{Binding UmountCommand}"
IsEnabled="{Binding Vfs, Converter={x:Static ObjectConverters.IsNotNull}}" />
<Separator />
</MenuItem>
<MenuItem Header="{Binding RomsMenuText}">
<MenuItem Header="{Binding RomsMenuImportText}" Command="{Binding ImportRomFolderCommand}" />
<MenuItem Header="{Binding RomsMenuImportText}"
Command="{Binding ImportRomFolderCommand}" />
<Separator />
</MenuItem>
<MenuItem Header="{Binding RomSetsMenuText}"
IsEnabled="{Binding SelectedRomSet, Converter={x:Static ObjectConverters.IsNotNull}}">
<MenuItem Header="{Binding RomSetsMenuSaveRomsText}" Command="{Binding ExportRomsCommand}" />
<MenuItem Header="{Binding RomSetsMenuSaveRomsText}"
Command="{Binding ExportRomsCommand}" />
<Separator />
<MenuItem Header="{Binding RomSetsMenuSaveDatText}" Command="{Binding ExportDatCommand}" />
<Separator /> <MenuItem Header="{Binding RomSetsMenuEditText}" Command="{Binding EditRomSetCommand}" />
<MenuItem Header="{Binding RomSetsMenuSaveDatText}"
Command="{Binding ExportDatCommand}" />
<Separator />
<MenuItem Header="{Binding RomSetsMenuDeleteText}" Command="{Binding DeleteRomSetCommand}" />
<MenuItem Header="{Binding RomSetsMenuEditText}"
Command="{Binding EditRomSetCommand}" />
<Separator />
<MenuItem Header="{Binding RomSetsMenuDeleteText}"
Command="{Binding DeleteRomSetCommand}" />
<Separator />
</MenuItem>
<MenuItem Header="{Binding DatabaseMenuText}">
<MenuItem Header="{Binding DatabaseMenuUpdateStatsText}" Command="{Binding UpdateStatsCommand}" />
<MenuItem Header="{Binding DatabaseMenuUpdateStatsText}"
Command="{Binding UpdateStatsCommand}" />
<Separator />
</MenuItem>
<MenuItem Header="{Binding HelpMenuText}">
<MenuItem Header="{Binding HelpMenuAboutText}" Name="AboutMenuItem"
IsVisible="{Binding !NativeMenuSupported}" Command="{Binding AboutCommand}" />
<MenuItem Header="{Binding HelpMenuAboutText}"
Name="AboutMenuItem"
IsVisible="{Binding !NativeMenuSupported}"
Command="{Binding AboutCommand}" />
</MenuItem>
</Menu>
<TabControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TabControl HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TabItem>
<TabItem.Header>
<TextBlock Text="{Binding RomSetLabel}" />
</TabItem.Header>
<DataGrid Items="{Binding RomSets}" HorizontalScrollBarVisibility="Visible"
SelectedItem="{Binding SelectedRomSet, Mode=TwoWay}" CanUserSortColumns="True"
<DataGrid Items="{Binding RomSets}"
HorizontalScrollBarVisibility="Visible"
SelectedItem="{Binding SelectedRomSet, Mode=TwoWay}"
CanUserSortColumns="True"
CanUserResizeColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Name}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetNameLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Version}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Version}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetVersionLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Author}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Author}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetAuthorLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Category}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Category}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetCategoryLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Date}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Date}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetDateLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Description}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Description}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetDescriptionLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Comment}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Comment}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetCommentLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Homepage}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding Homepage}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetHomepageLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding TotalMachines}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding TotalMachines}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetTotalMachinesLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding CompleteMachines}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding CompleteMachines}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetCompleteMachinesLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding IncompleteMachines}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding IncompleteMachines}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetIncompleteMachinesLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding TotalRoms}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding TotalRoms}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetTotalRomsLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding HaveRoms}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding HaveRoms}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetHaveRomsLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MissRoms}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn Binding="{Binding MissRoms}"
Width="Auto"
IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetMissRomsLabel}" />
</DataGridTextColumn.Header>

View File

@@ -27,18 +27,17 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace RomRepoMgr.Views
{
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
namespace RomRepoMgr.Views;
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}

View File

@@ -24,12 +24,21 @@
// Copyright © 2020-2024 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" Width="480" Height="90" x:Class="RomRepoMgr.Views.RemoveDat"
Icon="/Assets/avalonia-logo.ico" CanResize="False" Title="{Binding Title}" WindowStartupLocation="CenterOwner">
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Width="480"
Height="90"
x:Class="RomRepoMgr.Views.RemoveDat"
Icon="/Assets/avalonia-logo.ico"
CanResize="False"
Title="{Binding Title}"
WindowStartupLocation="CenterOwner">
<Design.DataContext>
<vm:RemoveDatViewModel />
</Design.DataContext>
@@ -38,8 +47,12 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding StatusMessage}" HorizontalAlignment="Center" />
<ProgressBar Grid.Row="1" IsIndeterminate="True" HorizontalAlignment="Stretch" />
<TextBlock Grid.Row="0"
Text="{Binding StatusMessage}"
HorizontalAlignment="Center" />
<ProgressBar Grid.Row="1"
IsIndeterminate="True"
HorizontalAlignment="Stretch" />
</Grid>
</Border>
</Window>

Some files were not shown because too many files have changed in this diff Show More