File: ZlibBufferWriter.hpp

package info (click to toggle)
r-bioc-alabaster.base 1.6.1%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,652 kB
  • sloc: cpp: 11,377; sh: 29; makefile: 2
file content (118 lines) | stat: -rw-r--r-- 3,387 bytes parent folder | download | duplicates (2)
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
#ifndef BYTEME_ZLIB_BUFFER_WRITER_HPP
#define BYTEME_ZLIB_BUFFER_WRITER_HPP

#include "zlib.h"
#include <stdexcept>
#include <vector>
#include "Writer.hpp"

/**
 * @file ZlibBufferWriter.hpp
 *
 * @brief Write bytes to a Zlib-compressed buffer.
 */

namespace byteme {

/**
 * @brief Compress and write bytes to a Zlib-compressed buffer.
 *
 * This is basically a wrapper around Zlib's deflate method, with correct closing and error checking.
 */
class ZlibBufferWriter : public Writer {
private:
    /**
     * @cond
     */
    struct ZStream {
        ZStream(int mode, int level) {
            strm.zalloc = Z_NULL;
            strm.zfree = Z_NULL;
            strm.opaque = Z_NULL;
            strm.avail_in = 0;
            strm.next_in = Z_NULL;

            // Check out https://zlib.net/manual.html for the constants.
            int windowBits;
            if (mode == 0) { // deflate
                windowBits = -15;
            } else if (mode == 1) { // Zlib
                windowBits = 15;
            } else if (mode == 2) { // Gzip
                windowBits = 16 + 15;
            } else {
                throw std::runtime_error("unknown Zlib compression mode supplied");
            } 

            int ret = deflateInit2(&strm, level, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY);
            if (ret != Z_OK) {
                throw std::runtime_error("failed to initialize Zlib buffer compression");
            }
        }

        ~ZStream() {
            (void)deflateEnd(&strm);
            return;
        }

        // Delete the remaining constructors.
        ZStream(const ZStream&) = delete;
        ZStream(ZStream&&) = delete;
        ZStream& operator=(const ZStream&) = delete;
        ZStream& operator=(ZStream&&) = delete;

        z_stream strm;
    };
    /**
     * @endcond
     */

public:
    /**
     * @param mode Compression mod of the stream - DEFLATE (0), Zlib (1) or Gzip (2).
     * @param compression_level Compression level from 1 to 9.
     * Larger values improve compression at the cost of speed.
     * @param buffer_size Size of the compression buffer in bytes.
     * Larger values improve speed at the cost of memory.
     */
    ZlibBufferWriter(int mode = 2, int compression_level = 6, size_t buffer_size = 65536) : zstr(mode, compression_level), holding(buffer_size) {}

    using Writer::write;

    void write(const unsigned char* buffer, size_t n) {
        zstr.strm.next_in = const_cast<unsigned char*>(buffer); // for C compatibility.
        zstr.strm.avail_in = n;
        dump(Z_NO_FLUSH);
    }

    void finish() {
        zstr.strm.next_in = nullptr;
        zstr.strm.avail_in = 0;
        dump(Z_FINISH);
    }

private:
    ZStream zstr;
    std::vector<unsigned char> holding;

    void dump(int flag) {
        do {
            zstr.strm.avail_out = holding.size();
            zstr.strm.next_out = holding.data();
            deflate(&(zstr.strm), flag); // no need to check, see https://zlib.net/zlib_how.html.
            size_t compressed = holding.size() - zstr.strm.avail_out;
            output.insert(output.end(), holding.begin(), holding.begin() + compressed);
        } while (zstr.strm.avail_out == 0);
    }

public:
    /**
     * Contents of the output buffer.
     * This should only be accessed after `finish()` is called.
     */
    std::vector<unsigned char> output;
};

}

#endif