mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-29 14:24:13 +08:00
246 lines
8.5 KiB
C#
246 lines
8.5 KiB
C#
//! \file Utility.cs
|
|
//! \date Sat Jul 05 02:47:33 2014
|
|
//! \brief utility class for GameRes assembly.
|
|
//
|
|
|
|
namespace GameRes.Utility
|
|
{
|
|
public static class Binary
|
|
{
|
|
public static uint BigEndian (uint u)
|
|
{
|
|
return (u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | (u & 0xff000000) >> 24;
|
|
}
|
|
public static int BigEndian (int i)
|
|
{
|
|
return (int)BigEndian ((uint)i);
|
|
}
|
|
public static ushort BigEndian (ushort u)
|
|
{
|
|
return (ushort)((u & 0xff) << 8 | (u & 0xff00) >> 8);
|
|
}
|
|
public static short BigEndian (short i)
|
|
{
|
|
return (short)BigEndian ((ushort)i);
|
|
}
|
|
public static ulong BigEndian (ulong u)
|
|
{
|
|
return (ulong)BigEndian((uint)(u & 0xffffffff)) << 32
|
|
| (ulong)BigEndian((uint)(u >> 32));
|
|
}
|
|
public static long BigEndian (long i)
|
|
{
|
|
return (long)BigEndian ((ulong)i);
|
|
}
|
|
|
|
public static bool AsciiEqual (byte[] name1, string name2)
|
|
{
|
|
return AsciiEqual (name1, 0, name2);
|
|
}
|
|
|
|
public static bool AsciiEqual (byte[] name1, int offset, string name2)
|
|
{
|
|
if (name1.Length-offset < name2.Length)
|
|
return false;
|
|
for (int i = 0; i < name2.Length; ++i)
|
|
if ((char)name1[offset+i] != name2[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public static class LittleEndian
|
|
{
|
|
public static ushort ToUInt16 (byte[] value, int index)
|
|
{
|
|
return (ushort)(value[index] | value[index+1] << 8);
|
|
}
|
|
|
|
public static short ToInt16 (byte[] value, int index)
|
|
{
|
|
return (short)(value[index] | value[index+1] << 8);
|
|
}
|
|
|
|
public static uint ToUInt32 (byte[] value, int index)
|
|
{
|
|
return (uint)(value[index] | value[index+1] << 8 | value[index+2] << 16 | value[index+3] << 24);
|
|
}
|
|
|
|
public static int ToInt32 (byte[] value, int index)
|
|
{
|
|
return (int)ToUInt32 (value, index);
|
|
}
|
|
|
|
public static ulong ToUInt64 (byte[] value, int index)
|
|
{
|
|
return (ulong)ToUInt32 (value, index) | ((ulong)ToUInt32 (value, index+4) << 32);
|
|
}
|
|
|
|
public static long ToInt64 (byte[] value, int index)
|
|
{
|
|
return (long)ToUInt64 (value, index);
|
|
}
|
|
}
|
|
|
|
public sealed class Crc32
|
|
{
|
|
/* Table of CRCs of all 8-bit messages. */
|
|
private static readonly uint[] crc_table = InitializeTable();
|
|
|
|
/* Make the table for a fast CRC. */
|
|
private static uint[] InitializeTable ()
|
|
{
|
|
uint[] table = new uint[256];
|
|
for (uint n = 0; n < 256; n++)
|
|
{
|
|
uint c = n;
|
|
for (int k = 0; k < 8; k++)
|
|
{
|
|
if (0 != (c & 1))
|
|
c = 0xedb88320 ^ (c >> 1);
|
|
else
|
|
c = c >> 1;
|
|
}
|
|
table[n] = c;
|
|
}
|
|
return table;
|
|
}
|
|
|
|
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
|
|
should be initialized to all 1's, and the transmitted value
|
|
is the 1's complement of the final running CRC (see the
|
|
crc() routine below)). */
|
|
static uint UpdateCrc (uint crc, byte[] buf, int pos, int len)
|
|
{
|
|
uint c = crc;
|
|
for (int n = 0; n < len; n++)
|
|
c = crc_table[(c ^ buf[pos+n]) & 0xff] ^ (c >> 8);
|
|
return c;
|
|
}
|
|
|
|
/* Return the CRC of the bytes buf[0..len-1]. */
|
|
public static uint Compute (byte[] buf, int pos, int len)
|
|
{
|
|
return UpdateCrc (0xffffffff, buf, pos, len) ^ 0xffffffff;
|
|
}
|
|
|
|
private uint m_crc = 0xffffffff;
|
|
public uint Value { get { return m_crc^0xffffffff; } }
|
|
|
|
public void Update (byte[] buf, int pos, int len)
|
|
{
|
|
m_crc = UpdateCrc (m_crc, buf, pos, len);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
private 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);
|
|
}
|
|
}
|
|
}
|