diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-01-11 12:52:41 -0800 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-01-13 13:40:31 -0800 |
commit | 86c8446d3a4390ff6577d070ac8b5fa3ad3c5cd1 (patch) | |
tree | ef10190d3fca34ff72b2473816901088b0b85ac2 /platform/android/src | |
parent | 2126e34e52dc5dd94c5a3907b240e62ee17d1e70 (diff) | |
download | qtlocation-mapboxgl-86c8446d3a4390ff6577d070ac8b5fa3ad3c5cd1.tar.gz |
[core] Simplify asset:// implementation
* Move asset:// URL handling to DefaultFileSource.
* AssetFileSource implements FileSource interface and follows familiar implementation patterns.
* Move default implementation to platform/default, zip implementation to platform/android.
* Don't bother with modified / expires / etag -- assets are not cached so it doesn't matter.
* Don't bother with interleaving individual IO calls on the implementation thread. That adds a lot of complexity for very little benefit.
Diffstat (limited to 'platform/android/src')
-rw-r--r-- | platform/android/src/asset_file_source.cpp | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/platform/android/src/asset_file_source.cpp b/platform/android/src/asset_file_source.cpp new file mode 100644 index 0000000000..1f02f9cf4a --- /dev/null +++ b/platform/android/src/asset_file_source.cpp @@ -0,0 +1,111 @@ +#include <mbgl/storage/asset_file_source.hpp> +#include <mbgl/storage/response.hpp> +#include <mbgl/util/util.hpp> +#include <mbgl/util/thread.hpp> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#include <zip.h> +#pragma GCC diagnostic pop + +namespace { + +struct ZipHolder { + ZipHolder(struct zip* archive_) : archive(archive_) {} + + ~ZipHolder() { + if (archive) ::zip_close(archive); + } + + struct zip* archive; +}; + +struct ZipFileHolder { + ZipFileHolder(struct zip_file* file_) : file(file_) {} + + ~ZipFileHolder() { + if (file) ::zip_fclose(file); + } + + struct zip_file* file; +}; + +} + +namespace mbgl { + +class AssetFileRequest : public FileRequest { +public: + AssetFileRequest(std::unique_ptr<WorkRequest> workRequest_) + : workRequest(std::move(workRequest_)) { + } + + std::unique_ptr<WorkRequest> workRequest; +}; + +class AssetFileSource::Impl { +public: + Impl(const std::string& root_) + : root(root_) { + } + + void request(const std::string& url, FileSource::Callback callback) { + ZipHolder archive = ::zip_open(root.c_str(), 0, nullptr); + if (!archive.archive) { + reportError(Response::Error::Reason::Other, "Could not open zip archive", callback); + return; + } + + struct zip_stat stat; + ::zip_stat_init(&stat); + + std::string path = std::string("assets/") + url.substr(8); + int ret = ::zip_stat(archive.archive, path.c_str(), 0, &stat); + if (ret < 0 || !(stat.valid & ZIP_STAT_SIZE)) { + reportError(Response::Error::Reason::NotFound, "Could not stat file in zip archive", callback); + return; + } + + ZipFileHolder file = ::zip_fopen(archive.archive, path.c_str(), 0); + if (!file.file) { + reportError(Response::Error::Reason::NotFound, "Could not open file in zip archive", callback); + return; + } + + std::shared_ptr<std::string> buf = std::make_shared<std::string>(); + buf->resize(stat.size); + + ret = ::zip_fread(file.file, &buf->front(), stat.size); + if (ret < 0) { + reportError(Response::Error::Reason::Other, "Could not read file in zip archive", callback); + return; + } + + Response response; + response.data = buf; + callback(response); + } + + void reportError(Response::Error::Reason reason, const char * message, FileSource::Callback callback) { + Response response; + response.error = std::make_unique<Response::Error>(reason, message); + callback(response); + } + +private: + std::string root; +}; + +AssetFileSource::AssetFileSource(const std::string& root) + : thread(std::make_unique<util::Thread<Impl>>( + util::ThreadContext{"AssetFileSource", util::ThreadType::Worker, util::ThreadPriority::Regular}, + root.empty() ? platform::assetRoot() : root)) { +} + +AssetFileSource::~AssetFileSource() = default; + +std::unique_ptr<FileRequest> AssetFileSource::request(const Resource& resource, Callback callback) { + return std::make_unique<AssetFileRequest>(thread->invokeWithCallback(&Impl::request, callback, resource.url)); +} + +} |