GARbro-mirror/adler32.cs

147 lines
5.3 KiB
C#
Raw Normal View History

2014-07-22 03:32:15 +08:00
//! \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);
}
}
}