diff --git a/.gitmodules b/.gitmodules index df618fe..6cbcec1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "3rdparty/lzfse"] path = 3rdparty/lzfse url = https://github.com/lzfse/lzfse +[submodule "3rdparty/flac"] + path = 3rdparty/flac + url = https://github.com/xiph/flac diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 24b40fc..9256295 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -15,4 +15,15 @@ set(ZSTD_MULTITHREAD_SUPPORT OFF) # Not really sure if it works properly set(ZSTD_LEGACY_SUPPORT ON) # Unsure if may ever be needed, just in case add_subdirectory(zstd-1.5.0/build/cmake) -include(lzma.cmake) \ No newline at end of file +include(lzma.cmake) + +cmake_policy(SET CMP0077 NEW) +set(BUILD_CXXLIBS OFF) +set(BUILD_PROGRAMS OFF) +set(BUILD_EXAMPLES OFF) +set(BUILD_DOCS OFF) +set(INSTALL_MANPAGES OFF) +set(INSTALL_PKGCONFIG_MODULES OFF) +set(INSTALL_CMAKE_CONFIG_MODULE OFF) +set(WITH_OGG OFF) +add_subdirectory(flac) diff --git a/3rdparty/flac b/3rdparty/flac new file mode 160000 index 0000000..b358381 --- /dev/null +++ b/3rdparty/flac @@ -0,0 +1 @@ +Subproject commit b358381a102a2c1c153ee4cf95dfc04af62faa1a diff --git a/CMakeLists.txt b/CMakeLists.txt index 846521a..cd12172 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,8 @@ message("Detected compiler: ${CMAKE_C_COMPILER_ID}") message("Detected build type: ${CMAKE_BUILD_TYPE}") message("Detected platform: ${CMAKE_C_PLATFORM_ID}") +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + if("${CMAKE_BUILD_TYPE}" MATCHES "Release") if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC") add_compile_options("/O2" "/fp:fast") @@ -73,7 +75,7 @@ endif() add_subdirectory(3rdparty) -add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h adc.c adc.h lzip.c lzip.h) +add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h adc.c adc.h lzip.c lzip.h flac.c flac.h) MACRO(TARGET_LINK_LIBRARIES_WHOLE_ARCHIVE target) if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC") @@ -94,6 +96,6 @@ MACRO(TARGET_LINK_LIBRARIES_WHOLE_ARCHIVE target) ENDIF() ENDMACRO() -TARGET_LINK_LIBRARIES_WHOLE_ARCHIVE("Aaru.Compression.Native" bz2_static lzlib lzfse libzstd_static lzma) +TARGET_LINK_LIBRARIES_WHOLE_ARCHIVE("Aaru.Compression.Native" bz2_static lzlib lzfse libzstd_static lzma FLAC) add_subdirectory(tests) diff --git a/flac.c b/flac.c new file mode 100644 index 0000000..60e2ad3 --- /dev/null +++ b/flac.c @@ -0,0 +1,117 @@ +// +// Created by claunia on 20/10/21. +// + +#include +#include +#include + +#include "library.h" +#include "FLAC/stream_decoder.h" +#include "flac.h" + +static FLAC__StreamDecoderReadStatus + read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data); +static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, + const FLAC__Frame* frame, + const FLAC__int32* const buffer[], + void* client_data); +static void + error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data); + +AARU_EXPORT size_t AARU_CALL flac_decode_redbook_buffer(uint8_t* dst_buffer, + size_t dst_size, + const uint8_t* src_buffer, + size_t src_size) +{ + FLAC__StreamDecoder* decoder; + FLAC__StreamDecoderInitStatus init_status; + aaru_flac_ctx* ctx = (aaru_flac_ctx*)malloc(sizeof(aaru_flac_ctx)); + FLAC__bool ok = true; + size_t ret_size; + + memset(ctx, 0, sizeof(aaru_flac_ctx)); + + ctx->src_buffer = src_buffer; + ctx->src_len = src_size; + ctx->src_pos = 0; + ctx->dst_buffer = dst_buffer; + ctx->dst_len = dst_size; + ctx->dst_pos = 0; + ctx->error = 0; + + decoder = FLAC__stream_decoder_new(); + + if(!decoder) + { + free(ctx); + return -1; + } + + FLAC__stream_decoder_set_md5_checking(decoder, false); + + init_status = FLAC__stream_decoder_init_stream( + decoder, read_callback, NULL, NULL, NULL, NULL, write_callback, NULL, error_callback, ctx); + + if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + { + free(ctx); + return -1; + } + + // TODO: Return error somehow + ok = FLAC__stream_decoder_process_until_end_of_stream(decoder); + + FLAC__stream_decoder_delete(decoder); + + ret_size = ctx->dst_pos; + + free(ctx); + + return ret_size; +} + +static FLAC__StreamDecoderReadStatus + read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data) +{ + aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data; + + if(ctx->src_len - ctx->src_pos < *bytes) *bytes = ctx->src_len - ctx->src_pos; + + if(*bytes == 0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + + memcpy(buffer, ctx->src_buffer + ctx->src_pos, *bytes); + ctx->src_pos += *bytes; + + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} + +static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, + const FLAC__Frame* frame, + const FLAC__int32* const bufffer[], + void* client_data) +{ + aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data; + size_t i; + + for(i = 0; i < frame->header.blocksize && ctx->dst_pos < ctx->dst_len; i++) + { + // Left channel + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)bufffer[0][i]; + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)bufffer[0][i] >> 8; + // Right channel + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)bufffer[1][i]; + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)bufffer[1][i] >> 8; + } + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +static void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data) +{ + aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data; + + fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]); + + ctx->error = 1; +} diff --git a/flac.h b/flac.h new file mode 100644 index 0000000..e3740bf --- /dev/null +++ b/flac.h @@ -0,0 +1,24 @@ +// +// Created by claunia on 20/10/21. +// + +#ifndef AARU_COMPRESSION_NATIVE__FLAC_H_ +#define AARU_COMPRESSION_NATIVE__FLAC_H_ + +typedef struct +{ + const uint8_t* src_buffer; + size_t src_len; + size_t src_pos; + uint8_t* dst_buffer; + size_t dst_len; + size_t dst_pos; + uint8_t error; +} aaru_flac_ctx; + +AARU_EXPORT size_t AARU_CALL flac_decode_redbook_buffer(uint8_t* dst_buffer, + size_t dst_size, + const uint8_t* src_buffer, + size_t src_size); + +#endif // AARU_COMPRESSION_NATIVE__FLAC_H_ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f6a9ba0..74a41e4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,7 +30,10 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/zstd.zst file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/lzma.bin DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/flac.flac + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/) + # '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) +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) target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native") diff --git a/tests/data/flac.flac b/tests/data/flac.flac new file mode 100644 index 0000000..11a00aa Binary files /dev/null and b/tests/data/flac.flac differ diff --git a/tests/flac.cpp b/tests/flac.cpp new file mode 100644 index 0000000..9c87392 --- /dev/null +++ b/tests/flac.cpp @@ -0,0 +1,79 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2021 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 "../library.h" +#include "../flac.h" +#include "crc32.h" +#include "gtest/gtest.h" + +#define EXPECTED_CRC32 0xdfbc99bb + +static const uint8_t* buffer; + +class flacFixture : public ::testing::Test +{ + public: + flacFixture() + { + // 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/flac.flac", path); + + FILE* file = fopen(filename, "rb"); + buffer = (const uint8_t*)malloc(6534197); + fread((void*)buffer, 1, 6534197, file); + fclose(file); + } + + void TearDown() { free((void*)buffer); } + + ~flacFixture() + { + // resources cleanup, no exceptions allowed + } + + // shared user data +}; + +TEST_F(flacFixture, flac) +{ + auto* outBuf = (uint8_t*)malloc(9633792); + + auto decoded = flac_decode_redbook_buffer(outBuf, 9633792, buffer, 6534197); + + EXPECT_EQ(decoded, 9633792); + + auto crc = crc32_data(outBuf, 9633792); + + free(outBuf); + + EXPECT_EQ(crc, EXPECTED_CRC32); +} \ No newline at end of file