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