summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/asset_request_baton_libzip.cpp99
-rw-r--r--platform/android/cache_database_data.cpp13
-rw-r--r--platform/android/log_android.cpp59
-rw-r--r--platform/darwin/http_request_baton_cocoa.mm4
-rw-r--r--platform/default/asset_request_baton_noop.cpp24
-rw-r--r--platform/default/caching_http_file_source.cpp6
-rw-r--r--platform/default/glfw_view.cpp2
-rw-r--r--platform/default/headless_view.cpp32
-rw-r--r--platform/default/http_request_baton_curl.cpp114
-rw-r--r--platform/default/image.cpp5
10 files changed, 343 insertions, 15 deletions
diff --git a/platform/android/asset_request_baton_libzip.cpp b/platform/android/asset_request_baton_libzip.cpp
new file mode 100644
index 0000000000..7fc86ae1be
--- /dev/null
+++ b/platform/android/asset_request_baton_libzip.cpp
@@ -0,0 +1,99 @@
+#include <mbgl/android/jni.hpp>
+#include <mbgl/storage/asset_request_baton.hpp>
+#include <mbgl/storage/asset_request.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/util/std.hpp>
+
+#include <cerrno>
+// NOTE a bug in the Android NDK breaks std::errno
+// See https://code.google.com/p/android/issues/detail?id=72349
+// After this is fixed change usage errno to std::errno
+#include <zip.h>
+#include <uv.h>
+
+namespace mbgl {
+
+void AssetRequestBaton::run(AssetRequestBaton *ptr) {
+ assert(uv_thread_self() == ptr->threadId);
+
+ if (ptr->canceled || !ptr->request) {
+ // Either the AssetRequest object has been destructed, or the
+ // request was canceled.
+ cleanup(ptr);
+ return;
+ }
+
+ int error = 0;
+ struct zip *apk = zip_open(mbgl::android::apkPath.c_str(), 0, &error);
+ if ((apk == nullptr) || ptr->canceled || !ptr->request) {
+ // Opening the APK failed or was canceled. There isn't much left we can do.
+ const int messageSize = zip_error_to_str(nullptr, 0, error, errno);
+ const std::unique_ptr<char[]> message = mbgl::util::make_unique<char[]>(messageSize);
+ zip_error_to_str(message.get(), 0, error, errno);
+ notify_error(ptr, 500, message.get());
+ cleanup(ptr);
+ return;
+ }
+
+ std::string apkFilePath = "assets/" + ptr->path;
+ struct zip_file *apkFile = zip_fopen(apk, apkFilePath.c_str(), ZIP_FL_NOCASE);
+ if ((apkFile == 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.
+ zip_error_get(apk, &error, nullptr);
+ notify_error(ptr, error == ZIP_ER_NOENT ? 404 : 500, zip_strerror(apk));
+ zip_close(apk);
+ apk = nullptr;
+ cleanup(ptr);
+ return;
+ }
+
+ struct zip_stat stat;
+ if ((zip_stat(apk, apkFilePath.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(ptr, 500, zip_strerror(apk));
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ cleanup(ptr);
+ return;
+ }
+
+ const std::unique_ptr<char[]> data = mbgl::util::make_unique<char[]>(stat.size);
+
+ if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(data.get()), stat.size)) != stat.size || 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(ptr, 500, zip_file_strerror(apkFile));
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ cleanup(ptr);
+ return;
+ }
+
+ if (ptr->request) {
+ ptr->request->response = std::unique_ptr<Response>(new Response);
+ ptr->request->response->code = 200;
+ std::string body(data.get(), stat.size);
+ ptr->request->response->data = body;
+ ptr->request->notify();
+ }
+
+ if (zip_fclose(apkFile) != 0) {
+ // Closing the asset failed. But there isn't anything we can do.
+ }
+ apkFile = nullptr;
+
+ if (zip_close(apk) != 0) {
+ // Closing the APK failed. But there isn't anything we can do.
+ }
+ apk = nullptr;
+
+ cleanup(ptr);
+}
+
+}
diff --git a/platform/android/cache_database_data.cpp b/platform/android/cache_database_data.cpp
new file mode 100644
index 0000000000..2fefcdc4a3
--- /dev/null
+++ b/platform/android/cache_database_data.cpp
@@ -0,0 +1,13 @@
+#include <mbgl/platform/platform.hpp>
+#include <mbgl/android/jni.hpp>
+
+namespace mbgl {
+namespace platform {
+
+// Returns the path to the default cache database on this system.
+std::string defaultCacheDatabase() {
+ return mbgl::android::cachePath + "/mbgl-cache.db";
+}
+
+}
+}
diff --git a/platform/android/log_android.cpp b/platform/android/log_android.cpp
new file mode 100644
index 0000000000..5e40ce33bd
--- /dev/null
+++ b/platform/android/log_android.cpp
@@ -0,0 +1,59 @@
+#include <mbgl/platform/android/log_android.hpp>
+
+#include <iostream>
+#include <cstdarg>
+#define __STDC_FORMAT_MACROS // NDK bug workaround: https://code.google.com/p/android/issues/detail?id=72349
+#include <cinttypes>
+
+#include <android/log.h>
+
+namespace mbgl {
+
+int AndroidLogBackend::severityToPriority(EventSeverity severity) {
+ switch(severity) {
+ case EventSeverity::Debug:
+ return ANDROID_LOG_DEBUG;
+
+ case EventSeverity::Info:
+ return ANDROID_LOG_INFO;
+
+ case EventSeverity::Warning:
+ return ANDROID_LOG_WARN;
+
+ case EventSeverity::Error:
+ return ANDROID_LOG_ERROR;
+
+ default:
+ return ANDROID_LOG_VERBOSE;
+ }
+}
+
+void AndroidLogBackend::record(EventSeverity severity, Event event, const std::string &msg) {
+ __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "%s", msg.c_str());
+}
+
+void AndroidLogBackend::record(EventSeverity severity, Event event, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ const int len = vsnprintf(nullptr, 0, format, args) + 1;
+ char* buf = new char[len];
+ vsnprintf(buf, len, format, args);
+
+ va_end(args);
+
+ __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "%s", buf);
+
+ delete buf;
+ buf = nullptr;
+}
+
+void AndroidLogBackend::record(EventSeverity severity, Event event, int64_t code) {
+ __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "(%" PRId64 ")", code);
+}
+
+void AndroidLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) {
+ __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "(%" PRId64 ") %s", code, msg.c_str());
+}
+
+}
diff --git a/platform/darwin/http_request_baton_cocoa.mm b/platform/darwin/http_request_baton_cocoa.mm
index 1c256d0ba8..472154dc2f 100644
--- a/platform/darwin/http_request_baton_cocoa.mm
+++ b/platform/darwin/http_request_baton_cocoa.mm
@@ -15,7 +15,7 @@ dispatch_once_t request_initialize = 0;
NSURLSession *session = nullptr;
void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
- assert(std::this_thread::get_id() == ptr->thread_id);
+ assert(std::this_thread::get_id() == ptr->threadId);
// Starts the request.
util::ptr<HTTPRequestBaton> baton = ptr;
@@ -131,7 +131,7 @@ void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
}
void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &ptr) {
- assert(std::this_thread::get_id() == ptr->thread_id);
+ assert(std::this_thread::get_id() == ptr->threadId);
assert(ptr->ptr);
NSURLSessionDataTask *task = CFBridgingRelease(ptr->ptr);
diff --git a/platform/default/asset_request_baton_noop.cpp b/platform/default/asset_request_baton_noop.cpp
new file mode 100644
index 0000000000..2f32026503
--- /dev/null
+++ b/platform/default/asset_request_baton_noop.cpp
@@ -0,0 +1,24 @@
+#include <mbgl/storage/asset_request_baton.hpp>
+#include <mbgl/storage/asset_request.hpp>
+#include <mbgl/storage/response.hpp>
+
+#include <uv.h>
+
+namespace mbgl {
+
+void AssetRequestBaton::run(AssetRequestBaton *ptr) {
+ assert(uv_thread_self() == ptr->threadId);
+
+ if (ptr->canceled || !ptr->request) {
+ // Either the AssetRequest object has been destructed, or the
+ // request was canceled.
+ cleanup(ptr);
+ return;
+ }
+
+ // Just return a 500 error until implemented properly
+ notify_error(ptr, 500, "Assets not implemented on this platform.");
+ cleanup(ptr);
+}
+
+}
diff --git a/platform/default/caching_http_file_source.cpp b/platform/default/caching_http_file_source.cpp
index 3e74f5ed05..20525a2647 100644
--- a/platform/default/caching_http_file_source.cpp
+++ b/platform/default/caching_http_file_source.cpp
@@ -2,6 +2,7 @@
#include <mbgl/storage/file_request.hpp>
#include <mbgl/storage/http_request.hpp>
#include <mbgl/storage/sqlite_store.hpp>
+#include <mbgl/storage/asset_request.hpp>
#include <mbgl/util/uv-messenger.h>
#include <mbgl/util/std.hpp>
@@ -14,7 +15,8 @@ CachingHTTPFileSource::CachingHTTPFileSource(const std::string &path_)
CachingHTTPFileSource::~CachingHTTPFileSource() {
if (hasLoop()) {
- assert(thread_id == std::this_thread::get_id());
+ // FIXME temp fix for #608 crash
+ // assert(thread_id == std::this_thread::get_id());
uv_messenger_stop(queue, [](uv_messenger_t *msgr) {
delete msgr;
});
@@ -82,6 +84,8 @@ std::unique_ptr<Request> CachingHTTPFileSource::request(ResourceType type, const
if (!req) {
if (absoluteURL.substr(0, 7) == "file://") {
req = std::make_shared<FileRequest>(absoluteURL.substr(7), loop);
+ } else if (absoluteURL.substr(0, 8) == "asset://") {
+ req = std::make_shared<AssetRequest>(absoluteURL.substr(8), loop);
} else {
req = std::make_shared<HTTPRequest>(type, absoluteURL, loop, store);
}
diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp
index 4ddcd9019d..e600340dda 100644
--- a/platform/default/glfw_view.cpp
+++ b/platform/default/glfw_view.cpp
@@ -69,7 +69,7 @@ void GLFWView::initialize(mbgl::Map *map_) {
glfwSetKeyCallback(window, key);
- const std::string extensions = (char *)glGetString(GL_EXTENSIONS);
+ const std::string extensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
{
using namespace mbgl;
diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp
index 5b95c76026..264fe4da6b 100644
--- a/platform/default/headless_view.cpp
+++ b/platform/default/headless_view.cpp
@@ -51,7 +51,23 @@ HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display)
void HeadlessView::loadExtensions() {
make_active();
- const std::string extensions = (char *)glGetString(GL_EXTENSIONS);
+
+ std::string extensions;
+ if (usingGl3OrNewer) {
+#ifdef GL_VERSION_3_0
+ GLuint num_extensions = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, reinterpret_cast<GLint *>(&num_extensions));
+ for (GLuint i = 0; i < num_extensions; i++) {
+ extensions.append(reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)));
+ extensions.append(" ");
+ }
+#else
+ throw std::runtime_error("Using GL 3.0+ context with out correct headers.\n");
+#endif
+ } else {
+ extensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
+ }
+
#ifdef MBGL_USE_CGL
if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) {
@@ -92,7 +108,7 @@ static const core_profile_version core_profile_versions[] = {
{0, 0},
};
-GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig) {
+GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig, bool& usingGl3OrNewer) {
static bool context_creation_failed = false;
GLXContext ctx = 0;
@@ -105,7 +121,8 @@ GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig) {
});
// Try to create core profiles from the highest known version on down.
- for (int i = 0; !ctx && core_profile_versions[i].major; i++) {
+ int i = 0;
+ for (; !ctx && core_profile_versions[i].major; i++) {
context_creation_failed = false;
const int context_flags[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, core_profile_versions[i].major,
@@ -118,6 +135,10 @@ GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig) {
}
}
+ if (core_profile_versions[i].major >= 3) {
+ usingGl3OrNewer = true;
+ }
+
// Restore the old error handler.
XSetErrorHandler(previous_error_handler);
return ctx;
@@ -151,11 +172,11 @@ void HeadlessView::createContext() {
#ifdef GLX_ARB_create_context
if (glXCreateContextAttribsARB) {
// Try to create a core profile context.
- gl_context = createCoreProfile(x_display, fb_configs[0]);
+ gl_context = createCoreProfile(x_display, fb_configs[0], usingGl3OrNewer);
}
#endif
- if (!gl_context) {
+ if (gl_context == 0) {
// Try to create a legacy context
gl_context = glXCreateNewContext(x_display, fb_configs[0], GLX_RGBA_TYPE, 0, True);
if (gl_context) {
@@ -333,4 +354,3 @@ void HeadlessView::make_inactive() {
void HeadlessView::swap() {}
}
-
diff --git a/platform/default/http_request_baton_curl.cpp b/platform/default/http_request_baton_curl.cpp
index f05ee5acf9..74c6187e76 100644
--- a/platform/default/http_request_baton_curl.cpp
+++ b/platform/default/http_request_baton_curl.cpp
@@ -1,9 +1,16 @@
+#include <mbgl/mbgl.hpp>
#include <mbgl/storage/http_request_baton.hpp>
#include <mbgl/util/uv-messenger.h>
#include <mbgl/util/time.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/std.hpp>
+#ifdef __ANDROID__
+ #include <mbgl/android/jni.hpp>
+ #include <zip.h>
+ #include <openssl/ssl.h>
+#endif
+
#include <uv.h>
#include <curl/curl.h>
@@ -405,6 +412,103 @@ size_t curl_header_cb(char * const buffer, const size_t size, const size_t nmemb
return length;
}
+// This function is called to load the CA bundle
+// from http://curl.haxx.se/libcurl/c/cacertinmem.html
+#ifdef __ANDROID__
+static CURLcode sslctx_function(CURL */*curl*/, void *sslctx, void */*parm*/) {
+
+ int error = 0;
+ struct zip *apk = zip_open(mbgl::android::apkPath.c_str(), 0, &error);
+ if (apk == nullptr) {
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ struct zip_file *apkFile = zip_fopen(apk, "assets/ca-bundle.crt", ZIP_FL_NOCASE);
+ if (apkFile == nullptr) {
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ struct zip_stat stat;
+ if (zip_stat(apk, "assets/ca-bundle.crt", ZIP_FL_NOCASE, &stat) != 0) {
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ if (stat.size > std::numeric_limits<int>::max()) {
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ const std::unique_ptr<char[]> pem = util::make_unique<char[]>(stat.size);
+
+ if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(pem.get()), stat.size)) != stat.size) {
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // get a pointer to the X509 certificate store (which may be empty!)
+ X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX *)sslctx);
+ if (store == nullptr) {
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // get a BIO
+ BIO *bio = BIO_new_mem_buf(pem.get(), static_cast<int>(stat.size));
+ if (bio == nullptr) {
+ store = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // use it to read the PEM formatted certificate from memory into an X509
+ // structure that SSL can use
+ X509 *cert = nullptr;
+ while (PEM_read_bio_X509(bio, &cert, 0, nullptr) != nullptr) {
+ if (cert == nullptr) {
+ BIO_free(bio);
+ bio = nullptr;
+ store = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ // add our certificate to this store
+ if (X509_STORE_add_cert(store, cert) == 0) {
+ X509_free(cert);
+ cert = nullptr;
+ BIO_free(bio);
+ bio = nullptr;
+ store = nullptr;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ X509_free(cert);
+ cert = nullptr;
+ }
+
+ // decrease reference counts
+ BIO_free(bio);
+ bio = nullptr;
+
+ zip_fclose(apkFile);
+ apkFile = nullptr;
+ zip_close(apk);
+ apk = nullptr;
+
+ // all set to go
+ return CURLE_OK;
+}
+#endif
+
// This function must run in the CURL thread.
void start_request(void *const ptr) {
assert(std::this_thread::get_id() == thread_id);
@@ -436,7 +540,12 @@ void start_request(void *const ptr) {
// Carry on the shared pointer in the private information of the CURL handle.
curl_easy_setopt(context->handle, CURLOPT_PRIVATE, context);
+#ifndef __ANDROID__
curl_easy_setopt(context->handle, CURLOPT_CAINFO, "ca-bundle.crt");
+#else
+ curl_easy_setopt(context->handle, CURLOPT_SSLCERTTYPE, "PEM");
+ curl_easy_setopt(context->handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function);
+#endif
curl_easy_setopt(context->handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(context->handle, CURLOPT_URL, context->baton->path.c_str());
curl_easy_setopt(context->handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
@@ -444,7 +553,6 @@ void start_request(void *const ptr) {
curl_easy_setopt(context->handle, CURLOPT_HEADERFUNCTION, curl_header_cb);
curl_easy_setopt(context->handle, CURLOPT_HEADERDATA, &context->baton->response);
curl_easy_setopt(context->handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate");
- curl_easy_setopt(context->handle, CURLOPT_SHARE, share);
// Start requesting the information.
curl_multi_add_handle(multi, context->handle);
@@ -488,14 +596,14 @@ void create_thread() {
// This function must be run from the main thread (== where the HTTPRequestBaton was created)
void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
- assert(std::this_thread::get_id() == ptr->thread_id);
+ assert(std::this_thread::get_id() == ptr->threadId);
uv_once(&once, create_thread);
uv_messenger_send(&start_messenger, new util::ptr<HTTPRequestBaton>(ptr));
}
// This function must be run from the main thread (== where the HTTPRequestBaton was created)
void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &ptr) {
- assert(std::this_thread::get_id() == ptr->thread_id);
+ assert(std::this_thread::get_id() == ptr->threadId);
uv_once(&once, create_thread);
uv_messenger_send(&stop_messenger, new util::ptr<HTTPRequestBaton>(ptr));
}
diff --git a/platform/default/image.cpp b/platform/default/image.cpp
index d881b9231c..311aa2ed72 100644
--- a/platform/default/image.cpp
+++ b/platform/default/image.cpp
@@ -1,4 +1,5 @@
#include <mbgl/util/image.hpp>
+#include <mbgl/platform/log.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/std.hpp>
@@ -31,14 +32,14 @@ std::string compress_png(int width, int height, void *rgba) {
png_voidp error_ptr = 0;
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr, NULL, NULL);
if (!png_ptr) {
- fprintf(stderr, "Couldn't create png_ptr\n");
+ Log::Error(Event::Image, "Couldn't create png_ptr");
return "";
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!png_ptr) {
png_destroy_write_struct(&png_ptr, (png_infopp)0);
- fprintf(stderr, "Couldn't create info_ptr\n");
+ Log::Error(Event::Image, "Couldn't create info_ptr");
return "";
}