diff options
author | Leith Bade <leith@mapbox.com> | 2014-11-17 23:17:22 +1100 |
---|---|---|
committer | Leith Bade <leith@mapbox.com> | 2014-11-17 23:17:22 +1100 |
commit | f0e4e27cd383f9c8b674cbfebb7a15ba8f8b6c0b (patch) | |
tree | 0f08f9a41c30023cb4590080c147ca141950eba5 /platform/android | |
parent | aee724d6cfed9a8703183c998d7fb7d077abe8b1 (diff) | |
download | qtlocation-mapboxgl-f0e4e27cd383f9c8b674cbfebb7a15ba8f8b6c0b.tar.gz |
Read styles from APK
Diffstat (limited to 'platform/android')
-rw-r--r-- | platform/android/asset_request_baton.cpp | 204 |
1 files changed, 101 insertions, 103 deletions
diff --git a/platform/android/asset_request_baton.cpp b/platform/android/asset_request_baton.cpp index 8563312b4d..c4e0a1799e 100644 --- a/platform/android/asset_request_baton.cpp +++ b/platform/android/asset_request_baton.cpp @@ -1,158 +1,156 @@ +#include <mbgl/android/jni.hpp> #include <mbgl/platform/android/asset_request_baton.hpp> #include <mbgl/platform/android/asset_request.hpp> #include <mbgl/storage/response.hpp> #include <limits> +#include <boost/make_unique.hpp> namespace mbgl { -AssetRequestBaton::AssetRequestBaton(AssetRequest *request_, const std::string &path, uv_loop_t *loop) - : thread_id(uv_thread_self()), request(request_) { - req.data = this; - uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, file_opened); +AssetRequestBaton::AssetRequestBaton(AssetRequest *request_, const std::string &path_, uv_loop_t *loop) + : thread_id(uv_thread_self()), + request(request_), + async_run(new uv_async_t()), + path(path_) { + + uv_async_init(loop, async_run.get(), run); + async_run->data = this; + + uv_async_send(async_run.get()); } AssetRequestBaton::~AssetRequestBaton() { + uv_close((uv_handle_t *)async_run.get(), nullptr); } void AssetRequestBaton::cancel() { canceled = true; - - // uv_cancel fails frequently when the request has already been started. - // In that case, we have to let it complete and check the canceled bool - // instead. - uv_cancel((uv_req_t *)&req); } -void AssetRequestBaton::notify_error(uv_fs_t *req) { - AssetRequestBaton *ptr = (AssetRequestBaton *)req->data; +void AssetRequestBaton::notify_error(uv_async_t *async, const int code, const char *message) { + AssetRequestBaton *ptr = (AssetRequestBaton *)async->data; assert(ptr->thread_id == uv_thread_self()); - if (ptr->request && req->result < 0 && !ptr->canceled && req->result != UV_ECANCELED) { + if (ptr->request && !ptr->canceled) { ptr->request->response = std::unique_ptr<Response>(new Response); - ptr->request->response->code = req->result == UV_ENOENT ? 404 : 500; -#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 - ptr->request->response->message = uv_strerror(uv_last_error(req->loop)); -#else - ptr->request->response->message = uv_strerror(int(req->result)); -#endif + ptr->request->response->code = code; + ptr->request->response->message = message; ptr->request->notify(); } } -void AssetRequestBaton::file_opened(uv_fs_t *req) { - AssetRequestBaton *ptr = (AssetRequestBaton *)req->data; +void AssetRequestBaton::run(uv_async_t *async) { + AssetRequestBaton *ptr = (AssetRequestBaton *)async->data; assert(ptr->thread_id == uv_thread_self()); - if (req->result < 0) { - // Opening failed or was canceled. There isn't much left we can do. - notify_error(req); - cleanup(req); - } else { - const uv_file fd = uv_file(req->result); - - // We're going to reuse this handle, so we need to cleanup first. - uv_fs_req_cleanup(req); - - if (ptr->canceled || !ptr->request) { - // Either the AssetRequest object has been destructed, or the - // request was canceled. - uv_fs_close(req->loop, req, fd, file_closed); - } else { - ptr->fd = fd; - uv_fs_fstat(req->loop, req, fd, file_stated); - } + if (ptr->canceled || !ptr->request) { + // Either the AssetRequest object has been destructed, or the + // request was canceled. + cleanup(async); + return; } -} -void AssetRequestBaton::file_stated(uv_fs_t *req) { - AssetRequestBaton *ptr = (AssetRequestBaton *)req->data; - assert(ptr->thread_id == uv_thread_self()); + int error = 0; + ptr->apk = zip_open(mbgl::android::apk_path.c_str(), 0, &error); + if (ptr->apk == nullptr || ptr->canceled || !ptr->request) { + // Opening the APK failed or was canceled. There isn't much left we can do. + const int message_size = zip_error_to_str(nullptr, 0, error, errno); + const std::unique_ptr<char[]> message = boost::make_unique<char[]>(message_size); + zip_error_to_str(message.get(), 0, error, errno); + notify_error(async, 500, message.get()); + cleanup(async); + return; + } - if (req->result != 0 || ptr->canceled || !ptr->request) { - // Stating failed or was canceled. We already have an open file handle + std::string apk_file_path = "assets/" + ptr->path; + ptr->apk_file = zip_fopen(ptr->apk, apk_file_path.c_str(), ZIP_FL_NOCASE); + if (ptr->apk_file == nullptr || ptr->canceled || !ptr->request) { + // Opening the asset failed or was canceled. We already have an open file handle // though, which we'll have to close. - notify_error(req); - - uv_fs_req_cleanup(req); - uv_fs_close(req->loop, req, ptr->fd, file_closed); - } else { -#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 - const uv_statbuf_t *stat = static_cast<const uv_statbuf_t *>(req->ptr); -#else - const uv_stat_t *stat = static_cast<const uv_stat_t *>(req->ptr); -#endif - if (stat->st_size > std::numeric_limits<int>::max()) { - // File is too large for us to open this way because uv_buf's only support unsigned - // ints as maximum size. - if (ptr->request) { - ptr->request->response = std::unique_ptr<Response>(new Response); - ptr->request->response->code = UV_EFBIG; -#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 - ptr->request->response->message = uv_strerror(uv_err_t {UV_EFBIG, 0}); -#else - ptr->request->response->message = uv_strerror(UV_EFBIG); -#endif - ptr->request->notify(); - } - - uv_fs_req_cleanup(req); - uv_fs_close(req->loop, req, ptr->fd, file_closed); - } else { - const unsigned int size = (unsigned int)(stat->st_size); - ptr->body.resize(size); - ptr->buffer = uv_buf_init(const_cast<char *>(ptr->body.data()), size); - uv_fs_req_cleanup(req); -#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 - uv_fs_read(req->loop, req, ptr->fd, ptr->buffer.base, ptr->buffer.len, -1, file_read); -#else - uv_fs_read(req->loop, req, ptr->fd, &ptr->buffer, 1, 0, file_read); -#endif - } + zip_error_get(ptr->apk, &error, nullptr); + notify_error(async, error == ZIP_ER_NOENT ? 404 : 500, zip_strerror(ptr->apk)); + zip_close(ptr->apk); + ptr->apk = nullptr; + cleanup(async); + return; } -} - -void AssetRequestBaton::file_read(uv_fs_t *req) { - AssetRequestBaton *ptr = (AssetRequestBaton *)req->data; - assert(ptr->thread_id == uv_thread_self()); - if (req->result < 0 || ptr->canceled || !ptr->request) { + struct zip_stat stat; + if (zip_stat(ptr->apk, apk_file_path.c_str(), ZIP_FL_NOCASE, &stat) != 0 || + ptr->canceled || !ptr->request) { // Stating failed or was canceled. We already have an open file handle // though, which we'll have to close. - notify_error(req); - } else { - // File was successfully read. + notify_error(async, 500, zip_strerror(ptr->apk)); + zip_fclose(ptr->apk_file); + ptr->apk_file = nullptr; + zip_close(ptr->apk); + ptr->apk = nullptr; + cleanup(async); + return; + } +/* + if (stat.size > std::numeric_limits<int>::max()) { + // File is too large for us to open this way because uv_buf's only support unsigned + // ints as maximum size. if (ptr->request) { ptr->request->response = std::unique_ptr<Response>(new Response); - ptr->request->response->code = 200; - ptr->request->response->data = std::move(ptr->body); + ptr->request->response->code = UV_EFBIG; + ptr->request->response->message = uv_strerror(UV_EFBIG); ptr->request->notify(); } + zip_fclose(ptr->apk_file); + ptr->apk_file = nullptr; + zip_close(ptr->apk); + ptr->apk = nullptr; + cleanup(async); + return; } +*/ + //const unsigned int size = static_cast<unsigned int>(stat.size); + const std::unique_ptr<char[]> body = boost::make_unique<char[]>(stat.size); - uv_fs_req_cleanup(req); - uv_fs_close(req->loop, req, ptr->fd, file_closed); -} + if (zip_fread(ptr->apk_file, reinterpret_cast<void *>(body.get()), stat.size) == -1 || + ptr->canceled || !ptr->request) { + // Reading failed or was canceled. We already have an open file handle + // though, which we'll have to close. + notify_error(async, 500, zip_file_strerror(ptr->apk_file)); + zip_fclose(ptr->apk_file); + ptr->apk_file = nullptr; + zip_close(ptr->apk); + ptr->apk = nullptr; + cleanup(async); + return; + } -void AssetRequestBaton::file_closed(uv_fs_t *req) { - assert(((AssetRequestBaton *)req->data)->thread_id == uv_thread_self()); + if (ptr->request) { + ptr->request->response = std::unique_ptr<Response>(new Response); + ptr->request->response->code = 200; + ptr->request->response->data = body.get(); + ptr->request->notify(); + } + + if (zip_fclose(ptr->apk_file) != 0) { + // Closing the asset failed. But there isn't anything we can do. + } + ptr->apk_file = nullptr; - if (req->result < 0) { - // Closing the file failed. But there isn't anything we can do. + if (zip_close(ptr->apk) != 0) { + // Closing the APK failed. But there isn't anything we can do. } + ptr->apk = nullptr; - cleanup(req); + cleanup(async); } -void AssetRequestBaton::cleanup(uv_fs_t *req) { - AssetRequestBaton *ptr = (AssetRequestBaton *)req->data; +void AssetRequestBaton::cleanup(uv_async_t *async) { + AssetRequestBaton *ptr = (AssetRequestBaton *)async->data; assert(ptr->thread_id == uv_thread_self()); if (ptr->request) { ptr->request->ptr = nullptr; } - uv_fs_req_cleanup(req); delete ptr; } |