diff options
Diffstat (limited to 'boost/beast/zlib/deflate_stream.hpp')
-rw-r--r-- | boost/beast/zlib/deflate_stream.hpp | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/boost/beast/zlib/deflate_stream.hpp b/boost/beast/zlib/deflate_stream.hpp new file mode 100644 index 0000000000..f57a0a5042 --- /dev/null +++ b/boost/beast/zlib/deflate_stream.hpp @@ -0,0 +1,404 @@ +// +// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// 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) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_ZLIB_DEFLATE_STREAM_HPP +#define BOOST_BEAST_ZLIB_DEFLATE_STREAM_HPP + +#include <boost/beast/core/detail/config.hpp> +#include <boost/beast/zlib/error.hpp> +#include <boost/beast/zlib/zlib.hpp> +#include <boost/beast/zlib/detail/deflate_stream.hpp> +#include <algorithm> +#include <cstdlib> +#include <cstdint> +#include <cstring> +#include <memory> + +namespace boost { +namespace beast { +namespace zlib { + +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +/** Raw deflate compressor. + + This is a port of zlib's "deflate" functionality to C++. +*/ +class deflate_stream + : private detail::deflate_stream +{ +public: + /** Construct a default deflate stream. + + Upon construction, the stream settings will be set + to these default values: + + @li `level = 6` + + @li `windowBits = 15` + + @li `memLevel = 8` + + @li `strategy = Strategy::normal` + + Although the stream is ready to be used immediately + after construction, any required internal buffers are + not dynamically allocated until needed. + */ + deflate_stream() + { + reset(6, 15, DEF_MEM_LEVEL, Strategy::normal); + } + + /** Reset the stream and compression settings. + + This function initializes the stream to the specified + compression settings. + + Although the stream is ready to be used immediately + after a reset, any required internal buffers are not + dynamically allocated until needed. + + @note Any unprocessed input or pending output from + previous calls are discarded. + */ + void + reset( + int level, + int windowBits, + int memLevel, + Strategy strategy) + { + doReset(level, windowBits, memLevel, strategy); + } + + /** Reset the stream without deallocating memory. + + This function performs the equivalent of calling `clear` + followed by `reset` with the same compression settings, + without deallocating the internal buffers. + + @note Any unprocessed input or pending output from + previous calls are discarded. + */ + void + reset() + { + doReset(); + } + + /** Clear the stream. + + This function resets the stream and frees all dynamically + allocated internal buffers. The compression settings are + left unchanged. + + @note Any unprocessed input or pending output from + previous calls are discarded. + */ + void + clear() + { + doClear(); + } + + /** Returns the upper limit on the size of a compressed block. + + This function makes a conservative estimate of the maximum number + of bytes needed to store the result of compressing a block of + data based on the current compression level and strategy. + + @param sourceLen The size of the uncompressed data. + + @return The maximum number of resulting compressed bytes. + */ + std::size_t + upper_bound(std::size_t sourceLen) const + { + return doUpperBound(sourceLen); + } + + /** Fine tune internal compression parameters. + + Compression parameters should only be tuned by someone who + understands the algorithm used by zlib's deflate for searching + for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit + for their specific input data. Read the deflate.c source code + (ZLib) for the meaning of the max_lazy, good_length, nice_length, + and max_chain parameters. + */ + void + tune( + int good_length, + int max_lazy, + int nice_length, + int max_chain) + { + doTune(good_length, max_lazy, nice_length, max_chain); + } + + /** Compress input and write output. + + This function compresses as much data as possible, and stops when + the input buffer becomes empty or the output buffer becomes full. + It may introduce some output latency (reading input without + producing any output) except when forced to flush. + + In each call, one or both of these actions are performed: + + @li Compress more input starting at `zs.next_in` and update + `zs.next_in` and `zs.avail_in` accordingly. If not all + input can be processed (because there is not enough room in + the output buffer), `zs.next_in` and `zs.avail_in` are updated + and processing will resume at this point for the next call. + + @li Provide more output starting at `zs.next_out` and update + `zs.next_out` and `zs.avail_out` accordingly. This action is + forced if the parameter flush is not `Flush::none`. Forcing + flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call, the application must ensure that at least one + of the actions is possible, by providing more input and/or + consuming more output, and updating `zs.avail_in` or `zs.avail_out` + accordingly; `zs.avail_out` should never be zero before the call. + The application can consume the compressed output when it wants, + for example when the output buffer is full (`zs.avail_out == 0`), + or after each call of `write`. If `write` returns no error + with zero `zs.avail_out`, it must be called again after making + room in the output buffer because there might be more output + pending. + + Normally the parameter flush is set to `Flush::none`, which allows + deflate to decide how much data to accumulate before producing + output, in order to maximize compression. + + If the parameter flush is set to `Flush::sync`, all pending output + is flushed to the output buffer and the output is aligned on a + byte boundary, so that the decompressor can get all input data + available so far. In particular `zs.avail_in` is zero after the + call if enough output space has been provided before the call. + Flushing may degrade compression for some compression algorithms + and so it should be used only when necessary. This completes the + current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed + by the four bytes `{ 0x00, 0x00 0xff 0xff }`. + + If flush is set to `Flush::partial`, all pending output is flushed + to the output buffer, but the output is not aligned to a byte + boundary. All of the input data so far will be available to the + decompressor, as for Z_SYNC_FLUSH. This completes the current + deflate block and follows it with an empty fixed codes block that + is 10 bits long. This assures that enough bytes are output in order + for the decompressor to finish the block before the empty fixed + code block. + + If flush is set to `Flush::block`, a deflate block is completed + and emitted, as for `Flush::sync`, but the output is not aligned + on a byte boundary, and up to seven bits of the current block are + held to be written as the next byte after the next deflate block + is completed. In this case, the decompressor may not be provided + enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait + for the next block to be emitted. This is for advanced applications + that need to control the emission of deflate blocks. + + If flush is set to `Flush::full`, all output is flushed as with + `Flush::sync`, and the compression state is reset so that + decompression can restart from this point if previous compressed + data has been damaged or if random access is desired. Using + `Flush::full` too often can seriously degrade compression. + + If `write` returns with `zs.avail_out == 0`, this function must + be called again with the same value of the flush parameter and + more output space (updated `zs.avail_out`), until the flush is + complete (`write` returns with non-zero `zs.avail_out`). In the + case of a `Flush::full`or `Flush::sync`, make sure that + `zs.avail_out` is greater than six to avoid repeated flush markers + due to `zs.avail_out == 0` on return. + + If the parameter flush is set to `Flush::finish`, pending input + is processed, pending output is flushed and deflate returns the + error `error::end_of_stream` if there was enough output space; + if deflate returns with no error, this function must be called + again with `Flush::finish` and more output space (updated + `zs.avail_out`) but no more input data, until it returns the + error `error::end_of_stream` or another error. After `write` has + returned the `error::end_of_stream` error, the only possible + operations on the stream are to reset or destroy. + + `Flush::finish` can be used immediately after initialization + if all the compression is to be done in a single step. In this + case, `zs.avail_out` must be at least value returned by + `upper_bound` (see below). Then `write` is guaranteed to return + the `error::end_of_stream` error. If not enough output space + is provided, deflate will not return `error::end_of_stream`, + and it must be called again as described above. + + `write` returns no error if some progress has been made (more + input processed or more output produced), `error::end_of_stream` + if all input has been consumed and all output has been produced + (only when flush is set to `Flush::finish`), `error::stream_error` + if the stream state was inconsistent (for example if `zs.next_in` + or `zs.next_out` was `nullptr`), `error::need_buffers` if no + progress is possible (for example `zs.avail_in` or `zs.avail_out` + was zero). Note that `error::need_buffers` is not fatal, and + `write` can be called again with more input and more output space + to continue compressing. + */ + void + write( + z_params& zs, + Flush flush, + error_code& ec) + { + doWrite(zs, flush, ec); + } + + /** Update the compression level and strategy. + + This function dynamically updates the compression level and + compression strategy. The interpretation of level and strategy + is as in @ref reset. This can be used to switch between compression + and straight copy of the input data, or to switch to a different kind + of input data requiring a different strategy. If the compression level + is changed, the input available so far is compressed with the old level + (and may be flushed); the new level will take effect only at the next + call of @ref write. + + Before the call of `params`, the stream state must be set as for a + call of @ref write, since the currently available input may have to be + compressed and flushed. In particular, `zs.avail_out` must be non-zero. + + @return `Z_OK` if success, `Z_STREAM_ERROR` if the source stream state + was inconsistent or if a parameter was invalid, `error::need_buffers` + if `zs.avail_out` was zero. + */ + void + params( + z_params& zs, + int level, + Strategy strategy, + error_code& ec) + { + doParams(zs, level, strategy, ec); + } + + /** Return bits pending in the output. + + This function returns the number of bytes and bits of output + that have been generated, but not yet provided in the available + output. The bytes not provided would be due to the available + output space having being consumed. The number of bits of output + not provided are between 0 and 7, where they await more bits to + join them in order to fill out a full byte. If pending or bits + are `nullptr`, then those values are not set. + + @return `Z_OK` if success, or `Z_STREAM_ERROR` if the source + stream state was inconsistent. + */ + void + pending(unsigned *value, int *bits) + { + doPending(value, bits); + } + + /** Insert bits into the compressed output stream. + + This function inserts bits in the deflate output stream. The + intent is that this function is used to start off the deflate + output with the bits leftover from a previous deflate stream when + appending to it. As such, this function can only be used for raw + deflate, and must be used before the first `write` call after an + initialization. `bits` must be less than or equal to 16, and that + many of the least significant bits of `value` will be inserted in + the output. + + @return `error::need_buffers` if there was not enough room in + the internal buffer to insert the bits. + */ + void + prime(int bits, int value, error_code& ec) + { + return doPrime(bits, value, ec); + } +}; + +/** Returns the upper limit on the size of a compressed block. + + This function makes a conservative estimate of the maximum number + of bytes needed to store the result of compressing a block of + data. + + @param bytes The size of the uncompressed data. + + @return The maximum number of resulting compressed bytes. +*/ +std::size_t +deflate_upper_bound(std::size_t bytes); + +/* For the default windowBits of 15 and memLevel of 8, this function returns + a close to exact, as well as small, upper bound on the compressed size. + They are coded as constants here for a reason--if the #define's are + changed, then this function needs to be changed as well. The return + value for 15 and 8 only works for those exact settings. + + For any setting other than those defaults for windowBits and memLevel, + the value returned is a conservative worst case for the maximum expansion + resulting from using fixed blocks instead of stored blocks, which deflate + can emit on compressed data for some combinations of the parameters. + + This function could be more sophisticated to provide closer upper bounds for + every combination of windowBits and memLevel. But even the conservative + upper bound of about 14% expansion does not seem onerous for output buffer + allocation. +*/ +inline +std::size_t +deflate_upper_bound(std::size_t bytes) +{ + return bytes + + ((bytes + 7) >> 3) + + ((bytes + 63) >> 6) + 5 + + 6; +} + +} // zlib +} // beast +} // boost + +#endif |