Joveler.Compression.ZLib requires the explicit loading of a zlib library.
You must call ZLibInit.GlobalInit()
before using Joveler.Compression.ZLib.
- Call
ZLibInit.GlobalInit(string libPath, ZLibInitOptions opts)
to load embedded binaries.- If you don't know what you are doing, just follow the init code snippet.
- Call parameterless
ZLibInit.GlobalInit()
on Linux/macOS to load system zlib binary. - Never call deprecated
ZLibInit.GlobalInit(string libPath)
.- This function now contains shim code to make Joveler.Compression.ZLib v5.x compatible with v4.x without any source code modification.
- It translates
zlibwapi.dll
in path tozlib1.dll
with cdecl ABI. - To avoid ABI ambiguity, always call
ZLibInit.GlobalInit(string libPath, ZLibInitOptions opts)
directly.
Please put this code snippet in your application init code:
WARNING: Caller process and callee library must have the same architecture!
public static void InitNativeLibrary()
{
string libDir = "runtimes";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
libDir = Path.Combine(libDir, "win-");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
libDir = Path.Combine(libDir, "linux-");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
libDir = Path.Combine(libDir, "osx-");
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.X86:
libDir += "x86";
break;
case Architecture.X64:
libDir += "x64";
break;
case Architecture.Arm:
libDir += "arm";
break;
case Architecture.Arm64:
libDir += "arm64";
break;
}
libDir = Path.Combine(libDir, "native");
string libPath = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
libPath = Path.Combine(libDir, "zlib1.dll");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
libPath = Path.Combine(libDir, "libz.so");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
libPath = Path.Combine(libDir, "libz.dylib");
if (libPath == null)
throw new PlatformNotSupportedException($"Unable to find native library.");
if (!File.Exists(libPath))
throw new PlatformNotSupportedException($"Unable to find native library [{libPath}].");
ZLibInit.GlobalInit(libPath, new ZLibInitOptions());
}
public static void InitNativeLibrary()
{
string arch = null;
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.X86:
arch = "x86";
break;
case Architecture.X64:
arch = "x64";
break;
case Architecture.Arm64:
arch = "arm64";
break;
}
string libPath = Path.Combine(arch, "zlib1.dll");
if (!File.Exists(libPath))
throw new PlatformNotSupportedException($"Unable to find native library [{libPath}].");
ZLibInit.GlobalInit(libPath, new ZLibInitOptions());
}
Joveler.Compression.ZLib comes with sets of static binaries of zlib-ng 2.2.3 (compat ABI)
. They will be copied into the build directory at build time.
Platform | Minimum Target | Binary | License | C Runtime |
---|---|---|---|---|
Windows x86 | Windows 7 SP1 | $(OutDir)\runtimes\win-x86\zlib1.dll |
zlib | Universal CRT |
Windows x64 | Windows 7 SP1 | $(OutDir)\runtimes\win-x64\zlib1.dll |
zlib | Universal CRT |
Windows arm64 | Windows 7 SP1 | $(OutDir)\runtimes\win-arm64\zlib1.dll |
zlib | Universal CRT |
Linux x64 | Ubuntu 20.04 | $(OutDir)\runtimes\linux-x64\libz.so |
zlib | glibc |
Linux armhf | Ubuntu 20.04 | $(OutDir)\runtimes\linux-arm\libz.so |
zlib | glibc |
Linux arm64 | Ubuntu 20.04 | $(OutDir)\runtimes\linux-arm64\libz.so |
zlib | glibc |
macOS x64 | macOS 11 | $(OutDir)\runtimes\osx-x64\libz.dylib |
zlib | libSystem |
macOS arm64 | macOS 11 | $(OutDir)\runtimes\osx-arm64\libz.dylib |
zlib | libSystem |
- Precompiled binaries were built from zlib-ng in compat mode, which is compatible with traditional zlib cdecl ABI.
- Bundled Windows binaires targets Universal CRT to ensure interoperability with modern .NET runtime.
- If you encounter a dependency issue on Windows 7 or 8.1, try installing UCRT manually.
- If you call
ZLibInit.GlobalInit()
withoutlibPath
parameter on Linux or macOS, it will search for system-installed zlib. - Linux binaries are not portable. They may not work on your distribution. In that case, call parameter-less
ZLibInit.GlobalInit()
to use system-installed zlib.
Platform | Binary | License | C Runtime |
---|---|---|---|
Windows x86 | $(OutDir)\x86\zlib1.dll |
zlib | Universal CRT |
Windows x64 | $(OutDir)\x64\zlib1.dll |
zlib | Universal CRT |
Windows arm64 | $(OutDir)\arm64\zlib1.dll |
zlib | Universal CRT |
- Create an empty file named
Joveler.Compression.ZLib.Precompiled.Exclude
in the project directory to prevent a copy of the package-embedded binary. - Precompiled binaries were built from zlib-ng in compat mode, which is compatible with traditional zlib cdecl ABI.
Joveler.Compression.ZLib uses zlib (cdecl)
ABI by default. Joveler.Compression.ZLib also supports zlib (stdcall)
ABI and zlib-ng (modern)
ABI.
ZLibInitOptions
controls which ABI should be used to load native library. Default ZLibInitOptions
instance is set to use default zlib (cdecl)
ABI.
If you want to load a non-default ABI, tweak ZLibInitOptions
properties. Set it to correct value, or it would crash the process in worst cases.
/// <summary>
/// Controls the ABI used to interface native library.
/// </summary>
/// <remarks>
/// Default values of ZLibInitOptions instance are tuned to load embedded zlib-ng compat binary.
/// </remarks>
public class ZLibInitOptions
{
/// <summary>
/// Does the native library have 'stdcall' calling convention? Set it to default unless you know what you are doing.
/// <para>Set it to false for zlib1.dll (cdecl), and true for zlibwapi.dll (stdcall).</para>
/// <para>This flag is effective only on Windows x86. Otherwise it will be ignored.</para>
/// </summary>
public bool IsWindowsStdcall { get; set; } = false;
/// <summary>
/// Does the naive library have zlib-ng 'modern' ABI? Set it to default unless you know what you are doing.
/// <para>Set it to true only if you are loading one of 'zlib-ng2.dll', 'libz-ng.so' or 'libz-ng.dylib'.</para>
/// <para>If the native library was built with zlib-ng 'compat' mode, set it to false.</para>
/// </summary>
public bool IsZLibNgModernAbi { get; set; } = false;
}
ABI | Calling Convention (x86) | FileNames | Note |
---|---|---|---|
zlib | cdecl | zlib1.dll , libz.so , libz.dylib |
Default ABI |
zlib | stdcall | zlibwapi.dll |
Effective only on Windows x86 |
zlib-ng | cdecl | zlib-ng2.dll , libz-ng.so , libz-ng.dylib |
zlib-ng modern ABI |
zlib
can be compiled into many ABIs due to its long history.- Its fork
zlib-ng
introduced its own ABI to avoid symbol conflict with long-standingzlib
ABI. - Calling convention difference is only effective on Windows x86.
- Specifying to use
stdcall
on POSIX or Windows x64/arm64 would be ignored.
- Specifying to use
To use custom zlib binary instead, call ZLibInit.GlobalInit(string libPath, ZLibInitOptions opts)
with a path to the custom binary.
You are required to pass valid ZLibInitOptions
instance alongside library path.
To unload the zlib library explicitly, call ZLibInit.GlobalCleanup()
or ZLibInit.TryGlobalCleanup()
.
DeflateStream
is the class that processes a data format conforming to RFC 1951.
// Create a compressing DeflateStream instance
public DeflateStream(Stream baseStream, ZLibCompressOptions compOpts)
// Create a parallel compressing DeflateStream instance (EXPERIMENTAL)
public DeflateStream(Stream baseStream, ZLibCompressOptions compOpts, ZLibParallelCompressOptions pcompOpts)
// Create a decompressing DeflateStream instance
public DeflateStream(Stream baseStream, ZLibDecompressOptions decompOpts)
You can tune zlib compress options with this class.
Property | Summary |
---|---|
Level | Compression level. The Default is ZLibCompLevel.Default . |
BufferSize | Size of the internal buffer. The default is 256KB. This value is ignored in parallel compression, and use ChunkSize instead. |
LeaveOpen | Whether to leave the base stream object open after disposing of the zlib stream object. |
It also contains more advanced options.
Property | Summary |
---|---|
Threads | The number of threads to use for parallel compression. |
ChunkSize | Size of the compress chunk, which would be a unit of data to be compressed per thread. |
WaitTimeout | Controls timeout to allow Write() to return early. Set to null to block until compress & write is complete. Set to TimeSpan value to enable an upper limit on blocking. Timeout value is kept as best effort. |
You can tune zlib decompress options with this class.
Property | Summary |
---|---|
BufferSize | Size of the internal buffer. The default is 256KB. |
LeaveOpen | Whether to leave the base stream object open after disposing of the zlib stream object. |
using Joveler.Compression.ZLib;
ZLibCompressOptions compOpts = new ZLibCompressOptions()
{
Level = ZLibCompLevel.Default,
};
using (FileStream fsOrigin = new FileStream("file_origin.bin", FileMode.Open))
using (FileStream fsComp = new FileStream("test.deflate", FileMode.Create))
using (DeflateStream zs = new DeflateStream(fsComp, compOpts))
{
fsOrigin.CopyTo(zs);
}
using Joveler.Compression.ZLib;
ZLibCompressOptions compOpts = new ZLibCompressOptions()
{
Level = ZLibCompLevel.Default,
};
ZLibParallelCompressOptions pcompOpts = new ZLibParallelCompressOptions()
{
Threads = Environment.ProcessorCount,
};
using (FileStream fsOrigin = new FileStream("file_origin.bin", FileMode.Open))
using (FileStream fsComp = new FileStream("test.deflate", FileMode.Create))
using (DeflateStream zs = new DeflateStream(fsComp, compOpts, pcompOpts))
{
fsOrigin.CopyTo(zs);
}
using Joveler.Compression.ZLib;
ZLibDecompressOptions decompOpts = new ZLibDecompressOptions();
using (FileStream fsComp = new FileStream("test.deflate", FileMode.Create))
using (FileStream fsDecomp = new FileStream("file_decomp.bin", FileMode.Open))
using (DeflateStream zs = new DeflateStream(fsComp, decompOpts))
{
zs.CopyTo(fsDecomp);
}
ZLibStream
is the class that processes a data format conforming to RFC 1950.
The zlib data format has its simple header and adler32 footer.
It has an interface same as DeflateStream
.
GZipStream
is the class that processes a data format conforming to RFC 1952.
Use this stream to handle .gz
files.
It has an interface same as DeflateStream
.
Adler32Checksum
is the class to compute Adler32 checksum.
Use Append()
methods to compute the checksum.
Use Checksum
property to get checksum value.
Use Reset()
methods to reset Checksum
property.
using Joveler.Compression.ZLib.Checksum;
Adler32Checksum adler = new Adler32Checksum();
byte[] bin = Encoding.UTF8.GetBytes("ABCDEF");
// Append(ReadOnlySpan<byte> buffer)
adler.Append(bin.AsSpan(2, 3));
Console.WriteLine($"0x{adler.Checksum:X8}");
// Append(byte[] buffer, int offset, int count)
adler.Reset();
adler.Append(bin, 2, 3);
Console.WriteLine($"0x{adler.Checksum:X8}");
using Joveler.Compression.ZLib.Checksum;
using (FileStream fs = new FileStream("read.txt", FileMode.Open))
{
Adler32Checksum adler = new Adler32Checksum();
// Append(Stream stream)
adler.Append(fs);
Console.WriteLine($"0x{adler.Checksum:X8}");
}
Adler32Algorithm
is the class designed to compute Adler32 checksum.
It inherits and implements HashAlgorithm.
Crc32Checksum
is the class to compute CRC32 checksum.
It has the same usage as Adler32Checksum
.
Crc32Algorithm
is the class designed to compute CRC32 checksum.
It inherits and implements HashAlgorithm.