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.
202 lines
5.9 KiB
C
202 lines
5.9 KiB
C
15 years ago
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
15 years ago
|
#include <stdarg.h>
|
||
15 years ago
|
|
||
|
#include "lzma.h"
|
||
|
|
||
15 years ago
|
|
||
15 years ago
|
#define DEFAULT_CHUNKSIZE (1024 * 1024)
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
size_t (*read)(void *data, uint8_t *buf, size_t size, int *eofp);
|
||
|
void *data;
|
||
|
} reader;
|
||
|
|
||
|
typedef struct {
|
||
|
// Return non-zero on error
|
||
|
size_t (*write)(void *data, const uint8_t *buf, size_t size);
|
||
|
void *data;
|
||
|
} writer;
|
||
|
|
||
|
typedef struct {
|
||
|
reader rd;
|
||
|
writer wr;
|
||
|
size_t chunksize;
|
||
|
lzma_stream_flags stream_flags;
|
||
|
|
||
|
lzma_filter filters[LZMA_FILTERS_MAX + 1];
|
||
|
} encode_options;
|
||
|
|
||
|
|
||
|
void die(const char *fmt, ...);
|
||
|
|
||
|
void file_reader(reader *rd, FILE *file);
|
||
|
size_t file_read(void *data, uint8_t *buf, size_t size, int *eofp);
|
||
|
void file_writer(writer *wr, FILE *file);
|
||
|
size_t file_write(void *data, const uint8_t *buf, size_t size);
|
||
|
|
||
|
void encode_stream_end(encode_options *eo, lzma_vli backward_size);
|
||
|
void encode_file(FILE *in, FILE *out);
|
||
|
void encode_stream_header(encode_options *eo);
|
||
|
void encode_block(encode_options *eo, lzma_block *block);
|
||
|
lzma_vli encode_index(encode_options *eo, lzma_block *blocks, size_t nblocks);
|
||
|
|
||
|
void encode(lzma_stream *stream, size_t chunksize, reader *rd, writer *wr);
|
||
15 years ago
|
|
||
|
int main(void) {
|
||
15 years ago
|
encode_file(stdin, stdout);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void die(const char *fmt, ...) {
|
||
|
va_list args;
|
||
|
va_start(args, fmt);
|
||
|
vfprintf(stderr, fmt, args);
|
||
|
fflush(stderr);
|
||
|
va_end(args);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void encode_file(FILE *in, FILE *out) {
|
||
|
lzma_options_lzma filt_options;
|
||
|
if (lzma_lzma_preset(&filt_options, LZMA_PRESET_DEFAULT))
|
||
|
die("Error determining filter options.\n");
|
||
15 years ago
|
|
||
15 years ago
|
encode_options eo = {
|
||
|
.chunksize = DEFAULT_CHUNKSIZE,
|
||
|
.stream_flags = { .version = 0, .check = LZMA_CHECK_CRC32 },
|
||
|
.filters = {
|
||
|
{ .id = LZMA_FILTER_LZMA2, .options = &filt_options },
|
||
|
{ .id = LZMA_VLI_UNKNOWN }
|
||
|
}
|
||
|
};
|
||
|
file_reader(&eo.rd, in);
|
||
|
file_writer(&eo.wr, out);
|
||
15 years ago
|
|
||
15 years ago
|
encode_stream_end(&eo, LZMA_VLI_UNKNOWN);
|
||
|
lzma_block block;
|
||
|
encode_block(&eo, &block);
|
||
|
lzma_vli backward = encode_index(&eo, &block, 1);
|
||
|
encode_stream_end(&eo, backward);
|
||
|
}
|
||
|
|
||
|
void file_reader(reader *rd, FILE *file) {
|
||
|
rd->read = &file_read;
|
||
|
rd->data = file;
|
||
|
}
|
||
|
|
||
|
size_t file_read(void *data, uint8_t *buf, size_t size, int *eofp) {
|
||
|
FILE *file = (FILE*)data;
|
||
|
size_t io = fread(buf, 1, size, file);
|
||
15 years ago
|
|
||
15 years ago
|
if (eofp)
|
||
|
*eofp = feof(file);
|
||
|
return io;
|
||
|
}
|
||
|
|
||
|
void file_writer(writer *wr, FILE *file) {
|
||
|
wr->write = &file_write;
|
||
|
wr->data = file;
|
||
|
}
|
||
|
|
||
|
size_t file_write(void *data, const uint8_t *buf, size_t size) {
|
||
|
FILE *file = (FILE*)data;
|
||
|
return fwrite(buf, 1, size, file);
|
||
|
}
|
||
|
|
||
|
void encode_block(encode_options *eo, lzma_block *block) {
|
||
|
block->version = 0;
|
||
|
block->check = eo->stream_flags.check;
|
||
|
block->filters = eo->filters;
|
||
|
block->compressed_size = block->uncompressed_size = LZMA_VLI_UNKNOWN;
|
||
|
|
||
|
// Write the header
|
||
|
lzma_ret err = lzma_block_header_size(block);
|
||
|
if (LZMA_OK != err)
|
||
|
die("Error #%d determining size of block header.\n", err);
|
||
|
uint8_t header[block->header_size];
|
||
|
err = lzma_block_header_encode(block, header);
|
||
|
if (LZMA_OK != err)
|
||
|
die("Error #%d encoding block header.\n", err);
|
||
|
size_t wr = eo->wr.write(eo->wr.data, header, block->header_size);
|
||
|
if (wr != LZMA_STREAM_HEADER_SIZE)
|
||
|
die("Error writing stream header.\n");
|
||
|
|
||
|
// Write the data
|
||
|
lzma_stream stream = LZMA_STREAM_INIT;
|
||
|
err = lzma_block_encoder(&stream, block);
|
||
|
if (err)
|
||
|
die("Error #%d creating block encoder.\n", err);
|
||
|
encode(&stream, eo->chunksize, &eo->rd, &eo->wr);
|
||
|
}
|
||
|
|
||
|
void encode(lzma_stream *stream, size_t chunksize, reader *rd, writer *wr) {
|
||
|
uint8_t inbuf[chunksize], outbuf[chunksize];
|
||
|
|
||
|
lzma_ret err = LZMA_OK;
|
||
|
stream->avail_in = 0;
|
||
|
stream->next_in = inbuf;
|
||
15 years ago
|
do {
|
||
15 years ago
|
stream->next_out = outbuf;
|
||
|
stream->avail_out = chunksize;
|
||
15 years ago
|
|
||
|
lzma_action action;
|
||
15 years ago
|
if (rd && stream->avail_in == 0) {
|
||
|
int eof = 0;
|
||
|
stream->avail_in = rd->read(rd->data, inbuf, chunksize, &eof);
|
||
|
if (!eof && stream->avail_in != chunksize)
|
||
|
die("Read error during encoding.\n");
|
||
|
stream->next_in = inbuf;
|
||
|
action = eof ? LZMA_FINISH : LZMA_RUN;
|
||
15 years ago
|
}
|
||
|
|
||
15 years ago
|
err = lzma_code(stream, action);
|
||
|
if (LZMA_OK != err && LZMA_STREAM_END != err)
|
||
|
die("Error #%d while encoding.\n", err);
|
||
15 years ago
|
|
||
15 years ago
|
size_t write_bytes = chunksize - stream->avail_out;
|
||
|
if (wr->write(wr->data, outbuf, write_bytes) != write_bytes)
|
||
|
die("Write error during encoding.\n");
|
||
15 years ago
|
} while (LZMA_STREAM_END != err);
|
||
|
}
|
||
15 years ago
|
|
||
15 years ago
|
lzma_vli encode_index(encode_options *eo, lzma_block *blocks, size_t nblocks) {
|
||
|
lzma_ret err;
|
||
|
lzma_index *index = lzma_index_init(NULL, NULL);
|
||
|
for (int i = 0; i < nblocks; ++i) {
|
||
|
err = lzma_index_append(index, NULL,
|
||
|
lzma_block_unpadded_size(&blocks[i]),
|
||
|
blocks[i].uncompressed_size);
|
||
|
if (LZMA_OK != err)
|
||
|
die("Error #%d appending record to index.\n", err);
|
||
|
}
|
||
15 years ago
|
|
||
15 years ago
|
lzma_stream stream = LZMA_STREAM_INIT;
|
||
|
err = lzma_index_encoder(&stream, index);
|
||
|
if (LZMA_OK != err)
|
||
|
die("Error #%d creating index encoder.\n", err);
|
||
|
|
||
|
encode(&stream, eo->chunksize, NULL, &eo->wr);
|
||
|
|
||
|
lzma_vli size = lzma_index_size(index);
|
||
|
lzma_index_end(index, NULL);
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
void encode_stream_end(encode_options *eo, lzma_vli backward_size) {
|
||
|
uint8_t buf[LZMA_STREAM_HEADER_SIZE];
|
||
|
eo->stream_flags.backward_size = backward_size;
|
||
15 years ago
|
|
||
15 years ago
|
lzma_ret err = (backward_size == LZMA_VLI_UNKNOWN
|
||
|
? &lzma_stream_header_encode
|
||
|
: &lzma_stream_footer_encode
|
||
|
)(&eo->stream_flags, buf);
|
||
|
if (LZMA_OK != err)
|
||
|
die("Error #%d encoding stream end.\n", err);
|
||
|
size_t wr = eo->wr.write(eo->wr.data, buf, LZMA_STREAM_HEADER_SIZE);
|
||
|
if (wr != LZMA_STREAM_HEADER_SIZE)
|
||
|
die("Error writing stream end.\n");
|
||
15 years ago
|
}
|