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