include/boost/http/zstd/decompress.hpp

100.0% Lines (1/0/1) 100.0% List of functions (1/0/1)
decompress.hpp
f(x) Functions (1)
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