Skip to content

Commit 9e6c60d

Browse files
authored
Implement a GZIP library (powered by ZLIB) (#1798)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent ef23a63 commit 9e6c60d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+23547
-7
lines changed

.github/workflows/website-build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
- run: >
1717
cmake -S . -B ./build
1818
-DCMAKE_BUILD_TYPE:STRING=Release
19+
-DSOURCEMETA_CORE_GZIP:BOOL=OFF
1920
-DSOURCEMETA_CORE_REGEX:BOOL=OFF
2021
-DSOURCEMETA_CORE_URI:BOOL=OFF
2122
-DSOURCEMETA_CORE_JSON:BOOL=OFF

.github/workflows/website-deploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
- run: >
2727
cmake -S . -B ./build
2828
-DCMAKE_BUILD_TYPE:STRING=Release
29+
-DSOURCEMETA_CORE_GZIP:BOOL=OFF
2930
-DSOURCEMETA_CORE_REGEX:BOOL=OFF
3031
-DSOURCEMETA_CORE_URI:BOOL=OFF
3132
-DSOURCEMETA_CORE_JSON:BOOL=OFF

CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ project(core VERSION 0.0.0 LANGUAGES C CXX DESCRIPTION "Sourcemeta Core")
33
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
44

55
# Options
6+
option(SOURCEMETA_CORE_GZIP "Build the Sourcemeta Core GZIP library" ON)
67
option(SOURCEMETA_CORE_REGEX "Build the Sourcemeta Core Regex library" ON)
78
option(SOURCEMETA_CORE_URI "Build the Sourcemeta Core URI library" ON)
89
option(SOURCEMETA_CORE_JSON "Build the Sourcemeta Core JSON library" ON)
@@ -17,6 +18,7 @@ option(SOURCEMETA_CORE_DOCS "Build the Sourcemeta Core docs" OFF)
1718
option(SOURCEMETA_CORE_INSTALL "Install the Sourcemeta Core library" ON)
1819
option(SOURCEMETA_CORE_ADDRESS_SANITIZER "Build Sourcemeta Core with an address sanitizer" OFF)
1920
option(SOURCEMETA_CORE_UNDEFINED_SANITIZER "Build Sourcemeta Core with an undefined behavior sanitizer" OFF)
21+
option(SOURCEMETA_CORE_CONTRIB_ZLIB "Build the ZLIB library for downstream consumers" OFF)
2022
option(SOURCEMETA_CORE_CONTRIB_GOOGLETEST "Build the GoogleTest library for downstream consumers" OFF)
2123
option(SOURCEMETA_CORE_CONTRIB_GOOGLEBENCHMARK "Build the GoogleBenchmark library for downstream consumers" OFF)
2224

@@ -45,6 +47,11 @@ if(SOURCEMETA_CORE_INSTALL)
4547
COMPONENT sourcemeta_${PROJECT_NAME}_dev)
4648
endif()
4749

50+
if(SOURCEMETA_CORE_GZIP OR SOURCEMETA_CORE_CONTRIB_ZLIB)
51+
find_package(ZLIB REQUIRED)
52+
add_subdirectory(src/core/gzip)
53+
endif()
54+
4855
if(SOURCEMETA_CORE_REGEX)
4956
find_package(BoostRegex REQUIRED)
5057
add_subdirectory(src/core/regex)
@@ -112,6 +119,10 @@ endif()
112119
if(SOURCEMETA_CORE_TESTS)
113120
enable_testing()
114121

122+
if(SOURCEMETA_CORE_GZIP)
123+
add_subdirectory(test/gzip)
124+
endif()
125+
115126
if(SOURCEMETA_CORE_REGEX)
116127
add_subdirectory(test/regex)
117128
endif()

DEPENDENCIES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ referencing-suite https://github.com/python-jsonschema/referencing-suite 61c4cc2
1313
jsonschema-test-suite https://github.com/json-schema-org/JSON-Schema-Test-Suite c2badb1298a8698f86dadf1aea7b44b3a894e5ac
1414
uriparser https://github.com/uriparser/uriparser bfe94f6e54d0abb5afa7bb0411940b7242cb835a
1515
yaml https://github.com/yaml/libyaml 0.2.5
16+
zlib https://github.com/madler/zlib 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf
1617
boost-regex https://github.com/boostorg/regex boost-1.86.0
1718
googletest https://github.com/google/googletest a7f443b80b105f940225332ed3c31f2790092f47
1819
googlebenchmark https://github.com/google/benchmark 378fe693a1ef51500db21b11ff05a8018c5f0e55

