mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 15:44:00 +08:00
147 lines
5.3 KiB
C#
147 lines
5.3 KiB
C#
//! \file adler32.cs
|
|
//! \date Mon Jul 21 11:19:54 2014
|
|
//! \brief compute adler32 checksum
|
|
//
|
|
|
|
using System.IO;
|
|
using System;
|
|
|
|
class Adler
|
|
{
|
|
public static void Main (string[] args)
|
|
{
|
|
if (args.Length < 1)
|
|
return;
|
|
try
|
|
{
|
|
uint adler = 1;
|
|
using (var input = File.Open (args[0], FileMode.Open, FileAccess.Read))
|
|
{
|
|
var buf = new byte[65536];
|
|
for (;;)
|
|
{
|
|
int read = input.Read (buf, 0, buf.Length);
|
|
if (0 == read)
|
|
break;
|
|
adler = Adler32.Update (adler, buf, 0, read);
|
|
}
|
|
}
|
|
Console.WriteLine ("{0} => {1:X8}", args[0], adler);
|
|
}
|
|
catch (Exception X)
|
|
{
|
|
Console.Error.WriteLine (X.Message);
|
|
}
|
|
}
|
|
|
|
public sealed class Adler32
|
|
{
|
|
const uint BASE = 65521; /* largest prime smaller than 65536 */
|
|
const int NMAX = 5552;
|
|
|
|
public static uint Compute (byte[] buf, int pos, int len)
|
|
{
|
|
return Update (1, buf, pos, len);
|
|
}
|
|
|
|
public static uint Update (uint adler, byte[] buf, int pos, int len)
|
|
{
|
|
/* split Adler-32 into component sums */
|
|
uint sum2 = (adler >> 16) & 0xffff;
|
|
adler &= 0xffff;
|
|
|
|
/* in case user likes doing a byte at a time, keep it fast */
|
|
if (1 == len) {
|
|
adler += buf[pos];
|
|
if (adler >= BASE)
|
|
adler -= BASE;
|
|
sum2 += adler;
|
|
if (sum2 >= BASE)
|
|
sum2 -= BASE;
|
|
return adler | (sum2 << 16);
|
|
}
|
|
|
|
/* in case short lengths are provided, keep it somewhat fast */
|
|
if (len < 16) {
|
|
while (0 != len--) {
|
|
adler += buf[pos++];
|
|
sum2 += adler;
|
|
}
|
|
if (adler >= BASE)
|
|
adler -= BASE;
|
|
sum2 %= BASE; /* only added so many BASE's */
|
|
return adler | (sum2 << 16);
|
|
}
|
|
|
|
/* do length NMAX blocks -- requires just one modulo operation */
|
|
while (len >= NMAX) {
|
|
len -= NMAX;
|
|
int n = NMAX / 16; /* NMAX is divisible by 16 */
|
|
do {
|
|
/* 16 sums unrolled */
|
|
adler += buf[pos]; sum2 += adler;
|
|
adler += buf[pos+1]; sum2 += adler;
|
|
adler += buf[pos+2]; sum2 += adler;
|
|
adler += buf[pos+3]; sum2 += adler;
|
|
adler += buf[pos+4]; sum2 += adler;
|
|
adler += buf[pos+5]; sum2 += adler;
|
|
adler += buf[pos+6]; sum2 += adler;
|
|
adler += buf[pos+7]; sum2 += adler;
|
|
adler += buf[pos+8]; sum2 += adler;
|
|
adler += buf[pos+9]; sum2 += adler;
|
|
adler += buf[pos+10]; sum2 += adler;
|
|
adler += buf[pos+11]; sum2 += adler;
|
|
adler += buf[pos+12]; sum2 += adler;
|
|
adler += buf[pos+13]; sum2 += adler;
|
|
adler += buf[pos+14]; sum2 += adler;
|
|
adler += buf[pos+15]; sum2 += adler;
|
|
pos += 16;
|
|
} while (0 != --n);
|
|
adler %= BASE;
|
|
sum2 %= BASE;
|
|
}
|
|
|
|
/* do remaining bytes (less than NMAX, still just one modulo) */
|
|
if (0 != len) { /* avoid modulos if none remaining */
|
|
while (len >= 16) {
|
|
len -= 16;
|
|
adler += buf[pos]; sum2 += adler;
|
|
adler += buf[pos+1]; sum2 += adler;
|
|
adler += buf[pos+2]; sum2 += adler;
|
|
adler += buf[pos+3]; sum2 += adler;
|
|
adler += buf[pos+4]; sum2 += adler;
|
|
adler += buf[pos+5]; sum2 += adler;
|
|
adler += buf[pos+6]; sum2 += adler;
|
|
adler += buf[pos+7]; sum2 += adler;
|
|
adler += buf[pos+8]; sum2 += adler;
|
|
adler += buf[pos+9]; sum2 += adler;
|
|
adler += buf[pos+10]; sum2 += adler;
|
|
adler += buf[pos+11]; sum2 += adler;
|
|
adler += buf[pos+12]; sum2 += adler;
|
|
adler += buf[pos+13]; sum2 += adler;
|
|
adler += buf[pos+14]; sum2 += adler;
|
|
adler += buf[pos+15]; sum2 += adler;
|
|
pos += 16;
|
|
}
|
|
while (0 != len--) {
|
|
adler += buf[pos++];
|
|
sum2 += adler;
|
|
}
|
|
adler %= BASE;
|
|
sum2 %= BASE;
|
|
}
|
|
|
|
/* return recombined sums */
|
|
return adler | (sum2 << 16);
|
|
}
|
|
|
|
private uint m_adler = 1;
|
|
public uint Value { get { return m_adler; } }
|
|
|
|
public void Update (byte[] buf, int pos, int len)
|
|
{
|
|
m_adler = Update (m_adler, buf, pos, len);
|
|
}
|
|
}
|
|
}
|