aboutsummaryrefslogtreecommitdiffstats
path: root/util/stream/zlib.h
blob: ead8c1e01314719866214a3f9be5500f6964cc65 (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
167
168
169
170
171
172
173
#pragma once

#include "fwd.h"
#include "input.h"
#include "output.h"
#include "buffered.h"

#include <util/system/defaults.h>
#include <util/generic/ptr.h>
#include <util/generic/yexception.h>

/**
 * @addtogroup Streams_Archs
 * @{
 */

struct TZLibError: public yexception {
};

struct TZLibCompressorError: public TZLibError {
};

struct TZLibDecompressorError: public TZLibError {
};

namespace ZLib {
    enum StreamType: ui8 {
        Auto = 0, /**< Auto detect format. Can be used for decompression only. */
        ZLib = 1,
        GZip = 2,
        Raw = 3,
        Invalid = 4
    };

    enum {
        ZLIB_BUF_LEN = 8 * 1024
    };
}

/**
 * Non-buffered ZLib decompressing stream.
 *
 * Please don't use `TZLibDecompress` if you read text data from stream using
 * `ReadLine`, it is VERY slow (approx 10 times slower, according to synthetic
 * benchmark). For fast buffered ZLib stream reading use `TBufferedZLibDecompress`
 * aka `TZDecompress`.
 */
class TZLibDecompress: public IInputStream {
public:
    TZLibDecompress(IZeroCopyInput* input, ZLib::StreamType type = ZLib::Auto, TStringBuf dict = {}); 
    TZLibDecompress(IInputStream* input, ZLib::StreamType type = ZLib::Auto, size_t buflen = ZLib::ZLIB_BUF_LEN, 
                    TStringBuf dict = {}); 

    /**
     * Allows/disallows multiple sequential compressed streams. Allowed by default.
     *
     * If multiple streams are allowed, their decompressed content will be concatenated.
     * If multiple streams are disabled, then only first stream is decompressed. After that end
     * of IInputStream will have happen, i.e. method Read() will return 0.
     *
     * @param allowMultipleStreams - flag to allow (true) or disable (false) multiple streams.
     */
    void SetAllowMultipleStreams(bool allowMultipleStreams);

    ~TZLibDecompress() override;

protected:
    size_t DoRead(void* buf, size_t size) override;

public:
    class TImpl;
    THolder<TImpl> Impl_;
};

/**
 * Non-buffered ZLib compressing stream.
 */
class TZLibCompress: public IOutputStream {
public:
    struct TParams {
        inline TParams(IOutputStream* out)
            : Out(out)
            , Type(ZLib::ZLib)
            , CompressionLevel(6)
            , BufLen(ZLib::ZLIB_BUF_LEN)
        {
        }

        inline TParams& SetType(ZLib::StreamType type) noexcept {
            Type = type;

            return *this;
        }

        inline TParams& SetCompressionLevel(size_t level) noexcept {
            CompressionLevel = level;

            return *this;
        }

        inline TParams& SetBufLen(size_t buflen) noexcept {
            BufLen = buflen;

            return *this;
        }

        inline TParams& SetDict(const TStringBuf dict) noexcept {
            Dict = dict;

            return *this;
        }

        IOutputStream* Out;
        ZLib::StreamType Type;
        size_t CompressionLevel;
        size_t BufLen;
        TStringBuf Dict;
    };

    inline TZLibCompress(const TParams& params) {
        Init(params);
    }

    inline TZLibCompress(IOutputStream* out, ZLib::StreamType type) {
        Init(TParams(out).SetType(type));
    }

    inline TZLibCompress(IOutputStream* out, ZLib::StreamType type, size_t compression_level) {
        Init(TParams(out).SetType(type).SetCompressionLevel(compression_level));
    }

    inline TZLibCompress(IOutputStream* out, ZLib::StreamType type, size_t compression_level, size_t buflen) {
        Init(TParams(out).SetType(type).SetCompressionLevel(compression_level).SetBufLen(buflen));
    }

    ~TZLibCompress() override;

private:
    void Init(const TParams& opts);

    void DoWrite(const void* buf, size_t size) override;
    void DoFlush() override;
    void DoFinish() override;

public:
    class TImpl;

    /** To allow inline constructors. */
    struct TDestruct {
        static void Destroy(TImpl* impl);
    };

    THolder<TImpl, TDestruct> Impl_;
};

/**
 * Buffered ZLib decompressing stream.
 *
 * Supports efficient `ReadLine` calls and similar "reading in small pieces"
 * usage patterns.
 */
class TBufferedZLibDecompress: public TBuffered<TZLibDecompress> {
public:
    template <class T>
    inline TBufferedZLibDecompress(T* in, ZLib::StreamType type = ZLib::Auto, size_t buf = 1 << 13)
        : TBuffered<TZLibDecompress>(buf, in, type)
    {
    }

    ~TBufferedZLibDecompress() override;
};

/** @} */