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

0001 // (C) Copyright Reimar Döffinger 2018.
0002 // Based on zstd.cpp by:
0003 // (C) Copyright Milan Svoboda 2008.
0004 // (C) Copyright Jonathan Turkanis 2003.
0005 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0006 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
0007 
0008 // See http://www.boost.org/libs/iostreams for documentation.
0009 
0010 // Define BOOST_IOSTREAMS_SOURCE so that <boost/iostreams/detail/config.hpp>
0011 // knows that we are building the library (possibly exporting code), rather
0012 // than using it (possibly importing code).
0013 #define BOOST_IOSTREAMS_SOURCE
0014 
0015 #include <zstd.h>
0016 
0017 #include <boost/throw_exception.hpp>
0018 #include <boost/iostreams/detail/config/dyn_link.hpp>
0019 //#include <boost/iostreams/filter/zstd.hpp>
0020 #include "zstd.hpp"
0021 
0022 namespace boost { namespace iostreams {
0023 
0024 namespace zstd {
0025                     // Compression levels
0026 
0027 const uint32_t best_speed           = 1;
0028 const uint32_t best_compression     = 19;
0029 const uint32_t default_compression  = 3;
0030 
0031                     // Status codes
0032 
0033 const int okay                 = 0;
0034 const int stream_end           = 1;
0035 
0036                     // Flush codes
0037 
0038 const int finish               = 0;
0039 const int flush                = 1;
0040 const int run                  = 2;
0041 } // End namespace zstd.
0042 
0043 //------------------Implementation of zstd_error------------------------------//
0044 
0045 zstd_error::zstd_error(size_t error)
0046     : BOOST_IOSTREAMS_FAILURE(ZSTD_getErrorName(error)), error_(error)
0047     { }
0048 
0049 void zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error)
0050 {
0051     if (ZSTD_isError(error))
0052         boost::throw_exception(zstd_error(error));
0053 }
0054 
0055 //------------------Implementation of zstd_base-------------------------------//
0056 
0057 namespace detail {
0058 
0059 zstd_base::zstd_base()
0060     : cstream_(ZSTD_createCStream()), dstream_(ZSTD_createDStream()), in_(new ZSTD_inBuffer), out_(new ZSTD_outBuffer), eof_(0)
0061     { }
0062 
0063 zstd_base::~zstd_base()
0064 {
0065     ZSTD_freeCStream(static_cast<ZSTD_CStream *>(cstream_));
0066     ZSTD_freeDStream(static_cast<ZSTD_DStream *>(dstream_));
0067     delete static_cast<ZSTD_inBuffer*>(in_);
0068     delete static_cast<ZSTD_outBuffer*>(out_);
0069 }
0070 
0071 void zstd_base::before( const char*& src_begin, const char* src_end,
0072                         char*& dest_begin, char* dest_end )
0073 {
0074     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
0075     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
0076     in->src = src_begin;
0077     in->size = static_cast<size_t>(src_end - src_begin);
0078     in->pos = 0;
0079     out->dst = dest_begin;
0080     out->size = static_cast<size_t>(dest_end - dest_begin);
0081     out->pos = 0;
0082 }
0083 
0084 void zstd_base::after(const char*& src_begin, char*& dest_begin, bool)
0085 {
0086     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
0087     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
0088     src_begin = reinterpret_cast<const char*>(in->src) + in->pos;
0089     dest_begin = reinterpret_cast<char*>(out->dst) + out->pos;
0090 }
0091 
0092 int zstd_base::deflate(int action)
0093 {
0094     ZSTD_CStream *s = static_cast<ZSTD_CStream *>(cstream_);
0095     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
0096     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
0097     // Ignore spurious extra calls.
0098     // Note size > 0 will trigger an error in this case.
0099     if (eof_ && in->size == 0) return zstd::stream_end;
0100     size_t result = ZSTD_compressStream(s, out, in);
0101     zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
0102     if (action != zstd::run)
0103     {
0104         result = action == zstd::finish ? ZSTD_endStream(s, out) : ZSTD_flushStream(s, out);
0105         zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
0106         eof_ = action == zstd::finish && result == 0;
0107         return result == 0 ? zstd::stream_end : zstd::okay;
0108     }
0109     return zstd::okay;
0110 }
0111 
0112 int zstd_base::inflate(int action)
0113 {
0114     ZSTD_DStream *s = static_cast<ZSTD_DStream *>(dstream_);
0115     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
0116     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
0117     // need loop since iostream code cannot handle short reads
0118     do {
0119         size_t result = ZSTD_decompressStream(s, out, in);
0120         zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
0121     } while (in->pos < in->size && out->pos < out->size);
0122     return action == zstd::finish && in->size == 0 && out->pos == 0 ? zstd::stream_end : zstd::okay;
0123 }
0124 
0125 void zstd_base::reset(bool compress, bool realloc)
0126 {
0127     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
0128     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
0129     if (realloc)
0130     {
0131         memset(in, 0, sizeof(*in));
0132         memset(out, 0, sizeof(*out));
0133         eof_ = 0;
0134 
0135         zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
0136             compress ?
0137                 ZSTD_initCStream(static_cast<ZSTD_CStream *>(cstream_), level) :
0138                 ZSTD_initDStream(static_cast<ZSTD_DStream *>(dstream_))
0139         );
0140     }
0141 }
0142 
0143 void zstd_base::do_init
0144     ( const zstd_params& p, bool compress,
0145       zstd::alloc_func, zstd::free_func,
0146       void* )
0147 {
0148     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
0149     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
0150 
0151     memset(in, 0, sizeof(*in));
0152     memset(out, 0, sizeof(*out));
0153     eof_ = 0;
0154 
0155     level = p.level;
0156     zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
0157         compress ?
0158             ZSTD_initCStream(static_cast<ZSTD_CStream *>(cstream_), level) :
0159             ZSTD_initDStream(static_cast<ZSTD_DStream *>(dstream_))
0160     );
0161 }
0162 
0163 } // End namespace detail.
0164 
0165 //----------------------------------------------------------------------------//
0166 
0167 } } // End namespaces iostreams, boost.