1 // (C) Copyright Reimar Döffinger 2018.
2 // Based on zstd.cpp by:
3 // (C) Copyright Milan Svoboda 2008.
4 // (C) Copyright Jonathan Turkanis 2003.
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
7 
8 // See http://www.boost.org/libs/iostreams for documentation.
9 
10 // Define BOOST_IOSTREAMS_SOURCE so that <boost/iostreams/detail/config.hpp>
11 // knows that we are building the library (possibly exporting code), rather
12 // than using it (possibly importing code).
13 #define BOOST_IOSTREAMS_SOURCE
14 
15 #include <zstd.h>
16 
17 #include <boost/throw_exception.hpp>
18 #include <boost/iostreams/detail/config/dyn_link.hpp>
19 #include <boost/iostreams/filter/zstd.hpp>
20 
21 namespace boost { namespace iostreams {
22 
23 namespace zstd {
24                     // Compression levels
25 
26 const uint32_t best_speed           = 1;
27 const uint32_t best_compression     = 19;
28 const uint32_t default_compression  = 3;
29 
30                     // Status codes
31 
32 const int okay                 = 0;
33 const int stream_end           = 1;
34 
35                     // Flush codes
36 
37 const int finish               = 0;
38 const int flush                = 1;
39 const int run                  = 2;
40 } // End namespace zstd.
41 
42 //------------------Implementation of zstd_error------------------------------//
43 
zstd_error(size_t error)44 zstd_error::zstd_error(size_t error)
45     : BOOST_IOSTREAMS_FAILURE(ZSTD_getErrorName(error)), error_(error)
46     { }
47 
BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error)48 void zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error)
49 {
50     if (ZSTD_isError(error))
51         boost::throw_exception(zstd_error(error));
52 }
53 
54 //------------------Implementation of zstd_base-------------------------------//
55 
56 namespace detail {
57 
zstd_base()58 zstd_base::zstd_base()
59     : cstream_(ZSTD_createCStream()), dstream_(ZSTD_createDStream()), in_(new ZSTD_inBuffer), out_(new ZSTD_outBuffer), eof_(0)
60     { }
61 
~zstd_base()62 zstd_base::~zstd_base()
63 {
64     ZSTD_freeCStream(static_cast<ZSTD_CStream *>(cstream_));
65     ZSTD_freeDStream(static_cast<ZSTD_DStream *>(dstream_));
66     delete static_cast<ZSTD_inBuffer*>(in_);
67     delete static_cast<ZSTD_outBuffer*>(out_);
68 }
69 
before(const char * & src_begin,const char * src_end,char * & dest_begin,char * dest_end)70 void zstd_base::before( const char*& src_begin, const char* src_end,
71                         char*& dest_begin, char* dest_end )
72 {
73     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
74     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
75     in->src = src_begin;
76     in->size = static_cast<size_t>(src_end - src_begin);
77     in->pos = 0;
78     out->dst = dest_begin;
79     out->size = static_cast<size_t>(dest_end - dest_begin);
80     out->pos = 0;
81 }
82 
after(const char * & src_begin,char * & dest_begin,bool)83 void zstd_base::after(const char*& src_begin, char*& dest_begin, bool)
84 {
85     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
86     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
87     src_begin = reinterpret_cast<const char*>(in->src) + in->pos;
88     dest_begin = reinterpret_cast<char*>(out->dst) + out->pos;
89 }
90 
deflate(int action)91 int zstd_base::deflate(int action)
92 {
93     ZSTD_CStream *s = static_cast<ZSTD_CStream *>(cstream_);
94     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
95     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
96     // Ignore spurious extra calls.
97     // Note size > 0 will trigger an error in this case.
98     if (eof_ && in->size == 0) return zstd::stream_end;
99     size_t result = ZSTD_compressStream(s, out, in);
100     zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
101     if (action != zstd::run)
102     {
103         result = action == zstd::finish ? ZSTD_endStream(s, out) : ZSTD_flushStream(s, out);
104         zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
105         eof_ = action == zstd::finish && result == 0;
106         return result == 0 ? zstd::stream_end : zstd::okay;
107     }
108     return zstd::okay;
109 }
110 
inflate(int action)111 int zstd_base::inflate(int action)
112 {
113     ZSTD_DStream *s = static_cast<ZSTD_DStream *>(dstream_);
114     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
115     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
116     // need loop since iostream code cannot handle short reads
117     do {
118         size_t result = ZSTD_decompressStream(s, out, in);
119         zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
120     } while (in->pos < in->size && out->pos < out->size);
121     return action == zstd::finish && in->size == 0 && out->pos == 0 ? zstd::stream_end : zstd::okay;
122 }
123 
reset(bool compress,bool realloc)124 void zstd_base::reset(bool compress, bool realloc)
125 {
126     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
127     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
128     if (realloc)
129     {
130         memset(in, 0, sizeof(*in));
131         memset(out, 0, sizeof(*out));
132         eof_ = 0;
133 
134         zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
135             compress ?
136                 ZSTD_initCStream(static_cast<ZSTD_CStream *>(cstream_), level) :
137                 ZSTD_initDStream(static_cast<ZSTD_DStream *>(dstream_))
138         );
139     }
140 }
141 
do_init(const zstd_params & p,bool compress,zstd::alloc_func,zstd::free_func,void *)142 void zstd_base::do_init
143     ( const zstd_params& p, bool compress,
144       zstd::alloc_func, zstd::free_func,
145       void* )
146 {
147     ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
148     ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
149 
150     memset(in, 0, sizeof(*in));
151     memset(out, 0, sizeof(*out));
152     eof_ = 0;
153 
154     level = p.level;
155     zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
156         compress ?
157             ZSTD_initCStream(static_cast<ZSTD_CStream *>(cstream_), level) :
158             ZSTD_initDStream(static_cast<ZSTD_DStream *>(dstream_))
159     );
160 }
161 
162 } // End namespace detail.
163 
164 //----------------------------------------------------------------------------//
165 
166 } } // End namespaces iostreams, boost.
167