File indexing completed on 2024-05-05 05:44:04

0001 // (C) Copyright Reimar Döffinger 2018.
0002 // Based on zstd.hpp by:
0003 // (C) Copyright Milan Svoboda 2008.
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
0006 
0007 // See http://www.boost.org/libs/iostreams for documentation.
0008 
0009 #ifndef BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED
0010 #define BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED
0011 
0012 #if defined(_MSC_VER)
0013 # pragma once
0014 #endif
0015 
0016 #include <cassert>
0017 #include <iosfwd>            // streamsize.
0018 #include <memory>            // allocator, bad_alloc.
0019 #include <new>
0020 #include <boost/config.hpp>  // MSVC, STATIC_CONSTANT, DEDUCED_TYPENAME, DINKUM.
0021 #include <boost/detail/workaround.hpp>
0022 #include <boost/iostreams/constants.hpp>   // buffer size.
0023 #include <boost/iostreams/detail/config/auto_link.hpp>
0024 #include <boost/iostreams/detail/config/dyn_link.hpp>
0025 #include <boost/iostreams/detail/config/wide_streams.hpp>
0026 #include <boost/iostreams/detail/ios.hpp>  // failure, streamsize.
0027 #include <boost/iostreams/filter/symmetric.hpp>
0028 #include <boost/iostreams/pipeline.hpp>
0029 #include <boost/type_traits/is_same.hpp>
0030 
0031 // Must come last.
0032 #ifdef BOOST_MSVC
0033 # pragma warning(push)
0034 # pragma warning(disable:4251 4231 4660)         // Dependencies not exported.
0035 #endif
0036 #include <boost/config/abi_prefix.hpp>
0037 
0038 namespace boost { namespace iostreams {
0039 
0040 namespace zstd {
0041 
0042 typedef void* (*alloc_func)(void*, size_t, size_t);
0043 typedef void (*free_func)(void*, void*);
0044 
0045                     // Compression levels
0046 
0047 BOOST_IOSTREAMS_DECL extern const uint32_t best_speed;
0048 BOOST_IOSTREAMS_DECL extern const uint32_t best_compression;
0049 BOOST_IOSTREAMS_DECL extern const uint32_t default_compression;
0050 
0051                     // Status codes
0052 
0053 BOOST_IOSTREAMS_DECL extern const int okay;
0054 BOOST_IOSTREAMS_DECL extern const int stream_end;
0055 
0056                     // Flush codes
0057 
0058 BOOST_IOSTREAMS_DECL extern const int finish;
0059 BOOST_IOSTREAMS_DECL extern const int flush;
0060 BOOST_IOSTREAMS_DECL extern const int run;
0061 
0062                     // Code for current OS
0063 
0064                     // Null pointer constant.
0065 
0066 const int null                               = 0;
0067 
0068                     // Default values
0069 
0070 } // End namespace zstd.
0071 
0072 //
0073 // Class name: zstd_params.
0074 // Description: Encapsulates the parameters passed to zstddec_init
0075 //      to customize compression and decompression.
0076 //
0077 struct zstd_params {
0078 
0079     // Non-explicit constructor.
0080     zstd_params( uint32_t level = zstd::default_compression )
0081         : level(level)
0082         { }
0083     uint32_t level;
0084 };
0085 
0086 //
0087 // Class name: zstd_error.
0088 // Description: Subclass of std::ios::failure thrown to indicate
0089 //     zstd errors other than out-of-memory conditions.
0090 //
0091 class BOOST_IOSTREAMS_DECL zstd_error : public BOOST_IOSTREAMS_FAILURE {
0092 public:
0093     explicit zstd_error(size_t error);
0094     int error() const { return error_; }
0095     static void check BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error);
0096 private:
0097     size_t error_;
0098 };
0099 
0100 namespace detail {
0101 
0102 template<typename Alloc>
0103 struct zstd_allocator_traits {
0104 #ifndef BOOST_NO_STD_ALLOCATOR
0105 #if defined(BOOST_NO_CXX11_ALLOCATOR)
0106     typedef typename Alloc::template rebind<char>::other type;
0107 #else
0108     typedef typename std::allocator_traits<Alloc>::template rebind_alloc<char> type;
0109 #endif
0110 #else
0111     typedef std::allocator<char> type;
0112 #endif
0113 };
0114 
0115 template< typename Alloc,
0116           typename Base = // VC6 workaround (C2516)
0117               BOOST_DEDUCED_TYPENAME zstd_allocator_traits<Alloc>::type >
0118 struct zstd_allocator : private Base {
0119 private:
0120 #if defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_STD_ALLOCATOR)
0121     typedef typename Base::size_type size_type;
0122 #else
0123     typedef typename std::allocator_traits<Base>::size_type size_type;
0124 #endif
0125 public:
0126     BOOST_STATIC_CONSTANT(bool, custom =
0127         (!is_same<std::allocator<char>, Base>::value));
0128     typedef typename zstd_allocator_traits<Alloc>::type allocator_type;
0129     static void* allocate(void* self, size_t items, size_t size);
0130     static void deallocate(void* self, void* address);
0131 };
0132 
0133 class BOOST_IOSTREAMS_DECL zstd_base {
0134 public:
0135     typedef char char_type;
0136 protected:
0137     zstd_base();
0138     ~zstd_base();
0139     template<typename Alloc>
0140     void init( const zstd_params& p,
0141                bool compress,
0142                zstd_allocator<Alloc>& zalloc )
0143         {
0144             bool custom = zstd_allocator<Alloc>::custom;
0145             do_init( p, compress,
0146                      custom ? zstd_allocator<Alloc>::allocate : 0,
0147                      custom ? zstd_allocator<Alloc>::deallocate : 0,
0148                      &zalloc );
0149         }
0150     void before( const char*& src_begin, const char* src_end,
0151                  char*& dest_begin, char* dest_end );
0152     void after( const char*& src_begin, char*& dest_begin,
0153                 bool compress );
0154     int deflate(int action);
0155     int inflate(int action);
0156     void reset(bool compress, bool realloc);
0157 private:
0158     void do_init( const zstd_params& p, bool compress,
0159                   zstd::alloc_func,
0160                   zstd::free_func,
0161                   void* derived );
0162     void*         cstream_;         // Actual type: ZSTD_CStream *
0163     void*         dstream_;         // Actual type: ZSTD_DStream *
0164     void*         in_;              // Actual type: ZSTD_inBuffer *
0165     void*         out_;             // Actual type: ZSTD_outBuffer *
0166     int eof_;
0167     uint32_t level;
0168 };
0169 
0170 //
0171 // Template name: zstd_compressor_impl
0172 // Description: Model of C-Style Filter implementing compression by
0173 //      delegating to the zstd function deflate.
0174 //
0175 template<typename Alloc = std::allocator<char> >
0176 class zstd_compressor_impl : public zstd_base, public zstd_allocator<Alloc> {
0177 public:
0178     zstd_compressor_impl(const zstd_params& = zstd::default_compression);
0179     ~zstd_compressor_impl();
0180     bool filter( const char*& src_begin, const char* src_end,
0181                  char*& dest_begin, char* dest_end, bool flush );
0182     void close();
0183 };
0184 
0185 //
0186 // Template name: zstd_compressor_impl
0187 // Description: Model of C-Style Filte implementing decompression by
0188 //      delegating to the zstd function inflate.
0189 //
0190 template<typename Alloc = std::allocator<char> >
0191 class zstd_decompressor_impl : public zstd_base, public zstd_allocator<Alloc> {
0192 public:
0193     zstd_decompressor_impl(const zstd_params&);
0194     zstd_decompressor_impl();
0195     ~zstd_decompressor_impl();
0196     bool filter( const char*& begin_in, const char* end_in,
0197                  char*& begin_out, char* end_out, bool flush );
0198     void close();
0199 };
0200 
0201 } // End namespace detail.
0202 
0203 //
0204 // Template name: zstd_compressor
0205 // Description: Model of InputFilter and OutputFilter implementing
0206 //      compression using zstd.
0207 //
0208 template<typename Alloc = std::allocator<char> >
0209 struct basic_zstd_compressor
0210     : symmetric_filter<detail::zstd_compressor_impl<Alloc>, Alloc>
0211 {
0212 private:
0213     typedef detail::zstd_compressor_impl<Alloc> impl_type;
0214     typedef symmetric_filter<impl_type, Alloc>  base_type;
0215 public:
0216     typedef typename base_type::char_type               char_type;
0217     typedef typename base_type::category                category;
0218     basic_zstd_compressor( const zstd_params& = zstd::default_compression,
0219                            std::streamsize buffer_size = default_device_buffer_size );
0220 };
0221 BOOST_IOSTREAMS_PIPABLE(basic_zstd_compressor, 1)
0222 
0223 typedef basic_zstd_compressor<> zstd_compressor;
0224 
0225 //
0226 // Template name: zstd_decompressor
0227 // Description: Model of InputFilter and OutputFilter implementing
0228 //      decompression using zstd.
0229 //
0230 template<typename Alloc = std::allocator<char> >
0231 struct basic_zstd_decompressor
0232     : symmetric_filter<detail::zstd_decompressor_impl<Alloc>, Alloc>
0233 {
0234 private:
0235     typedef detail::zstd_decompressor_impl<Alloc> impl_type;
0236     typedef symmetric_filter<impl_type, Alloc>    base_type;
0237 public:
0238     typedef typename base_type::char_type               char_type;
0239     typedef typename base_type::category                category;
0240     basic_zstd_decompressor( std::streamsize buffer_size = default_device_buffer_size );
0241     basic_zstd_decompressor( const zstd_params& p,
0242                              std::streamsize buffer_size = default_device_buffer_size );
0243 };
0244 BOOST_IOSTREAMS_PIPABLE(basic_zstd_decompressor, 1)
0245 
0246 typedef basic_zstd_decompressor<> zstd_decompressor;
0247 
0248 //----------------------------------------------------------------------------//
0249 
0250 //------------------Implementation of zstd_allocator--------------------------//
0251 
0252 namespace detail {
0253 
0254 template<typename Alloc, typename Base>
0255 void* zstd_allocator<Alloc, Base>::allocate
0256     (void* self, size_t items, size_t size)
0257 {
0258     size_type len = items * size;
0259     char* ptr =
0260         static_cast<allocator_type*>(self)->allocate
0261             (len + sizeof(size_type)
0262             #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
0263                 , (char*)0
0264             #endif
0265             );
0266     *reinterpret_cast<size_type*>(ptr) = len;
0267     return ptr + sizeof(size_type);
0268 }
0269 
0270 template<typename Alloc, typename Base>
0271 void zstd_allocator<Alloc, Base>::deallocate(void* self, void* address)
0272 {
0273     char* ptr = reinterpret_cast<char*>(address) - sizeof(size_type);
0274     size_type len = *reinterpret_cast<size_type*>(ptr) + sizeof(size_type);
0275     static_cast<allocator_type*>(self)->deallocate(ptr, len);
0276 }
0277 
0278 //------------------Implementation of zstd_compressor_impl--------------------//
0279 
0280 template<typename Alloc>
0281 zstd_compressor_impl<Alloc>::zstd_compressor_impl(const zstd_params& p)
0282 { init(p, true, static_cast<zstd_allocator<Alloc>&>(*this)); }
0283 
0284 template<typename Alloc>
0285 zstd_compressor_impl<Alloc>::~zstd_compressor_impl()
0286 { reset(true, false); }
0287 
0288 template<typename Alloc>
0289 bool zstd_compressor_impl<Alloc>::filter
0290     ( const char*& src_begin, const char* src_end,
0291       char*& dest_begin, char* dest_end, bool flush )
0292 {
0293     before(src_begin, src_end, dest_begin, dest_end);
0294     int result = deflate(flush ? zstd::finish : zstd::run);
0295     after(src_begin, dest_begin, true);
0296     return result != zstd::stream_end;
0297 }
0298 
0299 template<typename Alloc>
0300 void zstd_compressor_impl<Alloc>::close() { reset(true, true); }
0301 
0302 //------------------Implementation of zstd_decompressor_impl------------------//
0303 
0304 template<typename Alloc>
0305 zstd_decompressor_impl<Alloc>::zstd_decompressor_impl(const zstd_params& p)
0306 { init(p, false, static_cast<zstd_allocator<Alloc>&>(*this)); }
0307 
0308 template<typename Alloc>
0309 zstd_decompressor_impl<Alloc>::~zstd_decompressor_impl()
0310 { reset(false, false); }
0311 
0312 template<typename Alloc>
0313 zstd_decompressor_impl<Alloc>::zstd_decompressor_impl()
0314 {
0315     zstd_params p;
0316     init(p, false, static_cast<zstd_allocator<Alloc>&>(*this));
0317 }
0318 
0319 template<typename Alloc>
0320 bool zstd_decompressor_impl<Alloc>::filter
0321     ( const char*& src_begin, const char* src_end,
0322       char*& dest_begin, char* dest_end, bool flush )
0323 {
0324     before(src_begin, src_end, dest_begin, dest_end);
0325     int result = inflate(flush ? zstd::finish : zstd::run);
0326     after(src_begin, dest_begin, false);
0327     return result != zstd::stream_end;
0328 }
0329 
0330 template<typename Alloc>
0331 void zstd_decompressor_impl<Alloc>::close() { reset(false, true); }
0332 
0333 } // End namespace detail.
0334 
0335 //------------------Implementation of zstd_compressor-----------------------//
0336 
0337 template<typename Alloc>
0338 basic_zstd_compressor<Alloc>::basic_zstd_compressor
0339     (const zstd_params& p, std::streamsize buffer_size)
0340     : base_type(buffer_size, p) { }
0341 
0342 //------------------Implementation of zstd_decompressor-----------------------//
0343 
0344 template<typename Alloc>
0345 basic_zstd_decompressor<Alloc>::basic_zstd_decompressor
0346     (std::streamsize buffer_size)
0347     : base_type(buffer_size) { }
0348 
0349 template<typename Alloc>
0350 basic_zstd_decompressor<Alloc>::basic_zstd_decompressor
0351     (const zstd_params& p, std::streamsize buffer_size)
0352     : base_type(buffer_size, p) { }
0353 
0354 //----------------------------------------------------------------------------//
0355 
0356 } } // End namespaces iostreams, boost.
0357 
0358 #include <boost/config/abi_suffix.hpp> // Pops abi_suffix.hpp pragmas.
0359 #ifdef BOOST_MSVC
0360 # pragma warning(pop)
0361 #endif
0362 
0363 #endif // #ifndef BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED