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
Due to different naming of those compression libraries per OS there is a custom dll import resolver used.
  • Loading branch information
Fabi committed Dec 3, 2024
1 parent 79181b7 commit d1361e3
Show file tree
Hide file tree
Showing 7 changed files with 146 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
92 changes: 92 additions & 0 deletions WowPacketParser/Misc/ZLibHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
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 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;
}

nint uncompressedDataPtr = Marshal.AllocHGlobal(inflatedSize);
nint compressedDataPtr = Marshal.AllocHGlobal(arr.Length);

Marshal.Copy(arr, 0, compressedDataPtr, arr.Length);

zStream.AvailIn = (uint)arr.Length;
zStream.NextIn = compressedDataPtr;
zStream.AvailOut = (uint)inflatedSize;
zStream.NextOut = uncompressedDataPtr;

Inflate(ref zStream, FlushCode.SyncFlush);

Marshal.Copy(uncompressedDataPtr, newarr, 0, inflatedSize);

Marshal.FreeHGlobal(compressedDataPtr);
Marshal.FreeHGlobal(uncompressedDataPtr);

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

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

InflateInit2(ref zStream, 15);

nint uncompressedDataPtr = Marshal.AllocHGlobal(inflatedSize);
nint compressedDataPtr = Marshal.AllocHGlobal(arr.Length);

Marshal.Copy(arr, 0, compressedDataPtr, arr.Length);

zStream.AvailIn = (uint)arr.Length;
zStream.NextIn = compressedDataPtr;
zStream.AvailOut = (uint)inflatedSize;
zStream.NextOut = uncompressedDataPtr;

Inflate(ref zStream, FlushCode.NoFlush);
Inflate(ref zStream, FlushCode.Finish);
InflateEnd(ref zStream);

Marshal.Copy(uncompressedDataPtr, newarr, 0, inflatedSize);

Marshal.FreeHGlobal(compressedDataPtr);
Marshal.FreeHGlobal(uncompressedDataPtr);
}
}
}
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 struct ZStream
{
internal nint NextIn;
internal nint 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 d1361e3

Please sign in to comment.