blockStreaming_lineByLine.c 5.3 KB

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