Add ACE decompression support for v1 and v2 formats

- Implemented ace_decompress_v2 and ace_decompress_v20_block functions for handling ACE v2 (blocked) decompression.
- Added ace_decompress_lz77 function for ACE v1 (LZ77) decompression.
- Updated library.h to declare new decompression functions.
- Created unit tests for ACE v1 and v2 decompression, validating output against expected CRC32 checksums.
- Included necessary binary test data for ACE v1 and v2 formats.
- Refactored library.c to improve include order and reduce redundancy in function definitions.
This commit is contained in:
2026-04-14 21:49:37 +01:00
parent 882b775f71
commit d5c1cee932
17 changed files with 2250 additions and 160 deletions

View File

@@ -161,7 +161,17 @@ add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h a
lha/lh_old.c
lha/lh_old.h
lha/pmarc1.c
lha/pmarc1.h)
lha/pmarc1.h
ace/ace.c
ace/ace.h
ace/ace_internal.h
ace/bitstream.c
ace/huffman.c
ace/lz77.c
ace/sound.c
ace/pic.c
ace/v1.c
ace/v2.c)
include(3rdparty/bzip2.cmake)
include(3rdparty/flac.cmake)

93
ace/ace.c Normal file
View File

@@ -0,0 +1,93 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "ace.h"
#include "ace_internal.h"
void ace_init_bitwidth(ace_decompress_ctx_t *ctx)
{
int i, k, j;
i = k = 0;
j = 1;
do
{
if(i == j)
{
k++;
j <<= 1;
}
ctx->bit_width_array[i++] = (uint8_t)k;
} while(i < ACE_MAX_DIST2);
for(i = -128; i <= 127; i++)
{
if(i < 0)
ctx->dif_bit_width_array[(uint8_t)i] = ctx->bit_width_array[-2 * i - 1];
else
ctx->dif_bit_width_array[(uint8_t)i] = ctx->bit_width_array[2 * i];
}
}
int ace_get_bit_width(ace_decompress_ctx_t *ctx, int value)
{
return value < ACE_MAX_DIST2 ? ctx->bit_width_array[value]
: ctx->bit_width_array[value >> ACE_MAX_DIC_BITS2] + ACE_MAX_DIC_BITS2;
}
int ace_decompress_init(ace_decompress_ctx_t *ctx, int dic_bits)
{
memset(ctx, 0, sizeof(*ctx));
if(dic_bits < 10) dic_bits = 10;
if(dic_bits > ACE_MAX_DIC_BITS) dic_bits = ACE_MAX_DIC_BITS;
ctx->dic_bits = dic_bits;
ctx->dic_size = 1u << dic_bits;
ctx->dic_and = ctx->dic_size - 1;
ctx->dictionary = (uint8_t *)malloc(ctx->dic_size);
if(!ctx->dictionary) return -1;
memset(ctx->dictionary, 0, ctx->dic_size);
ace_init_bitwidth(ctx);
{
int i;
for(i = 0; i <= 128; i++)
{
ctx->sound_quantizer[256 - i] = ctx->sound_quantizer[i] = ace_get_bit_width(ctx, i);
}
}
return 0;
}
void ace_decompress_free(ace_decompress_ctx_t *ctx)
{
if(ctx->dictionary)
{
free(ctx->dictionary);
ctx->dictionary = NULL;
}
ace_pic_done(ctx);
}

245
ace/ace.h Normal file
View File

@@ -0,0 +1,245 @@
/*
* 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_ACE_H
#define AARU_ACE_H
#include <stddef.h>
#include <stdint.h>
/* ACE compression technique types */
#define ACE_TECHNIQUE_STORE 0
#define ACE_TECHNIQUE_LZ77 1 /* ACE v1 LZ77 */
#define ACE_TECHNIQUE_BLOCKED 2 /* ACE v2 blocked */
/* ACE v2 block subtypes */
#define ACE_BLOCK_LZ77_NORM 0
#define ACE_BLOCK_LZ77_DELTA 1
#define ACE_BLOCK_LZ77_EXE 2
#define ACE_BLOCK_SOUND_8 3
#define ACE_BLOCK_SOUND_16 4
#define ACE_BLOCK_SOUND_32_1 5
#define ACE_BLOCK_SOUND_32_2 6
#define ACE_BLOCK_PIC 7
/* Constants */
#define ACE_MAX_DIC_BITS 22
#define ACE_MAX_CODE_WIDTH 11
#define ACE_MAX_LEN 259
#define ACE_MAX_DIST_AT_LEN2 255
#define ACE_MAX_DIST_AT_LEN3 8191
#define ACE_MAX_DIC_BITS2 (ACE_MAX_DIC_BITS / 2)
#define ACE_MAX_DIC_SIZE (1 << ACE_MAX_DIC_BITS)
#define ACE_MAX_DIST2 (1 << ACE_MAX_DIC_BITS2)
#define ACE_MAX_MAIN_CODE (260 + ACE_MAX_DIC_BITS + 2)
#define ACE_MAX_LEN_CODE (256 - 1)
#define ACE_TYPE_CODE (260 + ACE_MAX_DIC_BITS + 1)
#define ACE_MAX_SAVE_WIDTH 7
#define ACE_MAX_WIDTH_TO_SAVE 15
/* Sound constants */
#define ACE_SOUND_RUNLEN_CODES 32
#define ACE_SOUND_MAX_CODE (256 + ACE_SOUND_RUNLEN_CODES + 1)
#define ACE_SOUND_MAX_CODE_WIDTH 10
#define ACE_SOUND_TYPE_CODE (256 + ACE_SOUND_RUNLEN_CODES)
#define ACE_SOUND_MAX_CHANNELS 3
#define ACE_SOUND_MAX_MODELS (ACE_SOUND_MAX_CHANNELS * 3)
#define ACE_SOUND_CHANNEL_BLOCK 2000
#define ACE_SOUND_HISTORY_SIZE 256
#define ACE_SOUND_MAX_BLOCK (ACE_SOUND_CHANNEL_BLOCK * ACE_SOUND_MAX_MODELS + 8)
/* PIC constants */
#define ACE_PIC_N0 32
#define ACE_PIC_S1 3
#define ACE_PIC_S2 12
#define ACE_PIC_S3 40
#define ACE_PIC_CONTEXT_NUMBER (9 * 9 * 9)
/* Read buffer size in 32-bit words */
#define ACE_READ_BUF_SIZE 8192
/* Max partition size for symbol batching */
#define ACE_MAX_PART_SIZE 1024
/* Max delta block */
#define ACE_MAX_DELTA_BLOCK 65536
/* Max HUFF code (for sort arrays) */
#define ACE_MAX_HUFF_CODE ACE_SOUND_MAX_CODE
/* PIC quantizer array access macros */
#define ACE_PIC_QUANT(ctx, v) ((ctx)->pic_quantizer[(v) + 255])
#define ACE_PIC_QUANT_X9(ctx, v) ((ctx)->pic_quantizer_x9[(v) + 255])
#define ACE_PIC_QUANT_X9X9(ctx, v) ((ctx)->pic_quantizer_x9x9[(v) + 255])
/* Sound channel number tables */
extern const int ace_sound_channel_num[4][4];
extern const int ace_sound_models[4];
/* PIC context entry */
typedef struct
{
uint8_t error_counters[4];
uint8_t predictor_number;
uint16_t used_counter;
uint16_t average_counter;
} ace_pic_context_t;
/* Main decompressor context */
typedef struct
{
/* Input buffer and position */
const uint8_t *in_buf;
size_t in_len;
size_t in_pos;
/* Bit reader state */
uint32_t read_buf[ACE_READ_BUF_SIZE];
int read_buf_pos;
int read_code_bit_pos;
uint32_t read_code;
/* Dictionary */
uint8_t *dictionary;
uint32_t dic_pos;
uint32_t dic_size;
uint32_t dic_and;
int dic_bits;
/* File decompression state */
int64_t file_size;
int64_t file_pos;
/* Huffman tables for LZ77 */
uint16_t main_huff_symbols[(1 << ACE_MAX_CODE_WIDTH) + 1];
uint16_t main_huff_widths[ACE_MAX_MAIN_CODE + 2];
uint16_t len_huff_symbols[(1 << ACE_MAX_CODE_WIDTH) + 1];
uint16_t len_huff_widths[ACE_MAX_LEN_CODE + 3];
/* Symbol batching buffers */
uint16_t main_buf[ACE_MAX_PART_SIZE];
uint16_t len_buf[ACE_MAX_PART_SIZE];
uint32_t dist_buf[ACE_MAX_PART_SIZE];
uint32_t main_buf_pos;
uint32_t len_dist_buf_pos;
/* LZ77 state */
int old_dists_pos;
uint32_t old_dists[4];
uint32_t block_size;
uint32_t part_size;
uint32_t block_byte_count;
uint32_t block_buf_size;
/* V2 blocked state */
int type;
int next_type;
int over_next_type;
/* Delta preprocessing */
int prep_num_kept_bytes;
int prep_kept_bytes_pos;
uint32_t prep_last_delta;
int delta_dist;
int next_delta_dist;
int delta_len;
int next_delta_len;
int delta_block_size;
int delta_plane_size;
int delta_plane;
int delta_plane_pos;
uint8_t prep_kept_bytes_buf[ACE_MAX_DELTA_BLOCK + ACE_MAX_LEN];
/* EXE preprocessing */
int exe_mode;
int next_exe_mode;
/* Quicksort working arrays */
uint16_t sort_elements[ACE_MAX_HUFF_CODE + 2];
uint16_t sort_frequencies[(ACE_MAX_HUFF_CODE + 2) * 2];
uint16_t save_widths[ACE_MAX_WIDTH_TO_SAVE];
/* Bitwidth tables */
uint8_t bit_width_array[ACE_MAX_DIST2];
uint8_t dif_bit_width_array[256];
/* Sound decompression */
uint16_t sound_huff_symbols[ACE_SOUND_MAX_MODELS][(1 << ACE_SOUND_MAX_CODE_WIDTH) + 1];
uint16_t sound_huff_widths[ACE_SOUND_MAX_MODELS][ACE_SOUND_MAX_CODE + 2];
int sound_quantizer[256];
struct
{
int predictor_dif_cnt[ACE_SOUND_MAX_CHANNELS][2];
int last_predictor_dif_cnt[ACE_SOUND_MAX_CHANNELS][2];
int rar_dif_cnt[ACE_SOUND_MAX_CHANNELS][4];
int rar_coefficient[ACE_SOUND_MAX_CHANNELS][4];
int rar_dif[ACE_SOUND_MAX_CHANNELS][9];
int byte_count[ACE_SOUND_MAX_CHANNELS];
int last_byte[ACE_SOUND_MAX_CHANNELS];
int last_delta[ACE_SOUND_MAX_CHANNELS];
int state[ACE_SOUND_MAX_CHANNELS];
int code[ACE_SOUND_MAX_CHANNELS];
int adaptive_model_cnt[ACE_SOUND_MAX_CHANNELS];
int adaptive_model_use[ACE_SOUND_MAX_CHANNELS];
int models;
int mode;
int sound_block_size;
} sound_var;
/* PIC decompression */
int pic_quantizer[511]; /* indexed as [v+255] for v in -255..255 */
int pic_quantizer_x9[511];
int pic_quantizer_x9x9[511];
ace_pic_context_t pic_context[2][ACE_PIC_CONTEXT_NUMBER];
ace_pic_context_t *cur_context;
int8_t *pic_data[2];
int pic_width;
int pic_planes;
int pic_data_pos;
int pic_cur_col;
int pic_cur_plane;
int pic_cur_pred;
int pic_cur_state;
int pic_pixel_a;
int pic_pixel_b;
int pic_pixel_c;
int pic_pixel_d;
int pic_pixel_x;
/* Error flag */
int error;
} ace_decompress_ctx_t;
/* Initialize context for decompression */
int ace_decompress_init(ace_decompress_ctx_t *ctx, int dic_bits);
/* Decompress an ACE v1 (LZ77) compressed block */
int ace_decompress_v1(ace_decompress_ctx_t *ctx, const uint8_t *in_buf, size_t in_len, uint8_t *out_buf,
size_t *out_len);
/* Decompress an ACE v2 (blocked) compressed block */
int ace_decompress_v2(ace_decompress_ctx_t *ctx, const uint8_t *in_buf, size_t in_len, uint8_t *out_buf,
size_t *out_len);
/* Free context resources */
void ace_decompress_free(ace_decompress_ctx_t *ctx);
#endif /* AARU_ACE_H */

