diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aebc71..faea6c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,6 @@ if("${CMAKE_BUILD_TYPE}" MATCHES "Release") endif() endif() -add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h) +add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h adc.c adc.h) add_subdirectory(tests) diff --git a/adc.c b/adc.c new file mode 100644 index 0000000..a673c15 --- /dev/null +++ b/adc.c @@ -0,0 +1,125 @@ +// +// Created by claunia on 17/10/21. +// + +#include +#include + +#include "library.h" +#include "adc.h" + +FORCE_INLINE int GetChunkType(uint8_t byt) +{ + if(byt & 0x80) return ADC_PLAIN; + if(byt & 0x40) return ADC_THREE_BYTE; + return ADC_TWO_BYTE; +} + +FORCE_INLINE int GetChunkSize(uint8_t byt) +{ + switch(GetChunkType(byt)) + { + case ADC_PLAIN: return (byt & 0x7F) + 1; + case ADC_TWO_BYTE: return ((byt & 0x3F) >> 2) + 3; + case ADC_THREE_BYTE: return (byt & 0x3F) + 4; + default: return -1; + } +} + +FORCE_INLINE int GetOffset(uint8_t chunk[]) +{ + switch(GetChunkType(chunk[0])) + { + case ADC_PLAIN: return 0; + case ADC_TWO_BYTE: return ((chunk[0] & 0x03) << 8) + chunk[1]; + case ADC_THREE_BYTE: return (chunk[1] << 8) + chunk[2]; + default: return -1; + } +} + +AARU_EXPORT int32_t AARU_CALL adc_decode_buffer(uint8_t* dst_buffer, + int32_t dst_size, + const uint8_t* src_buffer, + int32_t src_size) +{ + int inputPosition = 0; + int chunkSize; + int offset; + int chunkType; + int outPosition = 0; + uint8_t temp[3]; + uint8_t readByte; + uint8_t lastByte; + int i; + + while(inputPosition < src_size) + { + readByte = src_buffer[inputPosition++]; + + chunkType = GetChunkType(readByte); + + switch(chunkType) + { + case ADC_PLAIN: + chunkSize = GetChunkSize(readByte); + if(outPosition + chunkSize > dst_size) goto finished; + memcpy(dst_buffer + outPosition, src_buffer + inputPosition, chunkSize); + outPosition += chunkSize; + inputPosition += chunkSize; + break; + case ADC_TWO_BYTE: + chunkSize = GetChunkSize(readByte); + temp[0] = readByte; + temp[1] = src_buffer[inputPosition++]; + offset = GetOffset(temp); + if(outPosition + chunkSize > dst_size) goto finished; + if(offset == 0) + { + lastByte = dst_buffer[outPosition - 1]; + for(i = 0; i < chunkSize; i++) + { + dst_buffer[outPosition] = lastByte; + outPosition++; + } + } + else + { + for(i = 0; i < chunkSize; i++) + { + dst_buffer[outPosition] = dst_buffer[outPosition - offset - 1]; + outPosition++; + } + } + break; + case ADC_THREE_BYTE: + chunkSize = GetChunkSize(readByte); + temp[0] = readByte; + temp[1] = src_buffer[inputPosition++]; + temp[2] = src_buffer[inputPosition++]; + offset = GetOffset(temp); + + if(outPosition + chunkSize > dst_size) goto finished; + if(offset == 0) + { + lastByte = dst_buffer[outPosition - 1]; + for(i = 0; i < chunkSize; i++) + { + dst_buffer[outPosition] = lastByte; + outPosition++; + } + } + else + { + for(i = 0; i < chunkSize; i++) + { + dst_buffer[outPosition] = dst_buffer[outPosition - offset - 1]; + outPosition++; + } + } + break; + } + } + +finished: + return outPosition; +} \ No newline at end of file diff --git a/adc.h b/adc.h new file mode 100644 index 0000000..ef1e632 --- /dev/null +++ b/adc.h @@ -0,0 +1,17 @@ +// +// Created by claunia on 17/10/21. +// + +#ifndef AARU_COMPRESSION_NATIVE__ADC_H_ +#define AARU_COMPRESSION_NATIVE__ADC_H_ + +#define ADC_PLAIN 1 +#define ADC_TWO_BYTE 2 +#define ADC_THREE_BYTE 3 + +AARU_EXPORT int32_t AARU_CALL adc_decode_buffer(uint8_t* dst_buffer, + int32_t dst_size, + const uint8_t* src_buffer, + int32_t src_size); + +#endif // AARU_COMPRESSION_NATIVE__ADC_H_ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 324d45d..5f41b5a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,7 +12,10 @@ include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/apple_rle.bin DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/adc.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 apple_rle.cpp crc32.c crc32.h) +add_executable(tests_run apple_rle.cpp crc32.c crc32.h adc.cpp) target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native") diff --git a/tests/adc.cpp b/tests/adc.cpp new file mode 100644 index 0000000..d6c0e4c --- /dev/null +++ b/tests/adc.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 "../adc.h" +#include "crc32.h" +#include "gtest/gtest.h" + +#define EXPECTED_CRC32 0x5a5a7388 + +static const uint8_t* buffer; + +class adcFixture : public ::testing::Test +{ + public: + adcFixture() + { + // 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/adc.bin", path); + + FILE* file = fopen(filename, "rb"); + buffer = (const uint8_t*)malloc(34367); + fread((void*)buffer, 1, 34367, file); + fclose(file); + } + + void TearDown() { free((void*)buffer); } + + ~adcFixture() + { + // resources cleanup, no exceptions allowed + } + + // shared user data +}; + +TEST_F(adcFixture, adc) +{ + auto* outBuf = (uint8_t*)malloc(327680); + + auto decoded = adc_decode_buffer(outBuf, 327680, buffer, 34367); + + EXPECT_EQ(decoded, 262144); + + auto crc = crc32_data(outBuf, 262144); + + free(outBuf); + + EXPECT_EQ(crc, EXPECTED_CRC32); +} diff --git a/tests/data/adc.bin b/tests/data/adc.bin new file mode 100644 index 0000000..c9074a2 Binary files /dev/null and b/tests/data/adc.bin differ