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
21namespace boost { namespace iostreams {
22
23namespace zstd {
24 // Compression levels
25
26const uint32_t best_speed = 1;
27const uint32_t best_compression = 19;
28const uint32_t default_compression = 3;
29
30 // Status codes
31
32const int okay = 0;
33const int stream_end = 1;
34
35 // Flush codes
36
37const int finish = 0;
38const int flush = 1;
39const int run = 2;
40} // End namespace zstd.
41
42//------------------Implementation of zstd_error------------------------------//
43
44zstd_error::zstd_error(size_t error)
45 : BOOST_IOSTREAMS_FAILURE(ZSTD_getErrorName(code: error)), error_(error)
46 { }
47
48void zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error)
49{
50 if (ZSTD_isError(code: error))
51 boost::throw_exception(e: zstd_error(error));
52}
53
54//------------------Implementation of zstd_base-------------------------------//
55
56namespace detail {
57
58zstd_base::zstd_base()
59 : cstream_(ZSTD_createCStream()), dstream_(ZSTD_createDStream()), in_(new ZSTD_inBuffer), out_(new ZSTD_outBuffer), eof_(0)
60 { }
61
62zstd_base::~zstd_base()
63{
64 ZSTD_freeCStream(zcs: static_cast<ZSTD_CStream *>(cstream_));
65 ZSTD_freeDStream(zds: static_cast<ZSTD_DStream *>(dstream_));
66 delete static_cast<ZSTD_inBuffer*>(in_);
67 delete static_cast<ZSTD_outBuffer*>(out_);
68}
69
70void 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
83void 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
91int 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(zcs: s, output: out, input: in);
100 zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(error: result);
101 if (action != zstd::run)
102 {
103 result = action == zstd::finish ? ZSTD_endStream(zcs: s, output: out) : ZSTD_flushStream(zcs: s, output: out);
104 zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(error: result);
105 eof_ = action == zstd::finish && result == 0;
106 return result == 0 ? zstd::stream_end : zstd::okay;
107 }
108 return zstd::okay;
109}
110
111int 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(zds: s, output: out, input: in);
119 zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(error: 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
124void 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(s: in, c: 0, n: sizeof(*in));
131 memset(s: out, c: 0, n: sizeof(*out));
132 eof_ = 0;
133
134 zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
135 error: compress ?
136 ZSTD_initCStream(zcs: static_cast<ZSTD_CStream *>(cstream_), compressionLevel: level) :
137 ZSTD_initDStream(zds: static_cast<ZSTD_DStream *>(dstream_))
138 );
139 }
140}
141
142void 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(s: in, c: 0, n: sizeof(*in));
151 memset(s: out, c: 0, n: sizeof(*out));
152 eof_ = 0;
153
154 level = p.level;
155 zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
156 error: compress ?
157 ZSTD_initCStream(zcs: static_cast<ZSTD_CStream *>(cstream_), compressionLevel: level) :
158 ZSTD_initDStream(zds: static_cast<ZSTD_DStream *>(dstream_))
159 );
160}
161
162} // End namespace detail.
163
164//----------------------------------------------------------------------------//
165
166} } // End namespaces iostreams, boost.
167

source code of boost/libs/iostreams/src/zstd.cpp