Skip to content

Commit

Permalink
Merge pull request dotnet#4440 from eerhardt/ShimZLib
Browse files Browse the repository at this point in the history
Add shims for the zlib functions used in System.IO.Compression on Unix.
  • Loading branch information
stephentoub committed Nov 12, 2015
2 parents aec9e02 + c2561f5 commit fc4ecdf
Show file tree
Hide file tree
Showing 16 changed files with 429 additions and 139 deletions.
2 changes: 1 addition & 1 deletion src/Common/src/Interop/Unix/Interop.Libraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ internal static partial class Interop
private static partial class Libraries
{
internal const string LibCoreClr = "libcoreclr"; // CoreCLR runtime
internal const string Zlib = "libz"; // zlib compression library

// Shims
internal const string SystemNative = "System.Native";
internal const string HttpNative = "System.Net.Http.Native";
internal const string CryptoNative = "System.Security.Cryptography.Native";
internal const string GlobalizationNative = "System.Globalization.Native";
internal const string CompressionNative = "System.IO.Compression.Native";
}
}
1 change: 1 addition & 0 deletions src/Native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ endif ()

include(configure.cmake)

add_subdirectory(System.IO.Compression.Native)
add_subdirectory(System.Native)
add_subdirectory(System.Net.Http.Native)
add_subdirectory(System.Security.Cryptography.Native)
18 changes: 18 additions & 0 deletions src/Native/System.IO.Compression.Native/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
project(System.IO.Compression.Native)

find_package(ZLIB REQUIRED)

set(NATIVECOMPRESSION_SOURCES
pal_zlib.cpp
)

add_library(System.IO.Compression.Native
SHARED
${NATIVECOMPRESSION_SOURCES}
)

target_link_libraries(System.IO.Compression.Native
${ZLIB_LIBRARIES}
)

install (TARGETS System.IO.Compression.Native DESTINATION .)
173 changes: 173 additions & 0 deletions src/Native/System.IO.Compression.Native/pal_zlib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "pal_zlib.h"
#include "pal_utilities.h"

#include <assert.h>
#include <zlib.h>

static_assert(PAL_Z_NOFLUSH == Z_NO_FLUSH, "");
static_assert(PAL_Z_FINISH == Z_FINISH, "");

static_assert(PAL_Z_OK == Z_OK, "");
static_assert(PAL_Z_STREAMEND == Z_STREAM_END, "");
static_assert(PAL_Z_STREAMERROR == Z_STREAM_ERROR, "");
static_assert(PAL_Z_DATAERROR == Z_DATA_ERROR, "");
static_assert(PAL_Z_MEMERROR == Z_MEM_ERROR, "");
static_assert(PAL_Z_BUFERROR == Z_BUF_ERROR, "");
static_assert(PAL_Z_VERSIONERROR == Z_VERSION_ERROR, "");

static_assert(PAL_Z_NOCOMPRESSION == Z_NO_COMPRESSION, "");
static_assert(PAL_Z_BESTSPEED == Z_BEST_SPEED, "");
static_assert(PAL_Z_BESTCOMPRESSION == Z_BEST_COMPRESSION, "");
static_assert(PAL_Z_DEFAULTCOMPRESSION == Z_DEFAULT_COMPRESSION, "");

static_assert(PAL_Z_DEFAULTSTRATEGY == Z_DEFAULT_STRATEGY, "");

static_assert(PAL_Z_DEFLATED == Z_DEFLATED, "");

/*
Initializes the PAL_ZStream by creating and setting its underlying z_stream.
*/
static void Init(PAL_ZStream* stream)
{
z_stream* zStream = new z_stream();
zStream->zalloc = Z_NULL;
zStream->zfree = Z_NULL;
zStream->opaque = Z_NULL;

stream->internalState = zStream;
}

/*
Frees any memory on the PAL_ZStream that was created by Init.
*/
static void End(PAL_ZStream* stream)
{
z_stream* zStream = reinterpret_cast<z_stream*>(stream->internalState);
assert(zStream != nullptr);

delete zStream;
stream->internalState = nullptr;
}

