// LZ4frame API example : compress a file // Based on sample code from Zbigniew Jędrzejewski-Szmek #include #include #include #include #include #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 \n", argv[0]); return EXIT_FAILURE; } return compress(argv[1], argv[2]); }