mirror of
https://github.com/aaru-dps/Aaru.Compression.Native.git
synced 2026-07-08 18:06:12 +00:00
Add CompactPro compression algorithms.
This commit is contained in:
@@ -236,7 +236,9 @@ add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h a
|
||||
ppmd/SubAllocatorVariantH.c
|
||||
ppmd/SubAllocatorVariantH.h
|
||||
ppmd/VariantH.c
|
||||
ppmd/VariantH.h)
|
||||
ppmd/VariantH.h
|
||||
cpt/cpt.c
|
||||
cpt/cpt.h)
|
||||
|
||||
include(3rdparty/bzip2.cmake)
|
||||
include(3rdparty/flac.cmake)
|
||||
|
||||
370
cpt/cpt.c
Normal file
370
cpt/cpt.c
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* cpt.c - Compact Pro archive decompression
|
||||
*
|
||||
* This file is part of the Aaru Data Preservation Suite.
|
||||
* Copyright (c) 2019-2026 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../pak/bitstream.h"
|
||||
#include "../pak/prefixcode.h"
|
||||
|
||||
/* ============ Constants ============ */
|
||||
|
||||
#define CPT_WINDOW_SIZE 8192
|
||||
#define CPT_BLOCK_SIZE 0x1fff0
|
||||
#define CPT_RLE_ESCAPE 0x81
|
||||
#define CPT_LITERAL_SYMS 256
|
||||
#define CPT_LENGTH_SYMS 64
|
||||
#define CPT_OFFSET_SYMS 128
|
||||
#define CPT_MAX_CODELEN 15
|
||||
#define CPT_OFFSET_LOW 6
|
||||
|
||||
/* ============ Bitstream helpers ============ */
|
||||
|
||||
/** Discard remaining bits in the current byte to align to a byte boundary. */
|
||||
static void bs_align_to_byte(BitStream *bs)
|
||||
{
|
||||
int remainder = bs->bitcount & 7;
|
||||
|
||||
if(remainder > 0)
|
||||
{
|
||||
bs->bitbuffer <<= remainder;
|
||||
bs->bitcount -= remainder;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the logical byte offset of consumed data (bytes read from source). */
|
||||
static size_t bs_byte_offset(const BitStream *bs) { return bs->pos - (size_t)((bs->bitcount + 7) / 8); }
|
||||
|
||||
/** Skip n bytes through the bit buffer (must be at a byte boundary). */
|
||||
static void bs_skip_bytes(BitStream *bs, int n)
|
||||
{
|
||||
for(int i = 0; i < n; i++) bitstream_read_bits(bs, 8);
|
||||
}
|
||||
|
||||
/* ============ Huffman table reading ============ */
|
||||
|
||||
/**
|
||||
* Read a canonical Huffman code table from the bitstream.
|
||||
*
|
||||
* Format: one byte giving the number of packed byte pairs, then that many
|
||||
* bytes each containing two 4-bit code lengths (high nibble first).
|
||||
* Maximum code length is 15. Uses shortest-code-is-zeros convention.
|
||||
*
|
||||
* @param bs Bitstream positioned at the start of the code table.
|
||||
* @param size Number of symbols in the code alphabet.
|
||||
* @return Allocated PrefixCode on success, NULL on error.
|
||||
*/
|
||||
static PrefixCode *cpt_read_code_table(BitStream *bs, int size)
|
||||
{
|
||||
int numbytes = (int)bitstream_read_bits(bs, 8);
|
||||
|
||||
if(numbytes * 2 > size) return NULL;
|
||||
|
||||
int *lengths = (int *)calloc((size_t)size, sizeof(int));
|
||||
|
||||
if(!lengths) return NULL;
|
||||
|
||||
for(int i = 0; i < numbytes; i++)
|
||||
{
|
||||
int val = (int)bitstream_read_bits(bs, 8);
|
||||
lengths[2 * i] = val >> 4;
|
||||
lengths[2 * i + 1] = val & 0x0f;
|
||||
}
|
||||
|
||||
/* Remaining symbols have length 0 (no code assigned). */
|
||||
PrefixCode *code = prefix_code_alloc_with_lengths(lengths, size, CPT_MAX_CODELEN, true);
|
||||
free(lengths);
|
||||
return code;
|
||||
}
|
||||
|
||||
/* ============ LZH decoder ============ */
|
||||
|
||||
/**
|
||||
* Decompress LZH-encoded data (block-based Huffman LZSS, 8 KB window).
|
||||
*
|
||||
* The output is the intermediate RLE-encoded stream that must be further
|
||||
* processed by the RLE decoder to produce the final data.
|
||||
*
|
||||
* @param dst Output buffer.
|
||||
* @param dst_cap Capacity of output buffer.
|
||||
* @param src Input compressed data.
|
||||
* @param src_size Size of input data.
|
||||
* @param out_len Receives the number of bytes actually written.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
static int cpt_lzh_decode(uint8_t *dst, size_t dst_cap, const uint8_t *src, size_t src_size, size_t *out_len)
|
||||
{
|
||||
BitStream bs;
|
||||
bitstream_init(&bs, src, src_size);
|
||||
|
||||
uint8_t window[CPT_WINDOW_SIZE];
|
||||
memset(window, 0, sizeof(window));
|
||||
size_t win_pos = 0;
|
||||
|
||||
size_t out_pos = 0;
|
||||
int block_cost = CPT_BLOCK_SIZE; /* Force first block read immediately. */
|
||||
size_t block_start = 0;
|
||||
|
||||
PrefixCode *literal_code = NULL;
|
||||
PrefixCode *length_code = NULL;
|
||||
PrefixCode *offset_code = NULL;
|
||||
|
||||
while(!bitstream_eof(&bs))
|
||||
{
|
||||
/* New block required? */
|
||||
if(block_cost >= CPT_BLOCK_SIZE)
|
||||
{
|
||||
if(block_start)
|
||||
{
|
||||
/* Inter-block alignment padding:
|
||||
* Align to byte boundary, then skip 2 or 3 bytes depending on
|
||||
* whether the consumed byte count since block_start is odd or even. */
|
||||
bs_align_to_byte(&bs);
|
||||
|
||||
size_t consumed = bs_byte_offset(&bs) - block_start;
|
||||
|
||||
if(consumed & 1)
|
||||
bs_skip_bytes(&bs, 3);
|
||||
else
|
||||
bs_skip_bytes(&bs, 2);
|
||||
}
|
||||
|
||||
/* Free previous tables. */
|
||||
prefix_code_free(literal_code);
|
||||
prefix_code_free(length_code);
|
||||
prefix_code_free(offset_code);
|
||||
literal_code = length_code = offset_code = NULL;
|
||||
|
||||
/* Read three Huffman code tables for this block. */
|
||||
literal_code = cpt_read_code_table(&bs, CPT_LITERAL_SYMS);
|
||||
length_code = cpt_read_code_table(&bs, CPT_LENGTH_SYMS);
|
||||
offset_code = cpt_read_code_table(&bs, CPT_OFFSET_SYMS);
|
||||
|
||||
if(!literal_code || !length_code || !offset_code) goto fail;
|
||||
|
||||
block_cost = 0;
|
||||
block_start = bs_byte_offset(&bs);
|
||||
}
|
||||
|
||||
if(bitstream_eof(&bs)) break;
|
||||
|
||||
/* Read next symbol: bit=1 means literal, bit=0 means match. */
|
||||
uint32_t flag = bitstream_read_bit(&bs);
|
||||
|
||||
if(flag)
|
||||
{
|
||||
/* Literal byte. */
|
||||
int sym = prefix_code_read_symbol(&bs, literal_code);
|
||||
|
||||
if(sym < 0) goto fail;
|
||||
if(out_pos >= dst_cap) goto fail;
|
||||
|
||||
uint8_t byte = (uint8_t)sym;
|
||||
dst[out_pos++] = byte;
|
||||
window[win_pos] = byte;
|
||||
win_pos = (win_pos + 1) & (CPT_WINDOW_SIZE - 1);
|
||||
block_cost += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* LZSS match. */
|
||||
int match_len = prefix_code_read_symbol(&bs, length_code);
|
||||
|
||||
if(match_len < 0) goto fail;
|
||||
|
||||
int offset_high = prefix_code_read_symbol(&bs, offset_code);
|
||||
|
||||
if(offset_high < 0) goto fail;
|
||||
|
||||
int offset = (offset_high << CPT_OFFSET_LOW) | (int)bitstream_read_bits(&bs, CPT_OFFSET_LOW);
|
||||
|
||||
/* Copy from window. */
|
||||
size_t copy_pos = (win_pos - offset) & (CPT_WINDOW_SIZE - 1);
|
||||
|
||||
for(int i = 0; i < match_len; i++)
|
||||
{
|
||||
if(out_pos >= dst_cap) goto fail;
|
||||
|
||||
uint8_t byte = window[copy_pos];
|
||||
dst[out_pos++] = byte;
|
||||
window[win_pos] = byte;
|
||||
win_pos = (win_pos + 1) & (CPT_WINDOW_SIZE - 1);
|
||||
copy_pos = (copy_pos + 1) & (CPT_WINDOW_SIZE - 1);
|
||||
}
|
||||
|
||||
block_cost += 3;
|
||||
}
|
||||
}
|
||||
|
||||
*out_len = out_pos;
|
||||
|
||||
prefix_code_free(literal_code);
|
||||
prefix_code_free(length_code);
|
||||
prefix_code_free(offset_code);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
prefix_code_free(literal_code);
|
||||
prefix_code_free(length_code);
|
||||
prefix_code_free(offset_code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ============ RLE decoder ============ */
|
||||
|
||||
int cpt_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t src_size)
|
||||
{
|
||||
if(!dst_buffer || !dst_size || !src_buffer) return -1;
|
||||
|
||||
size_t dst_cap = *dst_size;
|
||||
size_t out_pos = 0;
|
||||
size_t in_pos = 0;
|
||||
|
||||
uint8_t saved = 0;
|
||||
int repeat = 0;
|
||||
int halfescaped = 0;
|
||||
|
||||
while(out_pos < dst_cap)
|
||||
{
|
||||
/* Emit pending repeats first. */
|
||||
if(repeat > 0)
|
||||
{
|
||||
repeat--;
|
||||
if(out_pos >= dst_cap) break;
|
||||
|
||||
dst_buffer[out_pos++] = saved;
|
||||
continue;
|
||||
}
|
||||
|
||||
int byte;
|
||||
|
||||
if(halfescaped)
|
||||
{
|
||||
byte = CPT_RLE_ESCAPE;
|
||||
halfescaped = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(in_pos >= src_size) break;
|
||||
|
||||
byte = src_buffer[in_pos++];
|
||||
}
|
||||
|
||||
if(byte == CPT_RLE_ESCAPE)
|
||||
{
|
||||
if(in_pos >= src_size) break;
|
||||
|
||||
byte = src_buffer[in_pos++];
|
||||
|
||||
if(byte == 0x82)
|
||||
{
|
||||
if(in_pos >= src_size) break;
|
||||
|
||||
byte = src_buffer[in_pos++];
|
||||
|
||||
if(byte != 0)
|
||||
{
|
||||
/* Repeat previous byte: byte-2 additional copies. */
|
||||
repeat = byte - 2;
|
||||
|
||||
if(out_pos >= dst_cap) break;
|
||||
|
||||
dst_buffer[out_pos++] = saved;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Literal 0x81 0x82 sequence. */
|
||||
repeat = 1;
|
||||
saved = 0x82;
|
||||
|
||||
if(out_pos >= dst_cap) break;
|
||||
|
||||
dst_buffer[out_pos++] = CPT_RLE_ESCAPE;
|
||||
}
|
||||
}
|
||||
else if(byte == CPT_RLE_ESCAPE)
|
||||
{
|
||||
/* Escaped 0x81: output 0x81 and set half-escaped state. */
|
||||
halfescaped = 1;
|
||||
saved = CPT_RLE_ESCAPE;
|
||||
|
||||
if(out_pos >= dst_cap) break;
|
||||
|
||||
dst_buffer[out_pos++] = saved;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Literal 0x81 followed by this byte. */
|
||||
repeat = 1;
|
||||
saved = (uint8_t)byte;
|
||||
|
||||
if(out_pos >= dst_cap) break;
|
||||
|
||||
dst_buffer[out_pos++] = CPT_RLE_ESCAPE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
saved = (uint8_t)byte;
|
||||
|
||||
if(out_pos >= dst_cap) break;
|
||||
|
||||
dst_buffer[out_pos++] = saved;
|
||||
}
|
||||
}
|
||||
|
||||
*dst_size = out_pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============ Combined LZH + RLE decoder ============ */
|
||||
|
||||
int cpt_lzh_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t src_size)
|
||||
{
|
||||
if(!dst_buffer || !dst_size || !src_buffer) return -1;
|
||||
|
||||
size_t final_size = *dst_size;
|
||||
|
||||
/* Intermediate buffer for LZH output (RLE-encoded data).
|
||||
* The RLE encoding can at most double the data size (every 0x81 byte in
|
||||
* the original needs escaping), so 2 × final_size is a safe upper bound. */
|
||||
size_t intermediate_cap = final_size * 2 + 4096;
|
||||
uint8_t *intermediate = (uint8_t *)malloc(intermediate_cap);
|
||||
|
||||
if(!intermediate) return -1;
|
||||
|
||||
size_t intermediate_len = 0;
|
||||
int ret = cpt_lzh_decode(intermediate, intermediate_cap, src_buffer, src_size, &intermediate_len);
|
||||
|
||||
if(ret != 0)
|
||||
{
|
||||
free(intermediate);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now RLE-decode the intermediate data to produce the final output. */
|
||||
*dst_size = final_size;
|
||||
ret = cpt_rle_decode_buffer(dst_buffer, dst_size, intermediate, intermediate_len);
|
||||
|
||||
free(intermediate);
|
||||
return ret;
|
||||
}
|
||||
54
cpt/cpt.h
Normal file
54
cpt/cpt.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* cpt.h - Compact Pro archive decompression
|
||||
*
|
||||
* This file is part of the Aaru Data Preservation Suite.
|
||||
* Copyright (c) 2019-2026 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AARU_CPT_H
|
||||
#define AARU_CPT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Decompress Compact Pro RLE-encoded data.
|
||||
*
|
||||
* All Compact Pro entries use RLE encoding with escape byte 0x81.
|
||||
*
|
||||
* @param dst_buffer Output buffer for decompressed data.
|
||||
* @param dst_size On input, size of dst_buffer. On output, actual bytes written.
|
||||
* @param src_buffer Input RLE-encoded data.
|
||||
* @param src_size Size of input data.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int cpt_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t src_size);
|
||||
|
||||
/**
|
||||
* Decompress Compact Pro LZH+RLE-encoded data.
|
||||
*
|
||||
* LZH-compressed entries use block-based canonical Huffman coding with an
|
||||
* 8192-byte LZSS sliding window, followed by RLE decoding.
|
||||
*
|
||||
* @param dst_buffer Output buffer for decompressed data.
|
||||
* @param dst_size On input, size of dst_buffer. On output, actual bytes written.
|
||||
* @param src_buffer Input LZH+RLE compressed data.
|
||||
* @param src_size Size of input data.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int cpt_lzh_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t src_size);
|
||||
|
||||
#endif /* AARU_CPT_H */
|
||||
11
library.c
11
library.c
@@ -48,6 +48,7 @@
|
||||
#include "3rdparty/lzo-2.10/include/lzo/lzodefs.h"
|
||||
#include "3rdparty/zstd/lib/zstd.h"
|
||||
#include "ace/ace.h"
|
||||
#include "cpt/cpt.h"
|
||||
#include "zip/zip.h"
|
||||
|
||||
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_decode_buffer(uint8_t *dst_buffer, uint32_t *dst_size,
|
||||
@@ -555,4 +556,14 @@ AARU_EXPORT int AARU_CALL AARU_zip_winzipjpeg_decode_buffer(uint8_t *dst_buffer,
|
||||
const uint8_t *src_buffer, size_t src_size)
|
||||
{ return zip_winzipjpeg_decompress(dst_buffer, dst_size, src_buffer, src_size); }
|
||||
|
||||
/* ============== Compact Pro Wrappers ============== */
|
||||
|
||||
AARU_EXPORT int AARU_CALL AARU_cpt_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
|
||||
size_t src_size)
|
||||
{ return cpt_rle_decode_buffer(dst_buffer, dst_size, src_buffer, src_size); }
|
||||
|
||||
AARU_EXPORT int AARU_CALL AARU_cpt_lzh_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size,
|
||||
const uint8_t *src_buffer, size_t src_size)
|
||||
{ return cpt_lzh_rle_decode_buffer(dst_buffer, dst_size, src_buffer, src_size); }
|
||||
|
||||
AARU_EXPORT uint64_t AARU_CALL AARU_get_acn_version() { return AARU_CHECKUMS_NATIVE_VERSION; }
|
||||
@@ -332,4 +332,12 @@ AARU_EXPORT int AARU_CALL rar30_decompress(const uint8_t *in_buf, size_t in_len,
|
||||
AARU_EXPORT int AARU_CALL rar50_decompress(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len,
|
||||
size_t window_size);
|
||||
|
||||
// Compact Pro: RLE decompression (always applied)
|
||||
AARU_EXPORT int AARU_CALL AARU_cpt_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
|
||||
size_t src_size);
|
||||
|
||||
// Compact Pro: LZH + RLE decompression (block Huffman LZSS + RLE)
|
||||
AARU_EXPORT int AARU_CALL AARU_cpt_lzh_rle_decode_buffer(uint8_t *dst_buffer, size_t *dst_size,
|
||||
const uint8_t *src_buffer, size_t src_size);
|
||||
|
||||
#endif // AARU_COMPRESSION_NATIVE_LIBRARY_H
|
||||
|
||||
@@ -147,6 +147,12 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/rar50_m4.bin
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/rar50_m5.bin
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/cpt_rle.bin
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/cpt_lzh_rle.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 adc.cpp bzip2.cpp lzip.cpp lzfse.cpp zstd.cpp lzma.cpp flac.cpp lz4.cpp
|
||||
@@ -157,5 +163,6 @@ add_executable(tests_run apple_rle.cpp crc32.c crc32.h adc.cpp bzip2.cpp lzip.cp
|
||||
arj/arj.cpp
|
||||
arjz/arjz.cpp
|
||||
zip/zip.cpp
|
||||
rar/rar.cpp)
|
||||
rar/rar.cpp
|
||||
cpt/cpt.cpp)
|
||||
target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native")
|
||||
|
||||
109
tests/cpt/cpt.cpp
Normal file
109
tests/cpt/cpt.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This file is part of the Aaru Data Preservation Suite.
|
||||
* Copyright (c) 2019-2026 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../../library.h"
|
||||
#include "../crc32.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#define EXPECTED_CRC32 0x66007DBA
|
||||
#define EXPECTED_ORIGSIZE 152089
|
||||
|
||||
/* ---- RLE only (STORE.CPT data fork) ---- */
|
||||
|
||||
#define RLE_COMPRESSED_SIZE 150125
|
||||
|
||||
static const uint8_t *rle_buffer;
|
||||
|
||||
class CptRleFixture : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp()
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char filename[PATH_MAX];
|
||||
getcwd(path, PATH_MAX);
|
||||
snprintf(filename, PATH_MAX, "%s/data/cpt_rle.bin", path);
|
||||
FILE *file = fopen(filename, "rb");
|
||||
rle_buffer = (const uint8_t *)malloc(RLE_COMPRESSED_SIZE);
|
||||
fread((void *)rle_buffer, 1, RLE_COMPRESSED_SIZE, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void TearDown() { free((void *)rle_buffer); }
|
||||
};
|
||||
|
||||
TEST_F(CptRleFixture, cpt_rle)
|
||||
{
|
||||
size_t destLen = EXPECTED_ORIGSIZE;
|
||||
auto *outBuf = (uint8_t *)malloc(EXPECTED_ORIGSIZE);
|
||||
|
||||
auto err = AARU_cpt_rle_decode_buffer(outBuf, &destLen, rle_buffer, RLE_COMPRESSED_SIZE);
|
||||
|
||||
EXPECT_EQ(err, 0);
|
||||
EXPECT_EQ(destLen, (size_t)EXPECTED_ORIGSIZE);
|
||||
|
||||
auto crc = crc32_data(outBuf, EXPECTED_ORIGSIZE);
|
||||
free(outBuf);
|
||||
EXPECT_EQ(crc, EXPECTED_CRC32);
|
||||
}
|
||||
|
||||
/* ---- LZH + RLE (DEFAULTS.CPT data fork) ---- */
|
||||
|
||||
#define LZH_RLE_COMPRESSED_SIZE 61101
|
||||
|
||||
static const uint8_t *lzh_rle_buffer;
|
||||
|
||||
class CptLzhRleFixture : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp()
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char filename[PATH_MAX];
|
||||
getcwd(path, PATH_MAX);
|
||||
snprintf(filename, PATH_MAX, "%s/data/cpt_lzh_rle.bin", path);
|
||||
FILE *file = fopen(filename, "rb");
|
||||
lzh_rle_buffer = (const uint8_t *)malloc(LZH_RLE_COMPRESSED_SIZE);
|
||||
fread((void *)lzh_rle_buffer, 1, LZH_RLE_COMPRESSED_SIZE, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void TearDown() { free((void *)lzh_rle_buffer); }
|
||||
};
|
||||
|
||||
TEST_F(CptLzhRleFixture, cpt_lzh_rle)
|
||||
{
|
||||
size_t destLen = EXPECTED_ORIGSIZE;
|
||||
auto *outBuf = (uint8_t *)malloc(EXPECTED_ORIGSIZE);
|
||||
|
||||
auto err = AARU_cpt_lzh_rle_decode_buffer(outBuf, &destLen, lzh_rle_buffer, LZH_RLE_COMPRESSED_SIZE);
|
||||
|
||||
EXPECT_EQ(err, 0);
|
||||
EXPECT_EQ(destLen, (size_t)EXPECTED_ORIGSIZE);
|
||||
|
||||
auto crc = crc32_data(outBuf, EXPECTED_ORIGSIZE);
|
||||
free(outBuf);
|
||||
EXPECT_EQ(crc, EXPECTED_CRC32);
|
||||
}
|
||||
BIN
tests/data/cpt_lzh_rle.bin
Normal file
BIN
tests/data/cpt_lzh_rle.bin
Normal file
Binary file not shown.
3628
tests/data/cpt_rle.bin
Normal file
3628
tests/data/cpt_rle.bin
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user