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