Compression (#147)

* enable header detection in util::decompress and also use it for gziped data

* expose zlib windowBits so mbgl::util::compress can be used for different formats

* also expose windowBits in decompress function for consistency
This commit is contained in:
Nathan Gass
2021-10-14 01:22:49 +02:00
committed by GitHub
parent bf16c74a12
commit cae0fc272e
3 changed files with 10 additions and 48 deletions

View File

@@ -5,8 +5,10 @@
namespace mbgl {
namespace util {
std::string compress(const std::string& raw);
std::string decompress(const std::string& raw);
enum CompressionFormat { ZLIB = 15, GZIP = 15 + 16, DEFLATE = -15, DETECT = 15 + 32 };
std::string compress(const std::string& raw, int windowBits = CompressionFormat::ZLIB);
std::string decompress(const std::string& raw, int windowBits = CompressionFormat::DETECT);
} // namespace util
} // namespace mbgl

View File

@@ -13,6 +13,7 @@
#include <mbgl/util/thread.hpp>
#include <mbgl/util/url.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/compression.hpp>
#include <mbgl/storage/sqlite3.hpp>
@@ -75,47 +76,6 @@ public:
return (((uint8_t) v[0]) == 0x1f) && (((uint8_t) v[1]) == 0x8b);
}
// Some Mbtiles store GZIP-ed tile data, this function is used for decompression
std::string decompress_string(const std::string &data) {
constexpr uint32_t OUT_SIZE = 8192;
int ret;
char outbuffer[OUT_SIZE];
std::string outstring;
z_stream zs{};
// Init inflate to gzip mode
if (inflateInit2(&zs, (16 + MAX_WBITS)) != Z_OK)
return "";
zs.next_in = (Bytef *) data.data();
zs.avail_in = (unsigned int) data.size();
// get the decompressed bytes blockwise using repeated calls to inflate
do {
zs.next_out = reinterpret_cast<Bytef *>(outbuffer);
zs.avail_out = OUT_SIZE;
ret = inflate(&zs, 0);
if (outstring.size() < zs.total_out) {
outstring.append(outbuffer, zs.total_out - outstring.size());
}
} while (ret == Z_OK);
inflateEnd(&zs);
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
return "";
}
return outstring;
}
// Generate a tilejson resource from .mbtiles file
void request_tilejson(const Resource &resource, ActorRef<FileSourceRequest> req) {
auto path = url_to_path(resource.url);
@@ -258,7 +218,7 @@ public:
response.error.release();
if (is_compressed(*response.data)) {
response.data = std::make_shared<std::string>(decompress_string(*response.data));
response.data = std::make_shared<std::string>(util::decompress(*response.data));
}
}
}

View File

@@ -37,12 +37,12 @@ namespace util {
// cause a link error.
#undef compress
std::string compress(const std::string &raw) {
std::string compress(const std::string &raw, int windowBits) {
z_stream deflate_stream;
memset(&deflate_stream, 0, sizeof(deflate_stream));
// TODO: reuse z_streams
if (deflateInit(&deflate_stream, Z_DEFAULT_COMPRESSION) != Z_OK) {
if (deflateInit2(&deflate_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
throw std::runtime_error("failed to initialize deflate");
}
@@ -72,12 +72,12 @@ std::string compress(const std::string &raw) {
return result;
}
std::string decompress(const std::string &raw) {
std::string decompress(const std::string &raw, int windowBits) {
z_stream inflate_stream;
memset(&inflate_stream, 0, sizeof(inflate_stream));
// TODO: reuse z_streams
if (inflateInit(&inflate_stream) != Z_OK) {
if (inflateInit2(&inflate_stream, windowBits) != Z_OK) {
throw std::runtime_error("failed to initialize inflate");
}