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
}