123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- #ifdef CROW_ENABLE_COMPRESSION
- #pragma once
- #include <string>
- #include <zlib.h>
- // http://zlib.net/manual.html
- namespace crow // NOTE: Already documented in "crow/app.h"
- {
- namespace compression
- {
- // Values used in the 'windowBits' parameter for deflateInit2.
- enum algorithm
- {
- // 15 is the default value for deflate
- DEFLATE = 15,
- // windowBits can also be greater than 15 for optional gzip encoding.
- // Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper.
- GZIP = 15 | 16,
- };
- inline std::string compress_string(std::string const& str, algorithm algo)
- {
- std::string compressed_str;
- z_stream stream{};
- // Initialize with the default values
- if (::deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, algo, 8, Z_DEFAULT_STRATEGY) == Z_OK)
- {
- char buffer[8192];
- stream.avail_in = str.size();
- // zlib does not take a const pointer. The data is not altered.
- stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(str.c_str()));
- int code = Z_OK;
- do
- {
- stream.avail_out = sizeof(buffer);
- stream.next_out = reinterpret_cast<Bytef*>(&buffer[0]);
- code = ::deflate(&stream, Z_FINISH);
- // Successful and non-fatal error code returned by deflate when used with Z_FINISH flush
- if (code == Z_OK || code == Z_STREAM_END)
- {
- std::copy(&buffer[0], &buffer[sizeof(buffer) - stream.avail_out], std::back_inserter(compressed_str));
- }
- } while (code == Z_OK);
- if (code != Z_STREAM_END)
- compressed_str.clear();
- ::deflateEnd(&stream);
- }
- return compressed_str;
- }
- inline std::string decompress_string(std::string const& deflated_string)
- {
- std::string inflated_string;
- Bytef tmp[8192];
- z_stream zstream{};
- zstream.avail_in = deflated_string.size();
- // Nasty const_cast but zlib won't alter its contents
- zstream.next_in = const_cast<Bytef*>(reinterpret_cast<Bytef const*>(deflated_string.c_str()));
- // Initialize with automatic header detection, for gzip support
- if (::inflateInit2(&zstream, MAX_WBITS | 32) == Z_OK)
- {
- do
- {
- zstream.avail_out = sizeof(tmp);
- zstream.next_out = &tmp[0];
- auto ret = ::inflate(&zstream, Z_NO_FLUSH);
- if (ret == Z_OK || ret == Z_STREAM_END)
- {
- std::copy(&tmp[0], &tmp[sizeof(tmp) - zstream.avail_out], std::back_inserter(inflated_string));
- }
- else
- {
- // Something went wrong with inflate; make sure we return an empty string
- inflated_string.clear();
- break;
- }
- } while (zstream.avail_out == 0);
- // Free zlib's internal memory
- ::inflateEnd(&zstream);
- }
- return inflated_string;
- }
- } // namespace compression
- } // namespace crow
- #endif
|