modify decompress algo

This commit is contained in:
NguyenVanDat
2025-10-15 16:01:48 +07:00
parent 793c8a370f
commit c67d0e5c4c
2 changed files with 151 additions and 264 deletions
@@ -305,10 +305,15 @@ namespace CSNetwork
_receiveOctets.Capacity - currentBufferLength,
token
);
if (currentBufferLength < _receiveOctets.Length)
_logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size from {_previousLength} to {currentBufferLength} --- Last byte: {_receiveOctets.RawBuffer[currentBufferLength - 1]}");
_previousLength = currentBufferLength; // cache to check if the buffer is growing
// if (bytesRead > 0)
// {
// _logger.Log(LogType.Info, $"ProcessReceivedData:: Last Byte: {_receiveOctets.RawBuffer[currentBufferLength + bytesRead - 1]}");
// if (_previousLength > 0)
// _logger.Log(LogType.Info, $"ProcessReceivedData:: Buffer remaining data size from {_previousLength} to {currentBufferLength + bytesRead} --- Last byte: {_receiveOctets.RawBuffer[_previousLength - 1]}");
// }
//
// _previousLength = currentBufferLength + bytesRead; // cache to check if the buffer is growing
}
catch (IOException ex)
when (ex.InnerException is SocketException se
@@ -399,7 +404,7 @@ namespace CSNetwork
catch (Exception ex)
{
_logger.Log(LogType.Info,
$"Input security update error: {ex.Message} - Clearing receive buffer."
$"Input security update error: {ex.Message} - {ex.StackTrace} - Clearing receive buffer."
);
OnErrorOccurred($"Input security error: {ex.Message}");
_receiveOctets.SetSize(0);
@@ -10,43 +10,43 @@ namespace CSNetwork.Security
private const int MPPC_HIST_LEN = 8192;
private byte[] history = new byte[MPPC_HIST_LEN];
private int historyPos;
private uint bitPos;
private uint adjust_bitPos;
private uint bitsProcessed;
private uint totalBits;
private int histptr;
private uint l;
private uint adjust_l;
private uint blen;
private uint blen_total;
private List<byte> legacyInput = new List<byte>();
private int readPos;
private int adjust_readPos;
private int rptr;
private int adjust_rptr;
public Decompress()
{
historyPos = 0;
bitPos = 0;
histptr = 0;
l = 0;
}
public Decompress(Decompress source)
{
Array.Copy(source.history, history, MPPC_HIST_LEN);
historyPos = source.historyPos;
bitPos = source.bitPos;
adjust_bitPos = source.adjust_bitPos;
bitsProcessed = source.bitsProcessed;
totalBits = source.totalBits;
histptr = source.histptr;
l = source.l;
adjust_l = source.adjust_l;
blen = source.blen;
blen_total = source.blen_total;
legacyInput = new List<byte>(source.legacyInput);
readPos = source.readPos;
adjust_readPos = source.adjust_readPos;
rptr = source.rptr;
adjust_rptr = source.adjust_rptr;
}
private bool PassBits(uint n)
private bool passbits(uint n)
{
bitPos += n;
bitsProcessed += n;
if (bitsProcessed < totalBits)
l += n;
blen += n;
if (blen < blen_total)
return true;
bitPos = adjust_bitPos;
readPos = adjust_readPos;
l = adjust_l;
rptr = adjust_rptr;
return false;
}
@@ -58,19 +58,19 @@ namespace CSNetwork.Security
| ((value & 0xFF000000) >> 24);
}
private uint Fetch()
private uint fetch()
{
readPos += (int)(bitPos >> 3);
bitPos &= 7;
rptr += (int)(l >> 3);
l &= 7;
byte[] fourBytes = new byte[4];
for (int i = 0; i < 4 && readPos + i < legacyInput.Count; i++)
for (int i = 0; i < 4; i++)
{
fourBytes[i] = legacyInput[readPos + i];
fourBytes[i] = legacyInput[rptr + i];
}
uint value = BitConverter.ToUInt32(fourBytes, 0);
return ByteOrder32(value) << (int)bitPos;
return ByteOrder32(value) << (int)l;
}
private void LameCopy(int dstPos, int srcPos, int len)
@@ -93,34 +93,6 @@ namespace CSNetwork.Security
}
}
// Copy bytes from history using MPPC's 8 KB circular window semantics.
// Source starts at (historyPos - offset) modulo window size and may overlap
// destination; freshly written bytes must be visible to subsequent reads.
private void CopyFromHistoryCircular(int offset, int length)
{
int srcPos = historyPos - offset;
if (srcPos < 0)
srcPos += MPPC_HIST_LEN; // wrap source into window
int dstPos = historyPos;
while (length-- > 0)
{
history[dstPos] = history[srcPos];
dstPos++;
if (dstPos == MPPC_HIST_LEN)
dstPos = 0; // wrap destination
srcPos++;
if (srcPos == MPPC_HIST_LEN)
srcPos = 0; // wrap source
}
// Advance history head to the end of the copied sequence
historyPos = dstPos;
}
public Octets Update(Octets input)
{
// Add input to legacy buffer
@@ -129,253 +101,163 @@ namespace CSNetwork.Security
legacyInput.Add(b);
}
totalBits = (uint)(legacyInput.Count * 8 - bitPos);
readPos = 0;
bitsProcessed = 7;
blen_total = (uint)(legacyInput.Count * 8 - l);
rptr = 0;
blen = 7;
Octets output = new Octets();
int histHead = historyPos;
int histhead = histptr;
while (totalBits > bitsProcessed)
while (blen_total > blen)
{
adjust_bitPos = bitPos;
adjust_readPos = readPos;
uint val = Fetch();
adjust_l = l;
adjust_rptr = rptr;
uint val = fetch();
if (val < 0x80000000)
{
if (!PassBits(8))
if (!passbits(8))
break;
// Defer if writing this literal would cross the end of the linear window.
// We only wrap at EOB to match the original C++ semantics.
if (historyPos + 1 > MPPC_HIST_LEN)
{
bitPos = adjust_bitPos;
readPos = adjust_readPos;
break;
}
history[historyPos++] = (byte)(val >> 24);
// Do not wrap here; wrapping is handled only at EOB.
history[histptr++] = (byte)(val >> 24);
continue;
}
if (val < 0xC0000000)
{
if (!PassBits(9))
if (!passbits(9))
break;
// Defer if writing this literal would cross the end of the linear window.
if (historyPos + 1 > MPPC_HIST_LEN)
{
bitPos = adjust_bitPos;
readPos = adjust_readPos;
break;
}
history[historyPos++] = (byte)(((val >> 23) | 0x80) & 0xFF);
// Do not wrap here; wrapping is handled only at EOB.
history[histptr++] = (byte)(((val >> 23) | 0x80) & 0xFF);
continue;
}
uint offset = 0,
length = 0;
uint off = 0, len = 0;
if (val >= 0xF0000000)
{
if (!PassBits(10))
if (!passbits(10))
break;
offset = (val >> 22) & 0x3F;
if (offset == CTRL_OFF_EOB)
off = (val >> 22) & 0x3F;
if (off == CTRL_OFF_EOB)
{
uint advance = 8 - (bitPos & 7);
uint advance = (uint)(8 - (l & 7));
if (advance < 8)
if (!PassBits(advance))
if (!passbits(advance))
break;
// Copy current history segment to output
if (historyPos >= histHead)
{
byte[] segment = new byte[historyPos - histHead];
Array.Copy(history, histHead, segment, 0, segment.Length);
byte[] segment = new byte[histptr - histhead];
Array.Copy(history, histhead, segment, 0, segment.Length);
output.Insert(output.Size, segment);
// If output is empty, replace it, otherwise insert at the end
if (output.Size == 0)
output.Replace(segment);
else
output.Insert(output.Size, segment);
}
else
{
// Wrap around case - two segments
byte[] segment1 = new byte[MPPC_HIST_LEN - histHead];
Array.Copy(history, histHead, segment1, 0, segment1.Length);
if (histptr - histhead == MPPC_HIST_LEN)
histptr = 0;
// Add first segment (from histHead to end of buffer)
if (output.Size == 0)
output.Replace(segment1);
else
output.Insert(output.Size, segment1);
// Add second segment (from beginning to historyPos)
if (historyPos > 0)
{
byte[] segment2 = new byte[historyPos];
Array.Copy(history, 0, segment2, 0, historyPos);
output.Insert(output.Size, segment2);
}
}
if (historyPos == MPPC_HIST_LEN)
historyPos = 0;
histHead = historyPos;
histhead = histptr;
continue;
}
}
else if (val >= 0xE0000000)
{
if (!PassBits(12))
if (!passbits(12))
break;
offset = ((val >> 20) & 0xFF) + 64;
off = ((val >> 20) & 0xFF) + 64;
}
else if (val >= 0xC0000000)
{
if (!PassBits(16))
if (!passbits(16))
break;
offset = ((val >> 16) & 0x1FFF) + 320;
off = ((val >> 16) & 0x1FFF) + 320;
}
val = fetch();
if ( val < 0x80000000 )
{
if ( !passbits(1) )
break;
len = 3;
}
else if ( val < 0xc0000000 )
{
if ( !passbits(4) )
break;
len = 4|((val>>28)&3);
}
else if ( val < 0xe0000000 )
{
if ( !passbits(6) )
break;
len = 8|((val>>26)&7);
}
else if ( val < 0xf0000000 )
{
if ( !passbits(8) )
break;
len = 16|((val>>24)&15);
}
else if ( val < 0xf8000000 )
{
if ( !passbits(10) )
break;
len = 32|((val>>22)&0x1f);
}
else if ( val < 0xfc000000 )
{
if ( !passbits(12) )
break;
len = 64|((val>>20)&0x3f);
}
else if ( val < 0xfe000000 )
{
if ( !passbits(14) )
break;
len = 128|((val>>18)&0x7f);
}
else if ( val < 0xff000000 )
{
if ( !passbits(16) )
break;
len = 256|((val>>16)&0xff);
}
else if ( val < 0xff800000 )
{
if ( !passbits(18) )
break;
len = 0x200|((val>>14)&0x1ff);
}
else if ( val < 0xffc00000 )
{
if ( !passbits(20) )
break;
len = 0x400|((val>>12)&0x3ff);
}
else if ( val < 0xffe00000 )
{
if ( !passbits(22) )
break;
len = 0x800|((val>>10)&0x7ff);
}
else if ( val < 0xfff00000 )
{
if ( !passbits(24) )
break;
len = 0x1000|((val>>8)&0xfff);
}
else
{
// Invalid data
bitPos = adjust_bitPos;
readPos = adjust_readPos;
l = adjust_l;
rptr = adjust_rptr;
break;
}
val = Fetch();
if (val < 0x80000000)
{
if (!PassBits(1))
break;
length = 3;
}
else if (val < 0xC0000000)
{
if (!PassBits(4))
break;
length = 4 | ((val >> 28) & 3);
}
else if (val < 0xE0000000)
{
if (!PassBits(6))
break;
length = 8 | ((val >> 26) & 7);
}
else if (val < 0xF0000000)
{
if (!PassBits(8))
break;
length = 16 | ((val >> 24) & 15);
}
else if (val < 0xF8000000)
{
if (!PassBits(10))
break;
length = 32 | ((val >> 22) & 0x1F);
}
else if (val < 0xFC000000)
{
if (!PassBits(12))
break;
length = 64 | ((val >> 20) & 0x3F);
}
else if (val < 0xFE000000)
{
if (!PassBits(14))
break;
length = 128 | ((val >> 18) & 0x7F);
}
else if (val < 0xFF000000)
{
if (!PassBits(16))
break;
length = 256 | ((val >> 16) & 0xFF);
}
else if (val < 0xFF800000)
{
if (!PassBits(18))
break;
length = 0x200 | ((val >> 14) & 0x1FF);
}
else if (val < 0xFFC00000)
{
if (!PassBits(20))
break;
length = 0x400 | ((val >> 12) & 0x3FF);
}
else if (val < 0xFFE00000)
{
if (!PassBits(22))
break;
length = 0x800 | ((val >> 10) & 0x7FF);
}
else if (val < 0xFFF00000)
{
if (!PassBits(24))
break;
length = 0x1000 | ((val >> 8) & 0xFFF);
}
else
{
bitPos = adjust_bitPos;
readPos = adjust_readPos;
if (histptr < off || histptr + len > MPPC_HIST_LEN)
break;
}
// Validate match boundaries against the current linear window. Defer if it would cross.
// This mirrors the C++ check: if (histptr - off < history || histptr + len > history + MPPC_HIST_LEN) break;
if (offset == 0 || offset > MPPC_HIST_LEN || historyPos - (int)offset < 0 || historyPos + (int)length > MPPC_HIST_LEN)
{
// Not enough room in the current linear window; rollback and wait for more data.
bitPos = adjust_bitPos;
readPos = adjust_readPos;
break;
}
// Linear, overlap-safe copy within current window. No mid-block wrap.
LameCopy(historyPos, historyPos - (int)offset, (int)length);
historyPos += (int)length;
}
// Copy remaining history segment to output
if (historyPos >= histHead)
{
byte[] result = new byte[historyPos - histHead];
Array.Copy(history, histHead, result, 0, result.Length);
if (output.Size == 0)
output.Replace(result);
else
output.Insert(output.Size, result);
}
else
{
if (histHead < MPPC_HIST_LEN)
{
byte[] segment1 = new byte[MPPC_HIST_LEN - histHead];
Array.Copy(history, histHead, segment1, 0, segment1.Length);
if (output.Size == 0)
output.Replace(segment1);
else
output.Insert(output.Size, segment1);
}
if (historyPos > 0)
{
byte[] segment2 = new byte[historyPos];
Array.Copy(history, 0, segment2, 0, historyPos);
output.Insert(output.Size, segment2);
}
LameCopy(histptr, histptr - (int)off, (int)len);
histptr += (int)len;
}
byte[] result = new byte[histptr - histhead];
Array.Copy(history, histhead, result, 0, result.Length);
output.Insert(output.Size, result);
// Remove processed bytes from legacy input
legacyInput.RemoveRange(0, readPos);
legacyInput.RemoveRange(0, rptr);
return output;
}