aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/compression/zlib/zlib.cpp
blob: 8e19288263ac3af09e9d11a35dcff9bcd37b18d9 (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
/*
* 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 <ctime>
#include <zlib.h>

namespace Botan {

BOTAN_REGISTER_COMPRESSION(Zlib_Compression, Zlib_Decompression);
BOTAN_REGISTER_COMPRESSION(Gzip_Compression, Gzip_Decompression);
BOTAN_REGISTER_COMPRESSION(Deflate_Compression, Deflate_Decompression);

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;
         }

      u32bit run_flag() const override { return Z_NO_FLUSH; }
      u32bit flush_flag() const override { return Z_SYNC_FLUSH; }
      u32bit 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);

         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(u32bit 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(u32bit 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 : public Zlib_Compression_Stream
   {
   public:
      Deflate_Compression_Stream(size_t level, int wbits) :
         Zlib_Compression_Stream(level, wbits, -1) {}
   };

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

class Gzip_Compression_Stream : public Zlib_Compression_Stream
   {
   public:
      Gzip_Compression_Stream(size_t level, int wbits, byte os_code) :
         Zlib_Compression_Stream(level, wbits, 16)
         {
         clear_mem(&m_header, 1);
         m_header.os = os_code;
         m_header.time = std::time(nullptr);

         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 : public Zlib_Decompression_Stream
   {
   public:
      Gzip_Decompression_Stream(int wbits) : Zlib_Decompression_Stream(wbits, 16) {}
   };

}

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

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

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

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

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

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

}