199 throw std::ios_base::failure(std::string(
"Attempting to create compressed_file from file that does not exist: ") + input_path.
generic_string());
203 if (input_size == 0) {
204 throw std::ios_base::failure(std::string(
"Attempting to create compressed_file from file that is empty: ") + input_path.
generic_string());
211 const auto seek_point_count = (input_size - 1) / seek_point_stride;
212 std::vector<seek_point_entry> seek_point_map(seek_point_count);
216 input_file.
open(
"rb");
220 output_file.
open(
"wb");
223 strm.zalloc = Z_NULL;
225 strm.opaque = Z_NULL;
227 if (deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, raw_zlib_window_bits, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
231 constexpr size_t buffer_size = 64*1024;
232 auto input_buffer = std::vector<uint8_t>(buffer_size);
233 auto output_buffer = std::vector<uint8_t>(buffer_size);
235 auto bytes_remaining_before_sync = seek_point_stride;
236 int next_sync_point = 0;
242 auto process_chunk = [&](
size_t input_size,
int mode ) {
243 strm.avail_in = input_size;
244 strm.next_in = input_buffer.data();
247 strm.avail_out = output_buffer.size();
248 strm.next_out = output_buffer.data();
249 auto ret = deflate(&strm, mode);
251 const bool success =
ret == Z_OK || (mode == Z_FINISH &&
ret == Z_STREAM_END);
256 output_file.
write(
reinterpret_cast<const char*
>(output_buffer.data()), output_buffer.size() - strm.avail_out);
257 }
while (strm.avail_out == 0);
262 size_t read_offset = 0;
263 while (read_offset < input_size) {
264 const auto bytes_remaining = input_size - read_offset;
265 const auto read_size = std::min({ buffer_size, bytes_remaining, bytes_remaining_before_sync });
266 input_file.
read(
reinterpret_cast<char*
>(input_buffer.data()), read_size);
268 auto ret = process_chunk(read_size, Z_NO_FLUSH);
272 read_offset += read_size;
274 if (read_size == bytes_remaining ) {
276 ret = process_chunk(0, Z_FINISH);
280 }
else if ( read_size == bytes_remaining_before_sync ) {
282 ret = process_chunk(0, Z_FULL_FLUSH);
287 seek_point_map.at(next_sync_point++) = {read_offset, output_file.
tellp()};
289 if (next_sync_point == seek_point_count) {
291 bytes_remaining_before_sync = input_size - read_offset + 1;
293 bytes_remaining_before_sync = seek_point_stride;
296 bytes_remaining_before_sync -= read_size;
304 if (seek_point_map.size() > 0) {
305 output_file.
write(
reinterpret_cast<const char*
>(seek_point_map.data()), seek_point_map.size() *
sizeof(seek_point_entry));
309 output_file.
write(
reinterpret_cast<const char*
>(&seek_point_count),
sizeof(seek_point_count_type));