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