60
ace/ace_internal.h Normal file
View File

@@ -0,0 +1,60 @@
/*
* 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_ACE_INTERNAL_H
#define AARU_ACE_INTERNAL_H
#include "ace.h"
/* bitstream.c */
void ace_fill_read_buf(ace_decompress_ctx_t *ctx);
void ace_add_bits(ace_decompress_ctx_t *ctx, int bits);
void ace_init_read_buf(ace_decompress_ctx_t *ctx);
/* huffman.c */
int ace_make_codes(ace_decompress_ctx_t *ctx, unsigned max_width, unsigned tab_size, uint16_t *widths, uint16_t *codes);
int ace_read_widths(ace_decompress_ctx_t *ctx, unsigned max_width, uint16_t *codes, uint16_t *widths,
unsigned max_size);
/* lz77.c */
void ace_lz77_write_char(ace_decompress_ctx_t *ctx, uint8_t ch);
void ace_lz77_copy_string(ace_decompress_ctx_t *ctx, uint32_t dist, int len);
int ace_lz77_calc_huff_tabs(ace_decompress_ctx_t *ctx);
int ace_lz77_read_symbols(ace_decompress_ctx_t *ctx);
void ace_lz77_block_core(ace_decompress_ctx_t *ctx);
int ace_lz77_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len);
void ace_lz77_copy_to_dict(ace_decompress_ctx_t *ctx, const uint8_t *buf, int len);
/* sound.c */
int ace_sound_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len);
void ace_sound_init(ace_decompress_ctx_t *ctx, int type);
/* pic.c */
int ace_pic_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len);
void ace_pic_init(ace_decompress_ctx_t *ctx);
void ace_pic_done(ace_decompress_ctx_t *ctx);
/* v2.c */
int ace_decompress_v20_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len);
int ace_lz77_preprocess_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len);
/* ace.c (init/bitwidth) */
void ace_init_bitwidth(ace_decompress_ctx_t *ctx);
int ace_get_bit_width(ace_decompress_ctx_t *ctx, int value);
#endif /* AARU_ACE_INTERNAL_H */

108
ace/bitstream.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* 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 <string.h>
#include "ace.h"
#include "ace_internal.h"
void ace_fill_read_buf(ace_decompress_ctx_t *ctx)
{
uint32_t i;
size_t bytes_to_read;
size_t words_to_read;
ctx->read_buf[0] = ctx->read_buf[ACE_READ_BUF_SIZE - 2];
ctx->read_buf[1] = ctx->read_buf[ACE_READ_BUF_SIZE - 1];
ctx->read_buf_pos -= ACE_READ_BUF_SIZE - 2;
bytes_to_read = (ACE_READ_BUF_SIZE - 2) * 4;
if(bytes_to_read > ctx->in_len - ctx->in_pos) bytes_to_read = ctx->in_len - ctx->in_pos;
words_to_read = bytes_to_read / 4;
for(i = 0; i < words_to_read; i++)
{
size_t off = ctx->in_pos + i * 4;
ctx->read_buf[2 + i] = (uint32_t)ctx->in_buf[off] | ((uint32_t)ctx->in_buf[off + 1] << 8) |
((uint32_t)ctx->in_buf[off + 2] << 16) | ((uint32_t)ctx->in_buf[off + 3] << 24);
}
if(bytes_to_read > words_to_read * 4)
{
uint32_t word = 0;
size_t off = ctx->in_pos + words_to_read * 4;
size_t rem = bytes_to_read - words_to_read * 4;
size_t b;
for(b = 0; b < rem; b++) word |= (uint32_t)ctx->in_buf[off + b] << (b * 8);
ctx->read_buf[2 + words_to_read] = word;
}
ctx->in_pos += bytes_to_read;
}
void ace_add_bits(ace_decompress_ctx_t *ctx, int bits)
{
uint32_t b0, b1;
ctx->read_buf_pos += (ctx->read_code_bit_pos += bits) >> 5;
ctx->read_code_bit_pos &= 31;
if(ctx->read_buf_pos == ACE_READ_BUF_SIZE - 2) ace_fill_read_buf(ctx);
b0 = ctx->read_buf[ctx->read_buf_pos];
b1 = ctx->read_buf[ctx->read_buf_pos + 1];
ctx->read_code = (b0 << ctx->read_code_bit_pos) +
((b1 >> (32 - ctx->read_code_bit_pos)) & ((uint32_t)(!ctx->read_code_bit_pos) - 1));
}
void ace_init_read_buf(ace_decompress_ctx_t *ctx)
{
size_t bytes_to_read;
size_t words_to_read;
size_t i;
bytes_to_read = ACE_READ_BUF_SIZE * 4;
if(bytes_to_read > ctx->in_len - ctx->in_pos) bytes_to_read = ctx->in_len - ctx->in_pos;
words_to_read = bytes_to_read / 4;
for(i = 0; i < words_to_read; i++)
{
size_t off = ctx->in_pos + i * 4;
ctx->read_buf[i] = (uint32_t)ctx->in_buf[off] | ((uint32_t)ctx->in_buf[off + 1] << 8) |
((uint32_t)ctx->in_buf[off + 2] << 16) | ((uint32_t)ctx->in_buf[off + 3] << 24);
}
if(bytes_to_read > words_to_read * 4)
{
uint32_t word = 0;
size_t off = ctx->in_pos + words_to_read * 4;
size_t rem = bytes_to_read - words_to_read * 4;
size_t b;
for(b = 0; b < rem; b++) word |= (uint32_t)ctx->in_buf[off + b] << (b * 8);
ctx->read_buf[words_to_read] = word;
}
ctx->in_pos += bytes_to_read;
ctx->read_code = ctx->read_buf[0];
ctx->read_code_bit_pos = 0;
ctx->read_buf_pos = 0;
}

176
ace/huffman.c Normal file
View File

