aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/compression/zlib/zlib.cpp
blob: 57494e2256cb3061742bb38d229b3da4167563d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
* Zlib Compressor
* (C) 2001 Peter J Jones
*     2001-2007,2014 Jack Lloyd
*     2006 Matt Johnston
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/zlib.h>
#include <botan/internal/compress_utils.h>
#include <botan/exceptn.h>
#include <zlib.h>

namespace Botan {

namespace {

class Zlib_Stream : public Zlib_Style_Stream<z_stream, Bytef>
   {
   public:
      Zlib_Stream()
         {
         streamp()->opaque = alloc();
         streamp()->zalloc = Compression_Alloc_Info::malloc<unsigned int>;
         streamp()->zfree = Compression_Alloc_Info::free;
         }

      uint32_t run_flag() const override { return Z_NO_FLUSH; }
      uint32_t flush_flag() const override { return Z_SYNC_FLUSH; }
      uint32_t finish_flag() const override { return Z_FINISH; }

      int compute_window_bits(int wbits, int wbits_offset) const
         {
         if(wbits_offset == -1)
            return -wbits;
         else
            return wbits + wbits_offset;
         }
   };

class Zlib_Compression_Stream : public Zlib_Stream
   {
   public:
      Zlib_Compression_Stream(size_t level, int wbits, int wbits_offset = 0)
         {
         wbits = compute_window_bits(wbits, wbits_offset);

         if(level >= 9)
            level = 9;
         else if(level == 0)
            level = 6;

         int rc = ::deflateInit2(streamp(), level, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY);

         if(rc != Z_OK)
            throw Exception("zlib deflate initialization failed");
         }

      ~Zlib_Compression_Stream()
         {
         ::deflateEnd(streamp());
         }

      bool run(uint32_t flags) override
         {
         int rc = ::deflate(streamp(), flags);

         if(rc == Z_MEM_ERROR)
            throw Exception("zlib memory allocation failure");
         else if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR)
            throw Exception("zlib deflate error " + std::to_string(rc));

         return (rc == Z_STREAM_END);
         }
   };

class Zlib_Decompression_Stream : public Zlib_Stream
   {
   public:
      Zlib_Decompression_Stream(int wbits, int wbits_offset = 0)
         {
         int rc = ::inflateInit2(streamp(), compute_window_bits(wbits, wbits_offset));

         if(rc == Z_MEM_ERROR)
            throw Exception("zlib memory allocation failure");
         else if(rc != Z_OK)
            throw Exception("zlib inflate initialization failed");
         }

      ~Zlib_Decompression_Stream()
         {
         ::inflateEnd(streamp());
         }

      bool run(uint32_t flags) override
         {
         int rc = ::inflate(streamp(), flags);

         if(rc == Z_MEM_ERROR)
            throw Exception("zlib memory allocation failure");
         else if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR)
            throw Exception("zlib inflate error " + std::to_string(rc));

         return (rc == Z_STREAM_END);
         }
   };

class Deflate_Compression_Stream final : public Zlib_Compression_Stream
   {
   public:
      Deflate_Compression_Stream(size_t level, int wbits) :
         Zlib_Compression_Stream(level, wbits, -1) {}
   };

class Deflate_Decompression_Stream final : public Zlib_Decompression_Stream
   {
   public:
      explicit Deflate_Decompression_Stream(int wbits) : Zlib_Decompression_Stream(wbits, -1) {}
   };

class Gzip_Compression_Stream final : public Zlib_Compression_Stream
   {
   public:
      Gzip_Compression_Stream(size_t level, int wbits, uint8_t os_code, uint64_t hdr_time) :
         Zlib_Compression_Stream(level, wbits, 16)
         {
         clear_mem(&m_header, 1);
         m_header.os = os_code;
         m_header.time = static_cast<uLong>(hdr_time);

         int rc = deflateSetHeader(streamp(), &m_header);
         if(rc != Z_OK)
            throw Exception("setting gzip header failed");
         }

   private:
      ::gz_header m_header;
   };

class Gzip_Decompression_Stream final : public Zlib_Decompression_Stream
   {
   public:
      explicit Gzip_Decompression_Stream(int wbits) : Zlib_Decompression_Stream(wbits, 16) {}
   };

}

Compression_Stream* Zlib_Compression::make_stream(size_t level) const
   {
   return new Zlib_Compression_Stream(level, 15);
   }

Compression_Stream* Zlib_Decompression::make_stream() const
   {
   return new Zlib_Decompression_Stream(15);
   }

Compression_Stream* Deflate_Compression::make_stream(size_t level) const
   {
   return new Deflate_Compression_Stream(level, 15);
   }

Compression_Stream* Deflate_Decompression::make_stream() const
   {
   return new Deflate_Decompression_Stream(15);
   }

Compression_Stream* Gzip_Compression::make_stream(size_t level) const
   {
   return new Gzip_Compression_Stream(level, 15, m_os_code, m_hdr_time);
   }

Compression_Stream* Gzip_Decompression::make_stream() const
   {
   return new Gzip_Decompression_Stream(15);
   }

}