• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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