diff --git a/3rdparty/flac.cmake b/3rdparty/flac.cmake new file mode 100644 index 0000000..e5bb2a7 --- /dev/null +++ b/3rdparty/flac.cmake @@ -0,0 +1,172 @@ +# 3.1 is OK for most parts. However: +# 3.3 is needed in src/libFLAC +# 3.5 is needed in src/libFLAC/ia32 +# 3.9 is needed in 'doc' because of doxygen_add_docs() +#cmake_minimum_required(VERSION 3.5) + +#if(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES OR DEFINED ENV{CFLAGS} OR DEFINED ENV{CXXFLAGS})) +# set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo") +#endif() + +set(FLAC_VERSION 1.3.3) # HOMEPAGE_URL "https://www.xiph.org/flac/") + +message(STATUS "FLAC VERSION: ${FLAC_VERSION}") +set(BUILD_SHARED_LIBS BOOL OFF) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/flac/cmake") + +set(VERSION ${FLAC_VERSION}) + +set(OLD_PROJECT_SOURCE_DIR "${PROJECT_SOURCE_DIR}") +set(PROJECT_SOURCE_DIR "${PROJECT_SOURCE_DIR}/3rdparty/flac/") + +#find_package(Iconv) +#set(HAVE_ICONV ${Iconv_FOUND}) + +#if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") +# set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -funroll-loops") +#endif() + +include(CMakePackageConfigHelpers) +include(CPack) +include(CTest) +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) +include(CheckSymbolExists) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +include(CheckCXXSourceCompiles) +include(UseSystemExtensions) +include(TestBigEndian) + +check_include_file("byteswap.h" HAVE_BYTESWAP_H) +check_include_file("inttypes.h" HAVE_INTTYPES_H) +check_include_file("stdint.h" HAVE_STDINT_H) +if(MSVC) + check_include_file("intrin.h" FLAC__HAS_X86INTRIN) +else() + check_include_file("x86intrin.h" FLAC__HAS_X86INTRIN) +endif() + +#check_function_exists(fseeko HAVE_FSEEKO) + +check_c_source_compiles("int main() { return __builtin_bswap16 (0) ; }" HAVE_BSWAP16) +check_c_source_compiles("int main() { return __builtin_bswap32 (0) ; }" HAVE_BSWAP32) + +if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW" OR (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")) + test_big_endian(CPU_IS_BIG_ENDIAN) +endif() + +check_c_compiler_flag(-mstackrealign HAVE_STACKREALIGN_FLAG) + +include_directories("3rdparty/flac/include") + +include_directories("${CMAKE_CURRENT_BINARY_DIR}/3rdparty/flac") +add_definitions(-DHAVE_CONFIG_H) + +if(MSVC) + add_definitions( + -D_CRT_SECURE_NO_WARNINGS + -D_USE_MATH_DEFINES) +endif() + +option(WITH_ASM "Use any assembly optimization routines" ON) + +check_include_file("cpuid.h" HAVE_CPUID_H) +check_include_file("sys/param.h" HAVE_SYS_PARAM_H) + +set(CMAKE_REQUIRED_LIBRARIES m) +check_function_exists(lround HAVE_LROUND) + +include(CheckCSourceCompiles) +include(CheckCPUArch) + +check_cpu_arch_x64(FLAC__CPU_X86_64) +if(NOT FLAC__CPU_X86_64) + check_cpu_arch_x86(FLAC__CPU_IA32) +endif() + +if(FLAC__CPU_X86_64 OR FLAC__CPU_IA32) + set(FLAC__ALIGN_MALLOC_DATA 1) + option(WITH_AVX "Enable AVX, AVX2 optimizations" ON) +endif() + +include(CheckLanguage) +check_language(ASM_NASM) +if(CMAKE_ASM_NASM_COMPILER) + enable_language(ASM_NASM) + add_definitions(-DFLAC__HAS_NASM) +endif() + +if(NOT WITH_ASM) + add_definitions(-DFLAC__NO_ASM) +endif() + +if(FLAC__CPU_IA32) + if(WITH_ASM AND CMAKE_ASM_NASM_COMPILER) + add_subdirectory(ia32) + endif() + + option(WITH_SSE "Enable SSE2 optimizations" ON) + check_c_compiler_flag(-msse2 HAVE_MSSE2_FLAG) + if(WITH_SSE) + add_compile_options( + $<$:-msse2> + $<$:/arch:SSE2>) + endif() +endif() + +include_directories("3rdparty/flac/src/libFLAC/include") + +target_sources(aaruformat PRIVATE + 3rdparty/flac/src/libFLAC/bitmath.c + 3rdparty/flac/src/libFLAC/bitreader.c + 3rdparty/flac/src/libFLAC/bitwriter.c + 3rdparty/flac/src/libFLAC/cpu.c + 3rdparty/flac/src/libFLAC/crc.c + 3rdparty/flac/src/libFLAC/fixed.c + 3rdparty/flac/src/libFLAC/fixed_intrin_sse2.c + 3rdparty/flac/src/libFLAC/fixed_intrin_ssse3.c + 3rdparty/flac/src/libFLAC/float.c + 3rdparty/flac/src/libFLAC/format.c + 3rdparty/flac/src/libFLAC/lpc.c + 3rdparty/flac/src/libFLAC/lpc_intrin_sse.c + 3rdparty/flac/src/libFLAC/lpc_intrin_sse2.c + 3rdparty/flac/src/libFLAC/lpc_intrin_sse41.c + 3rdparty/flac/src/libFLAC/lpc_intrin_avx2.c + 3rdparty/flac/src/libFLAC/lpc_intrin_vsx.c + 3rdparty/flac/src/libFLAC/md5.c + 3rdparty/flac/src/libFLAC/memory.c + 3rdparty/flac/src/libFLAC/metadata_iterators.c + 3rdparty/flac/src/libFLAC/metadata_object.c + 3rdparty/flac/src/libFLAC/stream_decoder.c + 3rdparty/flac/src/libFLAC/stream_encoder.c + 3rdparty/flac/src/libFLAC/stream_encoder_intrin_sse2.c + 3rdparty/flac/src/libFLAC/stream_encoder_intrin_ssse3.c + 3rdparty/flac/src/libFLAC/stream_encoder_intrin_avx2.c + 3rdparty/flac/src/libFLAC/stream_encoder_framing.c + 3rdparty/flac/src/libFLAC/window.c + $<$:3rdparty/flac/include/share/windows_unicode_filenames.h> + $<$:3rdparty/flac/src/libFLAC/windows_unicode_filenames.c> + $<$:ogg_decoder_aspect.c> + $<$:ogg_encoder_aspect.c> + $<$:ogg_helper.c> + $<$:ogg_mapping.c>) + +target_compile_definitions(aaruformat PUBLIC FLAC__NO_DLL) +target_compile_definitions(aaruformat PUBLIC FLAC__NO_FILEIO) + +# Disable fortify source when not-release or when cross-building with MingW for WoA +if(CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo OR "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW") + set(DODEFINE_FORTIFY_SOURCE 0) +endif() + +set_property(TARGET aaruformat PROPERTY C_VISIBILITY_PRESET hidden) + +if(ARCHITECTURE_IS_64BIT) + set(ENABLE_64_BIT_WORDS 1) +endif() + +configure_file(3rdparty/flac/config.cmake.h.in 3rdparty/flac/config.h) + +set(PROJECT_SOURCE_DIR "${OLD_PROJECT_SOURCE_DIR}") diff --git a/CMakeLists.txt b/CMakeLists.txt index 47fbe68..c454680 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,10 +96,12 @@ endif() add_library(aaruformat SHARED include/aaruformat/consts.h include/aaruformat/enums.h include/aaru.h include/aaruformat.h include/aaruformat/decls.h include/aaruformat/structs.h src/identify.c src/open.c include/aaruformat/context.h src/close.c include/aaruformat/errors.h src/read.c include/aaruformat/crc64.h src/cst.c src/ecc_cd.c src/helpers.c - src/simd.c include/aaruformat/simd.h src/crc64/crc64.c src/crc64/crc64_clmul.c src/crc64/crc64_vmull.c src/crc64/arm_vmull.c src/crc64/arm_vmull.h src/spamsum.c include/aaruformat/spamsum.h) + src/simd.c include/aaruformat/simd.h src/crc64/crc64.c src/crc64/crc64_clmul.c src/crc64/crc64_vmull.c src/crc64/arm_vmull.c src/crc64/arm_vmull.h src/spamsum.c include/aaruformat/spamsum.h include/aaruformat/flac.h src/flac.c) include_directories(include include/aaruformat) +include(3rdparty/flac.cmake) + MACRO(TARGET_LINK_LIBRARIES_WHOLE_ARCHIVE target) if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC") FOREACH(arg IN LISTS ARGN) diff --git a/README.md b/README.md index 9408446..4a51d1e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Things still to be implemented that are already in the C# version: - Writing - Hashing while writing (requires MD5, SHA1 and SHA256) - Deduplication (requires SHA256) -- Compression (requires FLAC and LZMA) +- Compression (requires LZMA) Things to be implemented not in the C# version: - Compile for Dreamcast (KallistiOS preferibly) diff --git a/include/aaruformat/decls.h b/include/aaruformat/decls.h index 1fa0b81..4e46fcb 100644 --- a/include/aaruformat/decls.h +++ b/include/aaruformat/decls.h @@ -142,6 +142,28 @@ AARU_LOCAL void roll_hash(spamsum_ctx* ctx, uint8_t c); AARU_LOCAL void fuzzy_try_reduce_blockhash(spamsum_ctx* ctx); AARU_LOCAL void fuzzy_try_fork_blockhash(spamsum_ctx* ctx); +AARU_EXPORT size_t AARU_CALL aaruf_flac_decode_redbook_buffer(uint8_t* dst_buffer, + size_t dst_size, + const uint8_t* src_buffer, + size_t src_size); + +AARU_EXPORT size_t AARU_CALL aaruf_flac_encode_redbook_buffer(uint8_t* dst_buffer, + size_t dst_size, + const uint8_t* src_buffer, + size_t src_size, + uint32_t blocksize, + int32_t do_mid_side_stereo, + int32_t loose_mid_side_stereo, + const char* apodization, + uint32_t max_lpc_order, + uint32_t qlp_coeff_precision, + int32_t do_qlp_coeff_prec_search, + int32_t do_exhaustive_model_search, + uint32_t min_residual_partition_order, + uint32_t max_residual_partition_order, + const char* application_id, + uint32_t application_id_len); + #if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || defined(__I386__) || \ defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86) diff --git a/include/aaruformat/flac.h b/include/aaruformat/flac.h new file mode 100644 index 0000000..8db1ddf --- /dev/null +++ b/include/aaruformat/flac.h @@ -0,0 +1,33 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 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 . + */ + +#ifndef LIBAARUFORMAT_FLAC_H +#define LIBAARUFORMAT_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; + +#endif // LIBAARUFORMAT_FLAC_H diff --git a/src/flac.c b/src/flac.c new file mode 100644 index 0000000..a41af0e --- /dev/null +++ b/src/flac.c @@ -0,0 +1,279 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 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 "../3rdparty/flac/include/FLAC/metadata.h" +#include "../3rdparty/flac/include/FLAC/stream_decoder.h" +#include "../3rdparty/flac/include/FLAC/stream_encoder.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 aaruf_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)); + 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 + 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 buffer[], + void* client_data) +{ + aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data; + size_t i; + uint16_t* buffer16 = (uint16_t*)(ctx->dst_buffer + ctx->dst_pos); + + // Why FLAC does not interleave the channels as PCM do, oh the mistery, we could use memcpy instead of looping + for(i = 0; i < frame->header.blocksize && ctx->dst_pos < ctx->dst_len; i++) + { + // Left channel + *(buffer16++) = (FLAC__int16)buffer[0][i]; + // Right channel + *(buffer16++) = (FLAC__int16)buffer[1][i]; + + ctx->dst_pos += 4; + + /* TODO: Big-endian (use bswap?) + // Left channel + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)buffer[0][i]; + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)buffer[0][i] >> 8; + // Right channel + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)buffer[1][i]; + ctx->dst_buffer[ctx->dst_pos++] = (FLAC__uint16)(FLAC__int16)buffer[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; +} + +static FLAC__StreamEncoderWriteStatus encoder_write_callback(const FLAC__StreamEncoder* encoder, + const FLAC__byte buffer[], + size_t bytes, + uint32_t samples, + uint32_t current_frame, + void* client_data); + +AARU_EXPORT size_t AARU_CALL aaruf_flac_encode_redbook_buffer(uint8_t* dst_buffer, + size_t dst_size, + const uint8_t* src_buffer, + size_t src_size, + uint32_t blocksize, + int32_t do_mid_side_stereo, + int32_t loose_mid_side_stereo, + const char* apodization, + uint32_t max_lpc_order, + uint32_t qlp_coeff_precision, + int32_t do_qlp_coeff_prec_search, + int32_t do_exhaustive_model_search, + uint32_t min_residual_partition_order, + uint32_t max_residual_partition_order, + const char* application_id, + uint32_t application_id_len) +{ + FLAC__StreamEncoder* encoder; + aaru_flac_ctx* ctx = (aaru_flac_ctx*)malloc(sizeof(aaru_flac_ctx)); + FLAC__StreamEncoderInitStatus init_status; + size_t ret_size; + FLAC__int32* pcm; + int i; + int16_t* buffer16 = (int16_t*)src_buffer; + FLAC__StreamMetadata* metadata[1]; + + 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; + + encoder = FLAC__stream_encoder_new(); + + if(!encoder) + { + free(ctx); + return -1; + } + + // TODO: Error detection here + FLAC__stream_encoder_set_verify(encoder, false); + FLAC__stream_encoder_set_streamable_subset(encoder, false); + FLAC__stream_encoder_set_channels(encoder, 2); + FLAC__stream_encoder_set_bits_per_sample(encoder, 16); + FLAC__stream_encoder_set_sample_rate(encoder, 44100); + FLAC__stream_encoder_set_blocksize(encoder, blocksize); + // true compresses more + FLAC__stream_encoder_set_do_mid_side_stereo(encoder, do_mid_side_stereo); + // false compresses more + FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, loose_mid_side_stereo); + // Apodization + FLAC__stream_encoder_set_apodization(encoder, apodization); + FLAC__stream_encoder_set_max_lpc_order(encoder, max_lpc_order); + FLAC__stream_encoder_set_qlp_coeff_precision(encoder, qlp_coeff_precision); + FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, do_qlp_coeff_prec_search); + FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, do_exhaustive_model_search); + FLAC__stream_encoder_set_min_residual_partition_order(encoder, min_residual_partition_order); + FLAC__stream_encoder_set_max_residual_partition_order(encoder, max_residual_partition_order); + FLAC__stream_encoder_set_total_samples_estimate(encoder, src_size / 4); + + /* TODO: This is ignored by FLAC, need to replace it + if((metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) != NULL) + { + memset(&vorbis_entry, 0, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); + vorbis_entry.entry = (unsigned char *)"Aaru.Compression.Native"; + vorbis_entry.length = strlen("Aaru.Compression.Native"); + + FLAC__metadata_object_vorbiscomment_set_vendor_string(metadata[0], vorbis_entry, true); + } + */ + + if(application_id_len > 0 && application_id != NULL) + if((metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)) != NULL) + FLAC__metadata_object_application_set_data( + metadata[0], (unsigned char*)application_id, application_id_len, true); + + FLAC__stream_encoder_set_metadata(encoder, metadata, 1); + + init_status = FLAC__stream_encoder_init_stream(encoder, encoder_write_callback, NULL, NULL, NULL, ctx); + + if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) + { + free(ctx); + return -1; + } + + pcm = malloc((src_size / 2) * sizeof(FLAC__int32)); + + for(i = 0; i < src_size / 2; i++) pcm[i] = (FLAC__int32) * (buffer16++); + + FLAC__stream_encoder_process_interleaved(encoder, pcm, src_size / 4); + + FLAC__stream_encoder_finish(encoder); + + FLAC__stream_encoder_delete(encoder); + + ret_size = ctx->dst_pos; + + free(ctx); + free(pcm); + FLAC__metadata_object_delete(metadata[0]); + + return ret_size; +} + +static FLAC__StreamEncoderWriteStatus encoder_write_callback(const FLAC__StreamEncoder* encoder, + const FLAC__byte buffer[], + size_t bytes, + uint32_t samples, + uint32_t current_frame, + void* client_data) +{ + aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data; + + if(bytes > ctx->dst_len - ctx->dst_pos) bytes = ctx->dst_len - ctx->dst_pos; + + memcpy(ctx->dst_buffer + ctx->dst_pos, buffer, bytes); + + ctx->dst_pos += bytes; + + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} \ No newline at end of file diff --git a/src/spamsum.c b/src/spamsum.c index 20c3412..a0c0d45 100644 --- a/src/spamsum.c +++ b/src/spamsum.c @@ -1,23 +1,23 @@ /* -* This file is part of the Aaru Data Preservation Suite. -* Copyright (c) 2019-2021 Natalia Portillo. -* Copyright (C) 2002 Andrew Tridgell -* Copyright (C) 2006 ManTech International Corporation -* Copyright (C) 2013 Helmut Grohne -* -* 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 . -*/ + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 Natalia Portillo. + * Copyright (C) 2002 Andrew Tridgell + * Copyright (C) 2006 ManTech International Corporation + * Copyright (C) 2013 Helmut Grohne + * + * 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 @@ -26,6 +26,7 @@ #include #include + #include "spamsum.h" static uint8_t b64[] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ee06af..6523ffd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,7 +8,13 @@ include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/random DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/flac.flac + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/) + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/audio.bin + 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 crc64.cpp spamsum.cpp) +add_executable(tests_run crc64.cpp spamsum.cpp crc32.c crc32.h flac.cpp) target_link_libraries(tests_run gtest gtest_main "aaruformat") diff --git a/tests/crc32.c b/tests/crc32.c new file mode 100644 index 0000000..825c822 --- /dev/null +++ b/tests/crc32.c @@ -0,0 +1,53 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 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 . + */ +#ifdef __cplusplus +extern "C" +{ +#endif +#include + +#define CRC32_ISO_POLY 0xEDB88320 +#define CRC32_ISO_SEED 0xFFFFFFFF + + uint32_t crc32_data(const uint8_t* data, uint32_t len) + { + uint32_t localHashInt = CRC32_ISO_SEED; + uint32_t localTable[256]; + int i, j; + + for(i = 0; i < 256; i++) + { + uint32_t entry = (uint32_t)i; + + for(j = 0; j < 8; j++) + if((entry & 1) == 1) entry = (entry >> 1) ^ CRC32_ISO_POLY; + else + entry >>= 1; + + localTable[i] = entry; + } + + for(i = 0; i < len; i++) localHashInt = (localHashInt >> 8) ^ localTable[data[i] ^ (localHashInt & 0xff)]; + + localHashInt ^= CRC32_ISO_SEED; + + return localHashInt; + } +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/tests/crc32.h b/tests/crc32.h new file mode 100644 index 0000000..386d5cd --- /dev/null +++ b/tests/crc32.h @@ -0,0 +1,31 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 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 . + */ + +#ifndef LIBAARUFORMAT_TESTS_CRC32_H_ +#define LIBAARUFORMAT_TESTS_CRC32_H_ +#ifdef __cplusplus +extern "C" +{ +#endif + + uint32_t crc32_data(const uint8_t* data, uint32_t len); +#ifdef __cplusplus +} +#endif + +#endif // LIBAARUFORMAT_TESTS_CRC32_H_ diff --git a/tests/data/audio.bin b/tests/data/audio.bin new file mode 100644 index 0000000..adcbfbc Binary files /dev/null and b/tests/data/audio.bin differ 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..2482397 --- /dev/null +++ b/tests/flac.cpp @@ -0,0 +1,145 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 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/aaruformat/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 = aaruf_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); +} + +TEST_F(flacFixture, flacCompress) +{ + size_t original_len = 9633792; + uint cmp_len = original_len; + uint 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; + size_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/audio.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 = aaruf_flac_encode_redbook_buffer(cmp_buffer, + cmp_len, + original, + original_len, + 4608, + 1, + 0, + "partial_tukey(0/1.0/1.0)", + 12, + 0, + 1, + false, + 0, + 8, + "Aaru.Compression.Native.Tests", + strlen("Aaru.Compression.Native.Tests")); + cmp_len = newSize; + + // Decompress + newSize = aaruf_flac_decode_redbook_buffer(decmp_buffer, decmp_len, cmp_buffer, cmp_len); + 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); +}