diff --git a/RomRepoMgr.Core/Aaru/FAT.cs b/RomRepoMgr.Core/Aaru/FAT.cs
index 3bead02..bc6dfaa 100644
--- a/RomRepoMgr.Core/Aaru/FAT.cs
+++ b/RomRepoMgr.Core/Aaru/FAT.cs
@@ -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;
+ }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Base32.cs b/RomRepoMgr.Core/Base32.cs
index dd264cf..99c3b6b 100644
--- a/RomRepoMgr.Core/Base32.cs
+++ b/RomRepoMgr.Core/Base32.cs
@@ -8,98 +8,76 @@ using System;
using System.Text;
using RomRepoMgr.Core.Resources;
-namespace RomRepoMgr.Core
+namespace RomRepoMgr.Core;
+
+/// Class used for conversion between byte array and Base32 notation
+public sealed class Base32
{
- /// Class used for conversion between byte array and Base32 notation
- public sealed class Base32
+ /// Size of the regular byte in bits
+ const int _inByteSize = 8;
+
+ /// Size of converted byte in bits
+ const int _outByteSize = 5;
+
+ /// Alphabet
+ const string _base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+ /// Convert byte array to Base32 format
+ /// An array of bytes to convert to Base32 format
+ /// Returns a string representing byte array
+ public static string ToBase32String(byte[] bytes)
{
- /// Size of the regular byte in bits
- const int _inByteSize = 8;
+ // Check if byte array is null
+ if(bytes == null) return null;
- /// Size of converted byte in bits
- const int _outByteSize = 5;
+ // Check if empty
- /// Alphabet
- const string _base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+ if(bytes.Length == 0) return string.Empty;
- /// Convert byte array to Base32 format
- /// An array of bytes to convert to Base32 format
- /// Returns a string representing byte array
- 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 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 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;
}
- /// Convert base32 string to array of bytes
- /// Base32 string to convert
- /// Returns a byte array converted from the string
- 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();
+ }
+
+ /// Convert base32 string to array of bytes
+ /// Base32 string to convert
+ /// Returns a byte array converted from the string
+ 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;
}
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/BigEndianBitConverter.cs b/RomRepoMgr.Core/Checksums/BigEndianBitConverter.cs
index 2d4a7ab..c91c305 100644
--- a/RomRepoMgr.Core/Checksums/BigEndianBitConverter.cs
+++ b/RomRepoMgr.Core/Checksums/BigEndianBitConverter.cs
@@ -33,288 +33,287 @@
using System;
using System.Linq;
-namespace Aaru.Helpers
+namespace Aaru.Helpers;
+
+///
+/// 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.
+///
+public static class BigEndianBitConverter
{
+ /// Converts the specified double-precision floating point number to a 64-bit signed integer.
+ /// The number to convert.
+ /// A 64-bit signed integer whose value is equivalent to value.
+ /// It is not currently implemented
+ public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
+
+ /// Returns the specified Boolean value as an array of bytes.
+ /// A Boolean value.
+ /// An array of bytes with length 1.
+ public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified Unicode character value as an array of bytes.
+ /// A character to convert.
+ /// An array of bytes with length 2.
+ public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified double-precision floating point value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified single-precision floating point value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified 32-bit signed integer value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified 64-bit signed integer value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified 16-bit signed integer value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 2.
+ public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified 32-bit unsigned integer value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified 64-bit unsigned integer value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Returns the specified 16-bit unsigned integer value as an array of bytes.
+ /// The number to convert.
+ /// An array of bytes with length 2.
+ public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
+
+ /// Converts the specified 64-bit signed integer to a double-precision floating point number.
+ /// The number to convert.
+ /// A double-precision floating point number whose value is equivalent to value.
+ public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
+
+ /// Returns a Boolean value converted from one byte at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within value.
+ /// true if the byte at in value is nonzero; otherwise, false.
+ /// value is null.
+ ///
+ /// is less than zero or greater than the
+ /// length of value minus 1.
+ ///
+ public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
+
+ /// Returns a Unicode character converted from two bytes at a specified position in a byte array.
+ /// An array.
+ /// The starting position within value.
+ /// A character formed by two bytes beginning at .
+ /// equals the length of value minus 1.
+ /// value is null.
+ ///
+ /// is less than zero or greater than the
+ /// length of value minus 1.
+ ///
+ public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
+
///
- /// 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.
///
- public static class BigEndianBitConverter
- {
- /// Converts the specified double-precision floating point number to a 64-bit signed integer.
- /// The number to convert.
- /// A 64-bit signed integer whose value is equivalent to value.
- /// It is not currently implemented
- public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A double precision floating point number formed by eight bytes beginning at .
+ ///
+ /// 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.
+ ///
+ /// value is null.
+ ///
+ /// is less than zero or greater than the
+ /// length of value minus 1.
+ ///
+ public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
- /// Returns the specified Boolean value as an array of bytes.
- /// A Boolean value.
- /// An array of bytes with length 1.
- public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ /// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 16-bit signed integer formed by two bytes beginning at .
+ /// equals the length of value minus 1.
+ /// value is null.
+ ///
+ /// startIndex is less than zero or greater than the length of value
+ /// minus 1.
+ ///
+ public static short ToInt16(byte[] value, int startIndex) =>
+ BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
- /// Returns the specified Unicode character value as an array of bytes.
- /// A character to convert.
- /// An array of bytes with length 2.
- public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ /// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 32-bit signed integer formed by four bytes beginning at .
+ ///
+ /// 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.
+ ///
+ /// value is null.
+ ///
+ /// startIndex is less than zero or greater than the length of value
+ /// minus 1.
+ ///
+ public static int ToInt32(byte[] value, int startIndex) =>
+ BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
- /// Returns the specified double-precision floating point value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 8.
- public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ /// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 64-bit signed integer formed by eight bytes beginning at .
+ ///
+ /// 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.
+ ///
+ /// value is null.
+ ///
+ /// is less than zero or greater than the
+ /// length of value minus 1.
+ ///
+ public static long ToInt64(byte[] value, int startIndex) =>
+ BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
- /// Returns the specified single-precision floating point value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 4.
- public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ ///
+ /// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
+ /// array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A single-precision floating point number formed by four bytes beginning at .
+ ///
+ /// 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.
+ ///
+ /// value is null.
+ ///
+ /// is less than zero or greater than the
+ /// length of value minus 1.
+ ///
+ public static float ToSingle(byte[] value, int startIndex) =>
+ BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
- /// Returns the specified 32-bit signed integer value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 4.
- public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ ///
+ /// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
+ /// representation.
+ ///
+ /// An array of bytes.
+ ///
+ /// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
+ /// element in value; for example, "7F-2C-4A".
+ ///
+ /// value is null.
+ public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
- /// Returns the specified 64-bit signed integer value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 8.
- public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ ///
+ /// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
+ /// string representation.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ ///
+ /// 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".
+ ///
+ /// value is null.
+ ///
+ /// startIndex is less than zero or greater than the length of value
+ /// minus 1.
+ ///
+ public static string ToString(byte[] value, int startIndex) =>
+ BitConverter.ToString(value.Reverse().ToArray(), startIndex);
- /// Returns the specified 16-bit signed integer value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 2.
- public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ ///
+ /// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
+ /// string representation.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// The number of array elements in value to convert.
+ ///
+ /// 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".
+ ///
+ /// value is null.
+ ///
+ /// startIndex or length is less than zero. -or- startIndex is greater
+ /// than zero and is greater than or equal to the length of value.
+ ///
+ ///
+ /// 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.
+ ///
+ public static string ToString(byte[] value, int startIndex, int length) =>
+ BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
- /// Returns the specified 32-bit unsigned integer value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 4.
- public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ /// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
+ /// The array of bytes.
+ /// The starting position within value.
+ /// A 16-bit unsigned integer formed by two bytes beginning at startIndex.
+ /// startIndex equals the length of value minus 1.
+ /// value is null.
+ ///
+ /// startIndex is less than zero or greater than the length of value
+ /// minus 1.
+ ///
+ public static ushort ToUInt16(byte[] value, int startIndex) =>
+ BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
- /// Returns the specified 64-bit unsigned integer value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 8.
- public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ /// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 32-bit unsigned integer formed by four bytes beginning at startIndex.
+ ///
+ /// 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.
+ ///
+ /// value is null.
+ ///
+ /// startIndex is less than zero or greater than the length of value
+ /// minus 1.
+ ///
+ public static uint ToUInt32(byte[] value, int startIndex) =>
+ BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
- /// Returns the specified 16-bit unsigned integer value as an array of bytes.
- /// The number to convert.
- /// An array of bytes with length 2.
- public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
+ /// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.
+ ///
+ /// 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.
+ ///
+ /// value is null.
+ ///
+ /// startIndex is less than zero or greater than the length of value
+ /// minus 1.
+ ///
+ public static ulong ToUInt64(byte[] value, int startIndex) =>
+ BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(ulong) - startIndex);
- /// Converts the specified 64-bit signed integer to a double-precision floating point number.
- /// The number to convert.
- /// A double-precision floating point number whose value is equivalent to value.
- public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
-
- /// Returns a Boolean value converted from one byte at a specified position in a byte array.
- /// An array of bytes.
- /// The starting position within value.
- /// true if the byte at in value is nonzero; otherwise, false.
- /// value is null.
- ///
- /// is less than zero or greater than the
- /// length of value minus 1.
- ///
- public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
-
- /// Returns a Unicode character converted from two bytes at a specified position in a byte array.
- /// An array.
- /// The starting position within value.
- /// A character formed by two bytes beginning at .
- /// equals the length of value minus 1.
- /// value is null.
- ///
- /// is less than zero or greater than the
- /// length of value minus 1.
- ///
- public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
-
- ///
- /// Returns a double-precision floating point number converted from eight bytes at a specified position in a byte
- /// array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A double precision floating point number formed by eight bytes beginning at .
- ///
- /// 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.
- ///
- /// value is null.
- ///
- /// is less than zero or greater than the
- /// length of value minus 1.
- ///
- public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
-
- /// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
- /// An array of bytes.
- /// The starting position within value.
- /// A 16-bit signed integer formed by two bytes beginning at .
- /// equals the length of value minus 1.
- /// value is null.
- ///
- /// startIndex is less than zero or greater than the length of value
- /// minus 1.
- ///
- public static short ToInt16(byte[] value, int startIndex) =>
- BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
-
- /// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
- /// An array of bytes.
- /// The starting position within value.
- /// A 32-bit signed integer formed by four bytes beginning at .
- ///
- /// 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.
- ///
- /// value is null.
- ///
- /// startIndex is less than zero or greater than the length of value
- /// minus 1.
- ///
- public static int ToInt32(byte[] value, int startIndex) =>
- BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
-
- /// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
- /// An array of bytes.
- /// The starting position within value.
- /// A 64-bit signed integer formed by eight bytes beginning at .
- ///
- /// 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.
- ///
- /// value is null.
- ///
- /// is less than zero or greater than the
- /// length of value minus 1.
- ///
- public static long ToInt64(byte[] value, int startIndex) =>
- BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
-
- ///
- /// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
- /// array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A single-precision floating point number formed by four bytes beginning at .
- ///
- /// 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.
- ///
- /// value is null.
- ///
- /// is less than zero or greater than the
- /// length of value minus 1.
- ///
- public static float ToSingle(byte[] value, int startIndex) =>
- BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
-
- ///
- /// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
- /// representation.
- ///
- /// An array of bytes.
- ///
- /// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
- /// element in value; for example, "7F-2C-4A".
- ///
- /// value is null.
- public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
-
- ///
- /// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
- /// string representation.
- ///
- /// An array of bytes.
- /// The starting position within value.
- ///
- /// 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".
- ///
- /// value is null.
- ///
- /// startIndex is less than zero or greater than the length of value
- /// minus 1.
- ///
- public static string ToString(byte[] value, int startIndex) =>
- BitConverter.ToString(value.Reverse().ToArray(), startIndex);
-
- ///
- /// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
- /// string representation.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// The number of array elements in value to convert.
- ///
- /// 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".
- ///
- /// value is null.
- ///
- /// startIndex or length is less than zero. -or- startIndex is greater
- /// than zero and is greater than or equal to the length of value.
- ///
- ///
- /// 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.
- ///
- public static string ToString(byte[] value, int startIndex, int length) =>
- BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
-
- /// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
- /// The array of bytes.
- /// The starting position within value.
- /// A 16-bit unsigned integer formed by two bytes beginning at startIndex.
- /// startIndex equals the length of value minus 1.
- /// value is null.
- ///
- /// startIndex is less than zero or greater than the length of value
- /// minus 1.
- ///
- public static ushort ToUInt16(byte[] value, int startIndex) =>
- BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
-
- /// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
- /// An array of bytes.
- /// The starting position within value.
- /// A 32-bit unsigned integer formed by four bytes beginning at startIndex.
- ///
- /// 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.
- ///
- /// value is null.
- ///
- /// startIndex is less than zero or greater than the length of value
- /// minus 1.
- ///
- public static uint ToUInt32(byte[] value, int startIndex) =>
- BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
-
- /// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
- /// An array of bytes.
- /// The starting position within value.
- /// A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.
- ///
- /// 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.
- ///
- /// value is null.
- ///
- /// startIndex is less than zero or greater than the length of value
- /// minus 1.
- ///
- 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]);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/CRC32Context.cs b/RomRepoMgr.Core/Checksums/CRC32Context.cs
index eadf5cb..ca50745 100644
--- a/RomRepoMgr.Core/Checksums/CRC32Context.cs
+++ b/RomRepoMgr.Core/Checksums/CRC32Context.cs
@@ -35,199 +35,202 @@ using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Implements a CRC32 algorithm
+public sealed class Crc32Context : IChecksum
{
- /// Implements a CRC32 algorithm
- 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;
+
+ /// Initializes the CRC32 table and seed as CRC32-ISO
+ 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];
- /// Initializes the CRC32 table and seed as CRC32-ISO
- 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;
- }
- }
-
- /// Initializes the CRC32 table with a custom polynomial and seed
- 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;
- }
- }
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len)
- {
- for(int i = 0; i < len; i++)
- _hashInt = (_hashInt >> 8) ^ _table[data[i] ^ (_hashInt & 0xff)];
- }
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed);
-
- ///
- /// Returns a hexadecimal representation of the hash value.
- 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();
- }
-
- /// Gets the hash of a file
- /// File path.
- public static byte[] File(string filename)
- {
- File(filename, out byte[] hash);
-
- return hash;
- }
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- public static string File(string filename, out byte[] hash) =>
- File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- /// CRC polynomial
- /// CRC seed
- 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;
}
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- public static string Data(byte[] data, uint len, out byte[] hash) =>
- Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- /// CRC polynomial
- /// CRC seed
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Byte array of the hash value.
- public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
+
+ /// Initializes the CRC32 table with a custom polynomial and seed
+ 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;
+ }
+ }
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len)
+ {
+ for(var i = 0; i < len; i++) _hashInt = _hashInt >> 8 ^ _table[data[i] ^ _hashInt & 0xff];
+ }
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed);
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of a file
+ /// File path.
+ public static byte[] File(string filename)
+ {
+ File(filename, out byte[] hash);
+
+ return hash;
+ }
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ public static string File(string filename, out byte[] hash) =>
+ File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ /// CRC polynomial
+ /// CRC seed
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, uint len, out byte[] hash) =>
+ Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ /// CRC polynomial
+ /// CRC seed
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/CRC64Context.cs b/RomRepoMgr.Core/Checksums/CRC64Context.cs
index 95fd3cb..ffddb0d 100644
--- a/RomRepoMgr.Core/Checksums/CRC64Context.cs
+++ b/RomRepoMgr.Core/Checksums/CRC64Context.cs
@@ -35,201 +35,204 @@ using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Implements a CRC64 algorithm
+public sealed class Crc64Context : IChecksum
{
- /// Implements a CRC64 algorithm
- 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;
+
+ /// Initializes the CRC64 table and seed as CRC64-ECMA
+ 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];
- /// Initializes the CRC64 table and seed as CRC64-ECMA
- 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;
}
- /// Initializes the CRC16 table with a custom polynomial and seed
- 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;
- }
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len)
- {
- for(int i = 0; i < len; i++)
- _hashInt = (_hashInt >> 8) ^ _table[data[i] ^ (_hashInt & 0xff)];
- }
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed);
-
- ///
- /// Returns a hexadecimal representation of the hash value.
- 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();
- }
-
- /// Gets the hash of a file
- /// File path.
- public static byte[] File(string filename)
- {
- File(filename, out byte[] localHash);
-
- return localHash;
- }
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- public static string File(string filename, out byte[] hash) =>
- File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- /// CRC polynomial
- /// CRC seed
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- public static string Data(byte[] data, uint len, out byte[] hash) =>
- Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- /// CRC polynomial
- /// CRC seed
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Byte array of the hash value.
- public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
+ _finalSeed = CRC64_ECMA_SEED;
}
+
+ /// Initializes the CRC16 table with a custom polynomial and seed
+ 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;
+ }
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len)
+ {
+ for(var i = 0; i < len; i++) _hashInt = _hashInt >> 8 ^ _table[data[i] ^ _hashInt & 0xff];
+ }
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed);
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of a file
+ /// File path.
+ public static byte[] File(string filename)
+ {
+ File(filename, out byte[] localHash);
+
+ return localHash;
+ }
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ public static string File(string filename, out byte[] hash) =>
+ File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ /// CRC polynomial
+ /// CRC seed
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, uint len, out byte[] hash) =>
+ Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ /// CRC polynomial
+ /// CRC seed
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/IChecksum.cs b/RomRepoMgr.Core/Checksums/IChecksum.cs
index 6b40c4a..996b63f 100644
--- a/RomRepoMgr.Core/Checksums/IChecksum.cs
+++ b/RomRepoMgr.Core/Checksums/IChecksum.cs
@@ -36,23 +36,22 @@
// Copyright © 2011-2024 Natalia Portillo
// ****************************************************************************/
-namespace Aaru.CommonTypes.Interfaces
+namespace Aaru.CommonTypes.Interfaces;
+
+public interface IChecksum
{
- public interface IChecksum
- {
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- void Update(byte[] data, uint len);
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ void Update(byte[] data, uint len);
- /// Updates the hash with data.
- /// Data buffer.
- void Update(byte[] data);
+ /// Updates the hash with data.
+ /// Data buffer.
+ void Update(byte[] data);
- /// Returns a byte array of the hash value.
- byte[] Final();
+ /// Returns a byte array of the hash value.
+ byte[] Final();
- /// Returns a hexadecimal representation of the hash value.
- string End();
- }
+ /// Returns a hexadecimal representation of the hash value.
+ string End();
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/MD5Context.cs b/RomRepoMgr.Core/Checksums/MD5Context.cs
index 70fb836..4f9e748 100644
--- a/RomRepoMgr.Core/Checksums/MD5Context.cs
+++ b/RomRepoMgr.Core/Checksums/MD5Context.cs
@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Wraps up .NET MD5 implementation to a Init(), Update(), Final() context.
+public sealed class Md5Context : IChecksum
{
- /// Wraps up .NET MD5 implementation to a Init(), Update(), Final() context.
- public sealed class Md5Context : IChecksum
+ readonly MD5 _provider;
+
+ /// Initializes the MD5 hash provider
+ public Md5Context() => _provider = MD5.Create();
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final()
{
- readonly MD5 _provider;
+ _provider.TransformFinalBlock(new byte[0], 0, 0);
- /// Initializes the MD5 hash provider
- public Md5Context() => _provider = MD5.Create();
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final()
- {
- _provider.TransformFinalBlock(new byte[0], 0, 0);
-
- return _provider.Hash;
- }
-
- ///
- /// Returns a hexadecimal representation of the hash value.
- 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();
- }
-
- /// Gets the hash of a file
- /// File path.
- 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;
- }
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Byte array of the hash value.
- public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
+ return _provider.Hash;
}
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of a file
+ /// File path.
+ 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;
+ }
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/SHA1Context.cs b/RomRepoMgr.Core/Checksums/SHA1Context.cs
index 78e913b..242b265 100644
--- a/RomRepoMgr.Core/Checksums/SHA1Context.cs
+++ b/RomRepoMgr.Core/Checksums/SHA1Context.cs
@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context.
+public sealed class Sha1Context : IChecksum
{
- /// Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context.
- public sealed class Sha1Context : IChecksum
+ readonly SHA1 _provider;
+
+ /// Initializes the SHA1 hash provider
+ public Sha1Context() => _provider = SHA1.Create();
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final()
{
- readonly SHA1 _provider;
+ _provider.TransformFinalBlock(new byte[0], 0, 0);
- /// Initializes the SHA1 hash provider
- public Sha1Context() => _provider = SHA1.Create();
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final()
- {
- _provider.TransformFinalBlock(new byte[0], 0, 0);
-
- return _provider.Hash;
- }
-
- ///
- /// Returns a hexadecimal representation of the hash value.
- 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();
- }
-
- /// Gets the hash of a file
- /// File path.
- 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;
- }
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Byte array of the hash value.
- public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
+ return _provider.Hash;
}
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of a file
+ /// File path.
+ 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;
+ }
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/SHA256Context.cs b/RomRepoMgr.Core/Checksums/SHA256Context.cs
index 273ec9c..7df7414 100644
--- a/RomRepoMgr.Core/Checksums/SHA256Context.cs
+++ b/RomRepoMgr.Core/Checksums/SHA256Context.cs
@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context.
+public sealed class Sha256Context : IChecksum
{
- /// Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context.
- public sealed class Sha256Context : IChecksum
+ readonly SHA256 _provider;
+
+ /// Initializes the SHA256 hash provider
+ public Sha256Context() => _provider = SHA256.Create();
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final()
{
- readonly SHA256 _provider;
+ _provider.TransformFinalBlock(new byte[0], 0, 0);
- /// Initializes the SHA256 hash provider
- public Sha256Context() => _provider = SHA256.Create();
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final()
- {
- _provider.TransformFinalBlock(new byte[0], 0, 0);
-
- return _provider.Hash;
- }
-
- ///
- /// Returns a hexadecimal representation of the hash value.
- 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();
- }
-
- /// Gets the hash of a file
- /// File path.
- 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;
- }
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Byte array of the hash value.
- public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
+ return _provider.Hash;
}
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of a file
+ /// File path.
+ 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;
+ }
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/SHA384Context.cs b/RomRepoMgr.Core/Checksums/SHA384Context.cs
index 280e889..bfe47a9 100644
--- a/RomRepoMgr.Core/Checksums/SHA384Context.cs
+++ b/RomRepoMgr.Core/Checksums/SHA384Context.cs
@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context.
+public sealed class Sha384Context : IChecksum
{
- /// Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context.
- public sealed class Sha384Context : IChecksum
+ readonly SHA384 _provider;
+
+ /// Initializes the SHA384 hash provider
+ public Sha384Context() => _provider = SHA384.Create();
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final()
{
- readonly SHA384 _provider;
+ _provider.TransformFinalBlock(new byte[0], 0, 0);
- /// Initializes the SHA384 hash provider
- public Sha384Context() => _provider = SHA384.Create();
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final()
- {
- _provider.TransformFinalBlock(new byte[0], 0, 0);
-
- return _provider.Hash;
- }
-
- ///
- /// Returns a hexadecimal representation of the hash value.
- 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();
- }
-
- /// Gets the hash of a file
- /// File path.
- 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;
- }
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Byte array of the hash value.
- public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
+ return _provider.Hash;
}
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of a file
+ /// File path.
+ 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;
+ }
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/SHA512Context.cs b/RomRepoMgr.Core/Checksums/SHA512Context.cs
index 0fb7d7b..7ed9df5 100644
--- a/RomRepoMgr.Core/Checksums/SHA512Context.cs
+++ b/RomRepoMgr.Core/Checksums/SHA512Context.cs
@@ -35,98 +35,94 @@ using System.Security.Cryptography;
using System.Text;
using Aaru.CommonTypes.Interfaces;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context.
+public sealed class Sha512Context : IChecksum
{
- /// Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context.
- public sealed class Sha512Context : IChecksum
+ readonly SHA512 _provider;
+
+ /// Initializes the SHA512 hash provider
+ public Sha512Context() => _provider = SHA512.Create();
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final()
{
- readonly SHA512 _provider;
+ _provider.TransformFinalBlock(new byte[0], 0, 0);
- /// Initializes the SHA512 hash provider
- public Sha512Context() => _provider = SHA512.Create();
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len) => _provider.TransformBlock(data, 0, (int)len, data, 0);
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final()
- {
- _provider.TransformFinalBlock(new byte[0], 0, 0);
-
- return _provider.Hash;
- }
-
- ///
- /// Returns a hexadecimal representation of the hash value.
- 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();
- }
-
- /// Gets the hash of a file
- /// File path.
- 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;
- }
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// Byte array of the hash value.
- 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();
- }
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Byte array of the hash value.
- public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
+ return _provider.Hash;
}
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of a file
+ /// File path.
+ 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;
+ }
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// Byte array of the hash value.
+ 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();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Byte array of the hash value.
+ public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Checksums/SpamSumContext.cs b/RomRepoMgr.Core/Checksums/SpamSumContext.cs
index a56ec5c..d655f9b 100644
--- a/RomRepoMgr.Core/Checksums/SpamSumContext.cs
+++ b/RomRepoMgr.Core/Checksums/SpamSumContext.cs
@@ -45,283 +45,316 @@ using System.Text;
using Aaru.CommonTypes.Interfaces;
using RomRepoMgr.Core.Resources;
-namespace Aaru.Checksums
+namespace Aaru.Checksums;
+
+/// Implements the SpamSum fuzzy hashing algorithm.
+public sealed class SpamSumContext : IChecksum
{
- /// Implements the SpamSum fuzzy hashing algorithm.
- 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;
+
+ /// Initializes the SpamSum structures
+ 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];
- /// Initializes the SpamSum structures
- 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();
+ }
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ /// Length of buffer to hash.
+ public void Update(byte[] data, uint len)
+ {
+ _self.TotalSize += len;
+
+ for(var i = 0; i < len; i++) fuzzy_engine_step(data[i]);
+ }
+
+ ///
+ /// Updates the hash with data.
+ /// Data buffer.
+ public void Update(byte[] data) => Update(data, (uint)data.Length);
+
+ ///
+ /// Returns a byte array of the hash value.
+ public byte[] Final() => throw new NotImplementedException(Localization.Spamsum_no_binary);
+
+ ///
+ /// Returns a base64 representation of the hash value.
+ 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();
- }
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- /// Length of buffer to hash.
- public void Update(byte[] data, uint len)
- {
- _self.TotalSize += len;
-
- for(int i = 0; i < len; i++)
- fuzzy_engine_step(data[i]);
- }
-
- ///
- /// Updates the hash with data.
- /// Data buffer.
- public void Update(byte[] data) => Update(data, (uint)data.Length);
-
- ///
- /// Returns a byte array of the hash value.
- public byte[] Final() => throw new NotImplementedException(Localization.Spamsum_no_binary);
-
- ///
- /// Returns a base64 representation of the hash value.
- 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;
}
-
- /// Gets the hash of a file
- /// File path.
- public static byte[] File(string filename) => throw new NotImplementedException(Localization.Spamsum_no_binary);
-
- /// Gets the hash of a file in hexadecimal and as a byte array.
- /// File path.
- /// Byte array of the hash value.
- public static string File(string filename, out byte[] hash) =>
- throw new NotImplementedException(Localization.Not_yet_implemented);
-
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// Length of the data buffer to hash.
- /// null
- /// Base64 representation of SpamSum $blocksize:$hash:$hash
- 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;
}
- /// Gets the hash of the specified data buffer.
- /// Data buffer.
- /// null
- /// Base64 representation of SpamSum $blocksize:$hash:$hash
- 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)
+ /// Gets the hash of a file
+ /// File path.
+ public static byte[] File(string filename) => throw new NotImplementedException(Localization.Spamsum_no_binary);
+
+ /// Gets the hash of a file in hexadecimal and as a byte array.
+ /// File path.
+ /// Byte array of the hash value.
+ public static string File(string filename, out byte[] hash) =>
+ throw new NotImplementedException(Localization.Not_yet_implemented);
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// Length of the data buffer to hash.
+ /// null
+ /// Base64 representation of SpamSum $blocksize:$hash:$hash
+ public static string Data(byte[] data, uint len, out byte[] hash)
+ {
+ var fuzzyContext = new SpamSumContext();
+
+ fuzzyContext.Update(data, len);
+
+ hash = null;
+
+ return fuzzyContext.End();
+ }
+
+ /// Gets the hash of the specified data buffer.
+ /// Data buffer.
+ /// null
+ /// Base64 representation of SpamSum $blocksize:$hash:$hash
+ 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;
}
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/EventArgs/ErrorEventArgs.cs b/RomRepoMgr.Core/EventArgs/ErrorEventArgs.cs
index 8db94d7..d63bbd6 100644
--- a/RomRepoMgr.Core/EventArgs/ErrorEventArgs.cs
+++ b/RomRepoMgr.Core/EventArgs/ErrorEventArgs.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/EventArgs/ImportedRomEventArgs.cs b/RomRepoMgr.Core/EventArgs/ImportedRomEventArgs.cs
index 0329cb8..34fa2e5 100644
--- a/RomRepoMgr.Core/EventArgs/ImportedRomEventArgs.cs
+++ b/RomRepoMgr.Core/EventArgs/ImportedRomEventArgs.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/EventArgs/MessageEventArgs.cs b/RomRepoMgr.Core/EventArgs/MessageEventArgs.cs
index 539483e..ba557d9 100644
--- a/RomRepoMgr.Core/EventArgs/MessageEventArgs.cs
+++ b/RomRepoMgr.Core/EventArgs/MessageEventArgs.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/EventArgs/ProgressBoundsEventArgs.cs b/RomRepoMgr.Core/EventArgs/ProgressBoundsEventArgs.cs
index c1951ae..c0ab420 100644
--- a/RomRepoMgr.Core/EventArgs/ProgressBoundsEventArgs.cs
+++ b/RomRepoMgr.Core/EventArgs/ProgressBoundsEventArgs.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/EventArgs/ProgressEventArgs.cs b/RomRepoMgr.Core/EventArgs/ProgressEventArgs.cs
index 402744b..c87f272 100644
--- a/RomRepoMgr.Core/EventArgs/ProgressEventArgs.cs
+++ b/RomRepoMgr.Core/EventArgs/ProgressEventArgs.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/EventArgs/RomSetEventArgs.cs b/RomRepoMgr.Core/EventArgs/RomSetEventArgs.cs
index b2a48e0..da3a600 100644
--- a/RomRepoMgr.Core/EventArgs/RomSetEventArgs.cs
+++ b/RomRepoMgr.Core/EventArgs/RomSetEventArgs.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/EventArgs/RomSetsEventArgs.cs b/RomRepoMgr.Core/EventArgs/RomSetsEventArgs.cs
index a9b4610..07ecfd4 100644
--- a/RomRepoMgr.Core/EventArgs/RomSetsEventArgs.cs
+++ b/RomRepoMgr.Core/EventArgs/RomSetsEventArgs.cs
@@ -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 RomSets { get; set; }
- }
+ public List RomSets { get; set; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Filesystem/Fuse.cs b/RomRepoMgr.Core/Filesystem/Fuse.cs
index d20243d..64f7688 100644
--- a/RomRepoMgr.Core/Filesystem/Fuse.cs
+++ b/RomRepoMgr.Core/Filesystem/Fuse.cs
@@ -10,166 +10,298 @@ using Mono.Fuse.NETStandard;
using Mono.Unix.Native;
using RomRepoMgr.Database.Models;
-namespace RomRepoMgr.Core.Filesystem
+namespace RomRepoMgr.Core.Filesystem;
+
+// TODO: Last handle goes negative
+[SupportedOSPlatform("Linux")]
+[SupportedOSPlatform("macOS")]
+public sealed class Fuse : FileSystem
{
- // TODO: Last handle goes negative
- [SupportedOSPlatform("Linux")]
- [SupportedOSPlatform("macOS")]
- public sealed class Fuse : FileSystem
+ readonly ConcurrentDictionary> _directoryCache;
+ readonly ConcurrentDictionary _fileStatHandleCache;
+ readonly Vfs _vfs;
+ long _lastHandle;
+ string _umountToken;
+
+ public Fuse(Vfs vfs)
{
- readonly ConcurrentDictionary> _directoryCache;
- readonly ConcurrentDictionary _fileStatHandleCache;
- readonly Vfs _vfs;
- long _lastHandle;
- string _umountToken;
+ _directoryCache = new ConcurrentDictionary>();
+ _lastHandle = 0;
+ _fileStatHandleCache = new ConcurrentDictionary();
+ Name = "romrepombgrfs";
+ _vfs = vfs;
+ }
- public Fuse(Vfs vfs)
+ public static bool IsAvailable
+ {
+ get
{
- _directoryCache = new ConcurrentDictionary>();
- _lastHandle = 0;
- _fileStatHandleCache = new ConcurrentDictionary();
- Name = "romrepombgrfs";
- _vfs = vfs;
- }
-
- public static bool IsAvailable
- {
- get
+ try
{
- try
+ IntPtr fuse = dlopen("libfuse.so.2", 2);
+
+ if(fuse == IntPtr.Zero) return false;
+
+ dlclose(fuse);
+
+ IntPtr helper = dlopen("libMonoFuseHelper.so", 2);
+
+ if(helper == IntPtr.Zero)
{
- IntPtr fuse = dlopen("libfuse.so.2", 2);
+ helper = dlopen("./libMonoFuseHelper.so", 2);
- if(fuse == IntPtr.Zero)
- return false;
-
- dlclose(fuse);
-
- IntPtr helper = dlopen("libMonoFuseHelper.so", 2);
-
- if(helper == IntPtr.Zero)
- {
- helper = dlopen("./libMonoFuseHelper.so", 2);
-
- if(helper == IntPtr.Zero)
- return false;
- }
-
- dlclose(helper);
-
- return true;
- }
- catch(Exception e)
- {
- return false;
+ if(helper == IntPtr.Zero) return false;
}
+
+ dlclose(helper);
+
+ return true;
+ }
+ catch(Exception e)
+ {
+ return false;
}
}
+ }
- [DllImport("libdl")]
- static extern IntPtr dlopen(string filename, int flags);
+ [DllImport("libdl")]
+ static extern IntPtr dlopen(string filename, int flags);
- [DllImport("libdl")]
- static extern int dlclose(IntPtr handle);
+ [DllImport("libdl")]
+ static extern int dlclose(IntPtr handle);
- protected override Errno OnGetPathStatus(string path, out Stat stat)
+ protected override Errno OnGetPathStatus(string path, out Stat stat)
+ {
+ stat = new Stat();
+
+ string[] pieces = _vfs.SplitPath(path);
+
+ if(pieces.Length == 0)
{
- stat = new Stat();
+ stat.st_mode = FilePermissions.S_IFDIR | NativeConvert.FromOctalPermissionString("0555");
+ stat.st_nlink = 2;
- string[] pieces = _vfs.SplitPath(path);
+ return 0;
+ }
- if(pieces.Length == 0)
+ long romSetId = _vfs.GetRomSetId(pieces[0]);
+
+ if(romSetId <= 0)
+ {
+ if(pieces[0] != ".fuse_umount" || _umountToken == null) return Errno.ENOENT;
+
+ stat = new Stat
{
- stat.st_mode = FilePermissions.S_IFDIR | NativeConvert.FromOctalPermissionString("0555");
- stat.st_nlink = 2;
+ st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
+ st_nlink = 1,
+ st_ctime = NativeConvert.ToTimeT(DateTime.UtcNow),
+ st_mtime = NativeConvert.ToTimeT(DateTime.UtcNow),
+ st_blksize = 0,
+ st_blocks = 0,
+ st_ino = 0,
+ st_size = 0
+ };
- return 0;
- }
+ return 0;
+ }
- long romSetId = _vfs.GetRomSetId(pieces[0]);
+ RomSet romSet = _vfs.GetRomSet(romSetId);
- if(romSetId <= 0)
+ if(romSet == null) return Errno.ENOENT;
+
+ if(pieces.Length == 1)
+ {
+ stat.st_mode = FilePermissions.S_IFDIR | NativeConvert.FromOctalPermissionString("0555");
+ stat.st_nlink = 2;
+ stat.st_ctime = NativeConvert.ToTimeT(romSet.CreatedOn.ToUniversalTime());
+ stat.st_mtime = NativeConvert.ToTimeT(romSet.UpdatedOn.ToUniversalTime());
+
+ return 0;
+ }
+
+ CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+
+ if(machine == null) return Errno.ENOENT;
+
+ if(pieces.Length == 2)
+ {
+ stat = new Stat
{
- if(pieces[0] != ".fuse_umount" ||
- _umountToken == null)
- return Errno.ENOENT;
+ st_mode = FilePermissions.S_IFDIR | NativeConvert.FromOctalPermissionString("0555"),
+ st_nlink = 2,
+ st_ctime = NativeConvert.ToTimeT(machine.CreationDate.ToUniversalTime()),
+ st_mtime = NativeConvert.ToTimeT(machine.ModificationDate.ToUniversalTime())
+ };
- stat = new Stat
- {
- st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
- st_nlink = 1,
- st_ctime = NativeConvert.ToTimeT(DateTime.UtcNow),
- st_mtime = NativeConvert.ToTimeT(DateTime.UtcNow),
- st_blksize = 0,
- st_blocks = 0,
- st_ino = 0,
- st_size = 0
- };
+ return 0;
+ }
- return 0;
- }
+ CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
- RomSet romSet = _vfs.GetRomSet(romSetId);
+ if(file != null)
+ {
+ if(pieces.Length != 3) return Errno.ENOSYS;
- if(romSet == null)
- return Errno.ENOENT;
-
- if(pieces.Length == 1)
+ stat = new Stat
{
- stat.st_mode = FilePermissions.S_IFDIR | NativeConvert.FromOctalPermissionString("0555");
- stat.st_nlink = 2;
- stat.st_ctime = NativeConvert.ToTimeT(romSet.CreatedOn.ToUniversalTime());
- stat.st_mtime = NativeConvert.ToTimeT(romSet.UpdatedOn.ToUniversalTime());
+ st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
+ st_nlink = 1,
+ st_ctime = NativeConvert.ToTimeT(file.CreatedOn.ToUniversalTime()),
+ st_mtime =
+ NativeConvert.ToTimeT(file.FileLastModification?.ToUniversalTime() ??
+ file.UpdatedOn.ToUniversalTime()),
+ st_blksize = 512,
+ st_blocks = (long)(file.Size / 512),
+ st_ino = file.Id,
+ st_size = (long)file.Size
+ };
- return 0;
- }
+ return 0;
+ }
- CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+ CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
- if(machine == null)
- return Errno.ENOENT;
+ if(disk != null)
+ {
+ if(pieces.Length != 3) return Errno.ENOSYS;
- if(pieces.Length == 2)
+ stat = new Stat
{
- stat = new Stat
- {
- st_mode = FilePermissions.S_IFDIR | NativeConvert.FromOctalPermissionString("0555"),
- st_nlink = 2,
- st_ctime = NativeConvert.ToTimeT(machine.CreationDate.ToUniversalTime()),
- st_mtime = NativeConvert.ToTimeT(machine.ModificationDate.ToUniversalTime())
- };
+ st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
+ st_nlink = 1,
+ st_ctime = NativeConvert.ToTimeT(disk.CreatedOn.ToUniversalTime()),
+ st_mtime = NativeConvert.ToTimeT(disk.UpdatedOn.ToUniversalTime()),
+ st_blksize = 512,
+ st_blocks = (long)(disk.Size / 512),
+ st_ino = disk.Id,
+ st_size = (long)disk.Size
+ };
- return 0;
- }
+ return 0;
+ }
- CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
+ CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
- if(file != null)
+ if(media == null) return Errno.ENOENT;
+
+ if(pieces.Length != 3) return Errno.ENOSYS;
+
+ stat = new Stat
+ {
+ st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
+ st_nlink = 1,
+ st_ctime = NativeConvert.ToTimeT(media.CreatedOn.ToUniversalTime()),
+ st_mtime = NativeConvert.ToTimeT(media.UpdatedOn.ToUniversalTime()),
+ st_blksize = 512,
+ st_blocks = (long)(media.Size / 512),
+ st_ino = media.Id,
+ st_size = (long)media.Size
+ };
+
+ return 0;
+ }
+
+ protected override Errno OnReadSymbolicLink(string link, out string target)
+ {
+ target = null;
+
+ return Errno.EOPNOTSUPP;
+ }
+
+ protected override Errno OnCreateSpecialFile(string file, FilePermissions perms, ulong dev) => Errno.EROFS;
+
+ protected override Errno OnCreateDirectory(string directory, FilePermissions mode) => Errno.EROFS;
+
+ protected override Errno OnRemoveFile(string file) => Errno.EROFS;
+
+ protected override Errno OnRemoveDirectory(string directory) => Errno.EROFS;
+
+ protected override Errno OnCreateSymbolicLink(string target, string link) => Errno.EROFS;
+
+ protected override Errno OnRenamePath(string oldPath, string newPath) => Errno.EROFS;
+
+ protected override Errno OnCreateHardLink(string oldPath, string link) => Errno.EROFS;
+
+ protected override Errno OnChangePathPermissions(string path, FilePermissions mode) => Errno.EROFS;
+
+ protected override Errno OnChangePathOwner(string path, long owner, long group) => Errno.EROFS;
+
+ protected override Errno OnTruncateFile(string file, long length) => Errno.EROFS;
+
+ protected override Errno OnChangePathTimes(string path, ref Utimbuf buf) => Errno.EROFS;
+
+ protected override Errno OnOpenHandle(string path, OpenedPathInfo info)
+ {
+ string[] pieces = _vfs.SplitPath(path);
+
+ if(pieces.Length == 0) return Errno.EISDIR;
+
+ long romSetId = _vfs.GetRomSetId(pieces[0]);
+
+ if(romSetId <= 0) return Errno.ENOENT;
+
+ RomSet romSet = _vfs.GetRomSet(romSetId);
+
+ if(romSet == null) return Errno.ENOENT;
+
+ if(pieces.Length == 1) return Errno.EISDIR;
+
+ CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+
+ if(machine == null) return Errno.ENOENT;
+
+ if(pieces.Length == 2) return Errno.EISDIR;
+
+ long handle = 0;
+ Stat stat;
+
+ CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
+
+ if(file != null)
+ {
+ if(pieces.Length > 3) return Errno.ENOSYS;
+
+ if(file.Sha384 == null) return Errno.ENOENT;
+
+ if(info.OpenAccess.HasFlag(OpenFlags.O_APPEND) ||
+ info.OpenAccess.HasFlag(OpenFlags.O_CREAT) ||
+ info.OpenAccess.HasFlag(OpenFlags.O_EXCL) ||
+ info.OpenAccess.HasFlag(OpenFlags.O_TRUNC))
+ return Errno.EROFS;
+
+ handle = _vfs.Open(file.Sha384, (long)file.Size);
+
+ stat = new Stat
{
- if(pieces.Length != 3)
- return Errno.ENOSYS;
-
- stat = new Stat
- {
- st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
- st_nlink = 1,
- st_ctime = NativeConvert.ToTimeT(file.CreatedOn.ToUniversalTime()),
- st_mtime = NativeConvert.ToTimeT(file.FileLastModification?.ToUniversalTime() ?? file.UpdatedOn.ToUniversalTime()),
- st_blksize = 512,
- st_blocks = (long)(file.Size / 512),
- st_ino = file.Id,
- st_size = (long)file.Size
- };
-
- return 0;
- }
-
+ st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
+ st_nlink = 1,
+ st_ctime = NativeConvert.ToTimeT(file.CreatedOn.ToUniversalTime()),
+ st_mtime =
+ NativeConvert.ToTimeT(file.FileLastModification?.ToUniversalTime() ??
+ file.UpdatedOn.ToUniversalTime()),
+ st_blksize = 512,
+ st_blocks = (long)(file.Size / 512),
+ st_ino = file.Id,
+ st_size = (long)file.Size
+ };
+ }
+ else
+ {
CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
if(disk != null)
{
- if(pieces.Length != 3)
- return Errno.ENOSYS;
+ if(pieces.Length > 3) return Errno.ENOSYS;
+
+ if(disk.Sha1 == null && disk.Md5 == null) return Errno.ENOENT;
+
+ if(info.OpenAccess.HasFlag(OpenFlags.O_APPEND) ||
+ info.OpenAccess.HasFlag(OpenFlags.O_CREAT) ||
+ info.OpenAccess.HasFlag(OpenFlags.O_EXCL) ||
+ info.OpenAccess.HasFlag(OpenFlags.O_TRUNC))
+ return Errno.EROFS;
+
+ handle = _vfs.OpenDisk(disk.Sha1, disk.Md5);
stat = new Stat
{
@@ -182,102 +314,16 @@ namespace RomRepoMgr.Core.Filesystem
st_ino = disk.Id,
st_size = (long)disk.Size
};
-
- return 0;
}
-
- CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
-
- if(media == null)
- return Errno.ENOENT;
-
- if(pieces.Length != 3)
- return Errno.ENOSYS;
-
- stat = new Stat
+ else
{
- st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
- st_nlink = 1,
- st_ctime = NativeConvert.ToTimeT(media.CreatedOn.ToUniversalTime()),
- st_mtime = NativeConvert.ToTimeT(media.UpdatedOn.ToUniversalTime()),
- st_blksize = 512,
- st_blocks = (long)(media.Size / 512),
- st_ino = media.Id,
- st_size = (long)media.Size
- };
+ CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
- return 0;
- }
+ if(media == null) return Errno.ENOENT;
- protected override Errno OnReadSymbolicLink(string link, out string target)
- {
- target = null;
+ if(pieces.Length > 3) return Errno.ENOSYS;
- return Errno.EOPNOTSUPP;
- }
-
- protected override Errno OnCreateSpecialFile(string file, FilePermissions perms, ulong dev) => Errno.EROFS;
-
- protected override Errno OnCreateDirectory(string directory, FilePermissions mode) => Errno.EROFS;
-
- protected override Errno OnRemoveFile(string file) => Errno.EROFS;
-
- protected override Errno OnRemoveDirectory(string directory) => Errno.EROFS;
-
- protected override Errno OnCreateSymbolicLink(string target, string link) => Errno.EROFS;
-
- protected override Errno OnRenamePath(string oldPath, string newPath) => Errno.EROFS;
-
- protected override Errno OnCreateHardLink(string oldPath, string link) => Errno.EROFS;
-
- protected override Errno OnChangePathPermissions(string path, FilePermissions mode) => Errno.EROFS;
-
- protected override Errno OnChangePathOwner(string path, long owner, long group) => Errno.EROFS;
-
- protected override Errno OnTruncateFile(string file, long length) => Errno.EROFS;
-
- protected override Errno OnChangePathTimes(string path, ref Utimbuf buf) => Errno.EROFS;
-
- protected override Errno OnOpenHandle(string path, OpenedPathInfo info)
- {
- string[] pieces = _vfs.SplitPath(path);
-
- if(pieces.Length == 0)
- return Errno.EISDIR;
-
- long romSetId = _vfs.GetRomSetId(pieces[0]);
-
- if(romSetId <= 0)
- return Errno.ENOENT;
-
- RomSet romSet = _vfs.GetRomSet(romSetId);
-
- if(romSet == null)
- return Errno.ENOENT;
-
- if(pieces.Length == 1)
- return Errno.EISDIR;
-
- CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
-
- if(machine == null)
- return Errno.ENOENT;
-
- if(pieces.Length == 2)
- return Errno.EISDIR;
-
- long handle = 0;
- Stat stat;
-
- CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
-
- if(file != null)
- {
- if(pieces.Length > 3)
- return Errno.ENOSYS;
-
- if(file.Sha384 == null)
- return Errno.ENOENT;
+ if(media.Sha256 == null && media.Sha1 == null && media.Md5 == null) return Errno.ENOENT;
if(info.OpenAccess.HasFlag(OpenFlags.O_APPEND) ||
info.OpenAccess.HasFlag(OpenFlags.O_CREAT) ||
@@ -285,672 +331,535 @@ namespace RomRepoMgr.Core.Filesystem
info.OpenAccess.HasFlag(OpenFlags.O_TRUNC))
return Errno.EROFS;
- handle = _vfs.Open(file.Sha384, (long)file.Size);
+ handle = _vfs.OpenMedia(media.Sha256, media.Sha1, media.Md5);
stat = new Stat
{
st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
st_nlink = 1,
- st_ctime = NativeConvert.ToTimeT(file.CreatedOn.ToUniversalTime()),
- st_mtime = NativeConvert.ToTimeT(file.FileLastModification?.ToUniversalTime() ?? file.UpdatedOn.ToUniversalTime()),
+ st_ctime = NativeConvert.ToTimeT(media.CreatedOn.ToUniversalTime()),
+ st_mtime = NativeConvert.ToTimeT(media.UpdatedOn.ToUniversalTime()),
st_blksize = 512,
- st_blocks = (long)(file.Size / 512),
- st_ino = file.Id,
- st_size = (long)file.Size
+ st_blocks = (long)(media.Size / 512),
+ st_ino = media.Id,
+ st_size = (long)media.Size
};
}
- else
- {
- CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
-
- if(disk != null)
- {
- if(pieces.Length > 3)
- return Errno.ENOSYS;
-
- if(disk.Sha1 == null &&
- disk.Md5 == null)
- return Errno.ENOENT;
-
- if(info.OpenAccess.HasFlag(OpenFlags.O_APPEND) ||
- info.OpenAccess.HasFlag(OpenFlags.O_CREAT) ||
- info.OpenAccess.HasFlag(OpenFlags.O_EXCL) ||
- info.OpenAccess.HasFlag(OpenFlags.O_TRUNC))
- return Errno.EROFS;
-
- handle = _vfs.OpenDisk(disk.Sha1, disk.Md5);
-
- stat = new Stat
- {
- st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
- st_nlink = 1,
- st_ctime = NativeConvert.ToTimeT(disk.CreatedOn.ToUniversalTime()),
- st_mtime = NativeConvert.ToTimeT(disk.UpdatedOn.ToUniversalTime()),
- st_blksize = 512,
- st_blocks = (long)(disk.Size / 512),
- st_ino = disk.Id,
- st_size = (long)disk.Size
- };
- }
- else
- {
- CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
-
- if(media == null)
- return Errno.ENOENT;
-
- if(pieces.Length > 3)
- return Errno.ENOSYS;
-
- if(media.Sha256 == null &&
- media.Sha1 == null &&
- media.Md5 == null)
- return Errno.ENOENT;
-
- if(info.OpenAccess.HasFlag(OpenFlags.O_APPEND) ||
- info.OpenAccess.HasFlag(OpenFlags.O_CREAT) ||
- info.OpenAccess.HasFlag(OpenFlags.O_EXCL) ||
- info.OpenAccess.HasFlag(OpenFlags.O_TRUNC))
- return Errno.EROFS;
-
- handle = _vfs.OpenMedia(media.Sha256, media.Sha1, media.Md5);
-
- stat = new Stat
- {
- st_mode = FilePermissions.S_IFREG | NativeConvert.FromOctalPermissionString("0444"),
- st_nlink = 1,
- st_ctime = NativeConvert.ToTimeT(media.CreatedOn.ToUniversalTime()),
- st_mtime = NativeConvert.ToTimeT(media.UpdatedOn.ToUniversalTime()),
- st_blksize = 512,
- st_blocks = (long)(media.Size / 512),
- st_ino = media.Id,
- st_size = (long)media.Size
- };
- }
- }
-
- if(handle <= 0)
- return Errno.ENOENT;
-
- info.Handle = new IntPtr(handle);
-
- _fileStatHandleCache[handle] = stat;
-
- return 0;
}
- protected override Errno OnReadHandle(string file, OpenedPathInfo info, byte[] buf, long offset,
- out int bytesWritten)
+ if(handle <= 0) return Errno.ENOENT;
+
+ info.Handle = new IntPtr(handle);
+
+ _fileStatHandleCache[handle] = stat;
+
+ return 0;
+ }
+
+ protected override Errno OnReadHandle(string file, OpenedPathInfo info, byte[] buf, long offset,
+ out int bytesWritten)
+ {
+ bytesWritten = _vfs.Read(info.Handle.ToInt64(), buf, offset);
+
+ if(bytesWritten >= 0) return 0;
+
+ bytesWritten = 0;
+
+ return Errno.EBADF;
+ }
+
+ protected override Errno OnWriteHandle(string file, OpenedPathInfo info, byte[] buf, long offset, out int bytesRead)
+ {
+ bytesRead = 0;
+
+ return Errno.EROFS;
+ }
+
+ protected override Errno OnGetFileSystemStatus(string path, out Statvfs buf)
+ {
+ _vfs.GetInfo(out ulong files, out ulong totalSize);
+
+ buf = new Statvfs
{
- bytesWritten = _vfs.Read(info.Handle.ToInt64(), buf, offset);
+ f_bsize = 512,
+ f_frsize = 512,
+ f_blocks = totalSize / 512,
+ f_bavail = 0,
+ f_files = files,
+ f_ffree = 0,
+ f_favail = 0,
+ f_fsid = 0xFFFFFFFF,
+ f_flag = 0,
+ f_namemax = 255
+ };
- if(bytesWritten >= 0)
- return 0;
+ return 0;
+ }
- bytesWritten = 0;
+ protected override Errno OnFlushHandle(string file, OpenedPathInfo info) => Errno.ENOSYS;
- return Errno.EBADF;
- }
+ protected override Errno OnReleaseHandle(string file, OpenedPathInfo info)
+ {
+ if(!_vfs.Close(info.Handle.ToInt64())) return Errno.EBADF;
- protected override Errno OnWriteHandle(string file, OpenedPathInfo info, byte[] buf, long offset,
- out int bytesRead)
+ _fileStatHandleCache.TryRemove(info.Handle.ToInt64(), out _);
+
+ return 0;
+ }
+
+ protected override Errno OnSynchronizeHandle(string file, OpenedPathInfo info, bool onlyUserData) =>
+ Errno.EOPNOTSUPP;
+
+ protected override Errno OnSetPathExtendedAttribute(string path, string name, byte[] value, XattrFlags flags)
+ {
+ if(_umountToken == null) return Errno.EROFS;
+
+ if(path != "/.fuse_umount") return Errno.EROFS;
+
+ if(name != _umountToken) return Errno.EROFS;
+
+ if(value?.Length != 0) return Errno.EROFS;
+
+ _umountToken = null;
+ Stop();
+
+ return 0;
+ }
+
+ protected override Errno OnGetPathExtendedAttribute(string path, string name, byte[] value, out int bytesWritten)
+ {
+ bytesWritten = 0;
+
+ string[] pieces = _vfs.SplitPath(path);
+
+ if(pieces.Length == 0) return Errno.ENODATA;
+
+ long romSetId = _vfs.GetRomSetId(pieces[0]);
+
+ if(romSetId <= 0) return Errno.ENOENT;
+
+ RomSet romSet = _vfs.GetRomSet(romSetId);
+
+ if(romSet == null) return Errno.ENOENT;
+
+ if(pieces.Length == 1) return Errno.ENODATA;
+
+ CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+
+ if(machine == null) return Errno.ENOENT;
+
+ if(pieces.Length == 2) return Errno.ENODATA;
+
+ CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
+
+ string hash = null;
+
+ if(file != null)
{
- bytesRead = 0;
+ if(pieces.Length > 3) return Errno.ENOSYS;
- return Errno.EROFS;
- }
-
- protected override Errno OnGetFileSystemStatus(string path, out Statvfs buf)
- {
- _vfs.GetInfo(out ulong files, out ulong totalSize);
-
- buf = new Statvfs
+ switch(name)
{
- f_bsize = 512,
- f_frsize = 512,
- f_blocks = totalSize / 512,
- f_bavail = 0,
- f_files = files,
- f_ffree = 0,
- f_favail = 0,
- f_fsid = 0xFFFFFFFF,
- f_flag = 0,
- f_namemax = 255
- };
+ case "user.crc32":
+ hash = file.Crc32;
- return 0;
- }
+ break;
+ case "user.md5":
+ hash = file.Md5;
- protected override Errno OnFlushHandle(string file, OpenedPathInfo info) => Errno.ENOSYS;
+ break;
+ case "user.sha1":
+ hash = file.Sha1;
- protected override Errno OnReleaseHandle(string file, OpenedPathInfo info)
- {
- if(!_vfs.Close(info.Handle.ToInt64()))
- return Errno.EBADF;
+ break;
+ case "user.sha256":
+ hash = file.Sha256;
- _fileStatHandleCache.TryRemove(info.Handle.ToInt64(), out _);
+ break;
+ case "user.sha384":
+ hash = file.Sha384;
- return 0;
- }
+ break;
+ case "user.sha512":
+ hash = file.Sha512;
- protected override Errno OnSynchronizeHandle(string file, OpenedPathInfo info, bool onlyUserData) =>
- Errno.EOPNOTSUPP;
-
- protected override Errno OnSetPathExtendedAttribute(string path, string name, byte[] value, XattrFlags flags)
- {
- if(_umountToken == null)
- return Errno.EROFS;
-
- if(path != "/.fuse_umount")
- return Errno.EROFS;
-
- if(name != _umountToken)
- return Errno.EROFS;
-
- if(value?.Length != 0)
- return Errno.EROFS;
-
- _umountToken = null;
- Stop();
-
- return 0;
- }
-
- protected override Errno OnGetPathExtendedAttribute(string path, string name, byte[] value,
- out int bytesWritten)
- {
- bytesWritten = 0;
-
- string[] pieces = _vfs.SplitPath(path);
-
- if(pieces.Length == 0)
- return Errno.ENODATA;
-
- long romSetId = _vfs.GetRomSetId(pieces[0]);
-
- if(romSetId <= 0)
- return Errno.ENOENT;
-
- RomSet romSet = _vfs.GetRomSet(romSetId);
-
- if(romSet == null)
- return Errno.ENOENT;
-
- if(pieces.Length == 1)
- return Errno.ENODATA;
-
- CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
-
- if(machine == null)
- return Errno.ENOENT;
-
- if(pieces.Length == 2)
- return Errno.ENODATA;
-
- CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
-
- string hash = null;
-
- if(file != null)
- {
- if(pieces.Length > 3)
- return Errno.ENOSYS;
-
- switch(name)
- {
- case "user.crc32":
- hash = file.Crc32;
-
- break;
- case "user.md5":
- hash = file.Md5;
-
- break;
- case "user.sha1":
- hash = file.Sha1;
-
- break;
- case "user.sha256":
- hash = file.Sha256;
-
- break;
- case "user.sha384":
- hash = file.Sha384;
-
- break;
- case "user.sha512":
- hash = file.Sha512;
-
- break;
- }
+ break;
}
- else
- {
- CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
-
- if(disk != null)
- {
- switch(name)
- {
- case "user.md5":
- hash = disk.Md5;
-
- break;
- case "user.sha1":
- hash = disk.Sha1;
-
- break;
- }
- }
- else
- {
- CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
-
- if(media == null)
- return Errno.ENOENT;
-
- switch(name)
- {
- case "user.md5":
- hash = media.Md5;
-
- break;
- case "user.sha1":
- hash = media.Sha1;
-
- break;
- case "user.sha256":
- hash = media.Sha256;
-
- break;
- case "user.spamsum":
- hash = media.SpamSum;
-
- break;
- }
- }
- }
-
- if(hash == null)
- return Errno.ENODATA;
-
- byte[] xattr = null;
-
- if(name == "user.spamsum")
- {
- xattr = Encoding.ASCII.GetBytes(hash);
- }
- else
- {
- xattr = new byte[hash.Length / 2];
-
- for(int i = 0; i < xattr.Length; i++)
- {
- if(hash[i * 2] >= 0x30 &&
- hash[i * 2] <= 0x39)
- xattr[i] = (byte)((hash[i * 2] - 0x30) * 0x10);
- else if(hash[i * 2] >= 0x41 &&
- hash[i * 2] <= 0x46)
- xattr[i] = (byte)((hash[i * 2] - 0x37) * 0x10);
- else if(hash[i * 2] >= 0x61 &&
- hash[i * 2] <= 0x66)
- xattr[i] = (byte)((hash[i * 2] - 0x57) * 0x10);
-
- if(hash[(i * 2) + 1] >= 0x30 &&
- hash[(i * 2) + 1] <= 0x39)
- xattr[i] += (byte)(hash[(i * 2) + 1] - 0x30);
- else if(hash[(i * 2) + 1] >= 0x41 &&
- hash[(i * 2) + 1] <= 0x46)
- xattr[i] += (byte)(hash[(i * 2) + 1] - 0x37);
- else if(hash[(i * 2) + 1] >= 0x61 &&
- hash[(i * 2) + 1] <= 0x66)
- xattr[i] += (byte)(hash[(i * 2) + 1] - 0x57);
- }
- }
-
- if(value == null)
- {
- bytesWritten = xattr.Length;
-
- return 0;
- }
-
- int maxSize = value.Length > xattr.Length ? xattr.Length : value.Length;
-
- Array.Copy(xattr, 0, value, 0, maxSize);
- bytesWritten = maxSize;
-
- return 0;
}
-
- protected override Errno OnListPathExtendedAttributes(string path, out string[] names)
+ else
{
- names = null;
-
- string[] pieces = _vfs.SplitPath(path);
-
- if(pieces.Length == 0)
- return 0;
-
- long romSetId = _vfs.GetRomSetId(pieces[0]);
-
- if(romSetId <= 0)
- return Errno.ENOENT;
-
- RomSet romSet = _vfs.GetRomSet(romSetId);
-
- if(romSet == null)
- return Errno.ENOENT;
-
- if(pieces.Length == 1)
- return 0;
-
- CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
-
- if(machine == null)
- return Errno.ENOENT;
-
- if(pieces.Length == 2)
- return 0;
-
- List xattrs = new List();
-
- CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
-
- if(file != null)
- {
- if(pieces.Length > 3)
- return Errno.ENOSYS;
-
- if(file.Crc32 != null)
- xattrs.Add("user.crc32");
-
- if(file.Md5 != null)
- xattrs.Add("user.md5");
-
- if(file.Sha1 != null)
- xattrs.Add("user.sha1");
-
- if(file.Sha256 != null)
- xattrs.Add("user.sha256");
-
- if(file.Sha384 != null)
- xattrs.Add("user.sha384");
-
- if(file.Sha512 != null)
- xattrs.Add("user.sha512");
-
- names = xattrs.ToArray();
-
- return 0;
- }
-
CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
if(disk != null)
{
- if(pieces.Length > 3)
- return Errno.ENOSYS;
+ switch(name)
+ {
+ case "user.md5":
+ hash = disk.Md5;
- if(disk.Md5 != null)
- xattrs.Add("user.md5");
+ break;
+ case "user.sha1":
+ hash = disk.Sha1;
- if(disk.Sha1 != null)
- xattrs.Add("user.sha1");
-
- names = xattrs.ToArray();
-
- return 0;
+ break;
+ }
}
+ else
+ {
+ CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
- CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
+ if(media == null) return Errno.ENOENT;
- if(media == null)
- return Errno.ENOENT;
+ switch(name)
+ {
+ case "user.md5":
+ hash = media.Md5;
- if(pieces.Length > 3)
- return Errno.ENOSYS;
+ break;
+ case "user.sha1":
+ hash = media.Sha1;
- if(media.Md5 != null)
- xattrs.Add("user.md5");
+ break;
+ case "user.sha256":
+ hash = media.Sha256;
- if(media.Sha1 != null)
- xattrs.Add("user.sha1");
+ break;
+ case "user.spamsum":
+ hash = media.SpamSum;
- if(media.Sha256 != null)
- xattrs.Add("user.sha256");
+ break;
+ }
+ }
+ }
- if(media.SpamSum != null)
- xattrs.Add("user.spamsum");
+ if(hash == null) return Errno.ENODATA;
+
+ byte[] xattr = null;
+
+ if(name == "user.spamsum")
+ xattr = Encoding.ASCII.GetBytes(hash);
+ else
+ {
+ xattr = new byte[hash.Length / 2];
+
+ for(var i = 0; i < xattr.Length; i++)
+ {
+ if(hash[i * 2] >= 0x30 && hash[i * 2] <= 0x39)
+ xattr[i] = (byte)((hash[i * 2] - 0x30) * 0x10);
+ else if(hash[i * 2] >= 0x41 && hash[i * 2] <= 0x46)
+ xattr[i] = (byte)((hash[i * 2] - 0x37) * 0x10);
+ else if(hash[i * 2] >= 0x61 && hash[i * 2] <= 0x66) xattr[i] = (byte)((hash[i * 2] - 0x57) * 0x10);
+
+ if(hash[i * 2 + 1] >= 0x30 && hash[i * 2 + 1] <= 0x39)
+ xattr[i] += (byte)(hash[i * 2 + 1] - 0x30);
+ else if(hash[i * 2 + 1] >= 0x41 && hash[i * 2 + 1] <= 0x46)
+ xattr[i] += (byte)(hash[i * 2 + 1] - 0x37);
+ else if(hash[i * 2 + 1] >= 0x61 && hash[i * 2 + 1] <= 0x66) xattr[i] += (byte)(hash[i * 2 + 1] - 0x57);
+ }
+ }
+
+ if(value == null)
+ {
+ bytesWritten = xattr.Length;
+
+ return 0;
+ }
+
+ int maxSize = value.Length > xattr.Length ? xattr.Length : value.Length;
+
+ Array.Copy(xattr, 0, value, 0, maxSize);
+ bytesWritten = maxSize;
+
+ return 0;
+ }
+
+ protected override Errno OnListPathExtendedAttributes(string path, out string[] names)
+ {
+ names = null;
+
+ string[] pieces = _vfs.SplitPath(path);
+
+ if(pieces.Length == 0) return 0;
+
+ long romSetId = _vfs.GetRomSetId(pieces[0]);
+
+ if(romSetId <= 0) return Errno.ENOENT;
+
+ RomSet romSet = _vfs.GetRomSet(romSetId);
+
+ if(romSet == null) return Errno.ENOENT;
+
+ if(pieces.Length == 1) return 0;
+
+ CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+
+ if(machine == null) return Errno.ENOENT;
+
+ if(pieces.Length == 2) return 0;
+
+ var xattrs = new List();
+
+ CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
+
+ if(file != null)
+ {
+ if(pieces.Length > 3) return Errno.ENOSYS;
+
+ if(file.Crc32 != null) xattrs.Add("user.crc32");
+
+ if(file.Md5 != null) xattrs.Add("user.md5");
+
+ if(file.Sha1 != null) xattrs.Add("user.sha1");
+
+ if(file.Sha256 != null) xattrs.Add("user.sha256");
+
+ if(file.Sha384 != null) xattrs.Add("user.sha384");
+
+ if(file.Sha512 != null) xattrs.Add("user.sha512");
names = xattrs.ToArray();
return 0;
}
- protected override Errno OnRemovePathExtendedAttribute(string path, string name) => Errno.EROFS;
+ CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
- protected override Errno OnOpenDirectory(string directory, OpenedPathInfo info)
+ if(disk != null)
{
- try
- {
- if(directory == "/")
- {
- List entries = new List
- {
- new DirectoryEntry("."),
- new DirectoryEntry("..")
- };
+ if(pieces.Length > 3) return Errno.ENOSYS;
- entries.AddRange(_vfs.GetRootEntries().Select(e => new DirectoryEntry(e)));
+ if(disk.Md5 != null) xattrs.Add("user.md5");
- _lastHandle++;
- info.Handle = new IntPtr(_lastHandle);
+ if(disk.Sha1 != null) xattrs.Add("user.sha1");
- _directoryCache[_lastHandle] = entries;
-
- return 0;
- }
-
- string[] pieces = directory.Split("/", StringSplitOptions.RemoveEmptyEntries);
-
- if(pieces.Length == 0)
- return Errno.ENOENT;
-
- long romSetId = _vfs.GetRomSetId(pieces[0]);
-
- if(romSetId <= 0)
- return Errno.ENOENT;
-
- RomSet romSet = _vfs.GetRomSet(romSetId);
-
- if(romSet == null)
- return Errno.ENOENT;
-
- ConcurrentDictionary machines = _vfs.GetMachinesFromRomSet(romSetId);
-
- if(pieces.Length == 1)
- {
- List entries = new List
- {
- new DirectoryEntry("."),
- new DirectoryEntry("..")
- };
-
- entries.AddRange(machines.Select(mach => new DirectoryEntry(mach.Key)));
-
- _lastHandle++;
- info.Handle = new IntPtr(_lastHandle);
-
- _directoryCache[_lastHandle] = entries;
-
- return 0;
- }
-
- CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
-
- if(machine == null)
- return Errno.ENOENT;
-
- ConcurrentDictionary cachedMachineFiles = _vfs.GetFilesFromMachine(machine.Id);
- ConcurrentDictionary cachedMachineDisks = _vfs.GetDisksFromMachine(machine.Id);
- ConcurrentDictionary cachedMachineMedias = _vfs.GetMediasFromMachine(machine.Id);
-
- if(pieces.Length == 2)
- {
- List entries = new List
- {
- new DirectoryEntry("."),
- new DirectoryEntry("..")
- };
-
- entries.AddRange(cachedMachineFiles.Select(file => new DirectoryEntry(file.Key)));
- entries.AddRange(cachedMachineDisks.Select(disk => new DirectoryEntry(disk.Key + ".chd")));
- entries.AddRange(cachedMachineMedias.Select(media => new DirectoryEntry(media.Key + ".aif")));
-
- _lastHandle++;
- info.Handle = new IntPtr(_lastHandle);
-
- _directoryCache[_lastHandle] = entries;
-
- return 0;
- }
-
- // TODO: DATs with subfolders as game name
- if(pieces.Length >= 3)
- return Errno.EISDIR;
-
- return Errno.ENOENT;
- }
- catch(Exception e)
- {
- Console.WriteLine(e);
-
- throw;
- }
- }
-
- protected override Errno OnReadDirectory(string directory, OpenedPathInfo info,
- out IEnumerable paths)
- {
- paths = null;
-
- if(!_directoryCache.TryGetValue(info.Handle.ToInt64(), out List cache))
- return Errno.EBADF;
-
- paths = cache;
+ names = xattrs.ToArray();
return 0;
}
- protected override Errno OnReleaseDirectory(string directory, OpenedPathInfo info)
+ CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
+
+ if(media == null) return Errno.ENOENT;
+
+ if(pieces.Length > 3) return Errno.ENOSYS;
+
+ if(media.Md5 != null) xattrs.Add("user.md5");
+
+ if(media.Sha1 != null) xattrs.Add("user.sha1");
+
+ if(media.Sha256 != null) xattrs.Add("user.sha256");
+
+ if(media.SpamSum != null) xattrs.Add("user.spamsum");
+
+ names = xattrs.ToArray();
+
+ return 0;
+ }
+
+ protected override Errno OnRemovePathExtendedAttribute(string path, string name) => Errno.EROFS;
+
+ protected override Errno OnOpenDirectory(string directory, OpenedPathInfo info)
+ {
+ try
{
- if(!_directoryCache.TryGetValue(info.Handle.ToInt64(), out _))
- return Errno.EBADF;
+ if(directory == "/")
+ {
+ var entries = new List
+ {
+ new("."),
+ new("..")
+ };
- _directoryCache.Remove(info.Handle.ToInt64(), out _);
+ entries.AddRange(_vfs.GetRootEntries().Select(e => new DirectoryEntry(e)));
- return 0;
- }
+ _lastHandle++;
+ info.Handle = new IntPtr(_lastHandle);
- protected override Errno OnSynchronizeDirectory(string directory, OpenedPathInfo info, bool onlyUserData) =>
- Errno.ENOSYS;
+ _directoryCache[_lastHandle] = entries;
- protected override Errno OnAccessPath(string path, AccessModes mode)
- {
- string[] pieces = _vfs.SplitPath(path);
+ return 0;
+ }
- if(pieces.Length == 0)
- return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
+ string[] pieces = directory.Split("/", StringSplitOptions.RemoveEmptyEntries);
+
+ if(pieces.Length == 0) return Errno.ENOENT;
long romSetId = _vfs.GetRomSetId(pieces[0]);
- if(romSetId <= 0)
- return Errno.ENOENT;
+ if(romSetId <= 0) return Errno.ENOENT;
RomSet romSet = _vfs.GetRomSet(romSetId);
- if(romSet == null)
- return Errno.ENOENT;
+ if(romSet == null) return Errno.ENOENT;
+
+ ConcurrentDictionary machines = _vfs.GetMachinesFromRomSet(romSetId);
if(pieces.Length == 1)
- return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
+ {
+ var entries = new List
+ {
+ new("."),
+ new("..")
+ };
+
+ entries.AddRange(machines.Select(mach => new DirectoryEntry(mach.Key)));
+
+ _lastHandle++;
+ info.Handle = new IntPtr(_lastHandle);
+
+ _directoryCache[_lastHandle] = entries;
+
+ return 0;
+ }
CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
- if(machine == null)
- return Errno.ENOENT;
+ if(machine == null) return Errno.ENOENT;
+
+ ConcurrentDictionary cachedMachineFiles = _vfs.GetFilesFromMachine(machine.Id);
+ ConcurrentDictionary cachedMachineDisks = _vfs.GetDisksFromMachine(machine.Id);
+ ConcurrentDictionary cachedMachineMedias = _vfs.GetMediasFromMachine(machine.Id);
if(pieces.Length == 2)
- return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
-
- CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
-
- if(file != null)
{
- if(pieces.Length > 3)
- return Errno.ENOSYS;
+ var entries = new List
+ {
+ new("."),
+ new("..")
+ };
- return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
+ entries.AddRange(cachedMachineFiles.Select(file => new DirectoryEntry(file.Key)));
+ entries.AddRange(cachedMachineDisks.Select(disk => new DirectoryEntry(disk.Key + ".chd")));
+ entries.AddRange(cachedMachineMedias.Select(media => new DirectoryEntry(media.Key + ".aif")));
+
+ _lastHandle++;
+ info.Handle = new IntPtr(_lastHandle);
+
+ _directoryCache[_lastHandle] = entries;
+
+ return 0;
}
- CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
+ // TODO: DATs with subfolders as game name
+ if(pieces.Length >= 3) return Errno.EISDIR;
- if(disk != null)
- {
- if(pieces.Length > 3)
- return Errno.ENOSYS;
+ return Errno.ENOENT;
+ }
+ catch(Exception e)
+ {
+ Console.WriteLine(e);
- return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
- }
+ throw;
+ }
+ }
- CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
+ protected override Errno OnReadDirectory(string directory, OpenedPathInfo info,
+ out IEnumerable paths)
+ {
+ paths = null;
- if(media == null)
- return Errno.ENOENT;
+ if(!_directoryCache.TryGetValue(info.Handle.ToInt64(), out List cache)) return Errno.EBADF;
- if(pieces.Length > 3)
- return Errno.ENOSYS;
+ paths = cache;
+
+ return 0;
+ }
+
+ protected override Errno OnReleaseDirectory(string directory, OpenedPathInfo info)
+ {
+ if(!_directoryCache.TryGetValue(info.Handle.ToInt64(), out _)) return Errno.EBADF;
+
+ _directoryCache.Remove(info.Handle.ToInt64(), out _);
+
+ return 0;
+ }
+
+ protected override Errno OnSynchronizeDirectory(string directory, OpenedPathInfo info, bool onlyUserData) =>
+ Errno.ENOSYS;
+
+ protected override Errno OnAccessPath(string path, AccessModes mode)
+ {
+ string[] pieces = _vfs.SplitPath(path);
+
+ if(pieces.Length == 0) return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
+
+ long romSetId = _vfs.GetRomSetId(pieces[0]);
+
+ if(romSetId <= 0) return Errno.ENOENT;
+
+ RomSet romSet = _vfs.GetRomSet(romSetId);
+
+ if(romSet == null) return Errno.ENOENT;
+
+ if(pieces.Length == 1) return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
+
+ CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+
+ if(machine == null) return Errno.ENOENT;
+
+ if(pieces.Length == 2) return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
+
+ CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
+
+ if(file != null)
+ {
+ if(pieces.Length > 3) return Errno.ENOSYS;
return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
}
- protected override Errno OnCreateHandle(string file, OpenedPathInfo info, FilePermissions mode) => Errno.EROFS;
+ CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
- protected override Errno OnTruncateHandle(string file, OpenedPathInfo info, long length) => Errno.EROFS;
-
- protected override Errno OnGetHandleStatus(string file, OpenedPathInfo info, out Stat buf)
+ if(disk != null)
{
- buf = new Stat();
+ if(pieces.Length > 3) return Errno.ENOSYS;
- if(!_fileStatHandleCache.TryGetValue(info.Handle.ToInt64(), out Stat fileStat))
- return Errno.EBADF;
-
- buf = fileStat;
-
- return 0;
+ return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
}
- protected override Errno OnLockHandle(string file, OpenedPathInfo info, FcntlCommand cmd, ref Flock @lock) =>
- Errno.EOPNOTSUPP;
+ CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
- protected override Errno OnMapPathLogicalToPhysicalIndex(string path, ulong logical, out ulong physical)
- {
- physical = ulong.MaxValue;
+ if(media == null) return Errno.ENOENT;
- return Errno.EOPNOTSUPP;
- }
+ if(pieces.Length > 3) return Errno.ENOSYS;
- [DllImport("libc", SetLastError = true)]
- static extern int setxattr(string path, string name, IntPtr value, long size, int flags);
+ return mode.HasFlag(AccessModes.W_OK) ? Errno.EROFS : 0;
+ }
- public void Umount()
- {
- var rnd = new Random();
- byte[] token = new byte[64];
- rnd.NextBytes(token);
- _umountToken = Base32.ToBase32String(token);
- setxattr(Path.Combine(MountPoint, ".fuse_umount"), _umountToken, IntPtr.Zero, 0, 0);
- }
+ protected override Errno OnCreateHandle(string file, OpenedPathInfo info, FilePermissions mode) => Errno.EROFS;
+
+ protected override Errno OnTruncateHandle(string file, OpenedPathInfo info, long length) => Errno.EROFS;
+
+ protected override Errno OnGetHandleStatus(string file, OpenedPathInfo info, out Stat buf)
+ {
+ buf = new Stat();
+
+ if(!_fileStatHandleCache.TryGetValue(info.Handle.ToInt64(), out Stat fileStat)) return Errno.EBADF;
+
+ buf = fileStat;
+
+ return 0;
+ }
+
+ protected override Errno OnLockHandle(string file, OpenedPathInfo info, FcntlCommand cmd, ref Flock @lock) =>
+ Errno.EOPNOTSUPP;
+
+ protected override Errno OnMapPathLogicalToPhysicalIndex(string path, ulong logical, out ulong physical)
+ {
+ physical = ulong.MaxValue;
+
+ return Errno.EOPNOTSUPP;
+ }
+
+ [DllImport("libc", SetLastError = true)]
+ static extern int setxattr(string path, string name, IntPtr value, long size, int flags);
+
+ public void Umount()
+ {
+ var rnd = new Random();
+ var token = new byte[64];
+ rnd.NextBytes(token);
+ _umountToken = Base32.ToBase32String(token);
+ setxattr(Path.Combine(MountPoint, ".fuse_umount"), _umountToken, IntPtr.Zero, 0, 0);
}
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Filesystem/Vfs.cs b/RomRepoMgr.Core/Filesystem/Vfs.cs
index db04249..a2dd94d 100644
--- a/RomRepoMgr.Core/Filesystem/Vfs.cs
+++ b/RomRepoMgr.Core/Filesystem/Vfs.cs
@@ -3,727 +3,698 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Runtime.InteropServices;
using System.Threading.Tasks;
using RomRepoMgr.Database;
using RomRepoMgr.Database.Models;
using SharpCompress.Compressors;
using SharpCompress.Compressors.LZMA;
-namespace RomRepoMgr.Core.Filesystem
+namespace RomRepoMgr.Core.Filesystem;
+
+// TODO: Last handle goes negative
+// TODO: Invalidate caches
+// TODO: Mount options
+// TODO: Do not show machines or romsets with no ROMs in repo
+public class Vfs : IDisposable
{
- // TODO: Last handle goes negative
- // TODO: Invalidate caches
- // TODO: Mount options
- // TODO: Do not show machines or romsets with no ROMs in repo
- public class Vfs : IDisposable
+ readonly ConcurrentDictionary> _machineDisksCache;
+ readonly ConcurrentDictionary> _machineFilesCache;
+ readonly ConcurrentDictionary> _machineMediasCache;
+ readonly ConcurrentDictionary> _machinesStatCache;
+ readonly ConcurrentDictionary _romSetsCache;
+ readonly ConcurrentDictionary _streamsCache;
+ Fuse _fuse;
+ long _lastHandle;
+ ConcurrentDictionary _rootDirectoryCache;
+ Winfsp _winfsp;
+
+ public Vfs()
{
- readonly ConcurrentDictionary> _machineDisksCache;
- readonly ConcurrentDictionary> _machineFilesCache;
- readonly ConcurrentDictionary> _machineMediasCache;
- readonly ConcurrentDictionary> _machinesStatCache;
- readonly ConcurrentDictionary _romSetsCache;
- readonly ConcurrentDictionary _streamsCache;
- Fuse _fuse;
- long _lastHandle;
- ConcurrentDictionary _rootDirectoryCache;
- Winfsp _winfsp;
+ _rootDirectoryCache = new ConcurrentDictionary();
+ _romSetsCache = new ConcurrentDictionary();
+ _machinesStatCache = new ConcurrentDictionary>();
+ _machineFilesCache = new ConcurrentDictionary>();
+ _machineDisksCache = new ConcurrentDictionary>();
+ _machineMediasCache = new ConcurrentDictionary>();
+ _streamsCache = new ConcurrentDictionary();
+ _lastHandle = 0;
+ }
- public Vfs()
+ public static bool IsAvailable => OperatingSystem.IsMacOS() || OperatingSystem.IsLinux()
+ ? Fuse.IsAvailable
+ : OperatingSystem.IsWindows() && Winfsp.IsAvailable;
+
+ public void Dispose() => Umount();
+
+ public event EventHandler Umounted;
+
+ public void MountTo(string mountPoint)
+ {
+ if((OperatingSystem.IsMacOS() || OperatingSystem.IsLinux()) && Fuse.IsAvailable)
{
- _rootDirectoryCache = new ConcurrentDictionary();
- _romSetsCache = new ConcurrentDictionary();
- _machinesStatCache = new ConcurrentDictionary>();
- _machineFilesCache = new ConcurrentDictionary>();
- _machineDisksCache = new ConcurrentDictionary>();
- _machineMediasCache = new ConcurrentDictionary>();
- _streamsCache = new ConcurrentDictionary();
- _lastHandle = 0;
+ _fuse = new Fuse(this)
+ {
+ MountPoint = mountPoint
+ };
+
+ Task.Run(() =>
+ {
+ _fuse.Start();
+
+ CleanUp();
+ });
+ }
+ else if(OperatingSystem.IsWindows() && Winfsp.IsAvailable)
+ {
+ _winfsp = new Winfsp(this);
+ bool ret = _winfsp.Mount(mountPoint);
+
+ if(ret) return;
+
+ _winfsp = null;
+ CleanUp();
+ }
+ else
+ CleanUp();
+ }
+
+ public void Umount()
+ {
+ if(OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
+ {
+ _fuse?.Umount();
+ _fuse = null;
}
- public static bool IsAvailable => OperatingSystem.IsMacOS() ||
- OperatingSystem.IsLinux() ? Fuse.IsAvailable
- : OperatingSystem.IsWindows() && Winfsp.IsAvailable;
-
- public void Dispose() => Umount();
-
- public event EventHandler Umounted;
-
- public void MountTo(string mountPoint)
+ if(OperatingSystem.IsWindows())
{
- if((OperatingSystem.IsMacOS() || OperatingSystem.IsLinux()) && Fuse.IsAvailable)
- {
- _fuse = new Fuse(this)
- {
- MountPoint = mountPoint
- };
-
- Task.Run(() =>
- {
- _fuse.Start();
-
- CleanUp();
- });
- }
- else if(OperatingSystem.IsWindows() && Winfsp.IsAvailable)
- {
- _winfsp = new Winfsp(this);
- bool ret = _winfsp.Mount(mountPoint);
-
- if(ret)
- return;
-
- _winfsp = null;
- CleanUp();
- }
- else
- CleanUp();
+ _winfsp?.Umount();
+ _winfsp = null;
}
- public void Umount()
+ CleanUp();
+ }
+
+ public void CleanUp()
+ {
+ foreach(KeyValuePair handle in _streamsCache) handle.Value.Close();
+
+ _streamsCache.Clear();
+ _lastHandle = 0;
+
+ Umounted?.Invoke(this, System.EventArgs.Empty);
+ }
+
+ internal void GetInfo(out ulong files, out ulong totalSize)
+ {
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+
+ totalSize = (ulong)(ctx.Files.Where(f => f.IsInRepo).Sum(f => (double)f.Size) +
+ ctx.Disks.Where(f => f.IsInRepo).Sum(f => (double)f.Size) +
+ ctx.Medias.Where(f => f.IsInRepo).Sum(f => (double)f.Size));
+
+ files = (ulong)(ctx.Files.Count(f => f.IsInRepo) +
+ ctx.Disks.Count(f => f.IsInRepo) +
+ ctx.Medias.Count(f => f.IsInRepo));
+ }
+
+ internal string[] SplitPath(string path) =>
+ path.Split(OperatingSystem.IsWindows() ? "\\" : "/", StringSplitOptions.RemoveEmptyEntries);
+
+ void FillRootDirectoryCache()
+ {
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+
+ var rootCache = new ConcurrentDictionary();
+
+ foreach(RomSet set in ctx.RomSets)
{
- if(OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
- {
- _fuse?.Umount();
- _fuse = null;
- }
+ string name;
if(OperatingSystem.IsWindows())
{
- _winfsp?.Umount();
- _winfsp = null;
- }
+ name = set.Name.Replace('/', '∕')
+ .Replace('<', '\uFF1C')
+ .Replace('>', '\uFF1E')
+ .Replace(':', '\uFF1A')
+ .Replace('"', '\u2033')
+ .Replace('\\', '\')
+ .Replace('|', '|')
+ .Replace('?', '?')
+ .Replace('*', '*');
- CleanUp();
- }
-
- public void CleanUp()
- {
- foreach(KeyValuePair handle in _streamsCache)
- handle.Value.Close();
-
- _streamsCache.Clear();
- _lastHandle = 0;
-
- Umounted?.Invoke(this, System.EventArgs.Empty);
- }
-
- internal void GetInfo(out ulong files, out ulong totalSize)
- {
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
-
- totalSize = (ulong)(ctx.Files.Where(f => f.IsInRepo).Sum(f => (double)f.Size) +
- ctx.Disks.Where(f => f.IsInRepo).Sum(f => (double)f.Size) +
- ctx.Medias.Where(f => f.IsInRepo).Sum(f => (double)f.Size));
-
- files = (ulong)(ctx.Files.Count(f => f.IsInRepo) + ctx.Disks.Count(f => f.IsInRepo) +
- ctx.Medias.Count(f => f.IsInRepo));
- }
-
- internal string[] SplitPath(string path) =>
- path.Split(OperatingSystem.IsWindows() ? "\\" : "/",
- StringSplitOptions.RemoveEmptyEntries);
-
- void FillRootDirectoryCache()
- {
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
-
- ConcurrentDictionary rootCache = new ConcurrentDictionary();
-
- foreach(RomSet set in ctx.RomSets)
- {
- string name;
-
- if(OperatingSystem.IsWindows())
+ if(rootCache.ContainsKey(name))
{
- name = set.Name.Replace('/', '∕').Replace('<', '\uFF1C').Replace('>', '\uFF1E').
- Replace(':', '\uFF1A').Replace('"', '\u2033').Replace('\\', '\').Replace('|', '|').
- Replace('?', '?').Replace('*', '*');
-
- if(rootCache.ContainsKey(name))
- name = Path.GetFileNameWithoutExtension(set.Filename)?.Replace('/', '∕').Replace('<', '\uFF1C').
- Replace('>', '\uFF1E').Replace(':', '\uFF1A').Replace('"', '\u2033').
- Replace('\\', '\').Replace('|', '|').Replace('?', '?').Replace('*', '*');
+ name = Path.GetFileNameWithoutExtension(set.Filename)
+ ?.Replace('/', '∕')
+ .Replace('<', '\uFF1C')
+ .Replace('>', '\uFF1E')
+ .Replace(':', '\uFF1A')
+ .Replace('"', '\u2033')
+ .Replace('\\', '\')
+ .Replace('|', '|')
+ .Replace('?', '?')
+ .Replace('*', '*');
}
- else
- {
- name = set.Name.Replace('/', '∕');
-
- if(rootCache.ContainsKey(name))
- name = Path.GetFileNameWithoutExtension(set.Filename)?.Replace('/', '∕');
- }
-
- if(name == null ||
- rootCache.ContainsKey(name))
- name = Path.GetFileNameWithoutExtension(set.Sha384);
-
- if(name == null)
- continue;
-
- rootCache[name] = set.Id;
- _romSetsCache[set.Id] = set;
}
-
- _rootDirectoryCache = rootCache;
- }
-
- internal long GetRomSetId(string name)
- {
- if(_rootDirectoryCache.Count == 0)
- FillRootDirectoryCache();
-
- if(!_rootDirectoryCache.TryGetValue(name, out long romSetId))
- return -1;
-
- return romSetId;
- }
-
- internal RomSet GetRomSet(long id)
- {
- if(_romSetsCache.TryGetValue(id, out RomSet romSet))
- return romSet;
-
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
-
- romSet = ctx.RomSets.Find(id);
-
- if(romSet == null)
- return null;
-
- _romSetsCache[id] = romSet;
-
- return romSet;
- }
-
- internal ConcurrentDictionary GetMachinesFromRomSet(long id)
- {
- _machinesStatCache.TryGetValue(id, out ConcurrentDictionary cachedMachines);
-
- if(cachedMachines != null)
- return cachedMachines;
-
- cachedMachines = new ConcurrentDictionary();
-
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
-
- foreach(Machine mach in ctx.Machines.Where(m => m.RomSet.Id == id))
+ else
{
- cachedMachines[mach.Name] = new CachedMachine
- {
- Id = mach.Id,
- CreationDate = mach.CreatedOn,
- ModificationDate = mach.UpdatedOn
- };
+ name = set.Name.Replace('/', '∕');
+
+ if(rootCache.ContainsKey(name))
+ name = Path.GetFileNameWithoutExtension(set.Filename)?.Replace('/', '∕');
}
- _machinesStatCache[id] = cachedMachines;
+ if(name == null || rootCache.ContainsKey(name)) name = Path.GetFileNameWithoutExtension(set.Sha384);
- return cachedMachines;
+ if(name == null) continue;
+
+ rootCache[name] = set.Id;
+ _romSetsCache[set.Id] = set;
}
- internal CachedMachine GetMachine(long romSetId, string name)
- {
- ConcurrentDictionary cachedMachines = GetMachinesFromRomSet(romSetId);
-
- if(cachedMachines == null ||
- !cachedMachines.TryGetValue(name, out CachedMachine machine))
- return null;
-
- return machine;
- }
-
- internal ConcurrentDictionary GetFilesFromMachine(ulong id)
- {
- _machineFilesCache.TryGetValue(id, out ConcurrentDictionary cachedMachineFiles);
-
- if(cachedMachineFiles != null)
- return cachedMachineFiles;
-
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
-
- cachedMachineFiles = new ConcurrentDictionary();
-
- foreach(FileByMachine machineFile in ctx.FilesByMachines.Where(fbm => fbm.Machine.Id == id &&
- fbm.File.IsInRepo))
- {
- var cachedFile = new CachedFile
- {
- Id = machineFile.File.Id,
- Crc32 = machineFile.File.Crc32,
- Md5 = machineFile.File.Md5,
- Sha1 = machineFile.File.Sha1,
- Sha256 = machineFile.File.Sha256,
- Sha384 = machineFile.File.Sha384,
- Sha512 = machineFile.File.Sha512,
- Size = machineFile.File.Size,
- CreatedOn = machineFile.File.CreatedOn,
- UpdatedOn = machineFile.File.UpdatedOn,
- FileLastModification = machineFile.FileLastModification
- };
-
- cachedMachineFiles[machineFile.Name] = cachedFile;
- }
-
- _machineFilesCache[id] = cachedMachineFiles;
-
- return cachedMachineFiles;
- }
-
- internal ConcurrentDictionary GetDisksFromMachine(ulong id)
- {
- _machineDisksCache.TryGetValue(id, out ConcurrentDictionary cachedMachineDisks);
-
- if(cachedMachineDisks != null)
- return cachedMachineDisks;
-
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
-
- cachedMachineDisks = new ConcurrentDictionary();
-
- foreach(DiskByMachine machineDisk in ctx.DisksByMachines.Where(dbm => dbm.Machine.Id == id &&
- dbm.Disk.IsInRepo &&
- dbm.Disk.Size != null))
- {
- var cachedDisk = new CachedDisk
- {
- Id = machineDisk.Disk.Id,
- Md5 = machineDisk.Disk.Md5,
- Sha1 = machineDisk.Disk.Sha1,
- Size = machineDisk.Disk.Size ?? 0,
- CreatedOn = machineDisk.Disk.CreatedOn,
- UpdatedOn = machineDisk.Disk.UpdatedOn
- };
-
- cachedMachineDisks[machineDisk.Name] = cachedDisk;
- }
-
- _machineDisksCache[id] = cachedMachineDisks;
-
- return cachedMachineDisks;
- }
-
- internal ConcurrentDictionary GetMediasFromMachine(ulong id)
- {
- _machineMediasCache.TryGetValue(id, out ConcurrentDictionary cachedMachineMedias);
-
- if(cachedMachineMedias != null)
- return cachedMachineMedias;
-
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
-
- cachedMachineMedias = new ConcurrentDictionary();
-
- foreach(MediaByMachine machineMedia in ctx.MediasByMachines.Where(mbm => mbm.Machine.Id == id &&
- mbm.Media.IsInRepo &&
- mbm.Media.Size != null))
- {
- var cachedDisk = new CachedMedia
- {
- Id = machineMedia.Media.Id,
- Md5 = machineMedia.Media.Md5,
- Sha1 = machineMedia.Media.Sha1,
- Sha256 = machineMedia.Media.Sha256,
- SpamSum = machineMedia.Media.SpamSum,
- Size = machineMedia.Media.Size ?? 0,
- CreatedOn = machineMedia.Media.CreatedOn,
- UpdatedOn = machineMedia.Media.UpdatedOn
- };
-
- cachedMachineMedias[machineMedia.Name] = cachedDisk;
- }
-
- _machineMediasCache[id] = cachedMachineMedias;
-
- return cachedMachineMedias;
- }
-
- internal CachedFile GetFile(ulong machineId, string name)
- {
- ConcurrentDictionary cachedFiles = GetFilesFromMachine(machineId);
-
- if(cachedFiles == null ||
- !cachedFiles.TryGetValue(name, out CachedFile file))
- return null;
-
- return file;
- }
-
- internal CachedDisk GetDisk(ulong machineId, string name)
- {
- if(name.EndsWith(".chd", StringComparison.OrdinalIgnoreCase))
- name = name.Substring(0, name.Length - 4);
-
- ConcurrentDictionary cachedDisks = GetDisksFromMachine(machineId);
-
- if(cachedDisks == null ||
- !cachedDisks.TryGetValue(name, out CachedDisk disk))
- return null;
-
- return disk;
- }
-
- internal CachedMedia GetMedia(ulong machineId, string name)
- {
- if(name.EndsWith(".aif", StringComparison.OrdinalIgnoreCase))
- name = name.Substring(0, name.Length - 4);
-
- ConcurrentDictionary cachedMedias = GetMediasFromMachine(machineId);
-
- if(cachedMedias == null ||
- !cachedMedias.TryGetValue(name, out CachedMedia media))
- return null;
-
- return media;
- }
-
- internal long Open(string sha384, long fileSize)
- {
- byte[] sha384Bytes = new byte[48];
-
- 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 sha384B32 = Base32.ToBase32String(sha384Bytes);
-
- string repoPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "files", sha384B32[0].ToString(),
- sha384B32[1].ToString(), sha384B32[2].ToString(), sha384B32[3].ToString(),
- sha384B32[4].ToString(), sha384B32 + ".lz");
-
- if(!File.Exists(repoPath))
- return -1;
-
- _lastHandle++;
- long handle = _lastHandle;
-
- _streamsCache[handle] =
- Stream.Synchronized(new ForcedSeekStream(fileSize,
- new FileStream(repoPath, FileMode.Open,
- FileAccess.Read),
- CompressionMode.Decompress));
-
- return handle;
- }
-
- internal int Read(long handle, byte[] buf, long offset)
- {
- if(!_streamsCache.TryGetValue(handle, out Stream stream))
- return -1;
-
- lock(stream)
- {
- stream.Position = offset;
-
- return stream.Read(buf, 0, buf.Length);
- }
- }
-
- internal bool Close(long handle)
- {
- if(!_streamsCache.TryGetValue(handle, out Stream stream))
- return false;
-
- stream.Close();
- _streamsCache.TryRemove(handle, out _);
-
- return true;
- }
-
- internal IEnumerable GetRootEntries()
- {
- if(_rootDirectoryCache.Count == 0)
- FillRootDirectoryCache();
-
- return _rootDirectoryCache.Keys.ToArray();
- }
-
- public long OpenDisk(string sha1, string md5)
- {
- if(sha1 == null &&
- md5 == null)
- return -1;
-
- string repoPath = null;
- string md5Path = null;
- string sha1Path = null;
-
- if(sha1 != null)
- {
- byte[] sha1Bytes = new byte[20];
-
- for(int i = 0; i < 20; i++)
- {
- if(sha1[i * 2] >= 0x30 &&
- sha1[i * 2] <= 0x39)
- sha1Bytes[i] = (byte)((sha1[i * 2] - 0x30) * 0x10);
- else if(sha1[i * 2] >= 0x41 &&
- sha1[i * 2] <= 0x46)
- sha1Bytes[i] = (byte)((sha1[i * 2] - 0x37) * 0x10);
- else if(sha1[i * 2] >= 0x61 &&
- sha1[i * 2] <= 0x66)
- sha1Bytes[i] = (byte)((sha1[i * 2] - 0x57) * 0x10);
-
- if(sha1[(i * 2) + 1] >= 0x30 &&
- sha1[(i * 2) + 1] <= 0x39)
- sha1Bytes[i] += (byte)(sha1[(i * 2) + 1] - 0x30);
- else if(sha1[(i * 2) + 1] >= 0x41 &&
- sha1[(i * 2) + 1] <= 0x46)
- sha1Bytes[i] += (byte)(sha1[(i * 2) + 1] - 0x37);
- else if(sha1[(i * 2) + 1] >= 0x61 &&
- sha1[(i * 2) + 1] <= 0x66)
- sha1Bytes[i] += (byte)(sha1[(i * 2) + 1] - 0x57);
- }
-
- string sha1B32 = Base32.ToBase32String(sha1Bytes);
-
- sha1Path = Path.Combine(Settings.Settings.Current.RepositoryPath, "chd", "sha1", sha1B32[0].ToString(),
- sha1B32[1].ToString(), sha1B32[2].ToString(), sha1B32[3].ToString(),
- sha1B32[4].ToString(), sha1B32 + ".chd");
- }
-
- if(md5 != null)
- {
- byte[] md5Bytes = new byte[16];
-
- for(int i = 0; i < 16; i++)
- {
- if(md5[i * 2] >= 0x30 &&
- md5[i * 2] <= 0x39)
- md5Bytes[i] = (byte)((md5[i * 2] - 0x30) * 0x10);
- else if(md5[i * 2] >= 0x41 &&
- md5[i * 2] <= 0x46)
- md5Bytes[i] = (byte)((md5[i * 2] - 0x37) * 0x10);
- else if(md5[i * 2] >= 0x61 &&
- md5[i * 2] <= 0x66)
- md5Bytes[i] = (byte)((md5[i * 2] - 0x57) * 0x10);
-
- if(md5[(i * 2) + 1] >= 0x30 &&
- md5[(i * 2) + 1] <= 0x39)
- md5Bytes[i] += (byte)(md5[(i * 2) + 1] - 0x30);
- else if(md5[(i * 2) + 1] >= 0x41 &&
- md5[(i * 2) + 1] <= 0x46)
- md5Bytes[i] += (byte)(md5[(i * 2) + 1] - 0x37);
- else if(md5[(i * 2) + 1] >= 0x61 &&
- md5[(i * 2) + 1] <= 0x66)
- md5Bytes[i] += (byte)(md5[(i * 2) + 1] - 0x57);
- }
-
- string md5B32 = Base32.ToBase32String(md5Bytes);
-
- md5Path = Path.Combine(Settings.Settings.Current.RepositoryPath, "chd", "md5", md5B32[0].ToString(),
- md5B32[1].ToString(), md5B32[2].ToString(), md5B32[3].ToString(),
- md5B32[4].ToString(), md5B32 + ".chd");
- }
-
- if(File.Exists(sha1Path))
- repoPath = sha1Path;
- else if(File.Exists(md5Path))
- repoPath = md5Path;
-
- if(repoPath == null)
- return -1;
-
- _lastHandle++;
- long handle = _lastHandle;
-
- _streamsCache[handle] = Stream.Synchronized(new FileStream(repoPath, FileMode.Open, FileAccess.Read));
-
- return handle;
- }
-
- public long OpenMedia(string sha256, string sha1, string md5)
- {
- if(sha256 == null &&
- sha1 == null &&
- md5 == null)
- return -1;
-
- string repoPath = null;
- string md5Path = null;
- string sha1Path = null;
- string sha256Path = null;
-
- if(sha256 != null)
- {
- byte[] sha256Bytes = new byte[32];
-
- for(int i = 0; i < 32; i++)
- {
- if(sha256[i * 2] >= 0x30 &&
- sha256[i * 2] <= 0x39)
- sha256Bytes[i] = (byte)((sha256[i * 2] - 0x30) * 0x10);
- else if(sha256[i * 2] >= 0x41 &&
- sha256[i * 2] <= 0x46)
- sha256Bytes[i] = (byte)((sha256[i * 2] - 0x37) * 0x10);
- else if(sha256[i * 2] >= 0x61 &&
- sha256[i * 2] <= 0x66)
- sha256Bytes[i] = (byte)((sha256[i * 2] - 0x57) * 0x10);
-
- if(sha256[(i * 2) + 1] >= 0x30 &&
- sha256[(i * 2) + 1] <= 0x39)
- sha256Bytes[i] += (byte)(sha256[(i * 2) + 1] - 0x30);
- else if(sha256[(i * 2) + 1] >= 0x41 &&
- sha256[(i * 2) + 1] <= 0x46)
- sha256Bytes[i] += (byte)(sha256[(i * 2) + 1] - 0x37);
- else if(sha256[(i * 2) + 1] >= 0x61 &&
- sha256[(i * 2) + 1] <= 0x66)
- sha256Bytes[i] += (byte)(sha256[(i * 2) + 1] - 0x57);
- }
-
- string sha256B32 = Base32.ToBase32String(sha256Bytes);
-
- sha256Path = Path.Combine(Settings.Settings.Current.RepositoryPath, "aaru", "sha256",
- sha256B32[0].ToString(), sha256B32[1].ToString(), sha256B32[2].ToString(),
- sha256B32[3].ToString(), sha256B32[4].ToString(), sha256B32 + ".aif");
- }
-
- if(sha1 != null)
- {
- byte[] sha1Bytes = new byte[20];
-
- for(int i = 0; i < 20; i++)
- {
- if(sha1[i * 2] >= 0x30 &&
- sha1[i * 2] <= 0x39)
- sha1Bytes[i] = (byte)((sha1[i * 2] - 0x30) * 0x10);
- else if(sha1[i * 2] >= 0x41 &&
- sha1[i * 2] <= 0x46)
- sha1Bytes[i] = (byte)((sha1[i * 2] - 0x37) * 0x10);
- else if(sha1[i * 2] >= 0x61 &&
- sha1[i * 2] <= 0x66)
- sha1Bytes[i] = (byte)((sha1[i * 2] - 0x57) * 0x10);
-
- if(sha1[(i * 2) + 1] >= 0x30 &&
- sha1[(i * 2) + 1] <= 0x39)
- sha1Bytes[i] += (byte)(sha1[(i * 2) + 1] - 0x30);
- else if(sha1[(i * 2) + 1] >= 0x41 &&
- sha1[(i * 2) + 1] <= 0x46)
- sha1Bytes[i] += (byte)(sha1[(i * 2) + 1] - 0x37);
- else if(sha1[(i * 2) + 1] >= 0x61 &&
- sha1[(i * 2) + 1] <= 0x66)
- sha1Bytes[i] += (byte)(sha1[(i * 2) + 1] - 0x57);
- }
-
- string sha1B32 = Base32.ToBase32String(sha1Bytes);
-
- sha1Path = Path.Combine(Settings.Settings.Current.RepositoryPath, "aaru", "sha1", sha1B32[0].ToString(),
- sha1B32[1].ToString(), sha1B32[2].ToString(), sha1B32[3].ToString(),
- sha1B32[4].ToString(), sha1B32 + ".aif");
- }
-
- if(md5 != null)
- {
- byte[] md5Bytes = new byte[16];
-
- for(int i = 0; i < 16; i++)
- {
- if(md5[i * 2] >= 0x30 &&
- md5[i * 2] <= 0x39)
- md5Bytes[i] = (byte)((md5[i * 2] - 0x30) * 0x10);
- else if(md5[i * 2] >= 0x41 &&
- md5[i * 2] <= 0x46)
- md5Bytes[i] = (byte)((md5[i * 2] - 0x37) * 0x10);
- else if(md5[i * 2] >= 0x61 &&
- md5[i * 2] <= 0x66)
- md5Bytes[i] = (byte)((md5[i * 2] - 0x57) * 0x10);
-
- if(md5[(i * 2) + 1] >= 0x30 &&
- md5[(i * 2) + 1] <= 0x39)
- md5Bytes[i] += (byte)(md5[(i * 2) + 1] - 0x30);
- else if(md5[(i * 2) + 1] >= 0x41 &&
- md5[(i * 2) + 1] <= 0x46)
- md5Bytes[i] += (byte)(md5[(i * 2) + 1] - 0x37);
- else if(md5[(i * 2) + 1] >= 0x61 &&
- md5[(i * 2) + 1] <= 0x66)
- md5Bytes[i] += (byte)(md5[(i * 2) + 1] - 0x57);
- }
-
- string md5B32 = Base32.ToBase32String(md5Bytes);
-
- md5Path = Path.Combine(Settings.Settings.Current.RepositoryPath, "aaru", "md5", md5B32[0].ToString(),
- md5B32[1].ToString(), md5B32[2].ToString(), md5B32[3].ToString(),
- md5B32[4].ToString(), md5B32 + ".aif");
- }
-
- if(File.Exists(sha256Path))
- repoPath = sha256Path;
- else if(File.Exists(sha1Path))
- repoPath = sha1Path;
- else if(File.Exists(md5Path))
- repoPath = md5Path;
-
- if(repoPath == null)
- return -1;
-
- _lastHandle++;
- long handle = _lastHandle;
-
- _streamsCache[handle] = Stream.Synchronized(new FileStream(repoPath, FileMode.Open, FileAccess.Read));
-
- return handle;
- }
+ _rootDirectoryCache = rootCache;
}
- internal sealed class CachedMachine
+ internal long GetRomSetId(string name)
{
- public ulong Id { get; set; }
- public DateTime CreationDate { get; set; }
- public DateTime ModificationDate { get; set; }
+ if(_rootDirectoryCache.Count == 0) FillRootDirectoryCache();
+
+ if(!_rootDirectoryCache.TryGetValue(name, out long romSetId)) return -1;
+
+ return romSetId;
}
- internal sealed class CachedFile
+ internal RomSet GetRomSet(long id)
{
- public ulong Id { get; set; }
- public ulong Size { get; set; }
- public string Crc32 { get; set; }
- public string Md5 { get; set; }
- public string Sha1 { get; set; }
- public string Sha256 { get; set; }
- public string Sha384 { get; set; }
- public string Sha512 { get; set; }
- public DateTime CreatedOn { get; set; }
- public DateTime UpdatedOn { get; set; }
- public DateTime? FileLastModification { get; set; }
+ if(_romSetsCache.TryGetValue(id, out RomSet romSet)) return romSet;
+
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+
+ romSet = ctx.RomSets.Find(id);
+
+ if(romSet == null) return null;
+
+ _romSetsCache[id] = romSet;
+
+ return romSet;
}
- internal sealed class CachedDisk
+ internal ConcurrentDictionary GetMachinesFromRomSet(long id)
{
- public ulong Id { get; set; }
- public ulong Size { get; set; }
- public string Md5 { get; set; }
- public string Sha1 { get; set; }
- public DateTime CreatedOn { get; set; }
- public DateTime UpdatedOn { get; set; }
+ _machinesStatCache.TryGetValue(id, out ConcurrentDictionary cachedMachines);
+
+ if(cachedMachines != null) return cachedMachines;
+
+ cachedMachines = new ConcurrentDictionary();
+
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+
+ foreach(Machine mach in ctx.Machines.Where(m => m.RomSet.Id == id))
+ {
+ cachedMachines[mach.Name] = new CachedMachine
+ {
+ Id = mach.Id,
+ CreationDate = mach.CreatedOn,
+ ModificationDate = mach.UpdatedOn
+ };
+ }
+
+ _machinesStatCache[id] = cachedMachines;
+
+ return cachedMachines;
}
- internal sealed class CachedMedia
+ internal CachedMachine GetMachine(long romSetId, string name)
{
- public ulong Id { get; set; }
- public ulong Size { get; set; }
- public string Md5 { get; set; }
- public string Sha1 { get; set; }
- public string Sha256 { get; set; }
- public string SpamSum { get; set; }
- public DateTime CreatedOn { get; set; }
- public DateTime UpdatedOn { get; set; }
+ ConcurrentDictionary cachedMachines = GetMachinesFromRomSet(romSetId);
+
+ if(cachedMachines == null || !cachedMachines.TryGetValue(name, out CachedMachine machine)) return null;
+
+ return machine;
}
+
+ internal ConcurrentDictionary GetFilesFromMachine(ulong id)
+ {
+ _machineFilesCache.TryGetValue(id, out ConcurrentDictionary cachedMachineFiles);
+
+ if(cachedMachineFiles != null) return cachedMachineFiles;
+
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+
+ cachedMachineFiles = new ConcurrentDictionary();
+
+ foreach(FileByMachine machineFile in
+ ctx.FilesByMachines.Where(fbm => fbm.Machine.Id == id && fbm.File.IsInRepo))
+ {
+ var cachedFile = new CachedFile
+ {
+ Id = machineFile.File.Id,
+ Crc32 = machineFile.File.Crc32,
+ Md5 = machineFile.File.Md5,
+ Sha1 = machineFile.File.Sha1,
+ Sha256 = machineFile.File.Sha256,
+ Sha384 = machineFile.File.Sha384,
+ Sha512 = machineFile.File.Sha512,
+ Size = machineFile.File.Size,
+ CreatedOn = machineFile.File.CreatedOn,
+ UpdatedOn = machineFile.File.UpdatedOn,
+ FileLastModification = machineFile.FileLastModification
+ };
+
+ cachedMachineFiles[machineFile.Name] = cachedFile;
+ }
+
+ _machineFilesCache[id] = cachedMachineFiles;
+
+ return cachedMachineFiles;
+ }
+
+ internal ConcurrentDictionary GetDisksFromMachine(ulong id)
+ {
+ _machineDisksCache.TryGetValue(id, out ConcurrentDictionary cachedMachineDisks);
+
+ if(cachedMachineDisks != null) return cachedMachineDisks;
+
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+
+ cachedMachineDisks = new ConcurrentDictionary();
+
+ foreach(DiskByMachine machineDisk in ctx.DisksByMachines.Where(dbm => dbm.Machine.Id == id &&
+ dbm.Disk.IsInRepo &&
+ dbm.Disk.Size != null))
+ {
+ var cachedDisk = new CachedDisk
+ {
+ Id = machineDisk.Disk.Id,
+ Md5 = machineDisk.Disk.Md5,
+ Sha1 = machineDisk.Disk.Sha1,
+ Size = machineDisk.Disk.Size ?? 0,
+ CreatedOn = machineDisk.Disk.CreatedOn,
+ UpdatedOn = machineDisk.Disk.UpdatedOn
+ };
+
+ cachedMachineDisks[machineDisk.Name] = cachedDisk;
+ }
+
+ _machineDisksCache[id] = cachedMachineDisks;
+
+ return cachedMachineDisks;
+ }
+
+ internal ConcurrentDictionary GetMediasFromMachine(ulong id)
+ {
+ _machineMediasCache.TryGetValue(id, out ConcurrentDictionary cachedMachineMedias);
+
+ if(cachedMachineMedias != null) return cachedMachineMedias;
+
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+
+ cachedMachineMedias = new ConcurrentDictionary();
+
+ foreach(MediaByMachine machineMedia in ctx.MediasByMachines.Where(mbm => mbm.Machine.Id == id &&
+ mbm.Media.IsInRepo &&
+ mbm.Media.Size != null))
+ {
+ var cachedDisk = new CachedMedia
+ {
+ Id = machineMedia.Media.Id,
+ Md5 = machineMedia.Media.Md5,
+ Sha1 = machineMedia.Media.Sha1,
+ Sha256 = machineMedia.Media.Sha256,
+ SpamSum = machineMedia.Media.SpamSum,
+ Size = machineMedia.Media.Size ?? 0,
+ CreatedOn = machineMedia.Media.CreatedOn,
+ UpdatedOn = machineMedia.Media.UpdatedOn
+ };
+
+ cachedMachineMedias[machineMedia.Name] = cachedDisk;
+ }
+
+ _machineMediasCache[id] = cachedMachineMedias;
+
+ return cachedMachineMedias;
+ }
+
+ internal CachedFile GetFile(ulong machineId, string name)
+ {
+ ConcurrentDictionary cachedFiles = GetFilesFromMachine(machineId);
+
+ if(cachedFiles == null || !cachedFiles.TryGetValue(name, out CachedFile file)) return null;
+
+ return file;
+ }
+
+ internal CachedDisk GetDisk(ulong machineId, string name)
+ {
+ if(name.EndsWith(".chd", StringComparison.OrdinalIgnoreCase)) name = name.Substring(0, name.Length - 4);
+
+ ConcurrentDictionary cachedDisks = GetDisksFromMachine(machineId);
+
+ if(cachedDisks == null || !cachedDisks.TryGetValue(name, out CachedDisk disk)) return null;
+
+ return disk;
+ }
+
+ internal CachedMedia GetMedia(ulong machineId, string name)
+ {
+ if(name.EndsWith(".aif", StringComparison.OrdinalIgnoreCase)) name = name.Substring(0, name.Length - 4);
+
+ ConcurrentDictionary cachedMedias = GetMediasFromMachine(machineId);
+
+ if(cachedMedias == null || !cachedMedias.TryGetValue(name, out CachedMedia media)) return null;
+
+ return media;
+ }
+
+ internal long Open(string sha384, long fileSize)
+ {
+ var sha384Bytes = new byte[48];
+
+ 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 sha384B32 = Base32.ToBase32String(sha384Bytes);
+
+ string repoPath = Path.Combine(Settings.Settings.Current.RepositoryPath,
+ "files",
+ sha384B32[0].ToString(),
+ sha384B32[1].ToString(),
+ sha384B32[2].ToString(),
+ sha384B32[3].ToString(),
+ sha384B32[4].ToString(),
+ sha384B32 + ".lz");
+
+ if(!File.Exists(repoPath)) return -1;
+
+ _lastHandle++;
+ long handle = _lastHandle;
+
+ _streamsCache[handle] =
+ Stream.Synchronized(new ForcedSeekStream(fileSize,
+ new FileStream(repoPath,
+ FileMode.Open,
+ FileAccess.Read),
+ CompressionMode.Decompress));
+
+ return handle;
+ }
+
+ internal int Read(long handle, byte[] buf, long offset)
+ {
+ if(!_streamsCache.TryGetValue(handle, out Stream stream)) return -1;
+
+ lock(stream)
+ {
+ stream.Position = offset;
+
+ return stream.Read(buf, 0, buf.Length);
+ }
+ }
+
+ internal bool Close(long handle)
+ {
+ if(!_streamsCache.TryGetValue(handle, out Stream stream)) return false;
+
+ stream.Close();
+ _streamsCache.TryRemove(handle, out _);
+
+ return true;
+ }
+
+ internal IEnumerable GetRootEntries()
+ {
+ if(_rootDirectoryCache.Count == 0) FillRootDirectoryCache();
+
+ return _rootDirectoryCache.Keys.ToArray();
+ }
+
+ public long OpenDisk(string sha1, string md5)
+ {
+ if(sha1 == null && md5 == null) return -1;
+
+ string repoPath = null;
+ string md5Path = null;
+ string sha1Path = null;
+
+ if(sha1 != null)
+ {
+ var sha1Bytes = new byte[20];
+
+ for(var i = 0; i < 20; i++)
+ {
+ if(sha1[i * 2] >= 0x30 && sha1[i * 2] <= 0x39)
+ sha1Bytes[i] = (byte)((sha1[i * 2] - 0x30) * 0x10);
+ else if(sha1[i * 2] >= 0x41 && sha1[i * 2] <= 0x46)
+ sha1Bytes[i] = (byte)((sha1[i * 2] - 0x37) * 0x10);
+ else if(sha1[i * 2] >= 0x61 && sha1[i * 2] <= 0x66) sha1Bytes[i] = (byte)((sha1[i * 2] - 0x57) * 0x10);
+
+ if(sha1[i * 2 + 1] >= 0x30 && sha1[i * 2 + 1] <= 0x39)
+ sha1Bytes[i] += (byte)(sha1[i * 2 + 1] - 0x30);
+ else if(sha1[i * 2 + 1] >= 0x41 && sha1[i * 2 + 1] <= 0x46)
+ sha1Bytes[i] += (byte)(sha1[i * 2 + 1] - 0x37);
+ else if(sha1[i * 2 + 1] >= 0x61 && sha1[i * 2 + 1] <= 0x66)
+ sha1Bytes[i] += (byte)(sha1[i * 2 + 1] - 0x57);
+ }
+
+ string sha1B32 = Base32.ToBase32String(sha1Bytes);
+
+ sha1Path = Path.Combine(Settings.Settings.Current.RepositoryPath,
+ "chd",
+ "sha1",
+ sha1B32[0].ToString(),
+ sha1B32[1].ToString(),
+ sha1B32[2].ToString(),
+ sha1B32[3].ToString(),
+ sha1B32[4].ToString(),
+ sha1B32 + ".chd");
+ }
+
+ if(md5 != null)
+ {
+ var md5Bytes = new byte[16];
+
+ for(var i = 0; i < 16; i++)
+ {
+ if(md5[i * 2] >= 0x30 && md5[i * 2] <= 0x39)
+ md5Bytes[i] = (byte)((md5[i * 2] - 0x30) * 0x10);
+ else if(md5[i * 2] >= 0x41 && md5[i * 2] <= 0x46)
+ md5Bytes[i] = (byte)((md5[i * 2] - 0x37) * 0x10);
+ else if(md5[i * 2] >= 0x61 && md5[i * 2] <= 0x66) md5Bytes[i] = (byte)((md5[i * 2] - 0x57) * 0x10);
+
+ if(md5[i * 2 + 1] >= 0x30 && md5[i * 2 + 1] <= 0x39)
+ md5Bytes[i] += (byte)(md5[i * 2 + 1] - 0x30);
+ else if(md5[i * 2 + 1] >= 0x41 && md5[i * 2 + 1] <= 0x46)
+ md5Bytes[i] += (byte)(md5[i * 2 + 1] - 0x37);
+ else if(md5[i * 2 + 1] >= 0x61 && md5[i * 2 + 1] <= 0x66) md5Bytes[i] += (byte)(md5[i * 2 + 1] - 0x57);
+ }
+
+ string md5B32 = Base32.ToBase32String(md5Bytes);
+
+ md5Path = Path.Combine(Settings.Settings.Current.RepositoryPath,
+ "chd",
+ "md5",
+ md5B32[0].ToString(),
+ md5B32[1].ToString(),
+ md5B32[2].ToString(),
+ md5B32[3].ToString(),
+ md5B32[4].ToString(),
+ md5B32 + ".chd");
+ }
+
+ if(File.Exists(sha1Path))
+ repoPath = sha1Path;
+ else if(File.Exists(md5Path)) repoPath = md5Path;
+
+ if(repoPath == null) return -1;
+
+ _lastHandle++;
+ long handle = _lastHandle;
+
+ _streamsCache[handle] = Stream.Synchronized(new FileStream(repoPath, FileMode.Open, FileAccess.Read));
+
+ return handle;
+ }
+
+ public long OpenMedia(string sha256, string sha1, string md5)
+ {
+ if(sha256 == null && sha1 == null && md5 == null) return -1;
+
+ string repoPath = null;
+ string md5Path = null;
+ string sha1Path = null;
+ string sha256Path = null;
+
+ if(sha256 != null)
+ {
+ var sha256Bytes = new byte[32];
+
+ for(var i = 0; i < 32; i++)
+ {
+ if(sha256[i * 2] >= 0x30 && sha256[i * 2] <= 0x39)
+ sha256Bytes[i] = (byte)((sha256[i * 2] - 0x30) * 0x10);
+ else if(sha256[i * 2] >= 0x41 && sha256[i * 2] <= 0x46)
+ sha256Bytes[i] = (byte)((sha256[i * 2] - 0x37) * 0x10);
+ else if(sha256[i * 2] >= 0x61 && sha256[i * 2] <= 0x66)
+ sha256Bytes[i] = (byte)((sha256[i * 2] - 0x57) * 0x10);
+
+ if(sha256[i * 2 + 1] >= 0x30 && sha256[i * 2 + 1] <= 0x39)
+ sha256Bytes[i] += (byte)(sha256[i * 2 + 1] - 0x30);
+ else if(sha256[i * 2 + 1] >= 0x41 && sha256[i * 2 + 1] <= 0x46)
+ sha256Bytes[i] += (byte)(sha256[i * 2 + 1] - 0x37);
+ else if(sha256[i * 2 + 1] >= 0x61 && sha256[i * 2 + 1] <= 0x66)
+ sha256Bytes[i] += (byte)(sha256[i * 2 + 1] - 0x57);
+ }
+
+ string sha256B32 = Base32.ToBase32String(sha256Bytes);
+
+ sha256Path = Path.Combine(Settings.Settings.Current.RepositoryPath,
+ "aaru",
+ "sha256",
+ sha256B32[0].ToString(),
+ sha256B32[1].ToString(),
+ sha256B32[2].ToString(),
+ sha256B32[3].ToString(),
+ sha256B32[4].ToString(),
+ sha256B32 + ".aif");
+ }
+
+ if(sha1 != null)
+ {
+ var sha1Bytes = new byte[20];
+
+ for(var i = 0; i < 20; i++)
+ {
+ if(sha1[i * 2] >= 0x30 && sha1[i * 2] <= 0x39)
+ sha1Bytes[i] = (byte)((sha1[i * 2] - 0x30) * 0x10);
+ else if(sha1[i * 2] >= 0x41 && sha1[i * 2] <= 0x46)
+ sha1Bytes[i] = (byte)((sha1[i * 2] - 0x37) * 0x10);
+ else if(sha1[i * 2] >= 0x61 && sha1[i * 2] <= 0x66) sha1Bytes[i] = (byte)((sha1[i * 2] - 0x57) * 0x10);
+
+ if(sha1[i * 2 + 1] >= 0x30 && sha1[i * 2 + 1] <= 0x39)
+ sha1Bytes[i] += (byte)(sha1[i * 2 + 1] - 0x30);
+ else if(sha1[i * 2 + 1] >= 0x41 && sha1[i * 2 + 1] <= 0x46)
+ sha1Bytes[i] += (byte)(sha1[i * 2 + 1] - 0x37);
+ else if(sha1[i * 2 + 1] >= 0x61 && sha1[i * 2 + 1] <= 0x66)
+ sha1Bytes[i] += (byte)(sha1[i * 2 + 1] - 0x57);
+ }
+
+ string sha1B32 = Base32.ToBase32String(sha1Bytes);
+
+ sha1Path = Path.Combine(Settings.Settings.Current.RepositoryPath,
+ "aaru",
+ "sha1",
+ sha1B32[0].ToString(),
+ sha1B32[1].ToString(),
+ sha1B32[2].ToString(),
+ sha1B32[3].ToString(),
+ sha1B32[4].ToString(),
+ sha1B32 + ".aif");
+ }
+
+ if(md5 != null)
+ {
+ var md5Bytes = new byte[16];
+
+ for(var i = 0; i < 16; i++)
+ {
+ if(md5[i * 2] >= 0x30 && md5[i * 2] <= 0x39)
+ md5Bytes[i] = (byte)((md5[i * 2] - 0x30) * 0x10);
+ else if(md5[i * 2] >= 0x41 && md5[i * 2] <= 0x46)
+ md5Bytes[i] = (byte)((md5[i * 2] - 0x37) * 0x10);
+ else if(md5[i * 2] >= 0x61 && md5[i * 2] <= 0x66) md5Bytes[i] = (byte)((md5[i * 2] - 0x57) * 0x10);
+
+ if(md5[i * 2 + 1] >= 0x30 && md5[i * 2 + 1] <= 0x39)
+ md5Bytes[i] += (byte)(md5[i * 2 + 1] - 0x30);
+ else if(md5[i * 2 + 1] >= 0x41 && md5[i * 2 + 1] <= 0x46)
+ md5Bytes[i] += (byte)(md5[i * 2 + 1] - 0x37);
+ else if(md5[i * 2 + 1] >= 0x61 && md5[i * 2 + 1] <= 0x66) md5Bytes[i] += (byte)(md5[i * 2 + 1] - 0x57);
+ }
+
+ string md5B32 = Base32.ToBase32String(md5Bytes);
+
+ md5Path = Path.Combine(Settings.Settings.Current.RepositoryPath,
+ "aaru",
+ "md5",
+ md5B32[0].ToString(),
+ md5B32[1].ToString(),
+ md5B32[2].ToString(),
+ md5B32[3].ToString(),
+ md5B32[4].ToString(),
+ md5B32 + ".aif");
+ }
+
+ if(File.Exists(sha256Path))
+ repoPath = sha256Path;
+ else if(File.Exists(sha1Path))
+ repoPath = sha1Path;
+ else if(File.Exists(md5Path)) repoPath = md5Path;
+
+ if(repoPath == null) return -1;
+
+ _lastHandle++;
+ long handle = _lastHandle;
+
+ _streamsCache[handle] = Stream.Synchronized(new FileStream(repoPath, FileMode.Open, FileAccess.Read));
+
+ return handle;
+ }
+}
+
+internal sealed class CachedMachine
+{
+ public ulong Id { get; set; }
+ public DateTime CreationDate { get; set; }
+ public DateTime ModificationDate { get; set; }
+}
+
+internal sealed class CachedFile
+{
+ public ulong Id { get; set; }
+ public ulong Size { get; set; }
+ public string Crc32 { get; set; }
+ public string Md5 { get; set; }
+ public string Sha1 { get; set; }
+ public string Sha256 { get; set; }
+ public string Sha384 { get; set; }
+ public string Sha512 { get; set; }
+ public DateTime CreatedOn { get; set; }
+ public DateTime UpdatedOn { get; set; }
+ public DateTime? FileLastModification { get; set; }
+}
+
+internal sealed class CachedDisk
+{
+ public ulong Id { get; set; }
+ public ulong Size { get; set; }
+ public string Md5 { get; set; }
+ public string Sha1 { get; set; }
+ public DateTime CreatedOn { get; set; }
+ public DateTime UpdatedOn { get; set; }
+}
+
+internal sealed class CachedMedia
+{
+ public ulong Id { get; set; }
+ public ulong Size { get; set; }
+ public string Md5 { get; set; }
+ public string Sha1 { get; set; }
+ public string Sha256 { get; set; }
+ public string SpamSum { get; set; }
+ public DateTime CreatedOn { get; set; }
+ public DateTime UpdatedOn { get; set; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Filesystem/Winfsp.cs b/RomRepoMgr.Core/Filesystem/Winfsp.cs
index b91b29f..f2271af 100644
--- a/RomRepoMgr.Core/Filesystem/Winfsp.cs
+++ b/RomRepoMgr.Core/Filesystem/Winfsp.cs
@@ -11,361 +11,262 @@ using Fsp.Interop;
using RomRepoMgr.Database.Models;
using FileInfo = Fsp.Interop.FileInfo;
-namespace RomRepoMgr.Core.Filesystem
+namespace RomRepoMgr.Core.Filesystem;
+
+[SupportedOSPlatform("windows")]
+public class Winfsp : FileSystemBase
{
- [SupportedOSPlatform("windows")]
- public class Winfsp : FileSystemBase
+ readonly Vfs _vfs;
+ FileSystemHost _host;
+
+ public Winfsp(Vfs vfs) => _vfs = vfs;
+
+ public static bool IsAvailable
{
- readonly Vfs _vfs;
- FileSystemHost _host;
-
- public Winfsp(Vfs vfs) => _vfs = vfs;
-
- public static bool IsAvailable
+ get
{
- get
+ try
{
- try
- {
- Version winfspVersion = FileSystemHost.Version();
+ Version winfspVersion = FileSystemHost.Version();
- if(winfspVersion == null)
- return false;
+ if(winfspVersion == null) return false;
- return winfspVersion.Major == 1 && winfspVersion.Minor >= 7;
- }
- catch(Exception)
- {
- return false;
- }
+ return winfspVersion.Major == 1 && winfspVersion.Minor >= 7;
+ }
+ catch(Exception)
+ {
+ return false;
}
}
+ }
- internal bool Mount(string mountPoint)
+ internal bool Mount(string mountPoint)
+ {
+ _host = new FileSystemHost(this)
{
- _host = new FileSystemHost(this)
+ SectorSize = 512,
+ CasePreservedNames = true,
+ CaseSensitiveSearch = true,
+ FileSystemName = "romrepomgrfs",
+ MaxComponentLength = 255,
+ UnicodeOnDisk = true,
+ SectorsPerAllocationUnit = 1
+ };
+
+ if(Directory.Exists(mountPoint)) Directory.Delete(mountPoint);
+
+ int ret = _host.Mount(mountPoint);
+
+ if(ret == STATUS_SUCCESS) return true;
+
+ _host = null;
+
+ return false;
+ }
+
+ internal void Umount() => _host?.Unmount();
+
+ public override int SetVolumeLabel(string volumeLabel, out VolumeInfo volumeInfo)
+ {
+ volumeInfo = default(VolumeInfo);
+
+ return STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ public override int Create(string fileName, uint createOptions, uint grantedAccess, uint fileAttributes,
+ byte[] securityDescriptor, ulong allocationSize, out object fileNode,
+ out object fileDesc, out FileInfo fileInfo, out string normalizedName)
+ {
+ fileNode = default(object);
+ fileDesc = default(object);
+ fileInfo = default(FileInfo);
+ normalizedName = default(string);
+
+ return STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ public override int Overwrite(object fileNode, object fileDesc, uint fileAttributes, bool replaceFileAttributes,
+ ulong allocationSize, out FileInfo fileInfo)
+ {
+ fileInfo = default(FileInfo);
+
+ return STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ public override int Write(object fileNode, object fileDesc, IntPtr buffer, ulong offset, uint length,
+ bool writeToEndOfFile, bool constrainedIo, out uint bytesTransferred,
+ out FileInfo fileInfo)
+ {
+ bytesTransferred = default(uint);
+ fileInfo = default(FileInfo);
+
+ return STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ public override int SetBasicInfo(object fileNode, object fileDesc, uint fileAttributes, ulong creationTime,
+ ulong lastAccessTime, ulong lastWriteTime, ulong changeTime, out FileInfo fileInfo)
+ {
+ fileInfo = default(FileInfo);
+
+ return STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ public override int SetFileSize(object fileNode, object fileDesc, ulong newSize, bool setAllocationSize,
+ out FileInfo fileInfo)
+ {
+ fileInfo = default(FileInfo);
+
+ return STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ public override int CanDelete(object fileNode, object fileDesc, string fileName) => STATUS_MEDIA_WRITE_PROTECTED;
+
+ public override int Rename(object fileNode, object fileDesc, string fileName, string newFileName,
+ bool replaceIfExists) => STATUS_MEDIA_WRITE_PROTECTED;
+
+ public override int GetVolumeInfo(out VolumeInfo volumeInfo)
+ {
+ volumeInfo = new VolumeInfo();
+
+ _vfs.GetInfo(out _, out ulong totalSize);
+
+ volumeInfo.FreeSize = 0;
+ volumeInfo.TotalSize = totalSize;
+
+ return STATUS_SUCCESS;
+ }
+
+ public override int Open(string fileName, uint createOptions, uint grantedAccess, out object fileNode,
+ out object fileDesc, out FileInfo fileInfo, out string normalizedName)
+ {
+ fileNode = default(object);
+ fileDesc = default(object);
+ fileInfo = default(FileInfo);
+ normalizedName = default(string);
+
+ string[] pieces = _vfs.SplitPath(fileName);
+
+ // Root directory
+ if(pieces.Length == 0)
+ {
+ fileInfo = new FileInfo
{
- SectorSize = 512,
- CasePreservedNames = true,
- CaseSensitiveSearch = true,
- FileSystemName = "romrepomgrfs",
- MaxComponentLength = 255,
- UnicodeOnDisk = true,
- SectorsPerAllocationUnit = 1
+ CreationTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
+ FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
+ LastWriteTime = (ulong)DateTime.UtcNow.ToFileTimeUtc()
};
- if(Directory.Exists(mountPoint))
- Directory.Delete(mountPoint);
+ normalizedName = "";
- int ret = _host.Mount(mountPoint);
-
- if(ret == STATUS_SUCCESS)
- return true;
-
- _host = null;
-
- return false;
- }
-
- internal void Umount() => _host?.Unmount();
-
- public override int SetVolumeLabel(string volumeLabel, out VolumeInfo volumeInfo)
- {
- volumeInfo = default;
-
- return STATUS_MEDIA_WRITE_PROTECTED;
- }
-
- public override int Create(string fileName, uint createOptions, uint grantedAccess, uint fileAttributes,
- byte[] securityDescriptor, ulong allocationSize, out object fileNode,
- out object fileDesc, out FileInfo fileInfo, out string normalizedName)
- {
- fileNode = default;
- fileDesc = default;
- fileInfo = default;
- normalizedName = default;
-
- return STATUS_MEDIA_WRITE_PROTECTED;
- }
-
- public override int Overwrite(object fileNode, object fileDesc, uint fileAttributes, bool replaceFileAttributes,
- ulong allocationSize, out FileInfo fileInfo)
- {
- fileInfo = default;
-
- return STATUS_MEDIA_WRITE_PROTECTED;
- }
-
- public override int Write(object fileNode, object fileDesc, IntPtr buffer, ulong offset, uint length,
- bool writeToEndOfFile, bool constrainedIo, out uint bytesTransferred,
- out FileInfo fileInfo)
- {
- bytesTransferred = default;
- fileInfo = default;
-
- return STATUS_MEDIA_WRITE_PROTECTED;
- }
-
- public override int SetBasicInfo(object fileNode, object fileDesc, uint fileAttributes, ulong creationTime,
- ulong lastAccessTime, ulong lastWriteTime, ulong changeTime,
- out FileInfo fileInfo)
- {
- fileInfo = default;
-
- return STATUS_MEDIA_WRITE_PROTECTED;
- }
-
- public override int SetFileSize(object fileNode, object fileDesc, ulong newSize, bool setAllocationSize,
- out FileInfo fileInfo)
- {
- fileInfo = default;
-
- return STATUS_MEDIA_WRITE_PROTECTED;
- }
-
- public override int CanDelete(object fileNode, object fileDesc, string fileName) =>
- STATUS_MEDIA_WRITE_PROTECTED;
-
- public override int Rename(object fileNode, object fileDesc, string fileName, string newFileName,
- bool replaceIfExists) => STATUS_MEDIA_WRITE_PROTECTED;
-
- public override int GetVolumeInfo(out VolumeInfo volumeInfo)
- {
- volumeInfo = new VolumeInfo();
-
- _vfs.GetInfo(out _, out ulong totalSize);
-
- volumeInfo.FreeSize = 0;
- volumeInfo.TotalSize = totalSize;
+ fileNode = new FileNode
+ {
+ FileName = normalizedName,
+ IsDirectory = true,
+ Info = fileInfo,
+ Path = fileName
+ };
return STATUS_SUCCESS;
}
- public override int Open(string fileName, uint createOptions, uint grantedAccess, out object fileNode,
- out object fileDesc, out FileInfo fileInfo, out string normalizedName)
+ long romSetId = _vfs.GetRomSetId(pieces[0]);
+
+ if(romSetId <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ RomSet romSet = _vfs.GetRomSet(romSetId);
+
+ if(romSet == null) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ // ROM Set
+ if(pieces.Length == 1)
{
- fileNode = default;
- fileDesc = default;
- fileInfo = default;
- normalizedName = default;
-
- string[] pieces = _vfs.SplitPath(fileName);
-
- // Root directory
- if(pieces.Length == 0)
+ fileInfo = new FileInfo
{
- fileInfo = new FileInfo
+ CreationTime = (ulong)romSet.CreatedOn.ToUniversalTime().ToFileTimeUtc(),
+ FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
+ LastWriteTime = (ulong)romSet.UpdatedOn.ToUniversalTime().ToFileTimeUtc()
+ };
+
+ normalizedName = Path.GetFileName(fileName);
+
+ fileNode = new FileNode
+ {
+ FileName = normalizedName,
+ IsDirectory = true,
+ Info = fileInfo,
+ Path = fileName,
+ RomSetId = romSet.Id,
+ ParentInfo = new FileInfo
{
CreationTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
LastWriteTime = (ulong)DateTime.UtcNow.ToFileTimeUtc()
- };
+ }
+ };
- normalizedName = "";
+ return STATUS_SUCCESS;
+ }
- fileNode = new FileNode
- {
- FileName = normalizedName,
- IsDirectory = true,
- Info = fileInfo,
- Path = fileName
- };
+ CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
- return STATUS_SUCCESS;
- }
+ if(machine == null) return STATUS_OBJECT_NAME_NOT_FOUND;
- long romSetId = _vfs.GetRomSetId(pieces[0]);
-
- if(romSetId <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- RomSet romSet = _vfs.GetRomSet(romSetId);
-
- if(romSet == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- // ROM Set
- if(pieces.Length == 1)
+ // Machine
+ if(pieces.Length == 2)
+ {
+ fileInfo = new FileInfo
{
- fileInfo = new FileInfo
+ CreationTime = (ulong)machine.CreationDate.ToUniversalTime().ToFileTimeUtc(),
+ FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
+ LastWriteTime = (ulong)machine.ModificationDate.ToUniversalTime().ToFileTimeUtc()
+ };
+
+ normalizedName = Path.GetFileName(fileName);
+
+ fileNode = new FileNode
+ {
+ FileName = normalizedName,
+ IsDirectory = true,
+ Info = fileInfo,
+ Path = fileName,
+ MachineId = machine.Id,
+ ParentInfo = new FileInfo
{
CreationTime = (ulong)romSet.CreatedOn.ToUniversalTime().ToFileTimeUtc(),
FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
LastWriteTime = (ulong)romSet.UpdatedOn.ToUniversalTime().ToFileTimeUtc()
- };
+ }
+ };
- normalizedName = Path.GetFileName(fileName);
+ return STATUS_SUCCESS;
+ }
- fileNode = new FileNode
- {
- FileName = normalizedName,
- IsDirectory = true,
- Info = fileInfo,
- Path = fileName,
- RomSetId = romSet.Id,
- ParentInfo = new FileInfo
- {
- CreationTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
- FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
- LastWriteTime = (ulong)DateTime.UtcNow.ToFileTimeUtc()
- }
- };
+ long handle = 0;
+ CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
- return STATUS_SUCCESS;
- }
+ if(file != null)
+ {
+ if(pieces.Length > 3) return STATUS_INVALID_DEVICE_REQUEST;
- CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+ if(file.Sha384 == null) return STATUS_OBJECT_NAME_NOT_FOUND;
- if(machine == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ handle = _vfs.Open(file.Sha384, (long)file.Size);
- // Machine
- if(pieces.Length == 2)
- {
- fileInfo = new FileInfo
- {
- CreationTime = (ulong)machine.CreationDate.ToUniversalTime().ToFileTimeUtc(),
- FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
- LastWriteTime = (ulong)machine.ModificationDate.ToUniversalTime().ToFileTimeUtc()
- };
-
- normalizedName = Path.GetFileName(fileName);
-
- fileNode = new FileNode
- {
- FileName = normalizedName,
- IsDirectory = true,
- Info = fileInfo,
- Path = fileName,
- MachineId = machine.Id,
- ParentInfo = new FileInfo
- {
- CreationTime = (ulong)romSet.CreatedOn.ToUniversalTime().ToFileTimeUtc(),
- FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
- LastWriteTime = (ulong)romSet.UpdatedOn.ToUniversalTime().ToFileTimeUtc()
- }
- };
-
- return STATUS_SUCCESS;
- }
-
- long handle = 0;
- CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
-
- if(file != null)
- {
- if(pieces.Length > 3)
- return STATUS_INVALID_DEVICE_REQUEST;
-
- if(file.Sha384 == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- handle = _vfs.Open(file.Sha384, (long)file.Size);
-
- if(handle <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- normalizedName = Path.GetFileName(fileName);
-
- // TODO: Real allocation size
- fileInfo = new FileInfo
- {
- ChangeTime = (ulong)file.UpdatedOn.ToFileTimeUtc(),
- AllocationSize = (file.Size + 511) / 512,
- FileSize = file.Size,
- CreationTime = (ulong)file.CreatedOn.ToFileTimeUtc(),
- FileAttributes =
- (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
- IndexNumber = file.Id,
- LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
- LastWriteTime = (ulong)(file.FileLastModification?.ToFileTimeUtc() ?? file.UpdatedOn.ToFileTimeUtc())
- };
-
- fileNode = new FileNode
- {
- FileName = normalizedName,
- Info = fileInfo,
- Path = fileName,
- Handle = handle
- };
-
- return STATUS_SUCCESS;
- }
-
- CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
-
- if(disk != null)
- {
- if(pieces.Length > 3)
- return STATUS_INVALID_DEVICE_REQUEST;
-
- if(disk.Sha1 == null &&
- disk.Md5 == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- handle = _vfs.OpenDisk(disk.Sha1, disk.Md5);
-
- if(handle <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- normalizedName = Path.GetFileName(fileName);
-
- // TODO: Real allocation size
- fileInfo = new FileInfo
- {
- ChangeTime = (ulong)disk.UpdatedOn.ToFileTimeUtc(),
- AllocationSize = (disk.Size + 511) / 512,
- FileSize = disk.Size,
- CreationTime = (ulong)disk.CreatedOn.ToFileTimeUtc(),
- FileAttributes =
- (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
- IndexNumber = disk.Id,
- LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
- LastWriteTime = (ulong)disk.UpdatedOn.ToFileTimeUtc()
- };
-
- fileNode = new FileNode
- {
- FileName = normalizedName,
- Info = fileInfo,
- Path = fileName,
- Handle = handle
- };
-
- return STATUS_SUCCESS;
- }
-
- CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
-
- if(media == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- if(pieces.Length > 3)
- return STATUS_INVALID_DEVICE_REQUEST;
-
- if(media.Sha256 == null &&
- media.Sha1 == null &&
- media.Md5 == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- handle = _vfs.OpenMedia(media.Sha256, media.Sha1, media.Md5);
-
- if(handle <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ if(handle <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
normalizedName = Path.GetFileName(fileName);
// TODO: Real allocation size
fileInfo = new FileInfo
{
- ChangeTime = (ulong)media.UpdatedOn.ToFileTimeUtc(),
- AllocationSize = (media.Size + 511) / 512,
- FileSize = media.Size,
- CreationTime = (ulong)media.CreatedOn.ToFileTimeUtc(),
+ ChangeTime = (ulong)file.UpdatedOn.ToFileTimeUtc(),
+ AllocationSize = (file.Size + 511) / 512,
+ FileSize = file.Size,
+ CreationTime = (ulong)file.CreatedOn.ToFileTimeUtc(),
FileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
- IndexNumber = media.Id,
+ IndexNumber = file.Id,
LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
- LastWriteTime = (ulong)media.UpdatedOn.ToFileTimeUtc()
+ LastWriteTime = (ulong)(file.FileLastModification?.ToFileTimeUtc() ?? file.UpdatedOn.ToFileTimeUtc())
};
fileNode = new FileNode
@@ -379,365 +280,411 @@ namespace RomRepoMgr.Core.Filesystem
return STATUS_SUCCESS;
}
- public override void Close(object fileNode, object fileDesc)
+ CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
+
+ if(disk != null)
{
- if(!(fileNode is FileNode node))
- return;
+ if(pieces.Length > 3) return STATUS_INVALID_DEVICE_REQUEST;
- if(node.Handle <= 0)
- return;
+ if(disk.Sha1 == null && disk.Md5 == null) return STATUS_OBJECT_NAME_NOT_FOUND;
- _vfs.Close(node.Handle);
- }
+ handle = _vfs.OpenDisk(disk.Sha1, disk.Md5);
- public override int Read(object fileNode, object fileDesc, IntPtr buffer, ulong offset, uint length,
- out uint bytesTransferred)
- {
- bytesTransferred = 0;
+ if(handle <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
- if(!(fileNode is FileNode node) ||
- node.Handle <= 0)
- return STATUS_INVALID_HANDLE;
+ normalizedName = Path.GetFileName(fileName);
- byte[] buf = new byte[length];
-
- int ret = _vfs.Read(node.Handle, buf, (long)offset);
-
- if(ret < 0)
- return STATUS_INVALID_HANDLE;
-
- Marshal.Copy(buf, 0, buffer, ret);
-
- bytesTransferred = (uint)ret;
-
- return STATUS_SUCCESS;
- }
-
- public override int GetFileInfo(object fileNode, object fileDesc, out FileInfo fileInfo)
- {
- fileInfo = default;
-
- if(!(fileNode is FileNode node))
- return STATUS_INVALID_HANDLE;
-
- fileInfo = node.Info;
-
- return STATUS_SUCCESS;
- }
-
- public override bool ReadDirectoryEntry(object fileNode, object fileDesc, string pattern, string marker,
- ref object context, out string fileName, out FileInfo fileInfo)
- {
- fileName = default;
- fileInfo = default;
-
- if(!(fileNode is FileNode node) ||
- !node.IsDirectory)
- return false;
-
- if(!(context is IEnumerator enumerator))
+ // TODO: Real allocation size
+ fileInfo = new FileInfo
{
- if(node.MachineId > 0)
+ ChangeTime = (ulong)disk.UpdatedOn.ToFileTimeUtc(),
+ AllocationSize = (disk.Size + 511) / 512,
+ FileSize = disk.Size,
+ CreationTime = (ulong)disk.CreatedOn.ToFileTimeUtc(),
+ FileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
+ IndexNumber = disk.Id,
+ LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
+ LastWriteTime = (ulong)disk.UpdatedOn.ToFileTimeUtc()
+ };
+
+ fileNode = new FileNode
+ {
+ FileName = normalizedName,
+ Info = fileInfo,
+ Path = fileName,
+ Handle = handle
+ };
+
+ return STATUS_SUCCESS;
+ }
+
+ CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
+
+ if(media == null) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ if(pieces.Length > 3) return STATUS_INVALID_DEVICE_REQUEST;
+
+ if(media.Sha256 == null && media.Sha1 == null && media.Md5 == null) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ handle = _vfs.OpenMedia(media.Sha256, media.Sha1, media.Md5);
+
+ if(handle <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ normalizedName = Path.GetFileName(fileName);
+
+ // TODO: Real allocation size
+ fileInfo = new FileInfo
+ {
+ ChangeTime = (ulong)media.UpdatedOn.ToFileTimeUtc(),
+ AllocationSize = (media.Size + 511) / 512,
+ FileSize = media.Size,
+ CreationTime = (ulong)media.CreatedOn.ToFileTimeUtc(),
+ FileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
+ IndexNumber = media.Id,
+ LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
+ LastWriteTime = (ulong)media.UpdatedOn.ToFileTimeUtc()
+ };
+
+ fileNode = new FileNode
+ {
+ FileName = normalizedName,
+ Info = fileInfo,
+ Path = fileName,
+ Handle = handle
+ };
+
+ return STATUS_SUCCESS;
+ }
+
+ public override void Close(object fileNode, object fileDesc)
+ {
+ if(!(fileNode is FileNode node)) return;
+
+ if(node.Handle <= 0) return;
+
+ _vfs.Close(node.Handle);
+ }
+
+ public override int Read(object fileNode, object fileDesc, IntPtr buffer, ulong offset, uint length,
+ out uint bytesTransferred)
+ {
+ bytesTransferred = 0;
+
+ if(!(fileNode is FileNode node) || node.Handle <= 0) return STATUS_INVALID_HANDLE;
+
+ var buf = new byte[length];
+
+ int ret = _vfs.Read(node.Handle, buf, (long)offset);
+
+ if(ret < 0) return STATUS_INVALID_HANDLE;
+
+ Marshal.Copy(buf, 0, buffer, ret);
+
+ bytesTransferred = (uint)ret;
+
+ return STATUS_SUCCESS;
+ }
+
+ public override int GetFileInfo(object fileNode, object fileDesc, out FileInfo fileInfo)
+ {
+ fileInfo = default(FileInfo);
+
+ if(!(fileNode is FileNode node)) return STATUS_INVALID_HANDLE;
+
+ fileInfo = node.Info;
+
+ return STATUS_SUCCESS;
+ }
+
+ public override bool ReadDirectoryEntry(object fileNode, object fileDesc, string pattern, string marker,
+ ref object context, out string fileName, out FileInfo fileInfo)
+ {
+ fileName = default(string);
+ fileInfo = default(FileInfo);
+
+ if(!(fileNode is FileNode node) || !node.IsDirectory) return false;
+
+ if(!(context is IEnumerator enumerator))
+ {
+ if(node.MachineId > 0)
+ {
+ ConcurrentDictionary cachedMachineFiles = _vfs.GetFilesFromMachine(node.MachineId);
+
+ ConcurrentDictionary cachedMachineDisks = _vfs.GetDisksFromMachine(node.MachineId);
+
+ ConcurrentDictionary cachedMachineMedias =
+ _vfs.GetMediasFromMachine(node.MachineId);
+
+ node.Children = new List
{
- ConcurrentDictionary cachedMachineFiles =
- _vfs.GetFilesFromMachine(node.MachineId);
-
- ConcurrentDictionary cachedMachineDisks =
- _vfs.GetDisksFromMachine(node.MachineId);
-
- ConcurrentDictionary cachedMachineMedias =
- _vfs.GetMediasFromMachine(node.MachineId);
-
- node.Children = new List
+ new()
{
- new FileEntry
- {
- FileName = ".",
- Info = node.Info
- },
- new FileEntry
- {
- FileName = "..",
- Info = node.ParentInfo
- }
- };
-
- node.Children.AddRange(cachedMachineFiles.Select(file => new FileEntry
+ FileName = ".",
+ Info = node.Info
+ },
+ new()
{
- FileName = file.Key,
- Info = new FileInfo
- {
- ChangeTime = (ulong)file.Value.UpdatedOn.ToFileTimeUtc(),
- AllocationSize = (file.Value.Size + 511) / 512,
- FileSize = file.Value.Size,
- CreationTime = (ulong)file.Value.CreatedOn.ToFileTimeUtc(),
- FileAttributes =
- (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
- IndexNumber = file.Value.Id,
- LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
- LastWriteTime = (ulong)(file.Value.FileLastModification?.ToFileTimeUtc() ?? file.Value.UpdatedOn.ToFileTimeUtc())
- }
- }));
+ FileName = "..",
+ Info = node.ParentInfo
+ }
+ };
- node.Children.AddRange(cachedMachineDisks.Select(disk => new FileEntry
- {
- FileName = disk.Key + ".chd",
- Info = new FileInfo
- {
- ChangeTime = (ulong)disk.Value.UpdatedOn.ToFileTimeUtc(),
- AllocationSize = (disk.Value.Size + 511) / 512,
- FileSize = disk.Value.Size,
- CreationTime = (ulong)disk.Value.CreatedOn.ToFileTimeUtc(),
- FileAttributes =
- (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
- IndexNumber = disk.Value.Id,
- LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
- LastWriteTime = (ulong)disk.Value.UpdatedOn.ToFileTimeUtc()
- }
- }));
-
- node.Children.AddRange(cachedMachineMedias.Select(media => new FileEntry
- {
- FileName = media.Key + ".aif",
- Info = new FileInfo
- {
- ChangeTime = (ulong)media.Value.UpdatedOn.ToFileTimeUtc(),
- AllocationSize = (media.Value.Size + 511) / 512,
- FileSize = media.Value.Size,
- CreationTime = (ulong)media.Value.CreatedOn.ToFileTimeUtc(),
- FileAttributes =
- (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
- IndexNumber = media.Value.Id,
- LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
- LastWriteTime = (ulong)media.Value.UpdatedOn.ToFileTimeUtc()
- }
- }));
- }
- else if(node.RomSetId > 0)
+ node.Children.AddRange(cachedMachineFiles.Select(file => new FileEntry
{
- ConcurrentDictionary machines = _vfs.GetMachinesFromRomSet(node.RomSetId);
-
- node.Children = new List
+ FileName = file.Key,
+ Info = new FileInfo
{
- new FileEntry
- {
- FileName = ".",
- Info = node.Info
- },
- new FileEntry
- {
- FileName = "..",
- Info = node.ParentInfo
- }
- };
+ ChangeTime = (ulong)file.Value.UpdatedOn.ToFileTimeUtc(),
+ AllocationSize = (file.Value.Size + 511) / 512,
+ FileSize = file.Value.Size,
+ CreationTime = (ulong)file.Value.CreatedOn.ToFileTimeUtc(),
+ FileAttributes =
+ (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
+ IndexNumber = file.Value.Id,
+ LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
+ LastWriteTime = (ulong)(file.Value.FileLastModification?.ToFileTimeUtc() ??
+ file.Value.UpdatedOn.ToFileTimeUtc())
+ }
+ }));
- node.Children.AddRange(machines.Select(machine => new FileEntry
- {
- FileName = machine.Key,
- Info = new FileInfo
- {
- CreationTime = (ulong)machine.Value.CreationDate.ToUniversalTime().ToFileTimeUtc(),
- FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
- LastWriteTime = (ulong)machine.Value.ModificationDate.ToUniversalTime().ToFileTimeUtc()
- }
- }));
- }
- else
+ node.Children.AddRange(cachedMachineDisks.Select(disk => new FileEntry
{
- node.Children = new List();
-
- node.Children.AddRange(_vfs.GetRootEntries().Select(e => new FileEntry
+ FileName = disk.Key + ".chd",
+ Info = new FileInfo
{
- FileName = e,
- IsRomSet = true
- }));
- }
+ ChangeTime = (ulong)disk.Value.UpdatedOn.ToFileTimeUtc(),
+ AllocationSize = (disk.Value.Size + 511) / 512,
+ FileSize = disk.Value.Size,
+ CreationTime = (ulong)disk.Value.CreatedOn.ToFileTimeUtc(),
+ FileAttributes =
+ (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
+ IndexNumber = disk.Value.Id,
+ LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
+ LastWriteTime = (ulong)disk.Value.UpdatedOn.ToFileTimeUtc()
+ }
+ }));
- if(marker != null)
+ node.Children.AddRange(cachedMachineMedias.Select(media => new FileEntry
{
- int idx = node.Children.FindIndex(f => f.FileName == marker);
-
- if(idx >= 0)
- node.Children.RemoveRange(0, idx + 1);
- }
-
- context = enumerator = node.Children.GetEnumerator();
+ FileName = media.Key + ".aif",
+ Info = new FileInfo
+ {
+ ChangeTime = (ulong)media.Value.UpdatedOn.ToFileTimeUtc(),
+ AllocationSize = (media.Value.Size + 511) / 512,
+ FileSize = media.Value.Size,
+ CreationTime = (ulong)media.Value.CreatedOn.ToFileTimeUtc(),
+ FileAttributes =
+ (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly),
+ IndexNumber = media.Value.Id,
+ LastAccessTime = (ulong)DateTime.UtcNow.ToFileTimeUtc(),
+ LastWriteTime = (ulong)media.Value.UpdatedOn.ToFileTimeUtc()
+ }
+ }));
}
-
- while(enumerator.MoveNext())
+ else if(node.RomSetId > 0)
{
- FileEntry entry = enumerator.Current;
+ ConcurrentDictionary machines = _vfs.GetMachinesFromRomSet(node.RomSetId);
- if(entry is null)
- continue;
-
- if(entry.IsRomSet)
+ node.Children = new List
{
- long romSetId = _vfs.GetRomSetId(entry.FileName);
-
- if(romSetId <= 0)
- continue;
-
- RomSet romSet = _vfs.GetRomSet(romSetId);
-
- if(romSet is null)
- continue;
-
- entry.Info = new FileInfo
+ new()
{
- CreationTime = (ulong)romSet.CreatedOn.ToUniversalTime().ToFileTimeUtc(),
+ FileName = ".",
+ Info = node.Info
+ },
+ new()
+ {
+ FileName = "..",
+ Info = node.ParentInfo
+ }
+ };
+
+ node.Children.AddRange(machines.Select(machine => new FileEntry
+ {
+ FileName = machine.Key,
+ Info = new FileInfo
+ {
+ CreationTime = (ulong)machine.Value.CreationDate.ToUniversalTime().ToFileTimeUtc(),
FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
- LastWriteTime = (ulong)romSet.UpdatedOn.ToUniversalTime().ToFileTimeUtc()
- };
- }
+ LastWriteTime = (ulong)machine.Value.ModificationDate.ToUniversalTime().ToFileTimeUtc()
+ }
+ }));
+ }
+ else
+ {
+ node.Children = new List();
- fileName = entry.FileName;
- fileInfo = entry.Info;
-
- return true;
+ node.Children.AddRange(_vfs.GetRootEntries()
+ .Select(e => new FileEntry
+ {
+ FileName = e,
+ IsRomSet = true
+ }));
}
- return false;
+ if(marker != null)
+ {
+ int idx = node.Children.FindIndex(f => f.FileName == marker);
+
+ if(idx >= 0) node.Children.RemoveRange(0, idx + 1);
+ }
+
+ context = enumerator = node.Children.GetEnumerator();
}
- public override int GetSecurityByName(string fileName, out uint fileAttributes, ref byte[] securityDescriptor)
+ while(enumerator.MoveNext())
{
- fileAttributes = 0;
+ FileEntry entry = enumerator.Current;
- string[] pieces = _vfs.SplitPath(fileName);
+ if(entry is null) continue;
- // Root directory
- if(pieces.Length == 0)
+ if(entry.IsRomSet)
{
- fileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed);
+ long romSetId = _vfs.GetRomSetId(entry.FileName);
- if(securityDescriptor == null)
- return STATUS_SUCCESS;
+ if(romSetId <= 0) continue;
- string rootSddl = "O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)";
+ RomSet romSet = _vfs.GetRomSet(romSetId);
- var rootSecurityDescriptor = new RawSecurityDescriptor(rootSddl);
- byte[] fileSecurity = new byte[rootSecurityDescriptor.BinaryLength];
- rootSecurityDescriptor.GetBinaryForm(fileSecurity, 0);
- securityDescriptor = fileSecurity;
+ if(romSet is null) continue;
- return STATUS_SUCCESS;
+ entry.Info = new FileInfo
+ {
+ CreationTime = (ulong)romSet.CreatedOn.ToUniversalTime().ToFileTimeUtc(),
+ FileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed),
+ LastWriteTime = (ulong)romSet.UpdatedOn.ToUniversalTime().ToFileTimeUtc()
+ };
}
- long romSetId = _vfs.GetRomSetId(pieces[0]);
+ fileName = entry.FileName;
+ fileInfo = entry.Info;
- if(romSetId <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ return true;
+ }
- RomSet romSet = _vfs.GetRomSet(romSetId);
+ return false;
+ }
- if(romSet == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ public override int GetSecurityByName(string fileName, out uint fileAttributes, ref byte[] securityDescriptor)
+ {
+ fileAttributes = 0;
- // ROM Set
- if(pieces.Length == 1)
- {
- fileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed);
+ string[] pieces = _vfs.SplitPath(fileName);
- return STATUS_SUCCESS;
- }
+ // Root directory
+ if(pieces.Length == 0)
+ {
+ fileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed);
- CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
+ if(securityDescriptor == null) return STATUS_SUCCESS;
- if(machine == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ var rootSddl = "O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)";
- // Machine
- if(pieces.Length == 2)
- {
- fileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed);
+ var rootSecurityDescriptor = new RawSecurityDescriptor(rootSddl);
+ var fileSecurity = new byte[rootSecurityDescriptor.BinaryLength];
+ rootSecurityDescriptor.GetBinaryForm(fileSecurity, 0);
+ securityDescriptor = fileSecurity;
- return STATUS_SUCCESS;
- }
+ return STATUS_SUCCESS;
+ }
- long handle = 0;
- CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
+ long romSetId = _vfs.GetRomSetId(pieces[0]);
- if(file != null)
- {
- if(pieces.Length > 3)
- return STATUS_INVALID_DEVICE_REQUEST;
+ if(romSetId <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
- if(file.Sha384 == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ RomSet romSet = _vfs.GetRomSet(romSetId);
- handle = _vfs.Open(file.Sha384, (long)file.Size);
+ if(romSet == null) return STATUS_OBJECT_NAME_NOT_FOUND;
- if(handle <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ // ROM Set
+ if(pieces.Length == 1)
+ {
+ fileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed);
- fileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly);
+ return STATUS_SUCCESS;
+ }
- return STATUS_SUCCESS;
- }
+ CachedMachine machine = _vfs.GetMachine(romSetId, pieces[1]);
- CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
+ if(machine == null) return STATUS_OBJECT_NAME_NOT_FOUND;
- if(disk != null)
- {
- if(pieces.Length > 3)
- return STATUS_INVALID_DEVICE_REQUEST;
+ // Machine
+ if(pieces.Length == 2)
+ {
+ fileAttributes = (uint)(FileAttributes.Directory | FileAttributes.Compressed);
- if(disk.Sha1 == null &&
- disk.Md5 == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ return STATUS_SUCCESS;
+ }
- handle = _vfs.OpenDisk(disk.Sha1, disk.Md5);
+ long handle = 0;
+ CachedFile file = _vfs.GetFile(machine.Id, pieces[2]);
- if(handle <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ if(file != null)
+ {
+ if(pieces.Length > 3) return STATUS_INVALID_DEVICE_REQUEST;
- fileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly);
+ if(file.Sha384 == null) return STATUS_OBJECT_NAME_NOT_FOUND;
- return STATUS_SUCCESS;
- }
+ handle = _vfs.Open(file.Sha384, (long)file.Size);
- CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
-
- if(media == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- if(pieces.Length > 3)
- return STATUS_INVALID_DEVICE_REQUEST;
-
- if(media.Sha256 == null &&
- media.Sha1 == null &&
- media.Md5 == null)
- return STATUS_OBJECT_NAME_NOT_FOUND;
-
- handle = _vfs.OpenMedia(media.Sha256, media.Sha1, media.Md5);
-
- if(handle <= 0)
- return STATUS_OBJECT_NAME_NOT_FOUND;
+ if(handle <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
fileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly);
return STATUS_SUCCESS;
}
- sealed class FileEntry
+ CachedDisk disk = _vfs.GetDisk(machine.Id, pieces[2]);
+
+ if(disk != null)
{
- public string FileName { get; set; }
- public FileInfo Info { get; set; }
- public bool IsRomSet { get; set; }
+ if(pieces.Length > 3) return STATUS_INVALID_DEVICE_REQUEST;
+
+ if(disk.Sha1 == null && disk.Md5 == null) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ handle = _vfs.OpenDisk(disk.Sha1, disk.Md5);
+
+ if(handle <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ fileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly);
+
+ return STATUS_SUCCESS;
}
- sealed class FileNode
- {
- public FileInfo Info { get; set; }
- public FileInfo ParentInfo { get; set; }
- public string FileName { get; set; }
- public string Path { get; set; }
- public long Handle { get; set; }
- public List Children { get; set; }
- public bool IsDirectory { get; set; }
- public long RomSetId { get; set; }
- public ulong MachineId { get; set; }
- }
+ CachedMedia media = _vfs.GetMedia(machine.Id, pieces[2]);
+
+ if(media == null) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ if(pieces.Length > 3) return STATUS_INVALID_DEVICE_REQUEST;
+
+ if(media.Sha256 == null && media.Sha1 == null && media.Md5 == null) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ handle = _vfs.OpenMedia(media.Sha256, media.Sha1, media.Md5);
+
+ if(handle <= 0) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ fileAttributes = (uint)(FileAttributes.Normal | FileAttributes.Compressed | FileAttributes.ReadOnly);
+
+ return STATUS_SUCCESS;
+ }
+
+ sealed class FileEntry
+ {
+ public string FileName { get; set; }
+ public FileInfo Info { get; set; }
+ public bool IsRomSet { get; set; }
+ }
+
+ sealed class FileNode
+ {
+ public FileInfo Info { get; set; }
+ public FileInfo ParentInfo { get; set; }
+ public string FileName { get; set; }
+ public string Path { get; set; }
+ public long Handle { get; set; }
+ public List Children { get; set; }
+ public bool IsDirectory { get; set; }
+ public long RomSetId { get; set; }
+ public ulong MachineId { get; set; }
}
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/ForcedSeekStream.cs b/RomRepoMgr.Core/ForcedSeekStream.cs
index 8600001..cc4c956 100644
--- a/RomRepoMgr.Core/ForcedSeekStream.cs
+++ b/RomRepoMgr.Core/ForcedSeekStream.cs
@@ -34,173 +34,165 @@ using System;
using System.IO;
using RomRepoMgr.Core.Resources;
-namespace RomRepoMgr.Core
+namespace RomRepoMgr.Core;
+
+///
+///
+/// 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.
+///
+internal sealed class ForcedSeekStream : Stream where T : Stream
{
+ const int BUFFER_LEN = 1048576;
+ readonly string _backFile;
+ readonly FileStream _backStream;
+ readonly T _baseStream;
+ long _streamLength;
+
///
- ///
- /// 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.
- ///
- internal sealed class ForcedSeekStream : Stream where T : Stream
+ /// Initializes a new instance of the class.
+ /// The real (uncompressed) length of the stream.
+ /// Parameters that are used to create the base stream.
+ 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);
- ///
- /// Initializes a new instance of the class.
- /// The real (uncompressed) length of the stream.
- /// Parameters that are used to create the base stream.
- 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);
+ }
+
+ ///
+ /// 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.
+ ///
+ /// The length.
+ 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);
}
- ///
- /// 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.
- ///
- /// The length.
- 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);
}
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Models/AssemblyModel.cs b/RomRepoMgr.Core/Models/AssemblyModel.cs
index 06451c5..e740695 100644
--- a/RomRepoMgr.Core/Models/AssemblyModel.cs
+++ b/RomRepoMgr.Core/Models/AssemblyModel.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Models/ImportRomItem.cs b/RomRepoMgr.Core/Models/ImportRomItem.cs
index c5bcb60..63e245c 100644
--- a/RomRepoMgr.Core/Models/ImportRomItem.cs
+++ b/RomRepoMgr.Core/Models/ImportRomItem.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Models/RomSetModel.cs b/RomRepoMgr.Core/Models/RomSetModel.cs
index e32ac82..ccaeedd 100644
--- a/RomRepoMgr.Core/Models/RomSetModel.cs
+++ b/RomRepoMgr.Core/Models/RomSetModel.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Resources/Localization.Designer.cs b/RomRepoMgr.Core/Resources/Localization.Designer.cs
index 00ecd66..37c9881 100644
--- a/RomRepoMgr.Core/Resources/Localization.Designer.cs
+++ b/RomRepoMgr.Core/Resources/Localization.Designer.cs
@@ -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()]
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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 {
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
get {
- if (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 {
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
get {
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);
- }
- }
-
+ ///
+ /// Looks up a localized string similar to Adding DAT to database....
+ ///
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);
- }
- }
-
+ ///
+ /// Looks up a localized string similar to Adding disks....
+ ///
internal static string AddingDisks {
get {
return ResourceManager.GetString("AddingDisks", resourceCulture);
}
}
- internal static string FoundDiskWithoutMachine {
+ ///
+ /// Looks up a localized string similar to Adding machines (games)....
+ ///
+ 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);
}
}
+ ///
+ /// Looks up a localized string similar to Adding medias....
+ ///
internal static string AddingMedias {
get {
return ResourceManager.GetString("AddingMedias", resourceCulture);
}
}
+ ///
+ /// Looks up a localized string similar to Adding ROMs....
+ ///
+ internal static string AddingRoms {
+ get {
+ return ResourceManager.GetString("AddingRoms", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Assertion failed.
+ ///
+ internal static string Assertion_failed {
+ get {
+ return ResourceManager.GetString("Assertion_failed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specified string is not valid Base32 format because character "{0}" does not exist in Base32 alphabet.
+ ///
+ internal static string Base32_Invalid_format {
+ get {
+ return ResourceManager.GetString("Base32_Invalid_format", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specified string is not valid Base32 format because it doesn't have enough data to construct a complete byte array.
+ ///
+ internal static string Base32_Not_enought_data {
+ get {
+ return ResourceManager.GetString("Base32_Not_enought_data", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot seek after stream end..
+ ///
+ internal static string Cannot_seek_after_end {
+ get {
+ return ResourceManager.GetString("Cannot_seek_after_end", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot seek before stream start..
+ ///
+ internal static string Cannot_seek_before_start {
+ get {
+ return ResourceManager.GetString("Cannot_seek_before_start", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot find file with hash {0} in the repository.
+ ///
+ internal static string CannotFindHashInRepository {
+ get {
+ return ResourceManager.GetString("CannotFindHashInRepository", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot find lsar executable..
+ ///
+ internal static string CannotFindLsAr {
+ get {
+ return ResourceManager.GetString("CannotFindLsAr", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot find unar executable at {0}..
+ ///
+ internal static string CannotFindUnArAtPath {
+ get {
+ return ResourceManager.GetString("CannotFindUnArAtPath", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot find requested zip entry in hashes dictionary.
+ ///
+ internal static string CannotFindZipEntryInDictionary {
+ get {
+ return ResourceManager.GetString("CannotFindZipEntryInDictionary", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot run lsar..
+ ///
+ internal static string CannotRunLsAr {
+ get {
+ return ResourceManager.GetString("CannotRunLsAr", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot run unar..
+ ///
+ internal static string CannotRunUnAr {
+ get {
+ return ResourceManager.GetString("CannotRunUnAr", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Checking if file is an archive....
+ ///
+ internal static string CheckingIfFIleIsAnArchive {
+ get {
+ return ResourceManager.GetString("CheckingIfFIleIsAnArchive", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Compressing {0}....
+ ///
+ internal static string Compressing {
+ get {
+ return ResourceManager.GetString("Compressing", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Compressing DAT file....
+ ///
+ internal static string CompressingDatFile {
+ get {
+ return ResourceManager.GetString("CompressingDatFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Compressing file....
+ ///
+ internal static string CompressingFile {
+ get {
+ return ResourceManager.GetString("CompressingFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Copying {0}....
+ ///
+ internal static string Copying {
+ get {
+ return ResourceManager.GetString("Copying", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Copying file....
+ ///
+ internal static string CopyingFile {
+ get {
+ return ResourceManager.GetString("CopyingFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Could not find ROM set in database..
+ ///
+ internal static string CouldNotFindRomSetInDatabase {
+ get {
+ return ResourceManager.GetString("CouldNotFindRomSetInDatabase", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to File exists.
+ ///
+ internal static string DatabaseFileExistsMsgBoxTitle {
+ get {
+ return ResourceManager.GetString("DatabaseFileExistsMsgBoxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to DAT file is already in database, not importing duplicates..
+ ///
+ internal static string DatAlreadyInDatabase {
+ get {
+ return ResourceManager.GetString("DatAlreadyInDatabase", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Imported {0} machines with {1} ROMs..
+ ///
+ internal static string DatImportSuccess {
+ get {
+ return ResourceManager.GetString("DatImportSuccess", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Enumerating files....
+ ///
+ internal static string EnumeratingFiles {
+ get {
+ return ResourceManager.GetString("EnumeratingFiles", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Error: {0}.
+ ///
+ internal static string ErrorWithMessage {
+ get {
+ return ResourceManager.GetString("ErrorWithMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exporting ROMs....
+ ///
+ internal static string ExportingRoms {
+ get {
+ return ResourceManager.GetString("ExportingRoms", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Extracted contents.
+ ///
+ internal static string ExtractedContents {
+ get {
+ return ResourceManager.GetString("ExtractedContents", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Extracting archive contents....
+ ///
+ internal static string ExtractingArchive {
+ get {
+ return ResourceManager.GetString("ExtractingArchive", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Finished.
+ ///
+ internal static string Finished {
+ get {
+ return ResourceManager.GetString("Finished", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Finishing....
+ ///
+ internal static string Finishing {
+ get {
+ return ResourceManager.GetString("Finishing", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Found a disk with an unknown machine, this should not happen..
+ ///
+ internal static string FoundDiskWithoutMachine {
+ get {
+ return ResourceManager.GetString("FoundDiskWithoutMachine", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Found media with an unknown machine, this should not happen..
+ ///
internal static string FoundMediaWithoutMachine {
get {
return ResourceManager.GetString("FoundMediaWithoutMachine", resourceCulture);
}
}
+ ///
+ /// Looks up a localized string similar to Found a ROM with an unknown machine, this should not happen..
+ ///
+ internal static string FoundRomWithoutMachine {
+ get {
+ return ResourceManager.GetString("FoundRomWithoutMachine", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Getting machine (game) names....
+ ///
+ internal static string GettingMachineNames {
+ get {
+ return ResourceManager.GetString("GettingMachineNames", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hashing DAT file....
+ ///
+ internal static string HashingDatFile {
+ get {
+ return ResourceManager.GetString("HashingDatFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hashing file....
+ ///
+ internal static string HashingFile {
+ get {
+ return ResourceManager.GetString("HashingFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Importing {0}....
+ ///
+ internal static string Importing {
+ get {
+ return ResourceManager.GetString("Importing", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to No checksums found..
+ ///
+ internal static string NoChecksumsFound {
+ get {
+ return ResourceManager.GetString("NoChecksumsFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Not yet implemented..
+ ///
+ internal static string Not_yet_implemented {
+ get {
+ return ResourceManager.GetString("Not_yet_implemented", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Not a CHD file..
+ ///
+ internal static string NotAChdFile {
+ get {
+ return ResourceManager.GetString("NotAChdFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Not an AaruFormat file..
+ ///
internal static string NotAnAaruFormatFile {
get {
return ResourceManager.GetString("NotAnAaruFormatFile", resourceCulture);
}
}
- internal static string DatImportSuccess {
+ ///
+ /// Looks up a localized string similar to Not the correct lsar executable.
+ ///
+ internal static string NotCorrectLsAr {
get {
- return ResourceManager.GetString("DatImportSuccess", resourceCulture);
+ return ResourceManager.GetString("NotCorrectLsAr", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Not the correct unar executable.
+ ///
+ internal static string NotCorrectUnAr {
+ get {
+ return ResourceManager.GetString("NotCorrectUnAr", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to OK.
+ ///
+ internal static string OK {
+ get {
+ return ResourceManager.GetString("OK", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Parsing DAT file....
+ ///
+ internal static string ParsinDatFile {
+ get {
+ return ResourceManager.GetString("ParsinDatFile", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Removing temporary path....
+ ///
+ internal static string RemovingTemporaryPath {
+ get {
+ return ResourceManager.GetString("RemovingTemporaryPath", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Retrieving ROMs and disks....
+ ///
+ internal static string RetrievingRomsAndDisks {
+ get {
+ return ResourceManager.GetString("RetrievingRomsAndDisks", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Retrieving ROM set from database..
+ ///
+ internal static string RetrievingRomSetFromDatabase {
+ get {
+ return ResourceManager.GetString("RetrievingRomSetFromDatabase", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Saving changes to database....
+ ///
+ internal static string SavingChangesToDatabase {
+ get {
+ return ResourceManager.GetString("SavingChangesToDatabase", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The input exceeds data types..
+ ///
+ internal static string Spamsum_Input_exceeds_data {
+ get {
+ return ResourceManager.GetString("Spamsum_Input_exceeds_data", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to SpamSum does not have a binary representation..
+ ///
+ internal static string Spamsum_no_binary {
+ get {
+ return ResourceManager.GetString("Spamsum_no_binary", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to unar path is not set..
+ ///
+ internal static string UnArPathNotSet {
+ get {
+ return ResourceManager.GetString("UnArPathNotSet", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Unhandled exception occurred..
+ ///
+ internal static string UnhandledException {
+ get {
+ return ResourceManager.GetString("UnhandledException", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Unhandled exception when importing file..
+ ///
+ internal static string UnhandledExceptionWhenImporting {
+ get {
+ return ResourceManager.GetString("UnhandledExceptionWhenImporting", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Unknown file..
+ ///
+ internal static string UnknownFile {
+ get {
+ return ResourceManager.GetString("UnknownFile", resourceCulture);
}
}
}
diff --git a/RomRepoMgr.Core/Resources/Localization.es.resx b/RomRepoMgr.Core/Resources/Localization.es.resx
index 83702f1..ebdacd0 100644
--- a/RomRepoMgr.Core/Resources/Localization.es.resx
+++ b/RomRepoMgr.Core/Resources/Localization.es.resx
@@ -1,185 +1,189 @@
-
- text/microsoft-resx
-
-
- 1.3
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
+ PublicKeyToken=b77a5c561934e089
+
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
+ PublicKeyToken=b77a5c561934e089
+
+
+
Añadiendo DAT a la base de datos...
-
+
Añadiendo máquinas (juegos)...
-
+
Añadiendo ROMs...
-
+
Aserción fallida
-
+
El texto especificado no tiene un formato Base32 válido porque el caracter "{0}" no existe en el alfabeto Base32
-
+
El texto especificado no tiene un formato Base32 válido porque no tiene datos suficientes para completar una ristra de bytes
-
+
No se puede encontrar el archivo con hash {0} en el repositorio
-
+
No se puede encontrar el ejecutable lsar.
-
+
No se puede encontrar el ejecutable unar en {0}.
-
+
No se puede encontrar la entrada zip solicitada en el diccionari de hashes
-
+
No se puede ejecutar lsar.
-
+
No se puede ejecutar unar.
-
+
No se puede posicionar antes del comienzo.
-
+
No se puede posicionar después del comienzo.
-
+
Comprobando si el fichero es un archivo comprimido...
-
+
Comprimiendo {0}...
-
+
Comprimiendo archivo DAT...
-
+
Comprimiendo archivo...
-
+
No se pudo encontrar el set de ROMs en la base de datos.
-
+
El archivo existe
-
+
El archivo DAT ya está en la base de datos, no importaré duplicados.
-
+
Enumerando archivos...
-
+
Error: {0}
-
+
Exportando ROMs...
-
+
Contenidos extraídos
-
+
Extrayendo contenidos del archivo...
-
+
Terminado
-
+
Terminando...
-
+
Se encontró una ROM sin máquina, esto no debería pasar.
-
+
Obteniendo nombre de las máquinas (juegos)...
-
+
Calculando hash del archivo DAT...
-
+
Calculando hash del archivo...
-
+
Importando {0}...
-
+
No es el ejecutable correcto de lsar
-
+
No es el ejecutable corrector de unar
-
+
Aún no implementado.
-
+
OK
-
+
Analizando archivo DAT...
-
+
Eliminando ruta remporal...
-
+
Recuperando ROMs y discos...
-
+
Recuperando set de ROMs de la base de datos...
-
+
Guardando cambios en la base de datos...
-
+
La entrada excede los tipos de datos.
-
+
SpamSum no posee una representación binaria.
-
+
La ruta a unar no está establecida.
-
+
Ocurrió una excepción no controlada.
-
+
Excepción no controlada al importar archivo.
-
+
Archivo desconocido.
-
+
Añadiendo discos...
-
+
Se encontró un disco sin máquina, esto no debería pasar.
-
+
No se encontraron hashes.
-
+
No es un CHD.
-
+
Copiando {0}...
-
+
Copiando archivo...
-
+
Se encontró un medio sin máquina, esto no debería pasar.
-
+
No es un archivo AaruFormat.
-
+
Añadiendo medios...
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Resources/Localization.resx b/RomRepoMgr.Core/Resources/Localization.resx
index 3d06f17..235219c 100644
--- a/RomRepoMgr.Core/Resources/Localization.resx
+++ b/RomRepoMgr.Core/Resources/Localization.resx
@@ -1,193 +1,198 @@
-
-
-
-
- text/microsoft-resx
-
-
- 1.3
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
+ PublicKeyToken=b77a5c561934e089
+
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
+ PublicKeyToken=b77a5c561934e089
+
+
+
Specified string is not valid Base32 format because it doesn't have enough data to construct a complete byte array
-
+
Specified string is not valid Base32 format because character "{0}" does not exist in Base32 alphabet
-
+
Cannot seek before stream start.
-
+
Cannot seek after stream end.
-
+
SpamSum does not have a binary representation.
-
+
Assertion failed
-
+
The input exceeds data types.
-
+
Not yet implemented.
-
+
File exists
-
+
unar path is not set.
-
+
Cannot find unar executable at {0}.
-
+
Cannot find lsar executable.
-
+
Cannot run unar.
-
+
Cannot run lsar.
-
+
Not the correct unar executable
-
+
Not the correct lsar executable
-
+
Parsing DAT file...
-
+
Hashing DAT file...
-
+
DAT file is already in database, not importing duplicates.
-
+
Adding DAT to database...
-
+
Compressing DAT file...
-
+
Getting machine (game) names...
-
+
Adding machines (games)...
-
+
Saving changes to database...
-
+
Retrieving ROMs and disks...
-
+
Adding ROMs...
-
+
Found a ROM with an unknown machine, this should not happen.
-
+
Unhandled exception occurred.
-
+
Retrieving ROM set from database.
-
+
Could not find ROM set in database.
-
+
Exporting ROMs...
-
+
Finished
-
+
Cannot find requested zip entry in hashes dictionary
-
+
Cannot find file with hash {0} in the repository
-
+
Compressing {0}...
-
+
Enumerating files...
-
+
Importing {0}...
-
+
Checking if file is an archive...
-
+
OK
-
+
Error: {0}
-
+
Extracting archive contents...
-
+
Removing temporary path...
-
+
Extracted contents
-
+
Hashing file...
-
+
Unknown file.
-
+
Compressing file...
-
+
Finishing...
-
+
Unhandled exception when importing file.
-
+
Adding disks...
-
+
Found a disk with an unknown machine, this should not happen.
-
+
Not a CHD file.
-
+
No checksums found.
-
+
Copying {0}...
-
+
Copying file...
-
+
Adding medias...
-
+
Found media with an unknown machine, this should not happen.
-
+
Not an AaruFormat file.
-
+
Imported {0} machines with {1} ROMs.
\ No newline at end of file
diff --git a/RomRepoMgr.Core/RomRepoMgr.Core.csproj b/RomRepoMgr.Core/RomRepoMgr.Core.csproj
index 4514a16..12ba233 100644
--- a/RomRepoMgr.Core/RomRepoMgr.Core.csproj
+++ b/RomRepoMgr.Core/RomRepoMgr.Core.csproj
@@ -1,39 +1,39 @@
-
- net9.0
- en
- default
-
+
+ net9.0
+ en
+ default
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
- ResXFileCodeGenerator
- Localization.Designer.cs
-
-
+
+
+ ResXFileCodeGenerator
+ Localization.Designer.cs
+
+
-
-
- True
- True
- Language.resx
-
-
+
+
+ True
+ True
+ Language.resx
+
+
diff --git a/RomRepoMgr.Core/StreamWithLength.cs b/RomRepoMgr.Core/StreamWithLength.cs
index dbae417..232f9eb 100644
--- a/RomRepoMgr.Core/StreamWithLength.cs
+++ b/RomRepoMgr.Core/StreamWithLength.cs
@@ -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();
}
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Workers/Checksum.cs b/RomRepoMgr.Core/Workers/Checksum.cs
index 17469b4..c16f0df 100644
--- a/RomRepoMgr.Core/Workers/Checksum.cs
+++ b/RomRepoMgr.Core/Workers/Checksum.cs
@@ -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 End() => new Dictionary
- {
- [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 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
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Workers/Compression.cs b/RomRepoMgr.Core/Workers/Compression.cs
index bc55d8b..f10f8f9 100644
--- a/RomRepoMgr.Core/Workers/Compression.cs
+++ b/RomRepoMgr.Core/Workers/Compression.cs
@@ -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 SetProgressBounds;
+ public event EventHandler SetProgress;
+ public event EventHandler FinishedWithText;
+ public event EventHandler 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 SetProgressBounds;
- public event EventHandler SetProgress;
- public event EventHandler FinishedWithText;
- public event EventHandler 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;
}
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Workers/DatImporter.cs b/RomRepoMgr.Core/Workers/DatImporter.cs
index 598ae84..6e26129 100644
--- a/RomRepoMgr.Core/Workers/DatImporter.cs
+++ b/RomRepoMgr.Core/Workers/DatImporter.cs
@@ -40,1138 +40,1202 @@ using RomRepoMgr.Database;
using RomRepoMgr.Database.Models;
using SabreTools.DatFiles;
using SabreTools.DatItems;
-using SabreTools.IO;
using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs;
using Machine = RomRepoMgr.Database.Models.Machine;
-namespace RomRepoMgr.Core.Workers
+namespace RomRepoMgr.Core.Workers;
+
+public sealed class DatImporter
{
- public sealed class DatImporter
+ readonly string _category;
+ readonly string _datFilesPath;
+ readonly string _datPath;
+ bool _aborted;
+
+ public DatImporter(string datPath, string category)
{
- readonly string _category;
- readonly string _datFilesPath;
- readonly string _datPath;
- bool _aborted;
+ _datPath = datPath;
+ _datFilesPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "datfiles");
- public DatImporter(string datPath, string category)
+ if(!string.IsNullOrWhiteSpace(category)) _category = category;
+ }
+
+ public void Import()
+ {
+ try
{
- _datPath = datPath;
- _datFilesPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "datfiles");
+ using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
- if(!string.IsNullOrWhiteSpace(category))
- _category = category;
- }
+ SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
- public void Import()
- {
- try
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.ParsinDatFile
+ });
+
+ var datFile = DatFile.Create();
+ datFile.ParseFile(_datPath, 0, false, true);
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.HashingDatFile
+ });
+
+ string datHash = Sha384Context.File(_datPath, out byte[] datHashBinary);
+
+ string datHash32 = Base32.ToBase32String(datHashBinary);
+
+ if(!Directory.Exists(_datFilesPath)) Directory.CreateDirectory(_datFilesPath);
+
+ string compressedDatPath = Path.Combine(_datFilesPath, datHash32 + ".lz");
+
+ if(File.Exists(compressedDatPath))
{
- using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
+ ErrorOccurred?.Invoke(this,
+ new ErrorEventArgs
+ {
+ Message = Localization.DatAlreadyInDatabase
+ });
+
+ return;
+ }
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.AddingDatToDatabase
+ });
+
+ // TODO: Check if there is a hash in database but not in repo
+
+ var romSet = new RomSet
+ {
+ Author = datFile.Header.Author,
+ Comment = datFile.Header.Comment,
+ Date = datFile.Header.Date,
+ Description = datFile.Header.Description,
+ Filename = Path.GetFileName(_datPath),
+ Homepage = datFile.Header.Homepage,
+ Name = datFile.Header.Name,
+ Sha384 = datHash,
+ Version = datFile.Header.Version,
+ CreatedOn = DateTime.UtcNow,
+ UpdatedOn = DateTime.UtcNow,
+ Category = _category
+ };
+
+ ctx.RomSets.Add(romSet);
+ ctx.SaveChanges();
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.CompressingDatFile
+ });
+
+ var datCompress = new Compression();
+ datCompress.SetProgress += SetProgress;
+ datCompress.SetProgressBounds += SetProgressBounds;
+ datCompress.CompressFile(_datPath, compressedDatPath);
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.GettingMachineNames
+ });
+
+ var machineNames = (from value in datFile.Items.Values from item in value select item.Machine.Name)
+ .Distinct()
+ .ToList();
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.AddingMachines
+ });
+
+ SetProgressBounds?.Invoke(this,
+ new ProgressBoundsEventArgs
+ {
+ Minimum = 0,
+ Maximum = machineNames.Count
+ });
+
+ var position = 0;
+ var machines = new Dictionary();
+
+ foreach(string name in machineNames)
+ {
+ SetProgress?.Invoke(this,
+ new ProgressEventArgs
+ {
+ Value = position
+ });
+
+ var machine = new Machine
+ {
+ Name = name,
+ RomSetId = romSet.Id,
+ CreatedOn = DateTime.UtcNow,
+ UpdatedOn = DateTime.UtcNow
+ };
+
+ machines[name] = machine;
+
+ position++;
+ }
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.SavingChangesToDatabase
+ });
+
+ SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
+
+ ctx.BulkInsert(machines.Values.ToList(), b => b.SetOutputIdentity = true);
+ ctx.SaveChanges();
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.RetrievingRomsAndDisks
+ });
+
+ var roms = new List();
+ var disks = new List();
+ var medias = new List();
+
+ var tmpRomCrc32Table = Guid.NewGuid().ToString();
+ var tmpRomMd5Table = Guid.NewGuid().ToString();
+ var tmpRomSha1Table = Guid.NewGuid().ToString();
+ var tmpRomSha256Table = Guid.NewGuid().ToString();
+ var tmpRomSha384Table = Guid.NewGuid().ToString();
+ var tmpRomSha512Table = Guid.NewGuid().ToString();
+ var tmpDiskMd5Table = Guid.NewGuid().ToString();
+ var tmpDiskSha1Table = Guid.NewGuid().ToString();
+ var tmpMediaMd5Table = Guid.NewGuid().ToString();
+ var tmpMediaSha1Table = Guid.NewGuid().ToString();
+ var tmpMediaSha256Table = Guid.NewGuid().ToString();
+
+ var romsHaveCrc = false;
+ var romsHaveMd5 = false;
+ var romsHaveSha1 = false;
+ var romsHaveSha256 = false;
+ var romsHaveSha384 = false;
+ var romsHaveSha512 = false;
+ var disksHaveMd5 = false;
+ var disksHaveSha1 = false;
+ var mediasHaveMd5 = false;
+ var mediasHaveSha1 = false;
+ var mediasHaveSha256 = false;
+
+ DbConnection dbConnection = ctx.Database.GetDbConnection();
+ dbConnection.Open();
+
+ position = 0;
+
+ SetProgressBounds?.Invoke(this,
+ new ProgressBoundsEventArgs
+ {
+ Minimum = 0,
+ Maximum = datFile.Items.Values.Count
+ });
+
+ using(DbTransaction dbTransaction = dbConnection.BeginTransaction())
+ {
+ DbCommand dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"CREATE TABLE \"{tmpRomCrc32Table}\" (\"Size\" INTEGER NOT NULL, \"Crc32\" TEXT NOT NULL);";
+
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"CREATE TABLE \"{tmpRomMd5Table}\" (\"Size\" INTEGER NOT NULL, \"Md5\" TEXT NOT NULL);";
+
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"CREATE TABLE \"{tmpRomSha1Table}\" (\"Size\" INTEGER NOT NULL, \"Sha1\" TEXT NOT NULL);";
+
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"CREATE TABLE \"{tmpRomSha256Table}\" (\"Size\" INTEGER NOT NULL, \"Sha256\" TEXT NOT NULL);";
+
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"CREATE TABLE \"{tmpRomSha384Table}\" (\"Size\" INTEGER NOT NULL, \"Sha384\" TEXT NOT NULL);";
+
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"CREATE TABLE \"{tmpRomSha512Table}\" (\"Size\" INTEGER NOT NULL, \"Sha512\" TEXT NOT NULL);";
+
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+ dbcc.CommandText = $"CREATE TABLE \"{tmpDiskMd5Table}\" (\"Md5\" TEXT NOT NULL);";
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+ dbcc.CommandText = $"CREATE TABLE \"{tmpDiskSha1Table}\" (\"Sha1\" TEXT NOT NULL);";
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+ dbcc.CommandText = $"CREATE TABLE \"{tmpMediaMd5Table}\" (\"Md5\" TEXT NOT NULL);";
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+ dbcc.CommandText = $"CREATE TABLE \"{tmpMediaSha1Table}\" (\"Sha1\" TEXT NOT NULL);";
+ dbcc.ExecuteNonQuery();
+ dbcc = dbConnection.CreateCommand();
+ dbcc.CommandText = $"CREATE TABLE \"{tmpMediaSha256Table}\" (\"Sha256\" TEXT NOT NULL);";
+ dbcc.ExecuteNonQuery();
+
+ foreach(List values in datFile.Items.Values)
+ {
+ SetProgress?.Invoke(this,
+ new ProgressEventArgs
+ {
+ Value = position
+ });
+
+ foreach(DatItem item in values)
+ {
+ switch(item)
+ {
+ case Rom rom:
+ if(rom.CRC != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpRomCrc32Table}\" (\"Size\", \"Crc32\") VALUES (\"{(ulong)rom.Size}\", \"{rom.CRC}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ romsHaveCrc = true;
+ }
+
+ if(rom.MD5 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpRomMd5Table}\" (\"Size\", \"Md5\") VALUES (\"{(ulong)rom.Size}\", \"{rom.MD5}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ romsHaveMd5 = true;
+ }
+
+ if(rom.SHA1 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpRomSha1Table}\" (\"Size\", \"Sha1\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA1}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ romsHaveSha1 = true;
+ }
+
+ if(rom.SHA256 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpRomSha256Table}\" (\"Size\", \"Sha256\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA256}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ romsHaveSha256 = true;
+ }
+
+ if(rom.SHA384 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpRomSha384Table}\" (\"Size\", \"Sha384\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA384}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ romsHaveSha384 = true;
+ }
+
+ if(rom.SHA512 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpRomSha512Table}\" (\"Size\", \"Sha512\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA512}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ romsHaveSha512 = true;
+ }
+
+ roms.Add(rom);
+
+ continue;
+ case Disk disk:
+ if(disk.MD5 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpDiskMd5Table}\" (\"Md5\") VALUES (\"{disk.MD5}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ disksHaveMd5 = true;
+ }
+
+ if(disk.SHA1 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpDiskSha1Table}\" (\"Sha1\") VALUES (\"{disk.SHA1}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ disksHaveSha1 = true;
+ }
+
+ disks.Add(disk);
+
+ continue;
+ case Media media:
+ if(media.MD5 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpMediaMd5Table}\" (\"Md5\") VALUES (\"{media.MD5}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ mediasHaveMd5 = true;
+ }
+
+ if(media.SHA1 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpMediaSha1Table}\" (\"Sha1\") VALUES (\"{media.SHA1}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ mediasHaveSha1 = true;
+ }
+
+ if(media.SHA256 != null)
+ {
+ dbcc = dbConnection.CreateCommand();
+
+ dbcc.CommandText =
+ $"INSERT INTO \"{tmpMediaSha256Table}\" (\"Sha256\") VALUES (\"{media.SHA256}\");";
+
+ dbcc.ExecuteNonQuery();
+
+ mediasHaveSha256 = true;
+ }
+
+ medias.Add(media);
+
+ continue;
+ }
+ }
+
+ position++;
+ }
SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
- SetMessage?.Invoke(this, new MessageEventArgs
+ dbTransaction.Commit();
+ }
+
+ List pendingFilesByCrcList = romsHaveCrc
+ ? ctx.Files
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomCrc32Table}] AS t WHERE f.Crc32 = t.Crc32 AND f.Size = t.Size")
+ .ToList()
+ : new List();
+
+ List pendingFilesByMd5List = romsHaveMd5
+ ? ctx.Files
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomMd5Table}] AS t WHERE f.Md5 = t.Md5 AND f.Size = t.Size")
+ .ToList()
+ : new List();
+
+ List pendingFilesBySha1List =
+ romsHaveSha1
+ ? ctx.Files
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha1Table}] AS t WHERE f.Sha1 = t.Sha1 AND f.Size = t.Size")
+ .ToList()
+ : new List();
+
+ List pendingFilesBySha256List =
+ romsHaveSha256
+ ? ctx.Files
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha256Table}] AS t WHERE f.Sha256 = t.Sha256 AND f.Size = t.Size")
+ .ToList()
+ : new List();
+
+ List pendingFilesBySha384List =
+ romsHaveSha384
+ ? ctx.Files
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha384Table}] AS t WHERE f.Sha384 = t.Sha384 AND f.Size = t.Size")
+ .ToList()
+ : new List();
+
+ List pendingFilesBySha512List =
+ romsHaveSha512
+ ? ctx.Files
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha512Table}] AS t WHERE f.Sha512 = t.Sha512 AND f.Size = t.Size")
+ .ToList()
+ : new List();
+
+ Dictionary pendingDisksByMd5 =
+ disksHaveMd5
+ ? ctx.Disks
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Disks AS f, [{tmpDiskMd5Table}] AS t WHERE f.Md5 = t.Md5")
+ .ToDictionary(f => f.Md5)
+ : new Dictionary();
+
+ Dictionary pendingDisksBySha1 =
+ disksHaveSha1
+ ? ctx.Disks
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Disks AS f, [{tmpDiskSha1Table}] AS t WHERE f.Sha1 = t.Sha1")
+ .ToDictionary(f => f.Sha1)
+ : new Dictionary();
+
+ Dictionary pendingMediasByMd5 =
+ mediasHaveMd5
+ ? ctx.Medias
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Medias AS f, [{tmpMediaMd5Table}] AS t WHERE f.Md5 = t.Md5")
+ .ToDictionary(f => f.Md5)
+ : new Dictionary();
+
+ Dictionary pendingMediasBySha1 =
+ mediasHaveSha1
+ ? ctx.Medias
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Medias AS f, [{tmpMediaSha1Table}] AS t WHERE f.Sha1 = t.Sha1")
+ .ToDictionary(f => f.Sha1)
+ : new Dictionary();
+
+ Dictionary pendingMediasBySha256 =
+ mediasHaveSha256
+ ? ctx.Medias
+ .FromSqlRaw($"SELECT DISTINCT f.* FROM Medias AS f, [{tmpMediaSha256Table}] AS t WHERE f.Sha256 = t.Sha256")
+ .ToDictionary(f => f.Sha256)
+ : new Dictionary();
+
+ var pendingFilesByCrc = new Dictionary();
+ var pendingFilesByMd5 = new Dictionary();
+ var pendingFilesBySha1 = new Dictionary();
+ var pendingFilesBySha256 = new Dictionary();
+ var pendingFilesBySha384 = new Dictionary();
+ var pendingFilesBySha512 = new Dictionary();
+ var pendingFiles = new List();
+
+ // This is because of hash collisions.
+ foreach(DbFile item in pendingFilesByCrcList)
+ {
+ if(pendingFilesByCrc.ContainsKey(item.Crc32))
+ pendingFiles.Add(item);
+ else
+ pendingFilesByCrc[item.Crc32] = item;
+ }
+
+ foreach(DbFile item in pendingFilesByMd5List)
+ {
+ if(pendingFilesByMd5.ContainsKey(item.Md5))
+ pendingFiles.Add(item);
+ else
+ pendingFilesByMd5[item.Md5] = item;
+ }
+
+ foreach(DbFile item in pendingFilesBySha1List)
+ {
+ if(pendingFilesBySha1.ContainsKey(item.Sha1))
+ pendingFiles.Add(item);
+ else
+ pendingFilesBySha1[item.Sha1] = item;
+ }
+
+ foreach(DbFile item in pendingFilesBySha256List)
+ {
+ if(pendingFilesBySha256.ContainsKey(item.Sha256))
+ pendingFiles.Add(item);
+ else
+ pendingFilesBySha256[item.Sha256] = item;
+ }
+
+ foreach(DbFile item in pendingFilesBySha384List)
+ {
+ if(pendingFilesBySha384.ContainsKey(item.Sha384))
+ pendingFiles.Add(item);
+ else
+ pendingFilesBySha384[item.Sha384] = item;
+ }
+
+ foreach(DbFile item in pendingFilesBySha512List)
+ {
+ if(pendingFilesBySha512.ContainsKey(item.Sha512))
+ pendingFiles.Add(item);
+ else
+ pendingFilesBySha512[item.Sha512] = item;
+ }
+
+ // Clear some memory
+ pendingFilesByCrcList.Clear();
+ pendingFilesByMd5List.Clear();
+ pendingFilesBySha1List.Clear();
+ pendingFilesBySha256List.Clear();
+ pendingFilesBySha384List.Clear();
+ pendingFilesBySha512List.Clear();
+
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomCrc32Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomMd5Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha1Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha256Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha384Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha512Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpDiskMd5Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpDiskSha1Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpMediaMd5Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpMediaSha1Table}]");
+ ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpMediaSha256Table}]");
+
+ SetProgressBounds?.Invoke(this,
+ new ProgressBoundsEventArgs
+ {
+ Minimum = 0,
+ Maximum = roms.Count
+ });
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.AddingRoms
+ });
+
+ position = 0;
+
+ var newFiles = new List();
+ var newFilesByMachine = new List();
+
+ foreach(Rom rom in roms)
+ {
+ var hashCollision = false;
+
+ SetProgress?.Invoke(this,
+ new ProgressEventArgs
+ {
+ Value = position
+ });
+
+ if(!machines.TryGetValue(rom.Machine.Name, out Machine machine))
{
- Message = Localization.ParsinDatFile
- });
-
- var datFile = DatFile.Create();
- datFile.ParseFile(_datPath, 0, false, throwOnError: true);
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.HashingDatFile
- });
-
- string datHash = Sha384Context.File(_datPath, out byte[] datHashBinary);
-
- string datHash32 = Base32.ToBase32String(datHashBinary);
-
- if(!Directory.Exists(_datFilesPath))
- Directory.CreateDirectory(_datFilesPath);
-
- string compressedDatPath = Path.Combine(_datFilesPath, datHash32 + ".lz");
-
- if(File.Exists(compressedDatPath))
- {
- ErrorOccurred?.Invoke(this, new ErrorEventArgs
- {
- Message = Localization.DatAlreadyInDatabase
- });
+ ErrorOccurred?.Invoke(this,
+ new ErrorEventArgs
+ {
+ Message = Localization.FoundRomWithoutMachine
+ });
return;
}
- SetMessage?.Invoke(this, new MessageEventArgs
+ var uSize = (ulong)rom.Size;
+
+ DbFile file = null;
+
+ if(rom.SHA512 != null)
{
- Message = Localization.AddingDatToDatabase
- });
-
- // TODO: Check if there is a hash in database but not in repo
-
- var romSet = new RomSet
- {
- Author = datFile.Header.Author,
- Comment = datFile.Header.Comment,
- Date = datFile.Header.Date,
- Description = datFile.Header.Description,
- Filename = Path.GetFileName(_datPath),
- Homepage = datFile.Header.Homepage,
- Name = datFile.Header.Name,
- Sha384 = datHash,
- Version = datFile.Header.Version,
- CreatedOn = DateTime.UtcNow,
- UpdatedOn = DateTime.UtcNow,
- Category = _category
- };
-
- ctx.RomSets.Add(romSet);
- ctx.SaveChanges();
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.CompressingDatFile
- });
-
- var datCompress = new Compression();
- datCompress.SetProgress += SetProgress;
- datCompress.SetProgressBounds += SetProgressBounds;
- datCompress.CompressFile(_datPath, compressedDatPath);
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.GettingMachineNames
- });
-
- List machineNames =
- (from value in datFile.Items.Values from item in value select item.Machine.Name).Distinct().
- ToList();
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.AddingMachines
- });
-
- SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs
- {
- Minimum = 0,
- Maximum = machineNames.Count
- });
-
- int position = 0;
- Dictionary machines = new Dictionary();
-
- foreach(string name in machineNames)
- {
- SetProgress?.Invoke(this, new ProgressEventArgs
+ if(pendingFilesBySha512.TryGetValue(rom.SHA512, out file))
{
- Value = position
- });
+ if(file.Size != uSize)
+ {
+ hashCollision = true;
+ file = null;
+ }
+ }
+ }
- var machine = new Machine
+ if(rom.SHA384 != null && file == null)
+ {
+ if(pendingFilesBySha384.TryGetValue(rom.SHA384, out file))
{
- Name = name,
- RomSetId = romSet.Id,
+ if(file.Size != uSize)
+ {
+ hashCollision = true;
+ file = null;
+ }
+ }
+ }
+
+ if(rom.SHA256 != null && file == null)
+ {
+ if(pendingFilesBySha256.TryGetValue(rom.SHA256, out file))
+ {
+ if(file.Size != uSize)
+ {
+ hashCollision = true;
+ file = null;
+ }
+ }
+ }
+
+ if(rom.SHA1 != null && file == null)
+ {
+ if(pendingFilesBySha1.TryGetValue(rom.SHA1, out file))
+ {
+ if(file.Size != uSize)
+ {
+ hashCollision = true;
+ file = null;
+ }
+ }
+ }
+
+ if(rom.MD5 != null && file == null)
+ {
+ if(pendingFilesByMd5.TryGetValue(rom.MD5, out file))
+ {
+ if(file.Size != uSize)
+ {
+ hashCollision = true;
+ file = null;
+ }
+ }
+ }
+
+ if(rom.CRC != null && file == null)
+ {
+ if(pendingFilesByCrc.TryGetValue(rom.CRC, out file))
+ {
+ if(file.Size != uSize)
+ {
+ hashCollision = true;
+ file = null;
+ }
+ }
+ }
+
+ if(file == null && hashCollision)
+ {
+ if(rom.SHA512 != null)
+ file = pendingFiles.FirstOrDefault(f => f.Sha512 == rom.SHA512 && f.Size == uSize);
+
+ if(file == null && rom.SHA384 != null)
+ file = pendingFiles.FirstOrDefault(f => f.Sha384 == rom.SHA384 && f.Size == uSize);
+
+ if(file == null && rom.SHA256 != null)
+ file = pendingFiles.FirstOrDefault(f => f.Sha256 == rom.SHA256 && f.Size == uSize);
+
+ if(file == null && rom.SHA1 != null)
+ file = pendingFiles.FirstOrDefault(f => f.Sha1 == rom.SHA1 && f.Size == uSize);
+
+ if(file == null && rom.MD5 != null)
+ file = pendingFiles.FirstOrDefault(f => f.Md5 == rom.MD5 && f.Size == uSize);
+
+ if(file == null && rom.CRC != null)
+ file = pendingFiles.FirstOrDefault(f => f.Crc32 == rom.CRC && f.Size == uSize);
+ }
+
+ if(file == null)
+ {
+ file = new DbFile
+ {
+ Crc32 = rom.CRC,
CreatedOn = DateTime.UtcNow,
+ Md5 = rom.MD5,
+ Sha1 = rom.SHA1,
+ Sha256 = rom.SHA256,
+ Sha384 = rom.SHA384,
+ Sha512 = rom.SHA512,
+ Size = uSize,
UpdatedOn = DateTime.UtcNow
};
- machines[name] = machine;
-
- position++;
+ newFiles.Add(file);
}
- SetMessage?.Invoke(this, new MessageEventArgs
+ if(string.IsNullOrEmpty(file.Crc32) && !string.IsNullOrEmpty(rom.CRC))
{
- Message = Localization.SavingChangesToDatabase
- });
-
- SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
-
- ctx.BulkInsert(machines.Values.ToList(), b => b.SetOutputIdentity = true);
- ctx.SaveChanges();
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.RetrievingRomsAndDisks
- });
-
- List roms = new List();
- List disks = new List();
- List medias = new List();
-
- string tmpRomCrc32Table = Guid.NewGuid().ToString();
- string tmpRomMd5Table = Guid.NewGuid().ToString();
- string tmpRomSha1Table = Guid.NewGuid().ToString();
- string tmpRomSha256Table = Guid.NewGuid().ToString();
- string tmpRomSha384Table = Guid.NewGuid().ToString();
- string tmpRomSha512Table = Guid.NewGuid().ToString();
- string tmpDiskMd5Table = Guid.NewGuid().ToString();
- string tmpDiskSha1Table = Guid.NewGuid().ToString();
- string tmpMediaMd5Table = Guid.NewGuid().ToString();
- string tmpMediaSha1Table = Guid.NewGuid().ToString();
- string tmpMediaSha256Table = Guid.NewGuid().ToString();
-
- bool romsHaveCrc = false;
- bool romsHaveMd5 = false;
- bool romsHaveSha1 = false;
- bool romsHaveSha256 = false;
- bool romsHaveSha384 = false;
- bool romsHaveSha512 = false;
- bool disksHaveMd5 = false;
- bool disksHaveSha1 = false;
- bool mediasHaveMd5 = false;
- bool mediasHaveSha1 = false;
- bool mediasHaveSha256 = false;
-
- DbConnection dbConnection = ctx.Database.GetDbConnection();
- dbConnection.Open();
-
- position = 0;
-
- SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs
- {
- Minimum = 0,
- Maximum = datFile.Items.Values.Count
- });
-
- using(DbTransaction dbTransaction = dbConnection.BeginTransaction())
- {
- DbCommand dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"CREATE TABLE \"{tmpRomCrc32Table}\" (\"Size\" INTEGER NOT NULL, \"Crc32\" TEXT NOT NULL);";
-
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"CREATE TABLE \"{tmpRomMd5Table}\" (\"Size\" INTEGER NOT NULL, \"Md5\" TEXT NOT NULL);";
-
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"CREATE TABLE \"{tmpRomSha1Table}\" (\"Size\" INTEGER NOT NULL, \"Sha1\" TEXT NOT NULL);";
-
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"CREATE TABLE \"{tmpRomSha256Table}\" (\"Size\" INTEGER NOT NULL, \"Sha256\" TEXT NOT NULL);";
-
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"CREATE TABLE \"{tmpRomSha384Table}\" (\"Size\" INTEGER NOT NULL, \"Sha384\" TEXT NOT NULL);";
-
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"CREATE TABLE \"{tmpRomSha512Table}\" (\"Size\" INTEGER NOT NULL, \"Sha512\" TEXT NOT NULL);";
-
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
- dbcc.CommandText = $"CREATE TABLE \"{tmpDiskMd5Table}\" (\"Md5\" TEXT NOT NULL);";
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
- dbcc.CommandText = $"CREATE TABLE \"{tmpDiskSha1Table}\" (\"Sha1\" TEXT NOT NULL);";
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
- dbcc.CommandText = $"CREATE TABLE \"{tmpMediaMd5Table}\" (\"Md5\" TEXT NOT NULL);";
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
- dbcc.CommandText = $"CREATE TABLE \"{tmpMediaSha1Table}\" (\"Sha1\" TEXT NOT NULL);";
- dbcc.ExecuteNonQuery();
- dbcc = dbConnection.CreateCommand();
- dbcc.CommandText = $"CREATE TABLE \"{tmpMediaSha256Table}\" (\"Sha256\" TEXT NOT NULL);";
- dbcc.ExecuteNonQuery();
-
- foreach(List values in datFile.Items.Values)
- {
- SetProgress?.Invoke(this, new ProgressEventArgs
- {
- Value = position
- });
-
- foreach(DatItem item in values)
- {
- switch(item)
- {
- case Rom rom:
- if(rom.CRC != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpRomCrc32Table}\" (\"Size\", \"Crc32\") VALUES (\"{(ulong)rom.Size}\", \"{rom.CRC}\");";
-
- dbcc.ExecuteNonQuery();
-
- romsHaveCrc = true;
- }
-
- if(rom.MD5 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpRomMd5Table}\" (\"Size\", \"Md5\") VALUES (\"{(ulong)rom.Size}\", \"{rom.MD5}\");";
-
- dbcc.ExecuteNonQuery();
-
- romsHaveMd5 = true;
- }
-
- if(rom.SHA1 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpRomSha1Table}\" (\"Size\", \"Sha1\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA1}\");";
-
- dbcc.ExecuteNonQuery();
-
- romsHaveSha1 = true;
- }
-
- if(rom.SHA256 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpRomSha256Table}\" (\"Size\", \"Sha256\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA256}\");";
-
- dbcc.ExecuteNonQuery();
-
- romsHaveSha256 = true;
- }
-
- if(rom.SHA384 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpRomSha384Table}\" (\"Size\", \"Sha384\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA384}\");";
-
- dbcc.ExecuteNonQuery();
-
- romsHaveSha384 = true;
- }
-
- if(rom.SHA512 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpRomSha512Table}\" (\"Size\", \"Sha512\") VALUES (\"{(ulong)rom.Size}\", \"{rom.SHA512}\");";
-
- dbcc.ExecuteNonQuery();
-
- romsHaveSha512 = true;
- }
-
- roms.Add(rom);
-
- continue;
- case Disk disk:
- if(disk.MD5 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpDiskMd5Table}\" (\"Md5\") VALUES (\"{disk.MD5}\");";
-
- dbcc.ExecuteNonQuery();
-
- disksHaveMd5 = true;
- }
-
- if(disk.SHA1 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpDiskSha1Table}\" (\"Sha1\") VALUES (\"{disk.SHA1}\");";
-
- dbcc.ExecuteNonQuery();
-
- disksHaveSha1 = true;
- }
-
- disks.Add(disk);
-
- continue;
- case Media media:
- if(media.MD5 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpMediaMd5Table}\" (\"Md5\") VALUES (\"{media.MD5}\");";
-
- dbcc.ExecuteNonQuery();
-
- mediasHaveMd5 = true;
- }
-
- if(media.SHA1 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpMediaSha1Table}\" (\"Sha1\") VALUES (\"{media.SHA1}\");";
-
- dbcc.ExecuteNonQuery();
-
- mediasHaveSha1 = true;
- }
-
- if(media.SHA256 != null)
- {
- dbcc = dbConnection.CreateCommand();
-
- dbcc.CommandText =
- $"INSERT INTO \"{tmpMediaSha256Table}\" (\"Sha256\") VALUES (\"{media.SHA256}\");";
-
- dbcc.ExecuteNonQuery();
-
- mediasHaveSha256 = true;
- }
-
- medias.Add(media);
-
- continue;
- }
- }
-
- position++;
- }
-
- SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
-
- dbTransaction.Commit();
+ file.Crc32 = rom.CRC;
+ file.UpdatedOn = DateTime.UtcNow;
}
- List pendingFilesByCrcList = romsHaveCrc ? ctx.Files.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomCrc32Table}] AS t WHERE f.Crc32 = t.Crc32 AND f.Size = t.Size").
- ToList() : new List();
-
- List pendingFilesByMd5List = romsHaveMd5 ? ctx.Files.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomMd5Table}] AS t WHERE f.Md5 = t.Md5 AND f.Size = t.Size").
- ToList() : new List();
-
- List pendingFilesBySha1List = romsHaveSha1 ? ctx.Files.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha1Table}] AS t WHERE f.Sha1 = t.Sha1 AND f.Size = t.Size").
- ToList() : new List();
-
- List pendingFilesBySha256List = romsHaveSha256 ? ctx.Files.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha256Table}] AS t WHERE f.Sha256 = t.Sha256 AND f.Size = t.Size").
- ToList() : new List();
-
- List pendingFilesBySha384List = romsHaveSha384 ? ctx.Files.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha384Table}] AS t WHERE f.Sha384 = t.Sha384 AND f.Size = t.Size").
- ToList() : new List();
-
- List pendingFilesBySha512List = romsHaveSha512 ? ctx.Files.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Files AS f, [{tmpRomSha512Table}] AS t WHERE f.Sha512 = t.Sha512 AND f.Size = t.Size").
- ToList() : new List();
-
- Dictionary pendingDisksByMd5 = disksHaveMd5 ? ctx.Disks.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Disks AS f, [{tmpDiskMd5Table}] AS t WHERE f.Md5 = t.Md5").
- ToDictionary(f => f.Md5)
- : new Dictionary();
-
- Dictionary pendingDisksBySha1 = disksHaveSha1 ? ctx.Disks.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Disks AS f, [{tmpDiskSha1Table}] AS t WHERE f.Sha1 = t.Sha1").
- ToDictionary(f => f.Sha1)
- : new Dictionary();
-
- Dictionary pendingMediasByMd5 = mediasHaveMd5 ? ctx.Medias.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Medias AS f, [{tmpMediaMd5Table}] AS t WHERE f.Md5 = t.Md5").
- ToDictionary(f => f.Md5)
- : new Dictionary();
-
- Dictionary pendingMediasBySha1 = mediasHaveSha1 ? ctx.Medias.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Medias AS f, [{tmpMediaSha1Table}] AS t WHERE f.Sha1 = t.Sha1").
- ToDictionary(f => f.Sha1)
- : new Dictionary();
-
- Dictionary pendingMediasBySha256 = mediasHaveSha256 ? ctx.Medias.
- FromSqlRaw($"SELECT DISTINCT f.* FROM Medias AS f, [{tmpMediaSha256Table}] AS t WHERE f.Sha256 = t.Sha256").
- ToDictionary(f => f.Sha256)
- : new Dictionary();
-
- Dictionary pendingFilesByCrc = new Dictionary();
- Dictionary pendingFilesByMd5 = new Dictionary();
- Dictionary pendingFilesBySha1 = new Dictionary();
- Dictionary pendingFilesBySha256 = new Dictionary();
- Dictionary pendingFilesBySha384 = new Dictionary();
- Dictionary pendingFilesBySha512 = new Dictionary();
- List pendingFiles = new List();
-
- // This is because of hash collisions.
- foreach(DbFile item in pendingFilesByCrcList)
- if(pendingFilesByCrc.ContainsKey(item.Crc32))
- pendingFiles.Add(item);
- else
- pendingFilesByCrc[item.Crc32] = item;
-
- foreach(DbFile item in pendingFilesByMd5List)
- if(pendingFilesByMd5.ContainsKey(item.Md5))
- pendingFiles.Add(item);
- else
- pendingFilesByMd5[item.Md5] = item;
-
- foreach(DbFile item in pendingFilesBySha1List)
- if(pendingFilesBySha1.ContainsKey(item.Sha1))
- pendingFiles.Add(item);
- else
- pendingFilesBySha1[item.Sha1] = item;
-
- foreach(DbFile item in pendingFilesBySha256List)
- if(pendingFilesBySha256.ContainsKey(item.Sha256))
- pendingFiles.Add(item);
- else
- pendingFilesBySha256[item.Sha256] = item;
-
- foreach(DbFile item in pendingFilesBySha384List)
- if(pendingFilesBySha384.ContainsKey(item.Sha384))
- pendingFiles.Add(item);
- else
- pendingFilesBySha384[item.Sha384] = item;
-
- foreach(DbFile item in pendingFilesBySha512List)
- if(pendingFilesBySha512.ContainsKey(item.Sha512))
- pendingFiles.Add(item);
- else
- pendingFilesBySha512[item.Sha512] = item;
-
- // Clear some memory
- pendingFilesByCrcList.Clear();
- pendingFilesByMd5List.Clear();
- pendingFilesBySha1List.Clear();
- pendingFilesBySha256List.Clear();
- pendingFilesBySha384List.Clear();
- pendingFilesBySha512List.Clear();
-
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomCrc32Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomMd5Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha1Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha256Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha384Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpRomSha512Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpDiskMd5Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpDiskSha1Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpMediaMd5Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpMediaSha1Table}]");
- ctx.Database.ExecuteSqlRaw($"DROP TABLE [{tmpMediaSha256Table}]");
-
- SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs
+ if(string.IsNullOrEmpty(file.Md5) && !string.IsNullOrEmpty(rom.MD5))
{
- Minimum = 0,
- Maximum = roms.Count
- });
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.AddingRoms
- });
-
- position = 0;
-
- List newFiles = new List();
- List newFilesByMachine = new List();
-
- foreach(Rom rom in roms)
- {
- bool hashCollision = false;
-
- SetProgress?.Invoke(this, new ProgressEventArgs
- {
- Value = position
- });
-
- if(!machines.TryGetValue(rom.Machine.Name, out Machine machine))
- {
- ErrorOccurred?.Invoke(this, new ErrorEventArgs
- {
- Message = Localization.FoundRomWithoutMachine
- });
-
- return;
- }
-
- ulong uSize = (ulong)rom.Size;
-
- DbFile file = null;
-
- if(rom.SHA512 != null)
- if(pendingFilesBySha512.TryGetValue(rom.SHA512, out file))
- if(file.Size != uSize)
- {
- hashCollision = true;
- file = null;
- }
-
- if(rom.SHA384 != null &&
- file == null)
- if(pendingFilesBySha384.TryGetValue(rom.SHA384, out file))
- if(file.Size != uSize)
- {
- hashCollision = true;
- file = null;
- }
-
- if(rom.SHA256 != null &&
- file == null)
- if(pendingFilesBySha256.TryGetValue(rom.SHA256, out file))
- if(file.Size != uSize)
- {
- hashCollision = true;
- file = null;
- }
-
- if(rom.SHA1 != null &&
- file == null)
- if(pendingFilesBySha1.TryGetValue(rom.SHA1, out file))
- if(file.Size != uSize)
- {
- hashCollision = true;
- file = null;
- }
-
- if(rom.MD5 != null &&
- file == null)
- if(pendingFilesByMd5.TryGetValue(rom.MD5, out file))
- if(file.Size != uSize)
- {
- hashCollision = true;
- file = null;
- }
-
- if(rom.CRC != null &&
- file == null)
- if(pendingFilesByCrc.TryGetValue(rom.CRC, out file))
- if(file.Size != uSize)
- {
- hashCollision = true;
- file = null;
- }
-
- if(file == null && hashCollision)
- {
- if(rom.SHA512 != null)
- file = pendingFiles.FirstOrDefault(f => f.Sha512 == rom.SHA512 && f.Size == uSize);
-
- if(file == null &&
- rom.SHA384 != null)
- file = pendingFiles.FirstOrDefault(f => f.Sha384 == rom.SHA384 && f.Size == uSize);
-
- if(file == null &&
- rom.SHA256 != null)
- file = pendingFiles.FirstOrDefault(f => f.Sha256 == rom.SHA256 && f.Size == uSize);
-
- if(file == null &&
- rom.SHA1 != null)
- file = pendingFiles.FirstOrDefault(f => f.Sha1 == rom.SHA1 && f.Size == uSize);
-
- if(file == null &&
- rom.MD5 != null)
- file = pendingFiles.FirstOrDefault(f => f.Md5 == rom.MD5 && f.Size == uSize);
-
- if(file == null &&
- rom.CRC != null)
- file = pendingFiles.FirstOrDefault(f => f.Crc32 == rom.CRC && f.Size == uSize);
- }
-
- if(file == null)
- {
- file = new DbFile
- {
- Crc32 = rom.CRC,
- CreatedOn = DateTime.UtcNow,
- Md5 = rom.MD5,
- Sha1 = rom.SHA1,
- Sha256 = rom.SHA256,
- Sha384 = rom.SHA384,
- Sha512 = rom.SHA512,
- Size = uSize,
- UpdatedOn = DateTime.UtcNow
- };
-
- newFiles.Add(file);
- }
-
- if(string.IsNullOrEmpty(file.Crc32) &&
- !string.IsNullOrEmpty(rom.CRC))
- {
- file.Crc32 = rom.CRC;
- file.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(file.Md5) &&
- !string.IsNullOrEmpty(rom.MD5))
- {
- file.Md5 = rom.MD5;
- file.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(file.Sha1) &&
- !string.IsNullOrEmpty(rom.SHA1))
- {
- file.Sha1 = rom.SHA1;
- file.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(file.Sha256) &&
- !string.IsNullOrEmpty(rom.SHA256))
- {
- file.Sha256 = rom.SHA256;
- file.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(file.Sha384) &&
- !string.IsNullOrEmpty(rom.SHA384))
- {
- file.Sha384 = rom.SHA384;
- file.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(file.Sha512) &&
- !string.IsNullOrEmpty(rom.SHA512))
- {
- file.Sha512 = rom.SHA512;
- file.UpdatedOn = DateTime.UtcNow;
- }
-
- DateTime? fileModificationDate = null;
-
- if(!string.IsNullOrEmpty(rom.Date))
- {
- rom.Date = rom.Date.Replace("/", "\\");
-
- if(DateTime.TryParseExact(rom.Date, @"yyyy\\M\\d H:mm", CultureInfo.InvariantCulture,
- DateTimeStyles.AssumeUniversal, out DateTime date))
- fileModificationDate = date;
- }
-
- string filename;
- string path = null;
-
- if(rom.Name.Contains('\\'))
- {
- filename = Path.GetFileName(rom.Name.Replace('\\', '/'));
- path = Path.GetDirectoryName(rom.Name.Replace('\\', '/'));
- }
- else if(rom.Name.Contains('/'))
- {
- filename = Path.GetFileName(rom.Name);
- path = Path.GetDirectoryName(rom.Name);
- }
- else
- filename = rom.Name;
-
- newFilesByMachine.Add(new FileByMachine
- {
- File = file,
- Machine = machine,
- Name = filename,
- FileLastModification = fileModificationDate,
- Path = path
- });
-
- if(hashCollision)
- pendingFiles.Add(file);
- else if(file.Sha512 != null)
- pendingFilesBySha512[file.Sha512] = file;
- else if(file.Sha384 != null)
- pendingFilesBySha384[file.Sha384] = file;
- else if(file.Sha256 != null)
- pendingFilesBySha256[file.Sha256] = file;
- else if(file.Sha1 != null)
- pendingFilesBySha1[file.Sha1] = file;
- else if(file.Md5 != null)
- pendingFilesByMd5[file.Md5] = file;
- else if(file.Crc32 != null)
- pendingFilesByCrc[file.Crc32] = file;
-
- position++;
+ file.Md5 = rom.MD5;
+ file.UpdatedOn = DateTime.UtcNow;
}
- SetMessage?.Invoke(this, new MessageEventArgs
+ if(string.IsNullOrEmpty(file.Sha1) && !string.IsNullOrEmpty(rom.SHA1))
{
- Message = Localization.SavingChangesToDatabase
- });
-
- SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
-
- ctx.BulkInsert(newFiles, b => b.SetOutputIdentity = true);
-
- foreach(FileByMachine fbm in newFilesByMachine)
- {
- fbm.FileId = fbm.File.Id;
- fbm.MachineId = fbm.Machine.Id;
+ file.Sha1 = rom.SHA1;
+ file.UpdatedOn = DateTime.UtcNow;
}
- ctx.BulkInsert(newFilesByMachine);
-
- ctx.SaveChanges();
-
- pendingFilesBySha512.Clear();
- pendingFilesBySha384.Clear();
- pendingFilesBySha256.Clear();
- pendingFilesBySha1.Clear();
- pendingFilesByMd5.Clear();
- pendingFilesByCrc.Clear();
- pendingFiles.Clear();
- newFiles.Clear();
- newFilesByMachine.Clear();
-
- SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs
+ if(string.IsNullOrEmpty(file.Sha256) && !string.IsNullOrEmpty(rom.SHA256))
{
- Minimum = 0,
- Maximum = disks.Count
- });
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.AddingDisks
- });
-
- position = 0;
-
- List newDisks = new List();
- List newDisksByMachine = new List();
-
- foreach(Disk disk in disks)
- {
- SetProgress?.Invoke(this, new ProgressEventArgs
- {
- Value = position
- });
-
- if(!machines.TryGetValue(disk.Machine.Name, out Machine machine))
- {
- ErrorOccurred?.Invoke(this, new ErrorEventArgs
- {
- Message = Localization.FoundDiskWithoutMachine
- });
-
- return;
- }
-
- if(disk.MD5 == null &&
- disk.SHA1 == null)
- {
- position++;
-
- continue;
- }
-
- DbDisk dbDisk = null;
-
- if(disk.SHA1 != null &&
- dbDisk == null)
- pendingDisksBySha1.TryGetValue(disk.SHA1, out dbDisk);
-
- if(disk.MD5 != null &&
- dbDisk == null)
- pendingDisksByMd5.TryGetValue(disk.MD5, out dbDisk);
-
- if(dbDisk == null)
- {
- dbDisk = new DbDisk
- {
- CreatedOn = DateTime.UtcNow,
- Md5 = disk.MD5,
- Sha1 = disk.SHA1,
- UpdatedOn = DateTime.UtcNow
- };
-
- newDisks.Add(dbDisk);
- }
-
- if(string.IsNullOrEmpty(dbDisk.Md5) &&
- !string.IsNullOrEmpty(disk.MD5))
- {
- dbDisk.Md5 = disk.MD5;
- dbDisk.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(dbDisk.Sha1) &&
- !string.IsNullOrEmpty(disk.SHA1))
- {
- dbDisk.Sha1 = disk.SHA1;
- dbDisk.UpdatedOn = DateTime.UtcNow;
- }
-
- newDisksByMachine.Add(new DiskByMachine
- {
- Disk = dbDisk,
- Machine = machine,
- Name = disk.Name
- });
-
- if(dbDisk.Sha1 != null)
- pendingDisksBySha1[dbDisk.Sha1] = dbDisk;
-
- if(dbDisk.Md5 != null)
- pendingDisksByMd5[dbDisk.Md5] = dbDisk;
-
- position++;
+ file.Sha256 = rom.SHA256;
+ file.UpdatedOn = DateTime.UtcNow;
}
- SetMessage?.Invoke(this, new MessageEventArgs
+ if(string.IsNullOrEmpty(file.Sha384) && !string.IsNullOrEmpty(rom.SHA384))
{
- Message = Localization.SavingChangesToDatabase
- });
-
- SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
-
- ctx.BulkInsert(newDisks, b => b.SetOutputIdentity = true);
-
- foreach(DiskByMachine dbm in newDisksByMachine)
- {
- dbm.DiskId = dbm.Disk.Id;
- dbm.MachineId = dbm.Machine.Id;
+ file.Sha384 = rom.SHA384;
+ file.UpdatedOn = DateTime.UtcNow;
}
- ctx.BulkInsert(newDisksByMachine);
-
- ctx.SaveChanges();
-
- pendingDisksBySha1.Clear();
- pendingDisksByMd5.Clear();
- newDisks.Clear();
- newDisksByMachine.Clear();
-
- SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs
+ if(string.IsNullOrEmpty(file.Sha512) && !string.IsNullOrEmpty(rom.SHA512))
{
- Minimum = 0,
- Maximum = medias.Count
- });
-
- SetMessage?.Invoke(this, new MessageEventArgs
- {
- Message = Localization.AddingMedias
- });
-
- position = 0;
-
- List newMedias = new List();
- List newMediasByMachine = new List();
-
- foreach(Media media in medias)
- {
- SetProgress?.Invoke(this, new ProgressEventArgs
- {
- Value = position
- });
-
- if(!machines.TryGetValue(media.Machine.Name, out Machine machine))
- {
- ErrorOccurred?.Invoke(this, new ErrorEventArgs
- {
- Message = Localization.FoundMediaWithoutMachine
- });
-
- return;
- }
-
- if(media.MD5 == null &&
- media.SHA1 == null &&
- media.SHA256 == null)
- {
- position++;
-
- continue;
- }
-
- DbMedia dbMedia = null;
-
- if(media.SHA256 != null &&
- dbMedia == null)
- pendingMediasBySha256.TryGetValue(media.SHA256, out dbMedia);
-
- if(media.SHA1 != null &&
- dbMedia == null)
- pendingMediasBySha1.TryGetValue(media.SHA1, out dbMedia);
-
- if(media.MD5 != null &&
- dbMedia == null)
- pendingMediasByMd5.TryGetValue(media.MD5, out dbMedia);
-
- // TODO: SpamSum
- if(dbMedia == null)
- {
- dbMedia = new DbMedia
- {
- CreatedOn = DateTime.UtcNow,
- Md5 = media.MD5,
- Sha1 = media.SHA1,
- Sha256 = media.SHA256,
- UpdatedOn = DateTime.UtcNow
- };
-
- newMedias.Add(dbMedia);
- }
-
- if(string.IsNullOrEmpty(dbMedia.Md5) &&
- !string.IsNullOrEmpty(media.MD5))
- {
- dbMedia.Md5 = media.MD5;
- dbMedia.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(dbMedia.Sha1) &&
- !string.IsNullOrEmpty(media.SHA1))
- {
- dbMedia.Sha1 = media.SHA1;
- dbMedia.UpdatedOn = DateTime.UtcNow;
- }
-
- if(string.IsNullOrEmpty(dbMedia.Sha256) &&
- !string.IsNullOrEmpty(media.SHA256))
- {
- dbMedia.Sha256 = media.SHA256;
- dbMedia.UpdatedOn = DateTime.UtcNow;
- }
-
- newMediasByMachine.Add(new MediaByMachine
- {
- Media = dbMedia,
- Machine = machine,
- Name = media.Name
- });
-
- if(dbMedia.Sha256 != null)
- pendingMediasBySha256[dbMedia.Sha256] = dbMedia;
-
- if(dbMedia.Sha1 != null)
- pendingMediasBySha1[dbMedia.Sha1] = dbMedia;
-
- if(dbMedia.Md5 != null)
- pendingMediasByMd5[dbMedia.Md5] = dbMedia;
-
- position++;
+ file.Sha512 = rom.SHA512;
+ file.UpdatedOn = DateTime.UtcNow;
}
- SetMessage?.Invoke(this, new MessageEventArgs
+ DateTime? fileModificationDate = null;
+
+ if(!string.IsNullOrEmpty(rom.Date))
{
- Message = Localization.SavingChangesToDatabase
- });
+ rom.Date = rom.Date.Replace("/", "\\");
- SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
-
- ctx.BulkInsert(newMedias, b => b.SetOutputIdentity = true);
-
- foreach(MediaByMachine mbm in newMediasByMachine)
- {
- mbm.MediaId = mbm.Media.Id;
- mbm.MachineId = mbm.Machine.Id;
+ if(DateTime.TryParseExact(rom.Date,
+ @"yyyy\\M\\d H:mm",
+ CultureInfo.InvariantCulture,
+ DateTimeStyles.AssumeUniversal,
+ out DateTime date))
+ fileModificationDate = date;
}
- ctx.BulkInsert(newMediasByMachine);
+ string filename;
+ string path = null;
- ctx.SaveChanges();
-
- pendingMediasBySha256.Clear();
- pendingMediasBySha1.Clear();
- pendingMediasByMd5.Clear();
- newMedias.Clear();
- newMediasByMachine.Clear();
-
- RomSetStat stats = ctx.RomSets.Where(r => r.Id == romSet.Id).Select(r => new RomSetStat
+ if(rom.Name.Contains('\\'))
{
- 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();
-
- RomSetStat oldStats = ctx.RomSetStats.Find(stats.RomSetId);
-
- if(oldStats != null)
- ctx.Remove(oldStats);
-
- ctx.RomSetStats.Add(stats);
-
- ctx.SaveChanges();
-
- WorkFinished?.Invoke(this, new MessageEventArgs
+ filename = Path.GetFileName(rom.Name.Replace('\\', '/'));
+ path = Path.GetDirectoryName(rom.Name.Replace('\\', '/'));
+ }
+ else if(rom.Name.Contains('/'))
{
- Message = string.Format(Localization.DatImportSuccess, stats.TotalMachines, stats.TotalRoms)
+ filename = Path.GetFileName(rom.Name);
+ path = Path.GetDirectoryName(rom.Name);
+ }
+ else
+ filename = rom.Name;
+
+ newFilesByMachine.Add(new FileByMachine
+ {
+ File = file,
+ Machine = machine,
+ Name = filename,
+ FileLastModification = fileModificationDate,
+ Path = path
});
- RomSetAdded?.Invoke(this, new RomSetEventArgs
- {
- RomSet = 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
- }
- });
+ if(hashCollision)
+ pendingFiles.Add(file);
+ else if(file.Sha512 != null)
+ pendingFilesBySha512[file.Sha512] = file;
+ else if(file.Sha384 != null)
+ pendingFilesBySha384[file.Sha384] = file;
+ else if(file.Sha256 != null)
+ pendingFilesBySha256[file.Sha256] = file;
+ else if(file.Sha1 != null)
+ pendingFilesBySha1[file.Sha1] = file;
+ else if(file.Md5 != null)
+ pendingFilesByMd5[file.Md5] = file;
+ else if(file.Crc32 != null) pendingFilesByCrc[file.Crc32] = file;
+
+ position++;
}
- catch(Exception e)
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.SavingChangesToDatabase
+ });
+
+ SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
+
+ ctx.BulkInsert(newFiles, b => b.SetOutputIdentity = true);
+
+ foreach(FileByMachine fbm in newFilesByMachine)
{
- if(Debugger.IsAttached)
- throw;
-
- ErrorOccurred?.Invoke(this, new ErrorEventArgs
- {
- Message = Localization.UnhandledException
- });
+ fbm.FileId = fbm.File.Id;
+ fbm.MachineId = fbm.Machine.Id;
}
+
+ ctx.BulkInsert(newFilesByMachine);
+
+ ctx.SaveChanges();
+
+ pendingFilesBySha512.Clear();
+ pendingFilesBySha384.Clear();
+ pendingFilesBySha256.Clear();
+ pendingFilesBySha1.Clear();
+ pendingFilesByMd5.Clear();
+ pendingFilesByCrc.Clear();
+ pendingFiles.Clear();
+ newFiles.Clear();
+ newFilesByMachine.Clear();
+
+ SetProgressBounds?.Invoke(this,
+ new ProgressBoundsEventArgs
+ {
+ Minimum = 0,
+ Maximum = disks.Count
+ });
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.AddingDisks
+ });
+
+ position = 0;
+
+ var newDisks = new List();
+ var newDisksByMachine = new List();
+
+ foreach(Disk disk in disks)
+ {
+ SetProgress?.Invoke(this,
+ new ProgressEventArgs
+ {
+ Value = position
+ });
+
+ if(!machines.TryGetValue(disk.Machine.Name, out Machine machine))
+ {
+ ErrorOccurred?.Invoke(this,
+ new ErrorEventArgs
+ {
+ Message = Localization.FoundDiskWithoutMachine
+ });
+
+ return;
+ }
+
+ if(disk.MD5 == null && disk.SHA1 == null)
+ {
+ position++;
+
+ continue;
+ }
+
+ DbDisk dbDisk = null;
+
+ if(disk.SHA1 != null && dbDisk == null) pendingDisksBySha1.TryGetValue(disk.SHA1, out dbDisk);
+
+ if(disk.MD5 != null && dbDisk == null) pendingDisksByMd5.TryGetValue(disk.MD5, out dbDisk);
+
+ if(dbDisk == null)
+ {
+ dbDisk = new DbDisk
+ {
+ CreatedOn = DateTime.UtcNow,
+ Md5 = disk.MD5,
+ Sha1 = disk.SHA1,
+ UpdatedOn = DateTime.UtcNow
+ };
+
+ newDisks.Add(dbDisk);
+ }
+
+ if(string.IsNullOrEmpty(dbDisk.Md5) && !string.IsNullOrEmpty(disk.MD5))
+ {
+ dbDisk.Md5 = disk.MD5;
+ dbDisk.UpdatedOn = DateTime.UtcNow;
+ }
+
+ if(string.IsNullOrEmpty(dbDisk.Sha1) && !string.IsNullOrEmpty(disk.SHA1))
+ {
+ dbDisk.Sha1 = disk.SHA1;
+ dbDisk.UpdatedOn = DateTime.UtcNow;
+ }
+
+ newDisksByMachine.Add(new DiskByMachine
+ {
+ Disk = dbDisk,
+ Machine = machine,
+ Name = disk.Name
+ });
+
+ if(dbDisk.Sha1 != null) pendingDisksBySha1[dbDisk.Sha1] = dbDisk;
+
+ if(dbDisk.Md5 != null) pendingDisksByMd5[dbDisk.Md5] = dbDisk;
+
+ position++;
+ }
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.SavingChangesToDatabase
+ });
+
+ SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
+
+ ctx.BulkInsert(newDisks, b => b.SetOutputIdentity = true);
+
+ foreach(DiskByMachine dbm in newDisksByMachine)
+ {
+ dbm.DiskId = dbm.Disk.Id;
+ dbm.MachineId = dbm.Machine.Id;
+ }
+
+ ctx.BulkInsert(newDisksByMachine);
+
+ ctx.SaveChanges();
+
+ pendingDisksBySha1.Clear();
+ pendingDisksByMd5.Clear();
+ newDisks.Clear();
+ newDisksByMachine.Clear();
+
+ SetProgressBounds?.Invoke(this,
+ new ProgressBoundsEventArgs
+ {
+ Minimum = 0,
+ Maximum = medias.Count
+ });
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.AddingMedias
+ });
+
+ position = 0;
+
+ var newMedias = new List();
+ var newMediasByMachine = new List();
+
+ foreach(Media media in medias)
+ {
+ SetProgress?.Invoke(this,
+ new ProgressEventArgs
+ {
+ Value = position
+ });
+
+ if(!machines.TryGetValue(media.Machine.Name, out Machine machine))
+ {
+ ErrorOccurred?.Invoke(this,
+ new ErrorEventArgs
+ {
+ Message = Localization.FoundMediaWithoutMachine
+ });
+
+ return;
+ }
+
+ if(media.MD5 == null && media.SHA1 == null && media.SHA256 == null)
+ {
+ position++;
+
+ continue;
+ }
+
+ DbMedia dbMedia = null;
+
+ if(media.SHA256 != null && dbMedia == null)
+ pendingMediasBySha256.TryGetValue(media.SHA256, out dbMedia);
+
+ if(media.SHA1 != null && dbMedia == null) pendingMediasBySha1.TryGetValue(media.SHA1, out dbMedia);
+
+ if(media.MD5 != null && dbMedia == null) pendingMediasByMd5.TryGetValue(media.MD5, out dbMedia);
+
+ // TODO: SpamSum
+ if(dbMedia == null)
+ {
+ dbMedia = new DbMedia
+ {
+ CreatedOn = DateTime.UtcNow,
+ Md5 = media.MD5,
+ Sha1 = media.SHA1,
+ Sha256 = media.SHA256,
+ UpdatedOn = DateTime.UtcNow
+ };
+
+ newMedias.Add(dbMedia);
+ }
+
+ if(string.IsNullOrEmpty(dbMedia.Md5) && !string.IsNullOrEmpty(media.MD5))
+ {
+ dbMedia.Md5 = media.MD5;
+ dbMedia.UpdatedOn = DateTime.UtcNow;
+ }
+
+ if(string.IsNullOrEmpty(dbMedia.Sha1) && !string.IsNullOrEmpty(media.SHA1))
+ {
+ dbMedia.Sha1 = media.SHA1;
+ dbMedia.UpdatedOn = DateTime.UtcNow;
+ }
+
+ if(string.IsNullOrEmpty(dbMedia.Sha256) && !string.IsNullOrEmpty(media.SHA256))
+ {
+ dbMedia.Sha256 = media.SHA256;
+ dbMedia.UpdatedOn = DateTime.UtcNow;
+ }
+
+ newMediasByMachine.Add(new MediaByMachine
+ {
+ Media = dbMedia,
+ Machine = machine,
+ Name = media.Name
+ });
+
+ if(dbMedia.Sha256 != null) pendingMediasBySha256[dbMedia.Sha256] = dbMedia;
+
+ if(dbMedia.Sha1 != null) pendingMediasBySha1[dbMedia.Sha1] = dbMedia;
+
+ if(dbMedia.Md5 != null) pendingMediasByMd5[dbMedia.Md5] = dbMedia;
+
+ position++;
+ }
+
+ SetMessage?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = Localization.SavingChangesToDatabase
+ });
+
+ SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty);
+
+ ctx.BulkInsert(newMedias, b => b.SetOutputIdentity = true);
+
+ foreach(MediaByMachine mbm in newMediasByMachine)
+ {
+ mbm.MediaId = mbm.Media.Id;
+ mbm.MachineId = mbm.Machine.Id;
+ }
+
+ ctx.BulkInsert(newMediasByMachine);
+
+ ctx.SaveChanges();
+
+ pendingMediasBySha256.Clear();
+ pendingMediasBySha1.Clear();
+ pendingMediasByMd5.Clear();
+ newMedias.Clear();
+ newMediasByMachine.Clear();
+
+ 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();
+
+ RomSetStat oldStats = ctx.RomSetStats.Find(stats.RomSetId);
+
+ if(oldStats != null) ctx.Remove(oldStats);
+
+ ctx.RomSetStats.Add(stats);
+
+ ctx.SaveChanges();
+
+ WorkFinished?.Invoke(this,
+ new MessageEventArgs
+ {
+ Message = string.Format(Localization.DatImportSuccess,
+ stats.TotalMachines,
+ stats.TotalRoms)
+ });
+
+ RomSetAdded?.Invoke(this,
+ new RomSetEventArgs
+ {
+ RomSet = 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
+ }
+ });
}
+ catch(Exception e)
+ {
+ if(Debugger.IsAttached) throw;
- // TODO: Cancel and get back
- public void Abort() => _aborted = true;
-
- public event EventHandler SetIndeterminateProgress;
- public event EventHandler WorkFinished;
- public event EventHandler ErrorOccurred;
- public event EventHandler SetProgressBounds;
- public event EventHandler SetProgress;
- public event EventHandler SetMessage;
- public event EventHandler RomSetAdded;
+ ErrorOccurred?.Invoke(this,
+ new ErrorEventArgs
+ {
+ Message = Localization.UnhandledException
+ });
+ }
}
+
+ // TODO: Cancel and get back
+ public void Abort() => _aborted = true;
+
+ public event EventHandler SetIndeterminateProgress;
+ public event EventHandler WorkFinished;
+ public event EventHandler ErrorOccurred;
+ public event EventHandler SetProgressBounds;
+ public event EventHandler SetProgress;
+ public event EventHandler SetMessage;
+ public event EventHandler RomSetAdded;
}
\ No newline at end of file
diff --git a/RomRepoMgr.Core/Workers/FileExporter.cs b/RomRepoMgr.Core/Workers/FileExporter.cs
index 31852fe..6733f79 100644
--- a/RomRepoMgr.Core/Workers/FileExporter.cs
+++ b/RomRepoMgr.Core/Workers/FileExporter.cs
@@ -13,637 +13,653 @@ using RomRepoMgr.Database.Models;
using SharpCompress.Compressors.LZMA;
using CompressionMode = SharpCompress.Compressors.CompressionMode;
-namespace RomRepoMgr.Core.Workers
+namespace RomRepoMgr.Core.Workers;
+
+public class FileExporter
{
- public class FileExporter
+ const long BUFFER_SIZE = 131072;
+ readonly string _outPath;
+ readonly long _romSetId;
+ long _filePosition;
+ Dictionary _filesByMachine;
+ long _machinePosition;
+ Machine[] _machines;
+ string _zipCurrentEntryName;
+
+ public FileExporter(long romSetId, string outPath)
{
- const long BUFFER_SIZE = 131072;
- readonly string _outPath;
- readonly long _romSetId;
- long _filePosition;
- Dictionary _filesByMachine;
- long _machinePosition;
- Machine[] _machines;
- string _zipCurrentEntryName;
+ _romSetId = romSetId;
+ _outPath = outPath;
+ }
- public FileExporter(long romSetId, string outPath)
+ public event EventHandler WorkFinished;
+ public event EventHandler SetProgressBounds;
+ public event EventHandler SetProgress;
+ public event EventHandler SetMessage;
+ public event EventHandler SetProgress2Bounds;
+ public event EventHandler