diff --git a/.gitmodules b/.gitmodules
index 4881782..fdcaafc 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
[submodule "3rdparty/zstd"]
path = 3rdparty/zstd
url = https://github.com/facebook/zstd
+[submodule "3rdparty/lz4"]
+ path = 3rdparty/lz4
+ url = https://github.com/lz4/lz4.git
diff --git a/3rdparty/lz4 b/3rdparty/lz4
new file mode 160000
index 0000000..c609c16
--- /dev/null
+++ b/3rdparty/lz4
@@ -0,0 +1 @@
+Subproject commit c609c16aed95ed339e142535b1b270e7b9e24ac1
diff --git a/3rdparty/lz4.cmake b/3rdparty/lz4.cmake
new file mode 100644
index 0000000..47a1ae5
--- /dev/null
+++ b/3rdparty/lz4.cmake
@@ -0,0 +1,378 @@
+# CMake support for LZ4
+#
+# To the extent possible under law, the author(s) have dedicated all
+# copyright and related and neighboring rights to this software to
+# the public domain worldwide. This software is distributed without
+# any warranty.
+#
+# For details, see .
+
+
+# Use range version specification for policy control while maintaining
+# compatibility with older CMake versions
+cmake_minimum_required(VERSION 3.5...4.0.2)
+
+set(LZ4_BUNDLED_MODE ON)
+set(LZ4_TOP_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/lz4")
+
+#-----------------------------------------------------------------------------
+# VERSION EXTRACTION - Parse version information from header file
+#-----------------------------------------------------------------------------
+function(parse_lz4_version VERSION_TYPE)
+ file(STRINGS "${LZ4_TOP_SOURCE_DIR}/lib/lz4.h" version_line REGEX "^#define LZ4_VERSION_${VERSION_TYPE} +([0-9]+).*$")
+ string(REGEX REPLACE "^#define LZ4_VERSION_${VERSION_TYPE} +([0-9]+).*$" "\\1" version_number "${version_line}")
+ set(LZ4_VERSION_${VERSION_TYPE} ${version_number} PARENT_SCOPE)
+endfunction()
+
+foreach(version_type IN ITEMS MAJOR MINOR RELEASE)
+ parse_lz4_version(${version_type})
+endforeach()
+
+set(LZ4_VERSION_STRING "${LZ4_VERSION_MAJOR}.${LZ4_VERSION_MINOR}.${LZ4_VERSION_RELEASE}")
+mark_as_advanced(LZ4_VERSION_STRING LZ4_VERSION_MAJOR LZ4_VERSION_MINOR LZ4_VERSION_RELEASE)
+
+message(STATUS "Creating build script for LZ4 version: ${LZ4_VERSION_STRING}")
+
+project(LZ4 VERSION ${LZ4_VERSION_STRING} LANGUAGES C)
+
+#-----------------------------------------------------------------------------
+# DEFAULT BUILD TYPE - Set Release as default when no build type is specified
+#-----------------------------------------------------------------------------
+# Set a default build type if none was specified
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+ message(STATUS "Setting build type to 'Release' as none was specified.")
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
+ # Set the possible values of build type for cmake-gui
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+ "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
+endif()
+
+#-----------------------------------------------------------------------------
+# BUILD OPTIONS - Configure build targets and features
+#-----------------------------------------------------------------------------
+option(LZ4_BUILD_CLI "Build lz4 program" OFF)
+option(LZ4_BUILD_LEGACY_LZ4C "Build lz4c program with legacy argument support" OFF)
+
+
+# Determine if LZ4 is being built as part of another project.
+# If LZ4 is bundled in another project, we don't want to install anything.
+# Default behavior can be overridden by setting the LZ4_BUNDLED_MODE variable.
+if(NOT DEFINED LZ4_BUNDLED_MODE)
+ get_directory_property(LZ4_IS_SUBPROJECT PARENT_DIRECTORY)
+ if(LZ4_IS_SUBPROJECT)
+ set(LZ4_BUNDLED_MODE ON)
+ else()
+ set(LZ4_BUNDLED_MODE OFF)
+ endif()
+endif()
+mark_as_advanced(LZ4_BUNDLED_MODE)
+
+#-----------------------------------------------------------------------------
+# PACKAGING - CPack configuration
+#-----------------------------------------------------------------------------
+if(NOT LZ4_BUNDLED_MODE AND NOT CPack_CMake_INCLUDED)
+ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LZ4 compression library")
+ set(CPACK_PACKAGE_DESCRIPTION_FILE "${LZ4_TOP_SOURCE_DIR}/README.md")
+ set(CPACK_RESOURCE_FILE_LICENSE "${LZ4_TOP_SOURCE_DIR}/LICENSE")
+ set(CPACK_PACKAGE_VERSION_MAJOR ${LZ4_VERSION_MAJOR})
+ set(CPACK_PACKAGE_VERSION_MINOR ${LZ4_VERSION_MINOR})
+ set(CPACK_PACKAGE_VERSION_PATCH ${LZ4_VERSION_RELEASE})
+ include(CPack)
+endif(NOT LZ4_BUNDLED_MODE AND NOT CPack_CMake_INCLUDED)
+
+#-----------------------------------------------------------------------------
+# LIBRARY TYPE CONFIGURATION - Static vs Shared libraries
+#-----------------------------------------------------------------------------
+# Allow people to choose whether to build shared or static libraries
+# via the BUILD_SHARED_LIBS option unless we are in bundled mode, in
+# which case we always use static libraries.
+include(CMakeDependentOption)
+CMAKE_DEPENDENT_OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON "NOT LZ4_BUNDLED_MODE" OFF)
+CMAKE_DEPENDENT_OPTION(BUILD_STATIC_LIBS "Build static libraries" OFF "BUILD_SHARED_LIBS" ON)
+
+if(NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS)
+ message(FATAL_ERROR "Both BUILD_SHARED_LIBS and BUILD_STATIC_LIBS have been disabled")
+endif(NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS)
+
+#-----------------------------------------------------------------------------
+# SOURCE FILES & DIRECTORIES - Path setup and source file collection
+#-----------------------------------------------------------------------------
+set(LZ4_LIB_SOURCE_DIR "${LZ4_TOP_SOURCE_DIR}/lib")
+set(LZ4_PROG_SOURCE_DIR "${LZ4_TOP_SOURCE_DIR}/programs")
+
+include_directories("${LZ4_LIB_SOURCE_DIR}")
+
+# CLI sources
+file(GLOB LZ4_SOURCES
+ "${LZ4_LIB_SOURCE_DIR}/*.c")
+file(GLOB LZ4_CLI_SOURCES
+ "${LZ4_PROG_SOURCE_DIR}/*.c")
+list(APPEND LZ4_CLI_SOURCES ${LZ4_SOURCES}) # LZ4_CLI always use liblz4 sources directly.
+
+#-----------------------------------------------------------------------------
+# POSITION INDEPENDENT CODE - PIC settings for static libraries
+#-----------------------------------------------------------------------------
+# Whether to use position independent code for the static library. If
+# we're building a shared library this is ignored and PIC is always
+# used.
+if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE OR CMAKE_POSITION_INDEPENDENT_CODE)
+ set(LZ4_POSITION_INDEPENDENT_LIB_DEFAULT ON)
+else()
+ set(LZ4_POSITION_INDEPENDENT_LIB_DEFAULT OFF)
+endif(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE OR CMAKE_POSITION_INDEPENDENT_CODE)
+
+option(LZ4_POSITION_INDEPENDENT_LIB "Use position independent code for static library (if applicable)" ${LZ4_POSITION_INDEPENDENT_LIB_DEFAULT})
+
+#-----------------------------------------------------------------------------
+# TARGETS - Library and executable targets
+#-----------------------------------------------------------------------------
+# liblz4
+include(GNUInstallDirs)
+set(LZ4_LIBRARIES_BUILT)
+if(BUILD_SHARED_LIBS)
+ add_library(lz4_shared SHARED ${LZ4_SOURCES})
+ target_include_directories(lz4_shared
+ PUBLIC $
+ INTERFACE $)
+ set_target_properties(lz4_shared PROPERTIES
+ OUTPUT_NAME lz4
+ SOVERSION "${LZ4_VERSION_MAJOR}"
+ VERSION "${LZ4_VERSION_STRING}")
+ if(MSVC)
+ target_compile_definitions(lz4_shared PRIVATE
+ LZ4_DLL_EXPORT=1)
+ endif(MSVC)
+ list(APPEND LZ4_LIBRARIES_BUILT lz4_shared)
+endif()
+if(BUILD_STATIC_LIBS)
+ set(STATIC_LIB_NAME lz4)
+ if(MSVC AND BUILD_SHARED_LIBS)
+ set(STATIC_LIB_NAME lz4_static)
+ endif(MSVC AND BUILD_SHARED_LIBS)
+ add_library(lz4_static STATIC ${LZ4_SOURCES})
+ target_include_directories(lz4_static
+ PUBLIC $
+ INTERFACE $)
+ set_target_properties(lz4_static PROPERTIES
+ OUTPUT_NAME ${STATIC_LIB_NAME}
+ POSITION_INDEPENDENT_CODE ${LZ4_POSITION_INDEPENDENT_LIB})
+ list(APPEND LZ4_LIBRARIES_BUILT lz4_static)
+endif()
+# Add unified target.
+add_library(lz4 INTERFACE)
+list(APPEND LZ4_LIBRARIES_BUILT lz4)
+if(BUILD_SHARED_LIBS)
+ target_link_libraries(lz4 INTERFACE lz4_shared)
+else()
+ target_link_libraries(lz4 INTERFACE lz4_static)
+endif(BUILD_SHARED_LIBS)
+
+#-----------------------------------------------------------------------------
+# DEBUG CONFIGURATION - Configurable LZ4_DEBUG level
+#-----------------------------------------------------------------------------
+# LZ4_DEBUG levels:
+# 0 - Disable everything (default for Release)
+# 1 - Enable assert() statements
+# 2-8 - Enable debug traces with increasing verbosity
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(LZ4_DEBUG_LEVEL_DEFAULT 1)
+else()
+ set(LZ4_DEBUG_LEVEL_DEFAULT 0)
+endif()
+
+set(LZ4_DEBUG_LEVEL ${LZ4_DEBUG_LEVEL_DEFAULT} CACHE STRING
+ "LZ4 debug level: 0=disabled, 1=assert(), 2-8=debug traces with increasing verbosity")
+set_property(CACHE LZ4_DEBUG_LEVEL PROPERTY STRINGS "0" "1" "2" "3" "4" "5" "6" "7" "8")
+
+# Apply LZ4_DEBUG configuration if level > 0
+if(LZ4_DEBUG_LEVEL GREATER 0)
+ if(MSVC)
+ add_definitions(/DLZ4_DEBUG=${LZ4_DEBUG_LEVEL})
+ else()
+ add_definitions(-DLZ4_DEBUG=${LZ4_DEBUG_LEVEL})
+ endif()
+endif()
+
+#-----------------------------------------------------------------------------
+# NAMESPACE CONFIGURATION - xxHash namespace settings
+#-----------------------------------------------------------------------------
+# xxhash namespace
+if(BUILD_SHARED_LIBS)
+ target_compile_definitions(lz4_shared PRIVATE
+ XXH_NAMESPACE=LZ4_)
+endif(BUILD_SHARED_LIBS)
+if(BUILD_STATIC_LIBS)
+ target_compile_definitions(lz4_static PRIVATE
+ XXH_NAMESPACE=LZ4_)
+endif(BUILD_STATIC_LIBS)
+
+#-----------------------------------------------------------------------------
+# CLI EXECUTABLES - Configuring command-line programs
+#-----------------------------------------------------------------------------
+# lz4
+if(LZ4_BUILD_CLI)
+ set(LZ4_PROGRAMS_BUILT lz4cli)
+ add_executable(lz4cli ${LZ4_CLI_SOURCES})
+ set_target_properties(lz4cli PROPERTIES OUTPUT_NAME lz4)
+endif(LZ4_BUILD_CLI)
+
+# lz4c
+if(LZ4_BUILD_LEGACY_LZ4C)
+ list(APPEND LZ4_PROGRAMS_BUILT lz4c)
+ add_executable(lz4c ${LZ4_CLI_SOURCES})
+ set_target_properties(lz4c PROPERTIES COMPILE_DEFINITIONS "ENABLE_LZ4C_LEGACY_OPTIONS")
+endif(LZ4_BUILD_LEGACY_LZ4C)
+
+#-----------------------------------------------------------------------------
+# COMPILER FLAGS - Configure warning flags and compiler-specific options
+#-----------------------------------------------------------------------------
+# Extra warning flags - apply only to LZ4 targets, not globally
+set(LZ4_WARNING_FLAGS)
+if(MSVC)
+ list(APPEND LZ4_WARNING_FLAGS "/W4")
+else()
+ include(CheckCCompilerFlag)
+ foreach(flag
+ # GCC-style
+ -pedantic-errors
+ -Wall
+ -Wextra
+ -Wundef
+ -Wcast-qual
+ -Wcast-align
+ -Wshadow
+ -Wswitch-enum
+ -Wdeclaration-after-statement
+ -Wstrict-prototypes
+ -Wpointer-arith)
+
+ # Because https://gcc.gnu.org/wiki/FAQ#wnowarning
+ string(REGEX REPLACE "\\-Wno\\-(.+)" "-W\\1" flag_to_test "${flag}")
+ string(REGEX REPLACE "[^a-zA-Z0-9]+" "_" test_name "CFLAG_${flag_to_test}")
+
+ check_c_compiler_flag("${ADD_COMPILER_FLAGS_PREPEND} ${flag_to_test}" ${test_name})
+
+ if(${test_name})
+ list(APPEND LZ4_WARNING_FLAGS "${flag}")
+ endif()
+
+ unset(test_name)
+ unset(flag_to_test)
+ endforeach(flag)
+endif(MSVC)
+
+# Apply warning flags to LZ4 targets only (not globally)
+if(BUILD_SHARED_LIBS AND LZ4_WARNING_FLAGS)
+ target_compile_options(lz4_shared PRIVATE $<$:${LZ4_WARNING_FLAGS}>)
+endif()
+if(BUILD_STATIC_LIBS AND LZ4_WARNING_FLAGS)
+ target_compile_options(lz4_static PRIVATE $<$:${LZ4_WARNING_FLAGS}>)
+endif()
+if(LZ4_BUILD_CLI AND LZ4_WARNING_FLAGS)
+ target_compile_options(lz4cli PRIVATE $<$:${LZ4_WARNING_FLAGS}>)
+endif()
+if(LZ4_BUILD_LEGACY_LZ4C AND LZ4_WARNING_FLAGS)
+ target_compile_options(lz4c PRIVATE $<$:${LZ4_WARNING_FLAGS}>)
+endif()
+
+
+#-----------------------------------------------------------------------------
+# INSTALLATION - Install targets, headers, and documentation
+#-----------------------------------------------------------------------------
+if(NOT LZ4_BUNDLED_MODE)
+ install(TARGETS ${LZ4_PROGRAMS_BUILT}
+ BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+ install(TARGETS ${LZ4_LIBRARIES_BUILT}
+ EXPORT lz4Targets
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+ install(FILES
+ "${LZ4_LIB_SOURCE_DIR}/lz4.h"
+ "${LZ4_LIB_SOURCE_DIR}/lz4hc.h"
+ "${LZ4_LIB_SOURCE_DIR}/lz4frame.h"
+ "${LZ4_LIB_SOURCE_DIR}/lz4file.h"
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
+ install(FILES "${LZ4_PROG_SOURCE_DIR}/lz4.1"
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/liblz4.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+
+#-----------------------------------------------------------------------------
+# CMAKE PACKAGE CONFIG - Configure CMake package for find_package support
+#-----------------------------------------------------------------------------
+ include(CMakePackageConfigHelpers)
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/lz4ConfigVersion.cmake"
+ VERSION ${LZ4_VERSION_STRING}
+ COMPATIBILITY SameMajorVersion)
+
+ set(LZ4_PKG_INSTALLDIR "${CMAKE_INSTALL_LIBDIR}/cmake/lz4")
+ configure_package_config_file(
+ "${CMAKE_CURRENT_LIST_DIR}/lz4Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/lz4Config.cmake"
+ INSTALL_DESTINATION ${LZ4_PKG_INSTALLDIR})
+ export(EXPORT lz4Targets
+ FILE ${CMAKE_CURRENT_BINARY_DIR}/lz4Targets.cmake
+ NAMESPACE LZ4::)
+
+ install(EXPORT lz4Targets
+ FILE lz4Targets.cmake
+ NAMESPACE LZ4::
+ DESTINATION ${LZ4_PKG_INSTALLDIR})
+ install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/lz4Config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/lz4ConfigVersion.cmake
+ DESTINATION ${LZ4_PKG_INSTALLDIR})
+
+#-----------------------------------------------------------------------------
+# SYMLINKS - Create and install Unix symlinks and manpage aliases
+#-----------------------------------------------------------------------------
+ # Install lz4cat and unlz4 symlinks on Unix systems
+ if(UNIX AND LZ4_BUILD_CLI)
+ foreach(cli_tool IN ITEMS lz4cat unlz4)
+ # Create a custom target for the symlink creation
+ add_custom_target("create_${cli_tool}_symlink" ALL
+ COMMAND ${CMAKE_COMMAND} -E create_symlink
+ $ ${cli_tool}
+ DEPENDS lz4cli
+ COMMENT "Creating symlink for ${cli_tool}"
+ VERBATIM)
+
+ # Install the symlink into the binary installation directory
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${cli_tool}"
+ DESTINATION ${CMAKE_INSTALL_BINDIR}
+ RENAME ${cli_tool})
+ endforeach()
+
+ # create manpage aliases
+ foreach(f lz4cat unlz4)
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${f}.1" ".so man1/lz4.1\n")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${f}.1"
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
+ endforeach()
+ endif(UNIX AND LZ4_BUILD_CLI)
+endif(NOT LZ4_BUNDLED_MODE)
+
+#-----------------------------------------------------------------------------
+# PKG-CONFIG - Generate and install pkg-config file
+#-----------------------------------------------------------------------------
+# pkg-config
+set(PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+if("${CMAKE_INSTALL_FULL_LIBDIR}" STREQUAL "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+ set(LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
+else()
+ set(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}")
+endif("${CMAKE_INSTALL_FULL_LIBDIR}" STREQUAL "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+
+if("${CMAKE_INSTALL_FULL_INCLUDEDIR}" STREQUAL "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
+ set(INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+else()
+ set(INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
+endif("${CMAKE_INSTALL_FULL_INCLUDEDIR}" STREQUAL "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
+
+# for liblz4.pc substitution
+set(VERSION ${LZ4_VERSION_STRING})
+configure_file(${LZ4_LIB_SOURCE_DIR}/liblz4.pc.in liblz4.pc @ONLY)
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93ae276..7a94bc9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -146,6 +146,7 @@ add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h a
include(3rdparty/bzip2.cmake)
include(3rdparty/flac.cmake)
+include(3rdparty/lz4.cmake)
include(3rdparty/lzfse.cmake)
include(3rdparty/lzip.cmake)
include(3rdparty/lzma.cmake)
@@ -169,7 +170,7 @@ macro(target_link_libraries_whole_archive target)
endif()
endmacro()
-target_link_libraries_whole_archive("Aaru.Compression.Native" libzstd_static m)
+target_link_libraries_whole_archive("Aaru.Compression.Native" libzstd_static lz4_static m)
check_include_file("semaphore.h" HAVE_SEMAPHORE_H)
diff --git a/README.md b/README.md
index 3613cbe..6f06b04 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ Currently implemented algorithms are:
- Apple RLE (Run Length Encoding created for Apple DART)
- [BZIP2](https://gitlab.com/bzip2/bzip2.git)
- [FLAC](https://github.com/xiph/flac)
+- [LZ4](https://github.com/lz4/lz4)
- [LZFSE](https://github.com/lzfse/lzfse)
- [LZIP](http://www.nongnu.org/lzip)
- [LZMA](https://www.7-zip.org)
diff --git a/library.c b/library.c
index 3a970fe..c62c9c7 100644
--- a/library.c
+++ b/library.c
@@ -21,6 +21,7 @@
#include "library.h"
#include "3rdparty/bzip2/bzlib.h"
+#include "3rdparty/lz4/lib/lz4.h"
#include "3rdparty/lzfse/src/lzfse.h"
#include "3rdparty/lzma/C/LzmaLib.h"
#include "3rdparty/zstd/lib/zstd.h"
@@ -38,6 +39,18 @@ AARU_EXPORT int32_t AARU_CALL AARU_bzip2_encode_buffer(uint8_t *dst_buffer, uint
return BZ2_bzBuffToBuffCompress((char *)dst_buffer, dst_size, (char *)src_buffer, src_size, blockSize100k, 0, 0);
}
+AARU_EXPORT int32_t AARU_CALL AARU_lz4_decode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
+ int32_t src_size)
+{
+ return LZ4_decompress_safe((const char *)src_buffer, (char *)dst_buffer, src_size, dst_size);
+}
+
+AARU_EXPORT int32_t AARU_CALL AARU_lz4_encode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
+ int32_t src_size)
+{
+ return LZ4_compress_default((const char *)src_buffer, (char *)dst_buffer, src_size, dst_size);
+}
+
AARU_EXPORT size_t AARU_CALL AARU_lzfse_decode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size, void *scratch_buffer)
{
diff --git a/library.h b/library.h
index 92cda9b..3ba6047 100644
--- a/library.h
+++ b/library.h
@@ -70,6 +70,12 @@ AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(
uint32_t min_residual_partition_order, uint32_t max_residual_partition_order, const char *application_id,
uint32_t application_id_len);
+AARU_EXPORT int32_t AARU_CALL AARU_lz4_decode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
+ int32_t src_size);
+
+AARU_EXPORT int32_t AARU_CALL AARU_lz4_encode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
+ int32_t src_size);
+
AARU_EXPORT int32_t AARU_CALL AARU_lzip_decode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
int32_t src_size);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 1ed61b8..836e6fc 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -27,6 +27,9 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/lzfse.bin
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/zstd.zst
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/lz4.bin
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
+
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/lzma.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
@@ -74,7 +77,7 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/ha_hsc.bin
# 'Google_Tests_run' is the target name
# 'test1.cpp tests2.cpp' are source files with tests
-add_executable(tests_run apple_rle.cpp crc32.c crc32.h adc.cpp bzip2.cpp lzip.cpp lzfse.cpp zstd.cpp lzma.cpp flac.cpp
+add_executable(tests_run apple_rle.cpp crc32.c crc32.h adc.cpp bzip2.cpp lzip.cpp lzfse.cpp zstd.cpp lzma.cpp flac.cpp lz4.cpp
zoo/lzd.cpp arc/pack.cpp lh5.cpp arc/squeeze.cpp arc/crunch.cpp arc/squash.cpp pak/crush.cpp
pak/distill.cpp ha.cpp)
target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native")
diff --git a/tests/data/lz4.bin b/tests/data/lz4.bin
new file mode 100644
index 0000000..75cae17
Binary files /dev/null and b/tests/data/lz4.bin differ
diff --git a/tests/lz4.cpp b/tests/lz4.cpp
new file mode 100644
index 0000000..347886f
--- /dev/null
+++ b/tests/lz4.cpp
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the Aaru Data Preservation Suite.
+ * Copyright (c) 2019-2025 Natalia Portillo.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "../library.h"
+#include "crc32.h"
+#include "gtest/gtest.h"
+
+#define EXPECTED_CRC32 0x954bf76e // CRC32 of whole 8MB data.bin file
+
+static const uint8_t *buffer;
+static int32_t buffer_size;
+
+class lz4Fixture : public ::testing::Test
+{
+public:
+ lz4Fixture()
+ {
+ // initialization;
+ // can also be done in SetUp()
+ }
+
+protected:
+ void SetUp()
+ {
+ char path[PATH_MAX];
+ char filename[PATH_MAX];
+
+ getcwd(path, PATH_MAX);
+ snprintf(filename, PATH_MAX, "%s/data/lz4.bin", path);
+
+ FILE *file = fopen(filename, "rb");
+ fseek(file, 0, SEEK_END);
+ buffer_size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ buffer = (const uint8_t *)malloc(buffer_size);
+ fread((void *)buffer, 1, buffer_size, file);
+ fclose(file);
+ }
+
+ void TearDown() { free((void *)buffer); }
+
+ ~lz4Fixture()
+ {
+ // resources cleanup, no exceptions allowed
+ }
+
+ // shared user data
+};
+
+TEST_F(lz4Fixture, lz4)
+{
+ int32_t original_len = 8388608; // 8MB
+ auto *outBuf = (uint8_t *)malloc(original_len);
+
+ auto decoded = AARU_lz4_decode_buffer(outBuf, original_len, buffer, buffer_size);
+
+ EXPECT_GT(decoded, 0);
+ EXPECT_EQ(decoded, original_len);
+
+ auto crc = crc32_data(outBuf, original_len);
+
+ free(outBuf);
+
+ EXPECT_EQ(crc, EXPECTED_CRC32);
+}
+
+TEST_F(lz4Fixture, lz4Compress)
+{
+ int32_t original_len = 8388608;
+ int32_t cmp_len = original_len;
+ int32_t decmp_len = original_len;
+ char path[PATH_MAX];
+ char filename[PATH_MAX * 2];
+ FILE *file;
+ uint32_t original_crc, decmp_crc;
+ const uint8_t *original;
+ uint8_t *cmp_buffer;
+ uint8_t *decmp_buffer;
+ int32_t newSize;
+
+ // Allocate buffers
+ original = (const uint8_t *)malloc(original_len);
+ cmp_buffer = (uint8_t *)malloc(cmp_len);
+ decmp_buffer = (uint8_t *)malloc(decmp_len);
+
+ // Read the file
+ getcwd(path, PATH_MAX);
+ snprintf(filename, PATH_MAX, "%s/data/data.bin", path);
+
+ file = fopen(filename, "rb");
+ fread((void *)original, 1, original_len, file);
+ fclose(file);
+
+ // Calculate the CRC
+ original_crc = crc32_data(original, original_len);
+
+ // Compress
+ newSize = AARU_lz4_encode_buffer(cmp_buffer, cmp_len, original, original_len);
+ EXPECT_GT(newSize, 0);
+ cmp_len = newSize;
+
+ // Decompress
+ newSize = AARU_lz4_decode_buffer(decmp_buffer, decmp_len, cmp_buffer, cmp_len);
+ EXPECT_GT(newSize, 0);
+ decmp_len = newSize;
+
+ EXPECT_EQ(decmp_len, original_len);
+
+ decmp_crc = crc32_data(decmp_buffer, decmp_len);
+
+ // Free buffers
+ free((void *)original);
+ free(cmp_buffer);
+ free(decmp_buffer);
+
+ EXPECT_EQ(decmp_crc, original_crc);
+}