1 // (C) Copyright Reimar Döffinger 2018.
2 // Based on zstd.hpp by:
3 // (C) Copyright Milan Svoboda 2008.
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
6
7 // See http://www.boost.org/libs/iostreams for documentation.
8
9 #ifndef BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED
10 #define BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED
11
12 #if defined(_MSC_VER)
13 # pragma once
14 #endif
15
16 #include <cassert>
17 #include <iosfwd> // streamsize.
18 #include <memory> // allocator, bad_alloc.
19 #include <new>
20 #include <boost/config.hpp> // MSVC, STATIC_CONSTANT, DEDUCED_TYPENAME, DINKUM.
21 #include <boost/detail/workaround.hpp>
22 #include <boost/iostreams/constants.hpp> // buffer size.
23 #include <boost/iostreams/detail/config/auto_link.hpp>
24 #include <boost/iostreams/detail/config/dyn_link.hpp>
25 #include <boost/iostreams/detail/config/wide_streams.hpp>
26 #include <boost/iostreams/detail/ios.hpp> // failure, streamsize.
27 #include <boost/iostreams/filter/symmetric.hpp>
28 #include <boost/iostreams/pipeline.hpp>
29 #include <boost/type_traits/is_same.hpp>
30
31 // Must come last.
32 #ifdef BOOST_MSVC
33 # pragma warning(push)
34 # pragma warning(disable:4251 4231 4660) // Dependencies not exported.
35 #endif
36 #include <boost/config/abi_prefix.hpp>
37
38 namespace boost { namespace iostreams {
39
40 namespace zstd {
41
42 typedef void* (*alloc_func)(void*, size_t, size_t);
43 typedef void (*free_func)(void*, void*);
44
45 // Compression levels
46
47 BOOST_IOSTREAMS_DECL extern const uint32_t best_speed;
48 BOOST_IOSTREAMS_DECL extern const uint32_t best_compression;
49 BOOST_IOSTREAMS_DECL extern const uint32_t default_compression;
50
51 // Status codes
52
53 BOOST_IOSTREAMS_DECL extern const int okay;
54 BOOST_IOSTREAMS_DECL extern const int stream_end;
55
56 // Flush codes
57
58 BOOST_IOSTREAMS_DECL extern const int finish;
59 BOOST_IOSTREAMS_DECL extern const int flush;
60 BOOST_IOSTREAMS_DECL extern const int run;
61
62 // Code for current OS
63
64 // Null pointer constant.
65
66 const int null = 0;
67
68 // Default values
69
70 } // End namespace zstd.
71
72 //
73 // Class name: zstd_params.
74 // Description: Encapsulates the parameters passed to zstddec_init
75 // to customize compression and decompression.
76 //
77 struct zstd_params {
78
79 // Non-explicit constructor.
zstd_paramsboost::iostreams::zstd_params80 zstd_params( uint32_t level = zstd::default_compression )
81 : level(level)
82 { }
83 uint32_t level;
84 };
85
86 //
87 // Class name: zstd_error.
88 // Description: Subclass of std::ios::failure thrown to indicate
89 // zstd errors other than out-of-memory conditions.
90 //
91 class BOOST_IOSTREAMS_DECL zstd_error : public BOOST_IOSTREAMS_FAILURE {
92 public:
93 explicit zstd_error(size_t error);
error() const94 int error() const { return error_; }
95 static void check BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error);
96 private:
97 size_t error_;
98 };
99
100 namespace detail {
101
102 template<typename Alloc>
103 struct zstd_allocator_traits {
104 #ifndef BOOST_NO_STD_ALLOCATOR
105 #if defined(BOOST_NO_CXX11_ALLOCATOR)
106 typedef typename Alloc::template rebind<char>::other type;
107 #else
108 typedef typename std::allocator_traits<Alloc>::template rebind_alloc<char> type;
109 #endif
110 #else
111 typedef std::allocator<char> type;
112 #endif
113 };
114
115 template< typename Alloc,
116 typename Base = // VC6 workaround (C2516)
117 BOOST_DEDUCED_TYPENAME zstd_allocator_traits<Alloc>::type >
118 struct zstd_allocator : private Base {
119 private:
120 #if defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_STD_ALLOCATOR)
121 typedef typename Base::size_type size_type;
122 #else
123 typedef typename std::allocator_traits<Base>::size_type size_type;
124 #endif
125 public:
126 BOOST_STATIC_CONSTANT(bool, custom =
127 (!is_same<std::allocator<char>, Base>::value));
128 typedef typename zstd_allocator_traits<Alloc>::type allocator_type;
129 static void* allocate(void* self, size_t items, size_t size);
130 static void deallocate(void* self, void* address);
131 };
132
133 class BOOST_IOSTREAMS_DECL zstd_base {
134 public:
135 typedef char char_type;
136 protected:
137 zstd_base();
138 ~zstd_base();
139 template<typename Alloc>
init(const zstd_params & p,bool compress,zstd_allocator<Alloc> & zalloc)140 void init( const zstd_params& p,
141 bool compress,
142 zstd_allocator<Alloc>& zalloc )
143 {
144 bool custom = zstd_allocator<Alloc>::custom;
145 do_init( p, compress,
146 custom ? zstd_allocator<Alloc>::allocate : 0,
147 custom ? zstd_allocator<Alloc>::deallocate : 0,
148 &zalloc );
149 }
150 void before( const char*& src_begin, const char* src_end,
151 char*& dest_begin, char* dest_end );
152 void after( const char*& src_begin, char*& dest_begin,
153 bool compress );
154 int deflate(int action);
155 int inflate(int action);
156 void reset(bool compress, bool realloc);
157 private:
158 void do_init( const zstd_params& p, bool compress,
159 zstd::alloc_func,
160 zstd::free_func,
161 void* derived );
162 void* cstream_; // Actual type: ZSTD_CStream *
163 void* dstream_; // Actual type: ZSTD_DStream *
164 void* in_; // Actual type: ZSTD_inBuffer *
165 void* out_; // Actual type: ZSTD_outBuffer *
166 int eof_;
167 uint32_t level;
168 };
169
170 //
171 // Template name: zstd_compressor_impl
172 // Description: Model of C-Style Filter implementing compression by
173 // delegating to the zstd function deflate.
174 //
175 template<typename Alloc = std::allocator<char> >
176 class zstd_compressor_impl : public zstd_base, public zstd_allocator<Alloc> {
177 public:
178 zstd_compressor_impl(const zstd_params& = zstd::default_compression);
179 ~zstd_compressor_impl();
180 bool filter( const char*& src_begin, const char* src_end,
181 char*& dest_begin, char* dest_end, bool flush );
182 void close();
183 };
184
185 //
186 // Template name: zstd_compressor_impl
187 // Description: Model of C-Style Filte implementing decompression by
188 // delegating to the zstd function inflate.
189 //
190 template<typename Alloc = std::allocator<char> >
191 class zstd_decompressor_impl : public zstd_base, public zstd_allocator<Alloc> {
192 public:
193 zstd_decompressor_impl(const zstd_params&);
194 zstd_decompressor_impl();
195 ~zstd_decompressor_impl();
196 bool filter( const char*& begin_in, const char* end_in,
197 char*& begin_out, char* end_out, bool flush );
198 void close();
199 };
200
201 } // End namespace detail.
202
203 //
204 // Template name: zstd_compressor
205 // Description: Model of InputFilter and OutputFilter implementing
206 // compression using zstd.
207 //
208 template<typename Alloc = std::allocator<char> >
209 struct basic_zstd_compressor
210 : symmetric_filter<detail::zstd_compressor_impl<Alloc>, Alloc>
211 {
212 private:
213 typedef detail::zstd_compressor_impl<Alloc> impl_type;
214 typedef symmetric_filter<impl_type, Alloc> base_type;
215 public:
216 typedef typename base_type::char_type char_type;
217 typedef typename base_type::category category;
218 basic_zstd_compressor( const zstd_params& = zstd::default_compression,
219 std::streamsize buffer_size = default_device_buffer_size );
220 };
221 BOOST_IOSTREAMS_PIPABLE(basic_zstd_compressor, 1)
222
223 typedef basic_zstd_compressor<> zstd_compressor;
224
225 //
226 // Template name: zstd_decompressor
227 // Description: Model of InputFilter and OutputFilter implementing
228 // decompression using zstd.
229 //
230 template<typename Alloc = std::allocator<char> >
231 struct basic_zstd_decompressor
232 : symmetric_filter<detail::zstd_decompressor_impl<Alloc>, Alloc>
233 {
234 private:
235 typedef detail::zstd_decompressor_impl<Alloc> impl_type;
236 typedef symmetric_filter<impl_type, Alloc> base_type;
237 public:
238 typedef typename base_type::char_type char_type;
239 typedef typename base_type::category category;
240 basic_zstd_decompressor( std::streamsize buffer_size = default_device_buffer_size );
241 basic_zstd_decompressor( const zstd_params& p,
242 std::streamsize buffer_size = default_device_buffer_size );
243 };
244 BOOST_IOSTREAMS_PIPABLE(basic_zstd_decompressor, 1)
245
246 typedef basic_zstd_decompressor<> zstd_decompressor;
247
248 //----------------------------------------------------------------------------//
249
250 //------------------Implementation of zstd_allocator--------------------------//
251
252 namespace detail {
253
254 template<typename Alloc, typename Base>
allocate(void * self,size_t items,size_t size)255 void* zstd_allocator<Alloc, Base>::allocate
256 (void* self, size_t items, size_t size)
257 {
258 size_type len = items * size;
259 char* ptr =
260 static_cast<allocator_type*>(self)->allocate
261 (len + sizeof(size_type)
262 #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
263 , (char*)0
264 #endif
265 );
266 *reinterpret_cast<size_type*>(ptr) = len;
267 return ptr + sizeof(size_type);
268 }
269
270 template<typename Alloc, typename Base>
deallocate(void * self,void * address)271 void zstd_allocator<Alloc, Base>::deallocate(void* self, void* address)
272 {
273 char* ptr = reinterpret_cast<char*>(address) - sizeof(size_type);
274 size_type len = *reinterpret_cast<size_type*>(ptr) + sizeof(size_type);
275 static_cast<allocator_type*>(self)->deallocate(ptr, len);
276 }
277
278 //------------------Implementation of zstd_compressor_impl--------------------//
279
280 template<typename Alloc>
zstd_compressor_impl(const zstd_params & p)281 zstd_compressor_impl<Alloc>::zstd_compressor_impl(const zstd_params& p)
282 { init(p, true, static_cast<zstd_allocator<Alloc>&>(*this)); }
283
284 template<typename Alloc>
~zstd_compressor_impl()285 zstd_compressor_impl<Alloc>::~zstd_compressor_impl()
286 { reset(true, false); }
287
288 template<typename Alloc>
filter(const char * & src_begin,const char * src_end,char * & dest_begin,char * dest_end,bool flush)289 bool zstd_compressor_impl<Alloc>::filter
290 ( const char*& src_begin, const char* src_end,
291 char*& dest_begin, char* dest_end, bool flush )
292 {
293 before(src_begin, src_end, dest_begin, dest_end);
294 int result = deflate(flush ? zstd::finish : zstd::run);
295 after(src_begin, dest_begin, true);
296 return result != zstd::stream_end;
297 }
298
299 template<typename Alloc>
close()300 void zstd_compressor_impl<Alloc>::close() { reset(true, true); }
301
302 //------------------Implementation of zstd_decompressor_impl------------------//
303
304 template<typename Alloc>
zstd_decompressor_impl(const zstd_params & p)305 zstd_decompressor_impl<Alloc>::zstd_decompressor_impl(const zstd_params& p)
306 { init(p, false, static_cast<zstd_allocator<Alloc>&>(*this)); }
307
308 template<typename Alloc>
~zstd_decompressor_impl()309 zstd_decompressor_impl<Alloc>::~zstd_decompressor_impl()
310 { reset(false, false); }
311
312 template<typename Alloc>
zstd_decompressor_impl()313 zstd_decompressor_impl<Alloc>::zstd_decompressor_impl()
314 {
315 zstd_params p;
316 init(p, false, static_cast<zstd_allocator<Alloc>&>(*this));
317 }
318
319 template<typename Alloc>
filter(const char * & src_begin,const char * src_end,char * & dest_begin,char * dest_end,bool flush)320 bool zstd_decompressor_impl<Alloc>::filter
321 ( const char*& src_begin, const char* src_end,
322 char*& dest_begin, char* dest_end, bool flush )
323 {
324 before(src_begin, src_end, dest_begin, dest_end);
325 int result = inflate(flush ? zstd::finish : zstd::run);
326 after(src_begin, dest_begin, false);
327 return result != zstd::stream_end;
328 }
329
330 template<typename Alloc>
close()331 void zstd_decompressor_impl<Alloc>::close() { reset(false, true); }
332
333 } // End namespace detail.
334
335 //------------------Implementation of zstd_compressor-----------------------//
336
337 template<typename Alloc>
basic_zstd_compressor(const zstd_params & p,std::streamsize buffer_size)338 basic_zstd_compressor<Alloc>::basic_zstd_compressor
339 (const zstd_params& p, std::streamsize buffer_size)
340 : base_type(buffer_size, p) { }
341
342 //------------------Implementation of zstd_decompressor-----------------------//
343
344 template<typename Alloc>
basic_zstd_decompressor(std::streamsize buffer_size)345 basic_zstd_decompressor<Alloc>::basic_zstd_decompressor
346 (std::streamsize buffer_size)
347 : base_type(buffer_size) { }
348
349 template<typename Alloc>
basic_zstd_decompressor(const zstd_params & p,std::streamsize buffer_size)350 basic_zstd_decompressor<Alloc>::basic_zstd_decompressor
351 (const zstd_params& p, std::streamsize buffer_size)
352 : base_type(buffer_size, p) { }
353
354 //----------------------------------------------------------------------------//
355
356 } } // End namespaces iostreams, boost.
357
358 #include <boost/config/abi_suffix.hpp> // Pops abi_suffix.hpp pragmas.
359 #ifdef BOOST_MSVC
360 # pragma warning(pop)
361 #endif
362
363 #endif // #ifndef BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED
364