diff --git a/BizHawk.Emulation.DiscSystem/DiscHasher.cs b/BizHawk.Emulation.DiscSystem/DiscHasher.cs
index 82ef7d93f8..e553effbe9 100644
--- a/BizHawk.Emulation.DiscSystem/DiscHasher.cs
+++ b/BizHawk.Emulation.DiscSystem/DiscHasher.cs
@@ -13,55 +13,6 @@ namespace BizHawk.Emulation.DiscSystem
Disc disc;
- class SpecialCRC32
- {
- private static readonly uint[] CRC32Table;
-
- static SpecialCRC32()
- {
- CRC32Table = new uint[256];
- for (uint i = 0; i < 256; ++i)
- {
- uint crc = i;
- for (int j = 8; j > 0; --j)
- {
- if ((crc & 1) == 1)
- crc = ((crc >> 1) ^ 0xEDB88320);
- else
- crc >>= 1;
- }
- CRC32Table[i] = crc;
- }
- }
-
- uint current = 0xFFFFFFFF;
- public unsafe void Add(byte[] data, int offset, int size)
- {
- if (offset + size > data.Length)
- throw new ArgumentOutOfRangeException();
- if(offset<0)
- throw new ArgumentOutOfRangeException();
- fixed(byte* pData = data)
- for (int i = 0; i < size; i++)
- {
- byte b = pData[offset + i];
- current = CRC32Table[(current ^ b) & 0xFF] ^ (current>>8);
- }
- }
-
- byte[] smallbuf = new byte[8];
- public void Add(int data)
- {
- smallbuf[0] = (byte)((data) & 0xFF);
- smallbuf[1] = (byte)((data >> 8) & 0xFF);
- smallbuf[2] = (byte)((data >> 16) & 0xFF);
- smallbuf[3] = (byte)((data >> 24) & 0xFF);
- Add(smallbuf, 0, 4);
- }
-
- public uint Result { get { return current ^ 0xFFFFFFFF; } }
- }
-
///
/// calculates the hash for quick PSX Disc identification
///
@@ -73,7 +24,7 @@ namespace BizHawk.Emulation.DiscSystem
//the TOC isn't needed!
//but it will help detect dumps with mangled TOCs which are all too common
//
- //a special CRC32 is used to help us match redump's DB elsewhere
+ //a possibly special CRC32 is used to help us match redump's DB elsewhere
SpecialCRC32 crc = new SpecialCRC32();
byte[] buffer2352 = new byte[2352];
@@ -144,5 +95,151 @@ namespace BizHawk.Emulation.DiscSystem
}
return "no data track found";
}
+
+ ///
+ /// A stateful special CRC32 calculator
+ /// This may be absolutely standard and not special at all. I don't know, there were some differences between it and other CRC code I found in bizhawk
+ ///
+ public class SpecialCRC32
+ {
+ private static readonly uint[] CRC32Table;
+
+ static SpecialCRC32()
+ {
+ CRC32Table = new uint[256];
+ for (uint i = 0; i < 256; ++i)
+ {
+ uint crc = i;
+ for (int j = 8; j > 0; --j)
+ {
+ if ((crc & 1) == 1)
+ crc = ((crc >> 1) ^ 0xEDB88320);
+ else
+ crc >>= 1;
+ }
+ CRC32Table[i] = crc;
+ }
+ }
+
+ uint current = 0xFFFFFFFF;
+ public unsafe void Add(byte[] data, int offset, int size)
+ {
+ if (offset + size > data.Length)
+ throw new ArgumentOutOfRangeException();
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException();
+ fixed (byte* pData = data)
+ for (int i = 0; i < size; i++)
+ {
+ byte b = pData[offset + i];
+ current = CRC32Table[(current ^ b) & 0xFF] ^ (current >> 8);
+ }
+ }
+
+ byte[] smallbuf = new byte[8];
+ public void Add(int data)
+ {
+ smallbuf[0] = (byte)((data) & 0xFF);
+ smallbuf[1] = (byte)((data >> 8) & 0xFF);
+ smallbuf[2] = (byte)((data >> 16) & 0xFF);
+ smallbuf[3] = (byte)((data >> 24) & 0xFF);
+ Add(smallbuf, 0, 4);
+ }
+
+ ///
+ /// The negated output (the typical result of the CRC calculation)
+ ///
+ public uint Result { get { return current ^ 0xFFFFFFFF; } }
+
+ ///
+ /// The raw non-negated output
+ ///
+ public uint Current { get { return current; } set { current = value; } }
+
+ uint gf2_matrix_times(uint[] mat, uint vec)
+ {
+ int matIdx = 0;
+ uint sum = 0;
+ while (vec != 0)
+ {
+ if ((vec & 1) != 0)
+ sum ^= mat[matIdx];
+ vec >>= 1;
+ matIdx++;
+ }
+ return sum;
+ }
+
+ void gf2_matrix_square(uint[] square, uint[] mat)
+ {
+ int n;
+ for (n = 0; n < 32; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+ }
+
+ ///
+ /// Incorporates a pre-calculated CRC with the given length by combining crcs
+ /// It's a bit flaky, so be careful, but it works
+ ///
+ public void Incorporate(uint crc, int len)
+ {
+ current = crc32_combine(current, crc, len);
+ }
+
+ //tables used by crc32_combine
+ uint[] even, odd;
+
+ //algorithm from zlib's crc32_combine. read http://www.leapsecond.com/tools/crcomb.c for more
+ uint crc32_combine(uint crc1, uint crc2, int len2)
+ {
+ if (even == null) even = new uint[32]; // even-power-of-two zeros operator
+ if (odd == null) odd = new uint[32]; // odd-power-of-two zeros operator
+
+ // degenerate case
+ if (len2 == 0)
+ return crc1;
+
+ // put operator for one zero bit in odd
+ odd[0] = 0xedb88320; //CRC-32 polynomial
+ uint row = 1;
+ for (int n = 1; n < 32; n++)
+ {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ //put operator for two zero bits in even
+ gf2_matrix_square(even, odd);
+
+ //put operator for four zero bits in odd
+ gf2_matrix_square(odd, even);
+
+ //apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even)
+ do
+ {
+ //apply zeros operator for this bit of len2
+ gf2_matrix_square(even, odd);
+ if ((len2 & 1) != 0)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ //if no more bits set, then done
+ if (len2 == 0)
+ break;
+
+ //another iteration of the loop with odd and even swapped
+ gf2_matrix_square(odd, even);
+ if ((len2 & 1) != 0)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ //if no more bits set, then done
+ } while (len2 != 0);
+
+ //return combined crc
+ crc1 ^= crc2;
+ return crc1;
+ }
+ }
}
}
\ No newline at end of file