197 {
199 throw std::ios_base::failure(std::string(
"Attempting to create compressed_file from file that does not exist: ") + input_path.
generic_string());
200 }
201
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());
205 }
206
207
208
209
210
211 const auto seek_point_count = (input_size - 1) / seek_point_stride;
212 std::vector<seek_point_entry> seek_point_map(seek_point_count);
213
216 input_file.
open(
"rb");
217
220 output_file.
open(
"wb");
221
222 z_stream strm;
223 strm.zalloc = Z_NULL;
224 strm.zfree = Z_NULL;
225 strm.opaque = Z_NULL;
226
227 if (deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, raw_zlib_window_bits, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
228 return false;
229 }
230
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);
234
235 auto bytes_remaining_before_sync = seek_point_stride;
236 int next_sync_point = 0;
237
238
239
240
241
242 auto process_chunk = [&]( size_t input_size, int mode ) {
243 strm.avail_in = input_size;
244 strm.next_in = input_buffer.data();
245
246 do {
247 strm.avail_out = output_buffer.size();
248 strm.next_out = output_buffer.data();
249 auto ret = deflate(&strm, mode);
250
251 const bool success =
ret == Z_OK || (mode == Z_FINISH &&
ret == Z_STREAM_END);
252 if (!success) {
254 }
255
256 output_file.
write(
reinterpret_cast<const char*
>(output_buffer.data()), output_buffer.size() - strm.avail_out);
257 } while (strm.avail_out == 0);
258
259 return Z_OK;
260 };
261
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);
267
268 auto ret = process_chunk(read_size, Z_NO_FLUSH);
270 throw compressed_file_error(std::string(
"deflate failed: ") + std::to_string(
ret));
271 }
272 read_offset += read_size;
273
274 if (read_size == bytes_remaining ) {
275
276 ret = process_chunk(0, Z_FINISH);
278 throw compressed_file_error(std::string(
"failed to finalize file compression: ") + std::to_string(
ret));
279 }
280 } else if ( read_size == bytes_remaining_before_sync ) {
281
282 ret = process_chunk(0, Z_FULL_FLUSH);
284 throw compressed_file_error(std::string(
"failed to create sync point: ") + std::to_string(
ret));
285 }
286
287 seek_point_map.at(next_sync_point++) = {read_offset, output_file.
tellp()};
288
289 if (next_sync_point == seek_point_count) {
290
291 bytes_remaining_before_sync = input_size - read_offset + 1;
292 } else {
293 bytes_remaining_before_sync = seek_point_stride;
294 }
295 } else {
296 bytes_remaining_before_sync -= read_size;
297 }
298 }
299
300 deflateEnd(&strm);
302
303
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));
306 }
307
308
309 output_file.
write(
reinterpret_cast<const char*
>(&seek_point_count),
sizeof(seek_point_count_type));
310
312 return true;
313}
void read(char *d, size_t n)
void open(const char *mode)
void set_file_path(fc::path file_path)
void write(const char *d, size_t n)
std::string generic_string() const
bool exists(const path &p)