byteme
Read/write bytes from various sources
Loading...
Searching...
No Matches
ZlibBufferWriter.hpp
Go to the documentation of this file.
1#ifndef BYTEME_ZLIB_BUFFER_WRITER_HPP
2#define BYTEME_ZLIB_BUFFER_WRITER_HPP
3
4#include <stdexcept>
5#include <vector>
6#include <cstddef>
7
8#include "zlib.h"
10
11#include "Writer.hpp"
12#include "magic_numbers.hpp"
13#include "utils.hpp"
14
21namespace byteme {
22
30 ZlibCompressionMode mode = ZlibCompressionMode::GZIP;
31
37
43};
44
50class ZlibBufferWriter final : public Writer {
51private:
55 struct ZStream {
56 ZStream(ZlibCompressionMode mode, int level) {
57 strm.zalloc = Z_NULL;
58 strm.zfree = Z_NULL;
59 strm.opaque = Z_NULL;
60 strm.avail_in = 0;
61 strm.next_in = Z_NULL;
62
63 // Check out https://zlib.net/manual.html for the constants.
64 int windowBits;
65 switch (mode) {
66 case ZlibCompressionMode::DEFLATE:
67 windowBits = -15;
68 break;
69 case ZlibCompressionMode::ZLIB:
70 windowBits = 15;
71 break;
72 case ZlibCompressionMode::GZIP:
73 windowBits = 16 + 15;
74 break;
75 default:
76 throw std::runtime_error("unknown Zlib compression mode");
77 }
78
79 int ret = deflateInit2(&strm, level, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY);
80 if (ret != Z_OK) {
81 throw std::runtime_error("failed to initialize Zlib buffer compression");
82 }
83 }
84
85 ~ZStream() {
86 deflateEnd(&strm);
87 return;
88 }
89
90 public:
91 // Delete the remaining constructors.
92 ZStream(const ZStream&) = delete;
93 ZStream(ZStream&&) = delete;
94 ZStream& operator=(const ZStream&) = delete;
95 ZStream& operator=(ZStream&&) = delete;
96
97 public:
98 z_stream strm;
99 };
104 typedef I<decltype(I<decltype(ZStream::strm)>::avail_out)> ZoutSize;
105
106public:
111 my_zstr(options.mode, options.compression_level),
112 // Cap it for both allocation safety and to avoid overflow of the avail_out member.
113 my_holding(sanisizer::cap<I<decltype(my_holding.size())> >(sanisizer::cap<ZoutSize>(options.buffer_size)))
114 {}
115
116 // One might think that we need to call finish() in the destructor, but in fact we don't.
117 // This is because the only observable effect of finish() is to flush all remaining content to the output buffer;
118 // but if we're destroying the object, the contents of the output buffer don't matter, as it'll be destroyed as well.
119 // So in fact, it's totally acceptable to just not do anything on destruction.
120
121public:
122 using Writer::write;
123
124 void write(const unsigned char* buffer, std::size_t n) {
125 typedef I<decltype(I<decltype(ZStream::strm)>::avail_in)> Size; // constrained for the z_stream interface.
126 safe_write<Size, false>(
127 buffer,
128 n,
129 [&](const unsigned char* buffer0, Size n0) -> void {
130 my_zstr.strm.next_in = const_cast<unsigned char*>(buffer0); // for C compatibility.
131 my_zstr.strm.avail_in = n0;
132 dump(Z_NO_FLUSH);
133 }
134 );
135 }
136
137 void finish() {
138 my_zstr.strm.next_in = nullptr;
139 my_zstr.strm.avail_in = 0;
140 dump(Z_FINISH);
141 }
142
143private:
144 ZStream my_zstr;
145 std::vector<unsigned char> my_holding;
146
147 void dump(int flag) {
148 do {
149 my_zstr.strm.avail_out = my_holding.size(); // no need to worry about overflow, we capped the size in the constructor.
150 my_zstr.strm.next_out = my_holding.data();
151 deflate(&(my_zstr.strm), flag); // no need to check, see https://zlib.net/zlib_how.html.
152 std::size_t compressed = my_holding.size() - my_zstr.strm.avail_out;
153 output.insert(output.end(), my_holding.begin(), my_holding.begin() + compressed);
154 } while (my_zstr.strm.avail_out == 0);
155 }
156
157public:
161 // Exposed for back-compatibility only.
162 std::vector<unsigned char> output;
171 std::vector<unsigned char>& get_output() {
172 return output;
173 }
174};
175
176}
177
178#endif
Write to an output sink.
Virtual class for writing bytes to a sink.
Definition Writer.hpp:21
virtual void write(const unsigned char *buffer, std::size_t n)=0
Compress and write bytes to a Zlib-compressed buffer.
Definition ZlibBufferWriter.hpp:50
ZlibBufferWriter(const ZlibBufferWriterOptions &options)
Definition ZlibBufferWriter.hpp:110
void finish()
Definition ZlibBufferWriter.hpp:137
void write(const unsigned char *buffer, std::size_t n)
Definition ZlibBufferWriter.hpp:124
std::vector< unsigned char > & get_output()
Definition ZlibBufferWriter.hpp:171
Magic numbers for various compression algorithms.
Simple byte readers and writers.
Definition BufferedReader.hpp:21
ZlibCompressionMode
Definition magic_numbers.hpp:66
constexpr Dest_ cap(Value_ x)
Options for the ZlibBufferWriter constructor.
Definition ZlibBufferWriter.hpp:26
int compression_level
Definition ZlibBufferWriter.hpp:36
ZlibCompressionMode mode
Definition ZlibBufferWriter.hpp:30
std::size_t buffer_size
Definition ZlibBufferWriter.hpp:42