Initial project state: .NET reference, design, Rust port (M0+M1), evidence
rust / build / test / clippy / fmt (push) Has been cancelled
rust / build / test / clippy / fmt (push) Has been cancelled
Layout:
- src/ .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
MxAsbClient, probes, tests, harnesses. Executable spec.
- design/ Architectural plan for the Rust port (M0–M6), error
model, protocol invariants, risks (R1–R16), adversarial
review log (review.md).
- rust/ Rust workspace. M0 skeleton + M1 codec parity.
mxaccess-codec: 215 unit tests + 2 cross-implementation
parity tests (byte-identical against .NET reference).
Other crates are M0 stubs awaiting M2+.
- captures/ Frida + netsh + pcap evidence per CLAUDE.md
("captures are evidence, not throwaway logs").
- analysis/ Decompiled C# (frida/proxy/decompiled-*),
Ghidra exports for native DLLs (`exports/` only —
working state at `projects/` and AVEVA's input
binaries at `input/` are gitignored).
- docs/ Reverse-engineering reference docs.
- tools/ Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/ Rust CI: fmt + build + test + clippy on Windows.
- LICENSE MIT (Joseph Doherty, 2026).
Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly
Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class AACopyEncoder
|
||||
{
|
||||
private const int PaddingSize = 5;
|
||||
|
||||
private const int MaxUncompressedBlockSize = 65536;
|
||||
|
||||
public void GetBlock(AADeflateInput input, AAOutputBuffer output, bool isFinal)
|
||||
{
|
||||
int num = 0;
|
||||
if (input != null)
|
||||
{
|
||||
num = Math.Min(input.Count, output.FreeBytes - 5 - output.BitsInBuffer);
|
||||
if (num > 65531)
|
||||
{
|
||||
num = 65531;
|
||||
}
|
||||
}
|
||||
if (isFinal)
|
||||
{
|
||||
output.WriteBits(3, 1u);
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteBits(3, 0u);
|
||||
}
|
||||
output.FlushBits();
|
||||
WriteLenNLen((ushort)num, output);
|
||||
if (input != null && num > 0)
|
||||
{
|
||||
output.WriteBytes(input.Buffer, input.StartIndex, num);
|
||||
input.ConsumeBytes(num);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteLenNLen(ushort len, AAOutputBuffer output)
|
||||
{
|
||||
output.WriteUInt16(len);
|
||||
ushort value = (ushort)(~len);
|
||||
output.WriteUInt16(value);
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class AADeflateInput
|
||||
{
|
||||
internal struct InputState
|
||||
{
|
||||
internal int count;
|
||||
|
||||
internal int startIndex;
|
||||
}
|
||||
|
||||
private byte[] buffer;
|
||||
|
||||
private int count;
|
||||
|
||||
private int startIndex;
|
||||
|
||||
internal byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
set
|
||||
{
|
||||
buffer = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
set
|
||||
{
|
||||
count = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int StartIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return startIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
startIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal void ConsumeBytes(int n)
|
||||
{
|
||||
startIndex += n;
|
||||
count -= n;
|
||||
}
|
||||
|
||||
internal InputState DumpState()
|
||||
{
|
||||
InputState result = default(InputState);
|
||||
result.count = count;
|
||||
result.startIndex = startIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void RestoreState(InputState state)
|
||||
{
|
||||
count = state.count;
|
||||
startIndex = state.startIndex;
|
||||
}
|
||||
}
|
||||
+400
@@ -0,0 +1,400 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Invensys.Compression;
|
||||
|
||||
public class AADeflateStream : Stream
|
||||
{
|
||||
internal delegate void AsyncWriteDelegate(byte[] array, int offset, int count, bool isAsync);
|
||||
|
||||
internal const int DefaultBufferSize = 8192;
|
||||
|
||||
private Stream _stream;
|
||||
|
||||
private CompressionMode _mode;
|
||||
|
||||
private bool _leaveOpen;
|
||||
|
||||
private AADeflaterManaged deflater;
|
||||
|
||||
private byte[] buffer;
|
||||
|
||||
private int asyncOperations;
|
||||
|
||||
private readonly AsyncCallback m_CallBack;
|
||||
|
||||
private readonly AsyncWriteDelegate m_AsyncWriterDelegate;
|
||||
|
||||
private bool wroteBytes;
|
||||
|
||||
public Stream BaseStream => _stream;
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stream == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_mode == CompressionMode.Decompress)
|
||||
{
|
||||
return _stream.CanRead;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stream == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_mode == CompressionMode.Compress)
|
||||
{
|
||||
return _stream.CanWrite;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public AADeflateStream(Stream stream, CompressionMode mode)
|
||||
: this(stream, mode, leaveOpen: false)
|
||||
{
|
||||
}
|
||||
|
||||
public AADeflateStream(Stream stream, CompressionMode mode, bool leaveOpen)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
if (CompressionMode.Compress != mode && mode != CompressionMode.Decompress)
|
||||
{
|
||||
throw new ArgumentException("mode");
|
||||
}
|
||||
_stream = stream;
|
||||
_mode = mode;
|
||||
_leaveOpen = leaveOpen;
|
||||
switch (_mode)
|
||||
{
|
||||
case CompressionMode.Decompress:
|
||||
throw new ArgumentException("CompressionMode.Decompress - Unsupported");
|
||||
case CompressionMode.Compress:
|
||||
if (!_stream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("stream");
|
||||
}
|
||||
deflater = new AADeflaterManaged();
|
||||
m_AsyncWriterDelegate = InternalWrite;
|
||||
m_CallBack = WriteCallback;
|
||||
break;
|
||||
}
|
||||
buffer = new byte[8192];
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] array, int offset, int count)
|
||||
{
|
||||
throw new ArgumentException("Read - Unsupported");
|
||||
}
|
||||
|
||||
private void ValidateParameters(byte[] array, int offset, int count)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
throw new ArgumentNullException("array");
|
||||
}
|
||||
if (offset < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
if (count < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
if (array.Length - offset < count)
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureNotDisposed()
|
||||
{
|
||||
if (_stream == null)
|
||||
{
|
||||
throw new ObjectDisposedException(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureDecompressionMode()
|
||||
{
|
||||
if (_mode != CompressionMode.Decompress)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureCompressionMode()
|
||||
{
|
||||
if (_mode != CompressionMode.Compress)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
[HostProtection(SecurityAction.LinkDemand, ExternalThreading = true)]
|
||||
public override IAsyncResult BeginRead(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState)
|
||||
{
|
||||
throw new ArgumentException("BeginRead - Unsupported");
|
||||
}
|
||||
|
||||
private void ReadCallback(IAsyncResult baseStreamResult)
|
||||
{
|
||||
throw new ArgumentException("ReadCallback - Unsupported");
|
||||
}
|
||||
|
||||
public override int EndRead(IAsyncResult asyncResult)
|
||||
{
|
||||
EnsureDecompressionMode();
|
||||
CheckEndXxxxLegalStateAndParams(asyncResult);
|
||||
DeflateStreamAsyncResult deflateStreamAsyncResult = (DeflateStreamAsyncResult)asyncResult;
|
||||
AwaitAsyncResultCompletion(deflateStreamAsyncResult);
|
||||
if (deflateStreamAsyncResult.Result is Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
return (int)deflateStreamAsyncResult.Result;
|
||||
}
|
||||
|
||||
public override void Write(byte[] array, int offset, int count)
|
||||
{
|
||||
EnsureCompressionMode();
|
||||
ValidateParameters(array, offset, count);
|
||||
EnsureNotDisposed();
|
||||
InternalWrite(array, offset, count, isAsync: false);
|
||||
}
|
||||
|
||||
internal void InternalWrite(byte[] array, int offset, int count, bool isAsync)
|
||||
{
|
||||
DoMaintenance(array, offset, count);
|
||||
WriteDeflaterOutput(isAsync);
|
||||
deflater.SetInput(array, offset, count);
|
||||
WriteDeflaterOutput(isAsync);
|
||||
}
|
||||
|
||||
private void WriteDeflaterOutput(bool isAsync)
|
||||
{
|
||||
while (!deflater.NeedsInput())
|
||||
{
|
||||
int deflateOutput = deflater.GetDeflateOutput(buffer);
|
||||
if (deflateOutput > 0)
|
||||
{
|
||||
DoWrite(buffer, 0, deflateOutput, isAsync);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DoWrite(byte[] array, int offset, int count, bool isAsync)
|
||||
{
|
||||
if (isAsync)
|
||||
{
|
||||
IAsyncResult asyncResult = _stream.BeginWrite(array, offset, count, null, null);
|
||||
_stream.EndWrite(asyncResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream.Write(array, offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoMaintenance(byte[] array, int offset, int count)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
wroteBytes = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void PurgeBuffers(bool disposing)
|
||||
{
|
||||
if (!disposing || _stream == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Flush();
|
||||
if (_mode != CompressionMode.Compress || !wroteBytes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
WriteDeflaterOutput(isAsync: false);
|
||||
bool flag;
|
||||
do
|
||||
{
|
||||
flag = deflater.Finish(buffer, out var bytesRead);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
DoWrite(buffer, 0, bytesRead, isAsync: false);
|
||||
}
|
||||
}
|
||||
while (!flag);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
PurgeBuffers(disposing);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing && !_leaveOpen && _stream != null)
|
||||
{
|
||||
_stream.Close();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_stream = null;
|
||||
try
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HostProtection(SecurityAction.LinkDemand, ExternalThreading = true)]
|
||||
public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState)
|
||||
{
|
||||
EnsureCompressionMode();
|
||||
if (asyncOperations != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
ValidateParameters(array, offset, count);
|
||||
EnsureNotDisposed();
|
||||
Interlocked.Increment(ref asyncOperations);
|
||||
try
|
||||
{
|
||||
DeflateStreamAsyncResult deflateStreamAsyncResult = new DeflateStreamAsyncResult(this, asyncState, asyncCallback, array, offset, count);
|
||||
deflateStreamAsyncResult.isWrite = true;
|
||||
m_AsyncWriterDelegate.BeginInvoke(array, offset, count, isAsync: true, m_CallBack, deflateStreamAsyncResult);
|
||||
deflateStreamAsyncResult.m_CompletedSynchronously &= deflateStreamAsyncResult.IsCompleted;
|
||||
return deflateStreamAsyncResult;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Interlocked.Decrement(ref asyncOperations);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteCallback(IAsyncResult asyncResult)
|
||||
{
|
||||
DeflateStreamAsyncResult deflateStreamAsyncResult = (DeflateStreamAsyncResult)asyncResult.AsyncState;
|
||||
deflateStreamAsyncResult.m_CompletedSynchronously &= asyncResult.CompletedSynchronously;
|
||||
try
|
||||
{
|
||||
m_AsyncWriterDelegate.EndInvoke(asyncResult);
|
||||
}
|
||||
catch (Exception result)
|
||||
{
|
||||
deflateStreamAsyncResult.InvokeCallback(result);
|
||||
return;
|
||||
}
|
||||
deflateStreamAsyncResult.InvokeCallback(null);
|
||||
}
|
||||
|
||||
public override void EndWrite(IAsyncResult asyncResult)
|
||||
{
|
||||
EnsureCompressionMode();
|
||||
CheckEndXxxxLegalStateAndParams(asyncResult);
|
||||
DeflateStreamAsyncResult deflateStreamAsyncResult = (DeflateStreamAsyncResult)asyncResult;
|
||||
AwaitAsyncResultCompletion(deflateStreamAsyncResult);
|
||||
if (deflateStreamAsyncResult.Result is Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckEndXxxxLegalStateAndParams(IAsyncResult asyncResult)
|
||||
{
|
||||
if (asyncOperations != 1)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (asyncResult == null)
|
||||
{
|
||||
throw new ArgumentNullException("asyncResult");
|
||||
}
|
||||
EnsureNotDisposed();
|
||||
if (!(asyncResult is DeflateStreamAsyncResult))
|
||||
{
|
||||
throw new ArgumentNullException("asyncResult");
|
||||
}
|
||||
}
|
||||
|
||||
private void AwaitAsyncResultCompletion(DeflateStreamAsyncResult asyncResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!asyncResult.IsCompleted)
|
||||
{
|
||||
asyncResult.AsyncWaitHandle.WaitOne();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Decrement(ref asyncOperations);
|
||||
asyncResult.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
using System;
|
||||
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class AADeflaterManaged : IDisposable
|
||||
{
|
||||
private enum DeflaterState
|
||||
{
|
||||
NotStarted,
|
||||
SlowDownForIncompressible1,
|
||||
SlowDownForIncompressible2,
|
||||
StartingSmallData,
|
||||
CompressThenCheck,
|
||||
CheckingForIncompressible,
|
||||
HandlingSmallData
|
||||
}
|
||||
|
||||
private const int MinBlockSize = 256;
|
||||
|
||||
private const int MaxHeaderFooterGoo = 120;
|
||||
|
||||
private const int CleanCopySize = 8072;
|
||||
|
||||
private const double BadCompressionThreshold = 1.0;
|
||||
|
||||
private AAFastEncoder deflateEncoder;
|
||||
|
||||
private AACopyEncoder copyEncoder;
|
||||
|
||||
private AADeflateInput input;
|
||||
|
||||
private AAOutputBuffer output;
|
||||
|
||||
private DeflaterState processingState;
|
||||
|
||||
private AADeflateInput inputFromHistory;
|
||||
|
||||
internal AADeflaterManaged()
|
||||
{
|
||||
deflateEncoder = new AAFastEncoder();
|
||||
copyEncoder = new AACopyEncoder();
|
||||
input = new AADeflateInput();
|
||||
output = new AAOutputBuffer();
|
||||
processingState = DeflaterState.NotStarted;
|
||||
}
|
||||
|
||||
public bool NeedsInput()
|
||||
{
|
||||
if (input.Count == 0)
|
||||
{
|
||||
return deflateEncoder.BytesInHistory == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetInput(byte[] inputBuffer, int startIndex, int count)
|
||||
{
|
||||
input.Buffer = inputBuffer;
|
||||
input.Count = count;
|
||||
input.StartIndex = startIndex;
|
||||
if (count > 0 && count < 256)
|
||||
{
|
||||
switch (processingState)
|
||||
{
|
||||
case DeflaterState.NotStarted:
|
||||
case DeflaterState.CheckingForIncompressible:
|
||||
processingState = DeflaterState.StartingSmallData;
|
||||
break;
|
||||
case DeflaterState.CompressThenCheck:
|
||||
processingState = DeflaterState.HandlingSmallData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetDeflateOutput(byte[] outputBuffer)
|
||||
{
|
||||
output.UpdateBuffer(outputBuffer);
|
||||
switch (processingState)
|
||||
{
|
||||
case DeflaterState.NotStarted:
|
||||
{
|
||||
AADeflateInput.InputState state3 = input.DumpState();
|
||||
AAOutputBuffer.BufferState state4 = output.DumpState();
|
||||
deflateEncoder.GetBlockHeader(output);
|
||||
deflateEncoder.GetCompressedData(input, output);
|
||||
if (!UseCompressed(deflateEncoder.LastCompressionRatio))
|
||||
{
|
||||
input.RestoreState(state3);
|
||||
output.RestoreState(state4);
|
||||
copyEncoder.GetBlock(input, output, isFinal: false);
|
||||
FlushInputWindows();
|
||||
processingState = DeflaterState.CheckingForIncompressible;
|
||||
}
|
||||
else
|
||||
{
|
||||
processingState = DeflaterState.CompressThenCheck;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DeflaterState.CompressThenCheck:
|
||||
deflateEncoder.GetCompressedData(input, output);
|
||||
if (!UseCompressed(deflateEncoder.LastCompressionRatio))
|
||||
{
|
||||
processingState = DeflaterState.SlowDownForIncompressible1;
|
||||
inputFromHistory = deflateEncoder.UnprocessedInput;
|
||||
}
|
||||
break;
|
||||
case DeflaterState.SlowDownForIncompressible1:
|
||||
deflateEncoder.GetBlockFooter(output);
|
||||
processingState = DeflaterState.SlowDownForIncompressible2;
|
||||
goto case DeflaterState.SlowDownForIncompressible2;
|
||||
case DeflaterState.SlowDownForIncompressible2:
|
||||
if (inputFromHistory.Count > 0)
|
||||
{
|
||||
copyEncoder.GetBlock(inputFromHistory, output, isFinal: false);
|
||||
}
|
||||
if (inputFromHistory.Count == 0)
|
||||
{
|
||||
deflateEncoder.FlushInput();
|
||||
processingState = DeflaterState.CheckingForIncompressible;
|
||||
}
|
||||
break;
|
||||
case DeflaterState.CheckingForIncompressible:
|
||||
{
|
||||
AADeflateInput.InputState state = input.DumpState();
|
||||
AAOutputBuffer.BufferState state2 = output.DumpState();
|
||||
deflateEncoder.GetBlock(input, output, 8072);
|
||||
if (!UseCompressed(deflateEncoder.LastCompressionRatio))
|
||||
{
|
||||
input.RestoreState(state);
|
||||
output.RestoreState(state2);
|
||||
copyEncoder.GetBlock(input, output, isFinal: false);
|
||||
FlushInputWindows();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DeflaterState.StartingSmallData:
|
||||
deflateEncoder.GetBlockHeader(output);
|
||||
processingState = DeflaterState.HandlingSmallData;
|
||||
goto case DeflaterState.HandlingSmallData;
|
||||
case DeflaterState.HandlingSmallData:
|
||||
deflateEncoder.GetCompressedData(input, output);
|
||||
break;
|
||||
}
|
||||
return output.BytesWritten;
|
||||
}
|
||||
|
||||
public bool Finish(byte[] outputBuffer, out int bytesRead)
|
||||
{
|
||||
if (processingState == DeflaterState.NotStarted)
|
||||
{
|
||||
bytesRead = 0;
|
||||
return true;
|
||||
}
|
||||
output.UpdateBuffer(outputBuffer);
|
||||
if (processingState == DeflaterState.CompressThenCheck || processingState == DeflaterState.HandlingSmallData || processingState == DeflaterState.SlowDownForIncompressible1)
|
||||
{
|
||||
deflateEncoder.GetBlockFooter(output);
|
||||
}
|
||||
WriteFinal();
|
||||
bytesRead = output.BytesWritten;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
private bool UseCompressed(double ratio)
|
||||
{
|
||||
return ratio <= 1.0;
|
||||
}
|
||||
|
||||
private void FlushInputWindows()
|
||||
{
|
||||
deflateEncoder.FlushInput();
|
||||
}
|
||||
|
||||
private void WriteFinal()
|
||||
{
|
||||
copyEncoder.GetBlock(null, output, isFinal: true);
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
using System;
|
||||
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class AAFastEncoder
|
||||
{
|
||||
private AAFastEncoderWindow inputWindow;
|
||||
|
||||
private AAMatch currentMatch;
|
||||
|
||||
private double lastCompressionRatio;
|
||||
|
||||
internal int BytesInHistory => inputWindow.BytesAvailable;
|
||||
|
||||
internal AADeflateInput UnprocessedInput => inputWindow.UnprocessedInput;
|
||||
|
||||
internal double LastCompressionRatio => lastCompressionRatio;
|
||||
|
||||
public AAFastEncoder()
|
||||
{
|
||||
inputWindow = new AAFastEncoderWindow();
|
||||
currentMatch = new AAMatch();
|
||||
}
|
||||
|
||||
internal void FlushInput()
|
||||
{
|
||||
inputWindow.FlushWindow();
|
||||
}
|
||||
|
||||
internal void GetBlock(AADeflateInput input, AAOutputBuffer output, int maxBytesToCopy)
|
||||
{
|
||||
WriteDeflatePreamble(output);
|
||||
GetCompressedOutput(input, output, maxBytesToCopy);
|
||||
WriteEndOfBlock(output);
|
||||
}
|
||||
|
||||
internal void GetCompressedData(AADeflateInput input, AAOutputBuffer output)
|
||||
{
|
||||
GetCompressedOutput(input, output, -1);
|
||||
}
|
||||
|
||||
internal void GetBlockHeader(AAOutputBuffer output)
|
||||
{
|
||||
WriteDeflatePreamble(output);
|
||||
}
|
||||
|
||||
internal void GetBlockFooter(AAOutputBuffer output)
|
||||
{
|
||||
WriteEndOfBlock(output);
|
||||
}
|
||||
|
||||
private void GetCompressedOutput(AADeflateInput input, AAOutputBuffer output, int maxBytesToCopy)
|
||||
{
|
||||
int bytesWritten = output.BytesWritten;
|
||||
int num = 0;
|
||||
int num2 = BytesInHistory + input.Count;
|
||||
do
|
||||
{
|
||||
int num3 = ((input.Count < inputWindow.FreeWindowSpace) ? input.Count : inputWindow.FreeWindowSpace);
|
||||
if (maxBytesToCopy >= 1)
|
||||
{
|
||||
num3 = Math.Min(num3, maxBytesToCopy - num);
|
||||
}
|
||||
if (num3 > 0)
|
||||
{
|
||||
inputWindow.CopyBytes(input.Buffer, input.StartIndex, num3);
|
||||
input.ConsumeBytes(num3);
|
||||
num += num3;
|
||||
}
|
||||
GetCompressedOutput(output);
|
||||
}
|
||||
while (SafeToWriteTo(output) && InputAvailable(input) && (maxBytesToCopy < 1 || num < maxBytesToCopy));
|
||||
int num4 = output.BytesWritten - bytesWritten;
|
||||
int num5 = BytesInHistory + input.Count;
|
||||
int num6 = num2 - num5;
|
||||
if (num4 != 0)
|
||||
{
|
||||
lastCompressionRatio = (double)num4 / (double)num6;
|
||||
}
|
||||
}
|
||||
|
||||
private void GetCompressedOutput(AAOutputBuffer output)
|
||||
{
|
||||
while (inputWindow.BytesAvailable > 0 && SafeToWriteTo(output))
|
||||
{
|
||||
inputWindow.GetNextSymbolOrMatch(currentMatch);
|
||||
if (currentMatch.State == AAMatchState.HasSymbol)
|
||||
{
|
||||
WriteChar(currentMatch.Symbol, output);
|
||||
continue;
|
||||
}
|
||||
if (currentMatch.State == AAMatchState.HasMatch)
|
||||
{
|
||||
WriteMatch(currentMatch.Length, currentMatch.Position, output);
|
||||
continue;
|
||||
}
|
||||
WriteChar(currentMatch.Symbol, output);
|
||||
WriteMatch(currentMatch.Length, currentMatch.Position, output);
|
||||
}
|
||||
}
|
||||
|
||||
private bool InputAvailable(AADeflateInput input)
|
||||
{
|
||||
if (input.Count <= 0)
|
||||
{
|
||||
return BytesInHistory > 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SafeToWriteTo(AAOutputBuffer output)
|
||||
{
|
||||
return output.FreeBytes > 16;
|
||||
}
|
||||
|
||||
private void WriteEndOfBlock(AAOutputBuffer output)
|
||||
{
|
||||
uint num = AAFastEncoderStatics.FastEncoderLiteralCodeInfo[256];
|
||||
int n = (int)(num & 0x1F);
|
||||
output.WriteBits(n, num >> 5);
|
||||
}
|
||||
|
||||
internal static void WriteMatch(int matchLen, int matchPos, AAOutputBuffer output)
|
||||
{
|
||||
uint num = AAFastEncoderStatics.FastEncoderLiteralCodeInfo[254 + matchLen];
|
||||
int num2 = (int)(num & 0x1F);
|
||||
if (num2 <= 16)
|
||||
{
|
||||
output.WriteBits(num2, num >> 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteBits(16, (num >> 5) & 0xFFFF);
|
||||
output.WriteBits(num2 - 16, num >> 21);
|
||||
}
|
||||
num = AAFastEncoderStatics.FastEncoderDistanceCodeInfo[AAFastEncoderStatics.GetSlot(matchPos)];
|
||||
output.WriteBits((int)(num & 0xF), num >> 8);
|
||||
int num3 = (int)((num >> 4) & 0xF);
|
||||
if (num3 != 0)
|
||||
{
|
||||
output.WriteBits(num3, (uint)matchPos & AAFastEncoderStatics.BitMask[num3]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteChar(byte b, AAOutputBuffer output)
|
||||
{
|
||||
uint num = AAFastEncoderStatics.FastEncoderLiteralCodeInfo[b];
|
||||
output.WriteBits((int)(num & 0x1F), num >> 5);
|
||||
}
|
||||
|
||||
internal static void WriteDeflatePreamble(AAOutputBuffer output)
|
||||
{
|
||||
output.WriteBytes(AAFastEncoderStatics.FastEncoderTreeStructureData, 0, AAFastEncoderStatics.FastEncoderTreeStructureData.Length);
|
||||
output.WriteBits(9, 34u);
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal static class AAFastEncoderStatics
|
||||
{
|
||||
internal static readonly byte[] FastEncoderTreeStructureData;
|
||||
|
||||
internal static readonly byte[] BFinalFastEncoderTreeStructureData;
|
||||
|
||||
internal static readonly uint[] FastEncoderLiteralCodeInfo;
|
||||
|
||||
internal static readonly uint[] FastEncoderDistanceCodeInfo;
|
||||
|
||||
internal static readonly uint[] BitMask;
|
||||
|
||||
internal static readonly byte[] ExtraLengthBits;
|
||||
|
||||
internal static readonly byte[] ExtraDistanceBits;
|
||||
|
||||
internal const int NumChars = 256;
|
||||
|
||||
internal const int NumLengthBaseCodes = 29;
|
||||
|
||||
internal const int NumDistBaseCodes = 30;
|
||||
|
||||
internal const uint FastEncoderPostTreeBitBuf = 34u;
|
||||
|
||||
internal const int FastEncoderPostTreeBitCount = 9;
|
||||
|
||||
internal const uint NoCompressionHeader = 0u;
|
||||
|
||||
internal const int NoCompressionHeaderBitCount = 3;
|
||||
|
||||
internal const uint BFinalNoCompressionHeader = 1u;
|
||||
|
||||
internal const int BFinalNoCompressionHeaderBitCount = 3;
|
||||
|
||||
internal const int MaxCodeLen = 16;
|
||||
|
||||
private static byte[] distLookup;
|
||||
|
||||
static AAFastEncoderStatics()
|
||||
{
|
||||
FastEncoderTreeStructureData = new byte[98]
|
||||
{
|
||||
236, 189, 7, 96, 28, 73, 150, 37, 38, 47,
|
||||
109, 202, 123, 127, 74, 245, 74, 215, 224, 116,
|
||||
161, 8, 128, 96, 19, 36, 216, 144, 64, 16,
|
||||
236, 193, 136, 205, 230, 146, 236, 29, 105, 71,
|
||||
35, 41, 171, 42, 129, 202, 101, 86, 101, 93,
|
||||
102, 22, 64, 204, 237, 157, 188, 247, 222, 123,
|
||||
239, 189, 247, 222, 123, 239, 189, 247, 186, 59,
|
||||
157, 78, 39, 247, 223, 255, 63, 92, 102, 100,
|
||||
1, 108, 246, 206, 74, 218, 201, 158, 33, 128,
|
||||
170, 200, 31, 63, 126, 124, 31, 63
|
||||
};
|
||||
BFinalFastEncoderTreeStructureData = new byte[98]
|
||||
{
|
||||
237, 189, 7, 96, 28, 73, 150, 37, 38, 47,
|
||||
109, 202, 123, 127, 74, 245, 74, 215, 224, 116,
|
||||
161, 8, 128, 96, 19, 36, 216, 144, 64, 16,
|
||||
236, 193, 136, 205, 230, 146, 236, 29, 105, 71,
|
||||
35, 41, 171, 42, 129, 202, 101, 86, 101, 93,
|
||||
102, 22, 64, 204, 237, 157, 188, 247, 222, 123,
|
||||
239, 189, 247, 222, 123, 239, 189, 247, 186, 59,
|
||||
157, 78, 39, 247, 223, 255, 63, 92, 102, 100,
|
||||
1, 108, 246, 206, 74, 218, 201, 158, 33, 128,
|
||||
170, 200, 31, 63, 126, 124, 31, 63
|
||||
};
|
||||
FastEncoderLiteralCodeInfo = new uint[513]
|
||||
{
|
||||
55278u, 317422u, 186350u, 448494u, 120814u, 382958u, 251886u, 514030u, 14318u, 51180u,
|
||||
294u, 276462u, 145390u, 407534u, 79854u, 341998u, 210926u, 473070u, 47086u, 309230u,
|
||||
178158u, 440302u, 112622u, 374766u, 243694u, 505838u, 30702u, 292846u, 161774u, 423918u,
|
||||
6125u, 96238u, 1318u, 358382u, 9194u, 116716u, 227310u, 489454u, 137197u, 25578u,
|
||||
2920u, 3817u, 23531u, 5098u, 1127u, 7016u, 3175u, 12009u, 1896u, 5992u,
|
||||
3944u, 7913u, 8040u, 16105u, 21482u, 489u, 232u, 8681u, 4585u, 4328u,
|
||||
12777u, 13290u, 2280u, 63470u, 325614u, 6376u, 2537u, 1256u, 10729u, 5352u,
|
||||
6633u, 29674u, 56299u, 3304u, 15339u, 194542u, 14825u, 3050u, 1513u, 19434u,
|
||||
9705u, 10220u, 5609u, 13801u, 3561u, 11242u, 75756u, 48107u, 456686u, 129006u,
|
||||
42988u, 31723u, 391150u, 64491u, 260078u, 522222u, 4078u, 806u, 615u, 2663u,
|
||||
1639u, 1830u, 7400u, 744u, 3687u, 166u, 108524u, 11753u, 1190u, 359u,
|
||||
2407u, 678u, 1383u, 71661u, 1702u, 422u, 1446u, 3431u, 4840u, 2792u,
|
||||
7657u, 6888u, 2027u, 202733u, 26604u, 38893u, 169965u, 266222u, 135150u, 397294u,
|
||||
69614u, 331758u, 200686u, 462830u, 36846u, 298990u, 167918u, 430062u, 102382u, 364526u,
|
||||
233454u, 495598u, 20462u, 282606u, 151534u, 413678u, 85998u, 348142u, 217070u, 479214u,
|
||||
53230u, 315374u, 184302u, 446446u, 118766u, 380910u, 249838u, 511982u, 12270u, 274414u,
|
||||
143342u, 405486u, 77806u, 339950u, 208878u, 471022u, 45038u, 307182u, 176110u, 438254u,
|
||||
110574u, 372718u, 241646u, 503790u, 28654u, 290798u, 159726u, 421870u, 94190u, 356334u,
|
||||
225262u, 487406u, 61422u, 323566u, 192494u, 454638u, 126958u, 389102u, 258030u, 520174u,
|
||||
8174u, 270318u, 139246u, 401390u, 73710u, 335854u, 204782u, 466926u, 40942u, 303086u,
|
||||
172014u, 434158u, 106478u, 368622u, 237550u, 499694u, 24558u, 286702u, 155630u, 417774u,
|
||||
90094u, 352238u, 221166u, 483310u, 57326u, 319470u, 188398u, 450542u, 122862u, 385006u,
|
||||
253934u, 516078u, 16366u, 278510u, 147438u, 409582u, 81902u, 344046u, 212974u, 475118u,
|
||||
49134u, 311278u, 180206u, 442350u, 114670u, 376814u, 245742u, 507886u, 32750u, 294894u,
|
||||
163822u, 425966u, 98286u, 104429u, 235501u, 22509u, 360430u, 153581u, 229358u, 88045u,
|
||||
491502u, 219117u, 65518u, 327662u, 196590u, 458734u, 131054u, 132u, 3u, 388u,
|
||||
68u, 324u, 197u, 709u, 453u, 966u, 1990u, 38u, 1062u, 935u,
|
||||
2983u, 1959u, 4007u, 551u, 1575u, 2599u, 3623u, 104u, 2152u, 4200u,
|
||||
6248u, 873u, 4969u, 9065u, 13161u, 1770u, 9962u, 18154u, 26346u, 5867u,
|
||||
14059u, 22251u, 30443u, 38635u, 46827u, 55019u, 63211u, 15852u, 32236u, 48620u,
|
||||
65004u, 81388u, 97772u, 114156u, 130540u, 27629u, 60397u, 93165u, 125933u, 158701u,
|
||||
191469u, 224237u, 257005u, 1004u, 17388u, 33772u, 50156u, 66540u, 82924u, 99308u,
|
||||
115692u, 7150u, 39918u, 72686u, 105454u, 138222u, 170990u, 203758u, 236526u, 269294u,
|
||||
302062u, 334830u, 367598u, 400366u, 433134u, 465902u, 498670u, 92144u, 223216u, 354288u,
|
||||
485360u, 616432u, 747504u, 878576u, 1009648u, 1140720u, 1271792u, 1402864u, 1533936u, 1665008u,
|
||||
1796080u, 1927152u, 2058224u, 34799u, 100335u, 165871u, 231407u, 296943u, 362479u, 428015u,
|
||||
493551u, 559087u, 624623u, 690159u, 755695u, 821231u, 886767u, 952303u, 1017839u, 59376u,
|
||||
190448u, 321520u, 452592u, 583664u, 714736u, 845808u, 976880u, 1107952u, 1239024u, 1370096u,
|
||||
1501168u, 1632240u, 1763312u, 1894384u, 2025456u, 393203u, 917491u, 1441779u, 1966067u, 2490355u,
|
||||
3014643u, 3538931u, 4063219u, 4587507u, 5111795u, 5636083u, 6160371u, 6684659u, 7208947u, 7733235u,
|
||||
8257523u, 8781811u, 9306099u, 9830387u, 10354675u, 10878963u, 11403251u, 11927539u, 12451827u, 12976115u,
|
||||
13500403u, 14024691u, 14548979u, 15073267u, 15597555u, 16121843u, 16646131u, 262131u, 786419u, 1310707u,
|
||||
1834995u, 2359283u, 2883571u, 3407859u, 3932147u, 4456435u, 4980723u, 5505011u, 6029299u, 6553587u,
|
||||
7077875u, 7602163u, 8126451u, 8650739u, 9175027u, 9699315u, 10223603u, 10747891u, 11272179u, 11796467u,
|
||||
12320755u, 12845043u, 13369331u, 13893619u, 14417907u, 14942195u, 15466483u, 15990771u, 16515059u, 524275u,
|
||||
1048563u, 1572851u, 2097139u, 2621427u, 3145715u, 3670003u, 4194291u, 4718579u, 5242867u, 5767155u,
|
||||
6291443u, 6815731u, 7340019u, 7864307u, 8388595u, 8912883u, 9437171u, 9961459u, 10485747u, 11010035u,
|
||||
11534323u, 12058611u, 12582899u, 13107187u, 13631475u, 14155763u, 14680051u, 15204339u, 15728627u, 16252915u,
|
||||
16777203u, 124913u, 255985u, 387057u, 518129u, 649201u, 780273u, 911345u, 1042417u, 1173489u,
|
||||
1304561u, 1435633u, 1566705u, 1697777u, 1828849u, 1959921u, 2090993u, 2222065u, 2353137u, 2484209u,
|
||||
2615281u, 2746353u, 2877425u, 3008497u, 3139569u, 3270641u, 3401713u, 3532785u, 3663857u, 3794929u,
|
||||
3926001u, 4057073u, 18411u
|
||||
};
|
||||
FastEncoderDistanceCodeInfo = new uint[32]
|
||||
{
|
||||
3846u, 130826u, 261899u, 524043u, 65305u, 16152u, 48936u, 32552u, 7991u, 24375u,
|
||||
3397u, 12102u, 84u, 7509u, 2148u, 869u, 1140u, 4981u, 3204u, 644u,
|
||||
2708u, 1684u, 3748u, 420u, 2484u, 2997u, 1476u, 7109u, 2005u, 6101u,
|
||||
0u, 256u
|
||||
};
|
||||
BitMask = new uint[16]
|
||||
{
|
||||
0u, 1u, 3u, 7u, 15u, 31u, 63u, 127u, 255u, 511u,
|
||||
1023u, 2047u, 4095u, 8191u, 16383u, 32767u
|
||||
};
|
||||
ExtraLengthBits = new byte[29]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
ExtraDistanceBits = new byte[32]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
|
||||
4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
|
||||
0, 0
|
||||
};
|
||||
distLookup = new byte[512];
|
||||
int num = 0;
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
for (int j = 0; j < 1 << (int)ExtraDistanceBits[i]; j++)
|
||||
{
|
||||
distLookup[num++] = (byte)i;
|
||||
}
|
||||
}
|
||||
num >>= 7;
|
||||
for (; i < 30; i++)
|
||||
{
|
||||
for (int k = 0; k < 1 << ExtraDistanceBits[i] - 7; k++)
|
||||
{
|
||||
distLookup[256 + num++] = (byte)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static int GetSlot(int pos)
|
||||
{
|
||||
return distLookup[(pos < 256) ? pos : (256 + (pos >> 7))];
|
||||
}
|
||||
|
||||
public static uint BitReverse(uint code, int length)
|
||||
{
|
||||
uint num = 0u;
|
||||
do
|
||||
{
|
||||
num |= code & 1;
|
||||
num <<= 1;
|
||||
code >>= 1;
|
||||
}
|
||||
while (--length > 0);
|
||||
return num >> 1;
|
||||
}
|
||||
}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class AAFastEncoderWindow
|
||||
{
|
||||
private byte[] window;
|
||||
|
||||
private int bufPos;
|
||||
|
||||
private int bufEnd;
|
||||
|
||||
private const int FastEncoderHashShift = 4;
|
||||
|
||||
private const int FastEncoderHashtableSize = 2048;
|
||||
|
||||
private const int FastEncoderHashMask = 2047;
|
||||
|
||||
private const int FastEncoderWindowSize = 8192;
|
||||
|
||||
private const int FastEncoderWindowMask = 8191;
|
||||
|
||||
private const int FastEncoderMatch3DistThreshold = 16384;
|
||||
|
||||
internal const int MaxMatch = 258;
|
||||
|
||||
internal const int MinMatch = 3;
|
||||
|
||||
private const int SearchDepth = 32;
|
||||
|
||||
private const int GoodLength = 4;
|
||||
|
||||
private const int NiceLength = 32;
|
||||
|
||||
private const int LazyMatchThreshold = 6;
|
||||
|
||||
private ushort[] prev;
|
||||
|
||||
private ushort[] lookup;
|
||||
|
||||
public int BytesAvailable => bufEnd - bufPos;
|
||||
|
||||
public AADeflateInput UnprocessedInput => new AADeflateInput
|
||||
{
|
||||
Buffer = window,
|
||||
StartIndex = bufPos,
|
||||
Count = bufEnd - bufPos
|
||||
};
|
||||
|
||||
public int FreeWindowSpace => 16384 - bufEnd;
|
||||
|
||||
public AAFastEncoderWindow()
|
||||
{
|
||||
ResetWindow();
|
||||
}
|
||||
|
||||
public void FlushWindow()
|
||||
{
|
||||
ResetWindow();
|
||||
}
|
||||
|
||||
private void ResetWindow()
|
||||
{
|
||||
window = new byte[16646];
|
||||
prev = new ushort[8450];
|
||||
lookup = new ushort[2048];
|
||||
bufPos = 8192;
|
||||
bufEnd = bufPos;
|
||||
}
|
||||
|
||||
public void CopyBytes(byte[] inputBuffer, int startIndex, int count)
|
||||
{
|
||||
Array.Copy(inputBuffer, startIndex, window, bufEnd, count);
|
||||
bufEnd += count;
|
||||
}
|
||||
|
||||
public void MoveWindows()
|
||||
{
|
||||
Array.Copy(window, bufPos - 8192, window, 0, 8192);
|
||||
for (int i = 0; i < 2048; i++)
|
||||
{
|
||||
int num = lookup[i] - 8192;
|
||||
if (num <= 0)
|
||||
{
|
||||
lookup[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lookup[i] = (ushort)num;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 8192; i++)
|
||||
{
|
||||
long num2 = (long)prev[i] - 8192L;
|
||||
if (num2 <= 0)
|
||||
{
|
||||
prev[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev[i] = (ushort)num2;
|
||||
}
|
||||
}
|
||||
bufPos = 8192;
|
||||
bufEnd = bufPos;
|
||||
}
|
||||
|
||||
private uint HashValue(uint hash, byte b)
|
||||
{
|
||||
return (hash << 4) ^ b;
|
||||
}
|
||||
|
||||
private uint InsertString(ref uint hash)
|
||||
{
|
||||
hash = HashValue(hash, window[bufPos + 2]);
|
||||
uint num = lookup[hash & 0x7FF];
|
||||
lookup[hash & 0x7FF] = (ushort)bufPos;
|
||||
prev[bufPos & 0x1FFF] = (ushort)num;
|
||||
return num;
|
||||
}
|
||||
|
||||
private void InsertStrings(ref uint hash, int matchLen)
|
||||
{
|
||||
if (bufEnd - bufPos <= matchLen)
|
||||
{
|
||||
bufPos += matchLen - 1;
|
||||
return;
|
||||
}
|
||||
while (--matchLen > 0)
|
||||
{
|
||||
InsertString(ref hash);
|
||||
bufPos++;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool GetNextSymbolOrMatch(AAMatch match)
|
||||
{
|
||||
uint hash = HashValue(0u, window[bufPos]);
|
||||
hash = HashValue(hash, window[bufPos + 1]);
|
||||
int matchPos = 0;
|
||||
int num;
|
||||
if (bufEnd - bufPos <= 3)
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int num2 = (int)InsertString(ref hash);
|
||||
if (num2 != 0)
|
||||
{
|
||||
num = FindMatch(num2, out matchPos, 32, 32);
|
||||
if (bufPos + num > bufEnd)
|
||||
{
|
||||
num = bufEnd - bufPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
}
|
||||
if (num < 3)
|
||||
{
|
||||
match.State = AAMatchState.HasSymbol;
|
||||
match.Symbol = window[bufPos];
|
||||
bufPos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufPos++;
|
||||
if (num <= 6)
|
||||
{
|
||||
int matchPos2 = 0;
|
||||
int num3 = (int)InsertString(ref hash);
|
||||
int num4;
|
||||
if (num3 != 0)
|
||||
{
|
||||
num4 = FindMatch(num3, out matchPos2, (num < 4) ? 32 : 8, 32);
|
||||
if (bufPos + num4 > bufEnd)
|
||||
{
|
||||
num4 = bufEnd - bufPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num4 = 0;
|
||||
}
|
||||
if (num4 > num)
|
||||
{
|
||||
match.State = AAMatchState.HasSymbolAndMatch;
|
||||
match.Symbol = window[bufPos - 1];
|
||||
match.Position = matchPos2;
|
||||
match.Length = num4;
|
||||
bufPos++;
|
||||
num = num4;
|
||||
InsertStrings(ref hash, num);
|
||||
}
|
||||
else
|
||||
{
|
||||
match.State = AAMatchState.HasMatch;
|
||||
match.Position = matchPos;
|
||||
match.Length = num;
|
||||
num--;
|
||||
bufPos++;
|
||||
InsertStrings(ref hash, num);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match.State = AAMatchState.HasMatch;
|
||||
match.Position = matchPos;
|
||||
match.Length = num;
|
||||
InsertStrings(ref hash, num);
|
||||
}
|
||||
}
|
||||
if (bufPos == 16384)
|
||||
{
|
||||
MoveWindows();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int FindMatch(int search, out int matchPos, int searchDepth, int niceLength)
|
||||
{
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
int num3 = bufPos - 8192;
|
||||
byte b = window[bufPos];
|
||||
while (search > num3)
|
||||
{
|
||||
if (window[search + num] == b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 258 && window[bufPos + i] == window[search + i]; i++)
|
||||
{
|
||||
}
|
||||
if (i > num)
|
||||
{
|
||||
num = i;
|
||||
num2 = search;
|
||||
if (i > 32)
|
||||
{
|
||||
break;
|
||||
}
|
||||
b = window[bufPos + i];
|
||||
}
|
||||
}
|
||||
if (--searchDepth == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
search = prev[search & 0x1FFF];
|
||||
}
|
||||
matchPos = bufPos - num2 - 1;
|
||||
if (num == 3 && matchPos >= 16384)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void VerifyHashes()
|
||||
{
|
||||
for (int i = 0; i < 2048; i++)
|
||||
{
|
||||
ushort num = lookup[i];
|
||||
while (num != 0 && bufPos - num < 8192)
|
||||
{
|
||||
ushort num2 = prev[num & 0x1FFF];
|
||||
if (bufPos - num2 >= 8192)
|
||||
{
|
||||
break;
|
||||
}
|
||||
num = num2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint RecalculateHash(int position)
|
||||
{
|
||||
return (uint)(((window[position] << 8) ^ (window[position + 1] << 4) ^ window[position + 2]) & 0x7FF);
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class AAMatch
|
||||
{
|
||||
private AAMatchState state;
|
||||
|
||||
private int pos;
|
||||
|
||||
private int len;
|
||||
|
||||
private byte symbol;
|
||||
|
||||
internal AAMatchState State
|
||||
{
|
||||
get
|
||||
{
|
||||
return state;
|
||||
}
|
||||
set
|
||||
{
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
set
|
||||
{
|
||||
pos = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return len;
|
||||
}
|
||||
set
|
||||
{
|
||||
len = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte Symbol
|
||||
{
|
||||
get
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
set
|
||||
{
|
||||
symbol = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal enum AAMatchState
|
||||
{
|
||||
HasSymbol,
|
||||
HasMatch,
|
||||
HasSymbolAndMatch
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class AAOutputBuffer
|
||||
{
|
||||
internal struct BufferState
|
||||
{
|
||||
internal int pos;
|
||||
|
||||
internal uint bitBuf;
|
||||
|
||||
internal int bitCount;
|
||||
}
|
||||
|
||||
private byte[] byteBuffer;
|
||||
|
||||
private int pos;
|
||||
|
||||
private uint bitBuf;
|
||||
|
||||
private int bitCount;
|
||||
|
||||
internal int BytesWritten => pos;
|
||||
|
||||
internal int FreeBytes => byteBuffer.Length - pos;
|
||||
|
||||
internal int BitsInBuffer => bitCount / 8 + 1;
|
||||
|
||||
internal void UpdateBuffer(byte[] output)
|
||||
{
|
||||
byteBuffer = output;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
internal void WriteUInt16(ushort value)
|
||||
{
|
||||
byteBuffer[pos++] = (byte)value;
|
||||
byteBuffer[pos++] = (byte)(value >> 8);
|
||||
}
|
||||
|
||||
internal void WriteBits(int n, uint bits)
|
||||
{
|
||||
bitBuf |= bits << bitCount;
|
||||
bitCount += n;
|
||||
if (bitCount >= 16)
|
||||
{
|
||||
byteBuffer[pos++] = (byte)bitBuf;
|
||||
byteBuffer[pos++] = (byte)(bitBuf >> 8);
|
||||
bitCount -= 16;
|
||||
bitBuf >>= 16;
|
||||
}
|
||||
}
|
||||
|
||||
internal void FlushBits()
|
||||
{
|
||||
while (bitCount >= 8)
|
||||
{
|
||||
byteBuffer[pos++] = (byte)bitBuf;
|
||||
bitCount -= 8;
|
||||
bitBuf >>= 8;
|
||||
}
|
||||
if (bitCount > 0)
|
||||
{
|
||||
byteBuffer[pos++] = (byte)bitBuf;
|
||||
bitBuf = 0u;
|
||||
bitCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteBytes(byte[] byteArray, int offset, int count)
|
||||
{
|
||||
if (bitCount == 0)
|
||||
{
|
||||
Array.Copy(byteArray, offset, byteBuffer, pos, count);
|
||||
pos += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBytesUnaligned(byteArray, offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteBytesUnaligned(byte[] byteArray, int offset, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
byte b = byteArray[offset + i];
|
||||
WriteByteUnaligned(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteByteUnaligned(byte b)
|
||||
{
|
||||
WriteBits(8, b);
|
||||
}
|
||||
|
||||
internal BufferState DumpState()
|
||||
{
|
||||
BufferState result = default(BufferState);
|
||||
result.pos = pos;
|
||||
result.bitBuf = bitBuf;
|
||||
result.bitCount = bitCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void RestoreState(BufferState state)
|
||||
{
|
||||
pos = state.pos;
|
||||
bitBuf = state.bitBuf;
|
||||
bitCount = state.bitCount;
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Invensys.Compression;
|
||||
|
||||
internal class DeflateStreamAsyncResult : IAsyncResult
|
||||
{
|
||||
public byte[] buffer;
|
||||
|
||||
public int offset;
|
||||
|
||||
public int count;
|
||||
|
||||
public bool isWrite;
|
||||
|
||||
private object m_AsyncObject;
|
||||
|
||||
private object m_AsyncState;
|
||||
|
||||
private AsyncCallback m_AsyncCallback;
|
||||
|
||||
private object m_Result;
|
||||
|
||||
internal bool m_CompletedSynchronously;
|
||||
|
||||
private int m_InvokedCallback;
|
||||
|
||||
private int m_Completed;
|
||||
|
||||
private object m_Event;
|
||||
|
||||
public object AsyncState => m_AsyncState;
|
||||
|
||||
public WaitHandle AsyncWaitHandle
|
||||
{
|
||||
get
|
||||
{
|
||||
int completed = m_Completed;
|
||||
if (m_Event == null)
|
||||
{
|
||||
Interlocked.CompareExchange(ref m_Event, new ManualResetEvent(completed != 0), null);
|
||||
}
|
||||
ManualResetEvent manualResetEvent = (ManualResetEvent)m_Event;
|
||||
if (completed == 0 && m_Completed != 0)
|
||||
{
|
||||
manualResetEvent.Set();
|
||||
}
|
||||
return manualResetEvent;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CompletedSynchronously => m_CompletedSynchronously;
|
||||
|
||||
public bool IsCompleted => m_Completed != 0;
|
||||
|
||||
internal object Result => m_Result;
|
||||
|
||||
public DeflateStreamAsyncResult(object asyncObject, object asyncState, AsyncCallback asyncCallback, byte[] buffer, int offset, int count)
|
||||
{
|
||||
this.buffer = buffer;
|
||||
this.offset = offset;
|
||||
this.count = count;
|
||||
m_CompletedSynchronously = true;
|
||||
m_AsyncObject = asyncObject;
|
||||
m_AsyncState = asyncState;
|
||||
m_AsyncCallback = asyncCallback;
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
if (m_Event != null)
|
||||
{
|
||||
((ManualResetEvent)m_Event).Close();
|
||||
}
|
||||
}
|
||||
|
||||
internal void InvokeCallback(bool completedSynchronously, object result)
|
||||
{
|
||||
Complete(completedSynchronously, result);
|
||||
}
|
||||
|
||||
internal void InvokeCallback(object result)
|
||||
{
|
||||
Complete(result);
|
||||
}
|
||||
|
||||
private void Complete(bool completedSynchronously, object result)
|
||||
{
|
||||
m_CompletedSynchronously = completedSynchronously;
|
||||
Complete(result);
|
||||
}
|
||||
|
||||
private void Complete(object result)
|
||||
{
|
||||
m_Result = result;
|
||||
Interlocked.Increment(ref m_Completed);
|
||||
if (m_Event != null)
|
||||
{
|
||||
((ManualResetEvent)m_Event).Set();
|
||||
}
|
||||
if (Interlocked.Increment(ref m_InvokedCallback) == 1 && m_AsyncCallback != null)
|
||||
{
|
||||
m_AsyncCallback(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user