aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/iostreams/src/zstd.cpp
blob: 20cc009804fc395da4e93cf51d35caa89dab0a3d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// (C) Copyright Reimar Döffinger 2018.
// Based on zstd.cpp by:
// (C) Copyright Milan Svoboda 2008.
// (C) Copyright Jonathan Turkanis 2003.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)

// See http://www.boost.org/libs/iostreams for documentation.

// Define BOOST_IOSTREAMS_SOURCE so that <boost/iostreams/detail/config.hpp>
// knows that we are building the library (possibly exporting code), rather
// than using it (possibly importing code).
#define BOOST_IOSTREAMS_SOURCE

#include <zstd.h>

#include <boost/throw_exception.hpp>
#include <boost/iostreams/detail/config/dyn_link.hpp>
#include <boost/iostreams/filter/zstd.hpp>

namespace boost { namespace iostreams {

namespace zstd {
                    // Compression levels

const uint32_t best_speed           = 1;
const uint32_t best_compression     = 19;
const uint32_t default_compression  = 3;

                    // Status codes

const int okay                 = 0;
const int stream_end           = 1;

                    // Flush codes

const int finish               = 0;
const int flush                = 1;
const int run                  = 2;
} // End namespace zstd.

//------------------Implementation of zstd_error------------------------------//

zstd_error::zstd_error(size_t error)
    : BOOST_IOSTREAMS_FAILURE(ZSTD_getErrorName(error)), error_(error)
    { }

void zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error)
{
    if (ZSTD_isError(error))
        boost::throw_exception(zstd_error(error));
}

//------------------Implementation of zstd_base-------------------------------//

namespace detail {

zstd_base::zstd_base()
    : cstream_(ZSTD_createCStream()), dstream_(ZSTD_createDStream()), in_(new ZSTD_inBuffer), out_(new ZSTD_outBuffer), eof_(0)
    { }

zstd_base::~zstd_base()
{
    ZSTD_freeCStream(static_cast<ZSTD_CStream *>(cstream_));
    ZSTD_freeDStream(static_cast<ZSTD_DStream *>(dstream_));
    delete static_cast<ZSTD_inBuffer*>(in_);
    delete static_cast<ZSTD_outBuffer*>(out_);
}

void zstd_base::before( const char*& src_begin, const char* src_end,
                        char*& dest_begin, char* dest_end )
{
    ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
    ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
    in->src = src_begin;
    in->size = static_cast<size_t>(src_end - src_begin);
    in->pos = 0;
    out->dst = dest_begin;
    out->size = static_cast<size_t>(dest_end - dest_begin);
    out->pos = 0;
}

void zstd_base::after(const char*& src_begin, char*& dest_begin, bool)
{
    ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
    ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
    src_begin = reinterpret_cast<const char*>(in->src) + in->pos;
    dest_begin = reinterpret_cast<char*>(out->dst) + out->pos;
}

int zstd_base::deflate(int action)
{
    ZSTD_CStream *s = static_cast<ZSTD_CStream *>(cstream_);
    ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
    ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
    // Ignore spurious extra calls.
    // Note size > 0 will trigger an error in this case.
    if (eof_ && in->size == 0) return zstd::stream_end;
    size_t result = ZSTD_compressStream(s, out, in);
    zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
    if (action != zstd::run)
    {
        result = action == zstd::finish ? ZSTD_endStream(s, out) : ZSTD_flushStream(s, out);
        zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
        eof_ = action == zstd::finish && result == 0;
        return result == 0 ? zstd::stream_end : zstd::okay;
    }
    return zstd::okay;
}

int zstd_base::inflate(int action)
{
    ZSTD_DStream *s = static_cast<ZSTD_DStream *>(dstream_);
    ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
    ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
    // need loop since iostream code cannot handle short reads
    do {
        size_t result = ZSTD_decompressStream(s, out, in);
        zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
    } while (in->pos < in->size && out->pos < out->size);
    return action == zstd::finish && in->size == 0 && out->pos == 0 ? zstd::stream_end : zstd::okay;
}

void zstd_base::reset(bool compress, bool realloc)
{
    ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
    ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);
    if (realloc)
    {
        memset(in, 0, sizeof(*in));
        memset(out, 0, sizeof(*out));
        eof_ = 0;

        zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
            compress ?
                ZSTD_initCStream(static_cast<ZSTD_CStream *>(cstream_), level) :
                ZSTD_initDStream(static_cast<ZSTD_DStream *>(dstream_))
        );
    }
}

void zstd_base::do_init
    ( const zstd_params& p, bool compress,
      zstd::alloc_func, zstd::free_func,
      void* )
{
    ZSTD_inBuffer *in = static_cast<ZSTD_inBuffer *>(in_);
    ZSTD_outBuffer *out = static_cast<ZSTD_outBuffer *>(out_);

    memset(in, 0, sizeof(*in));
    memset(out, 0, sizeof(*out));
    eof_ = 0;

    level = p.level;
    zstd_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(
        compress ?
            ZSTD_initCStream(static_cast<ZSTD_CStream *>(cstream_), level) :
            ZSTD_initDStream(static_cast<ZSTD_DStream *>(dstream_))
    );
}

} // End namespace detail.

//----------------------------------------------------------------------------//

} } // End namespaces iostreams, boost.