Skip to content

Commit

Permalink
Drop ancient zlib dependency in favor of native .NET library calls. (#…
Browse files Browse the repository at this point in the history
…897)

Due to different naming of those compression libraries per OS there is a custom dll import resolver used.
  • Loading branch information
Fabi authored Dec 4, 2024
1 parent 79181b7 commit b8b945e
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 76 deletions.
10 changes: 10 additions & 0 deletions WowPacketParser/Misc/FlushCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace WowPacketParser.Misc
{
public enum FlushCode
{
NoFlush = 0,
SyncFlush = 2,
Finish = 4,
Block = 5
}
}
78 changes: 6 additions & 72 deletions WowPacketParser/Misc/Packet.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Google.Protobuf.WellKnownTypes;
using Ionic.Zlib;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using WowPacketParser.Enums;
using WowPacketParser.Enums.Version;
Expand Down Expand Up @@ -95,26 +95,7 @@ public void AddSniffData(StoreNameType type, int id, string data)
Storage.SniffData.Add(item, TimeSpan);
}

public bool TryInflate(int inflatedSize, int index, byte[] arr, ref byte[] newarr)
{
try
{
if (!SessionHandler.ZStreams.ContainsKey(index))
SessionHandler.ZStreams[index] = new ZlibCodec(CompressionMode.Decompress);
SessionHandler.ZStreams[index].InputBuffer = arr;
SessionHandler.ZStreams[index].NextIn = 0;
SessionHandler.ZStreams[index].AvailableBytesIn = arr.Length;
SessionHandler.ZStreams[index].OutputBuffer = newarr;
SessionHandler.ZStreams[index].NextOut = 0;
SessionHandler.ZStreams[index].AvailableBytesOut = inflatedSize;
SessionHandler.ZStreams[index].Inflate(FlushType.Sync);
return true;
}
catch (ZlibException)
{
return false;
}
}
public void ResetInflateStream() => ZLibHelper.ResetInflateStream(ConnectionIndex);

