-
-
Notifications
You must be signed in to change notification settings - Fork 168
Expand file tree
/
Copy pathdecompress_zlib.cpp
More file actions
66 lines (62 loc) · 2.24 KB
/
decompress_zlib.cpp
File metadata and controls
66 lines (62 loc) · 2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "utils/decompress/decompress_zlib.h"
#include <zlib.h>
#include "utils/utils.hpp"
namespace cpptrace {
namespace detail {
Result<monostate, internal_error> decompress_zlib(
bspan decompressed_data,
base_file& compressed_file,
off_t offset,
size_t compressed_size
) {
// zlib docs provide an example of 16K and also says:
// Larger buffer sizes would be more efficient, especially for inflate(). If the memory is
// available, buffers sizes on the order of 128K or 256K bytes should be used.
constexpr size_t kChunkSize = 262144; // 256K
z_stream strm{};
int ret = inflateInit(&strm);
if(ret != Z_OK) {
return internal_error("zlib inflateInit failed");
}
std::unique_ptr<z_stream, decltype(&inflateEnd)> strm_raii(&strm, inflateEnd);
size_t total_read = 0;
size_t total_written = 0;
std::vector<char> chunk_buffer(kChunkSize);
strm.next_out = reinterpret_cast<Bytef*>(decompressed_data.data());
strm.avail_out = static_cast<uInt>(decompressed_data.size());
while(total_read < compressed_size) {
size_t to_read = std::min(kChunkSize, compressed_size - total_read);
auto read_res = compressed_file.read_span(
cpptrace::detail::make_span(chunk_buffer.begin(), chunk_buffer.begin() + static_cast<std::ptrdiff_t>(to_read)),
static_cast<off_t>(offset + total_read)
);
if(!read_res) {
return read_res.unwrap_error();
}
strm.next_in = reinterpret_cast<Bytef*>(chunk_buffer.data());
strm.avail_in = static_cast<uInt>(to_read);
while(strm.avail_in > 0) {
ret = inflate(&strm, Z_NO_FLUSH);
if(ret == Z_STREAM_END) {
break;
}
if(ret != Z_OK) {
return internal_error("zlib inflate failed");
}
}
total_read += to_read;
total_written = strm.total_out;
if(ret == Z_STREAM_END) {
break;
}
}
if(ret != Z_STREAM_END) {
return internal_error("zlib did not reach stream end");
}
if(total_written != decompressed_data.size()) {
return internal_error("zlib decompressed size mismatch");
}
return monostate{};
}
} // namespace detail
}