15280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet// LZ4 streaming API example : double buffer
25280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet// Copyright : Takayuki Matsuoka
35280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
45280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
55280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet#define _CRT_SECURE_NO_WARNINGS // for MSVC
65280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet#include "lz4.h"
75280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
85280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet#include <stdio.h>
95280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet#include <stdint.h>
105280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet#include <stdlib.h>
115280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet#include <string.h>
125280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
135280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletenum {
145280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    BLOCK_BYTES = 1024 * 8,
155280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet//  BLOCK_BYTES = 1024 * 64,
165280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet};
175280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
185280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
195280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletsize_t write_int(FILE* fp, int i) {
205280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    return fwrite(&i, sizeof(i), 1, fp);
215280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
225280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
235280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletsize_t write_bin(FILE* fp, const void* array, size_t arrayBytes) {
245280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    return fwrite(array, 1, arrayBytes, fp);
255280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
265280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
275280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletsize_t read_int(FILE* fp, int* i) {
285280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    return fread(i, sizeof(*i), 1, fp);
295280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
305280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
315280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletsize_t read_bin(FILE* fp, void* array, size_t arrayBytes) {
325280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    return fread(array, 1, arrayBytes, fp);
335280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
345280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
355280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
365280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletvoid test_compress(FILE* outFp, FILE* inpFp)
375280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet{
385280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    LZ4_stream_t lz4Stream_body = { 0 };
395280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    LZ4_stream_t* lz4Stream = &lz4Stream_body;
405280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
415280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    char inpBuf[2][BLOCK_BYTES];
425280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    int  inpBufIndex = 0;
435280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
445280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    for(;;) {
455280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        char* const inpPtr = inpBuf[inpBufIndex];
465280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        const int inpBytes = (int) read_bin(inpFp, inpPtr, BLOCK_BYTES);
475280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        if(0 == inpBytes) {
485280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            break;
495280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        }
505280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
515280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        {
525280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
535280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            const int cmpBytes = LZ4_compress_continue(
545280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet                lz4Stream, inpPtr, cmpBuf, inpBytes);
555280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            if(cmpBytes <= 0) {
565280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet                break;
575280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            }
585280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            write_int(outFp, cmpBytes);
595280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            write_bin(outFp, cmpBuf, (size_t) cmpBytes);
605280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        }
615280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
625280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        inpBufIndex = (inpBufIndex + 1) % 2;
635280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    }
645280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
655280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    write_int(outFp, 0);
665280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
675280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
685280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
695280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletvoid test_decompress(FILE* outFp, FILE* inpFp)
705280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet{
715280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
725280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
735280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
745280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    char decBuf[2][BLOCK_BYTES];
755280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    int  decBufIndex = 0;
765280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
775280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    for(;;) {
785280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
795280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        int  cmpBytes = 0;
805280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
815280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        {
825280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            const size_t readCount0 = read_int(inpFp, &cmpBytes);
835280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            if(readCount0 != 1 || cmpBytes <= 0) {
845280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet                break;
855280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            }
865280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
875280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            const size_t readCount1 = read_bin(inpFp, cmpBuf, (size_t) cmpBytes);
885280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            if(readCount1 != (size_t) cmpBytes) {
895280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet                break;
905280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            }
915280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        }
925280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
935280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        {
945280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            char* const decPtr = decBuf[decBufIndex];
955280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            const int decBytes = LZ4_decompress_safe_continue(
965280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet                lz4StreamDecode, cmpBuf, decPtr, cmpBytes, BLOCK_BYTES);
975280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            if(decBytes <= 0) {
985280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet                break;
995280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            }
1005280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            write_bin(outFp, decPtr, (size_t) decBytes);
1015280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        }
1025280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1035280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        decBufIndex = (decBufIndex + 1) % 2;
1045280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    }
1055280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
1065280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1075280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1085280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletint compare(FILE* fp0, FILE* fp1)
1095280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet{
1105280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    int result = 0;
1115280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1125280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    while(0 == result) {
1135280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        char b0[65536];
1145280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        char b1[65536];
1155280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        const size_t r0 = read_bin(fp0, b0, sizeof(b0));
1165280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        const size_t r1 = read_bin(fp1, b1, sizeof(b1));
1175280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1185280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        result = (int) r0 - (int) r1;
1195280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1205280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        if(0 == r0 || 0 == r1) {
1215280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            break;
1225280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        }
1235280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        if(0 == result) {
1245280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            result = memcmp(b0, b1, r0);
1255280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        }
1265280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    }
1275280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1285280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    return result;
1295280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
1305280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1315280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1325280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Colletint main(int argc, char* argv[])
1335280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet{
1345280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    char inpFilename[256] = { 0 };
1355280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    char lz4Filename[256] = { 0 };
1365280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    char decFilename[256] = { 0 };
1375280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1385280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    if(argc < 2) {
1395280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        printf("Please specify input filename\n");
1405280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        return 0;
1415280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    }
1425280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
143dc5fb73b9ee5c290cd1ea448791eefc8215b30d8Yann Collet    snprintf(inpFilename, 256, "%s", argv[1]);
144dc5fb73b9ee5c290cd1ea448791eefc8215b30d8Yann Collet    snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], BLOCK_BYTES);
145dc5fb73b9ee5c290cd1ea448791eefc8215b30d8Yann Collet    snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], BLOCK_BYTES);
1465280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1475280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    printf("inp = [%s]\n", inpFilename);
1485280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    printf("lz4 = [%s]\n", lz4Filename);
1495280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    printf("dec = [%s]\n", decFilename);
1505280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1515280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    // compress
1525280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    {
1535280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        FILE* inpFp = fopen(inpFilename, "rb");
1545280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        FILE* outFp = fopen(lz4Filename, "wb");
1555280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1565280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        printf("compress : %s -> %s\n", inpFilename, lz4Filename);
1575280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        test_compress(outFp, inpFp);
1585280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        printf("compress : done\n");
1595280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1605280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        fclose(outFp);
1615280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        fclose(inpFp);
1625280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    }
1635280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1645280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    // decompress
1655280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    {
1665280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        FILE* inpFp = fopen(lz4Filename, "rb");
1675280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        FILE* outFp = fopen(decFilename, "wb");
1685280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1695280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        printf("decompress : %s -> %s\n", lz4Filename, decFilename);
1705280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        test_decompress(outFp, inpFp);
1715280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        printf("decompress : done\n");
1725280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1735280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        fclose(outFp);
1745280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        fclose(inpFp);
1755280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    }
1765280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1775280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    // verify
1785280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    {
1795280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        FILE* inpFp = fopen(inpFilename, "rb");
1805280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        FILE* decFp = fopen(decFilename, "rb");
1815280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1825280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        printf("verify : %s <-> %s\n", inpFilename, decFilename);
1835280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        const int cmp = compare(inpFp, decFp);
1845280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        if(0 == cmp) {
1855280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            printf("verify : OK\n");
1865280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        } else {
1875280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet            printf("verify : NG\n");
1885280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        }
1895280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1905280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        fclose(decFp);
1915280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet        fclose(inpFp);
1925280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    }
1935280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet
1945280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet    return 0;
1955280091f429368a9d3fa846ab47b1ada8ddf5f84Yann Collet}
196