Initial commit from laurion branch

This commit is contained in:
KimLS
2025-02-16 13:49:38 -08:00
parent dfb089b0c1
commit 3c02b3e60f
14 changed files with 1870 additions and 0 deletions
@@ -0,0 +1,621 @@
using Ionic.Zlib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace StreamParser.Common.Daybreak
{
public class Connection : IConnection
{
private class EncodeType
{
public const int None = 0;
public const int Compression = 1;
public const int XOR = 4;
}
private enum SequenceOrder
{
Past,
Current,
Future
}
private readonly IParser _owner;
private readonly IPAddress _srcAddr;
private readonly int _srcPort;
private readonly IPAddress _dstAddr;
private readonly int _dstPort;
private readonly Util.Crc32 _crc_generator = new Util.Crc32();
private readonly Guid _id = Guid.NewGuid();
private uint _connect_code = 0;
private int _encode_key = 0;
private int _crc_bytes = 0;
private int[] _encode_pass = new int[2] { 0, 0 };
private ConnectionStream[] _client_streams = new ConnectionStream[4] {
new ConnectionStream(),
new ConnectionStream(),
new ConnectionStream(),
new ConnectionStream()
};
private ConnectionStream[] _server_streams = new ConnectionStream[4] {
new ConnectionStream(),
new ConnectionStream(),
new ConnectionStream(),
new ConnectionStream()
};
public IConnection.OnPacketRecvHandler OnPacketRecv { get; set; }
public IPAddress ClientAddress => _srcAddr;
public int ClientPort => _srcPort;
public IPAddress ServerAddress => _dstAddr;
public int ServerPort => _dstPort;
public Guid Id => _id;
public ConnectionType ConnectionType {
get
{
//World servers used to be coded to always be 9000 but live started using dynamic ports
//I've seen from 9000 to 9008 on live
if (_dstPort >= 9000 && _dstPort <= 9010)
{
return ConnectionType.World;
}
else if (_encode_pass[0] == EncodeType.None && _encode_pass[1] == EncodeType.None)
{
return ConnectionType.Login;
}
else if (_encode_pass[0] == EncodeType.XOR && _encode_pass[1] == EncodeType.None)
{
return ConnectionType.Chat;
}
else if (_encode_pass[0] == EncodeType.Compression && _encode_pass[1] == EncodeType.None)
{
return ConnectionType.Zone;
}
return ConnectionType.Unknown;
}
}
public Connection(IParser owner, IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort)
{
_owner = owner;
_srcAddr = srcAddr;
_srcPort = srcPort;
_dstAddr = dstAddr;
_dstPort = dstPort;
}
public void ProcessPacket(IPAddress srcAddr, int srcPort, DateTime packetTime, ReadOnlySpan<byte> data)
{
if (data.Length < 1)
{
return;
}
var opcode = data[1];
if (data[0] == 0 && (opcode == Opcode.KeepAlive || opcode == Opcode.OutboundPing))
{
return;
}
if (PacketCanBeDecoded(data))
{
if (!ValidateCRC(data))
{
return;
}
if (_encode_pass[0] == EncodeType.None && _encode_pass[1] == EncodeType.None)
{
ProcessDecodedPacket(srcAddr, srcPort, packetTime, data.Slice(0, data.Length - _crc_bytes));
}
else
{
//unfortunately we can't avoid a copy here
var temp = data.Slice(0, data.Length - _crc_bytes).ToArray();
for (int i = 1; i >= 0; --i)
{
switch(_encode_pass[i])
{
case EncodeType.Compression:
if(temp[0] == 0)
{
temp = Decompress(temp, 2, temp.Length - 2);
}
else
{
temp = Decompress(temp, 1, temp.Length - 1);
}
break;
case EncodeType.XOR:
if (temp[0] == 0)
{
temp = Decode(temp, 2, temp.Length - 2);
}
else
{
temp = Decode(temp, 1, temp.Length - 1);
}
break;
}
}
ProcessDecodedPacket(srcAddr, srcPort, packetTime, temp);
}
}
else
{
ProcessDecodedPacket(srcAddr, srcPort, packetTime, data);
}
}
private void ProcessDecodedPacket(IPAddress srcAddr, int srcPort, DateTime packetTime, ReadOnlySpan<byte> data)
{
if (data.Length < 1)
{
return;
}
if (data[0] == 0)
{
if (data.Length < 2)
{
return;
}
var opcode = data[1];
switch (opcode)
{
case Opcode.SessionResponse:
if (_connect_code == 0)
{
//if(data.Length != 21)
//{
// return;
//}
_connect_code = BitConverter.ToUInt32(data.Slice(2, 4));
_encode_key = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.Slice(6, 4)));
_crc_bytes = data[10];
_encode_pass[0] = data[11];
_encode_pass[1] = data[12];
_owner.OnNewConnection?.Invoke(this, packetTime);
}
break;
case Opcode.SessionDisconnect:
if(_connect_code != 0)
{
_connect_code = 0;
_encode_key = 0;
_crc_bytes = 0;
_encode_pass[0] = 0;
_encode_pass[1] = 0;
_owner.OnLostConnection?.Invoke(this, packetTime);
}
break;
case Opcode.Combined:
{
int current = 2;
int end = data.Length;
while (current < end)
{
byte subpacket_length = data[current];
current += 1;
if (end < current + subpacket_length)
{
return;
}
var subpacket = data.Slice(current, subpacket_length);
ProcessDecodedPacket(srcAddr, srcPort, packetTime, subpacket);
current += subpacket_length;
}
}
break;
case Opcode.AppCombined:
{
int current = 2;
int end = data.Length;
while (current < end)
{
int subpacket_length = 0;
if (data[current] == 0xff)
{
if (end < current + 3)
{
return;
}
if (data[current + 1] == 0xff && data[current + 2] == 0xff)
{
if (end < current + 7)
{
return;
}
subpacket_length =
((data[current + 3]) << 24) |
((data[current + 4]) << 16) |
((data[current + 5]) << 8) |
(data[current + 6]);
current += 7;
}
else
{
subpacket_length =
((data[current + 1]) << 8) |
(data[current + 2]);
current += 3;
}
}
else
{
subpacket_length = data[current];
current += 1;
}
var subpacket = data.Slice(current, subpacket_length);
ProcessDecodedPacket(srcAddr, srcPort, packetTime, subpacket);
current += subpacket_length;
}
}
break;
case Opcode.Packet:
case Opcode.Packet2:
case Opcode.Packet3:
case Opcode.Packet4:
{
var stream_id = opcode - Opcode.Packet;
var stream = FindStream(srcAddr, srcPort, stream_id);
var sequence = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data.Slice(2, 2)));
var order = CompareSequence(stream.Sequence, sequence);
if (order == SequenceOrder.Future)
{
if (!stream.PacketQueue.ContainsKey(sequence))
{
stream.PacketQueue.Add(sequence, new ConnectionStream.QueuedPacket
{
Data = data.ToArray(),
PacketTime = packetTime
});
}
}
else if (order == SequenceOrder.Current)
{
if (stream.PacketQueue.ContainsKey(sequence))
{
stream.PacketQueue.Remove(sequence);
}
stream.Sequence++;
ProcessDecodedPacket(srcAddr, srcPort, packetTime, data.Slice(4));
ProcessQueue(srcAddr, srcPort, stream_id);
}
}
break;
case Opcode.Fragment:
case Opcode.Fragment2:
case Opcode.Fragment3:
case Opcode.Fragment4:
{
var stream_id = opcode - Opcode.Fragment;
var stream = FindStream(srcAddr, srcPort, stream_id);
var sequence = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data.Slice(2, 2)));
var order = CompareSequence(stream.Sequence, sequence);
if (order == SequenceOrder.Future)
{
if (!stream.PacketQueue.ContainsKey(sequence))
{
stream.PacketQueue.Add(sequence, new ConnectionStream.QueuedPacket
{
Data = data.ToArray(),
PacketTime = packetTime
});
}
}
else if (order == SequenceOrder.Current)
{
if (stream.PacketQueue.ContainsKey(sequence))
{
stream.PacketQueue.Remove(sequence);
}
stream.Sequence++;
if (stream.TotalFragmentedBytes == 0)
{
stream.TotalFragmentedBytes = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.Slice(4, 4)));
stream.CurrentFragmentedBytes = (uint)(data.Length - 8);
if(stream.FragmentBuffer == null || stream.FragmentBuffer.Length < (stream.TotalFragmentedBytes + 512))
{
stream.FragmentBuffer = new byte[stream.TotalFragmentedBytes + 512];
}
var target = stream.FragmentBuffer.AsSpan();
data.Slice(8).CopyTo(target);
} else
{
var target = stream.FragmentBuffer.AsSpan((int)stream.CurrentFragmentedBytes);
data.Slice(4).CopyTo(target);
stream.CurrentFragmentedBytes += (uint)(data.Length - 4);
if (stream.CurrentFragmentedBytes >= stream.TotalFragmentedBytes)
{
ProcessDecodedPacket(srcAddr, srcPort, packetTime,
stream.FragmentBuffer.AsSpan(0, (int)stream.TotalFragmentedBytes));
stream.CurrentFragmentedBytes = 0;
stream.TotalFragmentedBytes = 0;
}
}
ProcessQueue(srcAddr, srcPort, stream_id);
}
}
break;
case Opcode.Padding:
OnPacketRecv?.Invoke(this, GetDirection(srcAddr, srcPort), packetTime, data.Slice(1));
break;
default:
break;
}
} else
{
OnPacketRecv?.Invoke(this, GetDirection(srcAddr, srcPort), packetTime, data);
}
}
private void ProcessQueue(IPAddress srcAddr, int srcPort, int stream_id)
{
var stream = FindStream(srcAddr, srcPort, stream_id);
var sequence = stream.Sequence;
//try to get the current sequence in the queue, if it exists then process it
ConnectionStream.QueuedPacket value;
if(stream.PacketQueue.TryGetValue(sequence, out value))
{
ProcessDecodedPacket(srcAddr, srcPort, value.PacketTime, value.Data);
}
}
public bool Match(IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort)
{
var p1 = _srcAddr.Equals(srcAddr) && _srcPort == srcPort && _dstAddr.Equals(dstAddr) && _dstPort == dstPort;
var p2 = _srcAddr.Equals(dstAddr) && _srcPort == dstPort && _dstAddr.Equals(srcAddr) && _dstPort == srcPort;
return p1 || p2;
}
private SequenceOrder CompareSequence(ushort expected, ushort actual)
{
int diff = (int)actual - (int)expected;
if (diff == 0)
{
return SequenceOrder.Current;
}
if (diff > 0)
{
if (diff > 10000)
{
return SequenceOrder.Past;
}
return SequenceOrder.Future;
}
if (diff < -10000)
{
return SequenceOrder.Future;
}
return SequenceOrder.Past;
}
private bool PacketCanBeDecoded(ReadOnlySpan<byte> p)
{
if (p.Length < 2)
{
return false;
}
if (p[0] != 0)
{
return true;
}
var opcode = p[1];
if (opcode == Opcode.SessionRequest || opcode == Opcode.SessionResponse || opcode == Opcode.OutOfSession)
{
return false;
}
return true;
}
private bool ValidateCRC(ReadOnlySpan<byte> p)
{
try
{
if (_crc_bytes == 0)
{
return true;
}
int actual = 0;
int calculated = _crc_generator.Calculate(p.Slice(0, p.Length - _crc_bytes), _encode_key);
switch (_crc_bytes)
{
case 2:
actual = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(p.Slice(p.Length - 2, 2))) & 0xFFFF;
calculated = calculated & 0xFFFF;
break;
case 4:
actual = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(p.Slice(p.Length - 4, 4)));
break;
default:
return false;
}
return actual == calculated;
} catch(Exception ex)
{
return false;
}
}
private byte[] Decompress(byte[] p, int offset, int length)
{
if (length < 2)
{
return p;
}
Span<byte> header = p.AsSpan(0, offset);
byte flag = p[offset];
Span<byte> payload = p.AsSpan(offset + 1, length - 1);
if (flag == 0x5a)
{
var pl = payload.ToArray();
var inflated = Inflate(payload.ToArray());
byte[] ret = new byte[offset + inflated.Length];
Array.Copy(p, 0, ret, 0, offset);
Array.Copy(inflated, 0, ret, offset, inflated.Length);
return ret;
}
else if (flag == 0xa5)
{
byte[] ret = new byte[offset + length - 1];
Array.Copy(p, 0, ret, 0, offset);
Array.Copy(p, offset + 1, ret, offset, length - 1);
return ret;
}
else
{
return p;
}
}
private byte[] Inflate(byte[] p)
{
try
{
using (var out_stream = new MemoryStream())
{
using (var in_stream = new MemoryStream(p))
{
var buffer = new byte[512];
using (var zs = new ZlibStream(in_stream, CompressionMode.Decompress))
{
int r = 0;
do
{
r = zs.Read(buffer, 0, 512);
out_stream.Write(buffer, 0, r);
} while (r == 512);
}
}
var ret = out_stream.ToArray();
return ret;
}
}
catch (Exception)
{
return null;
}
}
private byte[] Decode(byte[] p, int offset, int length)
{
int key = _encode_key;
Span<byte> buffer = p.AsSpan(offset, length);
int i = 0;
for (i = 0; i + 4 <= length; i += 4)
{
int pt = BitConverter.ToInt32(buffer.Slice(i)) ^ key;
key = BitConverter.ToInt32(buffer.Slice(i));
if(BitConverter.TryWriteBytes(buffer.Slice(i), pt) == false)
{
throw new Exception("Error writing bytes back in decode.");
}
}
byte kc = (byte)(key & 0xFF);
for (; i < length; i++)
{
buffer[i] = (byte)(buffer[i] ^ kc);
}
return p;
}
private Direction GetDirection(IPAddress srcAddr, int srcPort)
{
if(srcAddr.Equals(_srcAddr) && srcPort == _srcPort)
{
return Direction.ClientToServer;
} else
{
return Direction.ServerToClient;
}
}
private ConnectionStream FindStream(IPAddress srcAddr, int srcPort, int index)
{
if (index < 0 || index > 3)
{
return null;
}
var dir = GetDirection(srcAddr, srcPort);
if(dir == Direction.ClientToServer)
{
return _client_streams[index];
} else
{
return _server_streams[index];
}
}
private class ConnectionStream
{
public class QueuedPacket
{
public byte[] Data { get; set; }
public DateTime PacketTime { get; set; }
}
public ConnectionStream()
{
Sequence = 0;
CurrentFragmentedBytes = 0;
TotalFragmentedBytes = 0;
FragmentBuffer = null;
PacketQueue = new Dictionary<ushort, QueuedPacket>();
}
public ushort Sequence { get; set; }
public uint CurrentFragmentedBytes { get; set; }
public uint TotalFragmentedBytes { get; set; }
public byte[] FragmentBuffer { get; set; }
public Dictionary<ushort, QueuedPacket> PacketQueue { get; set; }
}
}
}
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StreamParser.Common.Daybreak
{
public ref struct GamePacket
{
private readonly ReadOnlySpan<byte> _data;
public GamePacket(ReadOnlySpan<byte> data)
{
_data = data;
}
public readonly override string ToString()
{
return ToString(16);
}
public readonly string ToString(int columns)
{
int rows = _data.Length / columns;
if (_data.Length % columns != 0)
{
rows += 1;
}
int expected = (10 + columns * 4) * rows;
var sb = new StringBuilder(expected);
for(var i = 0; i < rows; ++i)
{
sb.AppendFormat("{0} |", (i * columns).ToString("X5"));
for(var j = 0; j < columns; ++j)
{
var index = (i * 16) + j;
if (index >= _data.Length)
{
sb.Append(" ");
} else
{
var c = _data[index];
sb.AppendFormat("{0,3}", c.ToString("X2"));
}
}
sb.Append(" | ");
for (var j = 0; j < columns; ++j)
{
var index = (i * 16) + j;
if (index >= _data.Length)
{
sb.Append(" ");
}
else
{
var c = _data[index];
var ch = (char)c;
if (char.IsLetterOrDigit(ch) || char.IsPunctuation(ch) || char.IsSymbol(ch) || (ch == ' '))
{
sb.Append(ch);
}
else
{
sb.Append(".");
}
}
}
sb.AppendLine();
}
return sb.ToString();
}
public readonly string ToModelString(int max_taken, bool hex)
{
int expected = Math.Min(_data.Length, max_taken) * (hex ? 2 : 1);
if(expected <= 0)
{
return string.Empty;
}
var sb = new StringBuilder(expected);
for(var i = 0; i < Math.Min(_data.Length, max_taken); ++i)
{
var c = _data[i];
if(hex)
{
sb.Append(c.ToString("X2"));
} else
{
var ch = (char)c;
if (char.IsLetterOrDigit(ch) || char.IsPunctuation(ch) || char.IsSymbol(ch) || (ch == ' '))
{
sb.Append(ch);
}
else
{
sb.Append(".");
}
}
}
return sb.ToString();
}
}
}
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace StreamParser.Common.Daybreak
{
public enum Direction
{
ClientToServer,
ServerToClient
}
public enum ConnectionType
{
Unknown,
Login,
World,
Chat,
Zone
}
public interface IConnection
{
delegate void OnPacketRecvHandler(Connection connection, Direction direction, DateTime packetTime, ReadOnlySpan<byte> data);
OnPacketRecvHandler OnPacketRecv { get; set; }
void ProcessPacket(IPAddress srcAddr, int srcPort, DateTime packetTime, ReadOnlySpan<byte> data);
bool Match(IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort);
ConnectionType ConnectionType { get; }
IPAddress ClientAddress { get; }
int ClientPort { get; }
IPAddress ServerAddress { get; }
int ServerPort { get; }
Guid Id { get; }
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StreamParser.Common.Daybreak
{
public interface IParser
{
delegate void ConnectionHandler(IConnection connection, DateTime connectionTime);
ConnectionHandler OnNewConnection { get; set; }
ConnectionHandler OnLostConnection { get; set; }
void Parse(string filename);
}
}
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StreamParser.Common.Daybreak
{
public class Opcode
{
public const byte Padding = 0;
public const byte SessionRequest = 1;
public const byte SessionResponse = 2;
public const byte Combined = 3;
public const byte SessionDisconnect = 5;
public const byte KeepAlive = 6;
public const byte SessionStatRequest = 7;
public const byte SessionStatResponse = 8;
public const byte Packet = 9;
public const byte Packet2 = 10;
public const byte Packet3 = 11;
public const byte Packet4 = 12;
public const byte Fragment = 13;
public const byte Fragment2 = 14;
public const byte Fragment3 = 15;
public const byte Fragment4 = 16;
public const byte OutOfOrderAck = 17;
public const byte OutOfOrderAck2 = 18;
public const byte OutOfOrderAck3 = 19;
public const byte OutOfOrderAck4 = 20;
public const byte Ack = 21;
public const byte Ack2 = 22;
public const byte Ack3 = 23;
public const byte Ack4 = 22;
public const byte AppCombined = 25;
public const byte OutboundPing = 28;
public const byte OutOfSession = 29;
}
}
@@ -0,0 +1,115 @@
using Microsoft.Extensions.Logging;
using SharpPcap;
using SharpPcap.LibPcap;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace StreamParser.Common.Daybreak
{
public class Parser : IParser
{
/**
* Dependencies
*/
private readonly ILogger<Parser> _logger;
private readonly List<IConnection> _connections = new List<IConnection>();
public IParser.ConnectionHandler OnNewConnection { get; set; }
public IParser.ConnectionHandler OnLostConnection { get; set; }
public Parser(ILogger<Parser> logger)
{
_logger = logger;
}
public void Parse(string filename)
{
ICaptureDevice device = null;
try
{
device = new CaptureFileReaderDevice(filename);
device.Open();
device.OnPacketArrival += new PacketArrivalEventHandler(OnPacketCapture);
device.Capture();
device.Close();
} catch(Exception ex)
{
_logger.LogError(ex, "Error reading device capture.");
}
}
private void OnPacketCapture(object sender, PacketCapture capture)
{
var raw = capture.GetPacket();
if (raw.LinkLayerType == PacketDotNet.LinkLayers.Ethernet || raw.LinkLayerType == PacketDotNet.LinkLayers.Null)
{
var packet = PacketDotNet.Packet.ParsePacket(raw.LinkLayerType, raw.Data);
var ipPacket = packet.Extract<PacketDotNet.IPv4Packet>();
var udpPacket = packet.Extract<PacketDotNet.UdpPacket>();
if (ipPacket != null && udpPacket != null)
{
try
{
ProcessPacket(ipPacket.SourceAddress,
udpPacket.SourcePort,
ipPacket.DestinationAddress,
udpPacket.DestinationPort,
raw.Timeval.Date,
udpPacket.PayloadData);
} catch(Exception ex)
{
_logger.LogError(ex, "Error processing packet");
}
}
}
}
private void ProcessPacket(IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort, DateTime packetTime, ReadOnlySpan<byte> data)
{
if(data.Length < 2)
{
_logger.LogTrace("Tossing packet, {0} was less than minimum packet size", data.Length);
return;
}
var c = FindConnection(srcAddr, srcPort, dstAddr, dstPort);
if(c != null)
{
c.ProcessPacket(srcAddr, srcPort, packetTime, data);
}
else if (data[0] == 0 && data[1] == Opcode.SessionRequest)
{
if(data.Length != 24)
{
_logger.LogTrace("Tossing packet, {0} was not the right size for a SessionRequest", data.Length);
return;
}
c = new Connection(this, srcAddr, srcPort, dstAddr, dstPort);
_connections.Add(c);
c.ProcessPacket(srcAddr, srcPort, packetTime, data);
}
}
private IConnection FindConnection(IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort)
{
foreach (var c in _connections)
{
if (c.Match(srcAddr, srcPort, dstAddr, dstPort))
{
return c;
}
}
return null;
}
}
}
+103
View File
@@ -0,0 +1,103 @@
using System;
namespace StreamParser.Common.Util
{
public class Crc32
{
private uint[] _encodeTable =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
public int Calculate(ReadOnlySpan<byte> data)
{
uint crc = 0xffffffff;
for (int i = 0; i < data.Length; ++i)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ _encodeTable[(crc ^ data[i]) & 0x000000FF];
}
return (int)~crc;
}
public int Calculate(ReadOnlySpan<byte> data, int key)
{
uint crc = 0xffffffff;
for (int i = 0; i < 4; ++i)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ _encodeTable[(crc ^ ((key >> (i * 8)) & 0xff)) & 0x000000FF];
}
for (int i = 0; i < data.Length; ++i)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ _encodeTable[(crc ^ data[i]) & 0x000000FF];
}
return (int)~crc;
}
}
}
+14
View File
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>StreamParser.Common</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Iconic.Zlib.Netstandard" Version="1.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageReference Include="SharpPcap" Version="6.3.0" />
</ItemGroup>
</Project>