/*
Transfers the output values from the underlying z_stream to the PAL_ZStream.
*/
static void TransferState(z_stream* from, PAL_ZStream* to)
{
to->nextIn = from->next_in;
to->availIn = from->avail_in;

to->nextOut = from->next_out;
to->availOut = from->avail_out;

to->msg = from->msg;
}

/*
Transfers the input values from the PAL_ZStream to the underlying z_stream object.
*/
static void TransferState(PAL_ZStream* from, z_stream* to)
{
to->next_in = from->nextIn;
to->avail_in = from->availIn;

to->next_out = from->nextOut;
to->avail_out = from->availOut;
}

/*
Gets the current z_stream object for the specified PAL_ZStream.
This ensures any inputs are transferred from the PAL_ZStream to the underlying z_stream,
since the current values are always needed.
*/
static z_stream* GetCurrentZStream(PAL_ZStream* stream)
{
z_stream* zStream = reinterpret_cast<z_stream*>(stream->internalState);
assert(zStream != nullptr);

TransferState(stream, zStream);
return zStream;
}

extern "C" int32_t DeflateInit2_(PAL_ZStream* stream, int32_t level, int32_t method, int32_t windowBits, int32_t memLevel, int32_t strategy)
{
assert(stream != nullptr);

Init(stream);

z_stream* zStream = GetCurrentZStream(stream);
int32_t result = deflateInit2(zStream, level, method, windowBits, memLevel, strategy);
TransferState(zStream, stream);

return result;
}

extern "C" int32_t Deflate(PAL_ZStream* stream, int32_t flush)
{
assert(stream != nullptr);

z_stream* zStream = GetCurrentZStream(stream);
int32_t result = deflate(zStream, flush);
TransferState(zStream, stream);

return result;
}

extern "C" int32_t DeflateEnd(PAL_ZStream* stream)
{
assert(stream != nullptr);

z_stream* zStream = GetCurrentZStream(stream);
int32_t result = deflateEnd(zStream);
End(stream);

return result;
}

extern "C" int32_t InflateInit2_(PAL_ZStream* stream, int32_t windowBits)
{
assert(stream != nullptr);

Init(stream);

z_stream* zStream = GetCurrentZStream(stream);
int32_t result = inflateInit2(zStream, windowBits);
TransferState(zStream, stream);

return result;
}

extern "C" int32_t Inflate(PAL_ZStream* stream, int32_t flush)
{
assert(stream != nullptr);

z_stream* zStream = GetCurrentZStream(stream);
int32_t result = inflate(zStream, flush);
TransferState(zStream, stream);

return result;
}

extern "C" int32_t InflateEnd(PAL_ZStream* stream)
{
assert(stream != nullptr);

z_stream* zStream = GetCurrentZStream(stream);
int32_t result = inflateEnd(zStream);
End(stream);

return result;
}

extern "C" uint32_t Crc32(uint32_t crc, uint8_t* buffer, int32_t len)
{
assert(buffer != nullptr);

unsigned long result = crc32(crc, buffer, UnsignedCast(len));
assert(result <= UINT32_MAX);
return static_cast<uint32_t>(result);
}
123 changes: 123 additions & 0 deletions src/Native/System.IO.Compression.Native/pal_zlib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "pal_types.h"

/*
A structure that holds the input and output values for the zlib functions.
*/
struct PAL_ZStream
{
uint8_t* nextIn; // next input byte
uint8_t* nextOut; // next output byte should be put there

char* msg; // last error message, NULL if no error

// the underlying z_stream object is held in internalState, but it should not be used by external callers
void* internalState;

uint32_t availIn; // number of bytes available at nextIn
uint32_t availOut; // remaining free space at nextOut
};

/*
Allowed flush values for the Deflate and Inflate functions.
*/
enum PAL_FlushCode : int32_t
{
PAL_Z_NOFLUSH = 0,
PAL_Z_FINISH = 4,
};

/*
Error codes from the zlib functions.
*/
enum PAL_ErrorCode : int32_t
{
PAL_Z_OK = 0,
PAL_Z_STREAMEND = 1,
PAL_Z_STREAMERROR = -2,
PAL_Z_DATAERROR = -3,
PAL_Z_MEMERROR = -4,
PAL_Z_BUFERROR = -5,
PAL_Z_VERSIONERROR = -6
};

