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