Files
mxaccess/analysis/decompiled/aaServicesContractIAuthenticateASB/Invensys.Compression/AAFastEncoder.cs
T
Joseph Doherty fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
Initial project state: .NET reference, design, Rust port (M0+M1), evidence
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>
2026-05-05 06:21:00 -04:00

157 lines
3.9 KiB
C#

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);
}
}