@@ -0,0 +1,176 @@
/*
* 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 <string.h>
#include "ace.h"
#include "ace_internal.h"
static void ace_qsort_xchg(uint16_t *a, uint16_t *b)
{
uint16_t tmp = *a;
*a = *b;
*b = tmp;
}
static void ace_qsort_range(ace_decompress_ctx_t *ctx, int left, int right)
{
int new_left, new_right;
uint16_t hyphen;
new_left = left;
new_right = right;
hyphen = ctx->sort_frequencies[right];
do
{
while(ctx->sort_frequencies[new_left] > hyphen) new_left++;
while(ctx->sort_frequencies[new_right] < hyphen) new_right--;
if(new_left <= new_right)
{
ace_qsort_xchg(&ctx->sort_frequencies[new_left], &ctx->sort_frequencies[new_right]);
ace_qsort_xchg(&ctx->sort_elements[new_left], &ctx->sort_elements[new_right]);
new_left++;
new_right--;
}
} while(new_left < new_right);
if(left < new_right)
{
if(left < new_right - 1)
ace_qsort_range(ctx, left, new_right);
else if(ctx->sort_frequencies[left] < ctx->sort_frequencies[new_right])
{
ace_qsort_xchg(&ctx->sort_frequencies[left], &ctx->sort_frequencies[new_right]);
ace_qsort_xchg(&ctx->sort_elements[left], &ctx->sort_elements[new_right]);
}
}
if(right > new_left)
{
if(new_left < right - 1)
ace_qsort_range(ctx, new_left, right);
else if(ctx->sort_frequencies[new_left] < ctx->sort_frequencies[right])
{
ace_qsort_xchg(&ctx->sort_frequencies[new_left], &ctx->sort_frequencies[right]);
ace_qsort_xchg(&ctx->sort_elements[new_left], &ctx->sort_elements[right]);
}
}
}
static void ace_quicksort(ace_decompress_ctx_t *ctx, int n)
{
int i;
for(i = n + 1; i--;) ctx->sort_elements[i] = (uint16_t)i;
ace_qsort_range(ctx, 0, n);
}
static void ace_memset16(uint16_t *buf, uint16_t val, int count)
{
while(count--) *buf++ = val;
}
int ace_make_codes(ace_decompress_ctx_t *ctx, unsigned max_width, unsigned tab_size, uint16_t *widths, uint16_t *codes)
{
unsigned num_codes, code, code_pos, i, max_code_pos, actual_size;
memcpy(ctx->sort_frequencies, widths, (tab_size + 1) * sizeof(uint16_t));
if(tab_size)
ace_quicksort(ctx, (int)tab_size);
else
ctx->sort_elements[0] = 0;
ctx->sort_frequencies[tab_size + 1] = actual_size = code_pos = 0;
while(ctx->sort_frequencies[actual_size]) actual_size++;
if(actual_size < 2)
{
i = ctx->sort_elements[0];
widths[i] = 1;
actual_size += (actual_size == 0);
}
actual_size--;
max_code_pos = 1u << max_width;
for(i = actual_size + 1; i-- && code_pos < max_code_pos;)
{
num_codes = 1u << (max_width - ctx->sort_frequencies[i]);
code = ctx->sort_elements[i];
if(code_pos + num_codes > max_code_pos) return 0;
ace_memset16(&codes[code_pos], (uint16_t)code, (int)num_codes);
code_pos += num_codes;
}
return 1;
}
int ace_read_widths(ace_decompress_ctx_t *ctx, unsigned max_width, uint16_t *codes, uint16_t *widths, unsigned max_size)
{
unsigned code, i, width_pos, num_widths, len, upper_width, lower_width;
memset(widths, 0, max_size * sizeof(uint16_t));
memset(codes, 0, (1u << max_width) * sizeof(uint16_t));
num_widths = ctx->read_code >> (32 - 9);
ace_add_bits(ctx, 9);
if(num_widths > max_size) num_widths = max_size;
lower_width = ctx->read_code >> (32 - 4);
ace_add_bits(ctx, 4);
upper_width = ctx->read_code >> (32 - 4);
ace_add_bits(ctx, 4);
for(i = 0; i <= upper_width; i++)
{
ctx->save_widths[i] = ctx->read_code >> (32 - 3);
ace_add_bits(ctx, 3);
}
if(!ace_make_codes(ctx, ACE_MAX_SAVE_WIDTH, upper_width, ctx->save_widths, codes)) return 0;
width_pos = 0;
while(width_pos <= num_widths)
{
code = codes[ctx->read_code >> (32 - ACE_MAX_SAVE_WIDTH)];
ace_add_bits(ctx, ctx->save_widths[code]);
if(code < upper_width)
widths[width_pos++] = (uint16_t)code;
else
{
len = (ctx->read_code >> 28) + 4;
ace_add_bits(ctx, 4);
while(len-- && width_pos <= num_widths) widths[width_pos++] = 0;
}
}
if(upper_width)
{
for(i = 1; i <= num_widths; i++) widths[i] = (widths[i] + widths[i - 1]) % upper_width;
}
for(i = 0; i <= num_widths; i++)
{
if(widths[i]) widths[i] += (uint16_t)lower_width;
}
return ace_make_codes(ctx, max_width, num_widths, widths, codes);
}

260
ace/lz77.c Normal file
View File

@@ -0,0 +1,260 @@
/*
* 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 <string.h>
#include "ace.h"
#include "ace_internal.h"
void ace_lz77_write_char(ace_decompress_ctx_t *ctx, uint8_t ch)
{
ctx->dictionary[ctx->dic_pos] = ch;
ctx->dic_pos = (ctx->dic_pos + 1) & ctx->dic_and;
ctx->block_byte_count++;
}
void ace_lz77_copy_string(ace_decompress_ctx_t *ctx, uint32_t dist, int len)
{
uint32_t src_pos;
int i;
src_pos = (ctx->dic_pos - dist) & ctx->dic_and;
if(src_pos >= ctx->dic_size - ACE_MAX_LEN || ctx->dic_pos >= ctx->dic_size - ACE_MAX_LEN)
{
for(i = len; i--;)
{
ctx->dictionary[ctx->dic_pos] = ctx->dictionary[src_pos];
ctx->dic_pos = (ctx->dic_pos + 1) & ctx->dic_and;
src_pos = (src_pos + 1) & ctx->dic_and;
}
}
else
{
for(i = 0; i < len; i++) ctx->dictionary[ctx->dic_pos + i] = ctx->dictionary[src_pos + i];
ctx->dic_pos = (ctx->dic_pos + len) & ctx->dic_and;
}
ctx->block_byte_count += len;
}
int ace_lz77_calc_huff_tabs(ace_decompress_ctx_t *ctx)
{
if(!ace_read_widths(ctx, ACE_MAX_CODE_WIDTH, ctx->main_huff_symbols, ctx->main_huff_widths, ACE_MAX_MAIN_CODE) ||
!ace_read_widths(ctx, ACE_MAX_CODE_WIDTH, ctx->len_huff_symbols, ctx->len_huff_widths, ACE_MAX_LEN_CODE))
return 0;
ctx->block_size = ctx->read_code >> (32 - 15);
ace_add_bits(ctx, 15);
return 1;
}
int ace_lz77_read_symbols(ace_decompress_ctx_t *ctx)
{
int symbol_count, match_count, symbol, type;
if(!ctx->block_size && !ace_lz77_calc_huff_tabs(ctx)) return 0;
ctx->part_size = ACE_MAX_PART_SIZE > ctx->block_size ? ctx->block_size : ACE_MAX_PART_SIZE;
ctx->block_size -= ctx->part_size;
match_count = 0;
for(symbol_count = 0; (uint32_t)symbol_count < ctx->part_size; symbol_count++)
{
symbol = ctx->main_huff_symbols[ctx->read_code >> (32 - ACE_MAX_CODE_WIDTH)];
ace_add_bits(ctx, ctx->main_huff_widths[symbol]);
ctx->main_buf[symbol_count] = (uint16_t)symbol;
if(symbol > 255)
{
if(symbol == ACE_TYPE_CODE)
{
type = ctx->read_code >> 24;
ctx->len_buf[match_count] = (uint16_t)type;
ace_add_bits(ctx, 8);
switch(type)
{
case ACE_BLOCK_LZ77_DELTA:
ctx->dist_buf[match_count] = ctx->read_code >> (32 - 25);
ace_add_bits(ctx, 25);
break;
case ACE_BLOCK_LZ77_EXE:
ctx->dist_buf[match_count] = ctx->read_code >> (32 - 8);
ace_add_bits(ctx, 8);
break;
default:
break;
}
match_count++;
}
else
{
if(symbol > 259)
{
if((symbol -= 260) > 1)
{
ctx->dist_buf[match_count] = (ctx->read_code >> (33 - symbol)) + (1u << (symbol - 1));
ace_add_bits(ctx, symbol - 1);
}
else
{
ctx->dist_buf[match_count] = (uint32_t)symbol;
}
}
ctx->len_buf[match_count] = ctx->len_huff_symbols[ctx->read_code >> (32 - ACE_MAX_CODE_WIDTH)];
ace_add_bits(ctx, ctx->len_huff_widths[ctx->len_buf[match_count]]);
match_count++;
}
}
}
ctx->len_dist_buf_pos = ctx->main_buf_pos = 0;
return 1;
}
void ace_lz77_block_core(ace_decompress_ctx_t *ctx)
{
int symbol, len_symbol, i;
uint32_t match_dist;
while(ctx->block_byte_count < ctx->block_buf_size)
{
if(ctx->main_buf_pos == ctx->part_size)
{
if(!ace_lz77_read_symbols(ctx)) return;
}
symbol = ctx->main_buf[ctx->main_buf_pos++];
if(symbol > 255)
{
if(symbol == ACE_TYPE_CODE)
{
ctx->next_type = ctx->len_buf[ctx->len_dist_buf_pos] & 255;
switch(ctx->next_type)
{
case ACE_BLOCK_LZ77_DELTA:
ctx->next_delta_dist = ctx->dist_buf[ctx->len_dist_buf_pos] >> 17;
ctx->next_delta_len = ctx->dist_buf[ctx->len_dist_buf_pos] & 0x1FFFF;
break;
case ACE_BLOCK_LZ77_EXE:
ctx->next_exe_mode = ctx->dist_buf[ctx->len_dist_buf_pos];
break;
default:
break;
}
ctx->len_dist_buf_pos++;
break;
}
if(symbol > 259)
{
symbol -= 260;
match_dist = ctx->dist_buf[ctx->len_dist_buf_pos];
ctx->old_dists_pos = (ctx->old_dists_pos + 1) & 3;
ctx->old_dists[ctx->old_dists_pos] = match_dist;
i = 2;
if(match_dist > ACE_MAX_DIST_AT_LEN2)
{
i++;
if(match_dist > ACE_MAX_DIST_AT_LEN3) i++;
}
}
else
{
match_dist = ctx->old_dists[(ctx->old_dists_pos - (symbol &= 255)) & 3];
for(i = symbol; i >= 0; i--)
ctx->old_dists[(ctx->old_dists_pos - i) & 3] = ctx->old_dists[(ctx->old_dists_pos - i + 1) & 3];
ctx->old_dists[ctx->old_dists_pos] = match_dist;
i = symbol > 1 ? 3 : 2;
}
len_symbol = ctx->len_buf[ctx->len_dist_buf_pos++] + i;
match_dist++;
ace_lz77_copy_string(ctx, match_dist, len_symbol);
}
else
{
ace_lz77_write_char(ctx, (uint8_t)symbol);
}
}
}
int ace_lz77_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len)
{
int old_pos, i;
old_pos = ctx->dic_pos;
ctx->block_byte_count = 0;
if(len < ACE_MAX_LEN)
{
if(ctx->file_size <= 0 || (int64_t)len < ctx->file_size) return 0;
ctx->block_buf_size = (uint32_t)ctx->file_size;
}
else
{
ctx->block_buf_size = len - ACE_MAX_LEN;
}
if((int64_t)ctx->block_buf_size > ctx->file_size) ctx->block_buf_size = (uint32_t)ctx->file_size;
if(ctx->block_buf_size > ctx->dic_size - ACE_MAX_LEN) ctx->block_buf_size = ctx->dic_size - ACE_MAX_LEN;
if(ctx->file_size > 0 && ctx->block_buf_size)
{
ace_lz77_block_core(ctx);
if(ctx->block_byte_count <= (uint32_t)len)
{
if((uint32_t)old_pos + ctx->block_byte_count > ctx->dic_size)
{
i = ctx->dic_size - old_pos;
memcpy(buf, &ctx->dictionary[old_pos], i);
memcpy(&buf[i], ctx->dictionary, ctx->block_byte_count - i);
}
else
{
memcpy(buf, &ctx->dictionary[old_pos], ctx->block_byte_count);
}
}
}
ctx->file_size -= ctx->block_byte_count;
return (int)ctx->block_byte_count;
}
void ace_lz77_copy_to_dict(ace_decompress_ctx_t *ctx, const uint8_t *buf, int len)
{
int i;
for(i = 0; i < len; i++)
{
ctx->dictionary[ctx->dic_pos] = buf[i];
ctx->dic_pos = (ctx->dic_pos + 1) & ctx->dic_and;
}
}

378
ace/pic.c Normal file
View File

@@ -0,0 +1,378 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "ace.h"
#include "ace_internal.h"
static int ace_pic_golomb_rice(ace_decompress_ctx_t *ctx, int k)
{
int i, err;
err = k ? (int)(ctx->read_code >> (32 - k)) : 0;
ace_add_bits(ctx, k);
do
{
i = ctx->read_code >> 31;
if(i) err += 1 << k;
ace_add_bits(ctx, 1);
} while(i);
return err;
}
static int ace_pic_get_context(ace_decompress_ctx_t *ctx)
{
return ACE_PIC_QUANT_X9X9(ctx, ctx->pic_pixel_d - ctx->pic_pixel_a) +
ACE_PIC_QUANT_X9(ctx, ctx->pic_pixel_a - ctx->pic_pixel_c) +
ACE_PIC_QUANT(ctx, ctx->pic_pixel_c - ctx->pic_pixel_b);
}
static void ace_pic_init_model(ace_decompress_ctx_t *ctx)
{
int pred, i;
for(pred = 0; pred <= 1; pred++)
{
memset(&ctx->pic_context[pred], 0, sizeof(ctx->pic_context[0]));
for(i = 0; i < ACE_PIC_CONTEXT_NUMBER; i++) ctx->pic_context[pred][i].average_counter = 4;
}
}
static void ace_pic_init_quantizers(ace_decompress_ctx_t *ctx)
{
int i;
for(i = -255; i <= 255; i++)
{
if(i <= -ACE_PIC_S3)
ACE_PIC_QUANT(ctx, i) = -4;
else if(i <= -ACE_PIC_S2)
ACE_PIC_QUANT(ctx, i) = -3;
else if(i <= -ACE_PIC_S1)
ACE_PIC_QUANT(ctx, i) = -2;
else if(i <= -1)
ACE_PIC_QUANT(ctx, i) = -1;
else if(!i)
ACE_PIC_QUANT(ctx, i) = 0;
else if(i < ACE_PIC_S1)
ACE_PIC_QUANT(ctx, i) = 1;
else if(i < ACE_PIC_S2)
ACE_PIC_QUANT(ctx, i) = 2;
else if(i < ACE_PIC_S3)
ACE_PIC_QUANT(ctx, i) = 3;
else
ACE_PIC_QUANT(ctx, i) = 4;
}
for(i = -255; i <= 255; i++) ACE_PIC_QUANT_X9(ctx, i) = 9 * ACE_PIC_QUANT(ctx, i);
for(i = -255; i <= 255; i++) ACE_PIC_QUANT_X9X9(ctx, i) = 9 * ACE_PIC_QUANT_X9(ctx, i);
}
static void ace_pic_set_pixels1(ace_decompress_ctx_t *ctx)
{
ctx->pic_pixel_d = ctx->pic_data[1][ctx->pic_cur_plane];
ctx->pic_pixel_a = ctx->pic_pixel_b = ctx->pic_pixel_c = ctx->pic_pixel_x = 0;
if(ctx->pic_cur_pred == 1)
{
ctx->pic_pixel_a = ctx->pic_pixel_b = ctx->pic_pixel_c = ctx->pic_pixel_x = 128;
if(ctx->pic_cur_plane > 0) ctx->pic_pixel_d -= ctx->pic_data[1][ctx->pic_cur_plane - 1] - 128;
}
else if(ctx->pic_cur_pred == 2)
{
ctx->pic_pixel_a = ctx->pic_pixel_b = ctx->pic_pixel_c = ctx->pic_pixel_x = 128;
if(ctx->pic_cur_plane > 0) ctx->pic_pixel_d -= (ctx->pic_data[1][ctx->pic_cur_plane - 1] * 11 >> 4) - 128;
}
}
static void ace_pic_set_pixels2(ace_decompress_ctx_t *ctx)
{
ctx->pic_pixel_c = ctx->pic_pixel_a;
ctx->pic_pixel_a = ctx->pic_pixel_d;
ctx->pic_pixel_b = ctx->pic_pixel_x;
}
static void ace_pic_set_pixels3(ace_decompress_ctx_t *ctx)
{
ctx->pic_pixel_a = ctx->pic_data[1][ctx->pic_cur_col];
ctx->pic_pixel_b = ctx->pic_data[0][ctx->pic_cur_col - ctx->pic_planes];
ctx->pic_pixel_c = ctx->pic_data[1][ctx->pic_cur_col - ctx->pic_planes];
if(ctx->pic_cur_pred == 1)
{
ctx->pic_pixel_a -= ctx->pic_data[1][ctx->pic_cur_col - 1] - 128;
ctx->pic_pixel_b -= ctx->pic_data[0][ctx->pic_cur_col - ctx->pic_planes - 1] - 128;
ctx->pic_pixel_c -= ctx->pic_data[1][ctx->pic_cur_col - ctx->pic_planes - 1] - 128;
}
else if(ctx->pic_cur_pred == 2)
{
ctx->pic_pixel_a -= (ctx->pic_data[1][ctx->pic_cur_col - 1] * 11 >> 4) - 128;
ctx->pic_pixel_b -= (ctx->pic_data[0][ctx->pic_cur_col - ctx->pic_planes - 1] * 11 >> 4) - 128;
ctx->pic_pixel_c -= (ctx->pic_data[1][ctx->pic_cur_col - ctx->pic_planes - 1] * 11 >> 4) - 128;
}
}
static void ace_pic_set_pixel_state(ace_decompress_ctx_t *ctx)
{
ctx->pic_pixel_d = ctx->pic_data[1][ctx->pic_cur_col + ctx->pic_planes];
if(ctx->pic_cur_pred == 1)
ctx->pic_pixel_d -= ctx->pic_data[1][ctx->pic_cur_col + ctx->pic_planes - 1] - 128;
else if(ctx->pic_cur_pred == 2)
ctx->pic_pixel_d -= (ctx->pic_data[1][ctx->pic_cur_col + ctx->pic_planes - 1] * 11 >> 4) - 128;
ctx->pic_cur_state = abs(ace_pic_get_context(ctx));
}
static void ace_pic_pixel(ace_decompress_ctx_t *ctx)
{
int k, best_predictor, best_error_count;
uint8_t m_epsilon, predicted;
int8_t epsilon;
ctx->cur_context[ctx->pic_cur_state].used_counter++;
k = ctx->bit_width_array[ctx->cur_context[ctx->pic_cur_state].average_counter /
ctx->cur_context[ctx->pic_cur_state].used_counter];
m_epsilon = (uint8_t)ace_pic_golomb_rice(ctx, k);
if(m_epsilon & 1)
epsilon = -(int8_t)(m_epsilon / 2) - 1;
else
epsilon = (int8_t)(m_epsilon / 2);
switch(ctx->cur_context[ctx->pic_cur_state].predictor_number)
{
case 0:
predicted = (uint8_t)ctx->pic_pixel_a;
break;
case 1:
predicted = (uint8_t)ctx->pic_pixel_b;
break;
case 2:
predicted = (uint8_t)((ctx->pic_pixel_a + ctx->pic_pixel_b) >> 1);
break;
case 3:
predicted = (uint8_t)(ctx->pic_pixel_a + ctx->pic_pixel_b - ctx->pic_pixel_c);
break;
default:
predicted = 0;
}
ctx->pic_pixel_x = (uint8_t)(epsilon + predicted);
ctx->cur_context[ctx->pic_cur_state].error_counters[0] +=
ctx->dif_bit_width_array[(uint8_t)(ctx->pic_pixel_x - ctx->pic_pixel_a)];
best_predictor = 0;
best_error_count = ctx->cur_context[ctx->pic_cur_state].error_counters[0];
ctx->cur_context[ctx->pic_cur_state].error_counters[1] +=
ctx->dif_bit_width_array[(uint8_t)(ctx->pic_pixel_x - ctx->pic_pixel_b)];
if(ctx->cur_context[ctx->pic_cur_state].error_counters[1] < best_error_count)
{
best_predictor = 1;
best_error_count = ctx->cur_context[ctx->pic_cur_state].error_counters[1];
}
ctx->cur_context[ctx->pic_cur_state].error_counters[2] +=
ctx->dif_bit_width_array[(uint8_t)(ctx->pic_pixel_x - ((ctx->pic_pixel_a + ctx->pic_pixel_b) >> 1))];
if(ctx->cur_context[ctx->pic_cur_state].error_counters[2] < best_error_count)
{
best_predictor = 2;
best_error_count = ctx->cur_context[ctx->pic_cur_state].error_counters[2];
}
ctx->cur_context[ctx->pic_cur_state].error_counters[3] += ctx->dif_bit_width_array[(
uint8_t)(ctx->pic_pixel_x - (ctx->pic_pixel_a + ctx->pic_pixel_b - ctx->pic_pixel_c))];
if(ctx->cur_context[ctx->pic_cur_state].error_counters[3] < best_error_count) best_predictor = 3;
{
uint32_t *ec = (uint32_t *)&ctx->cur_context[ctx->pic_cur_state].error_counters;
if(*ec & 0x80808080u) *ec = (*ec >> 1) & 0x7f7f7f7fu;
}
ctx->cur_context[ctx->pic_cur_state].predictor_number = (uint8_t)best_predictor;
ctx->cur_context[ctx->pic_cur_state].average_counter += (uint16_t)abs(epsilon);
if(ctx->cur_context[ctx->pic_cur_state].used_counter == ACE_PIC_N0)
{
ctx->cur_context[ctx->pic_cur_state].used_counter >>= 1;
ctx->cur_context[ctx->pic_cur_state].average_counter >>= 1;
}
switch(ctx->pic_cur_pred)
{
case 0:
ctx->pic_data[0][ctx->pic_cur_col] = (int8_t)ctx->pic_pixel_x;
break;
case 1:
ctx->pic_data[0][ctx->pic_cur_col] =
(int8_t)(ctx->pic_pixel_x + ctx->pic_data[0][ctx->pic_cur_col - 1] - 128);
break;
case 2:
ctx->pic_data[0][ctx->pic_cur_col] =
(int8_t)(ctx->pic_pixel_x + (ctx->pic_data[0][ctx->pic_cur_col - 1] * 11 >> 4) - 128);
break;
}
}
static void ace_pic_symbol(ace_decompress_ctx_t *ctx)
{
ace_pic_set_pixels2(ctx);
ace_pic_set_pixels3(ctx);
ace_pic_set_pixel_state(ctx);
ace_pic_pixel(ctx);
}
static void ace_pic_line(ace_decompress_ctx_t *ctx)
{
int8_t *temp;
for(ctx->pic_cur_plane = 0; ctx->pic_cur_plane < ctx->pic_planes; ctx->pic_cur_plane++)
{
if(ctx->pic_cur_plane)
{
ctx->cur_context = ctx->pic_context[1];
ctx->pic_cur_pred = ctx->read_code >> (32 - 2);
ace_add_bits(ctx, 2);
}
else
{
ctx->cur_context = ctx->pic_context[0];
ctx->pic_cur_pred = 0;
}
ace_pic_set_pixels1(ctx);
for(ctx->pic_cur_col = ctx->pic_cur_plane; ctx->pic_cur_col < ctx->pic_width;
ctx->pic_cur_col += ctx->pic_planes)
{
ace_pic_symbol(ctx);
}
}
ctx->pic_data_pos = ctx->pic_width;
temp = ctx->pic_data[0];
ctx->pic_data[0] = ctx->pic_data[1];
ctx->pic_data[1] = temp;
}
void ace_pic_done(ace_decompress_ctx_t *ctx)
{
if(ctx->pic_data[0])
{
free(ctx->pic_data[0] - ctx->pic_planes);
free(ctx->pic_data[1] - ctx->pic_planes);
ctx->pic_data[0] = NULL;
ctx->pic_data[1] = NULL;
}
}
void ace_pic_init(ace_decompress_ctx_t *ctx)
{
int i, j;
int8_t *buf;
ace_pic_done(ctx);
ctx->pic_width = ace_pic_golomb_rice(ctx, 12);
ctx->pic_planes = ace_pic_golomb_rice(ctx, 2);
i = ctx->pic_width + 2 * ctx->pic_planes;
for(j = 0; j <= 1; j++)
{
buf = (int8_t *)malloc(i);
if(!buf)
{
ctx->error = 1;
return;
}
memset(buf, 0, i);
ctx->pic_data[j] = buf + ctx->pic_planes;
}
ace_pic_init_model(ctx);
ace_pic_init_quantizers(ctx);
ctx->pic_data_pos = 0;
}
int ace_pic_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len)
{
int i, rest_len;
rest_len = len;
while(rest_len)
{
if(!ctx->pic_data_pos)
{
if(ctx->file_size)
{
i = ctx->read_code >> (32 - 1);
ace_add_bits(ctx, 1);
if(!i)
{
ctx->next_type = ctx->read_code >> (32 - 8);
ace_add_bits(ctx, 8);
switch(ctx->next_type)
{
case ACE_BLOCK_LZ77_DELTA:
ctx->next_delta_dist = ctx->read_code >> (32 - 8);
ace_add_bits(ctx, 8);
ctx->next_delta_len = ctx->read_code >> (32 - 17);
ace_add_bits(ctx, 17);
break;
case ACE_BLOCK_LZ77_EXE:
ctx->next_exe_mode = ctx->read_code >> (32 - 8);
ace_add_bits(ctx, 8);
break;
default:
break;
}
break;
}
}
else
{
break;
}
ace_pic_line(ctx);
}
i = rest_len > ctx->pic_data_pos ? ctx->pic_data_pos : rest_len;
memcpy(buf, &ctx->pic_data[1][ctx->pic_width - ctx->pic_data_pos], i);
buf += i;
rest_len -= i;
ctx->pic_data_pos -= i;
ctx->file_size -= i;
}
return len - rest_len;
}

250
ace/sound.c Normal file
View File

@@ -0,0 +1,250 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "ace.h"
#include "ace_internal.h"
const int ace_sound_channel_num[4][4] = {
{0, 0, 0, 0},
{0, 1, 0, 1},
{0, 1, 2, 0},
{0, 1, 2, 0}
};
const int ace_sound_models[4] = {3, 6, 9, 6};
static uint8_t ace_sound_get_predicted(ace_decompress_ctx_t *ctx, int ch)
{
return (uint8_t)((8 * ctx->sound_var.last_byte[ch] +
ctx->sound_var.rar_coefficient[ch][0] * ctx->sound_var.rar_dif_cnt[ch][0] +
ctx->sound_var.rar_coefficient[ch][1] * ctx->sound_var.rar_dif_cnt[ch][1] +
ctx->sound_var.rar_coefficient[ch][2] * ctx->sound_var.rar_dif_cnt[ch][2] +
ctx->sound_var.rar_coefficient[ch][3] * ctx->sound_var.rar_dif_cnt[ch][3]) >>
3);
}
static int ace_sound_calc_tabs(ace_decompress_ctx_t *ctx)
{
int i;
for(i = 0; i < ctx->sound_var.models; i++)
{
ace_read_widths(ctx, ACE_SOUND_MAX_CODE_WIDTH, ctx->sound_huff_symbols[i], ctx->sound_huff_widths[i],
ACE_SOUND_MAX_CODE);
}
ctx->sound_var.sound_block_size = ctx->read_code >> (32 - 15);
ace_add_bits(ctx, 15);
return 1;
}
static int ace_sound_get_symbol(ace_decompress_ctx_t *ctx, int model, int channel)
{
int symbol;
if(!ctx->sound_var.sound_block_size) ace_sound_calc_tabs(ctx);
model <<= 1;
if(!model) model += ctx->sound_var.adaptive_model_use[channel];
model += 3 * channel;
symbol = ctx->sound_huff_symbols[model][ctx->read_code >> (32 - ACE_SOUND_MAX_CODE_WIDTH)];
ace_add_bits(ctx, ctx->sound_huff_widths[model][symbol]);
ctx->sound_var.sound_block_size--;
return symbol;
}
static int ace_sound_get(ace_decompress_ctx_t *ctx, int channel)
{
int err;
if(ctx->sound_var.state[channel] != 2)
{
ctx->sound_var.code[channel] = ace_sound_get_symbol(ctx, ctx->sound_var.state[channel], channel);
if(ctx->sound_var.code[channel] == ACE_SOUND_TYPE_CODE)
{
ctx->next_type = ctx->read_code >> (32 - 8);
ace_add_bits(ctx, 8);
switch(ctx->next_type)
{
case ACE_BLOCK_LZ77_DELTA:
ctx->next_delta_dist = ctx->read_code >> (32 - 8);
ace_add_bits(ctx, 8);
ctx->next_delta_len = ctx->read_code >> (32 - 17);
ace_add_bits(ctx, 17);
break;
case ACE_BLOCK_LZ77_EXE:
ctx->next_exe_mode = ctx->read_code >> (32 - 8);
ace_add_bits(ctx, 8);
break;
default:
break;
}
return -1;
}
}
if(ctx->sound_var.state[channel] != 2)
{
if(!ctx->sound_var.state[channel] && ctx->sound_var.code[channel] < ACE_SOUND_RUNLEN_CODES)
{
ctx->sound_var.state[channel] = 2;
}
else
{
if(ctx->sound_var.state[channel] == 1)
{
err = ctx->sound_var.code[channel];
ctx->sound_var.state[channel] = 0;
}
else
{
err = ctx->sound_var.code[channel] - ACE_SOUND_RUNLEN_CODES;
ctx->sound_var.adaptive_model_cnt[channel] =
(ctx->sound_var.adaptive_model_cnt[channel] * 7 >> 3) + err;
ctx->sound_var.adaptive_model_use[channel] = ctx->sound_var.adaptive_model_cnt[channel] > 40;
}
}
}
if(ctx->sound_var.state[channel] == 2)
{
if(!ctx->sound_var.code[channel])
ctx->sound_var.state[channel] = 1;
else
ctx->sound_var.code[channel]--;
err = 0;
}
return err & 1 ? (255 - (err >> 1)) : err >> 1;
}
static int ace_sound_rar_predict(ace_decompress_ctx_t *ctx, int channel)
{
int pch = ace_sound_get_predicted(ctx, channel);
if(ctx->sound_var.predictor_dif_cnt[channel][0] > ctx->sound_var.predictor_dif_cnt[channel][1])
pch = ctx->sound_var.last_byte[channel];
return pch - 128;
}
static void ace_sound_rar_adjust(ace_decompress_ctx_t *ctx, int channel, int ch)
{
int pred_dif, i, min_dif, min_dif_pos = 0, pch;
ctx->sound_var.byte_count[channel]++;
pch = ace_sound_get_predicted(ctx, channel);
pred_dif = ((int8_t)(pch - ch)) << 3;
ctx->sound_var.rar_dif[channel][0] += abs(pred_dif - ctx->sound_var.rar_dif_cnt[channel][0]);
ctx->sound_var.rar_dif[channel][1] += abs(pred_dif + ctx->sound_var.rar_dif_cnt[channel][0]);
ctx->sound_var.rar_dif[channel][2] += abs(pred_dif - ctx->sound_var.rar_dif_cnt[channel][1]);
ctx->sound_var.rar_dif[channel][3] += abs(pred_dif + ctx->sound_var.rar_dif_cnt[channel][1]);
ctx->sound_var.rar_dif[channel][4] += abs(pred_dif - ctx->sound_var.rar_dif_cnt[channel][2]);
ctx->sound_var.rar_dif[channel][5] += abs(pred_dif + ctx->sound_var.rar_dif_cnt[channel][2]);
ctx->sound_var.rar_dif[channel][6] += abs(pred_dif - ctx->sound_var.rar_dif_cnt[channel][3]);
ctx->sound_var.rar_dif[channel][7] += abs(pred_dif + ctx->sound_var.rar_dif_cnt[channel][3]);
ctx->sound_var.rar_dif[channel][8] += abs(pred_dif);
ctx->sound_var.predictor_dif_cnt[channel][0] += ctx->sound_quantizer[(uint8_t)(pred_dif >> 3)];
ctx->sound_var.predictor_dif_cnt[channel][1] +=
ctx->sound_quantizer[(uint8_t)(ctx->sound_var.last_byte[channel] - ch)];
ctx->sound_var.last_delta[channel] = (int8_t)(ch - ctx->sound_var.last_byte[channel]);
ctx->sound_var.last_byte[channel] = ch;
if(!(ctx->sound_var.byte_count[channel] & 0x1f))
{
min_dif = 0xffff;
for(i = 8; i >= 0; i--)
{
if(ctx->sound_var.rar_dif[channel][i] <= min_dif)
{
min_dif = ctx->sound_var.rar_dif[channel][i];
min_dif_pos = i;
}
ctx->sound_var.rar_dif[channel][i] = 0;
}
if(min_dif_pos != 8)
{
i = min_dif_pos >> 1;
if(!(min_dif_pos & 1))
{
if(ctx->sound_var.rar_coefficient[channel][i] >= -16) ctx->sound_var.rar_coefficient[channel][i]--;
}
else
{
if(ctx->sound_var.rar_coefficient[channel][i] <= 16) ctx->sound_var.rar_coefficient[channel][i]++;
}
}
if(!(ctx->sound_var.byte_count[channel] & 0xff))
{
ctx->sound_var.predictor_dif_cnt[channel][0] -= ctx->sound_var.last_predictor_dif_cnt[channel][0];
ctx->sound_var.last_predictor_dif_cnt[channel][0] = ctx->sound_var.predictor_dif_cnt[channel][0];
ctx->sound_var.predictor_dif_cnt[channel][1] -= ctx->sound_var.last_predictor_dif_cnt[channel][1];
ctx->sound_var.last_predictor_dif_cnt[channel][1] = ctx->sound_var.predictor_dif_cnt[channel][1];
}
}
ctx->sound_var.rar_dif_cnt[channel][3] = ctx->sound_var.rar_dif_cnt[channel][2];
ctx->sound_var.rar_dif_cnt[channel][2] = ctx->sound_var.rar_dif_cnt[channel][1];
ctx->sound_var.rar_dif_cnt[channel][1] =
ctx->sound_var.last_delta[channel] - ctx->sound_var.rar_dif_cnt[channel][0];
ctx->sound_var.rar_dif_cnt[channel][0] = ctx->sound_var.last_delta[channel];
}
int ace_sound_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len)
{
int i, err, channel, sample;
len &= (int)0xfffffffc;
if(len > (int)ctx->file_size) len = (int)ctx->file_size;
for(i = 0; i < len; i++)
{
channel = ace_sound_channel_num[ctx->sound_var.mode][i & 3];
err = ace_sound_get(ctx, channel);
if(err == -1) break;
sample = (uint8_t)(err + ace_sound_rar_predict(ctx, channel));
buf[i] = (uint8_t)(sample + 128);
ace_sound_rar_adjust(ctx, channel, buf[i]);
}
ctx->file_size -= i;
return i;
}
void ace_sound_init(ace_decompress_ctx_t *ctx, int type)
{
memset(&ctx->sound_var, 0, sizeof(ctx->sound_var));
ctx->sound_var.mode = type - ACE_BLOCK_SOUND_8;
ctx->sound_var.models = ace_sound_models[ctx->sound_var.mode];
}

148
ace/v1.c Normal file
View File

@@ -0,0 +1,148 @@
/*
* 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 <string.h>
#include "ace.h"
#include "ace_internal.h"
static void ace_v1_decompress_core(ace_decompress_ctx_t *ctx)
{
int c, lg, i, k;
uint32_t dist;
while(ctx->block_byte_count < ctx->block_buf_size && !ctx->error)
{
if(!ctx->block_size)
{
if(!ace_read_widths(ctx, ACE_MAX_CODE_WIDTH, ctx->main_huff_symbols, ctx->main_huff_widths,
ACE_MAX_MAIN_CODE) ||
!ace_read_widths(ctx, ACE_MAX_CODE_WIDTH, ctx->len_huff_symbols, ctx->len_huff_widths, ACE_MAX_LEN_CODE))
{
ctx->error = 1;
return;
}
ctx->block_size = ctx->read_code >> (32 - 15);
ace_add_bits(ctx, 15);
}
c = ctx->main_huff_symbols[ctx->read_code >> (32 - ACE_MAX_CODE_WIDTH)];
ace_add_bits(ctx, ctx->main_huff_widths[c]);
ctx->block_size--;
if(c > 255)
{
if(c > 259)
{
if((c -= 260) > 1)
{
dist = (ctx->read_code >> (33 - c)) + (1u << (c - 1));
ace_add_bits(ctx, c - 1);
}
else
{
dist = (uint32_t)c;
}
ctx->old_dists[(ctx->old_dists_pos = (ctx->old_dists_pos + 1) & 3)] = dist;
i = 2;
if(dist > ACE_MAX_DIST_AT_LEN2)
{
i++;
if(dist > ACE_MAX_DIST_AT_LEN3) i++;
}
}
else
{
dist = ctx->old_dists[(ctx->old_dists_pos - (c &= 255)) & 3];
for(k = c + 1; k--;)
ctx->old_dists[(ctx->old_dists_pos - k) & 3] = ctx->old_dists[(ctx->old_dists_pos - k + 1) & 3];
ctx->old_dists[ctx->old_dists_pos] = dist;
i = 2;
if(c > 1) i++;
}
lg = ctx->len_huff_symbols[ctx->read_code >> (32 - ACE_MAX_CODE_WIDTH)];
ace_add_bits(ctx, ctx->len_huff_widths[lg]);
lg += i;
dist++;
ace_lz77_copy_string(ctx, dist, lg);
}
else
{
ace_lz77_write_char(ctx, (uint8_t)c);
}
}
}
int ace_decompress_v1(ace_decompress_ctx_t *ctx, const uint8_t *in_buf, size_t in_len, uint8_t *out_buf,
size_t *out_len)
{
size_t orig_size = *out_len;
uint32_t old_pos;
int i;
ctx->in_buf = in_buf;
ctx->in_len = in_len;
ctx->in_pos = 0;
ctx->error = 0;
ctx->dic_pos = 0;
ctx->file_size = (int64_t)orig_size;
ctx->block_size = 0;
ctx->block_byte_count = 0;
ctx->old_dists_pos = 0;
memset(ctx->old_dists, 0, sizeof(ctx->old_dists));
ace_init_read_buf(ctx);
{
size_t total_out = 0;
while(ctx->file_size > 0 && !ctx->error)
{
old_pos = ctx->dic_pos;
ctx->block_byte_count = 0;
ctx->block_buf_size = (uint32_t)ctx->file_size;
if(ctx->block_buf_size > ctx->dic_size - ACE_MAX_LEN) ctx->block_buf_size = ctx->dic_size - ACE_MAX_LEN;
ace_v1_decompress_core(ctx);
if(ctx->block_byte_count > 0 && total_out + ctx->block_byte_count <= orig_size)
{
if(old_pos + ctx->block_byte_count > ctx->dic_size)
{
i = ctx->dic_size - old_pos;
memcpy(out_buf + total_out, &ctx->dictionary[old_pos], i);
memcpy(out_buf + total_out + i, ctx->dictionary, ctx->block_byte_count - i);
}
else
{
memcpy(out_buf + total_out, &ctx->dictionary[old_pos], ctx->block_byte_count);
}
}
total_out += ctx->block_byte_count;
ctx->file_size -= ctx->block_byte_count;
}
*out_len = total_out;
}
return ctx->error ? -1 : 0;
}

248
ace/v2.c Normal file
View File

@@ -0,0 +1,248 @@
/*
* 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 <string.h>
#include "ace.h"
#include "ace_internal.h"
int ace_decompress_v20_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len)
{
int r, rest_len;
rest_len = len;
do
{
if(ctx->type != ctx->next_type)
{
switch(ctx->next_type)
{
case ACE_BLOCK_SOUND_8:
case ACE_BLOCK_SOUND_16:
case ACE_BLOCK_SOUND_32_1:
case ACE_BLOCK_SOUND_32_2:
ace_sound_init(ctx, ctx->next_type);
break;
case ACE_BLOCK_PIC:
ace_pic_init(ctx);
break;
default:
break;
}
}
ctx->type = ctx->next_type;
switch(ctx->type)
{
case ACE_BLOCK_LZ77_NORM:
case ACE_BLOCK_LZ77_DELTA:
case ACE_BLOCK_LZ77_EXE:
r = ace_lz77_preprocess_block(ctx, buf, rest_len);
break;
case ACE_BLOCK_PIC:
r = ace_pic_block(ctx, buf, rest_len);
ace_lz77_copy_to_dict(ctx, buf, r);
break;
case ACE_BLOCK_SOUND_8:
case ACE_BLOCK_SOUND_16:
case ACE_BLOCK_SOUND_32_1:
case ACE_BLOCK_SOUND_32_2:
r = ace_sound_block(ctx, buf, rest_len);
ace_lz77_copy_to_dict(ctx, buf, r);
break;
default:
r = 0;
break;
}
ctx->file_pos += r;
buf += r;
rest_len -= r;
} while((r || ctx->next_type != ctx->type || (ctx->next_type == ACE_BLOCK_LZ77_DELTA && ctx->next_delta_len)) &&
(rest_len > ACE_MAX_LEN || (ctx->file_size > 0 && ctx->file_size <= ACE_MAX_LEN && rest_len > 0)));
return len - rest_len;
}
int ace_lz77_preprocess_block(ace_decompress_ctx_t *ctx, uint8_t *buf, int len)
{
int i, r, pos, read_count;
if(ctx->type == ACE_BLOCK_LZ77_DELTA)
{
if(!ctx->prep_num_kept_bytes)
{
ctx->delta_dist = ctx->next_delta_dist;
ctx->delta_len = ctx->next_delta_len;
ctx->next_delta_len = 0;
do
{
ctx->prep_num_kept_bytes +=
(read_count = ace_lz77_block(ctx, ctx->prep_kept_bytes_buf + ctx->prep_num_kept_bytes,
ACE_MAX_DELTA_BLOCK + ACE_MAX_LEN - ctx->prep_num_kept_bytes));
} while(ctx->prep_num_kept_bytes < ctx->delta_len);
ctx->delta_block_size = ctx->prep_num_kept_bytes;
if(ctx->delta_dist)
ctx->delta_plane_size = ctx->delta_block_size / ctx->delta_dist;
else
ctx->delta_plane_size = 0;
ctx->over_next_type = ctx->next_type;
ctx->next_type = ACE_BLOCK_LZ77_DELTA;
for(i = 0; i < ctx->delta_block_size; i++)
ctx->prep_last_delta = (ctx->prep_kept_bytes_buf[i] += (uint8_t)ctx->prep_last_delta);
ctx->prep_kept_bytes_pos = ctx->delta_plane = ctx->delta_plane_pos = 0;
}
r = ctx->prep_num_kept_bytes > len ? len : ctx->prep_num_kept_bytes;
if(ctx->delta_plane_size)
{
for(i = 0;; ctx->delta_plane_pos++)
{
for(; ctx->delta_plane < ctx->delta_block_size; ctx->delta_plane += ctx->delta_plane_size, i++)
{
if(i == r) goto DELTA_BREAK;
buf[i] = ctx->prep_kept_bytes_buf[ctx->delta_plane_pos + ctx->delta_plane];
}
ctx->delta_plane = 0;
}
}
DELTA_BREAK:
ctx->prep_kept_bytes_pos += r;
ctx->prep_num_kept_bytes -= r;
if(!ctx->prep_num_kept_bytes) ctx->next_type = ctx->over_next_type;
return r;
}
else
{
memcpy(buf, ctx->prep_kept_bytes_buf, ctx->prep_num_kept_bytes);
r = ace_lz77_block(ctx, &buf[ctx->prep_num_kept_bytes], len - ctx->prep_num_kept_bytes) +
ctx->prep_num_kept_bytes;
ctx->prep_num_kept_bytes = 0;
if(ctx->type == ACE_BLOCK_LZ77_EXE)
{
ctx->exe_mode = ctx->next_exe_mode;
for(i = 0; i < r - 4; i++)
{
pos = (int)(ctx->file_pos + i);
if(buf[i] == (uint8_t)0xe8)
{
if(!ctx->exe_mode)
{
uint16_t val;
memcpy(&val, &buf[i + 1], 2);
val -= (uint16_t)pos;
memcpy(&buf[i + 1], &val, 2);
i += 2;
}
else
{
uint32_t val;
memcpy(&val, &buf[i + 1], 4);
val -= (uint32_t)pos;
memcpy(&buf[i + 1], &val, 4);
i += 4;
}
}
else if(buf[i] == (uint8_t)0xe9)
{
uint16_t val;
memcpy(&val, &buf[i + 1], 2);
val -= (uint16_t)pos;
memcpy(&buf[i + 1], &val, 2);
i += 2;
}
}
for(; i < r; i++)
{
if(buf[i] == (uint8_t)0xe8 || buf[i] == (uint8_t)0xe9)
{
ctx->prep_num_kept_bytes = r - i;
memcpy(ctx->prep_kept_bytes_buf, &buf[i], ctx->prep_num_kept_bytes);
break;
}
}
}
return r - ctx->prep_num_kept_bytes;
}
}
int ace_decompress_v2(ace_decompress_ctx_t *ctx, const uint8_t *in_buf, size_t in_len, uint8_t *out_buf,
size_t *out_len)
{
size_t orig_size = *out_len;
size_t total_out = 0;
int r;
ctx->in_buf = in_buf;
ctx->in_len = in_len;
ctx->in_pos = 0;
ctx->error = 0;
ctx->dic_pos = 0;
ctx->file_size = (int64_t)orig_size;
ctx->file_pos = 0;
ctx->block_size = 0;
ctx->part_size = 0;
ctx->main_buf_pos = 0;
ctx->old_dists_pos = 0;
ctx->prep_num_kept_bytes = 0;
ctx->prep_last_delta = 0;
ctx->delta_block_size = 0;
ctx->next_delta_len = 0;
memset(ctx->old_dists, 0, sizeof(ctx->old_dists));
ctx->type = ACE_BLOCK_LZ77_NORM;
ctx->next_type = ACE_BLOCK_LZ77_NORM;
ace_init_read_buf(ctx);
while(total_out < orig_size && !ctx->error)
{
int remaining = (int)(orig_size - total_out);
r = ace_decompress_v20_block(ctx, out_buf + total_out, remaining);
if(r <= 0) break;
total_out += r;
}
*out_len = total_out;
ace_pic_done(ctx);
return ctx->error ? -1 : 0;
}

301
library.c
View File

@@ -25,15 +25,14 @@
#include "3rdparty/bzip2/bzlib.h"
#include "3rdparty/lz4/lib/lz4.h"
#include "3rdparty/lzfse/src/lzfse.h"
#include "3rdparty/lzfse/src/lzvn_encode_base.h"
#include "3rdparty/lzfse/src/lzvn_decode_base.h"
#include "3rdparty/lzfse/src/lzvn_encode_base.h"
#include "3rdparty/lzma/C/7zCrc.h"
#include "3rdparty/lzma/C/Alloc.h"
#include "3rdparty/lzma/C/LzmaLib.h"
#include "3rdparty/lzma/C/Xz.h"
#include "3rdparty/lzma/C/XzEnc.h"
#include "3rdparty/lzma/C/Alloc.h"
#include "3rdparty/lzma/C/7zCrc.h"
#include "3rdparty/lzma/C/XzCrc64.h"
#include "3rdparty/lzo-2.10/include/lzo/lzoconf.h"
#include "3rdparty/lzma/C/XzEnc.h"
#include "3rdparty/lzo-2.10/include/lzo/lzo1.h"
#include "3rdparty/lzo-2.10/include/lzo/lzo1a.h"
#include "3rdparty/lzo-2.10/include/lzo/lzo1b.h"
@@ -43,64 +42,38 @@
#include "3rdparty/lzo-2.10/include/lzo/lzo1y.h"
#include "3rdparty/lzo-2.10/include/lzo/lzo1z.h"
#include "3rdparty/lzo-2.10/include/lzo/lzo2a.h"
#include "3rdparty/lzo-2.10/include/lzo/lzoconf.h"
#include "3rdparty/lzo-2.10/include/lzo/lzodefs.h"
#include "3rdparty/zstd/lib/zstd.h"
#include "ace/ace.h"
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_decode_buffer(uint8_t * dst_buffer,
uint32_t * dst_size,
const uint8_t *src_buffer,
uint32_t src_size)
{
return BZ2_bzBuffToBuffDecompress((char *)dst_buffer, dst_size, (char *)src_buffer, src_size, 0, 0);
}
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_decode_buffer(uint8_t *dst_buffer, uint32_t *dst_size,
const uint8_t *src_buffer, uint32_t src_size)
{ return BZ2_bzBuffToBuffDecompress((char *)dst_buffer, dst_size, (char *)src_buffer, src_size, 0, 0); }
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_encode_buffer(uint8_t * dst_buffer,
uint32_t * dst_size,
const uint8_t *src_buffer,
uint32_t src_size,
int32_t blockSize100k)
{
return BZ2_bzBuffToBuffCompress((char *)dst_buffer, dst_size, (char *)src_buffer, src_size, blockSize100k, 0, 0);
}
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_encode_buffer(uint8_t *dst_buffer, uint32_t *dst_size,
const uint8_t *src_buffer, uint32_t src_size,
int32_t blockSize100k)
{ 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_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 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)
{
return lzfse_decode_buffer(dst_buffer, dst_size, src_buffer, src_size, scratch_buffer);
}
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)
{ return lzfse_decode_buffer(dst_buffer, dst_size, src_buffer, src_size, scratch_buffer); }
AARU_EXPORT size_t AARU_CALL AARU_lzfse_encode_buffer(uint8_t * dst_buffer,
size_t dst_size,
const uint8_t *src_buffer,
size_t src_size,
void * scratch_buffer)
{
return lzfse_encode_buffer(dst_buffer, dst_size, src_buffer, src_size, scratch_buffer);
}
AARU_EXPORT size_t AARU_CALL AARU_lzfse_encode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size, void *scratch_buffer)
{ return lzfse_encode_buffer(dst_buffer, dst_size, src_buffer, src_size, scratch_buffer); }
AARU_EXPORT size_t AARU_CALL AARU_lzvn_decode_buffer(uint8_t * dst_buffer,
size_t dst_size,
const uint8_t *src_buffer,
size_t src_size)
AARU_EXPORT size_t AARU_CALL AARU_lzvn_decode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size)
{
lzvn_decoder_state state;
memset(&state, 0, sizeof(state));
@@ -117,11 +90,8 @@ AARU_EXPORT size_t AARU_CALL AARU_lzvn_decode_buffer(uint8_t * dst_buffer,
return (size_t)(state.dst - dst_buffer);
}
AARU_EXPORT size_t AARU_CALL AARU_lzvn_encode_buffer(uint8_t * dst_buffer,
size_t dst_size,
const uint8_t *src_buffer,
size_t src_size,
void * scratch_buffer)
AARU_EXPORT size_t AARU_CALL AARU_lzvn_encode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size, void *scratch_buffer)
{
lzvn_encoder_state state;
memset(&state, 0, sizeof(state));
@@ -144,29 +114,14 @@ AARU_EXPORT size_t AARU_CALL AARU_lzvn_encode_buffer(uint8_t * dst_buffer,
return (size_t)(state.dst - dst_buffer);
}
AARU_EXPORT int32_t AARU_CALL AARU_lzma_decode_buffer(uint8_t * dst_buffer,
size_t * dst_size,
const uint8_t *src_buffer,
size_t * srcLen,
const uint8_t *props,
size_t propsSize)
{
return LzmaUncompress(dst_buffer, dst_size, src_buffer, srcLen, props, propsSize);
}
AARU_EXPORT int32_t AARU_CALL AARU_lzma_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t *srcLen, const uint8_t *props, size_t propsSize)
{ return LzmaUncompress(dst_buffer, dst_size, src_buffer, srcLen, props, propsSize); }
AARU_EXPORT int32_t AARU_CALL AARU_lzma_encode_buffer(uint8_t * dst_buffer,
size_t * dst_size,
const uint8_t *src_buffer,
size_t srcLen,
uint8_t * outProps,
size_t * outPropsSize,
int32_t level,
uint32_t dictSize,
int32_t lc,
int32_t lp,
int32_t pb,
int32_t fb,
int32_t numThreads)
AARU_EXPORT int32_t AARU_CALL AARU_lzma_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t srcLen, uint8_t *outProps, size_t *outPropsSize,
int32_t level, uint32_t dictSize, int32_t lc, int32_t lp,
int32_t pb, int32_t fb, int32_t numThreads)
{
return LzmaCompress(dst_buffer, dst_size, src_buffer, srcLen, outProps, outPropsSize, level, dictSize, lc, lp, pb,
fb, numThreads);
@@ -176,7 +131,7 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzma_encode_buffer(uint8_t * dst_buffer,
typedef struct
{
ISeqInStream vt;
const Byte * data;
const Byte *data;
size_t size;
size_t pos;
} CBufferInStream;
@@ -194,7 +149,7 @@ static SRes BufferInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
typedef struct
{
ISeqOutStream vt;
Byte * data;
Byte *data;
size_t size;
size_t pos;
} CBufferOutStream;
@@ -220,10 +175,8 @@ static void xz_init_crc_tables(void)
}
}
AARU_EXPORT int32_t AARU_CALL AARU_xz_decode_buffer(uint8_t * dst_buffer,
size_t * dst_size,
const uint8_t *src_buffer,
size_t src_size)
AARU_EXPORT int32_t AARU_CALL AARU_xz_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t src_size)
{
CXzUnpacker state;
SizeT destLen = (SizeT)*dst_size;
@@ -245,12 +198,8 @@ AARU_EXPORT int32_t AARU_CALL AARU_xz_decode_buffer(uint8_t * dst_buffer,
return res;
}
AARU_EXPORT int32_t AARU_CALL AARU_xz_encode_buffer(uint8_t * dst_buffer,
size_t * dst_size,
const uint8_t *src_buffer,
size_t src_size,
uint32_t preset,
uint32_t checkType)
AARU_EXPORT int32_t AARU_CALL AARU_xz_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t src_size, uint32_t preset, uint32_t checkType)
{
CXzProps props;
CBufferInStream inStream;
@@ -280,33 +229,21 @@ AARU_EXPORT int32_t AARU_CALL AARU_xz_encode_buffer(uint8_t * dst_buffer,
return res;
}
AARU_EXPORT size_t AARU_CALL AARU_zstd_decode_buffer(void * dst_buffer,
size_t dst_size,
const void *src_buffer,
size_t src_size)
{
return ZSTD_decompress(dst_buffer, dst_size, src_buffer, src_size);
}
AARU_EXPORT size_t AARU_CALL AARU_zstd_decode_buffer(void *dst_buffer, size_t dst_size, const void *src_buffer,
size_t src_size)
{ return ZSTD_decompress(dst_buffer, dst_size, src_buffer, src_size); }
AARU_EXPORT size_t AARU_CALL AARU_zstd_encode_buffer(void * dst_buffer,
size_t dst_size,
const void *src_buffer,
size_t src_size,
int32_t compressionLevel)
{
return ZSTD_compress(dst_buffer, dst_size, src_buffer, src_size, compressionLevel);
}
AARU_EXPORT size_t AARU_CALL AARU_zstd_encode_buffer(void *dst_buffer, size_t dst_size, const void *src_buffer,
size_t src_size, int32_t compressionLevel)
{ return ZSTD_compress(dst_buffer, dst_size, src_buffer, src_size, compressionLevel); }
AARU_EXPORT int32_t AARU_CALL AARU_lzo_decode_buffer(uint8_t * dst_buffer,
size_t * dst_size,
const uint8_t *src_buffer,
size_t src_size,
int32_t algorithm)
AARU_EXPORT int32_t AARU_CALL AARU_lzo_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t src_size, int32_t algorithm)
{
lzo_uint out_len = *dst_size;
int result = lzo_init();
if(result != LZO_E_OK) return result; // Initialization failed
if(result != LZO_E_OK) return result; // Initialization failed
switch(algorithm)
{
@@ -338,59 +275,74 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_decode_buffer(uint8_t * dst_buffer,
result = lzo2a_decompress_safe(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, NULL);
break;
default:
return -1; // Invalid algorithm
return -1; // Invalid algorithm
}
*dst_size = out_len;
return result;
}
AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
size_t * dst_size,
const uint8_t *src_buffer,
size_t src_size,
int32_t algorithm,
int32_t compression_level)
AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t src_size, int32_t algorithm, int32_t compression_level)
{
lzo_uint out_len = *dst_size;
void * wrkmem = NULL;
void *wrkmem = NULL;
size_t wrkmem_size = 0;
// Determine work memory size based on algorithm and compression level
switch(algorithm)
{
case AARU_LZO_ALGORITHM_LZO1:
if(compression_level == 99) wrkmem_size = LZO1_99_MEM_COMPRESS;
else wrkmem_size = LZO1_MEM_COMPRESS;
if(compression_level == 99)
wrkmem_size = LZO1_99_MEM_COMPRESS;
else
wrkmem_size = LZO1_MEM_COMPRESS;
break;
case AARU_LZO_ALGORITHM_LZO1A:
if(compression_level == 99) wrkmem_size = LZO1A_99_MEM_COMPRESS;
else wrkmem_size = LZO1A_MEM_COMPRESS;
if(compression_level == 99)
wrkmem_size = LZO1A_99_MEM_COMPRESS;
else
wrkmem_size = LZO1A_MEM_COMPRESS;
break;
case AARU_LZO_ALGORITHM_LZO1B:
if(compression_level == 99) wrkmem_size = LZO1B_99_MEM_COMPRESS;
else if(compression_level == 999) wrkmem_size = LZO1B_999_MEM_COMPRESS;
else wrkmem_size = LZO1B_MEM_COMPRESS;
if(compression_level == 99)
wrkmem_size = LZO1B_99_MEM_COMPRESS;
else if(compression_level == 999)
wrkmem_size = LZO1B_999_MEM_COMPRESS;
else
wrkmem_size = LZO1B_MEM_COMPRESS;
break;
case AARU_LZO_ALGORITHM_LZO1C:
if(compression_level == 99) wrkmem_size = LZO1C_99_MEM_COMPRESS;
else if(compression_level == 999) wrkmem_size = LZO1C_999_MEM_COMPRESS;
else wrkmem_size = LZO1C_MEM_COMPRESS;
if(compression_level == 99)
wrkmem_size = LZO1C_99_MEM_COMPRESS;
else if(compression_level == 999)
wrkmem_size = LZO1C_999_MEM_COMPRESS;
else
wrkmem_size = LZO1C_MEM_COMPRESS;
break;
case AARU_LZO_ALGORITHM_LZO1F:
if(compression_level == 999) wrkmem_size = LZO1F_999_MEM_COMPRESS;
else wrkmem_size = LZO1F_MEM_COMPRESS;
if(compression_level == 999)
wrkmem_size = LZO1F_999_MEM_COMPRESS;
else
wrkmem_size = LZO1F_MEM_COMPRESS;
break;
case AARU_LZO_ALGORITHM_LZO1X:
if(compression_level == 11) wrkmem_size = LZO1X_1_11_MEM_COMPRESS;
else if(compression_level == 12) wrkmem_size = LZO1X_1_12_MEM_COMPRESS;
else if(compression_level == 15) wrkmem_size = LZO1X_1_15_MEM_COMPRESS;
else if(compression_level == 999) wrkmem_size = LZO1X_999_MEM_COMPRESS;
else wrkmem_size = LZO1X_1_MEM_COMPRESS;
if(compression_level == 11)
wrkmem_size = LZO1X_1_11_MEM_COMPRESS;
else if(compression_level == 12)
wrkmem_size = LZO1X_1_12_MEM_COMPRESS;
else if(compression_level == 15)
wrkmem_size = LZO1X_1_15_MEM_COMPRESS;
else if(compression_level == 999)
wrkmem_size = LZO1X_999_MEM_COMPRESS;
else
wrkmem_size = LZO1X_1_MEM_COMPRESS;
break;
case AARU_LZO_ALGORITHM_LZO1Y:
if(compression_level == 999) wrkmem_size = LZO1Y_999_MEM_COMPRESS;
else wrkmem_size = LZO1Y_MEM_COMPRESS;
if(compression_level == 999)
wrkmem_size = LZO1Y_999_MEM_COMPRESS;
else
wrkmem_size = LZO1Y_MEM_COMPRESS;
break;
case AARU_LZO_ALGORITHM_LZO1Z:
wrkmem_size = LZO1Z_999_MEM_COMPRESS;
@@ -399,11 +351,11 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
wrkmem_size = LZO2A_999_MEM_COMPRESS;
break;
default:
return -1; // Invalid algorithm
return -1; // Invalid algorithm
}
int result = lzo_init();
if(result != LZO_E_OK) return result; // Initialization failed
if(result != LZO_E_OK) return result; // Initialization failed
wrkmem = malloc(wrkmem_size);
if(wrkmem == NULL) return -1;
@@ -413,13 +365,15 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
{
case AARU_LZO_ALGORITHM_LZO1:
if(compression_level == 99)
result = lzo1_99_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else result = lzo1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
result = lzo1_99_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else
result = lzo1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
break;
case AARU_LZO_ALGORITHM_LZO1A:
if(compression_level == 99)
result = lzo1a_99_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else result = lzo1a_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
result = lzo1a_99_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else
result = lzo1a_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
break;
case AARU_LZO_ALGORITHM_LZO1B:
if(compression_level == 99)
@@ -427,8 +381,8 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
else if(compression_level == 999)
result = lzo1b_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else if(compression_level >= 1 && compression_level <= 9)
result = lzo1b_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem,
compression_level);
result =
lzo1b_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem, compression_level);
else
result = lzo1b_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem,
LZO1B_DEFAULT_COMPRESSION);
@@ -439,16 +393,17 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
else if(compression_level == 999)
result = lzo1c_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else if(compression_level >= 1 && compression_level <= 9)
result = lzo1c_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem,
compression_level);
result =
lzo1c_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem, compression_level);
else
result = lzo1c_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem,
LZO1C_DEFAULT_COMPRESSION);
break;
case AARU_LZO_ALGORITHM_LZO1F:
if(compression_level == 999)
result = lzo1f_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else result = lzo1f_1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
result = lzo1f_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else
result = lzo1f_1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
break;
case AARU_LZO_ALGORITHM_LZO1X:
if(compression_level == 11)
@@ -458,13 +413,15 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
else if(compression_level == 15)
result = lzo1x_1_15_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else if(compression_level == 999)
result = lzo1x_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else result = lzo1x_1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
result = lzo1x_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else
result = lzo1x_1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
break;
case AARU_LZO_ALGORITHM_LZO1Y:
if(compression_level == 999)
result = lzo1y_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else result = lzo1y_1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
result = lzo1y_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
else
result = lzo1y_1_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
break;
case AARU_LZO_ALGORITHM_LZO1Z:
result = lzo1z_999_compress(src_buffer, (lzo_uint)src_size, dst_buffer, &out_len, wrkmem);
@@ -474,7 +431,7 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
break;
default:
free(wrkmem);
return -1; // Invalid algorithm
return -1; // Invalid algorithm
}
free(wrkmem);
@@ -485,4 +442,32 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzo_encode_buffer(uint8_t * dst_buffer,
// This is required if BZ_NO_STDIO
void bz_internal_error(int errcode) {}
AARU_EXPORT int AARU_CALL ace_decompress_lz77(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len,
int dic_bits)
{
ace_decompress_ctx_t ctx;
int ret;
if(ace_decompress_init(&ctx, dic_bits) != 0) return -1;
ret = ace_decompress_v1(&ctx, in_buf, in_len, out_buf, out_len);
ace_decompress_free(&ctx);
return ret;
}
AARU_EXPORT int AARU_CALL ace_decompress_blocked(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf,
size_t *out_len, int dic_bits)
{
ace_decompress_ctx_t ctx;
int ret;
if(ace_decompress_init(&ctx, dic_bits) != 0) return -1;
ret = ace_decompress_v2(&ctx, in_buf, in_len, out_buf, out_len);
ace_decompress_free(&ctx);
return ret;
}
AARU_EXPORT uint64_t AARU_CALL AARU_get_acn_version() { return AARU_CHECKUMS_NATIVE_VERSION; }

View File

@@ -234,4 +234,10 @@ AARU_EXPORT int AARU_CALL pmarc_decompress_pm1(const uint8_t *in_buf, size_t in_
// PMarc -pm2- (Dynamic trees + history, legacy)
AARU_EXPORT int AARU_CALL pmarc_decompress_pm2(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len);
// ACE v1 (LZ77) decompression
AARU_EXPORT int AARU_CALL ace_decompress_lz77(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len, int dic_bits);
// ACE v2 (Blocked) decompression
AARU_EXPORT int AARU_CALL ace_decompress_blocked(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len, int dic_bits);
#endif // AARU_COMPRESSION_NATIVE_LIBRARY_H

View File

@@ -90,10 +90,17 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/lharc_lh1.lzh
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/pmarc_pm2.pma
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/ace_v1_lz77.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/ace_v2_blocked.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
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 xz.cpp
lha/lh_static.cpp lha/lh1.cpp lha/larc.cpp lha/lh_old.cpp)
lha/lh_static.cpp lha/lh1.cpp lha/larc.cpp lha/lh_old.cpp
ace/ace.cpp)
target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native")

116
tests/ace/ace.cpp Normal file
View File

@@ -0,0 +1,116 @@
/*
* 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 <climits>
#include <cstddef>
#include <cstdint>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer_v1;
static const uint8_t *buffer_v2;
class ace_v1Fixture : public ::testing::Test
{
public:
ace_v1Fixture() {}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/ace_v1_lz77.bin", path);
FILE *file = fopen(filename, "rb");
buffer_v1 = (const uint8_t *)malloc(54904);
fread((void *)buffer_v1, 1, 54904, file);
fclose(file);
}
void TearDown() { free((void *)buffer_v1); }
~ace_v1Fixture() {}
};
TEST_F(ace_v1Fixture, ace_v1_lz77)
{
size_t destLen = 152089;
size_t srcLen = 54904;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = ace_decompress_lz77(buffer_v1, srcLen, outBuf, &destLen, 20);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}
class ace_v2Fixture : public ::testing::Test
{
public:
ace_v2Fixture() {}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/ace_v2_blocked.bin", path);
FILE *file = fopen(filename, "rb");
buffer_v2 = (const uint8_t *)malloc(50984);
fread((void *)buffer_v2, 1, 50984, file);
fclose(file);
}
void TearDown() { free((void *)buffer_v2); }
~ace_v2Fixture() {}
};
TEST_F(ace_v2Fixture, ace_v2_blocked)
{
size_t destLen = 152089;
size_t srcLen = 50984;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = ace_decompress_blocked(buffer_v2, srcLen, outBuf, &destLen, 20);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

BIN
tests/data/ace_v1_lz77.bin Normal file

Binary file not shown.

Binary file not shown.