|
kusano |
7d535a |
// LZ4frame API example : compress a file
|
|
kusano |
7d535a |
// Based on sample code from Zbigniew Jędrzejewski-Szmek
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#include <stdio.h></stdio.h>
|
|
kusano |
7d535a |
#include <stdlib.h></stdlib.h>
|
|
kusano |
7d535a |
#include <string.h></string.h>
|
|
kusano |
7d535a |
#include <errno.h></errno.h>
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#include <lz4frame.h></lz4frame.h>
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
#define BUF_SIZE (16*1024)
|
|
kusano |
7d535a |
#define LZ4_HEADER_SIZE 19
|
|
kusano |
7d535a |
#define LZ4_FOOTER_SIZE 4
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static const LZ4F_preferences_t lz4_preferences = {
|
|
kusano |
7d535a |
{ LZ4F_max256KB, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0, { 0, 0 } },
|
|
kusano |
7d535a |
0, /* compression level */
|
|
kusano |
7d535a |
0, /* autoflush */
|
|
kusano |
7d535a |
{ 0, 0, 0, 0 }, /* reserved, must be set to 0 */
|
|
kusano |
7d535a |
};
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static int compress_file(FILE *in, FILE *out, size_t *size_in, size_t *size_out) {
|
|
kusano |
7d535a |
LZ4F_errorCode_t r;
|
|
kusano |
7d535a |
LZ4F_compressionContext_t ctx;
|
|
kusano |
7d535a |
char *src, *buf = NULL;
|
|
kusano |
7d535a |
size_t size, n, k, count_in = 0, count_out, offset = 0, frame_size;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
r = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
|
|
kusano |
7d535a |
if (LZ4F_isError(r)) {
|
|
kusano |
7d535a |
printf("Failed to create context: error %zu", r);
|
|
kusano |
7d535a |
return 1;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
r = 1;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
src = malloc(BUF_SIZE);
|
|
kusano |
7d535a |
if (!src) {
|
|
kusano |
7d535a |
printf("Not enough memory");
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
frame_size = LZ4F_compressBound(BUF_SIZE, &lz4_preferences);
|
|
kusano |
7d535a |
size = frame_size + LZ4_HEADER_SIZE + LZ4_FOOTER_SIZE;
|
|
kusano |
7d535a |
buf = malloc(size);
|
|
kusano |
7d535a |
if (!buf) {
|
|
kusano |
7d535a |
printf("Not enough memory");
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
n = offset = count_out = LZ4F_compressBegin(ctx, buf, size, &lz4_preferences);
|
|
kusano |
7d535a |
if (LZ4F_isError(n)) {
|
|
kusano |
7d535a |
printf("Failed to start compression: error %zu", n);
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
printf("Buffer size is %zu bytes, header size %zu bytes\n", size, n);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
for (;;) {
|
|
kusano |
7d535a |
k = fread(src, 1, BUF_SIZE, in);
|
|
kusano |
7d535a |
if (k == 0)
|
|
kusano |
7d535a |
break;
|
|
kusano |
7d535a |
count_in += k;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
n = LZ4F_compressUpdate(ctx, buf + offset, size - offset, src, k, NULL);
|
|
kusano |
7d535a |
if (LZ4F_isError(n)) {
|
|
kusano |
7d535a |
printf("Compression failed: error %zu", n);
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
offset += n;
|
|
kusano |
7d535a |
count_out += n;
|
|
kusano |
7d535a |
if (size - offset < frame_size + LZ4_FOOTER_SIZE) {
|
|
kusano |
7d535a |
printf("Writing %zu bytes\n", offset);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
k = fwrite(buf, 1, offset, out);
|
|
kusano |
7d535a |
if (k < offset) {
|
|
kusano |
7d535a |
if (ferror(out))
|
|
kusano |
7d535a |
printf("Write failed");
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
printf("Short write");
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
offset = 0;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
n = LZ4F_compressEnd(ctx, buf + offset, size - offset, NULL);
|
|
kusano |
7d535a |
if (LZ4F_isError(n)) {
|
|
kusano |
7d535a |
printf("Failed to end compression: error %zu", n);
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
offset += n;
|
|
kusano |
7d535a |
count_out += n;
|
|
kusano |
7d535a |
printf("Writing %zu bytes\n", offset);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
k = fwrite(buf, 1, offset, out);
|
|
kusano |
7d535a |
if (k < offset) {
|
|
kusano |
7d535a |
if (ferror(out))
|
|
kusano |
7d535a |
printf("Write failed");
|
|
kusano |
7d535a |
else
|
|
kusano |
7d535a |
printf("Short write");
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
*size_in = count_in;
|
|
kusano |
7d535a |
*size_out = count_out;
|
|
kusano |
7d535a |
r = 0;
|
|
kusano |
7d535a |
cleanup:
|
|
kusano |
7d535a |
if (ctx)
|
|
kusano |
7d535a |
LZ4F_freeCompressionContext(ctx);
|
|
kusano |
7d535a |
free(src);
|
|
kusano |
7d535a |
free(buf);
|
|
kusano |
7d535a |
return r;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
static int compress(const char *input, const char *output) {
|
|
kusano |
7d535a |
char *tmp = NULL;
|
|
kusano |
7d535a |
FILE *in = NULL, *out = NULL;
|
|
kusano |
7d535a |
size_t size_in = 0, size_out = 0;
|
|
kusano |
7d535a |
int r = 1;
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
if (!output) {
|
|
kusano |
7d535a |
size_t len = strlen(input);
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
output = tmp = malloc(len + 5);
|
|
kusano |
7d535a |
if (!tmp) {
|
|
kusano |
7d535a |
printf("Not enough memory");
|
|
kusano |
7d535a |
return 1;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
strcpy(tmp, input);
|
|
kusano |
7d535a |
strcpy(tmp + len, ".lz4");
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
in = fopen(input, "rb");
|
|
kusano |
7d535a |
if (!in) {
|
|
kusano |
7d535a |
fprintf(stderr, "Failed to open input file %s: %s\n", input, strerror(errno));
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
out = fopen(output, "wb");
|
|
kusano |
7d535a |
if (!out) {
|
|
kusano |
7d535a |
fprintf(stderr, "Failed to open output file %s: %s\n", output, strerror(errno));
|
|
kusano |
7d535a |
goto cleanup;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
r = compress_file(in, out, &size_in, &size_out);
|
|
kusano |
7d535a |
if (r == 0)
|
|
kusano |
7d535a |
printf("%s: %zu → %zu bytes, %.1f%%\n",
|
|
kusano |
7d535a |
input, size_in, size_out,
|
|
kusano |
7d535a |
(double)size_out / size_in * 100);
|
|
kusano |
7d535a |
cleanup:
|
|
kusano |
7d535a |
if (in)
|
|
kusano |
7d535a |
fclose(in);
|
|
kusano |
7d535a |
if (out)
|
|
kusano |
7d535a |
fclose(out);
|
|
kusano |
7d535a |
free(tmp);
|
|
kusano |
7d535a |
return r;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
int main(int argc, char **argv) {
|
|
kusano |
7d535a |
if (argc < 2 || argc > 3) {
|
|
kusano |
7d535a |
fprintf(stderr, "Syntax: %s <input> <output>\n", argv[0]);</output>
|
|
kusano |
7d535a |
return EXIT_FAILURE;
|
|
kusano |
7d535a |
}
|
|
kusano |
7d535a |
|
|
kusano |
7d535a |
return compress(argv[1], argv[2]);
|
|
kusano |
7d535a |
}
|