1 #include <mbgl/util/compression.hpp>
2
3 #if defined(__QT__) && defined(_WINDOWS) && !defined(__GNUC__)
4 #include <QtZlib/zlib.h>
5 #else
6 #include <zlib.h>
7 #endif
8
9 #include <cstdio>
10 #include <cstring>
11 #include <stdexcept>
12
13 // Check zlib library version.
__anonae6a6b5d0102() 14 const static bool zlibVersionCheck __attribute__((unused)) = []() {
15 const char *const version = zlibVersion();
16 if (version[0] != ZLIB_VERSION[0]) {
17 char message[96];
18 snprintf(message, 96, "zlib version mismatch: headers report %s, but library reports %s",
19 ZLIB_VERSION, version);
20 throw std::runtime_error(message);
21 }
22
23 return true;
24 }();
25
26 namespace mbgl {
27 namespace util {
28
29 // Needed when using a zlib compiled with -DZ_PREFIX
30 // because it will mess with this function name and
31 // cause a link error.
32 #undef compress
33
compress(const std::string & raw)34 std::string compress(const std::string &raw) {
35 z_stream deflate_stream;
36 memset(&deflate_stream, 0, sizeof(deflate_stream));
37
38 // TODO: reuse z_streams
39 if (deflateInit(&deflate_stream, Z_DEFAULT_COMPRESSION) != Z_OK) {
40 throw std::runtime_error("failed to initialize deflate");
41 }
42
43 deflate_stream.next_in = (Bytef *)raw.data();
44 deflate_stream.avail_in = uInt(raw.size());
45
46 std::string result;
47 char out[16384];
48
49 int code;
50 do {
51 deflate_stream.next_out = reinterpret_cast<Bytef *>(out);
52 deflate_stream.avail_out = sizeof(out);
53 code = deflate(&deflate_stream, Z_FINISH);
54 if (result.size() < deflate_stream.total_out) {
55 // append the block to the output string
56 result.append(out, deflate_stream.total_out - result.size());
57 }
58 } while (code == Z_OK);
59
60 deflateEnd(&deflate_stream);
61
62 if (code != Z_STREAM_END) {
63 throw std::runtime_error(deflate_stream.msg);
64 }
65
66 return result;
67 }
68
decompress(const std::string & raw)69 std::string decompress(const std::string &raw) {
70 z_stream inflate_stream;
71 memset(&inflate_stream, 0, sizeof(inflate_stream));
72
73 // TODO: reuse z_streams
74 if (inflateInit(&inflate_stream) != Z_OK) {
75 throw std::runtime_error("failed to initialize inflate");
76 }
77
78 inflate_stream.next_in = (Bytef *)raw.data();
79 inflate_stream.avail_in = uInt(raw.size());
80
81 std::string result;
82 char out[15384];
83
84 int code;
85 do {
86 inflate_stream.next_out = reinterpret_cast<Bytef *>(out);
87 inflate_stream.avail_out = sizeof(out);
88 code = inflate(&inflate_stream, 0);
89 // result.append(out, sizeof(out) - inflate_stream.avail_out);
90 if (result.size() < inflate_stream.total_out) {
91 result.append(out, inflate_stream.total_out - result.size());
92 }
93 } while (code == Z_OK);
94
95 inflateEnd(&inflate_stream);
96
97 if (code != Z_STREAM_END) {
98 throw std::runtime_error(inflate_stream.msg ? inflate_stream.msg : "decompression error");
99 }
100
101 return result;
102 }
103 } // namespace util
104 } // namespace mbgl
105