cmake/FindZLIB.cmake

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
if(NOT ZLIB_FOUND)
2+
set(Z_HAVE_UNISTD_H ON)
3+
configure_file("${PROJECT_SOURCE_DIR}/vendor/zlib/zconf.h.cmakein"
4+
"${CMAKE_CURRENT_BINARY_DIR}/zlib/zconf.h" @ONLY)
5+
6+
set(ZLIB_DIR "${PROJECT_SOURCE_DIR}/vendor/zlib")
7+
set(ZLIB_PUBLIC_HEADER "${ZLIB_DIR}/zlib.h")
8+
set(ZLIB_PRIVATE_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/zlib/zconf.h")
9+
10+
add_library(zlib
11+
"${ZLIB_PUBLIC_HEADER}" ${ZLIB_PRIVATE_HEADERS}
12+
"${ZLIB_DIR}/adler32.c"
13+
"${ZLIB_DIR}/compress.c"
14+
"${ZLIB_DIR}/crc32.c"
15+
"${ZLIB_DIR}/crc32.h"
16+
"${ZLIB_DIR}/deflate.c"
17+
"${ZLIB_DIR}/deflate.h"
18+
"${ZLIB_DIR}/gzclose.c"
19+
"${ZLIB_DIR}/gzguts.h"
20+
"${ZLIB_DIR}/gzlib.c"
21+
"${ZLIB_DIR}/gzread.c"
22+
"${ZLIB_DIR}/gzwrite.c"
23+
"${ZLIB_DIR}/infback.c"
24+
"${ZLIB_DIR}/inffast.c"
25+
"${ZLIB_DIR}/inffast.h"
26+
"${ZLIB_DIR}/inffixed.h"
27+
"${ZLIB_DIR}/inflate.c"
28+
"${ZLIB_DIR}/inflate.h"
29+
"${ZLIB_DIR}/inftrees.c"
30+
"${ZLIB_DIR}/inftrees.h"
31+
"${ZLIB_DIR}/trees.c"
32+
"${ZLIB_DIR}/trees.h"
33+
"${ZLIB_DIR}/uncompr.c"
34+
"${ZLIB_DIR}/zutil.c"
35+
"${ZLIB_DIR}/zutil.h")
36+
37+
target_compile_definitions(zlib PUBLIC NO_FSEEKO)
38+
target_compile_definitions(zlib PUBLIC _LARGEFILE64_SOURCE=1)
39+
40+
target_include_directories(zlib PUBLIC
41+
"$<BUILD_INTERFACE:${ZLIB_DIR}>"
42+
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
43+
44+
add_library(ZLIB::ZLIB ALIAS zlib)
45+
46+
set_target_properties(zlib
47+
PROPERTIES
48+
OUTPUT_NAME zlib
49+
PUBLIC_HEADER "${ZLIB_PUBLIC_HEADER}"
50+
PRIVATE_HEADER "${ZLIB_PRIVATE_HEADERS}"
51+
C_VISIBILITY_PRESET "default"
52+
C_VISIBILITY_INLINES_HIDDEN FALSE
53+
WINDOWS_EXPORT_ALL_SYMBOLS TRUE
54+
EXPORT_NAME zlib)
55+
56+
if(SOURCEMETA_CORE_INSTALL)
57+
include(GNUInstallDirs)
58+
install(TARGETS zlib
59+
EXPORT zlib
60+
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
61+
COMPONENT sourcemeta_core_dev
62+
PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
63+
COMPONENT sourcemeta_core_dev
64+
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
65+
COMPONENT sourcemeta_core
66+
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
67+
COMPONENT sourcemeta_core
68+
NAMELINK_COMPONENT sourcemeta_core_dev
69+
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
70+
COMPONENT sourcemeta_core_dev)
71+
install(EXPORT zlib
72+
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zlib"
73+
COMPONENT sourcemeta_core_dev)
74+
75+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/zlib-config.cmake
76+
"include(\"\${CMAKE_CURRENT_LIST_DIR}/zlib.cmake\")\n"
77+
"check_required_components(\"zlib\")\n")
78+
install(FILES
79+
"${CMAKE_CURRENT_BINARY_DIR}/zlib-config.cmake"
80+
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zlib"
81+
COMPONENT sourcemeta_core_dev)
82+
endif()
83+
84+
set(ZLIB_FOUND ON)
85+
endif()

config.cmake.in

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
list(APPEND SOURCEMETA_CORE_COMPONENTS ${Core_FIND_COMPONENTS})
55
list(APPEND SOURCEMETA_CORE_COMPONENTS ${core_FIND_COMPONENTS})
66
if(NOT SOURCEMETA_CORE_COMPONENTS)
7+
list(APPEND SOURCEMETA_CORE_COMPONENTS gzip)
78
list(APPEND SOURCEMETA_CORE_COMPONENTS regex)
89
list(APPEND SOURCEMETA_CORE_COMPONENTS uri)
910
list(APPEND SOURCEMETA_CORE_COMPONENTS json)
@@ -17,35 +18,38 @@ endif()
1718
include(CMakeFindDependencyMacro)
1819

1920
foreach(component ${SOURCEMETA_CORE_COMPONENTS})
20-
if(component STREQUAL "regex")
21-
find_dependency(BoostRegex)
21+
if(component STREQUAL "gzip")
22+
find_dependency(ZLIB CONFIG)
23+
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_gzip.cmake")
24+
elseif(component STREQUAL "regex")
25+
find_dependency(BoostRegex CONFIG)
2226
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_regex.cmake")
2327
elseif(component STREQUAL "uri")
24-
find_dependency(uriparser)
28+
find_dependency(uriparser CONFIG)
2529
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_uri.cmake")
2630
elseif(component STREQUAL "json")
2731
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_json.cmake")
2832
elseif(component STREQUAL "jsonl")
2933
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_json.cmake")
3034
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_jsonl.cmake")
3135
elseif(component STREQUAL "jsonpointer")
32-
find_dependency(uriparser)
36+
find_dependency(uriparser CONFIG)
3337
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_regex.cmake")
3438
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_uri.cmake")
3539
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_json.cmake")
3640
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_jsonpointer.cmake")
3741
elseif(component STREQUAL "jsonschema")
38-
find_dependency(uriparser)
42+
find_dependency(uriparser CONFIG)
3943
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_uri.cmake")
4044
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_json.cmake")
4145
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_jsonpointer.cmake")
4246
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_jsonschema.cmake")
4347
elseif(component STREQUAL "yaml")
4448
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_json.cmake")
45-
find_dependency(yaml)
49+
find_dependency(yaml CONFIG)
4650
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_yaml.cmake")
4751
elseif(component STREQUAL "alterschema")
48-
find_dependency(uriparser)
52+
find_dependency(uriparser CONFIG)
4953
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_uri.cmake")
5054
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_json.cmake")
5155
include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_jsonpointer.cmake")

src/core/gzip/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME gzip SOURCES gzip.cc)
2+
3+
if(SOURCEMETA_CORE_INSTALL)
4+
sourcemeta_library_install(NAMESPACE sourcemeta PROJECT core NAME gzip)
5+
endif()
6+
7+
target_link_libraries(sourcemeta_core_gzip PRIVATE ZLIB::ZLIB)