/*
Compression levels
*/
enum PAL_CompressionLevel : int32_t
{
PAL_Z_NOCOMPRESSION = 0,
PAL_Z_BESTSPEED = 1,
PAL_Z_BESTCOMPRESSION = 9,
PAL_Z_DEFAULTCOMPRESSION = -1
};

/*
Compression strategy
*/
enum PAL_CompressionStrategy : int32_t
{
PAL_Z_DEFAULTSTRATEGY = 0
};

/*
The deflate compression method (the only one supported in this version)
*/
enum PAL_CompressionMethod : int32_t
{
PAL_Z_DEFLATED = 8
};

/*
Initializes the PAL_ZStream so the Deflate function can be invoked on it.
Returns a PAL_ErrorCode indicating success or an error number on failure.
*/
extern "C" int32_t DeflateInit2_(PAL_ZStream* stream, int32_t level, int32_t method, int32_t windowBits, int32_t memLevel, int32_t strategy);

/*
Deflates (compresses) the bytes in the PAL_ZStream's nextIn buffer and puts the
compressed bytes in nextOut.
Returns a PAL_ErrorCode indicating success or an error number on failure.
*/
extern "C" int32_t Deflate(PAL_ZStream* stream, int32_t flush);

/*
All dynamically allocated data structures for this stream are freed.
Returns a PAL_ErrorCode indicating success or an error number on failure.
*/
extern "C" int32_t DeflateEnd(PAL_ZStream* stream);

/*
Initializes the PAL_ZStream so the Inflate function can be invoked on it.
Returns a PAL_ErrorCode indicating success or an error number on failure.
*/
extern "C" int32_t InflateInit2_(PAL_ZStream* stream, int32_t windowBits);

/*
Inflates (uncompresses) the bytes in the PAL_ZStream's nextIn buffer and puts the
uncompressed bytes in nextOut.
Returns a PAL_ErrorCode indicating success or an error number on failure.
*/
extern "C" int32_t Inflate(PAL_ZStream* stream, int32_t flush);

/*
All dynamically allocated data structures for this stream are freed.
Returns a PAL_ErrorCode indicating success or an error number on failure.
*/
extern "C" int32_t InflateEnd(PAL_ZStream* stream);

/*
Update a running CRC-32 with the bytes buffer[0..len-1] and return the
updated CRC-32.
Returns the updated CRC-32.
*/
extern "C" uint32_t Crc32(uint32_t crc, uint8_t* buffer, int32_t len);
49 changes: 49 additions & 0 deletions src/System.IO.Compression/src/Interop/Interop.zlib.Unix.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.IO.Compression;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class zlib
{
[DllImport(Libraries.CompressionNative)]
internal static extern ZLibNative.ErrorCode DeflateInit2_(
ref ZLibNative.ZStream stream,
ZLibNative.CompressionLevel level,
ZLibNative.CompressionMethod method,
int windowBits,
int memLevel,
ZLibNative.CompressionStrategy strategy);

[DllImport(Libraries.CompressionNative)]
internal static extern ZLibNative.ErrorCode Deflate(ref ZLibNative.ZStream stream, ZLibNative.FlushCode flush);

[DllImport(Libraries.CompressionNative)]
internal static extern ZLibNative.ErrorCode DeflateEnd(ref ZLibNative.ZStream stream);

[DllImport(Libraries.CompressionNative)]
internal static extern ZLibNative.ErrorCode InflateInit2_(ref ZLibNative.ZStream stream, int windowBits);

[DllImport(Libraries.CompressionNative)]
internal static extern ZLibNative.ErrorCode Inflate(ref ZLibNative.ZStream stream, ZLibNative.FlushCode flush);

[DllImport(Libraries.CompressionNative)]
internal static extern ZLibNative.ErrorCode InflateEnd(ref ZLibNative.ZStream stream);

internal static bool IsCrc32Available()
{
return true;
}

internal static unsafe uint crc32(uint crc, byte[] buffer, int offset, int len)
{
fixed (byte* buf = &buffer[offset])
return Crc32(crc, buf, len);
}

[DllImport(Libraries.CompressionNative)]
private static unsafe extern uint Crc32(uint crc, byte* buffer, int len);
}
}
Loading

0 comments on commit fc4ecdf

Please sign in to comment.