1/* LZ4 streaming API example : ring buffer 2 * Based on sample code from Takayuki Matsuoka */ 3 4 5/************************************** 6 * Compiler Options 7 **************************************/ 8#if defined(_MSC_VER) && (_MSC_VER <= 1800) /* Visual Studio <= 2013 */ 9# define _CRT_SECURE_NO_WARNINGS 10# define snprintf sprintf_s 11#endif 12 13 14/************************************** 15 * Includes 16 **************************************/ 17#include <stdio.h> 18#include <stdint.h> 19#include <stdlib.h> 20#include <string.h> 21#include "lz4.h" 22 23 24enum { 25 MESSAGE_MAX_BYTES = 1024, 26 RING_BUFFER_BYTES = 1024 * 8 + MESSAGE_MAX_BYTES, 27 DECODE_RING_BUFFER = RING_BUFFER_BYTES + MESSAGE_MAX_BYTES /* Intentionally larger, to test unsynchronized ring buffers */ 28}; 29 30 31size_t write_int32(FILE* fp, int32_t i) { 32 return fwrite(&i, sizeof(i), 1, fp); 33} 34 35size_t write_bin(FILE* fp, const void* array, int arrayBytes) { 36 return fwrite(array, 1, arrayBytes, fp); 37} 38 39size_t read_int32(FILE* fp, int32_t* i) { 40 return fread(i, sizeof(*i), 1, fp); 41} 42 43size_t read_bin(FILE* fp, void* array, int arrayBytes) { 44 return fread(array, 1, arrayBytes, fp); 45} 46 47 48void test_compress(FILE* outFp, FILE* inpFp) 49{ 50 LZ4_stream_t lz4Stream_body = { { 0 } }; 51 LZ4_stream_t* lz4Stream = &lz4Stream_body; 52 53 static char inpBuf[RING_BUFFER_BYTES]; 54 int inpOffset = 0; 55 56 for(;;) { 57 // Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer. 58 char* const inpPtr = &inpBuf[inpOffset]; 59 const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1; 60 const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength); 61 if (0 == inpBytes) break; 62 63 { 64#define CMPBUFSIZE (LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)) 65 char cmpBuf[CMPBUFSIZE]; 66 const int cmpBytes = LZ4_compress_fast_continue(lz4Stream, inpPtr, cmpBuf, inpBytes, CMPBUFSIZE, 0); 67 if(cmpBytes <= 0) break; 68 write_int32(outFp, cmpBytes); 69 write_bin(outFp, cmpBuf, cmpBytes); 70 71 inpOffset += inpBytes; 72 73 // Wraparound the ringbuffer offset 74 if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES) inpOffset = 0; 75 } 76 } 77 78 write_int32(outFp, 0); 79} 80 81 82void test_decompress(FILE* outFp, FILE* inpFp) 83{ 84 static char decBuf[DECODE_RING_BUFFER]; 85 int decOffset = 0; 86 LZ4_streamDecode_t lz4StreamDecode_body = { { 0 } }; 87 LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body; 88 89 for(;;) { 90 int cmpBytes = 0; 91 char cmpBuf[CMPBUFSIZE]; 92 93 { const size_t r0 = read_int32(inpFp, &cmpBytes); 94 if(r0 != 1 || cmpBytes <= 0) break; 95 96 const size_t r1 = read_bin(inpFp, cmpBuf, cmpBytes); 97 if(r1 != (size_t) cmpBytes) break; 98 } 99 100 { char* const decPtr = &decBuf[decOffset]; 101 const int decBytes = LZ4_decompress_safe_continue( 102 lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES); 103 if(decBytes <= 0) break; 104 decOffset += decBytes; 105 write_bin(outFp, decPtr, decBytes); 106 107 // Wraparound the ringbuffer offset 108 if(decOffset >= DECODE_RING_BUFFER - MESSAGE_MAX_BYTES) decOffset = 0; 109 } 110 } 111} 112 113 114int compare(FILE* f0, FILE* f1) 115{ 116 int result = 0; 117 118 while (0 == result) { 119 char b0[65536]; 120 char b1[65536]; 121 const size_t r0 = fread(b0, 1, sizeof(b0), f0); 122 const size_t r1 = fread(b1, 1, sizeof(b1), f1); 123 124 result = (int) r0 - (int) r1; 125 126 if (0 == r0 || 0 == r1) break; 127 128 if (0 == result) result = memcmp(b0, b1, r0); 129 } 130 131 return result; 132} 133 134 135int main(int argc, char** argv) 136{ 137 char inpFilename[256] = { 0 }; 138 char lz4Filename[256] = { 0 }; 139 char decFilename[256] = { 0 }; 140 141 if (argc < 2) { 142 printf("Please specify input filename\n"); 143 return 0; 144 } 145 146 snprintf(inpFilename, 256, "%s", argv[1]); 147 snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], 0); 148 snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], 0); 149 150 printf("inp = [%s]\n", inpFilename); 151 printf("lz4 = [%s]\n", lz4Filename); 152 printf("dec = [%s]\n", decFilename); 153 154 // compress 155 { FILE* const inpFp = fopen(inpFilename, "rb"); 156 FILE* const outFp = fopen(lz4Filename, "wb"); 157 158 test_compress(outFp, inpFp); 159 160 fclose(outFp); 161 fclose(inpFp); 162 } 163 164 // decompress 165 { FILE* const inpFp = fopen(lz4Filename, "rb"); 166 FILE* const outFp = fopen(decFilename, "wb"); 167 168 test_decompress(outFp, inpFp); 169 170 fclose(outFp); 171 fclose(inpFp); 172 } 173 174 // verify 175 { FILE* const inpFp = fopen(inpFilename, "rb"); 176 FILE* const decFp = fopen(decFilename, "rb"); 177 178 const int cmp = compare(inpFp, decFp); 179 if (0 == cmp) { 180 printf("Verify : OK\n"); 181 } else { 182 printf("Verify : NG\n"); 183 } 184 185 fclose(decFp); 186 fclose(inpFp); 187 } 188 189 return 0; 190} 191