SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
gz_ostream.hpp
1// SPDX-FileCopyrightText: 2003 Jonathan de Halleux
2// SPDX-License-Identifier: Zlib
3// zipstream Library License:
4// --------------------------
5//
6// The zlib/libpng License Copyright (c) 2003 Jonathan de Halleux.
7//
8// This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
9//
10// Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
11//
12// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
13//
14// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
15//
16// 3. This notice may not be removed or altered from any source distribution
17//
18// Altered zipstream library header
19// Author: Jonathan de Halleux, dehalleux@pelikhan.com, 2003
20// Author: David Weese <david.weese@fu-berlin.de>
21// Author: Enrico Siragusa <enrico.siragusa@fu-berlin.de>
22// Author: Hannes Hauswedell <hannes.hauswedell@fu-berlin.de>
23
24#pragma once
25
26#include <iostream>
27#include <cstring>
28#include <vector>
29
30#if !defined(SEQAN3_HAS_ZLIB) && !defined(SEQAN3_HEADER_TEST)
31#error "This file cannot be used when building without ZLIB-support."
32#endif // !defined(SEQAN3_HAS_ZLIB) && !defined(SEQAN3_HEADER_TEST)
33
34#if defined(SEQAN3_HAS_ZLIB)
35
36#include <zlib.h>
37
38namespace seqan3::contrib
39{
40
41// Default gzip buffer size, change this to suite your needs.
42const size_t GZ_OUTPUT_DEFAULT_BUFFER_SIZE = 921600;
43
44// --------------------------------------------------------------------------
45// Enum EStrategy
46// --------------------------------------------------------------------------
47// Compression strategy, see zlib doc.
48
49enum EStrategy
50{
51 StrategyFiltered = 1,
52 StrategyHuffmanOnly = 2,
53 DefaultStrategy = 0
54};
55
56// --------------------------------------------------------------------------
57// Class basic_gz_ostreambuf
58// --------------------------------------------------------------------------
59// A stream decorator that takes raw input and zips it to a ostream.
60// The class wraps up the inflate method of the zlib library 1.1.4 https://www.zlib.net
61
62template <typename Elem,
63 typename Tr = std::char_traits<Elem>,
64 typename ElemA = std::allocator<Elem>,
65 typename ByteT = unsigned char,
66 typename ByteAT = std::allocator<ByteT>
67 >
68class basic_gz_ostreambuf :
69 public std::basic_streambuf<Elem, Tr>
70{
71public:
72 typedef std::basic_ostream<Elem, Tr> & ostream_reference;
73 typedef ElemA char_allocator_type;
74 typedef ByteT byte_type;
75 typedef ByteAT byte_allocator_type;
76 typedef byte_type * byte_buffer_type;
77 typedef Tr traits_type;
78 typedef typename Tr::char_type char_type;
79 typedef typename Tr::int_type int_type;
80 typedef std::vector<byte_type, byte_allocator_type> byte_vector_type;
81 typedef std::vector<char_type, char_allocator_type> char_vector_type;
82
83 // Construct a zip stream
84 // More info on the following parameters can be found in the zlib documentation.
85 basic_gz_ostreambuf(ostream_reference ostream_,
86 size_t level_,
87 EStrategy strategy_,
88 size_t window_size_,
89 size_t memory_level_,
90 size_t buffer_size_);
91
92 ~basic_gz_ostreambuf();
93
94 int sync();
95 int_type overflow(int_type c);
96
97 // flushes the zip buffer and output buffer.
98 // This method should be called at the end of the compression.
99 // Calling flush multiple times, will lower the compression ratio.
101
102 // flushes the zip buffer and output buffer and finalize the zip stream
103 // This method should be called at the end of the compression.
104 std::streamsize flush_finalize();
105
106
107private:
108 bool zip_to_stream(char_type *, std::streamsize);
109 size_t fill_input_buffer();
110 // flush the zip buffer using a particular mode and flush output buffer
111 std::streamsize flush(int flush_mode);
112
113 ostream_reference m_ostream;
114 z_stream m_zip_stream;
115 int m_err;
116 byte_vector_type m_output_buffer;
117 char_vector_type m_buffer;
118};
119
120// --------------------------------------------------------------------------
121// Class basic_gz_ostreambuf implementation
122// --------------------------------------------------------------------------
123
124template <typename Elem,
125 typename Tr,
126 typename ElemA,
127 typename ByteT,
128 typename ByteAT>
129basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::basic_gz_ostreambuf(
130 ostream_reference ostream_,
131 size_t level_,
132 EStrategy strategy_,
133 size_t window_size_,
134 size_t memory_level_,
135 size_t buffer_size_
136 ) :
137 m_ostream(ostream_),
138 m_output_buffer(buffer_size_, 0),
139 m_buffer(buffer_size_, 0)
140{
141 m_zip_stream.zalloc = (alloc_func)0;
142 m_zip_stream.zfree = (free_func)0;
143
144 m_zip_stream.next_in = NULL;
145 m_zip_stream.avail_in = 0;
146 m_zip_stream.avail_out = 0;
147 m_zip_stream.next_out = NULL;
148
149 m_err = deflateInit2(
150 &m_zip_stream,
151 std::min(9, static_cast<int>(level_)),
152 Z_DEFLATED,
153 static_cast<int>(window_size_),
154 std::min(9, static_cast<int>(memory_level_)),
155 static_cast<int>(strategy_)
156 );
157
158 this->setp(&(m_buffer[0]), &(m_buffer[m_buffer.size() - 1]));
159}
160
161template <typename Elem,
162 typename Tr,
163 typename ElemA,
164 typename ByteT,
165 typename ByteAT>
166basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::~basic_gz_ostreambuf()
167{
168 flush_finalize();
169 m_ostream.flush();
170 m_err = deflateEnd(&m_zip_stream);
171}
172
173template <typename Elem,
174 typename Tr,
175 typename ElemA,
176 typename ByteT,
177 typename ByteAT>
178int basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::sync()
179{
180 if (this->pptr() && this->pptr() > this->pbase())
181 {
182 if (traits_type::eq_int_type(overflow(traits_type::eof()), traits_type::eof()))
183 return -1;
184 }
185
186 return 0;
187}
188
189template <typename Elem,
190 typename Tr,
191 typename ElemA,
192 typename ByteT,
193 typename ByteAT>
194typename basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::int_type
195basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::overflow(
196 typename basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::int_type c)
197{
198 int w = static_cast<int>(this->pptr() - this->pbase());
199
200 if (!traits_type::eq_int_type(c, traits_type::eof()))
201 {
202 *this->pptr() = c;
203 ++w;
204 }
205
206 if (zip_to_stream(this->pbase(), w))
207 {
208 this->setp(this->pbase(), this->epptr() - 1);
209 return c;
210 }
211 else
212 {
213 return traits_type::eof();
214 }
215}
216
217template <typename Elem,
218 typename Tr,
219 typename ElemA,
220 typename ByteT,
221 typename ByteAT>
222bool basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::zip_to_stream(
223 typename basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::char_type * buffer_,
224 std::streamsize buffer_size_)
225{
226 std::streamsize written_byte_size = 0;
227
228 m_zip_stream.next_in = (byte_buffer_type)buffer_;
229 m_zip_stream.avail_in = static_cast<uInt>(buffer_size_ * sizeof(char_type));
230 m_zip_stream.avail_out = static_cast<uInt>(m_output_buffer.size());
231 m_zip_stream.next_out = &(m_output_buffer[0]);
232 size_t remainder = 0;
233
234 do
235 {
236 m_err = deflate(&m_zip_stream, 0);
237
238 if (m_err == Z_OK || m_err == Z_STREAM_END)
239 {
240 written_byte_size = static_cast<std::streamsize>(m_output_buffer.size()) - m_zip_stream.avail_out;
241
242 // output buffer is full, dumping to ostream
243 m_ostream.write((const char_type *) &(m_output_buffer[0]),
244 static_cast<std::streamsize>(written_byte_size / sizeof(char_type)));
245
246 // checking if some bytes were not written.
247 if ((remainder = written_byte_size % sizeof(char_type)) != 0)
248 {
249 // copy to the beginning of the stream
250 std::memmove(&(m_output_buffer[0]),
251 &(m_output_buffer[written_byte_size - remainder]),
252 remainder);
253 }
254
255 m_zip_stream.avail_out = static_cast<uInt>(m_output_buffer.size() - remainder);
256 m_zip_stream.next_out = &m_output_buffer[remainder];
257 }
258 }
259 while (m_zip_stream.avail_in != 0 && m_err == Z_OK);
260
261 return m_err == Z_OK;
262}
263
264template <typename Elem,
265 typename Tr,
266 typename ElemA,
267 typename ByteT,
268 typename ByteAT>
269std::streamsize basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::flush(int flush_mode)
270{
271 int const buffer_size = static_cast<int>(this->pptr() - this->pbase()); // amount of data currently in buffer
272
273 std::streamsize written_byte_size = 0, total_written_byte_size = 0;
274
275 m_zip_stream.next_in = (byte_buffer_type) this->pbase();
276 m_zip_stream.avail_in = static_cast<uInt>(buffer_size * sizeof(char_type));
277 m_zip_stream.avail_out = static_cast<uInt>(m_output_buffer.size());
278 m_zip_stream.next_out = &(m_output_buffer[0]);
279 size_t remainder = 0;
280
281 do
282 {
283 m_err = deflate(&m_zip_stream, flush_mode);
284 if (m_err == Z_OK || m_err == Z_STREAM_END)
285 {
286 written_byte_size = static_cast<std::streamsize>(m_output_buffer.size()) - m_zip_stream.avail_out;
287 total_written_byte_size += written_byte_size;
288
289 // output buffer is full, dumping to ostream
290 m_ostream.write((const char_type *) &(m_output_buffer[0]),
291 static_cast<std::streamsize>(written_byte_size / sizeof(char_type) * sizeof(byte_type)));
292
293 // checking if some bytes were not written.
294 if ((remainder = written_byte_size % sizeof(char_type)) != 0)
295 {
296 // copy to the beginning of the stream
297 std::memmove(&(m_output_buffer[0]),
298 &(m_output_buffer[written_byte_size - remainder]),
299 remainder);
300 }
301
302 m_zip_stream.avail_out = static_cast<uInt>(m_output_buffer.size() - remainder);
303 m_zip_stream.next_out = &m_output_buffer[remainder];
304 }
305 }
306 while (m_err == Z_OK);
307
308 m_ostream.flush();
309
310 return total_written_byte_size;
311}
312
313template <typename Elem,
314 typename Tr,
315 typename ElemA,
316 typename ByteT,
317 typename ByteAT>
318std::streamsize basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::flush()
319{
320 return flush(Z_SYNC_FLUSH);
321}
322
323template <typename Elem,
324 typename Tr,
325 typename ElemA,
326 typename ByteT,
327 typename ByteAT>
328std::streamsize basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT>::flush_finalize()
329{
330 return flush(Z_FINISH);
331}
332
333// --------------------------------------------------------------------------
334// Class basic_gz_ostreambase
335// --------------------------------------------------------------------------
336// Base class for zip ostreams.
337// Contains a basic_gz_ostreambuf.
338
339template <typename Elem,
340 typename Tr = std::char_traits<Elem>,
341 typename ElemA = std::allocator<Elem>,
342 typename ByteT = unsigned char,
343 typename ByteAT = std::allocator<ByteT>
344 >
345class basic_gz_ostreambase :
346 virtual public std::basic_ios<Elem, Tr>
347{
348public:
349 typedef std::basic_ostream<Elem, Tr> & ostream_reference;
350 typedef basic_gz_ostreambuf<Elem, Tr, ElemA, ByteT, ByteAT> zip_streambuf_type;
351
352 // Construct a zip stream
353 // More info on the following parameters can be found in the zlib documentation.
354 basic_gz_ostreambase(ostream_reference ostream_,
355 size_t level_,
356 EStrategy strategy_,
357 size_t window_size_,
358 size_t memory_level_,
359 size_t buffer_size_) :
360 m_buf(ostream_, level_, strategy_, window_size_, memory_level_, buffer_size_)
361 {
362 this->init(&m_buf);
363 }
364
365 // returns the underlying zip ostream object
366 zip_streambuf_type * rdbuf() { return &m_buf; }
367
368private:
369 zip_streambuf_type m_buf;
370};
371
372// --------------------------------------------------------------------------
373// Class basic_gz_ostream
374// --------------------------------------------------------------------------
375// A zipper ostream
376//
377// This class is a ostream decorator that behaves 'almost' like any other ostream.
378// At construction, it takes any ostream that shall be used to output of the compressed data.
379// When finished, you need to call the special method zflush or call the destructor
380// to flush all the intermidiate streams.
381//
382// Example:
383//
384// // creating the target zip string, could be a fstream
385// ostringstream ostringstream_;
386// // creating the zip layer
387// zip_ostream zipper(ostringstream_);
388// // writing data
389// zipper<<f<<" "<<d<<" "<<ui<<" "<<ul<<" "<<us<<" "<<c<<" "<<dum;
390// // zip ostream needs special flushing...
391// zipper.zflush();
392
393template <typename Elem,
394 typename Tr = std::char_traits<Elem>,
395 typename ElemA = std::allocator<Elem>,
396 typename ByteT = unsigned char,
397 typename ByteAT = std::allocator<ByteT>
398 >
399class basic_gz_ostream :
400 public basic_gz_ostreambase<Elem, Tr, ElemA, ByteT, ByteAT>,
401 public std::basic_ostream<Elem, Tr>
402{
403public:
404 typedef basic_gz_ostreambase<Elem, Tr, ElemA, ByteT, ByteAT> zip_ostreambase_type;
405 typedef std::basic_ostream<Elem, Tr> ostream_type;
406 typedef ostream_type & ostream_reference;
407
408 // Constructs a zipper ostream decorator
409 //
410 // ostream_ ostream where the compressed output is written
411 // is_gzip_ true if gzip header and footer have to be added
412 // level_ level of compression 0, bad and fast, 9, good and slower,
413 // strategy_ compression strategy
414 // window_size_ see zlib doc
415 // memory_level_ see zlib doc
416 // buffer_size_ the buffer size used to zip data
417
418 basic_gz_ostream(ostream_reference ostream_,
419 size_t level_ = Z_DEFAULT_COMPRESSION,
420 EStrategy strategy_ = DefaultStrategy,
421 size_t window_size_ = 31, // 15 (size) + 16 (gzip header)
422 size_t memory_level_ = 8,
423 size_t buffer_size_ = GZ_OUTPUT_DEFAULT_BUFFER_SIZE) :
424 zip_ostreambase_type(ostream_, level_, strategy_, window_size_, memory_level_, buffer_size_),
425 ostream_type(this->rdbuf())
426 {}
427
428 ~basic_gz_ostream()
429 {
430 ostream_type::flush(); this->rdbuf()->flush_finalize();
431 }
432
433 // flush inner buffer and zipper buffer
434 basic_gz_ostream<Elem, Tr> & flush()
435 {
436 ostream_type::flush(); this->rdbuf()->flush(); return *this;
437 }
438
439#ifdef _WIN32
440private:
441 void _Add_vtordisp1() {} // Required to avoid VC++ warning C4250
442 void _Add_vtordisp2() {} // Required to avoid VC++ warning C4250
443#endif
444};
445
446// ===========================================================================
447// Typedefs
448// ===========================================================================
449
450// A typedef for basic_gz_ostream<char>
451typedef basic_gz_ostream<char> gz_ostream;
452// A typedef for basic_gz_ostream<wchar_t>
453typedef basic_gz_ostream<wchar_t> gz_wostream;
454
455} // namespace seqan3::contrib
456
457#endif // defined(SEQAN3_HAS_ZLIB)
T flush(T... args)
T init(T... args)
T memmove(T... args)
T min(T... args)
T rdbuf(T... args)
T remainder(T... args)
Hide me