include/boost/http/zstd/decompress.hpp
100.0% Lines (1/0/1)
100.0% List of functions (1/0/1)
Functions (1)
Function
Calls
Lines
Blocks
boost::http::zstd::decompress_service::shutdown()
:454
5x
100.0%
100.0%
| Line | TLA | Hits | Source Code |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2026 Mohammad Nejati | ||
| 3 | // | ||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 6 | // | ||
| 7 | // Official repository: https://github.com/cppalliance/http | ||
| 8 | // | ||
| 9 | |||
| 10 | #ifndef BOOST_HTTP_ZSTD_DECOMPRESS_HPP | ||
| 11 | #define BOOST_HTTP_ZSTD_DECOMPRESS_HPP | ||
| 12 | |||
| 13 | #include <boost/http/detail/config.hpp> | ||
| 14 | #include <boost/http/zstd/error.hpp> | ||
| 15 | #include <boost/http/zstd/service.hpp> | ||
| 16 | #include <boost/http/zstd/types.hpp> | ||
| 17 | |||
| 18 | #include <boost/capy/ex/execution_context.hpp> | ||
| 19 | |||
| 20 | #include <cstddef> | ||
| 21 | |||
| 22 | namespace boost { | ||
| 23 | namespace http { | ||
| 24 | namespace zstd { | ||
| 25 | |||
| 26 | /** Opaque structure that holds decompression context state. | ||
| 27 | |||
| 28 | A context is created with @ref decompress_service::create_dctx | ||
| 29 | and released with @ref decompress_service::free_dctx. It holds | ||
| 30 | the sticky parameters and the state of the frame being | ||
| 31 | decompressed, and may be reused for successive frames. | ||
| 32 | */ | ||
| 33 | struct dctx; | ||
| 34 | |||
| 35 | /** Opaque structure that holds a digested decompression dictionary. | ||
| 36 | |||
| 37 | Created with @ref decompress_service::create_ddict and released | ||
| 38 | with @ref decompress_service::free_ddict. A digested dictionary | ||
| 39 | is read-only and may be shared by multiple contexts and threads. | ||
| 40 | */ | ||
| 41 | struct ddict; | ||
| 42 | |||
| 43 | /** Decompression parameter identifiers. | ||
| 44 | |||
| 45 | These values identify parameters that can be set on a | ||
| 46 | decompression context with @ref decompress_service::set_parameter. | ||
| 47 | Parameters are sticky and remain valid for all following frames. | ||
| 48 | */ | ||
| 49 | enum class d_parameter | ||
| 50 | { | ||
| 51 | /** Maximum window size accepted, as a power of 2. | ||
| 52 | |||
| 53 | In streaming mode the decoder refuses to allocate a | ||
| 54 | buffer larger than this, protecting the host from | ||
| 55 | unreasonable memory requirements. Zero selects the | ||
| 56 | default limit. | ||
| 57 | */ | ||
| 58 | window_log_max = 100 | ||
| 59 | }; | ||
| 60 | |||
| 61 | /** Provides the Zstandard decompression API. | ||
| 62 | |||
| 63 | This service interface exposes Zstandard decompression | ||
| 64 | functionality through a set of virtual functions. Data | ||
| 65 | can be decompressed in one shot with @ref decompress or | ||
| 66 | @ref decompress_dctx when the content size is known, or | ||
| 67 | incrementally with @ref decompress_stream. | ||
| 68 | |||
| 69 | Most functions return a `std::size_t` which is either a | ||
| 70 | byte count or an encoded error code. Test results with | ||
| 71 | @ref is_error and convert them with @ref get_error_code | ||
| 72 | or @ref get_error_name. | ||
| 73 | |||
| 74 | @code | ||
| 75 | // Example: Simple one-shot decompression | ||
| 76 | auto& decompressor = boost::http::zstd::install_decompress_service(ctx); | ||
| 77 | |||
| 78 | std::vector<char> compressed = get_compressed_data(); | ||
| 79 | auto size = decompressor.get_frame_content_size( | ||
| 80 | compressed.data(), compressed.size()); | ||
| 81 | if (size == boost::http::zstd::content_size_error || | ||
| 82 | size == boost::http::zstd::content_size_unknown) | ||
| 83 | return; // invalid frame, or streaming mode is required | ||
| 84 | |||
| 85 | std::vector<char> output(size); | ||
| 86 | std::size_t n = decompressor.decompress( | ||
| 87 | output.data(), output.size(), | ||
| 88 | compressed.data(), compressed.size()); | ||
| 89 | |||
| 90 | if (! decompressor.is_error(n)) | ||
| 91 | { | ||
| 92 | // Use decompressed data | ||
| 93 | } | ||
| 94 | @endcode | ||
| 95 | |||
| 96 | @code | ||
| 97 | // Example: Streaming decompression | ||
| 98 | auto* ctx = decompressor.create_dctx(); | ||
| 99 | |||
| 100 | std::vector<char> buf(decompressor.stream_out_size()); | ||
| 101 | boost::http::zstd::in_buffer in{ compressed.data(), compressed.size(), 0 }; | ||
| 102 | std::size_t rs; | ||
| 103 | do | ||
| 104 | { | ||
| 105 | boost::http::zstd::out_buffer out{ buf.data(), buf.size(), 0 }; | ||
| 106 | rs = decompressor.decompress_stream(ctx, out, in); | ||
| 107 | if (decompressor.is_error(rs)) | ||
| 108 | break; | ||
| 109 | output.insert(output.end(), buf.data(), buf.data() + out.pos); | ||
| 110 | } | ||
| 111 | while (rs != 0); | ||
| 112 | |||
| 113 | decompressor.free_dctx(ctx); | ||
| 114 | @endcode | ||
| 115 | */ | ||
| 116 | struct BOOST_SYMBOL_VISIBLE | ||
| 117 | decompress_service | ||
| 118 | : capy::execution_context::service | ||
| 119 | { | ||
| 120 | /** Return the Zstandard library version number. | ||
| 121 | @return The version as `MAJOR * 10000 + MINOR * 100 + RELEASE`. | ||
| 122 | */ | ||
| 123 | virtual | ||
| 124 | unsigned | ||
| 125 | version_number() const noexcept = 0; | ||
| 126 | |||
| 127 | /** Return the Zstandard library version string. | ||
| 128 | @return Pointer to a string such as "1.5.7". | ||
| 129 | */ | ||
| 130 | virtual | ||
| 131 | char const* | ||
| 132 | version_string() const noexcept = 0; | ||
| 133 | |||
| 134 | /** Decompress data in one call. | ||
| 135 | |||
| 136 | The input must be the exact size of one or more | ||
| 137 | complete frames; the output is their concatenation. | ||
| 138 | |||
| 139 | @param dst Output buffer. | ||
| 140 | @param dst_capacity Output buffer size; an upper bound | ||
| 141 | of the decompressed size. | ||
| 142 | @param src Compressed data. | ||
| 143 | @param compressed_size Compressed data size. | ||
| 144 | @return The decompressed size, or an error code. | ||
| 145 | */ | ||
| 146 | virtual | ||
| 147 | std::size_t | ||
| 148 | decompress( | ||
| 149 | void* dst, | ||
| 150 | std::size_t dst_capacity, | ||
| 151 | void const* src, | ||
| 152 | std::size_t compressed_size) const noexcept = 0; | ||
| 153 | |||
| 154 | /** Return the decompressed size recorded in a frame header. | ||
| 155 | |||
| 156 | The size is an optional field which is always present | ||
| 157 | for frames produced by the one-shot functions, and may | ||
| 158 | be absent for frames produced in streaming mode. If the | ||
| 159 | source is untrusted the value may be wrong; always check | ||
| 160 | it against an application limit. | ||
| 161 | |||
| 162 | @param src Start of a frame. | ||
| 163 | @param src_size Number of bytes available; must cover | ||
| 164 | the frame header. | ||
| 165 | @return The content size, @ref content_size_unknown if | ||
| 166 | it is not recorded, or @ref content_size_error | ||
| 167 | if the header is invalid or incomplete. | ||
| 168 | */ | ||
| 169 | virtual | ||
| 170 | unsigned long long | ||
| 171 | get_frame_content_size( | ||
| 172 | void const* src, | ||
| 173 | std::size_t src_size) const noexcept = 0; | ||
| 174 | |||
| 175 | /** Return the compressed size of the first frame. | ||
| 176 | |||
| 177 | This may need to scan the whole frame to find its end. | ||
| 178 | |||
| 179 | @param src Start of a frame or skippable frame. | ||
| 180 | @param src_size Number of bytes available; must cover | ||
| 181 | the whole first frame. | ||
| 182 | @return The compressed size of the first frame, or an | ||
| 183 | error code. | ||
| 184 | */ | ||
| 185 | virtual | ||
| 186 | std::size_t | ||
| 187 | find_frame_compressed_size( | ||
| 188 | void const* src, | ||
| 189 | std::size_t src_size) const noexcept = 0; | ||
| 190 | |||
| 191 | /** Create a new decompression context. | ||
| 192 | @return Pointer to the context, or nullptr on error. | ||
| 193 | */ | ||
| 194 | virtual | ||
| 195 | dctx* | ||
| 196 | create_dctx() const noexcept = 0; | ||
| 197 | |||
| 198 | /** Release a decompression context. | ||
| 199 | @param ctx The context to release; may be nullptr. | ||
| 200 | @return Zero, or an error code. | ||
| 201 | */ | ||
| 202 | virtual | ||
| 203 | std::size_t | ||
| 204 | free_dctx(dctx* ctx) const noexcept = 0; | ||
| 205 | |||
| 206 | /** Return the current memory usage of a decompression context. | ||
| 207 | @param ctx The context. | ||
| 208 | @return Memory usage in bytes. | ||
| 209 | */ | ||
| 210 | virtual | ||
| 211 | std::size_t | ||
| 212 | sizeof_dctx(dctx const* ctx) const noexcept = 0; | ||
| 213 | |||
| 214 | /** Return the valid bounds of a decompression parameter. | ||
| 215 | @param param The parameter identifier. | ||
| 216 | @return The bounds; test the `error` field with @ref is_error. | ||
| 217 | */ | ||
| 218 | virtual | ||
| 219 | bounds | ||
| 220 | param_bounds(d_parameter param) const noexcept = 0; | ||
| 221 | |||
| 222 | /** Set a decompression parameter. | ||
| 223 | |||
| 224 | Parameters can only be set between frames, before | ||
| 225 | decompression of the next frame starts. | ||
| 226 | |||
| 227 | @param ctx The context. | ||
| 228 | @param param The parameter identifier. | ||
| 229 | @param value The parameter value. | ||
| 230 | @return Zero, or an error code. | ||
| 231 | */ | ||
| 232 | virtual | ||
| 233 | std::size_t | ||
| 234 | set_parameter( | ||
| 235 | dctx* ctx, | ||
| 236 | d_parameter param, | ||
| 237 | int value) const noexcept = 0; | ||
| 238 | |||
| 239 | /** Reset a decompression context. | ||
| 240 | @param ctx The context. | ||
| 241 | @param directive What to reset. | ||
| 242 | @return Zero, or an error code. | ||
| 243 | */ | ||
| 244 | virtual | ||
| 245 | std::size_t | ||
| 246 | reset( | ||
| 247 | dctx* ctx, | ||
| 248 | reset_directive directive) const noexcept = 0; | ||
| 249 | |||
| 250 | /** Decompress data in one call using a context. | ||
| 251 | |||
| 252 | Behaves like @ref decompress, honoring the parameters | ||
| 253 | and dictionary set on the context. | ||
| 254 | |||
| 255 | @param ctx The context. | ||
| 256 | @param dst Output buffer. | ||
| 257 | @param dst_capacity Output buffer size. | ||
| 258 | @param src Compressed data. | ||
| 259 | @param src_size Compressed data size. | ||
| 260 | @return The decompressed size, or an error code. | ||
| 261 | */ | ||
| 262 | virtual | ||
| 263 | std::size_t | ||
| 264 | decompress_dctx( | ||
| 265 | dctx* ctx, | ||
| 266 | void* dst, | ||
| 267 | std::size_t dst_capacity, | ||
| 268 | void const* src, | ||
| 269 | std::size_t src_size) const noexcept = 0; | ||
| 270 | |||
| 271 | /** Decompress data in streaming mode. | ||
| 272 | |||
| 273 | Consumes input from `input` and writes output to | ||
| 274 | `output`, advancing the `pos` field of each. If | ||
| 275 | `input.pos < input.size` afterwards, the remaining | ||
| 276 | input must be presented again. If the output buffer | ||
| 277 | was filled completely, data may still be buffered | ||
| 278 | internally; call again to flush it. | ||
| 279 | |||
| 280 | @param ctx The context. | ||
| 281 | @param output The output buffer. | ||
| 282 | @param input The input buffer. | ||
| 283 | @return Zero when a frame is completely decoded and | ||
| 284 | fully flushed, an error code, or any other | ||
| 285 | value which means more decoding or flushing | ||
| 286 | is needed to complete the frame. The value | ||
| 287 | is a hint for the next input size. | ||
| 288 | */ | ||
| 289 | virtual | ||
| 290 | std::size_t | ||
| 291 | decompress_stream( | ||
| 292 | dctx* ctx, | ||
| 293 | out_buffer& output, | ||
| 294 | in_buffer& input) const noexcept = 0; | ||
| 295 | |||
| 296 | /** Return the recommended input buffer size for streaming. | ||
| 297 | @return Size in bytes. | ||
| 298 | */ | ||
| 299 | virtual | ||
| 300 | std::size_t | ||
| 301 | stream_in_size() const noexcept = 0; | ||
| 302 | |||
| 303 | /** Return the recommended output buffer size for streaming. | ||
| 304 | |||
| 305 | An output buffer of this size is guaranteed to be able | ||
| 306 | to flush at least one complete block in all circumstances. | ||
| 307 | |||
| 308 | @return Size in bytes. | ||
| 309 | */ | ||
| 310 | virtual | ||
| 311 | std::size_t | ||
| 312 | stream_out_size() const noexcept = 0; | ||
| 313 | |||
| 314 | /** Create a digested dictionary for decompression. | ||
| 315 | @param dict The dictionary content; copied internally. | ||
| 316 | @param dict_size The dictionary size. | ||
| 317 | @return Pointer to the dictionary, or nullptr on error. | ||
| 318 | */ | ||
| 319 | virtual | ||
| 320 | ddict* | ||
| 321 | create_ddict( | ||
| 322 | void const* dict, | ||
| 323 | std::size_t dict_size) const noexcept = 0; | ||
| 324 | |||
| 325 | /** Release a digested dictionary. | ||
| 326 | @param dict The dictionary to release; may be nullptr. | ||
| 327 | @return Zero, or an error code. | ||
| 328 | */ | ||
| 329 | virtual | ||
| 330 | std::size_t | ||
| 331 | free_ddict(ddict* dict) const noexcept = 0; | ||
| 332 | |||
| 333 | /** Return the current memory usage of a digested dictionary. | ||
| 334 | @param dict The dictionary. | ||
| 335 | @return Memory usage in bytes. | ||
| 336 | */ | ||
| 337 | virtual | ||
| 338 | std::size_t | ||
| 339 | sizeof_ddict(ddict const* dict) const noexcept = 0; | ||
| 340 | |||
| 341 | /** Load a dictionary into a context. | ||
| 342 | |||
| 343 | The content is copied and digested; it is used for all | ||
| 344 | future frames until another dictionary is loaded or the | ||
| 345 | parameters are reset. Loading a null or empty dictionary | ||
| 346 | returns to no-dictionary mode. | ||
| 347 | |||
| 348 | @param ctx The context. | ||
| 349 | @param dict The dictionary content. | ||
| 350 | @param dict_size The dictionary size. | ||
| 351 | @return Zero, or an error code. | ||
| 352 | */ | ||
| 353 | virtual | ||
| 354 | std::size_t | ||
| 355 | load_dictionary( | ||
| 356 | dctx* ctx, | ||
| 357 | void const* dict, | ||
| 358 | std::size_t dict_size) const noexcept = 0; | ||
| 359 | |||
| 360 | /** Reference a digested dictionary from a context. | ||
| 361 | |||
| 362 | The dictionary is only referenced and must outlive its | ||
| 363 | use by the context. Referencing nullptr returns to | ||
| 364 | no-dictionary mode. | ||
| 365 | |||
| 366 | @param ctx The context. | ||
| 367 | @param dict The digested dictionary. | ||
| 368 | @return Zero, or an error code. | ||
| 369 | */ | ||
| 370 | virtual | ||
| 371 | std::size_t | ||
| 372 | ref_ddict( | ||
| 373 | dctx* ctx, | ||
| 374 | ddict const* dict) const noexcept = 0; | ||
| 375 | |||
| 376 | /** Reference a prefix for the next frame. | ||
| 377 | |||
| 378 | The prefix must be the same raw content used with | ||
| 379 | @ref compress_service::ref_prefix during compression. | ||
| 380 | It is used once and discarded when the frame ends. | ||
| 381 | The buffer is only referenced and must remain valid | ||
| 382 | and unmodified until then. | ||
| 383 | |||
| 384 | @param ctx The context. | ||
| 385 | @param prefix The prefix content. | ||
| 386 | @param prefix_size The prefix size. | ||
| 387 | @return Zero, or an error code. | ||
| 388 | */ | ||
| 389 | virtual | ||
| 390 | std::size_t | ||
| 391 | ref_prefix( | ||
| 392 | dctx* ctx, | ||
| 393 | void const* prefix, | ||
| 394 | std::size_t prefix_size) const noexcept = 0; | ||
| 395 | |||
| 396 | /** Return the dictionary ID stored within a dictionary. | ||
| 397 | @param dict The dictionary content. | ||
| 398 | @param dict_size The dictionary size. | ||
| 399 | @return The dictionary ID, or zero if the content is | ||
| 400 | not a conformant dictionary. | ||
| 401 | */ | ||
| 402 | virtual | ||
| 403 | unsigned | ||
| 404 | get_dict_id_from_dict( | ||
| 405 | void const* dict, | ||
| 406 | std::size_t dict_size) const noexcept = 0; | ||
| 407 | |||
| 408 | /** Return the dictionary ID required to decompress a frame. | ||
| 409 | @param src Start of a frame. | ||
| 410 | @param src_size Number of bytes available. | ||
| 411 | @return The dictionary ID, or zero if the frame needs | ||
| 412 | no dictionary, the ID was omitted, the header | ||
| 413 | is incomplete, or this is not a frame. | ||
| 414 | */ | ||
| 415 | virtual | ||
| 416 | unsigned | ||
| 417 | get_dict_id_from_frame( | ||
| 418 | void const* src, | ||
| 419 | std::size_t src_size) const noexcept = 0; | ||
| 420 | |||
| 421 | /** Check whether a result is an error code. | ||
| 422 | @param result A value returned from a function of this service. | ||
| 423 | @return True if the result encodes an error. | ||
| 424 | */ | ||
| 425 | virtual | ||
| 426 | bool | ||
| 427 | is_error(std::size_t result) const noexcept = 0; | ||
| 428 | |||
| 429 | /** Convert a result to an error code. | ||
| 430 | @param result A value returned from a function of this service. | ||
| 431 | @return The error code, or @ref error::no_error. | ||
| 432 | */ | ||
| 433 | virtual | ||
| 434 | error | ||
| 435 | get_error_code(std::size_t result) const noexcept = 0; | ||
| 436 | |||
| 437 | /** Return a readable description of a result. | ||
| 438 | @param result A value returned from a function of this service. | ||
| 439 | @return Pointer to a description string. | ||
| 440 | */ | ||
| 441 | virtual | ||
| 442 | char const* | ||
| 443 | get_error_name(std::size_t result) const noexcept = 0; | ||
| 444 | |||
| 445 | /** Return a string description of an error code. | ||
| 446 | @param c The error code. | ||
| 447 | @return Pointer to error description string. | ||
| 448 | */ | ||
| 449 | virtual | ||
| 450 | char const* | ||
| 451 | error_string(error c) const noexcept = 0; | ||
| 452 | |||
| 453 | protected: | ||
| 454 | 5x | void shutdown() override {} | |
| 455 | }; | ||
| 456 | |||
| 457 | } // zstd | ||
| 458 | } // http | ||
| 459 | } // boost | ||
| 460 | |||
| 461 | #endif | ||
| 462 |