src/core/gzip/gzip.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <sourcemeta/core/gzip.h>
2+
3+
extern "C" {
4+
#include <zlib.h>
5+
}
6+
7+
#include <cstring> // std::memset
8+
#include <sstream> // std::ostringstream
9+
10+
namespace sourcemeta::core {
11+
12+
auto gzip(std::string_view input) -> std::optional<std::string> {
13+
z_stream stream;
14+
std::memset(&stream, 0, sizeof(stream));
15+
int code = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
16+
16 + MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
17+
if (code != Z_OK) {
18+
return std::nullopt;
19+
}
20+
21+
stream.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
22+
stream.avail_in = static_cast<uInt>(input.size());
23+
24+
char buffer[4096];
25+
std::ostringstream compressed;
26+
27+
do {
28+
stream.next_out = reinterpret_cast<Bytef *>(buffer);
29+
stream.avail_out = sizeof(buffer);
30+
code = deflate(&stream, Z_FINISH);
31+
compressed.write(buffer, sizeof(buffer) - stream.avail_out);
32+
} while (code == Z_OK);
33+
34+
if (code != Z_STREAM_END) {
35+
return std::nullopt;
36+
}
37+
38+
code = deflateEnd(&stream);
39+
if (code != Z_OK) {
40+
return std::nullopt;
41+
}
42+
43+
return compressed.str();
44+
}
45+
46+
} // namespace sourcemeta::core
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef SOURCEMETA_CORE_GZIP_H_
2+
#define SOURCEMETA_CORE_GZIP_H_
3+
4+
#ifndef SOURCEMETA_CORE_GZIP_EXPORT
5+
#include <sourcemeta/core/gzip_export.h>
6+
#endif
7+
8+
#include <optional> // std::optional
9+
#include <string> // std::string
10+
#include <string_view> // std::string_view
11+
12+
/// @defgroup gzip GZIP
13+
/// @brief An growing implementation of RFC 1952 GZIP.
14+
///
15+
/// This functionality is included as follows:
16+
///
17+
/// ```cpp
18+
/// #include <sourcemeta/core/gzip.h>
19+
/// ```
20+
21+
namespace sourcemeta::core {
22+
23+
/// @ingroup gzip
24+
///
25+
/// Compress an input string into a sequence of bytes represented using a
26+
/// string. For example:
27+
///
28+
/// ```cpp
29+
/// #include <sourcemeta/core/gzip.h>
30+
/// #include <cassert>
31+
///
32+
/// const auto result{sourcemeta::core::gzip("Hello World")};
33+
/// assert(result.has_value());
34+
/// assert(!result.value().empty());
35+
/// ```
36+
SOURCEMETA_CORE_GZIP_EXPORT auto gzip(std::string_view input)
37+
-> std::optional<std::string>;
38+
39+
} // namespace sourcemeta::core
40+
41+
#endif

test/gzip/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
sourcemeta_googletest(NAMESPACE sourcemeta PROJECT core NAME gzip
2+
SOURCES gzip_test.cc)
3+
4+
target_link_libraries(sourcemeta_core_gzip_unit
5+
PRIVATE sourcemeta::core::gzip)

0 commit comments

Comments
 (0)