Photon 1.0.0
Loading...
Searching...
No Matches
decompress.hpp
Go to the documentation of this file.
1#include <gzip/config.hpp>
2
3// zlib
4#include <zlib.h>
5
6// std
7#include <limits>
8#include <stdexcept>
9#include <string>
10
11namespace gzip
12{
13
15 {
16 std::size_t max_;
17
18 public:
19 Decompressor(std::size_t max_bytes = 1000000000) // by default refuse operation if compressed data is > 1GB
20 : max_(max_bytes)
21 {
22 }
23
24 template <typename OutputType> void decompress(OutputType& output, const char* data, std::size_t size) const
25 {
26 z_stream inflate_s;
27
28 inflate_s.zalloc = Z_NULL;
29 inflate_s.zfree = Z_NULL;
30 inflate_s.opaque = Z_NULL;
31 inflate_s.avail_in = 0;
32 inflate_s.next_in = Z_NULL;
33
34 // The windowBits parameter is the base two logarithm of the window size (the size of the history buffer).
35 // It should be in the range 8..15 for this version of the library.
36 // Larger values of this parameter result in better compression at the expense of memory usage.
37 // This range of values also changes the decoding type:
38 // -8 to -15 for raw deflate
39 // 8 to 15 for zlib
40 // (8 to 15) + 16 for gzip
41 // (8 to 15) + 32 to automatically detect gzip/zlib header
42 constexpr int window_bits = 15 + 32; // auto with windowbits of 15
43
44#pragma GCC diagnostic push
45#pragma GCC diagnostic ignored "-Wold-style-cast"
46 if (inflateInit2(&inflate_s, window_bits) != Z_OK)
47 {
48 throw std::runtime_error("inflate init failed");
49 }
50#pragma GCC diagnostic pop
51 inflate_s.next_in = reinterpret_cast<z_const Bytef*>(data);
52
53#ifdef DEBUG
54 // Verify if size (long type) input will fit into unsigned int, type used for zlib's avail_in
55 std::uint64_t size_64 = size * 2;
56 if (size_64 > std::numeric_limits<unsigned int>::max())
57 {
58 inflateEnd(&inflate_s);
59 throw std::runtime_error("size arg is too large to fit into unsigned int type x2");
60 }
61#endif
62 if (size > max_ || (size * 2) > max_)
63 {
64 inflateEnd(&inflate_s);
65 throw std::runtime_error("size may use more memory than intended when decompressing");
66 }
67 inflate_s.avail_in = static_cast<unsigned int>(size);
68 std::size_t size_uncompressed = 0;
69 do
70 {
71 std::size_t resize_to = size_uncompressed + 2 * size;
72 if (resize_to > max_)
73 {
74 inflateEnd(&inflate_s);
75 throw std::runtime_error(
76 "size of output string will use more memory then intended when decompressing");
77 }
78 output.resize(resize_to);
79 inflate_s.avail_out = static_cast<unsigned int>(2 * size);
80 inflate_s.next_out = reinterpret_cast<Bytef*>(&output[0] + size_uncompressed);
81 int ret = inflate(&inflate_s, Z_FINISH);
82 if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR)
83 {
84 std::string error_msg = inflate_s.msg;
85 inflateEnd(&inflate_s);
86 throw std::runtime_error(error_msg);
87 }
88
89 size_uncompressed += (2 * size - inflate_s.avail_out);
90 } while (inflate_s.avail_out == 0);
91 inflateEnd(&inflate_s);
92 output.resize(size_uncompressed);
93 }
94 };
95
96 inline std::string decompress(const char* data, std::size_t size)
97 {
98 Decompressor decomp;
99 std::string output;
100 decomp.decompress(output, data, size);
101 return output;
102 }
103
104} // namespace gzip
Definition decompress.hpp:15
void decompress(OutputType &output, const char *data, std::size_t size) const
Definition decompress.hpp:24
std::size_t max_
Definition decompress.hpp:16
Decompressor(std::size_t max_bytes=1000000000)
Definition decompress.hpp:19
Definition compress.hpp:12
std::string decompress(const char *data, std::size_t size)
Definition decompress.hpp:96
Definition format.h:1901
annotation output
Definition tag_strings.h:122