@@ -86,8 +86,7 @@ class zlib_compressor_base : public compress_provider
8686
8787 if (m_state != Z_OK && m_state != Z_BUF_ERROR && m_state != Z_STREAM_ERROR)
8888 {
89- throw std::runtime_error (" Prior unrecoverable compression stream error " +
90- std::to_string (m_state));
89+ throw std::runtime_error (" Prior unrecoverable compression stream error " + std::to_string (m_state));
9190 }
9291
9392 if (input_size > std::numeric_limits<uInt>::max () || output_size > std::numeric_limits<uInt>::max ())
@@ -294,8 +293,17 @@ class brotli_compressor : public compress_provider
294293
295294 brotli_compressor (uint32_t window = BROTLI_DEFAULT_WINDOW,
296295 uint32_t quality = BROTLI_DEFAULT_QUALITY,
297- uint32_t mode = BROTLI_DEFAULT_MODE)
298- : m_algorithm(BROTLI), m_window(window), m_quality(quality), m_mode(mode)
296+ uint32_t mode = BROTLI_DEFAULT_MODE,
297+ uint32_t block = 0 ,
298+ uint32_t nomodel = 0 ,
299+ uint32_t hint = 0 )
300+ : m_algorithm(BROTLI)
301+ , m_window(window)
302+ , m_quality(quality)
303+ , m_mode(mode)
304+ , m_block(block)
305+ , m_nomodel(nomodel)
306+ , m_hint(hint)
299307 {
300308 (void )reset ();
301309 }
@@ -323,42 +331,36 @@ class brotli_compressor : public compress_provider
323331 }
324332
325333 const uint8_t * next_in = input;
326- size_t avail_in;
334+ size_t avail_in = 0 ;
327335 uint8_t * next_out = output;
328336 size_t avail_out = output_size;
329337 size_t total_out;
330338
331339 if (BrotliEncoderHasMoreOutput (m_stream) == BROTLI_TRUE)
332340 {
333- avail_in = 0 ;
341+ // Drain any compressed bytes remaining from a prior call
334342 do
335343 {
336- m_state = BrotliEncoderCompressStream (m_stream,
337- (hint == operation_hint::is_last) ? BROTLI_OPERATION_FINISH
338- : BROTLI_OPERATION_FLUSH,
339- &avail_in,
340- &next_in,
341- &avail_out,
342- &next_out,
343- &total_out);
344+ m_state = BrotliEncoderCompressStream (
345+ m_stream, BROTLI_OPERATION_FLUSH, &avail_in, &next_in, &avail_out, &next_out, &total_out);
344346 } while (m_state == BROTLI_TRUE && avail_out && BrotliEncoderHasMoreOutput (m_stream) == BROTLI_TRUE);
345347 }
346348
347- if (m_state == BROTLI_TRUE && avail_out)
349+ if (m_state == BROTLI_TRUE && avail_out && input_size )
348350 {
351+ // Compress the caller-supplied buffer
349352 avail_in = input_size;
350353 do
351354 {
352- m_state = BrotliEncoderCompressStream (m_stream,
353- (hint == operation_hint::is_last) ? BROTLI_OPERATION_FINISH
354- : BROTLI_OPERATION_FLUSH,
355- &avail_in,
356- &next_in,
357- &avail_out,
358- &next_out,
359- &total_out);
355+ m_state = BrotliEncoderCompressStream (
356+ m_stream, BROTLI_OPERATION_FLUSH, &avail_in, &next_in, &avail_out, &next_out, &total_out);
360357 } while (m_state == BROTLI_TRUE && avail_out && BrotliEncoderHasMoreOutput (m_stream) == BROTLI_TRUE);
361358 }
359+ else
360+ {
361+ // We're not compressing any new data; ensure calculation sanity
362+ input_size = 0 ;
363+ }
362364
363365 if (m_state != BROTLI_TRUE)
364366 {
@@ -367,7 +369,18 @@ class brotli_compressor : public compress_provider
367369
368370 if (hint == operation_hint::is_last)
369371 {
370- m_done = (BrotliEncoderIsFinished (m_stream) == BROTLI_TRUE);
372+ if (avail_out)
373+ {
374+ // Make one more pass to finalize the compressed stream
375+ _ASSERTE (!avail_in);
376+ m_state = BrotliEncoderCompressStream (
377+ m_stream, BROTLI_OPERATION_FINISH, &avail_in, &next_in, &avail_out, &next_out, &total_out);
378+ if (m_state != BROTLI_TRUE)
379+ {
380+ throw std::runtime_error (" Unrecoverable error finalizing compression stream" );
381+ }
382+ m_done = (BrotliEncoderIsFinished (m_stream) == BROTLI_TRUE);
383+ }
371384 }
372385
373386 input_bytes_processed = input_size - avail_in;
@@ -415,7 +428,19 @@ class brotli_compressor : public compress_provider
415428 }
416429 if (m_state == BROTLI_TRUE && m_mode != BROTLI_DEFAULT_MODE)
417430 {
418- m_state = BrotliEncoderSetParameter (m_stream, BROTLI_PARAM_MODE, m_window);
431+ m_state = BrotliEncoderSetParameter (m_stream, BROTLI_PARAM_MODE, m_mode);
432+ }
433+ if (m_state == BROTLI_TRUE && m_block != 0 )
434+ {
435+ m_state = BrotliEncoderSetParameter (m_stream, BROTLI_PARAM_LGBLOCK, m_block);
436+ }
437+ if (m_state == BROTLI_TRUE && m_nomodel != 0 )
438+ {
439+ m_state = BrotliEncoderSetParameter (m_stream, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING, m_nomodel);
440+ }
441+ if (m_state == BROTLI_TRUE && m_hint != 0 )
442+ {
443+ m_state = BrotliEncoderSetParameter (m_stream, BROTLI_PARAM_SIZE_HINT, m_hint);
419444 }
420445
421446 if (m_state != BROTLI_TRUE)
@@ -439,6 +464,9 @@ class brotli_compressor : public compress_provider
439464 uint32_t m_window;
440465 uint32_t m_quality;
441466 uint32_t m_mode;
467+ uint32_t m_block;
468+ uint32_t m_nomodel;
469+ uint32_t m_hint;
442470 const utility::string_t & m_algorithm;
443471};
444472
@@ -599,7 +627,8 @@ class generic_decompress_factory : public decompress_factory
599627static const std::vector<std::shared_ptr<compress_factory>> g_compress_factories
600628#if defined(CPPREST_HTTP_COMPRESSION)
601629 = {std::make_shared<generic_compress_factory>(
602- algorithm::GZIP, []() -> std::unique_ptr<compress_provider> { return utility::details::make_unique<gzip_compressor>(); }),
630+ algorithm::GZIP,
631+ []() -> std::unique_ptr<compress_provider> { return utility::details::make_unique<gzip_compressor>(); }),
603632 std::make_shared<generic_compress_factory>(
604633 algorithm::DEFLATE,
605634 []() -> std::unique_ptr<compress_provider> { return utility::details::make_unique<deflate_compressor>(); }),
@@ -619,15 +648,17 @@ static const std::vector<std::shared_ptr<decompress_factory>> g_decompress_facto
619648 algorithm::GZIP,
620649 500 ,
621650 []() -> std::unique_ptr<decompress_provider> { return utility::details::make_unique<gzip_decompressor>(); }),
622- std::make_shared<generic_decompress_factory>(
623- algorithm::DEFLATE,
624- 500 ,
625- []() -> std::unique_ptr<decompress_provider> { return utility::details::make_unique<deflate_decompressor>(); }),
651+ std::make_shared<generic_decompress_factory>(algorithm::DEFLATE,
652+ 500 ,
653+ []() -> std::unique_ptr<decompress_provider> {
654+ return utility::details::make_unique<deflate_decompressor>();
655+ }),
626656#if defined(CPPREST_BROTLI_COMPRESSION)
627- std::make_shared<generic_decompress_factory>(
628- algorithm::BROTLI,
629- 500 ,
630- []() -> std::unique_ptr<decompress_provider> { return utility::details::make_unique<brotli_decompressor>(); })
657+ std::make_shared<generic_decompress_factory>(algorithm::BROTLI,
658+ 500 ,
659+ []() -> std::unique_ptr<decompress_provider> {
660+ return utility::details::make_unique<brotli_decompressor>();
661+ })
631662#endif // CPPREST_BROTLI_COMPRESSION
632663};
633664#else // CPPREST_HTTP_COMPRESSION
@@ -713,7 +744,6 @@ std::shared_ptr<decompress_factory> get_decompress_factory(const utility::string
713744 return std::shared_ptr<decompress_factory>();
714745}
715746
716-
717747std::unique_ptr<compress_provider> make_gzip_compressor (int compressionLevel, int method, int strategy, int memLevel)
718748{
719749#if defined(CPPREST_HTTP_COMPRESSION)
@@ -740,14 +770,18 @@ std::unique_ptr<compress_provider> make_deflate_compressor(int compressionLevel,
740770#endif // CPPREST_HTTP_COMPRESSION
741771}
742772
743- std::unique_ptr<compress_provider> make_brotli_compressor (uint32_t window, uint32_t quality, uint32_t mode)
773+ std::unique_ptr<compress_provider> make_brotli_compressor (
774+ uint32_t window, uint32_t quality, uint32_t mode, uint32_t block, uint32_t nomodel, uint32_t hint)
744775{
745776#if defined(CPPREST_HTTP_COMPRESSION) && defined(CPPREST_BROTLI_COMPRESSION)
746- return utility::details::make_unique<brotli_compressor>(window, quality, mode);
777+ return utility::details::make_unique<brotli_compressor>(window, quality, mode, block, nomodel, hint );
747778#else // CPPREST_BROTLI_COMPRESSION
748779 (void )window;
749780 (void )quality;
750781 (void )mode;
782+ (void )block;
783+ (void )nomodel;
784+ (void )hint;
751785 return std::unique_ptr<compress_provider>();
752786#endif // CPPREST_BROTLI_COMPRESSION
753787}
0 commit comments