| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 | //// Copyright (c) 2016-2019 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_tdeflate_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.*/inlinestd::size_tdeflate_upper_bound(std::size_t bytes){    return bytes +        ((bytes + 7) >> 3) +        ((bytes + 63) >> 6) + 5 +        6;}} // zlib} // beast} // boost#endif
 |