public Packet Inflate(int inflatedSize, bool keepStream = true)
{
Expand All @@ -127,36 +108,12 @@ public Packet Inflate(int inflatedSize, bool keepStream = true)
if (keepStream)
{
int idx = ConnectionIndex;
while (!TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4)
while (!ZLibHelper.TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4)
idx += 1;
}
else
{
/*try
{
var inflater = new Inflater(true);
inflater.SetInput(arr, 0, arr.Length);
inflater.Inflate(newarr, 0, inflatedSize);
}
catch (ICSharpCode.SharpZipLib.SharpZipBaseException)
{
var inflater = new Inflater(true);
inflater.SetInput(arr, 0, arr.Length);
inflater.Inflate(newarr, 0, inflatedSize);
}*/
var stream = new ZlibCodec(CompressionMode.Decompress)
{
InputBuffer = arr,
NextIn = 0,
AvailableBytesIn = arr.Length,
OutputBuffer = newarr,
NextOut = 0,
AvailableBytesOut = inflatedSize
};

stream.Inflate(FlushType.None);
stream.Inflate(FlushType.Finish);
stream.EndInflate();
ZLibHelper.Inflate(inflatedSize, arr, newarr);
}

// Cannot use "using" here
Expand All @@ -178,35 +135,12 @@ public Packet Inflate(int arrSize, int inflatedSize, bool keepStream = true)
if (keepStream)
{
int idx = ConnectionIndex;
while (!TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4)
while (!ZLibHelper.TryInflate(inflatedSize, idx, arr, ref newarr) && idx <= 4)
idx += 1;
}
else
{
/*try
{
var inflater = new Inflater(true);
inflater.SetInput(arr, 0, arr.Length);
inflater.Inflate(newarr, 0, inflatedSize);
}
catch (ICSharpCode.SharpZipLib.SharpZipBaseException)
{
var inflater = new Inflater(true);
inflater.SetInput(arr, 0, arr.Length);
inflater.Inflate(newarr, 0, inflatedSize);
}*/
var stream = new ZlibCodec(CompressionMode.Decompress)
{
InputBuffer = arr,
NextIn = 0,
AvailableBytesIn = arr.Length,
OutputBuffer = newarr,
NextOut = 0,
AvailableBytesOut = inflatedSize
};
stream.Inflate(FlushType.None);
stream.Inflate(FlushType.Finish);
stream.EndInflate();
ZLibHelper.Inflate(inflatedSize, arr, newarr);
}

// Cannot use "using" here
Expand Down
80 changes: 80 additions & 0 deletions WowPacketParser/Misc/ZLibHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Runtime.InteropServices;
using WowPacketParser.Parsing.Parsers;

namespace WowPacketParser.Misc
{
internal partial class ZLibHelper
{
private const string CompressionLib = "compression_native";

[LibraryImport(CompressionLib, EntryPoint = "CompressionNative_InflateInit2_")]
private static partial int InflateInit2(ref ZStream zStream, int windowBits);

[LibraryImport(CompressionLib, EntryPoint = "CompressionNative_Inflate")]
private static partial int Inflate(ref ZStream zStream, FlushCode flush);

[LibraryImport(CompressionLib, EntryPoint = "CompressionNative_InflateEnd")]
private static partial int InflateEnd(ref ZStream zStream);

public static void ResetInflateStream(int connectionIndex)
{
ref var zStream = ref CollectionsMarshal.GetValueRefOrAddDefault(SessionHandler.ZStreams, connectionIndex, out bool exists);

InflateInit2(ref zStream, 15);
}

public static unsafe bool TryInflate(int inflatedSize, int index, byte[] arr, ref byte[] newarr)
{
try
{
ref var zStream = ref CollectionsMarshal.GetValueRefOrAddDefault(SessionHandler.ZStreams, index, out bool exists);

if (!exists)
{
var initResult = InflateInit2(ref zStream, 15);

if (initResult != 0)
return false;
}

fixed (byte* compressedData = arr)
fixed (byte* uncompressedData = newarr)
{
zStream.AvailIn = (uint)arr.Length;
zStream.NextIn = compressedData;
zStream.AvailOut = (uint)inflatedSize;
zStream.NextOut = uncompressedData;

Inflate(ref zStream, FlushCode.SyncFlush);
}

return true;
}
catch (Exception)
{
return false;
}
}

public static unsafe void Inflate(int inflatedSize, byte[] arr, byte[] newarr)
{
ZStream zStream = default;

InflateInit2(ref zStream, 15);

fixed (byte* compressedData = arr)
fixed (byte* uncompressedData = newarr)
{
zStream.AvailIn = (uint)arr.Length;
zStream.NextIn = compressedData;
zStream.AvailOut = (uint)inflatedSize;
zStream.NextOut = uncompressedData;

Inflate(ref zStream, FlushCode.NoFlush);
Inflate(ref zStream, FlushCode.Finish);
InflateEnd(ref zStream);
}
}
}
}
17 changes: 17 additions & 0 deletions WowPacketParser/Misc/ZStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Runtime.InteropServices;

namespace WowPacketParser.Misc
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public unsafe struct ZStream
{
internal byte* NextIn;
internal byte* NextOut;
internal nint Msg;

readonly nint InternalState;

internal uint AvailIn;
internal uint AvailOut;
}
}
5 changes: 2 additions & 3 deletions WowPacketParser/Parsing/Parsers/SessionHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Ionic.Zlib;
using System;
using System.Collections.Generic;
using System.Text;
Expand All @@ -10,7 +9,7 @@ namespace WowPacketParser.Parsing.Parsers
public static class SessionHandler
{
public static WowGuid LoginGuid;
public static Dictionary<int, ZlibCodec> ZStreams = new Dictionary<int, ZlibCodec>();
public static Dictionary<int, ZStream> ZStreams = new Dictionary<int, ZStream>();

[Parser(Opcode.SMSG_AUTH_CHALLENGE, ClientVersionBuild.Zero, ClientVersionBuild.V4_0_1a_13205)]
public static void HandleServerAuthChallenge(Packet packet)
Expand Down Expand Up @@ -559,7 +558,7 @@ public static void HandleMessageOfTheDay(Packet packet)
public static void HandleResetCompressionContext(Packet packet)
{
packet.ReadInt32("Unk?");
ZStreams[packet.ConnectionIndex] = new ZlibCodec(CompressionMode.Decompress);
packet.ResetInflateStream();
}
}
}
19 changes: 19 additions & 0 deletions WowPacketParser/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using WowPacketParser.Loading;
using WowPacketParser.Misc;
Expand All @@ -15,6 +17,23 @@ public static class Program
{
private static void Main(string[] args)
{
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), (libraryName, assembly, searchPath) =>
{
if (libraryName.Equals("compression_native", StringComparison.OrdinalIgnoreCase))
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return NativeLibrary.Load("System.IO.Compression.Native.dll", assembly, searchPath);

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return NativeLibrary.Load("libSystem.IO.Compression.Native.dylib", assembly, searchPath);

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return NativeLibrary.Load("libSystem.IO.Compression.Native.so", assembly, searchPath);
}

return default;
});

SetUpWindowTitle();
SetUpConsole();

Expand Down
1 change: 0 additions & 1 deletion WowPacketParser/WowPacketParser.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Iconic.Zlib.Netstandard" Version="1.0.0" />
<PackageReference Include="MySql.Data" Version="8.3.0" />
<PackageReference Include="RawScape.Wintellect.PowerCollections" Version="1.0.1" />
<PackageReference Include="Sigil" Version="5.0.0" />
Expand Down

0 comments on commit b8b945e

Please sign in to comment.