size_t io::compressed::zlib_decompression_reader::read_some()

in src/native/io/compressed/zlib_decompression_reader.cpp [49:101]


size_t io::compressed::zlib_decompression_reader::read_some(std::span<char> output_buffer)
{
	size_t remaining_to_write = output_buffer.size();
	uint64_t total_read{0};

	while (true)
	{
		m_zstr.next_out = reinterpret_cast<Bytef *>(output_buffer.data() + total_read);

		uInt avail_out_capacity =
			static_cast<uInt>(std::min(remaining_to_write, (size_t)std::numeric_limits<uInt>::max));
		m_zstr.avail_out = avail_out_capacity;

		if (m_zstr.avail_in == 0)
		{
			auto actual_read = m_reader->read_some(std::span{m_input_data.data(), m_input_data.capacity()});
			m_zstr.next_in   = reinterpret_cast<Bytef *>(m_input_data.data());
			m_zstr.avail_in  = static_cast<uInt>(actual_read);
		}

		int ret = ::inflate(&m_zstr, Z_NO_FLUSH);

		if (ret == Z_OK || ret == Z_STREAM_END)
		{
			if (m_zstr.avail_out < avail_out_capacity)
			{
				size_t written = avail_out_capacity - m_zstr.avail_out;
				remaining_to_write -= written;
				total_read += written;
			}
		}

		if (ret == Z_STREAM_END)
		{
			inflateEnd(&m_zstr);
			break;
		}

		if (ret != Z_OK)
		{
			auto msg = "inflate() failed. ret: " + std::to_string(ret);
			throw errors::user_exception(errors::error_code::io_zlib_reader_inflate_failed, msg);
		}

		if (remaining_to_write == 0)
		{
			break;
		}
	}

	m_read_offset += total_read;
	return total_read;
}