src/detail/decoders.cpp

93.8% Lines (91/97) 100.0% List of functions (14/14) 90.5% Branches (38/42)
decoders.cpp
f(x) Functions (14)
Function Calls Lines Branches Blocks
boost::burl::detail::(anonymous namespace)::zlib_decoder::zlib_decoder(int) :52 12x 80.0% 66.7% 56.0% boost::burl::detail::(anonymous namespace)::zlib_decoder::~zlib_decoder() :58 24x 100.0% 100.0% boost::burl::detail::(anonymous namespace)::zlib_decoder::process(boost::capy::mutable_buffer, boost::capy::const_buffer, bool) :64 179x 100.0% 100.0% 100.0% boost::burl::detail::(anonymous namespace)::zlib_decoder::process(boost::capy::mutable_buffer, boost::capy::const_buffer, bool)::{lambda()#1}::operator()() const :79 179x 100.0% 100.0% 100.0% boost::burl::detail::(anonymous namespace)::zlib_decoder::saturate(unsigned long) :96 716x 80.0% 50.0% 75.0% boost::burl::detail::(anonymous namespace)::brotli_decoder::brotli_decoder() :114 7x 83.3% 66.7% 56.0% boost::burl::detail::(anonymous namespace)::brotli_decoder::~brotli_decoder() :122 14x 100.0% 100.0% boost::burl::detail::(anonymous namespace)::brotli_decoder::process(boost::capy::mutable_buffer, boost::capy::const_buffer, bool) :128 111x 100.0% 100.0% 92.0% boost::burl::detail::(anonymous namespace)::brotli_decoder::process(boost::capy::mutable_buffer, boost::capy::const_buffer, bool)::{lambda()#1}::operator()() const :146 111x 90.0% 100.0% 100.0% boost::burl::detail::(anonymous namespace)::zstd_decoder::zstd_decoder() :170 7x 83.3% 75.0% 60.0% boost::burl::detail::(anonymous namespace)::zstd_decoder::~zstd_decoder() :178 14x 100.0% 100.0% boost::burl::detail::(anonymous namespace)::zstd_decoder::process(boost::capy::mutable_buffer, boost::capy::const_buffer, bool) :184 122x 100.0% 100.0% 90.0% boost::burl::detail::(anonymous namespace)::zstd_decoder::process(boost::capy::mutable_buffer, boost::capy::const_buffer, bool)::{lambda()#1}::operator()() const :195 122x 90.0% 100.0% 100.0% boost::burl::detail::make_decoder(boost::http::content_coding) :215 51x 100.0% 100.0% 81.0%
Line Branch 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/burl
8 //
9
10 #include "decoders.hpp"
11
12 #include <boost/burl/error.hpp>
13
14 #include <boost/capy/error.hpp>
15
16 #include <cstdint>
17 #include <limits>
18 #include <new>
19 #include <system_error>
20
21 #ifdef BOOST_BURL_HAS_ZLIB
22 #include <zlib.h>
23 #endif
24
25 #ifdef BOOST_BURL_HAS_BROTLI
26 #include <brotli/decode.h>
27 #endif
28
29 #ifdef BOOST_BURL_HAS_ZSTD
30 #include <zstd.h>
31 #endif
32
33 namespace boost
34 {
35 namespace burl
36 {
37 namespace detail
38 {
39
40 namespace
41 {
42
43 #ifdef BOOST_BURL_HAS_ZLIB
44 class zlib_decoder final
45 : public parser::decoder
46 {
47 z_stream strm_ = {};
48
49 public:
50 // window_bits: 15 for zlib/deflate, 15 + 16 for gzip.
51 explicit
52 12x zlib_decoder(int window_bits)
53 12x {
54
2/3
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12x if(inflateInit2(&strm_, window_bits) != Z_OK)
55 throw std::bad_alloc();
56 12x }
57
58 24x ~zlib_decoder() override
59 12x {
60 12x inflateEnd(&strm_);
61 24x }
62
63 result
64 179x process(
65 capy::mutable_buffer out,
66 capy::const_buffer in,
67 bool eof) override
68 {
69 179x strm_.next_in = static_cast<unsigned char*>(
70 179x const_cast<void*>(in.data()));
71 179x strm_.avail_in = saturate(in.size());
72 179x strm_.next_out =
73 179x static_cast<unsigned char*>(out.data());
74 179x strm_.avail_out = saturate(out.size());
75
76
3/3
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 151 times.
✓ Branch 3 taken 179 times.
179x auto const rs = ::inflate(
77 179x &strm_, eof ? Z_FINISH : Z_NO_FLUSH);
78
79 537x auto const ec = [&]() -> std::error_code
80 {
81
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 169 times.
179x if(rs == Z_STREAM_END)
82 10x return capy::error::eof;
83
4/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 18 times.
169x if(rs != Z_OK && rs != Z_BUF_ERROR)
84 1x return error::decode_error;
85 168x return {};
86 179x }();
87
88 return {
89 179x .consumed = saturate(in.size()) - strm_.avail_in,
90 179x .produced = saturate(out.size()) - strm_.avail_out,
91 358x .ec = ec };
92 }
93
94 static
95 unsigned
96 716x saturate(std::size_t n) noexcept
97 {
98 716x constexpr auto max =
99 (std::numeric_limits<unsigned>::max)();
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 716 times.
716x if(n >= max)
101 return max;
102 716x return static_cast<unsigned>(n);
103 }
104 };
105 #endif // BOOST_BURL_HAS_ZLIB
106
107 #ifdef BOOST_BURL_HAS_BROTLI
108 class brotli_decoder final
109 : public parser::decoder
110 {
111 BrotliDecoderState* state_;
112
113 public:
114 7x brotli_decoder()
115 21x : state_(BrotliDecoderCreateInstance(
116
1/1
✓ Branch 2 taken 7 times.
7x nullptr, nullptr, nullptr))
117 {
118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7x if(!state_)
119 throw std::bad_alloc();
120 7x }
121
122 14x ~brotli_decoder() override
123 7x {
124 7x BrotliDecoderDestroyInstance(state_);
125 14x }
126
127 result
128 111x process(
129 capy::mutable_buffer out,
130 capy::const_buffer in,
131 bool eof) override
132 {
133 111x auto* next_in = static_cast<std::uint8_t const*>(in.data());
134 111x auto available_in = in.size();
135 111x auto* next_out = static_cast<std::uint8_t*>(out.data());
136 111x auto available_out = out.size();
137
138
1/1
✓ Branch 1 taken 111 times.
111x auto const rs = BrotliDecoderDecompressStream(
139 state_,
140 &available_in,
141 &next_in,
142 &available_out,
143 &next_out,
144 111x nullptr);
145
146 auto const ec = [&]() -> std::error_code
147 {
148
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 105 times.
111x if(BrotliDecoderIsFinished(state_))
149 6x return capy::error::eof;
150
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 104 times.
105x if(rs == BROTLI_DECODER_RESULT_ERROR)
151 1x return error::decode_error;
152 104x return {};
153
1/1
✓ Branch 1 taken 111 times.
111x }();
154
155 return {
156 111x .consumed = in.size() - available_in,
157 222x .produced = out.size() - available_out,
158 111x .ec = ec };
159 }
160 };
161 #endif // BOOST_BURL_HAS_BROTLI
162
163 #ifdef BOOST_BURL_HAS_ZSTD
164 class zstd_decoder final
165 : public parser::decoder
166 {
167 ZSTD_DStream* strm_;
168
169 public:
170 7x zstd_decoder()
171
1/1
✓ Branch 2 taken 7 times.
7x : strm_(ZSTD_createDStream())
172 {
173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7x if(!strm_)
174 throw std::bad_alloc();
175
1/1
✓ Branch 1 taken 7 times.
7x ZSTD_initDStream(strm_);
176 7x }
177
178 14x ~zstd_decoder() override
179 7x {
180 7x ZSTD_freeDStream(strm_);
181 14x }
182
183 result
184 122x process(
185 capy::mutable_buffer out,
186 capy::const_buffer in,
187 bool eof) override
188 {
189 122x ZSTD_inBuffer in_buf{ in.data(), in.size(), 0 };
190 122x ZSTD_outBuffer out_buf{ out.data(), out.size(), 0 };
191
192 auto const rs =
193
1/1
✓ Branch 1 taken 122 times.
122x ZSTD_decompressStream(strm_, &out_buf, &in_buf);
194
195 auto const ec = [&]() -> std::error_code
196 {
197
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 117 times.
122x if(rs == 0)
198 5x return capy::error::eof;
199
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 116 times.
117x if(ZSTD_isError(rs))
200 1x return error::decode_error;
201 116x return {};
202
1/1
✓ Branch 1 taken 122 times.
122x }();
203
204 return {
205 122x .consumed = in_buf.pos,
206 122x .produced = out_buf.pos,
207 122x .ec = ec };
208 }
209 };
210 #endif // BOOST_BURL_HAS_ZSTD
211
212 } // namespace
213
214 std::unique_ptr<parser::decoder>
215 51x make_decoder(http::content_coding coding)
216 {
217
5/5
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 25 times.
51x switch(coding)
218 {
219 #ifdef BOOST_BURL_HAS_ZLIB
220 3x case http::content_coding::deflate:
221
1/1
✓ Branch 1 taken 3 times.
3x return std::make_unique<zlib_decoder>(15);
222 9x case http::content_coding::gzip:
223
1/1
✓ Branch 1 taken 9 times.
9x return std::make_unique<zlib_decoder>(15 + 16);
224 #endif
225 #ifdef BOOST_BURL_HAS_BROTLI
226 7x case http::content_coding::br:
227
1/1
✓ Branch 1 taken 7 times.
7x return std::make_unique<brotli_decoder>();
228 #endif
229 #ifdef BOOST_BURL_HAS_ZSTD
230 7x case http::content_coding::zstd:
231
1/1
✓ Branch 1 taken 7 times.
7x return std::make_unique<zstd_decoder>();
232 #endif
233 25x default:
234 25x break;
235 }
236 25x return nullptr;
237 }
238
239 } // namespace detail
240 } // namespace burl
241 } // namespace boost
242