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> | |
//#define BLOCK_BYTES (1024*64) | |
#define BLOCK_BYTES (1024*8) | |
size_t write_int32(FILE* fp, int32_t i) { | |
return fwrite(&i, sizeof(i), 1, fp); | |
} | |
size_t write_bin(FILE* fp, const void* array, int arrayBytes) { | |
return fwrite(array, 1, arrayBytes, fp); | |
} | |
size_t read_int32(FILE* fp, int32_t* i) { | |
return fread(i, sizeof(*i), 1, fp); | |
} | |
size_t read_bin(FILE* fp, void* array, int 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] = { 0 }; | |
int inpBufIndex = 0; | |
#if BLOCK_BYTES < 65536 | |
char* inpPrevPtr = NULL; | |
int inpPrevBytes = 0; | |
#endif | |
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)]; | |
#if BLOCK_BYTES < 65536 | |
// Question : Is memset() necessary and valid ? | |
memset(lz4Stream, 0, sizeof(*lz4Stream)); | |
LZ4_loadDict(lz4Stream, inpPrevPtr, inpPrevBytes); | |
#endif | |
const int cmpBytes = LZ4_compress_continue( | |
lz4Stream, inpPtr, cmpBuf, inpBytes); | |
if(cmpBytes <= 0) { | |
break; | |
} | |
write_int32(outFp, cmpBytes); | |
write_bin(outFp, cmpBuf, cmpBytes); | |
} | |
#if BLOCK_BYTES < 65536 | |
inpPrevPtr = inpPtr; | |
inpPrevBytes = inpBytes; | |
#endif | |
inpBufIndex = (inpBufIndex + 1) % 2; | |
} | |
write_int32(outFp, 0); | |
} | |
void test_decompress(FILE* outFp, FILE* inpFp) | |
{ | |
char decBuf[2][BLOCK_BYTES] = { 0 }; | |
int decBufIndex = 0; | |
char* decPrevPtr = NULL; | |
int decPrevBytes = 0; | |
for(;;) { | |
char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)]; | |
int cmpBytes = 0; | |
{ | |
const size_t readCount0 = read_int32(inpFp, &cmpBytes); | |
if(readCount0 != 1 || cmpBytes <= 0) { | |
break; | |
} | |
const size_t readCount1 = read_bin(inpFp, cmpBuf, cmpBytes); | |
if(readCount1 != (size_t) cmpBytes) { | |
break; | |
} | |
} | |
{ | |
char* const decPtr = decBuf[decBufIndex]; | |
const int decBytes = LZ4_decompress_safe_usingDict( | |
cmpBuf, decPtr, cmpBytes, BLOCK_BYTES, | |
decPrevPtr, decPrevBytes); | |
if(decBytes <= 0) { | |
break; | |
} | |
write_bin(outFp, decPtr, decBytes); | |
decPrevPtr = decPtr; | |
decPrevBytes = decBytes; | |
decBufIndex = (decBufIndex + 1) % 2; | |
} | |
} | |
} | |
int compare(FILE* f0, FILE* f1) | |
{ | |
int result = 0; | |
while(0 == result) { | |
char b0[65536]; | |
char b1[65536]; | |
const size_t r0 = fread(b0, 1, sizeof(b0), f0); | |
const size_t r1 = fread(b1, 1, sizeof(b1), f1); | |
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"); | |
test_compress(outFp, inpFp); | |
fclose(outFp); | |
fclose(inpFp); | |
} | |
// decompress | |
{ | |
FILE* inpFp = fopen(lz4Filename, "rb"); | |
FILE* outFp = fopen(decFilename, "wb"); | |
test_decompress(outFp, inpFp); | |
fclose(outFp); | |
fclose(inpFp); | |
} | |
// verify | |
{ | |
FILE* inpFp = fopen(inpFilename, "rb"); | |
FILE* decFp = fopen(decFilename, "rb"); | |
const int cmp = compare(inpFp, decFp); | |
if(0 == cmp) { | |
printf("OK\n"); | |
} else { | |
printf("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.