From bf6085a67a25c0242e3f170c3e617a08498d9ad0 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sun, 4 Aug 2024 16:58:09 -0400 Subject: fix compression source tree and source package --- lib/Net.Compression/vnlib_compress/CMakeLists.txt | 17 +- lib/Net.Compression/vnlib_compress/Taskfile.yaml | 22 +- lib/Net.Compression/vnlib_compress/compression.c | 349 --------------------- lib/Net.Compression/vnlib_compress/compression.h | 263 ---------------- .../vnlib_compress/feature_brotli.c | 249 --------------- .../vnlib_compress/feature_brotli.h | 46 --- lib/Net.Compression/vnlib_compress/feature_zlib.c | 304 ------------------ lib/Net.Compression/vnlib_compress/feature_zlib.h | 50 --- .../vnlib_compress/src/compression.c | 349 +++++++++++++++++++++ .../vnlib_compress/src/compression.h | 263 ++++++++++++++++ .../vnlib_compress/src/feature_brotli.c | 249 +++++++++++++++ .../vnlib_compress/src/feature_brotli.h | 46 +++ .../vnlib_compress/src/feature_zlib.c | 304 ++++++++++++++++++ .../vnlib_compress/src/feature_zlib.h | 50 +++ lib/Net.Compression/vnlib_compress/src/util.h | 140 +++++++++ .../vnlib_compress/src/vnlib_compress.vcxitems | 34 ++ lib/Net.Compression/vnlib_compress/util.h | 140 --------- .../vnlib_compress/vnlib_compress.vcxitems | 34 -- 18 files changed, 1455 insertions(+), 1454 deletions(-) delete mode 100644 lib/Net.Compression/vnlib_compress/compression.c delete mode 100644 lib/Net.Compression/vnlib_compress/compression.h delete mode 100644 lib/Net.Compression/vnlib_compress/feature_brotli.c delete mode 100644 lib/Net.Compression/vnlib_compress/feature_brotli.h delete mode 100644 lib/Net.Compression/vnlib_compress/feature_zlib.c delete mode 100644 lib/Net.Compression/vnlib_compress/feature_zlib.h create mode 100644 lib/Net.Compression/vnlib_compress/src/compression.c create mode 100644 lib/Net.Compression/vnlib_compress/src/compression.h create mode 100644 lib/Net.Compression/vnlib_compress/src/feature_brotli.c create mode 100644 lib/Net.Compression/vnlib_compress/src/feature_brotli.h create mode 100644 lib/Net.Compression/vnlib_compress/src/feature_zlib.c create mode 100644 lib/Net.Compression/vnlib_compress/src/feature_zlib.h create mode 100644 lib/Net.Compression/vnlib_compress/src/util.h create mode 100644 lib/Net.Compression/vnlib_compress/src/vnlib_compress.vcxitems delete mode 100644 lib/Net.Compression/vnlib_compress/util.h delete mode 100644 lib/Net.Compression/vnlib_compress/vnlib_compress.vcxitems diff --git a/lib/Net.Compression/vnlib_compress/CMakeLists.txt b/lib/Net.Compression/vnlib_compress/CMakeLists.txt index 6097a34..d0dbbb2 100644 --- a/lib/Net.Compression/vnlib_compress/CMakeLists.txt +++ b/lib/Net.Compression/vnlib_compress/CMakeLists.txt @@ -14,14 +14,13 @@ set(CMAKE_BUILD_TYPE "Release" CACHE STRING "The build configuration type") string(TOLOWER ${CMAKE_BUILD_TYPE} build_type) message(STATUS "Build type is '${build_type}'") -#export all header files to the main project -file(GLOB COMP_HEADERS *.h) +include(FetchContent) + +#the compression source file is required, all other sources will be added set(VNLIB_COMPRESS_SOURCES - compression.c + src/compression.c ) -include(FetchContent) - ############################### # # DOWNLOAD DEPENDENCIES @@ -50,7 +49,7 @@ if(ENABLE_BROTLI) include_directories(${lib_brotli_SOURCE_DIR}/c/include) #add the brotli source files to the project - list(APPEND VNLIB_COMPRESS_SOURCES feature_brotli.c) + list(APPEND VNLIB_COMPRESS_SOURCES src/feature_brotli.c) add_compile_definitions(VNLIB_COMPRESSOR_BROTLI_ENABLED) endif() @@ -77,7 +76,7 @@ if(ENABLE_ZLIB) include_directories(${lib_cf_zlib_SOURCE_DIR}) #enable the feature code for zlib and add the source files - list(APPEND VNLIB_COMPRESS_SOURCES feature_zlib.c) + list(APPEND VNLIB_COMPRESS_SOURCES src/feature_zlib.c) add_compile_definitions(VNLIB_COMPRESSOR_ZLIB_ENABLED) endif() @@ -104,12 +103,12 @@ endif() set(CMAKE_C_STANDARD_REQUIRED ON) if(COMPRESS_BUILD_SHARED) - add_library(${_COMP_PROJ_NAME} SHARED ${VNLIB_COMPRESS_SOURCES} ${COMP_HEADERS}) + add_library(${_COMP_PROJ_NAME} SHARED ${VNLIB_COMPRESS_SOURCES}) #enable position independent code (for shared libraries with exports) set_target_properties(${_COMP_PROJ_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) else() set(_COMP_PROJ_NAME ${_COMP_PROJ_NAME}_static) #append static to the name - add_library(${_COMP_PROJ_NAME} STATIC ${VNLIB_COMPRESS_SOURCES} ${COMP_HEADERS}) + add_library(${_COMP_PROJ_NAME} STATIC ${VNLIB_COMPRESS_SOURCES}) endif() target_compile_features(${_COMP_PROJ_NAME} PRIVATE c_std_90) #force compiler to use c90 standard for library diff --git a/lib/Net.Compression/vnlib_compress/Taskfile.yaml b/lib/Net.Compression/vnlib_compress/Taskfile.yaml index 32636ee..2133c0b 100644 --- a/lib/Net.Compression/vnlib_compress/Taskfile.yaml +++ b/lib/Net.Compression/vnlib_compress/Taskfile.yaml @@ -15,9 +15,9 @@ tasks: default: cmds: - - cmd: echo "Building {{.PROJECT_NAME}}" + - cmd: echo "Building {{ .PROJECT_NAME }}" silent: true - - cmake -Bbuild/ -DCMAKE_BUILD_TYPE=Release {{.CLI_ARGS}} + - cmake -Bbuild/ -DCMAKE_BUILD_TYPE=Release {{ .CLI_ARGS }} - cmake --build build/ --config Release #called by ci pipline to build the winx64 project @@ -77,8 +77,8 @@ tasks: embed: internal: true cmds: - - powershell cp ../LICENSE '{{.TARGET}}/license.txt' - - powershell cp compression.h '{{.TARGET}}/compression.h' + - powershell cp ../LICENSE '{{ .TARGET }}/license.txt' + - powershell cp src/compression.h '{{ .TARGET }}/compression.h' #packages source code for distribution pack_source: @@ -87,30 +87,32 @@ tasks: EXCLUDES: INCLUDES: - "*.c - *.h - CMakeLists.txt + "src/* LICENSE + CMakeLists.txt Taskfile.yaml" cmds: + - powershell cp ../LICENSE 'LICENSE' -Force #just pack up current directory, excluding build, bin, and git directories - tar {{ .EXCLUDES }} -czf 'bin/src.tgz' {{ .INCLUDES }} + - cmd: powershell rm LICENSE + #Remove the output dirs on clean clean: ignore_error: true cmds: - for: [ bin/, build/ ] - cmd: powershell rm -Recurse '{{.ITEM}}' -Force + cmd: powershell rm -Recurse '{{ .ITEM }}' -Force clean-third-party: internal: false ignore_error: true cmds: - cmd: powershell rm -Recurse -Force 'build/_deps/' - platforms: [windows] + platforms: [ windows ] - cmd: rm -rf 'build/_deps/' - platforms: [linux, darwin] + platforms: [ linux, darwin ] \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/compression.c b/lib/Net.Compression/vnlib_compress/compression.c deleted file mode 100644 index 0cba998..0000000 --- a/lib/Net.Compression/vnlib_compress/compression.c +++ /dev/null @@ -1,349 +0,0 @@ -/* -* Copyright (c) 2024 Vaughn Nugent -* -* Library: VNLib -* Package: vnlib_compress -* File: compression.c -* -* vnlib_compress is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* vnlib_compress is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. -*/ - -/* -* Notes: -* This api is desgined to be friendly to many types of callers -* without needing to worry about the platform integer size. I would -* like to return errors as negative values, and I am requiring block -* operations on block sizes under INT64_MAX. This allows 64bit support -* while allowing negative error codes as return values. I think -* this is a good compromise. -*/ - -#define VNLIB_COMPRESS_EXPORTING 1 - -#include "compression.h" -#include "util.h" - -#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED -#include "feature_brotli.h" -#endif /* VNLIB_COMPRESSOR_BROTLI_ENABLED */ - - -#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED -#include "feature_zlib.h" -#endif /* VNLIB_COMPRESSOR_GZIP_ENABLED */ - -/* - Gets the supported compressors, this is defined at compile time and is a convenience method for - the user to know what compressors are supported at runtime. -*/ -VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetSupportedCompressors(void) -{ - /* - * Supported compressors are defined at compile time - */ - CompressorType supported; - - supported = COMP_TYPE_NONE; - -#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED - supported |= COMP_TYPE_GZIP; - supported |= COMP_TYPE_DEFLATE; -#endif - -#ifdef VNLIB_COMPRESSOR_LZ4_ENABLED - supported |= COMP_TYPE_LZ4; -#endif - -#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED - supported |= COMP_TYPE_BROTLI; -#endif - - return supported; -} - -VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetCompressorType(_In_ const void* compressor) -{ - CHECK_NULL_PTR(compressor) - return ((CompressorState*)compressor)->type; -} - -VNLIB_COMPRESS_EXPORT CompressionLevel VNLIB_COMPRESS_CC GetCompressorLevel(_In_ const void* compressor) -{ - CHECK_NULL_PTR(compressor) - return ((CompressorState*)compressor)->level; -} - -VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressorBlockSize(_In_ const void* compressor) -{ - CHECK_NULL_PTR(compressor) - return (int64_t)((CompressorState*)compressor)->blockSize; -} - -VNLIB_COMPRESS_EXPORT void* VNLIB_COMPRESS_CC AllocateCompressor(CompressorType type, CompressionLevel level) -{ - int result; - CompressorState* state; - - /* Validate input arguments */ - if (level < 0 || level > 9) - { - return (void*)ERR_COMP_LEVEL_NOT_SUPPORTED; - } - - state = (CompressorState*)vncalloc(1, sizeof(CompressorState)); - - if (!state) - { - return (void*)ERR_OUT_OF_MEMORY; - } - - /* Configure the comp state */ - state->type = type; - state->level = level; - - result = ERR_COMP_TYPE_NOT_SUPPORTED; - - /* - * Compressor types are defined at compile time - * and callers are allowed to choose which to allocate - */ - - switch (type) - { - case COMP_TYPE_BROTLI: - -#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED - result = BrAllocCompressor(state); -#endif - - break; - - case COMP_TYPE_DEFLATE: - case COMP_TYPE_GZIP: - -#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED - result = DeflateAllocCompressor(state); -#endif - break; - - /* - * Unsupported compressor type allow error to propagate - */ - case COMP_TYPE_LZ4: - case COMP_TYPE_NONE: - default: - break; - } - - - /* - If result was successfull return the context pointer, if - the creation failed, free the state if it was allocated - and return the error code. - */ - - if (result > 0) - { - return (void*)state; - } - else - { - vnfree(state); - - /* - * Using strict/pedantic error checking int gcc will cause a warning - * when casting an int to a void* pointer. We are returning an error code - * and it is expected behavior - */ -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" - return (void*)result; -#pragma GCC diagnostic pop -#elif defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable: 4312) - return (void*)result; -#pragma warning(pop) -#else - return (void*)result; -#endif - } -} - -VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC FreeCompressor(void* compressor) -{ - CompressorState* comp; - int errorCode; - - CHECK_NULL_PTR(compressor) - - comp = (CompressorState*)compressor; - errorCode = TRUE; - - switch (comp->type) - { - case COMP_TYPE_BROTLI: -#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED - BrFreeCompressor(comp); -#endif - break; - - case COMP_TYPE_DEFLATE: - case COMP_TYPE_GZIP: - /* - * Releasing a deflate compressor will cause a deflate - * end call, which can fail, we should send the error - * to the caller and clean up as best we can. - */ -#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED - errorCode = DeflateFreeCompressor(comp); -#endif - break; - - - /* - * If compression type is none, there is nothing to do - * since its not technically an error, so just return - * true. - */ - case COMP_TYPE_NONE: - case COMP_TYPE_LZ4: - default: - break; - } - - /* - * Free the compressor state - */ - - vnfree(comp); - return errorCode; -} - -VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressedSize(_In_ const void* compressor, uint64_t inputLength, int32_t flush) -{ - CompressorState* comp; - int64_t result; - - CHECK_NULL_PTR(compressor) - - if (inputLength > INT64_MAX) - { - return ERR_OVERFLOW; - } - - comp = (CompressorState*)compressor; - result = ERR_COMP_TYPE_NOT_SUPPORTED; - - switch (comp->type) - { - - case COMP_TYPE_BROTLI: - -#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED - result = BrGetCompressedSize(comp, inputLength, flush); -#endif - break; - - case COMP_TYPE_DEFLATE: - case COMP_TYPE_GZIP: - -#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED - result = DeflateGetCompressedSize(comp, inputLength, flush); -#endif - break; - - /* - * Set the result as an error code, since the compressor - * type is not supported. - */ - case COMP_TYPE_NONE: - case COMP_TYPE_LZ4: - break; - } - - return result; -} - -/* -* Compresses the data contained in the operation structure, ingests and compresses -* the data then writes it to the output buffer. The result of the operation is -* returned as an error code. Positive integers indicate success, negative integers -* indicate failure. -* @param compressor -*/ -VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC CompressBlock(_In_ const void* compressor, CompressionOperation* operation) -{ - int result; - CompressorState* comp; - - comp = (CompressorState*)compressor; - - /* - * Validate input arguments - */ - - CHECK_NULL_PTR(comp) - CHECK_NULL_PTR(operation) - - /* - * Validate buffers, if the buffer length is greate than 0 - * it must point to a valid buffer - */ - - if (operation->bytesInLength > 0 && !operation->bytesIn) - { - return ERR_INVALID_INPUT_DATA; - } - - if (operation->bytesOutLength > 0 && !operation->bytesOut) - { - return ERR_INVALID_OUTPUT_DATA; - } - - /* - * Determine the compressor type and call the appropriate - * compression function - */ - - result = ERR_COMP_TYPE_NOT_SUPPORTED; - - switch (comp->type) - { - /* Brolti support */ - case COMP_TYPE_BROTLI: - -#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED - result = BrCompressBlock(comp, operation); -#endif - break; - - - /* Deflate support */ - case COMP_TYPE_DEFLATE: - case COMP_TYPE_GZIP: - -#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED - result = DeflateCompressBlock(comp, operation); -#endif - break; - - case COMP_TYPE_NONE: - case COMP_TYPE_LZ4: - break; - } - - return result; -} diff --git a/lib/Net.Compression/vnlib_compress/compression.h b/lib/Net.Compression/vnlib_compress/compression.h deleted file mode 100644 index 3d03145..0000000 --- a/lib/Net.Compression/vnlib_compress/compression.h +++ /dev/null @@ -1,263 +0,0 @@ -/* -* Copyright (c) 2024 Vaughn Nugent -* -* Library: VNLib -* Package: vnlib_compress -* File: compression.h -* -* vnlib_compress is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* vnlib_compress is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. -*/ - - -/* -* Implementation notes: -* -* This library is designed to be a wrapper around the various compression libraries -* used for dynamic HTTP compression. Is is designed to be exported as a DLL or a shared -* library and written in portable C code. -* -* Compressors are standalone instances created by callers and used to perform compression -* operations. Compressors are created, used, and destroyed by callers. This library is meant -* to unify compression to a single api. The goal is performance and portability, so it can -* be easily used by portable runtimes. -*/ - -#pragma once - -#ifndef COMPRESSION_H_ -#define COMPRESSION_H_ - -#include - -#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) - #define _IS_WINDOWS -#endif - -/*Set api export calling convention(allow used to override)*/ -#ifndef VNLIB_COMPRESS_CC - #ifdef _IS_WINDOWS - /*STD for importing to other languages such as.NET*/ - #define VNLIB_COMPRESS_CC __stdcall - #else - #define VNLIB_COMPRESS_CC - #endif -#endif /* !VNLIB_CC */ - -#ifndef VNLIB_COMPRESS_EXPORT /*Allow users to disable the export/impoty macro if using source code directly*/ - #ifdef VNLIB_COMPRESS_EXPORTING - #ifdef _IS_WINDOWS - #define VNLIB_COMPRESS_EXPORT __declspec(dllexport) - #else - #define VNLIB_COMPRESS_EXPORT __attribute__((visibility("default"))) - #endif /* IS_WINDOWS */ - #else - #ifdef _IS_WINDOWS - #define VNLIB_COMPRESS_EXPORT __declspec(dllimport) - #else - #define VNLIB_COMPRESS_EXPORT - #endif /* IS_WINDOWS */ - #endif /* !VNLIB_EXPORTING */ -#endif /* !VNLIB_EXPORT */ - -#ifndef _In_ - #define _In_ -#endif - -/* -* ERRORS AND CONSTANTS -*/ -#define ERR_INVALID_PTR -1 -#define ERR_OUT_OF_MEMORY -2 - -#define ERR_COMP_TYPE_NOT_SUPPORTED -9 -#define ERR_COMP_LEVEL_NOT_SUPPORTED -10 -#define ERR_INVALID_INPUT_DATA -11 -#define ERR_INVALID_OUTPUT_DATA -12 -#define ERR_COMPRESSION_FAILED -13 -#define ERR_OVERFLOW -14 - -/* -* Enumerated list of supported compression types for user selection -* at runtime. -*/ -typedef enum CompressorType -{ - COMP_TYPE_NONE = 0x00, - COMP_TYPE_GZIP = 0x01, - COMP_TYPE_DEFLATE = 0x02, - COMP_TYPE_BROTLI = 0x04, - COMP_TYPE_LZ4 = 0x08 -} CompressorType; - - -/* - Specifies values that indicate whether a compression operation emphasizes speed - or compression size. -*/ -typedef enum CompressionLevel -{ - /* - The compression operation should be optimally compressed, even if the operation - takes a longer time to complete. - */ - COMP_LEVEL_OPTIMAL = 0, - /* - The compression operation should complete as quickly as possible, even if the - resulting file is not optimally compressed. - */ - COMP_LEVEL_FASTEST = 1, - /* - No compression should be performed on the file. - */ - COMP_LEVEL_NO_COMPRESSION = 2, - /* - The compression operation should create output as small as possible, even if - the operation takes a longer time to complete. - */ - COMP_LEVEL_SMALLEST_SIZE = 3 -} CompressionLevel; - - -typedef enum CompressorStatus { - COMPRESSOR_STATUS_READY = 0x00, - COMPRESSOR_STATUS_INITALIZED = 0x01, - COMPRESSOR_STATUS_NEEDS_FLUSH = 0x02 -} CompressorStatus; - -typedef struct CompressorStateStruct{ - - /* - Pointer to the underlying compressor implementation. - */ - void* compressor; - - /* - Indicates the type of underlying compressor. - */ - CompressorType type; - - /* - The user specified compression level, the underlying compressor will decide - how to handle this value. - */ - CompressionLevel level; - - /* - Indicates the suggested block size for the underlying compressor. - */ - uint32_t blockSize; - - -} CompressorState; - -/* -* An extern caller generated structure passed to calls for -* stream compression operations. -*/ -typedef struct CompressionOperationStruct { - - /* - * Input stream data - */ - const void* bytesIn; - /* - * Output buffer/data stream - */ - void* bytesOut; - - /* - * If the operation is a flush operation - */ - const int32_t flush; - - const uint32_t bytesInLength; - const uint32_t bytesOutLength; - - /* - * Results of the streaming operation - */ - - uint32_t bytesRead; - uint32_t bytesWritten; - -} CompressionOperation; - -/* -* Public API functions -*/ -VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetSupportedCompressors(void); - -/* -* Returns the suggested block size for the underlying compressor. -* -* @param compressor A pointer to the desired compressor instance to query. -* @return The suggested block size for the underlying compressor in bytes -*/ -VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressorBlockSize(_In_ const void* compressor); - -/* -* Gets the compressor type of the specified compressor instance. -* -* @param compressor A pointer to the desired compressor instance to query. -* @return The type of the specified compressor instance. -*/ -VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetCompressorType(_In_ const void* compressor); - -/* -* Gets the compression level of the specified compressor instance. -* -* @param compressor A pointer to the desired compressor instance to query. -* @return The compression level of the specified compressor instance. -*/ -VNLIB_COMPRESS_EXPORT CompressionLevel VNLIB_COMPRESS_CC GetCompressorLevel(_In_ const void* compressor); - -/* -* Allocates a new compressor instance on the native heap of the desired compressor type. -* -* @param type The desired compressor type. -* @param level The desired compression level. -* @return A pointer to the newly allocated compressor instance. NULL if the compressor -could not be allocated. -*/ -VNLIB_COMPRESS_EXPORT void* VNLIB_COMPRESS_CC AllocateCompressor(CompressorType type, CompressionLevel level); - -/* -* Frees a previously allocated compressor instance. -* -* @param compressor A pointer to the desired compressor instance to free. -* @return The underlying compressor's native return code. -*/ -VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC FreeCompressor(void* compressor); - -/* -* Computes the maximum compressed size of the specified input data. This is not supported - for all compression types. -* -* @param compressor A pointer to the initialized compressor instance to use. -* @param inputLength The length of the input data in bytes. -* @return The maximum compressed size of the specified input data in bytes. -*/ -VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressedSize(_In_ const void* compressor, uint64_t inputLength, int32_t flush); - - -/* -* Perform compression operation using the specified compressor instance. -* -* @param compressor A pointer to the initialized compressor instance to use. -* @param operation A pointer to the compression operation structure -* @return The underlying compressor's native return code -*/ -VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC CompressBlock(_In_ const void* compressor, CompressionOperation* operation); - -#endif /* !VNLIB_COMPRESS_MAIN_H_ */ \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/feature_brotli.c b/lib/Net.Compression/vnlib_compress/feature_brotli.c deleted file mode 100644 index 361c61a..0000000 --- a/lib/Net.Compression/vnlib_compress/feature_brotli.c +++ /dev/null @@ -1,249 +0,0 @@ -/* -* Copyright (c) 2024 Vaughn Nugent -* -* Library: VNLib -* Package: vnlib_compress -* File: feature_brotli.c -* -* vnlib_compress is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* vnlib_compress is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. -*/ - -#include -#include "feature_brotli.h" -#include "util.h" - -#define validateCompState(state) \ - if (!state) return ERR_INVALID_PTR; \ - if (!state->compressor) return ERR_BR_INVALID_STATE; \ - -/* -* Stream memory management functions -*/ -static void* _brAllocCallback(void* opaque, size_t size) -{ - (void)opaque; - return vnmalloc(size, 1); -} - -static void _brFreeCallback(void* opaque, void* address) -{ - (void)opaque; - - /*Brotli may pass a null address to the free callback*/ - if (address) - { - vnfree(address); - } -} - - -int BrAllocCompressor(CompressorState* state) -{ - BrotliEncoderState* comp; - - assert(state != NULL); - - /* - * Never allow no compression, it is not supported by the br encoder - */ - - if (state->level == COMP_LEVEL_NO_COMPRESSION) - { - return ERR_COMP_LEVEL_NOT_SUPPORTED; - } - - comp = BrotliEncoderCreateInstance( - &_brAllocCallback, - &_brFreeCallback, - NULL - ); - - if (!comp) - { - return ERR_OUT_OF_MEMORY; - } - - state->compressor = comp; - - /* - * Setting parameters will only return false if the parameter type is - * invalid, or the compressor state is not valid - * - * Setup some defaults - */ - - BrotliEncoderSetParameter(comp, BROTLI_PARAM_MODE, BROTLI_MODE_GENERIC); - BrotliEncoderSetParameter(comp, BROTLI_PARAM_LGWIN, BR_DEFAULT_WINDOW); - - /* - * Capture the block size as a size hint if it is greater than 0 - */ - if (state->blockSize > 0) - { - BrotliEncoderSetParameter(comp, BROTLI_PARAM_SIZE_HINT, state->blockSize); - } - - /* - * Setup compressor quality level based on the requested compression level - */ - - switch (state->level) - { - - case COMP_LEVEL_FASTEST: - BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_FASTEST); - break; - - case COMP_LEVEL_OPTIMAL: - BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_OPTIMAL); - break; - - case COMP_LEVEL_SMALLEST_SIZE: - BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_SMALLEST_SIZE); - break; - - case COMP_LEVEL_NO_COMPRESSION: - default: - BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_DEFAULT); - break; - } - - return TRUE; -} - -void BrFreeCompressor(CompressorState* state) -{ - assert(state != NULL); - - /* - * Free the compressor instance if it exists - */ - if (state->compressor) - { - BrotliEncoderDestroyInstance((BrotliEncoderState*)state->compressor); - state->compressor = NULL; - } -} - -int BrCompressBlock(const CompressorState* state, CompressionOperation* operation) -{ - BrotliEncoderOperation brOperation; - BROTLI_BOOL brResult; - - size_t availableIn, availableOut, totalOut; - const uint8_t* nextIn; - uint8_t* nextOut; - - /* Validate inputs */ - validateCompState(state) - - /* Clear the result read / written fields */ - operation->bytesRead = 0; - operation->bytesWritten = 0; - - /* - * If the input is empty a flush is not requested, they we are waiting for - * more input and this was just an empty call. Should be a no-op - */ - - if (operation->bytesInLength == 0 && operation->flush < 1) - { - return TRUE; - } - - /* - * Determine the operation to perform - */ - - if (operation->flush) - { - brOperation = BROTLI_OPERATION_FINISH; - } - else - { - brOperation = BROTLI_OPERATION_PROCESS; - } - - /* - * Update lengths and data pointers from input/output spans - * for stream variables - */ - - availableIn = operation->bytesInLength; - availableOut = operation->bytesOutLength; - nextIn = operation->bytesIn; - nextOut = operation->bytesOut; - - - /* - * Compress block as stream and store the result - * directly on the result output to pass back to the caller - */ - - brResult = BrotliEncoderCompressStream( - state->compressor, - brOperation, - &availableIn, - &nextIn, - &availableOut, - &nextOut, - &totalOut - ); - - /* - * check for possible overflow and retrun error - */ - if (availableIn > operation->bytesInLength || availableOut > operation->bytesOutLength) - { - return ERR_COMPRESSION_FAILED; - } - - /* - * Regardless of the operation success we should return the - * results to the caller. Br encoder sets the number of - * bytes remaining in the input/output spans - */ - operation->bytesRead = operation->bytesInLength - (uint32_t)availableIn; - operation->bytesWritten = operation->bytesOutLength - (uint32_t)availableOut; - - return brResult; -} - - -int64_t BrGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush) -{ - size_t size; - - (void)sizeof(flush); - /* - * When the flush flag is set, the caller is requesting the - * entire size of the compressed data, which can include metadata - */ - - validateCompState(state) - - if (length <= 0) - { - return 0; - } - - size = BrotliEncoderMaxCompressedSize(length); - - if (size > INT64_MAX) - { - return ERR_OVERFLOW; - } - - return (int64_t)size; -} \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/feature_brotli.h b/lib/Net.Compression/vnlib_compress/feature_brotli.h deleted file mode 100644 index 1f2090b..0000000 --- a/lib/Net.Compression/vnlib_compress/feature_brotli.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Copyright (c) 2023 Vaughn Nugent -* -* Library: VNLib -* Package: vnlib_compress -* File: feature_brotli.h -* -* vnlib_compress is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* vnlib_compress is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. -*/ - -#pragma once - -#ifndef BROTLI_STUB_H_ -#define BROTLI_STUB_H_ - -#include "compression.h" - -#define ERR_BR_INVALID_STATE -24 - -#define BR_COMP_LEVEL_FASTEST 1 -#define BR_COMP_LEVEL_OPTIMAL 11 -#define BR_COMP_LEVEL_SMALLEST_SIZE 9 -#define BR_COMP_LEVEL_DEFAULT 5 - -#define BR_DEFAULT_WINDOW 22 - -int BrAllocCompressor(CompressorState* state); - -void BrFreeCompressor(CompressorState* state); - -int BrCompressBlock(const CompressorState* state, CompressionOperation* operation); - -int64_t BrGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush); - -#endif /* !BROTLI_STUB_H_ */ \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/feature_zlib.c b/lib/Net.Compression/vnlib_compress/feature_zlib.c deleted file mode 100644 index a07f106..0000000 --- a/lib/Net.Compression/vnlib_compress/feature_zlib.c +++ /dev/null @@ -1,304 +0,0 @@ -/* -* Copyright (c) 2024 Vaughn Nugent -* -* Library: VNLib -* Package: vnlib_compress -* File: feature_zlib.c -* -* vnlib_compress is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* vnlib_compress is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. -*/ - -/* -* Include the stub header and also the zlib header -*/ - - -#include -#include "feature_zlib.h" -#include "util.h" - -#define validateCompState(state) \ - if (!state) return ERR_INVALID_PTR; \ - if (!state->compressor) return ERR_GZ_INVALID_STATE; \ - -/* -* Stream memory management functions -*/ -static void* _gzAllocCallback(void* opaque, uint32_t items, uint32_t size) -{ - (void)opaque; - return vnmalloc(items, size); -} - -static void _gzFreeCallback(void* opaque, void* address) -{ - (void)opaque; - vnfree(address); -} - -int DeflateAllocCompressor(CompressorState* state) -{ - int result, compLevel; - z_stream* stream; - - assert(state); - - /* - * Allocate the z-stream state on the heap so we can - * store it in the compressor state - */ - stream = (z_stream*)vncalloc(1, sizeof(z_stream)); - - if (!stream) - { - return ERR_OUT_OF_MEMORY; - } - - stream->zalloc = &_gzAllocCallback; - stream->zfree = &_gzFreeCallback; - stream->opaque = Z_NULL; - - /* - * Initialize the z-stream state with the - * desired compression level - */ - - - switch (state->level) - { - case COMP_LEVEL_NO_COMPRESSION: - compLevel = Z_NO_COMPRESSION; - break; - - case COMP_LEVEL_FASTEST: - compLevel = Z_BEST_SPEED; - break; - - case COMP_LEVEL_OPTIMAL: - compLevel = Z_BEST_COMPRESSION; - break; - - case COMP_LEVEL_SMALLEST_SIZE: - compLevel = Z_BEST_COMPRESSION; - break; - - /* - Default compression level - */ - default: - compLevel = Z_DEFAULT_COMPRESSION; - break; - } - - /* - * If gzip is enabled, we need to configure the deflatenit2, with - * the max window size to 16 - */ - - if(state->type & COMP_TYPE_GZIP) - { - result = deflateInit2( - stream, - compLevel, - Z_DEFLATED, - GZ_ENABLE_GZIP_WINDOW, - GZ_DEFAULT_MEM_LEVEL, - Z_DEFAULT_STRATEGY - ); - } - else - { - /* Enable raw deflate */ - result = deflateInit2( - stream, - compLevel, - Z_DEFLATED, - GZ_ENABLE_RAW_DEFLATE_WINDOW, - GZ_DEFAULT_MEM_LEVEL, - Z_DEFAULT_STRATEGY - ); - } - - /* - * Inspect the result of the initialization, - * of the init failed, free the stream and return - * the error code - */ - - if (result != Z_OK) - { - vnfree(stream); - return result; - } - - /* - * Assign the z-stream state to the compressor state, all done! - */ - state->compressor = stream; - return TRUE; -} - -int DeflateFreeCompressor(CompressorState* state) -{ - int result; - - assert(state); - - /* - * Free the z-stream state, only if the compressor is initialized - */ - if (state->compressor) - { - /* - * Attempt to end the deflate stream, and store the status code - */ - - result = deflateEnd(state->compressor); - - /* - * We can always free the z-stream state, even if the deflate - * stream failed to end. - */ - - vnfree(state->compressor); - state->compressor = NULL; - - /* - * A data error is acceptable when calling end in this library - * since at that point all resources have been cleaned, and zlib - * is simply returning a warning that the stream was not properly - * terminated. - * - * We assum that calls to free are meant to clean up resources regarless - * of their status - */ - return result == Z_OK || result == Z_DATA_ERROR; - } - - return TRUE; -} - -int DeflateCompressBlock(const CompressorState* state, CompressionOperation* operation) -{ - z_stream* stream; - int result; - - validateCompState(state) - - /* Clear the result read/written fields */ - operation->bytesRead = 0; - operation->bytesWritten = 0; - - /* - * If the input is empty a flush is not requested, they we are waiting for - * more input and this was just an empty call. Should be a no-op - */ - - if (operation->bytesInLength == 0 && operation->flush < 1) - { - return TRUE; - } - - stream = (z_stream*)state->compressor; - - /* - * Overwrite the stream state with the operation parameters from - * this next compression operation. - * - * The caller stores the stream positions in its application memory. - */ - stream->avail_in = operation->bytesInLength; - stream->next_in = (Bytef*)operation->bytesIn; - - stream->avail_out = operation->bytesOutLength; - stream->next_out = (Bytef*)operation->bytesOut; - - /* - * In this library we only use the flush flag as a boolean value. - * Callers only set the flush flag when the operation has completed - * and the compressor is expected to flush its internal buffers. - * (aka finish) - */ - - result = deflate(stream, operation->flush ? Z_FINISH : Z_NO_FLUSH); - - /* - * Allways clear stream fields as they are assigned on every call - */ - stream->next_in = NULL; - stream->next_out = NULL; - - /* - * check for result overflow and return the error code - */ - if (stream->avail_in > operation->bytesInLength || stream->avail_out > operation->bytesOutLength) - { - return ERR_COMPRESSION_FAILED; - } - - /* - * Regardless of the return value, we should always update the - * the number of bytes read and written. - * - * The result is the number total bytes minus the number of - * bytes remaining in the stream. - */ - - operation->bytesRead = operation->bytesInLength - stream->avail_in; - operation->bytesWritten = operation->bytesOutLength - stream->avail_out; - - stream->avail_in = 0; - stream->avail_out = 0; - - return result; -} - -int64_t DeflateGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush) -{ - uint64_t compressedSize; - - /* - * When the flush flag is set, the caller is requesting the - * entire size of the compressed data, which can include metadata - */ - - validateCompState(state) - - if (length <= 0) - { - return 0; - } - - if(flush) - { - /* - * TODO: actualy determine the size of the compressed data - * when the flush flag is set. - */ - - compressedSize = deflateBound(state->compressor, length); - } - else - { - compressedSize = deflateBound(state->compressor, length); - } - - /* Verify the results to make sure the value doesnt overflow */ - if (compressedSize > INT64_MAX) - { - return ERR_GZ_OVERFLOW; - } - - return (int64_t)compressedSize; -} \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/feature_zlib.h b/lib/Net.Compression/vnlib_compress/feature_zlib.h deleted file mode 100644 index 2544d25..0000000 --- a/lib/Net.Compression/vnlib_compress/feature_zlib.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2023 Vaughn Nugent -* -* Library: VNLib -* Package: vnlib_compress -* File: feature_zlib.h -* -* vnlib_compress is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* vnlib_compress is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. -*/ - -#pragma once - -#ifndef ZLIB_STUB_H_ -#define ZLIB_STUB_H_ - -#include "compression.h" - -#define ERR_GZ_INVALID_STATE -16 -#define ERR_GZ_OVERFLOW -17 - -/* Allow user to define their own memory level value */ -#ifndef GZ_DEFAULT_MEM_LEVEL -#define GZ_DEFAULT_MEM_LEVEL 8 -#endif - -/* Specifies the window value to enable GZIP */ -#define GZ_ENABLE_GZIP_WINDOW 15 + 16 -#define GZ_ENABLE_RAW_DEFLATE_WINDOW -15 - - -int DeflateAllocCompressor(CompressorState* state); - -int DeflateFreeCompressor(CompressorState* state); - -int DeflateCompressBlock(const CompressorState* state, CompressionOperation* operation); - -int64_t DeflateGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush); - -#endif diff --git a/lib/Net.Compression/vnlib_compress/src/compression.c b/lib/Net.Compression/vnlib_compress/src/compression.c new file mode 100644 index 0000000..0cba998 --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/compression.c @@ -0,0 +1,349 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: vnlib_compress +* File: compression.c +* +* vnlib_compress is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* vnlib_compress is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. +*/ + +/* +* Notes: +* This api is desgined to be friendly to many types of callers +* without needing to worry about the platform integer size. I would +* like to return errors as negative values, and I am requiring block +* operations on block sizes under INT64_MAX. This allows 64bit support +* while allowing negative error codes as return values. I think +* this is a good compromise. +*/ + +#define VNLIB_COMPRESS_EXPORTING 1 + +#include "compression.h" +#include "util.h" + +#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED +#include "feature_brotli.h" +#endif /* VNLIB_COMPRESSOR_BROTLI_ENABLED */ + + +#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED +#include "feature_zlib.h" +#endif /* VNLIB_COMPRESSOR_GZIP_ENABLED */ + +/* + Gets the supported compressors, this is defined at compile time and is a convenience method for + the user to know what compressors are supported at runtime. +*/ +VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetSupportedCompressors(void) +{ + /* + * Supported compressors are defined at compile time + */ + CompressorType supported; + + supported = COMP_TYPE_NONE; + +#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED + supported |= COMP_TYPE_GZIP; + supported |= COMP_TYPE_DEFLATE; +#endif + +#ifdef VNLIB_COMPRESSOR_LZ4_ENABLED + supported |= COMP_TYPE_LZ4; +#endif + +#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED + supported |= COMP_TYPE_BROTLI; +#endif + + return supported; +} + +VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetCompressorType(_In_ const void* compressor) +{ + CHECK_NULL_PTR(compressor) + return ((CompressorState*)compressor)->type; +} + +VNLIB_COMPRESS_EXPORT CompressionLevel VNLIB_COMPRESS_CC GetCompressorLevel(_In_ const void* compressor) +{ + CHECK_NULL_PTR(compressor) + return ((CompressorState*)compressor)->level; +} + +VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressorBlockSize(_In_ const void* compressor) +{ + CHECK_NULL_PTR(compressor) + return (int64_t)((CompressorState*)compressor)->blockSize; +} + +VNLIB_COMPRESS_EXPORT void* VNLIB_COMPRESS_CC AllocateCompressor(CompressorType type, CompressionLevel level) +{ + int result; + CompressorState* state; + + /* Validate input arguments */ + if (level < 0 || level > 9) + { + return (void*)ERR_COMP_LEVEL_NOT_SUPPORTED; + } + + state = (CompressorState*)vncalloc(1, sizeof(CompressorState)); + + if (!state) + { + return (void*)ERR_OUT_OF_MEMORY; + } + + /* Configure the comp state */ + state->type = type; + state->level = level; + + result = ERR_COMP_TYPE_NOT_SUPPORTED; + + /* + * Compressor types are defined at compile time + * and callers are allowed to choose which to allocate + */ + + switch (type) + { + case COMP_TYPE_BROTLI: + +#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED + result = BrAllocCompressor(state); +#endif + + break; + + case COMP_TYPE_DEFLATE: + case COMP_TYPE_GZIP: + +#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED + result = DeflateAllocCompressor(state); +#endif + break; + + /* + * Unsupported compressor type allow error to propagate + */ + case COMP_TYPE_LZ4: + case COMP_TYPE_NONE: + default: + break; + } + + + /* + If result was successfull return the context pointer, if + the creation failed, free the state if it was allocated + and return the error code. + */ + + if (result > 0) + { + return (void*)state; + } + else + { + vnfree(state); + + /* + * Using strict/pedantic error checking int gcc will cause a warning + * when casting an int to a void* pointer. We are returning an error code + * and it is expected behavior + */ +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" + return (void*)result; +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4312) + return (void*)result; +#pragma warning(pop) +#else + return (void*)result; +#endif + } +} + +VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC FreeCompressor(void* compressor) +{ + CompressorState* comp; + int errorCode; + + CHECK_NULL_PTR(compressor) + + comp = (CompressorState*)compressor; + errorCode = TRUE; + + switch (comp->type) + { + case COMP_TYPE_BROTLI: +#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED + BrFreeCompressor(comp); +#endif + break; + + case COMP_TYPE_DEFLATE: + case COMP_TYPE_GZIP: + /* + * Releasing a deflate compressor will cause a deflate + * end call, which can fail, we should send the error + * to the caller and clean up as best we can. + */ +#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED + errorCode = DeflateFreeCompressor(comp); +#endif + break; + + + /* + * If compression type is none, there is nothing to do + * since its not technically an error, so just return + * true. + */ + case COMP_TYPE_NONE: + case COMP_TYPE_LZ4: + default: + break; + } + + /* + * Free the compressor state + */ + + vnfree(comp); + return errorCode; +} + +VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressedSize(_In_ const void* compressor, uint64_t inputLength, int32_t flush) +{ + CompressorState* comp; + int64_t result; + + CHECK_NULL_PTR(compressor) + + if (inputLength > INT64_MAX) + { + return ERR_OVERFLOW; + } + + comp = (CompressorState*)compressor; + result = ERR_COMP_TYPE_NOT_SUPPORTED; + + switch (comp->type) + { + + case COMP_TYPE_BROTLI: + +#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED + result = BrGetCompressedSize(comp, inputLength, flush); +#endif + break; + + case COMP_TYPE_DEFLATE: + case COMP_TYPE_GZIP: + +#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED + result = DeflateGetCompressedSize(comp, inputLength, flush); +#endif + break; + + /* + * Set the result as an error code, since the compressor + * type is not supported. + */ + case COMP_TYPE_NONE: + case COMP_TYPE_LZ4: + break; + } + + return result; +} + +/* +* Compresses the data contained in the operation structure, ingests and compresses +* the data then writes it to the output buffer. The result of the operation is +* returned as an error code. Positive integers indicate success, negative integers +* indicate failure. +* @param compressor +*/ +VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC CompressBlock(_In_ const void* compressor, CompressionOperation* operation) +{ + int result; + CompressorState* comp; + + comp = (CompressorState*)compressor; + + /* + * Validate input arguments + */ + + CHECK_NULL_PTR(comp) + CHECK_NULL_PTR(operation) + + /* + * Validate buffers, if the buffer length is greate than 0 + * it must point to a valid buffer + */ + + if (operation->bytesInLength > 0 && !operation->bytesIn) + { + return ERR_INVALID_INPUT_DATA; + } + + if (operation->bytesOutLength > 0 && !operation->bytesOut) + { + return ERR_INVALID_OUTPUT_DATA; + } + + /* + * Determine the compressor type and call the appropriate + * compression function + */ + + result = ERR_COMP_TYPE_NOT_SUPPORTED; + + switch (comp->type) + { + /* Brolti support */ + case COMP_TYPE_BROTLI: + +#ifdef VNLIB_COMPRESSOR_BROTLI_ENABLED + result = BrCompressBlock(comp, operation); +#endif + break; + + + /* Deflate support */ + case COMP_TYPE_DEFLATE: + case COMP_TYPE_GZIP: + +#ifdef VNLIB_COMPRESSOR_ZLIB_ENABLED + result = DeflateCompressBlock(comp, operation); +#endif + break; + + case COMP_TYPE_NONE: + case COMP_TYPE_LZ4: + break; + } + + return result; +} diff --git a/lib/Net.Compression/vnlib_compress/src/compression.h b/lib/Net.Compression/vnlib_compress/src/compression.h new file mode 100644 index 0000000..3d03145 --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/compression.h @@ -0,0 +1,263 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: vnlib_compress +* File: compression.h +* +* vnlib_compress is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* vnlib_compress is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. +*/ + + +/* +* Implementation notes: +* +* This library is designed to be a wrapper around the various compression libraries +* used for dynamic HTTP compression. Is is designed to be exported as a DLL or a shared +* library and written in portable C code. +* +* Compressors are standalone instances created by callers and used to perform compression +* operations. Compressors are created, used, and destroyed by callers. This library is meant +* to unify compression to a single api. The goal is performance and portability, so it can +* be easily used by portable runtimes. +*/ + +#pragma once + +#ifndef COMPRESSION_H_ +#define COMPRESSION_H_ + +#include + +#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) + #define _IS_WINDOWS +#endif + +/*Set api export calling convention(allow used to override)*/ +#ifndef VNLIB_COMPRESS_CC + #ifdef _IS_WINDOWS + /*STD for importing to other languages such as.NET*/ + #define VNLIB_COMPRESS_CC __stdcall + #else + #define VNLIB_COMPRESS_CC + #endif +#endif /* !VNLIB_CC */ + +#ifndef VNLIB_COMPRESS_EXPORT /*Allow users to disable the export/impoty macro if using source code directly*/ + #ifdef VNLIB_COMPRESS_EXPORTING + #ifdef _IS_WINDOWS + #define VNLIB_COMPRESS_EXPORT __declspec(dllexport) + #else + #define VNLIB_COMPRESS_EXPORT __attribute__((visibility("default"))) + #endif /* IS_WINDOWS */ + #else + #ifdef _IS_WINDOWS + #define VNLIB_COMPRESS_EXPORT __declspec(dllimport) + #else + #define VNLIB_COMPRESS_EXPORT + #endif /* IS_WINDOWS */ + #endif /* !VNLIB_EXPORTING */ +#endif /* !VNLIB_EXPORT */ + +#ifndef _In_ + #define _In_ +#endif + +/* +* ERRORS AND CONSTANTS +*/ +#define ERR_INVALID_PTR -1 +#define ERR_OUT_OF_MEMORY -2 + +#define ERR_COMP_TYPE_NOT_SUPPORTED -9 +#define ERR_COMP_LEVEL_NOT_SUPPORTED -10 +#define ERR_INVALID_INPUT_DATA -11 +#define ERR_INVALID_OUTPUT_DATA -12 +#define ERR_COMPRESSION_FAILED -13 +#define ERR_OVERFLOW -14 + +/* +* Enumerated list of supported compression types for user selection +* at runtime. +*/ +typedef enum CompressorType +{ + COMP_TYPE_NONE = 0x00, + COMP_TYPE_GZIP = 0x01, + COMP_TYPE_DEFLATE = 0x02, + COMP_TYPE_BROTLI = 0x04, + COMP_TYPE_LZ4 = 0x08 +} CompressorType; + + +/* + Specifies values that indicate whether a compression operation emphasizes speed + or compression size. +*/ +typedef enum CompressionLevel +{ + /* + The compression operation should be optimally compressed, even if the operation + takes a longer time to complete. + */ + COMP_LEVEL_OPTIMAL = 0, + /* + The compression operation should complete as quickly as possible, even if the + resulting file is not optimally compressed. + */ + COMP_LEVEL_FASTEST = 1, + /* + No compression should be performed on the file. + */ + COMP_LEVEL_NO_COMPRESSION = 2, + /* + The compression operation should create output as small as possible, even if + the operation takes a longer time to complete. + */ + COMP_LEVEL_SMALLEST_SIZE = 3 +} CompressionLevel; + + +typedef enum CompressorStatus { + COMPRESSOR_STATUS_READY = 0x00, + COMPRESSOR_STATUS_INITALIZED = 0x01, + COMPRESSOR_STATUS_NEEDS_FLUSH = 0x02 +} CompressorStatus; + +typedef struct CompressorStateStruct{ + + /* + Pointer to the underlying compressor implementation. + */ + void* compressor; + + /* + Indicates the type of underlying compressor. + */ + CompressorType type; + + /* + The user specified compression level, the underlying compressor will decide + how to handle this value. + */ + CompressionLevel level; + + /* + Indicates the suggested block size for the underlying compressor. + */ + uint32_t blockSize; + + +} CompressorState; + +/* +* An extern caller generated structure passed to calls for +* stream compression operations. +*/ +typedef struct CompressionOperationStruct { + + /* + * Input stream data + */ + const void* bytesIn; + /* + * Output buffer/data stream + */ + void* bytesOut; + + /* + * If the operation is a flush operation + */ + const int32_t flush; + + const uint32_t bytesInLength; + const uint32_t bytesOutLength; + + /* + * Results of the streaming operation + */ + + uint32_t bytesRead; + uint32_t bytesWritten; + +} CompressionOperation; + +/* +* Public API functions +*/ +VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetSupportedCompressors(void); + +/* +* Returns the suggested block size for the underlying compressor. +* +* @param compressor A pointer to the desired compressor instance to query. +* @return The suggested block size for the underlying compressor in bytes +*/ +VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressorBlockSize(_In_ const void* compressor); + +/* +* Gets the compressor type of the specified compressor instance. +* +* @param compressor A pointer to the desired compressor instance to query. +* @return The type of the specified compressor instance. +*/ +VNLIB_COMPRESS_EXPORT CompressorType VNLIB_COMPRESS_CC GetCompressorType(_In_ const void* compressor); + +/* +* Gets the compression level of the specified compressor instance. +* +* @param compressor A pointer to the desired compressor instance to query. +* @return The compression level of the specified compressor instance. +*/ +VNLIB_COMPRESS_EXPORT CompressionLevel VNLIB_COMPRESS_CC GetCompressorLevel(_In_ const void* compressor); + +/* +* Allocates a new compressor instance on the native heap of the desired compressor type. +* +* @param type The desired compressor type. +* @param level The desired compression level. +* @return A pointer to the newly allocated compressor instance. NULL if the compressor +could not be allocated. +*/ +VNLIB_COMPRESS_EXPORT void* VNLIB_COMPRESS_CC AllocateCompressor(CompressorType type, CompressionLevel level); + +/* +* Frees a previously allocated compressor instance. +* +* @param compressor A pointer to the desired compressor instance to free. +* @return The underlying compressor's native return code. +*/ +VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC FreeCompressor(void* compressor); + +/* +* Computes the maximum compressed size of the specified input data. This is not supported + for all compression types. +* +* @param compressor A pointer to the initialized compressor instance to use. +* @param inputLength The length of the input data in bytes. +* @return The maximum compressed size of the specified input data in bytes. +*/ +VNLIB_COMPRESS_EXPORT int64_t VNLIB_COMPRESS_CC GetCompressedSize(_In_ const void* compressor, uint64_t inputLength, int32_t flush); + + +/* +* Perform compression operation using the specified compressor instance. +* +* @param compressor A pointer to the initialized compressor instance to use. +* @param operation A pointer to the compression operation structure +* @return The underlying compressor's native return code +*/ +VNLIB_COMPRESS_EXPORT int VNLIB_COMPRESS_CC CompressBlock(_In_ const void* compressor, CompressionOperation* operation); + +#endif /* !VNLIB_COMPRESS_MAIN_H_ */ \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/src/feature_brotli.c b/lib/Net.Compression/vnlib_compress/src/feature_brotli.c new file mode 100644 index 0000000..361c61a --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/feature_brotli.c @@ -0,0 +1,249 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: vnlib_compress +* File: feature_brotli.c +* +* vnlib_compress is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* vnlib_compress is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include "feature_brotli.h" +#include "util.h" + +#define validateCompState(state) \ + if (!state) return ERR_INVALID_PTR; \ + if (!state->compressor) return ERR_BR_INVALID_STATE; \ + +/* +* Stream memory management functions +*/ +static void* _brAllocCallback(void* opaque, size_t size) +{ + (void)opaque; + return vnmalloc(size, 1); +} + +static void _brFreeCallback(void* opaque, void* address) +{ + (void)opaque; + + /*Brotli may pass a null address to the free callback*/ + if (address) + { + vnfree(address); + } +} + + +int BrAllocCompressor(CompressorState* state) +{ + BrotliEncoderState* comp; + + assert(state != NULL); + + /* + * Never allow no compression, it is not supported by the br encoder + */ + + if (state->level == COMP_LEVEL_NO_COMPRESSION) + { + return ERR_COMP_LEVEL_NOT_SUPPORTED; + } + + comp = BrotliEncoderCreateInstance( + &_brAllocCallback, + &_brFreeCallback, + NULL + ); + + if (!comp) + { + return ERR_OUT_OF_MEMORY; + } + + state->compressor = comp; + + /* + * Setting parameters will only return false if the parameter type is + * invalid, or the compressor state is not valid + * + * Setup some defaults + */ + + BrotliEncoderSetParameter(comp, BROTLI_PARAM_MODE, BROTLI_MODE_GENERIC); + BrotliEncoderSetParameter(comp, BROTLI_PARAM_LGWIN, BR_DEFAULT_WINDOW); + + /* + * Capture the block size as a size hint if it is greater than 0 + */ + if (state->blockSize > 0) + { + BrotliEncoderSetParameter(comp, BROTLI_PARAM_SIZE_HINT, state->blockSize); + } + + /* + * Setup compressor quality level based on the requested compression level + */ + + switch (state->level) + { + + case COMP_LEVEL_FASTEST: + BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_FASTEST); + break; + + case COMP_LEVEL_OPTIMAL: + BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_OPTIMAL); + break; + + case COMP_LEVEL_SMALLEST_SIZE: + BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_SMALLEST_SIZE); + break; + + case COMP_LEVEL_NO_COMPRESSION: + default: + BrotliEncoderSetParameter(comp, BROTLI_PARAM_QUALITY, BR_COMP_LEVEL_DEFAULT); + break; + } + + return TRUE; +} + +void BrFreeCompressor(CompressorState* state) +{ + assert(state != NULL); + + /* + * Free the compressor instance if it exists + */ + if (state->compressor) + { + BrotliEncoderDestroyInstance((BrotliEncoderState*)state->compressor); + state->compressor = NULL; + } +} + +int BrCompressBlock(const CompressorState* state, CompressionOperation* operation) +{ + BrotliEncoderOperation brOperation; + BROTLI_BOOL brResult; + + size_t availableIn, availableOut, totalOut; + const uint8_t* nextIn; + uint8_t* nextOut; + + /* Validate inputs */ + validateCompState(state) + + /* Clear the result read / written fields */ + operation->bytesRead = 0; + operation->bytesWritten = 0; + + /* + * If the input is empty a flush is not requested, they we are waiting for + * more input and this was just an empty call. Should be a no-op + */ + + if (operation->bytesInLength == 0 && operation->flush < 1) + { + return TRUE; + } + + /* + * Determine the operation to perform + */ + + if (operation->flush) + { + brOperation = BROTLI_OPERATION_FINISH; + } + else + { + brOperation = BROTLI_OPERATION_PROCESS; + } + + /* + * Update lengths and data pointers from input/output spans + * for stream variables + */ + + availableIn = operation->bytesInLength; + availableOut = operation->bytesOutLength; + nextIn = operation->bytesIn; + nextOut = operation->bytesOut; + + + /* + * Compress block as stream and store the result + * directly on the result output to pass back to the caller + */ + + brResult = BrotliEncoderCompressStream( + state->compressor, + brOperation, + &availableIn, + &nextIn, + &availableOut, + &nextOut, + &totalOut + ); + + /* + * check for possible overflow and retrun error + */ + if (availableIn > operation->bytesInLength || availableOut > operation->bytesOutLength) + { + return ERR_COMPRESSION_FAILED; + } + + /* + * Regardless of the operation success we should return the + * results to the caller. Br encoder sets the number of + * bytes remaining in the input/output spans + */ + operation->bytesRead = operation->bytesInLength - (uint32_t)availableIn; + operation->bytesWritten = operation->bytesOutLength - (uint32_t)availableOut; + + return brResult; +} + + +int64_t BrGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush) +{ + size_t size; + + (void)sizeof(flush); + /* + * When the flush flag is set, the caller is requesting the + * entire size of the compressed data, which can include metadata + */ + + validateCompState(state) + + if (length <= 0) + { + return 0; + } + + size = BrotliEncoderMaxCompressedSize(length); + + if (size > INT64_MAX) + { + return ERR_OVERFLOW; + } + + return (int64_t)size; +} \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/src/feature_brotli.h b/lib/Net.Compression/vnlib_compress/src/feature_brotli.h new file mode 100644 index 0000000..1f2090b --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/feature_brotli.h @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: vnlib_compress +* File: feature_brotli.h +* +* vnlib_compress is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* vnlib_compress is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. +*/ + +#pragma once + +#ifndef BROTLI_STUB_H_ +#define BROTLI_STUB_H_ + +#include "compression.h" + +#define ERR_BR_INVALID_STATE -24 + +#define BR_COMP_LEVEL_FASTEST 1 +#define BR_COMP_LEVEL_OPTIMAL 11 +#define BR_COMP_LEVEL_SMALLEST_SIZE 9 +#define BR_COMP_LEVEL_DEFAULT 5 + +#define BR_DEFAULT_WINDOW 22 + +int BrAllocCompressor(CompressorState* state); + +void BrFreeCompressor(CompressorState* state); + +int BrCompressBlock(const CompressorState* state, CompressionOperation* operation); + +int64_t BrGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush); + +#endif /* !BROTLI_STUB_H_ */ \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/src/feature_zlib.c b/lib/Net.Compression/vnlib_compress/src/feature_zlib.c new file mode 100644 index 0000000..a07f106 --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/feature_zlib.c @@ -0,0 +1,304 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: vnlib_compress +* File: feature_zlib.c +* +* vnlib_compress is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* vnlib_compress is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. +*/ + +/* +* Include the stub header and also the zlib header +*/ + + +#include +#include "feature_zlib.h" +#include "util.h" + +#define validateCompState(state) \ + if (!state) return ERR_INVALID_PTR; \ + if (!state->compressor) return ERR_GZ_INVALID_STATE; \ + +/* +* Stream memory management functions +*/ +static void* _gzAllocCallback(void* opaque, uint32_t items, uint32_t size) +{ + (void)opaque; + return vnmalloc(items, size); +} + +static void _gzFreeCallback(void* opaque, void* address) +{ + (void)opaque; + vnfree(address); +} + +int DeflateAllocCompressor(CompressorState* state) +{ + int result, compLevel; + z_stream* stream; + + assert(state); + + /* + * Allocate the z-stream state on the heap so we can + * store it in the compressor state + */ + stream = (z_stream*)vncalloc(1, sizeof(z_stream)); + + if (!stream) + { + return ERR_OUT_OF_MEMORY; + } + + stream->zalloc = &_gzAllocCallback; + stream->zfree = &_gzFreeCallback; + stream->opaque = Z_NULL; + + /* + * Initialize the z-stream state with the + * desired compression level + */ + + + switch (state->level) + { + case COMP_LEVEL_NO_COMPRESSION: + compLevel = Z_NO_COMPRESSION; + break; + + case COMP_LEVEL_FASTEST: + compLevel = Z_BEST_SPEED; + break; + + case COMP_LEVEL_OPTIMAL: + compLevel = Z_BEST_COMPRESSION; + break; + + case COMP_LEVEL_SMALLEST_SIZE: + compLevel = Z_BEST_COMPRESSION; + break; + + /* + Default compression level + */ + default: + compLevel = Z_DEFAULT_COMPRESSION; + break; + } + + /* + * If gzip is enabled, we need to configure the deflatenit2, with + * the max window size to 16 + */ + + if(state->type & COMP_TYPE_GZIP) + { + result = deflateInit2( + stream, + compLevel, + Z_DEFLATED, + GZ_ENABLE_GZIP_WINDOW, + GZ_DEFAULT_MEM_LEVEL, + Z_DEFAULT_STRATEGY + ); + } + else + { + /* Enable raw deflate */ + result = deflateInit2( + stream, + compLevel, + Z_DEFLATED, + GZ_ENABLE_RAW_DEFLATE_WINDOW, + GZ_DEFAULT_MEM_LEVEL, + Z_DEFAULT_STRATEGY + ); + } + + /* + * Inspect the result of the initialization, + * of the init failed, free the stream and return + * the error code + */ + + if (result != Z_OK) + { + vnfree(stream); + return result; + } + + /* + * Assign the z-stream state to the compressor state, all done! + */ + state->compressor = stream; + return TRUE; +} + +int DeflateFreeCompressor(CompressorState* state) +{ + int result; + + assert(state); + + /* + * Free the z-stream state, only if the compressor is initialized + */ + if (state->compressor) + { + /* + * Attempt to end the deflate stream, and store the status code + */ + + result = deflateEnd(state->compressor); + + /* + * We can always free the z-stream state, even if the deflate + * stream failed to end. + */ + + vnfree(state->compressor); + state->compressor = NULL; + + /* + * A data error is acceptable when calling end in this library + * since at that point all resources have been cleaned, and zlib + * is simply returning a warning that the stream was not properly + * terminated. + * + * We assum that calls to free are meant to clean up resources regarless + * of their status + */ + return result == Z_OK || result == Z_DATA_ERROR; + } + + return TRUE; +} + +int DeflateCompressBlock(const CompressorState* state, CompressionOperation* operation) +{ + z_stream* stream; + int result; + + validateCompState(state) + + /* Clear the result read/written fields */ + operation->bytesRead = 0; + operation->bytesWritten = 0; + + /* + * If the input is empty a flush is not requested, they we are waiting for + * more input and this was just an empty call. Should be a no-op + */ + + if (operation->bytesInLength == 0 && operation->flush < 1) + { + return TRUE; + } + + stream = (z_stream*)state->compressor; + + /* + * Overwrite the stream state with the operation parameters from + * this next compression operation. + * + * The caller stores the stream positions in its application memory. + */ + stream->avail_in = operation->bytesInLength; + stream->next_in = (Bytef*)operation->bytesIn; + + stream->avail_out = operation->bytesOutLength; + stream->next_out = (Bytef*)operation->bytesOut; + + /* + * In this library we only use the flush flag as a boolean value. + * Callers only set the flush flag when the operation has completed + * and the compressor is expected to flush its internal buffers. + * (aka finish) + */ + + result = deflate(stream, operation->flush ? Z_FINISH : Z_NO_FLUSH); + + /* + * Allways clear stream fields as they are assigned on every call + */ + stream->next_in = NULL; + stream->next_out = NULL; + + /* + * check for result overflow and return the error code + */ + if (stream->avail_in > operation->bytesInLength || stream->avail_out > operation->bytesOutLength) + { + return ERR_COMPRESSION_FAILED; + } + + /* + * Regardless of the return value, we should always update the + * the number of bytes read and written. + * + * The result is the number total bytes minus the number of + * bytes remaining in the stream. + */ + + operation->bytesRead = operation->bytesInLength - stream->avail_in; + operation->bytesWritten = operation->bytesOutLength - stream->avail_out; + + stream->avail_in = 0; + stream->avail_out = 0; + + return result; +} + +int64_t DeflateGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush) +{ + uint64_t compressedSize; + + /* + * When the flush flag is set, the caller is requesting the + * entire size of the compressed data, which can include metadata + */ + + validateCompState(state) + + if (length <= 0) + { + return 0; + } + + if(flush) + { + /* + * TODO: actualy determine the size of the compressed data + * when the flush flag is set. + */ + + compressedSize = deflateBound(state->compressor, length); + } + else + { + compressedSize = deflateBound(state->compressor, length); + } + + /* Verify the results to make sure the value doesnt overflow */ + if (compressedSize > INT64_MAX) + { + return ERR_GZ_OVERFLOW; + } + + return (int64_t)compressedSize; +} \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/src/feature_zlib.h b/lib/Net.Compression/vnlib_compress/src/feature_zlib.h new file mode 100644 index 0000000..2544d25 --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/feature_zlib.h @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: vnlib_compress +* File: feature_zlib.h +* +* vnlib_compress is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* vnlib_compress is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. +*/ + +#pragma once + +#ifndef ZLIB_STUB_H_ +#define ZLIB_STUB_H_ + +#include "compression.h" + +#define ERR_GZ_INVALID_STATE -16 +#define ERR_GZ_OVERFLOW -17 + +/* Allow user to define their own memory level value */ +#ifndef GZ_DEFAULT_MEM_LEVEL +#define GZ_DEFAULT_MEM_LEVEL 8 +#endif + +/* Specifies the window value to enable GZIP */ +#define GZ_ENABLE_GZIP_WINDOW 15 + 16 +#define GZ_ENABLE_RAW_DEFLATE_WINDOW -15 + + +int DeflateAllocCompressor(CompressorState* state); + +int DeflateFreeCompressor(CompressorState* state); + +int DeflateCompressBlock(const CompressorState* state, CompressionOperation* operation); + +int64_t DeflateGetCompressedSize(const CompressorState* state, uint64_t length, int32_t flush); + +#endif diff --git a/lib/Net.Compression/vnlib_compress/src/util.h b/lib/Net.Compression/vnlib_compress/src/util.h new file mode 100644 index 0000000..292e3bf --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/util.h @@ -0,0 +1,140 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: vnlib_compress +* File: util.h +* +* vnlib_compress is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* vnlib_compress is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. +*/ + +#pragma once + +#ifndef UTIL_H_ +#define UTIL_H_ + +/* +* If a custom allocator is enabled, use the native heap api +* header and assume linking is enabled. Heap functions below +* will be enabled when heapapi.h is included. +*/ +#ifdef VNLIB_CUSTOM_MALLOC_ENABLE + /* Since static linking ie snabled, heapapi must have extern symbol not dllimport */ + #define VNLIB_HEAP_API extern + #include +#endif + +#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) + #define IS_WINDOWS +#endif + +#if defined(IS_WINDOWS) || defined(inline) || defined(__clang__) + #define _cp_fn_inline inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 allows usage of inline keyword */ + #define _cp_fn_inline inline +#elif defined(__GNUC__) || defined(__GNUG__) + #define _cp_fn_inline __inline__ +#else + #define _cp_fn_inline + #pragma message("Warning: No inline keyword defined for this compiler") +#endif + +#ifndef NULL + #define NULL ((void*)0) +#endif /* !NULL */ + +#ifndef TRUE + #define TRUE 1 +#endif /* !TRUE */ + +#ifndef FALSE + #define FALSE 0 +#endif /* !FALSE */ + +/* +* Add debug runtime assertions +*/ +#ifdef DEBUG + #include +#else + #define assert(x) {} +#endif + +#define CHECK_NULL_PTR(ptr) if(!ptr) return ERR_INVALID_PTR; + +#ifdef NATIVE_HEAP_API /* Defined in the NativeHeapApi */ + + #include + + /* + * Add overrides for malloc, calloc, and free that use + * the nativeheap api to allocate memory + * + * Inline fuctions are used to enforce type safety and + * api consistency. + */ + + static _cp_fn_inline void* vnmalloc(size_t num, size_t size) + { + return heapAlloc(heapGetSharedHeapHandle(), num, size, FALSE); + } + + static _cp_fn_inline void* vncalloc(size_t num, size_t size) + { + return heapAlloc(heapGetSharedHeapHandle(), num, size, TRUE); + } + + static _cp_fn_inline void vnfree(void* ptr) + { + #ifdef DEBUG + + ERRNO result; + result = heapFree(heapGetSharedHeapHandle(), ptr); + + /* track failed free results */ + assert(result > 0); + + #else + + heapFree(heapGetSharedHeapHandle(), ptr); + + #endif + + } + +#else + + /* + * Required for built-in memory api + */ + #include + + /* + * Stub method for malloc. All calls to vnmalloc should be freed with vnfree. + */ + #define vnmalloc(num, size) malloc(num * size) + + /* + * Stub method for free + */ + #define vnfree(ptr) free(ptr) + + /* + * Stub method for calloc. All calls to vncalloc should be freed with vnfree. + */ + #define vncalloc(num, size) calloc(num, size) + +#endif /* NATIVE_HEAP_API */ + +#endif /* !UTIL_H_ */ \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/src/vnlib_compress.vcxitems b/lib/Net.Compression/vnlib_compress/src/vnlib_compress.vcxitems new file mode 100644 index 0000000..7f5eb0e --- /dev/null +++ b/lib/Net.Compression/vnlib_compress/src/vnlib_compress.vcxitems @@ -0,0 +1,34 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {f2e07583-6244-41a4-84a3-e29fd257ee7c} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/util.h b/lib/Net.Compression/vnlib_compress/util.h deleted file mode 100644 index 292e3bf..0000000 --- a/lib/Net.Compression/vnlib_compress/util.h +++ /dev/null @@ -1,140 +0,0 @@ -/* -* Copyright (c) 2024 Vaughn Nugent -* -* Library: VNLib -* Package: vnlib_compress -* File: util.h -* -* vnlib_compress is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* vnlib_compress is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with vnlib_compress. If not, see http://www.gnu.org/licenses/. -*/ - -#pragma once - -#ifndef UTIL_H_ -#define UTIL_H_ - -/* -* If a custom allocator is enabled, use the native heap api -* header and assume linking is enabled. Heap functions below -* will be enabled when heapapi.h is included. -*/ -#ifdef VNLIB_CUSTOM_MALLOC_ENABLE - /* Since static linking ie snabled, heapapi must have extern symbol not dllimport */ - #define VNLIB_HEAP_API extern - #include -#endif - -#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) - #define IS_WINDOWS -#endif - -#if defined(IS_WINDOWS) || defined(inline) || defined(__clang__) - #define _cp_fn_inline inline -#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 allows usage of inline keyword */ - #define _cp_fn_inline inline -#elif defined(__GNUC__) || defined(__GNUG__) - #define _cp_fn_inline __inline__ -#else - #define _cp_fn_inline - #pragma message("Warning: No inline keyword defined for this compiler") -#endif - -#ifndef NULL - #define NULL ((void*)0) -#endif /* !NULL */ - -#ifndef TRUE - #define TRUE 1 -#endif /* !TRUE */ - -#ifndef FALSE - #define FALSE 0 -#endif /* !FALSE */ - -/* -* Add debug runtime assertions -*/ -#ifdef DEBUG - #include -#else - #define assert(x) {} -#endif - -#define CHECK_NULL_PTR(ptr) if(!ptr) return ERR_INVALID_PTR; - -#ifdef NATIVE_HEAP_API /* Defined in the NativeHeapApi */ - - #include - - /* - * Add overrides for malloc, calloc, and free that use - * the nativeheap api to allocate memory - * - * Inline fuctions are used to enforce type safety and - * api consistency. - */ - - static _cp_fn_inline void* vnmalloc(size_t num, size_t size) - { - return heapAlloc(heapGetSharedHeapHandle(), num, size, FALSE); - } - - static _cp_fn_inline void* vncalloc(size_t num, size_t size) - { - return heapAlloc(heapGetSharedHeapHandle(), num, size, TRUE); - } - - static _cp_fn_inline void vnfree(void* ptr) - { - #ifdef DEBUG - - ERRNO result; - result = heapFree(heapGetSharedHeapHandle(), ptr); - - /* track failed free results */ - assert(result > 0); - - #else - - heapFree(heapGetSharedHeapHandle(), ptr); - - #endif - - } - -#else - - /* - * Required for built-in memory api - */ - #include - - /* - * Stub method for malloc. All calls to vnmalloc should be freed with vnfree. - */ - #define vnmalloc(num, size) malloc(num * size) - - /* - * Stub method for free - */ - #define vnfree(ptr) free(ptr) - - /* - * Stub method for calloc. All calls to vncalloc should be freed with vnfree. - */ - #define vncalloc(num, size) calloc(num, size) - -#endif /* NATIVE_HEAP_API */ - -#endif /* !UTIL_H_ */ \ No newline at end of file diff --git a/lib/Net.Compression/vnlib_compress/vnlib_compress.vcxitems b/lib/Net.Compression/vnlib_compress/vnlib_compress.vcxitems deleted file mode 100644 index 5b2a317..0000000 --- a/lib/Net.Compression/vnlib_compress/vnlib_compress.vcxitems +++ /dev/null @@ -1,34 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - {f2e07583-6244-41a4-84a3-e29fd257ee7c} - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file -- cgit