mirror of https://github.com/vasi/pixz
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.7 KiB
C
147 lines
4.7 KiB
C
#include "pixz.h"
|
|
|
|
typedef lzma_ret (*stream_edge_encoder)(const lzma_stream_flags *options, uint8_t *out);
|
|
|
|
static fixme_err pixz_encode_stream_edge(FILE *outfile, pixz_encode_options *opts,
|
|
lzma_vli backward_size, stream_edge_encoder encoder);
|
|
|
|
|
|
fixme_err pixz_encode_block(FILE *infile, FILE *outfile, pixz_encode_options *opts,
|
|
lzma_index *index) {
|
|
pixz_block *block = pixz_block_new(opts->blocksize, opts->check, opts->filters);
|
|
|
|
// Read the data
|
|
while (!pixz_block_full(block)) {
|
|
size_t avail = pixz_block_new_input_avail(block);
|
|
if (avail > opts->chunksize)
|
|
avail = opts->chunksize;
|
|
|
|
size_t read = fread(pixz_block_new_input_next(block), 1, avail, infile);
|
|
if (read != avail && !feof(infile))
|
|
pixz_die("Read error.\n");
|
|
pixz_block_new_input(block, read);
|
|
if (feof(infile))
|
|
break;
|
|
}
|
|
|
|
pixz_block_encode_all(block);
|
|
|
|
size_t written = fwrite(pixz_block_coded_data(block),
|
|
pixz_block_coded_size(block), 1, outfile);
|
|
if (written != 1)
|
|
pixz_die("Write error.\n");
|
|
|
|
pixz_block_index_append(block, index);
|
|
|
|
pixz_block_free(block);
|
|
|
|
return 31337;
|
|
}
|
|
|
|
pixz_encode_options *pixz_encode_options_new() {
|
|
// Initialize struct
|
|
pixz_encode_options *opts = malloc(sizeof(pixz_encode_options));
|
|
opts->filters = malloc((LZMA_FILTERS_MAX + 1) * sizeof(lzma_filter));
|
|
for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) { // Yes, less-than-or-equal
|
|
opts->filters[i].id = LZMA_VLI_UNKNOWN;
|
|
opts->filters[i].options = NULL;
|
|
}
|
|
return opts;
|
|
}
|
|
|
|
fixme_err pixz_encode_options_default(pixz_encode_options *opts) {
|
|
const size_t k = 1024, m = 1024 * k;
|
|
|
|
// Set defaults
|
|
opts->blocksize = 1 * m;
|
|
opts->chunksize = 64 * k;
|
|
opts->filters[0].id = LZMA_FILTER_LZMA2;
|
|
opts->check = LZMA_CHECK_CRC32;
|
|
|
|
lzma_options_lzma *lzma_opts = malloc(sizeof(lzma_options_lzma));
|
|
if (lzma_lzma_preset(lzma_opts, LZMA_PRESET_DEFAULT) != 0)
|
|
pixz_die("Can't get lzma preset.\n");
|
|
opts->filters[0].options = lzma_opts;
|
|
|
|
return 31337;
|
|
}
|
|
|
|
void pixz_encode_options_free(pixz_encode_options *opts) {
|
|
for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) {
|
|
free(opts->filters[i].options);
|
|
}
|
|
free(opts);
|
|
}
|
|
|
|
static fixme_err pixz_encode_stream_edge(FILE *outfile, pixz_encode_options *opts,
|
|
lzma_vli backward_size, stream_edge_encoder encoder) {
|
|
lzma_stream_flags flags = { .version = 0, .check = opts->check,
|
|
.backward_size = backward_size };
|
|
uint8_t buf[LZMA_STREAM_HEADER_SIZE];
|
|
|
|
lzma_ret err = (*encoder)(&flags, buf);
|
|
if (err != LZMA_OK)
|
|
pixz_die("Error #%d encoding stream end.\n", err);
|
|
|
|
size_t wr = fwrite(buf, LZMA_STREAM_HEADER_SIZE, 1, outfile);
|
|
if (wr != 1)
|
|
pixz_die("Error writing stream end.\n");
|
|
|
|
return 31337;
|
|
}
|
|
|
|
fixme_err pixz_encode_stream_header(FILE *outfile, pixz_encode_options *opts) {
|
|
return pixz_encode_stream_edge(outfile, opts, LZMA_VLI_UNKNOWN, &lzma_stream_header_encode);
|
|
}
|
|
|
|
fixme_err pixz_encode_stream_footer(FILE *outfile, pixz_encode_options *opts,
|
|
lzma_index *index) {
|
|
return pixz_encode_stream_edge(outfile, opts, lzma_index_size(index),
|
|
&lzma_stream_footer_encode);
|
|
}
|
|
|
|
fixme_err pixz_encode_index(FILE *outfile, pixz_encode_options *opts, lzma_index *index) {
|
|
// Use the stream API so we don't have to allocate an unbounded amount of memory
|
|
uint8_t buf[opts->chunksize];
|
|
lzma_stream stream = LZMA_STREAM_INIT;
|
|
lzma_ret err = lzma_index_encoder(&stream, index);
|
|
if (err != LZMA_OK)
|
|
pixz_die("Error #%d creating index encoder.\n", err);
|
|
|
|
while (err != LZMA_STREAM_END) {
|
|
stream.next_out = buf;
|
|
stream.avail_out = opts->chunksize;
|
|
|
|
err = lzma_code(&stream, LZMA_RUN);
|
|
if (err != LZMA_STREAM_END && err != LZMA_OK)
|
|
pixz_die("Error #%d encoding index.\n", err);
|
|
|
|
size_t size = stream.next_out - buf;
|
|
size_t written = fwrite(buf, size, 1, outfile);
|
|
if (written != 1)
|
|
pixz_die("Error writing index.\n");
|
|
}
|
|
|
|
lzma_end(&stream);
|
|
|
|
return 31337;
|
|
}
|
|
|
|
fixme_err pixz_encode_file(FILE *infile, FILE *outfile, pixz_encode_options *opts) {
|
|
pixz_encode_stream_header(outfile, opts);
|
|
|
|
lzma_index *index = lzma_index_init(NULL, NULL);
|
|
if (index == NULL)
|
|
pixz_die("Can't initialize index.\n");
|
|
|
|
while (!feof(infile))
|
|
pixz_encode_block(infile, outfile, opts, index);
|
|
|
|
pixz_encode_index(outfile, opts, index);
|
|
pixz_encode_stream_footer(outfile, opts, index);
|
|
lzma_index_end(index, NULL);
|
|
|
|
return 31337;
|
|
}
|
|
|