Last active
August 29, 2015 14:02
-
-
Save t-mat/cdb1bffe0f9664e968d1 to your computer and use it in GitHub Desktop.
LZ4 streaming API example (double buffer)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// LZ4 streaming API example | |
#define _CRT_SECURE_NO_WARNINGS // for MSVC | |
#include "lz4.h" | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
enum { | |
BLOCK_BYTES = 1024 * 8, | |
// BLOCK_BYTES = 1024 * 64, | |
}; | |
size_t write_int(FILE* fp, int i) { | |
return fwrite(&i, sizeof(i), 1, fp); | |
} | |
size_t write_bin(FILE* fp, const void* array, size_t arrayBytes) { | |
return fwrite(array, 1, arrayBytes, fp); | |
} | |
size_t read_int(FILE* fp, int* i) { | |
return fread(i, sizeof(*i), 1, fp); | |
} | |
size_t read_bin(FILE* fp, void* array, size_t arrayBytes) { | |
return fread(array, 1, arrayBytes, fp); | |
} | |
void test_compress(FILE* outFp, FILE* inpFp) | |
{ | |
LZ4_stream_t lz4Stream_body = { 0 }; | |
LZ4_stream_t* lz4Stream = &lz4Stream_body; | |
char inpBuf[2][BLOCK_BYTES]; | |
int inpBufIndex = 0; | |
for(;;) { | |
char* const inpPtr = inpBuf[inpBufIndex]; | |
const int inpBytes = (int) read_bin(inpFp, inpPtr, BLOCK_BYTES); | |
if(0 == inpBytes) { | |
break; | |
} | |
{ | |
char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)]; | |
const int cmpBytes = LZ4_compress_continue( | |
lz4Stream, inpPtr, cmpBuf, inpBytes); | |
if(cmpBytes <= 0) { | |
break; | |
} | |
write_int(outFp, cmpBytes); | |
write_bin(outFp, cmpBuf, (size_t) cmpBytes); | |
} | |
inpBufIndex = (inpBufIndex + 1) % 2; | |
} | |
write_int(outFp, 0); | |
} | |
void test_decompress(FILE* outFp, FILE* inpFp) | |
{ | |
LZ4_streamDecode_t lz4StreamDecode_body = { 0 }; | |
LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body; | |
char decBuf[2][BLOCK_BYTES]; | |
int decBufIndex = 0; | |
for(;;) { | |
char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)]; | |
int cmpBytes = 0; | |
{ | |
const size_t readCount0 = read_int(inpFp, &cmpBytes); | |
if(readCount0 != 1 || cmpBytes <= 0) { | |
break; | |
} | |
const size_t readCount1 = read_bin(inpFp, cmpBuf, (size_t) cmpBytes); | |
if(readCount1 != (size_t) cmpBytes) { | |
break; | |
} | |
} | |
{ | |
char* const decPtr = decBuf[decBufIndex]; | |
const int decBytes = LZ4_decompress_safe_continue( | |
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, BLOCK_BYTES); | |
if(decBytes <= 0) { | |
break; | |
} | |
write_bin(outFp, decPtr, (size_t) decBytes); | |
} | |
decBufIndex = (decBufIndex + 1) % 2; | |
} | |
} | |
int compare(FILE* fp0, FILE* fp1) | |
{ | |
int result = 0; | |
while(0 == result) { | |
char b0[65536]; | |
char b1[65536]; | |
const size_t r0 = read_bin(fp0, b0, sizeof(b0)); | |
const size_t r1 = read_bin(fp1, b1, sizeof(b1)); | |
result = (int) r0 - (int) r1; | |
if(0 == r0 || 0 == r1) { | |
break; | |
} | |
if(0 == result) { | |
result = memcmp(b0, b1, r0); | |
} | |
} | |
return result; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
char inpFilename[256] = { 0 }; | |
char lz4Filename[256] = { 0 }; | |
char decFilename[256] = { 0 }; | |
if(argc < 2) { | |
printf("Please specify input filename\n"); | |
return 0; | |
} | |
sprintf(inpFilename, "%s", argv[1]); | |
sprintf(lz4Filename, "%s.lz4s-%d", argv[1], BLOCK_BYTES); | |
sprintf(decFilename, "%s.lz4s-%d.dec", argv[1], BLOCK_BYTES); | |
printf("inp = [%s]\n", inpFilename); | |
printf("lz4 = [%s]\n", lz4Filename); | |
printf("dec = [%s]\n", decFilename); | |
// compress | |
{ | |
FILE* inpFp = fopen(inpFilename, "rb"); | |
FILE* outFp = fopen(lz4Filename, "wb"); | |
printf("compress : %s -> %s\n", inpFilename, lz4Filename); | |
test_compress(outFp, inpFp); | |
printf("compress : done\n"); | |
fclose(outFp); | |
fclose(inpFp); | |
} | |
// decompress | |
{ | |
FILE* inpFp = fopen(lz4Filename, "rb"); | |
FILE* outFp = fopen(decFilename, "wb"); | |
printf("decompress : %s -> %s\n", lz4Filename, decFilename); | |
test_decompress(outFp, inpFp); | |
printf("decompress : done\n"); | |
fclose(outFp); | |
fclose(inpFp); | |
} | |
// verify | |
{ | |
FILE* inpFp = fopen(inpFilename, "rb"); | |
FILE* decFp = fopen(decFilename, "rb"); | |
printf("verify : %s <-> %s\n", inpFilename, decFilename); | |
const int cmp = compare(inpFp, decFp); | |
if(0 == cmp) { | |
printf("verify : OK\n"); | |
} else { | |
printf("verify : NG\n"); | |
} | |
fclose(decFp); | |
fclose(inpFp); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
NOTE : The original example code I've posted in lz4c forum is revision 3.