summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2018-02-20 15:06:26 +0100
committerKonstantin Käfer <mail@kkaefer.com>2018-02-21 14:50:13 +0100
commit021e1ae596440cfdee5ffe75907b76069ae44307 (patch)
treeebf15ff8a72e5f14291ba37b6f297ca9a738eea4 /src
parent06213d9145d3b20b63e235cc25678fd76dc296d0 (diff)
downloadqtlocation-mapboxgl-upstream/blob.tar.gz
[core] introduce Blob for compressed and uncompressed dataupstream/blob
- Blob is a wrapper type for a shared_ptr<const string> that has accessor functions for getting compressed and uncompressed data - Moved util::writeFile, util::readFile, util::compress, util::uncompress, decodeImage, and encodePNG to the Blob interface - Added Blob support to Request and file sources - Added Blob support to VectorTile objects - Added support for gzip decoding to util::uncompress - We're no longer compressing WebP, PNG, and JPEG data when storing in the OfflineDatabase - Android's HTTPRequest returns compressed Blobs by default One caveat is that our previous decompress function didn't support gzip, so once users upgrade to this version, their offline cache may contain both zlib-compressed data and gzip-compressed data, but older versions won't be able to decompress gzip data. On the other hand, we don't support downgrading SDKs anyway, so this shouldn't be a problem. To be on the safe side, we could bump the user_version of the SQLite DB.
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/gl/program.hpp4
-rw-r--r--src/mbgl/programs/binary_program.cpp9
-rw-r--r--src/mbgl/programs/binary_program.hpp5
-rw-r--r--src/mbgl/sprite/sprite_loader.cpp8
-rw-r--r--src/mbgl/sprite/sprite_loader_worker.cpp5
-rw-r--r--src/mbgl/sprite/sprite_loader_worker.hpp3
-rw-r--r--src/mbgl/sprite/sprite_parser.cpp7
-rw-r--r--src/mbgl/sprite/sprite_parser.hpp2
-rw-r--r--src/mbgl/storage/resource.cpp18
-rw-r--r--src/mbgl/style/sources/geojson_source.cpp3
-rw-r--r--src/mbgl/style/sources/image_source.cpp2
-rw-r--r--src/mbgl/style/sources/raster_source.cpp2
-rw-r--r--src/mbgl/style/sources/vector_source.cpp3
-rw-r--r--src/mbgl/style/style.cpp4
-rw-r--r--src/mbgl/style/style_impl.cpp12
-rw-r--r--src/mbgl/style/style_impl.hpp8
-rw-r--r--src/mbgl/text/glyph_manager.cpp2
-rw-r--r--src/mbgl/text/glyph_pbf.cpp5
-rw-r--r--src/mbgl/text/glyph_pbf.hpp2
-rw-r--r--src/mbgl/tile/raster_dem_tile.cpp2
-rw-r--r--src/mbgl/tile/raster_dem_tile.hpp2
-rw-r--r--src/mbgl/tile/raster_dem_tile_worker.cpp4
-rw-r--r--src/mbgl/tile/raster_dem_tile_worker.hpp3
-rw-r--r--src/mbgl/tile/raster_tile.cpp2
-rw-r--r--src/mbgl/tile/raster_tile.hpp2
-rw-r--r--src/mbgl/tile/raster_tile_worker.cpp4
-rw-r--r--src/mbgl/tile/raster_tile_worker.hpp3
-rw-r--r--src/mbgl/tile/tile_loader_impl.hpp2
-rw-r--r--src/mbgl/tile/vector_tile.cpp4
-rw-r--r--src/mbgl/tile/vector_tile.hpp2
-rw-r--r--src/mbgl/tile/vector_tile_data.cpp15
-rw-r--r--src/mbgl/tile/vector_tile_data.hpp9
-rw-r--r--src/mbgl/util/blob.cpp46
-rw-r--r--src/mbgl/util/compression.cpp37
-rw-r--r--src/mbgl/util/io.cpp34
-rw-r--r--src/mbgl/util/io.hpp7
36 files changed, 188 insertions, 94 deletions
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
index 3b54ec194a..64e3a355d6 100644
--- a/src/mbgl/gl/program.hpp
+++ b/src/mbgl/gl/program.hpp
@@ -62,7 +62,7 @@ public:
try {
if (auto cachedBinaryProgram = util::readFile(*cachePath)) {
- const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram));
+ const BinaryProgram binaryProgram(cachedBinaryProgram);
if (binaryProgram.identifier() == identifier) {
return Program { context, binaryProgram };
} else {
@@ -82,7 +82,7 @@ public:
try {
if (const auto binaryProgram =
result.template get<BinaryProgram>(context, identifier)) {
- util::write_file(*cachePath, binaryProgram->serialize());
+ util::writeFile(*cachePath, binaryProgram->serialize());
Log::Warning(Event::OpenGL, "Caching program in: %s", (*cachePath).c_str());
}
} catch (std::runtime_error& error) {
diff --git a/src/mbgl/programs/binary_program.cpp b/src/mbgl/programs/binary_program.cpp
index da629194b4..e5943bb5db 100644
--- a/src/mbgl/programs/binary_program.cpp
+++ b/src/mbgl/programs/binary_program.cpp
@@ -32,9 +32,10 @@ static std::pair<const std::string, Binding> parseBinding(protozero::pbf_reader&
namespace mbgl {
-BinaryProgram::BinaryProgram(std::string&& data) {
+BinaryProgram::BinaryProgram(Blob blob) {
+ const auto data = blob.uncompressedData();
bool hasFormat = false, hasCode = false;
- protozero::pbf_reader pbf(data);
+ protozero::pbf_reader pbf(*data);
while (pbf.next()) {
switch (pbf.tag()) {
case 1: // format
@@ -76,7 +77,7 @@ BinaryProgram::BinaryProgram(
uniforms(std::move(uniforms_)) {
}
-std::string BinaryProgram::serialize() const {
+Blob BinaryProgram::serialize() const {
std::string data;
data.reserve(32 + binaryCode.size() + uniforms.size() * 32 + attributes.size() * 32);
protozero::pbf_writer pbf(data);
@@ -95,7 +96,7 @@ std::string BinaryProgram::serialize() const {
if (!binaryIdentifier.empty()) {
pbf.add_string(5 /* identifier */, binaryIdentifier);
}
- return data;
+ return { std::move(data), false };
}
optional<gl::AttributeLocation> BinaryProgram::attributeLocation(const std::string& name) const {
diff --git a/src/mbgl/programs/binary_program.hpp b/src/mbgl/programs/binary_program.hpp
index 8690f3fd6f..2d3ea45aa6 100644
--- a/src/mbgl/programs/binary_program.hpp
+++ b/src/mbgl/programs/binary_program.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/gl/types.hpp>
+#include <mbgl/util/blob.hpp>
#include <mbgl/util/optional.hpp>
#include <string>
@@ -11,7 +12,7 @@ namespace mbgl {
class BinaryProgram {
public:
// Initialize a BinaryProgram object from a serialized represenation.
- BinaryProgram(std::string&& data);
+ BinaryProgram(Blob data);
BinaryProgram(gl::BinaryProgramFormat,
std::string&& binaryCode,
@@ -19,7 +20,7 @@ public:
std::vector<std::pair<const std::string, gl::AttributeLocation>>&&,
std::vector<std::pair<const std::string, gl::UniformLocation>>&&);
- std::string serialize() const;
+ Blob serialize() const;
gl::BinaryProgramFormat format() const {
return binaryFormat;
diff --git a/src/mbgl/sprite/sprite_loader.cpp b/src/mbgl/sprite/sprite_loader.cpp
index 93d6dfd9ae..3bc8add160 100644
--- a/src/mbgl/sprite/sprite_loader.cpp
+++ b/src/mbgl/sprite/sprite_loader.cpp
@@ -25,8 +25,8 @@ struct SpriteLoader::Loader {
worker(scheduler, ActorRef<SpriteLoader>(imageManager, mailbox)) {
}
- std::shared_ptr<const std::string> image;
- std::shared_ptr<const std::string> json;
+ Blob image;
+ Blob json;
std::unique_ptr<AsyncRequest> jsonRequest;
std::unique_ptr<AsyncRequest> spriteRequest;
std::shared_ptr<Mailbox> mailbox;
@@ -55,7 +55,7 @@ void SpriteLoader::load(const std::string& url, Scheduler& scheduler, FileSource
} else if (res.notModified) {
return;
} else if (res.noContent) {
- loader->json = std::make_shared<const std::string>();
+ loader->json = {};
emitSpriteLoadedIfComplete();
} else {
// Only trigger a sprite loaded event we got new data.
@@ -70,7 +70,7 @@ void SpriteLoader::load(const std::string& url, Scheduler& scheduler, FileSource
} else if (res.notModified) {
return;
} else if (res.noContent) {
- loader->image = std::make_shared<const std::string>();
+ loader->image = {};
emitSpriteLoadedIfComplete();
} else {
loader->image = res.data;
diff --git a/src/mbgl/sprite/sprite_loader_worker.cpp b/src/mbgl/sprite/sprite_loader_worker.cpp
index 4bded33d53..a2e3f331e9 100644
--- a/src/mbgl/sprite/sprite_loader_worker.cpp
+++ b/src/mbgl/sprite/sprite_loader_worker.cpp
@@ -8,8 +8,7 @@ SpriteLoaderWorker::SpriteLoaderWorker(ActorRef<SpriteLoaderWorker>, ActorRef<Sp
: parent(std::move(parent_)) {
}
-void SpriteLoaderWorker::parse(std::shared_ptr<const std::string> image,
- std::shared_ptr<const std::string> json) {
+void SpriteLoaderWorker::parse(Blob image, Blob json) {
try {
if (!image) {
// This shouldn't happen, since we always invoke it with a non-empty pointer.
@@ -20,7 +19,7 @@ void SpriteLoaderWorker::parse(std::shared_ptr<const std::string> image,
throw std::runtime_error("missing sprite metadata");
}
- parent.invoke(&SpriteLoader::onParsed, parseSprite(*image, *json));
+ parent.invoke(&SpriteLoader::onParsed, parseSprite(std::move(image), std::move(json)));
} catch (...) {
parent.invoke(&SpriteLoader::onError, std::current_exception());
}
diff --git a/src/mbgl/sprite/sprite_loader_worker.hpp b/src/mbgl/sprite/sprite_loader_worker.hpp
index d61e07d14f..4f2e38be29 100644
--- a/src/mbgl/sprite/sprite_loader_worker.hpp
+++ b/src/mbgl/sprite/sprite_loader_worker.hpp
@@ -2,6 +2,7 @@
#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/sprite/sprite_parser.hpp>
+#include <mbgl/storage/response.hpp>
#include <memory>
#include <string>
@@ -14,7 +15,7 @@ class SpriteLoaderWorker {
public:
SpriteLoaderWorker(ActorRef<SpriteLoaderWorker>, ActorRef<SpriteLoader>);
- void parse(std::shared_ptr<const std::string> image, std::shared_ptr<const std::string> json);
+ void parse(Blob image, Blob json);
private:
ActorRef<SpriteLoader> parent;
diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp
index 1a36e3e990..c93d97ba78 100644
--- a/src/mbgl/sprite/sprite_parser.cpp
+++ b/src/mbgl/sprite/sprite_parser.cpp
@@ -85,11 +85,12 @@ bool getBoolean(const JSValue& value, const char* name, const bool def = false)
} // namespace
-std::vector<std::unique_ptr<style::Image>> parseSprite(const std::string& encodedImage, const std::string& json) {
- const PremultipliedImage raster = decodeImage(encodedImage);
+std::vector<std::unique_ptr<style::Image>> parseSprite(Blob imageBlob, Blob jsonBlob) {
+ const PremultipliedImage raster = decodeImage(imageBlob);
+ const auto json = jsonBlob.uncompressedData();
JSDocument doc;
- doc.Parse<0>(json.c_str());
+ doc.Parse<0>(json->c_str());
if (doc.HasParseError()) {
std::stringstream message;
message << "Failed to parse JSON: " << rapidjson::GetParseError_En(doc.GetParseError()) << " at offset " << doc.GetErrorOffset();
diff --git a/src/mbgl/sprite/sprite_parser.hpp b/src/mbgl/sprite/sprite_parser.hpp
index f602818d3b..b17f4cc458 100644
--- a/src/mbgl/sprite/sprite_parser.hpp
+++ b/src/mbgl/sprite/sprite_parser.hpp
@@ -23,6 +23,6 @@ std::unique_ptr<style::Image> createStyleImage(const std::string& id,
bool sdf);
// Parses an image and an associated JSON file and returns the sprite objects.
-std::vector<std::unique_ptr<style::Image>> parseSprite(const std::string& image, const std::string& json);
+std::vector<std::unique_ptr<style::Image>> parseSprite(Blob image, Blob json);
} // namespace mbgl
diff --git a/src/mbgl/storage/resource.cpp b/src/mbgl/storage/resource.cpp
index 207dd2ee69..9bc8495d53 100644
--- a/src/mbgl/storage/resource.cpp
+++ b/src/mbgl/storage/resource.cpp
@@ -42,14 +42,20 @@ static std::string getTileBBox(int32_t x, int32_t y, int8_t z) {
Resource Resource::style(const std::string& url) {
return Resource {
Resource::Kind::Style,
- url
+ url,
+ {},
+ LoadingMethod::All,
+ Compression::Uncompressed
};
}
Resource Resource::source(const std::string& url) {
return Resource {
Resource::Kind::Source,
- url
+ url,
+ {},
+ LoadingMethod::All,
+ Compression::Uncompressed
};
}
@@ -87,7 +93,10 @@ Resource Resource::glyphs(const std::string& urlTemplate, const FontStack& fontS
} else {
return std::string();
}
- })
+ }),
+ {},
+ LoadingMethod::All,
+ Compression::Uncompressed
};
}
@@ -133,7 +142,8 @@ Resource Resource::tile(const std::string& urlTemplate,
y,
z
},
- loadingMethod
+ loadingMethod,
+ Compression::PreferCompressed
};
}
diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp
index 4e3478322d..48308ccbc3 100644
--- a/src/mbgl/style/sources/geojson_source.cpp
+++ b/src/mbgl/style/sources/geojson_source.cpp
@@ -61,7 +61,8 @@ void GeoJSONSource::loadDescription(FileSource& fileSource) {
*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON")));
} else {
conversion::Error error;
- optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error);
+ optional<GeoJSON> geoJSON =
+ conversion::convertJSON<GeoJSON>(*res.data.uncompressedData(), error);
if (!geoJSON) {
Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s",
error.message.c_str());
diff --git a/src/mbgl/style/sources/image_source.cpp b/src/mbgl/style/sources/image_source.cpp
index fa268da0ef..5be1b54410 100644
--- a/src/mbgl/style/sources/image_source.cpp
+++ b/src/mbgl/style/sources/image_source.cpp
@@ -70,7 +70,7 @@ void ImageSource::loadDescription(FileSource& fileSource) {
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty image url")));
} else {
try {
- baseImpl = makeMutable<Impl>(impl(), decodeImage(*res.data));
+ baseImpl = makeMutable<Impl>(impl(), decodeImage(res.data));
} catch (...) {
observer->onSourceError(*this, std::current_exception());
}
diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp
index 53f29d660b..c3c47567aa 100644
--- a/src/mbgl/style/sources/raster_source.cpp
+++ b/src/mbgl/style/sources/raster_source.cpp
@@ -57,7 +57,7 @@ void RasterSource::loadDescription(FileSource& fileSource) {
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON")));
} else {
conversion::Error error;
- optional<Tileset> tileset = conversion::convertJSON<Tileset>(*res.data, error);
+ optional<Tileset> tileset = conversion::convertJSON<Tileset>(*res.data.uncompressedData(), error);
if (!tileset) {
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(error.message)));
return;
diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp
index ccdd453c75..d88622f1b8 100644
--- a/src/mbgl/style/sources/vector_source.cpp
+++ b/src/mbgl/style/sources/vector_source.cpp
@@ -54,7 +54,8 @@ void VectorSource::loadDescription(FileSource& fileSource) {
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON")));
} else {
conversion::Error error;
- optional<Tileset> tileset = conversion::convertJSON<Tileset>(*res.data, error);
+ optional<Tileset> tileset =
+ conversion::convertJSON<Tileset>(*res.data.uncompressedData(), error);
if (!tileset) {
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(error.message)));
return;
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index bd8631fc52..82f421ecdf 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -14,7 +14,7 @@ Style::Style(Scheduler& scheduler, FileSource& fileSource, float pixelRatio)
Style::~Style() = default;
-void Style::loadJSON(const std::string& json) {
+void Style::loadJSON(Blob json) {
impl->loadJSON(json);
}
@@ -22,7 +22,7 @@ void Style::loadURL(const std::string& url) {
impl->loadURL(url);
}
-std::string Style::getJSON() const {
+Blob Style::getJSON() const {
return impl->getJSON();
}
diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp
index d330b3120a..a952ccb8c2 100644
--- a/src/mbgl/style/style_impl.cpp
+++ b/src/mbgl/style/style_impl.cpp
@@ -39,7 +39,7 @@ Style::Impl::Impl(Scheduler& scheduler_, FileSource& fileSource_, float pixelRat
Style::Impl::~Impl() = default;
-void Style::Impl::loadJSON(const std::string& json_) {
+void Style::Impl::loadJSON(Blob json_) {
lastError = nullptr;
observer->onStyleLoading();
@@ -73,15 +73,17 @@ void Style::Impl::loadURL(const std::string& url_) {
} else if (res.notModified || res.noContent) {
return;
} else {
- parse(*res.data);
+ parse(res.data);
}
});
}
-void Style::Impl::parse(const std::string& json_) {
+void Style::Impl::parse(Blob json_) {
Parser parser;
- if (auto error = parser.parse(json_)) {
+ const auto data = json_.uncompressedData();
+
+ if (auto error = parser.parse(*data)) {
std::string message = "Failed to parse style: " + util::toString(error);
Log::Error(Event::ParseStyle, message.c_str());
observer->onStyleError(std::make_exception_ptr(util::StyleParseException(message)));
@@ -124,7 +126,7 @@ void Style::Impl::parse(const std::string& json_) {
observer->onStyleLoaded();
}
-std::string Style::Impl::getJSON() const {
+Blob Style::Impl::getJSON() const {
return json;
}
diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp
index 3dc222bfad..9dc2704391 100644
--- a/src/mbgl/style/style_impl.hpp
+++ b/src/mbgl/style/style_impl.hpp
@@ -41,10 +41,10 @@ public:
Impl(Scheduler&, FileSource&, float pixelRatio);
~Impl() override;
- void loadJSON(const std::string&);
+ void loadJSON(Blob);
void loadURL(const std::string&);
- std::string getJSON() const;
+ Blob getJSON() const;
std::string getURL() const;
void setObserver(Observer*);
@@ -96,13 +96,13 @@ public:
bool spriteLoaded = false;
private:
- void parse(const std::string&);
+ void parse(Blob);
Scheduler& scheduler;
FileSource& fileSource;
std::string url;
- std::string json;
+ Blob json;
std::unique_ptr<AsyncRequest> styleRequest;
std::unique_ptr<SpriteLoader> spriteLoader;
diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp
index 3130418908..37574eff15 100644
--- a/src/mbgl/text/glyph_manager.cpp
+++ b/src/mbgl/text/glyph_manager.cpp
@@ -91,7 +91,7 @@ void GlyphManager::processResponse(const Response& res, const FontStack& fontSta
std::vector<Glyph> glyphs;
try {
- glyphs = parseGlyphPBF(range, *res.data);
+ glyphs = parseGlyphPBF(range, res.data);
} catch (...) {
observer->onGlyphsError(fontStack, range, std::current_exception());
return;
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index cfaf803f75..77ea5ec2cb 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -4,11 +4,12 @@
namespace mbgl {
-std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) {
+std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, Blob blob) {
+ const auto data = blob.uncompressedData();
std::vector<Glyph> result;
result.reserve(256);
- protozero::pbf_reader glyphs_pbf(data);
+ protozero::pbf_reader glyphs_pbf(*data);
while (glyphs_pbf.next(1)) {
auto fontstack_pbf = glyphs_pbf.get_message();
diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp
index 28a28b4114..0c82343ce5 100644
--- a/src/mbgl/text/glyph_pbf.hpp
+++ b/src/mbgl/text/glyph_pbf.hpp
@@ -8,6 +8,6 @@
namespace mbgl {
-std::vector<Glyph> parseGlyphPBF(const GlyphRange&, const std::string& data);
+std::vector<Glyph> parseGlyphPBF(const GlyphRange&, Blob blob);
} // namespace mbgl
diff --git a/src/mbgl/tile/raster_dem_tile.cpp b/src/mbgl/tile/raster_dem_tile.cpp
index 5db298cf4c..10f22e378b 100644
--- a/src/mbgl/tile/raster_dem_tile.cpp
+++ b/src/mbgl/tile/raster_dem_tile.cpp
@@ -45,7 +45,7 @@ void RasterDEMTile::setMetadata(optional<Timestamp> modified_, optional<Timestam
expires = expires_;
}
-void RasterDEMTile::setData(std::shared_ptr<const std::string> data) {
+void RasterDEMTile::setData(Blob data) {
pending = true;
++correlationID;
worker.invoke(&RasterDEMTileWorker::parse, data, correlationID, encoding);
diff --git a/src/mbgl/tile/raster_dem_tile.hpp b/src/mbgl/tile/raster_dem_tile.hpp
index 0c8dd75961..0c5b3e7bf2 100644
--- a/src/mbgl/tile/raster_dem_tile.hpp
+++ b/src/mbgl/tile/raster_dem_tile.hpp
@@ -70,7 +70,7 @@ public:
void setError(std::exception_ptr);
void setMetadata(optional<Timestamp> modified, optional<Timestamp> expires);
- void setData(std::shared_ptr<const std::string> data);
+ void setData(Blob data);
void upload(gl::Context&) override;
Bucket* getBucket(const style::Layer::Impl&) const override;
diff --git a/src/mbgl/tile/raster_dem_tile_worker.cpp b/src/mbgl/tile/raster_dem_tile_worker.cpp
index 7338e578c7..ec5aba380a 100644
--- a/src/mbgl/tile/raster_dem_tile_worker.cpp
+++ b/src/mbgl/tile/raster_dem_tile_worker.cpp
@@ -10,14 +10,14 @@ RasterDEMTileWorker::RasterDEMTileWorker(ActorRef<RasterDEMTileWorker>, ActorRef
: parent(std::move(parent_)) {
}
-void RasterDEMTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID, Tileset::DEMEncoding encoding) {
+void RasterDEMTileWorker::parse(Blob data, uint64_t correlationID, Tileset::DEMEncoding encoding) {
if (!data) {
parent.invoke(&RasterDEMTile::onParsed, nullptr, correlationID); // No data; empty tile.
return;
}
try {
- auto bucket = std::make_unique<HillshadeBucket>(decodeImage(*data), encoding);
+ auto bucket = std::make_unique<HillshadeBucket>(decodeImage(data), encoding);
parent.invoke(&RasterDEMTile::onParsed, std::move(bucket), correlationID);
} catch (...) {
parent.invoke(&RasterDEMTile::onError, std::current_exception(), correlationID);
diff --git a/src/mbgl/tile/raster_dem_tile_worker.hpp b/src/mbgl/tile/raster_dem_tile_worker.hpp
index 5a8222bc2d..5b9bce1a19 100644
--- a/src/mbgl/tile/raster_dem_tile_worker.hpp
+++ b/src/mbgl/tile/raster_dem_tile_worker.hpp
@@ -2,6 +2,7 @@
#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/util/tileset.hpp>
+#include <mbgl/util/blob.hpp>
#include <memory>
#include <string>
@@ -14,7 +15,7 @@ class RasterDEMTileWorker {
public:
RasterDEMTileWorker(ActorRef<RasterDEMTileWorker>, ActorRef<RasterDEMTile>);
- void parse(std::shared_ptr<const std::string> data, uint64_t correlationID, Tileset::DEMEncoding encoding);
+ void parse(Blob data, uint64_t correlationID, Tileset::DEMEncoding encoding);
private:
ActorRef<RasterDEMTile> parent;
diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp
index ff23d4493e..4bc9830fda 100644
--- a/src/mbgl/tile/raster_tile.cpp
+++ b/src/mbgl/tile/raster_tile.cpp
@@ -34,7 +34,7 @@ void RasterTile::setMetadata(optional<Timestamp> modified_, optional<Timestamp>
expires = expires_;
}
-void RasterTile::setData(std::shared_ptr<const std::string> data) {
+void RasterTile::setData(Blob data) {
pending = true;
++correlationID;
worker.invoke(&RasterTileWorker::parse, data, correlationID);
diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp
index e25329119a..c1fa6caa99 100644
--- a/src/mbgl/tile/raster_tile.hpp
+++ b/src/mbgl/tile/raster_tile.hpp
@@ -26,7 +26,7 @@ public:
void setError(std::exception_ptr);
void setMetadata(optional<Timestamp> modified, optional<Timestamp> expires);
- void setData(std::shared_ptr<const std::string> data);
+ void setData(Blob data);
void upload(gl::Context&) override;
Bucket* getBucket(const style::Layer::Impl&) const override;
diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp
index 4afa876429..d0dd8918a2 100644
--- a/src/mbgl/tile/raster_tile_worker.cpp
+++ b/src/mbgl/tile/raster_tile_worker.cpp
@@ -10,14 +10,14 @@ RasterTileWorker::RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTi
: parent(std::move(parent_)) {
}
-void RasterTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID) {
+void RasterTileWorker::parse(Blob data, uint64_t correlationID) {
if (!data) {
parent.invoke(&RasterTile::onParsed, nullptr, correlationID); // No data; empty tile.
return;
}
try {
- auto bucket = std::make_unique<RasterBucket>(decodeImage(*data));
+ auto bucket = std::make_unique<RasterBucket>(decodeImage(data));
parent.invoke(&RasterTile::onParsed, std::move(bucket), correlationID);
} catch (...) {
parent.invoke(&RasterTile::onError, std::current_exception(), correlationID);
diff --git a/src/mbgl/tile/raster_tile_worker.hpp b/src/mbgl/tile/raster_tile_worker.hpp
index 520973c3c3..c56da82d0a 100644
--- a/src/mbgl/tile/raster_tile_worker.hpp
+++ b/src/mbgl/tile/raster_tile_worker.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/actor/actor_ref.hpp>
+#include <mbgl/util/blob.hpp>
#include <memory>
#include <string>
@@ -13,7 +14,7 @@ class RasterTileWorker {
public:
RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTile>);
- void parse(std::shared_ptr<const std::string> data, uint64_t correlationID);
+ void parse(Blob data, uint64_t correlationID);
private:
ActorRef<RasterTile> parent;
diff --git a/src/mbgl/tile/tile_loader_impl.hpp b/src/mbgl/tile/tile_loader_impl.hpp
index 1b29638269..48b3b7c87b 100644
--- a/src/mbgl/tile/tile_loader_impl.hpp
+++ b/src/mbgl/tile/tile_loader_impl.hpp
@@ -106,7 +106,7 @@ void TileLoader<T>::loadedData(const Response& res) {
resource.priorExpires = res.expires;
resource.priorEtag = res.etag;
tile.setMetadata(res.modified, res.expires);
- tile.setData(res.noContent ? nullptr : res.data);
+ tile.setData(res.noContent ? Blob{} : res.data);
}
}
diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index 0756d3e526..a815f31e41 100644
--- a/src/mbgl/tile/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -21,8 +21,8 @@ void VectorTile::setMetadata(optional<Timestamp> modified_, optional<Timestamp>
expires = expires_;
}
-void VectorTile::setData(std::shared_ptr<const std::string> data_) {
- GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr);
+void VectorTile::setData(Blob data_) {
+ GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(std::move(data_)) : nullptr);
}
} // namespace mbgl
diff --git a/src/mbgl/tile/vector_tile.hpp b/src/mbgl/tile/vector_tile.hpp
index 7dae414fef..87abf2f598 100644
--- a/src/mbgl/tile/vector_tile.hpp
+++ b/src/mbgl/tile/vector_tile.hpp
@@ -17,7 +17,7 @@ public:
void setNecessity(TileNecessity) final;
void setMetadata(optional<Timestamp> modified, optional<Timestamp> expires);
- void setData(std::shared_ptr<const std::string> data);
+ void setData(Blob data);
private:
TileLoader<VectorTile> loader;
diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp
index 2d4a01bda3..eaa91dc9cf 100644
--- a/src/mbgl/tile/vector_tile_data.cpp
+++ b/src/mbgl/tile/vector_tile_data.cpp
@@ -60,19 +60,24 @@ std::string VectorTileLayer::getName() const {
return layer.getName();
}
-VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_) : data(std::move(data_)) {
+VectorTileData::VectorTileData(Blob blob_) : blob(std::move(blob_)) {
}
std::unique_ptr<GeometryTileData> VectorTileData::clone() const {
- return std::make_unique<VectorTileData>(data);
+ // Always pass on data that is uncompressed, if we have it.
+ return std::make_unique<VectorTileData>(data ? Blob{ data, false } : blob);
}
std::unique_ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const {
- if (!parsed) {
+ if (!blob) {
+ return nullptr;
+ }
+
+ if (!data) {
// We're parsing this lazily so that we can construct VectorTileData objects on the main
- // thread without incurring the overhead of parsing immediately.
+ // thread without incurring the overhead of parsing and decompressing immediately.
+ data = blob.uncompressedData();
layers = mapbox::vector_tile::buffer(*data).getLayers();
- parsed = true;
}
auto it = layers.find(name);
diff --git a/src/mbgl/tile/vector_tile_data.hpp b/src/mbgl/tile/vector_tile_data.hpp
index 48beaf9d07..ce120e97c0 100644
--- a/src/mbgl/tile/vector_tile_data.hpp
+++ b/src/mbgl/tile/vector_tile_data.hpp
@@ -1,5 +1,7 @@
#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/util/blob.hpp>
+
#include <mapbox/vector_tile.hpp>
#include <protozero/pbf_reader.hpp>
@@ -38,7 +40,8 @@ private:
class VectorTileData : public GeometryTileData {
public:
- VectorTileData(std::shared_ptr<const std::string> data);
+ VectorTileData(const VectorTileData&);
+ VectorTileData(Blob blob);
std::unique_ptr<GeometryTileData> clone() const override;
std::unique_ptr<GeometryTileLayer> getLayer(const std::string& name) const override;
@@ -46,8 +49,8 @@ public:
std::vector<std::string> layerNames() const;
private:
- std::shared_ptr<const std::string> data;
- mutable bool parsed = false;
+ Blob blob;
+ mutable std::shared_ptr<const std::string> data;
mutable std::map<std::string, const protozero::data_view> layers;
};
diff --git a/src/mbgl/util/blob.cpp b/src/mbgl/util/blob.cpp
new file mode 100644
index 0000000000..53d7644002
--- /dev/null
+++ b/src/mbgl/util/blob.cpp
@@ -0,0 +1,46 @@
+#include <mbgl/util/blob.hpp>
+#include <mbgl/util/compression.hpp>
+
+namespace mbgl {
+
+Blob::Blob() = default;
+
+Blob::Blob(std::shared_ptr<const std::string> bytes_, bool compressed_)
+ : bytes(std::move(bytes_)), compressed(compressed_) {
+}
+
+Blob::Blob(std::string&& bytes_, bool compressed_)
+ : bytes(std::make_shared<const std::string>(std::move(bytes_))), compressed(compressed_) {
+}
+
+std::shared_ptr<const std::string> Blob::uncompressedData() const {
+ if (!bytes) {
+ throw std::runtime_error("invalid blob");
+ }
+ if (compressed) {
+ return std::make_shared<const std::string>(util::decompress(*bytes));
+ } else {
+ return bytes;
+ }
+}
+
+std::shared_ptr<const std::string> Blob::compressedData() const {
+ if (!bytes) {
+ throw std::runtime_error("invalid blob");
+ }
+ if (compressed) {
+ return bytes;
+ } else {
+ return std::make_shared<const std::string>(util::compress(*bytes));
+ }
+}
+
+void Blob::uncompress() {
+ if (compressed) {
+ bytes = uncompressedData();
+ compressed = false;
+ }
+}
+
+
+} // namespace mbgl
diff --git a/src/mbgl/util/compression.cpp b/src/mbgl/util/compression.cpp
index 30e813cbb8..4d4e094f06 100644
--- a/src/mbgl/util/compression.cpp
+++ b/src/mbgl/util/compression.cpp
@@ -71,7 +71,8 @@ std::string decompress(const std::string &raw) {
memset(&inflate_stream, 0, sizeof(inflate_stream));
// TODO: reuse z_streams
- if (inflateInit(&inflate_stream) != Z_OK) {
+ // MAX_WBITS + allows decoding gzip in addition to zlib
+ if (inflateInit2(&inflate_stream, MAX_WBITS + 32) != Z_OK) {
throw std::runtime_error("failed to initialize inflate");
}
@@ -100,5 +101,39 @@ std::string decompress(const std::string &raw) {
return result;
}
+
+bool isCompressible(const std::string& raw) {
+ // WebP
+ if (raw.size() >= 12 && static_cast<uint8_t>(raw[0]) == 'R' &&
+ static_cast<uint8_t>(raw[1]) == 'I' && static_cast<uint8_t>(raw[2]) == 'F' &&
+ static_cast<uint8_t>(raw[3]) == 'F' && static_cast<uint8_t>(raw[8]) == 'W' &&
+ static_cast<uint8_t>(raw[9]) == 'E' && static_cast<uint8_t>(raw[10]) == 'B' &&
+ static_cast<uint8_t>(raw[11]) == 'P') {
+ // Note: the WebP container format allows uncompressed data as well, but we just assume that
+ // all WebP files are already compressed.
+ return false;
+ }
+
+ // PNG
+ if (raw.size() >= 8 && static_cast<uint8_t>(raw[0]) == 0x89 &&
+ static_cast<uint8_t>(raw[1]) == 'P' && static_cast<uint8_t>(raw[2]) == 'N' &&
+ static_cast<uint8_t>(raw[3]) == 'G' && static_cast<uint8_t>(raw[4]) == '\r' &&
+ static_cast<uint8_t>(raw[5]) == '\n' && static_cast<uint8_t>(raw[6]) == 0x1a &&
+ static_cast<uint8_t>(raw[7]) == '\n') {
+ // Note: this assumes the PNG file itself is compressed. However, it is possible to create
+ // PNG files with uncompressed data in it (zlib compression 0), but they are exceedingly
+ // rare, so we don't care about them.
+ return false;
+ }
+
+ // JPEG
+ if (raw.size() >= 3 && static_cast<uint8_t>(raw[0]) == 0xff &&
+ static_cast<uint8_t>(raw[1]) == 0xd8 && static_cast<uint8_t>(raw[2]) == 0xff) {
+ return false;
+ }
+
+ return true;
+}
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/io.cpp b/src/mbgl/util/io.cpp
index 6a6ed7b250..2dc6cabf0f 100644
--- a/src/mbgl/util/io.cpp
+++ b/src/mbgl/util/io.cpp
@@ -1,43 +1,29 @@
#include <mbgl/util/io.hpp>
-#include <cstdio>
#include <cerrno>
#include <iostream>
-#include <sstream>
#include <fstream>
namespace mbgl {
namespace util {
-void write_file(const std::string &filename, const std::string &data) {
- FILE *fd = fopen(filename.c_str(), "wb");
- if (fd) {
- fwrite(data.data(), sizeof(std::string::value_type), data.size(), fd);
- fclose(fd);
- } else {
- throw std::runtime_error(std::string("Failed to open file ") + filename);
- }
-}
-
-std::string read_file(const std::string &filename) {
- std::ifstream file(filename);
+void writeFile(const std::string &filename, Blob blob) {
+ std::ofstream file(filename, std::ios::binary);
if (file.good()) {
- std::stringstream data;
- data << file.rdbuf();
- return data.str();
+ file << *blob.uncompressedData();
} else {
- throw std::runtime_error(std::string("Cannot read file ") + filename);
+ throw IOException(errno, "failed to write file");
}
}
-optional<std::string> readFile(const std::string &filename) {
- std::ifstream file(filename);
+Blob readFile(const std::string &filename) {
+ std::ifstream file(filename, std::ios::binary);
if (file.good()) {
- std::stringstream data;
- data << file.rdbuf();
- return data.str();
+ return { { std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() },
+ false };
+ } else {
+ return {};
}
- return {};
}
void deleteFile(const std::string& filename) {
diff --git a/src/mbgl/util/io.hpp b/src/mbgl/util/io.hpp
index 847271acf0..b74f89485b 100644
--- a/src/mbgl/util/io.hpp
+++ b/src/mbgl/util/io.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/blob.hpp>
#include <string>
#include <stdexcept>
@@ -14,10 +15,8 @@ struct IOException : std::runtime_error {
const int code = 0;
};
-void write_file(const std::string &filename, const std::string &data);
-std::string read_file(const std::string &filename);
-
-optional<std::string> readFile(const std::string &filename);
+void writeFile(const std::string &filename, Blob blob);
+Blob readFile(const std::string &filename);
void deleteFile(const std::string& filename);
} // namespace util