compression.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #ifdef CROW_ENABLE_COMPRESSION
  2. #pragma once
  3. #include <string>
  4. #include <zlib.h>
  5. // http://zlib.net/manual.html
  6. namespace crow // NOTE: Already documented in "crow/app.h"
  7. {
  8. namespace compression
  9. {
  10. // Values used in the 'windowBits' parameter for deflateInit2.
  11. enum algorithm
  12. {
  13. // 15 is the default value for deflate
  14. DEFLATE = 15,
  15. // windowBits can also be greater than 15 for optional gzip encoding.
  16. // Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper.
  17. GZIP = 15 | 16,
  18. };
  19. inline std::string compress_string(std::string const& str, algorithm algo)
  20. {
  21. std::string compressed_str;
  22. z_stream stream{};
  23. // Initialize with the default values
  24. if (::deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, algo, 8, Z_DEFAULT_STRATEGY) == Z_OK)
  25. {
  26. char buffer[8192];
  27. stream.avail_in = str.size();
  28. // zlib does not take a const pointer. The data is not altered.
  29. stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(str.c_str()));
  30. int code = Z_OK;
  31. do
  32. {
  33. stream.avail_out = sizeof(buffer);
  34. stream.next_out = reinterpret_cast<Bytef*>(&buffer[0]);
  35. code = ::deflate(&stream, Z_FINISH);
  36. // Successful and non-fatal error code returned by deflate when used with Z_FINISH flush
  37. if (code == Z_OK || code == Z_STREAM_END)
  38. {
  39. std::copy(&buffer[0], &buffer[sizeof(buffer) - stream.avail_out], std::back_inserter(compressed_str));
  40. }
  41. } while (code == Z_OK);
  42. if (code != Z_STREAM_END)
  43. compressed_str.clear();
  44. ::deflateEnd(&stream);
  45. }
  46. return compressed_str;
  47. }
  48. inline std::string decompress_string(std::string const& deflated_string)
  49. {
  50. std::string inflated_string;
  51. Bytef tmp[8192];
  52. z_stream zstream{};
  53. zstream.avail_in = deflated_string.size();
  54. // Nasty const_cast but zlib won't alter its contents
  55. zstream.next_in = const_cast<Bytef*>(reinterpret_cast<Bytef const*>(deflated_string.c_str()));
  56. // Initialize with automatic header detection, for gzip support
  57. if (::inflateInit2(&zstream, MAX_WBITS | 32) == Z_OK)
  58. {
  59. do
  60. {
  61. zstream.avail_out = sizeof(tmp);
  62. zstream.next_out = &tmp[0];
  63. auto ret = ::inflate(&zstream, Z_NO_FLUSH);
  64. if (ret == Z_OK || ret == Z_STREAM_END)
  65. {
  66. std::copy(&tmp[0], &tmp[sizeof(tmp) - zstream.avail_out], std::back_inserter(inflated_string));
  67. }
  68. else
  69. {
  70. // Something went wrong with inflate; make sure we return an empty string
  71. inflated_string.clear();
  72. break;
  73. }
  74. } while (zstream.avail_out == 0);
  75. // Free zlib's internal memory
  76. ::inflateEnd(&zstream);
  77. }
  78. return inflated_string;
  79. }
  80. } // namespace compression
  81. } // namespace crow
  82. #endif