diff options
Diffstat (limited to 'misc')
-rw-r--r-- | misc/bstr.c | 20 | ||||
-rw-r--r-- | misc/bstr.h | 8 | ||||
-rw-r--r-- | misc/charset_conv.c | 21 | ||||
-rw-r--r-- | misc/dispatch.c | 95 | ||||
-rw-r--r-- | misc/io_utils.c | 87 | ||||
-rw-r--r-- | misc/io_utils.h | 25 | ||||
-rw-r--r-- | misc/jni.c | 312 | ||||
-rw-r--r-- | misc/jni.h | 16 | ||||
-rw-r--r-- | misc/json.c | 7 | ||||
-rw-r--r-- | misc/json.h | 2 | ||||
-rw-r--r-- | misc/language.c | 362 | ||||
-rw-r--r-- | misc/language.h | 31 | ||||
-rw-r--r-- | misc/node.c | 17 | ||||
-rw-r--r-- | misc/node.h | 3 | ||||
-rw-r--r-- | misc/path_utils.c | 219 | ||||
-rw-r--r-- | misc/path_utils.h | 64 | ||||
-rw-r--r-- | misc/random.c | 75 | ||||
-rw-r--r-- | misc/random.h | 41 | ||||
-rw-r--r-- | misc/rendezvous.c | 17 | ||||
-rw-r--r-- | misc/thread_pool.c | 78 | ||||
-rw-r--r-- | misc/thread_pool.h | 1 | ||||
-rw-r--r-- | misc/thread_tools.c | 83 | ||||
-rw-r--r-- | misc/thread_tools.h | 11 | ||||
-rw-r--r-- | misc/uuid.c | 141 | ||||
-rw-r--r-- | misc/uuid.h | 146 |
25 files changed, 1543 insertions, 339 deletions
diff --git a/misc/bstr.c b/misc/bstr.c index 4f1e8629b3..abe688bd14 100644 --- a/misc/bstr.c +++ b/misc/bstr.c @@ -467,3 +467,23 @@ bool bstr_decode_hex(void *talloc_ctx, struct bstr hex, struct bstr *out) *out = (struct bstr){ .start = arr, .len = len }; return true; } + +#ifdef _WIN32 + +#include <windows.h> + +int bstr_to_wchar(void *talloc_ctx, struct bstr s, wchar_t **ret) +{ + int count = MultiByteToWideChar(CP_UTF8, 0, s.start, s.len, NULL, 0); + if (count <= 0) + abort(); + wchar_t *wbuf = *ret; + if (!wbuf || ta_get_size(wbuf) < (count + 1) * sizeof(wchar_t)) + wbuf = talloc_realloc(talloc_ctx, wbuf, wchar_t, count + 1); + MultiByteToWideChar(CP_UTF8, 0, s.start, s.len, wbuf, count); + wbuf[count] = L'\0'; + *ret = wbuf; + return count; +} + +#endif diff --git a/misc/bstr.h b/misc/bstr.h index dc8ad4030c..aaae7d695c 100644 --- a/misc/bstr.h +++ b/misc/bstr.h @@ -56,6 +56,8 @@ static inline struct bstr bstrdup(void *talloc_ctx, struct bstr str) return r; } +#define bstr0_lit(s) {(unsigned char *)(s), sizeof("" s) - 1} + static inline struct bstr bstr0(const char *s) { return (struct bstr){(unsigned char *)s, s ? strlen(s) : 0}; @@ -223,6 +225,12 @@ static inline bool bstr_eatend0(struct bstr *s, const char *prefix) return bstr_eatend(s, bstr0(prefix)); } +#ifdef _WIN32 + +int bstr_to_wchar(void *talloc_ctx, struct bstr s, wchar_t **ret); + +#endif + // create a pair (not single value!) for "%.*s" printf syntax #define BSTR_P(bstr) (int)((bstr).len), ((bstr).start ? (char*)(bstr).start : "") diff --git a/misc/charset_conv.c b/misc/charset_conv.c index 51e55c6338..b54f6362b6 100644 --- a/misc/charset_conv.c +++ b/misc/charset_conv.c @@ -101,18 +101,6 @@ static const char *mp_uchardet(void *talloc_ctx, struct mp_log *log, bstr buf) const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, const char *user_cp, int flags) { - if (strcasecmp(user_cp, "enca") == 0 || strcasecmp(user_cp, "guess") == 0 || - strcasecmp(user_cp, "uchardet") == 0 || strchr(user_cp, ':')) - { - mp_err(log, "This syntax for the --sub-codepage option was deprecated " - "and has been removed.\n"); - if (strncasecmp(user_cp, "utf8:", 5) == 0) { - user_cp = user_cp + 5; - } else { - user_cp = ""; - } - } - if (user_cp[0] == '+') { mp_verbose(log, "Forcing charset '%s'.\n", user_cp + 1); return user_cp + 1; @@ -126,7 +114,8 @@ const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, int r = bstr_validate_utf8(buf); if (r >= 0 || (r > -8 && (flags & MP_ICONV_ALLOW_CUTOFF))) { - mp_verbose(log, "Data looks like UTF-8, ignoring user-provided charset.\n"); + if (strcmp(user_cp, "auto") != 0 && !mp_charset_is_utf8(user_cp)) + mp_verbose(log, "Data looks like UTF-8, ignoring user-provided charset.\n"); return "utf-8"; } @@ -161,6 +150,9 @@ const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags) { #if HAVE_ICONV + if (!buf.len) + return buf; + if (!cp || !cp[0] || mp_charset_is_utf8(cp)) return buf; @@ -231,9 +223,10 @@ bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags) outbuf[osize - oleft - 1] = 0; return (bstr){outbuf, osize - oleft - 1}; -#endif failure: +#endif + if (flags & MP_NO_LATIN1_FALLBACK) { return buf; } else { diff --git a/misc/dispatch.c b/misc/dispatch.c index 0c3c574afa..6fd9fe1a43 100644 --- a/misc/dispatch.c +++ b/misc/dispatch.c @@ -26,8 +26,8 @@ struct mp_dispatch_queue { struct mp_dispatch_item *head, *tail; - pthread_mutex_t lock; - pthread_cond_t cond; + mp_mutex lock; + mp_cond cond; void (*wakeup_fn)(void *wakeup_ctx); void *wakeup_ctx; void (*onlock_fn)(void *onlock_ctx); @@ -39,7 +39,7 @@ struct mp_dispatch_queue { // The target thread is in mp_dispatch_queue_process() (and either idling, // locked, or running a dispatch callback). bool in_process; - pthread_t in_process_thread; + mp_thread_id in_process_thread_id; // The target thread is in mp_dispatch_queue_process(), and currently // something has exclusive access to it (e.g. running a dispatch callback, // or a different thread got it with mp_dispatch_lock()). @@ -48,7 +48,7 @@ struct mp_dispatch_queue { size_t lock_requests; // locked==true is due to a mp_dispatch_lock() call (for debugging). bool locked_explicit; - pthread_t locked_explicit_thread; + mp_thread_id locked_explicit_thread_id; }; struct mp_dispatch_item { @@ -67,8 +67,8 @@ static void queue_dtor(void *p) assert(!queue->in_process); assert(!queue->lock_requests); assert(!queue->locked); - pthread_cond_destroy(&queue->cond); - pthread_mutex_destroy(&queue->lock); + mp_cond_destroy(&queue->cond); + mp_mutex_destroy(&queue->lock); } // A dispatch queue lets other threads run callbacks in a target thread. @@ -76,7 +76,7 @@ static void queue_dtor(void *p) // Free the dispatch queue with talloc_free(). At the time of destruction, // the queue must be empty. The easiest way to guarantee this is to // terminate all potential senders, then call mp_dispatch_run() with a -// function that e.g. makes the target thread exit, then pthread_join() the +// function that e.g. makes the target thread exit, then mp_thread_join() the // target thread, and finally destroy the queue. Another way is calling // mp_dispatch_queue_process() after terminating all potential senders, and // then destroying the queue. @@ -85,8 +85,8 @@ struct mp_dispatch_queue *mp_dispatch_create(void *ta_parent) struct mp_dispatch_queue *queue = talloc_ptrtype(ta_parent, queue); *queue = (struct mp_dispatch_queue){0}; talloc_set_destructor(queue, queue_dtor); - pthread_mutex_init(&queue->lock, NULL); - pthread_cond_init(&queue->cond, NULL); + mp_mutex_init(&queue->lock); + mp_cond_init(&queue->cond); return queue; } @@ -126,14 +126,14 @@ void mp_dispatch_set_onlock_fn(struct mp_dispatch_queue *queue, static void mp_dispatch_append(struct mp_dispatch_queue *queue, struct mp_dispatch_item *item) { - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); if (item->mergeable) { for (struct mp_dispatch_item *cur = queue->head; cur; cur = cur->next) { if (cur->mergeable && cur->fn == item->fn && cur->fn_data == item->fn_data) { talloc_free(item); - pthread_mutex_unlock(&queue->lock); + mp_mutex_unlock(&queue->lock); return; } } @@ -148,12 +148,12 @@ static void mp_dispatch_append(struct mp_dispatch_queue *queue, // Wake up the main thread; note that other threads might wait on this // condition for reasons, so broadcast the condition. - pthread_cond_broadcast(&queue->cond); + mp_cond_broadcast(&queue->cond); // No wakeup callback -> assume mp_dispatch_queue_process() needs to be // interrupted instead. if (!queue->wakeup_fn) queue->interrupted = true; - pthread_mutex_unlock(&queue->lock); + mp_mutex_unlock(&queue->lock); if (queue->wakeup_fn) queue->wakeup_fn(queue->wakeup_ctx); @@ -218,7 +218,7 @@ void mp_dispatch_enqueue_notify(struct mp_dispatch_queue *queue, void mp_dispatch_cancel_fn(struct mp_dispatch_queue *queue, mp_dispatch_fn fn, void *fn_data) { - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); struct mp_dispatch_item **pcur = &queue->head; queue->tail = NULL; while (*pcur) { @@ -231,7 +231,7 @@ void mp_dispatch_cancel_fn(struct mp_dispatch_queue *queue, pcur = &cur->next; } } - pthread_mutex_unlock(&queue->lock); + mp_mutex_unlock(&queue->lock); } // Run fn(fn_data) on the target thread synchronously. This function enqueues @@ -247,10 +247,10 @@ void mp_dispatch_run(struct mp_dispatch_queue *queue, }; mp_dispatch_append(queue, &item); - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); while (!item.completed) - pthread_cond_wait(&queue->cond, &queue->lock); - pthread_mutex_unlock(&queue->lock); + mp_cond_wait(&queue->cond, &queue->lock); + mp_mutex_unlock(&queue->lock); } // Process any outstanding dispatch items in the queue. This also handles @@ -271,18 +271,18 @@ void mp_dispatch_run(struct mp_dispatch_queue *queue, // no enqueued callback can call the lock/unlock functions). void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout) { - pthread_mutex_lock(&queue->lock); - queue->wait = timeout > 0 ? mp_add_timeout(mp_time_us(), timeout) : 0; + mp_mutex_lock(&queue->lock); + queue->wait = timeout > 0 ? mp_time_ns_add(mp_time_ns(), timeout) : 0; assert(!queue->in_process); // recursion not allowed queue->in_process = true; - queue->in_process_thread = pthread_self(); + queue->in_process_thread_id = mp_thread_current_id(); // Wake up thread which called mp_dispatch_lock(). if (queue->lock_requests) - pthread_cond_broadcast(&queue->cond); + mp_cond_broadcast(&queue->cond); while (1) { if (queue->lock_requests) { // Block due to something having called mp_dispatch_lock(). - pthread_cond_wait(&queue->cond, &queue->lock); + mp_cond_wait(&queue->cond, &queue->lock); } else if (queue->head) { struct mp_dispatch_item *item = queue->head; queue->head = item->next; @@ -295,23 +295,22 @@ void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout) // from mp_dispatch_lock(), which is done by locked=true. assert(!queue->locked); queue->locked = true; - pthread_mutex_unlock(&queue->lock); + mp_mutex_unlock(&queue->lock); item->fn(item->fn_data); - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); assert(queue->locked); queue->locked = false; // Wakeup mp_dispatch_run(), also mp_dispatch_lock(). - pthread_cond_broadcast(&queue->cond); + mp_cond_broadcast(&queue->cond); if (item->asynchronous) { talloc_free(item); } else { item->completed = true; } } else if (queue->wait > 0 && !queue->interrupted) { - struct timespec ts = mp_time_us_to_timespec(queue->wait); - if (pthread_cond_timedwait(&queue->cond, &queue->lock, &ts)) + if (mp_cond_timedwait_until(&queue->cond, &queue->lock, queue->wait)) queue->wait = 0; } else { break; @@ -320,7 +319,7 @@ void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout) assert(!queue->locked); queue->in_process = false; queue->interrupted = false; - pthread_mutex_unlock(&queue->lock); + mp_mutex_unlock(&queue->lock); } // If the queue is inside of mp_dispatch_queue_process(), make it return as @@ -331,10 +330,10 @@ void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout) // wakeup the main thread from another thread in a race free way). void mp_dispatch_interrupt(struct mp_dispatch_queue *queue) { - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); queue->interrupted = true; - pthread_cond_broadcast(&queue->cond); - pthread_mutex_unlock(&queue->lock); + mp_cond_broadcast(&queue->cond); + mp_mutex_unlock(&queue->lock); } // If a mp_dispatch_queue_process() call is in progress, then adjust the maximum @@ -347,12 +346,12 @@ void mp_dispatch_interrupt(struct mp_dispatch_queue *queue) // to wait in external APIs. void mp_dispatch_adjust_timeout(struct mp_dispatch_queue *queue, int64_t until) { - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); if (queue->in_process && queue->wait > until) { queue->wait = until; - pthread_cond_broadcast(&queue->cond); + mp_cond_broadcast(&queue->cond); } - pthread_mutex_unlock(&queue->lock); + mp_mutex_unlock(&queue->lock); } // Grant exclusive access to the target thread's state. While this is active, @@ -364,13 +363,13 @@ void mp_dispatch_adjust_timeout(struct mp_dispatch_queue *queue, int64_t until) // already holding the dispatch lock. void mp_dispatch_lock(struct mp_dispatch_queue *queue) { - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); // Must not be called recursively from dispatched callbacks. if (queue->in_process) - assert(!pthread_equal(queue->in_process_thread, pthread_self())); + assert(!mp_thread_id_equal(queue->in_process_thread_id, mp_thread_current_id())); // Must not be called recursively at all. if (queue->locked_explicit) - assert(!pthread_equal(queue->locked_explicit_thread, pthread_self())); + assert(!mp_thread_id_equal(queue->locked_explicit_thread_id, mp_thread_current_id())); queue->lock_requests += 1; // And now wait until the target thread gets "trapped" within the // mp_dispatch_queue_process() call, which will mean we get exclusive @@ -378,41 +377,41 @@ void mp_dispatch_lock(struct mp_dispatch_queue *queue) if (queue->onlock_fn) queue->onlock_fn(queue->onlock_ctx); while (!queue->in_process) { - pthread_mutex_unlock(&queue->lock); + mp_mutex_unlock(&queue->lock); if (queue->wakeup_fn) queue->wakeup_fn(queue->wakeup_ctx); - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); if (queue->in_process) break; - pthread_cond_wait(&queue->cond, &queue->lock); + mp_cond_wait(&queue->cond, &queue->lock); } // Wait until we can get the lock. while (!queue->in_process || queue->locked) - pthread_cond_wait(&queue->cond, &queue->lock); + mp_cond_wait(&queue->cond, &queue->lock); // "Lock". assert(queue->lock_requests); assert(!queue->locked); assert(!queue->locked_explicit); queue->locked = true; queue->locked_explicit = true; - queue->locked_explicit_thread = pthread_self(); - pthread_mutex_unlock(&queue->lock); + queue->locked_explicit_thread_id = mp_thread_current_id(); + mp_mutex_unlock(&queue->lock); } // Undo mp_dispatch_lock(). void mp_dispatch_unlock(struct mp_dispatch_queue *queue) { - pthread_mutex_lock(&queue->lock); + mp_mutex_lock(&queue->lock); assert(queue->locked); // Must be called after a mp_dispatch_lock(), from the same thread. assert(queue->locked_explicit); - assert(pthread_equal(queue->locked_explicit_thread, pthread_self())); + assert(mp_thread_id_equal(queue->locked_explicit_thread_id, mp_thread_current_id())); // "Unlock". queue->locked = false; queue->locked_explicit = false; queue->lock_requests -= 1; // Wakeup mp_dispatch_queue_process(), and maybe other mp_dispatch_lock()s. // (Would be nice to wake up only 1 other locker if lock_requests>0.) - pthread_cond_broadcast(&queue->cond); - pthread_mutex_unlock(&queue->lock); + mp_cond_broadcast(&queue->cond); + mp_mutex_unlock(&queue->lock); } diff --git a/misc/io_utils.c b/misc/io_utils.c new file mode 100644 index 0000000000..c973cee0e4 --- /dev/null +++ b/misc/io_utils.c @@ -0,0 +1,87 @@ +/* + * I/O utility functions + * + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <limits.h> +#include <unistd.h> + +#include "mpv_talloc.h" +#include "config.h" +#include "misc/random.h" +#include "misc/io_utils.h" +#include "osdep/io.h" + +int mp_mkostemps(char *template, int suffixlen, int flags) +{ + size_t len = strlen(template); + char *t = len >= 6 + suffixlen ? &template[len - (6 + suffixlen)] : NULL; + if (!t || strncmp(t, "XXXXXX", 6) != 0) { + errno = EINVAL; + return -1; + } + + for (size_t fuckshit = 0; fuckshit < UINT32_MAX; fuckshit++) { + // Using a random value may make it require fewer iterations (even if + // not truly random; just a counter would be sufficient). + size_t fuckmess = mp_rand_next(); + char crap[7] = ""; + snprintf(crap, sizeof(crap), "%06zx", fuckmess); + memcpy(t, crap, 6); + + int res = open(template, O_RDWR | O_CREAT | O_EXCL | flags, 0600); + if (res >= 0 || errno != EEXIST) + return res; + } + + errno = EEXIST; + return -1; +} + +bool mp_save_to_file(const char *filepath, const void *data, size_t size) +{ + assert(filepath && data && size); + + bool result = false; + char *tmp = talloc_asprintf(NULL, "%sXXXXXX", filepath); + int fd = mkstemp(tmp); + if (fd < 0) + goto done; + FILE *cache = fdopen(fd, "wb"); + if (!cache) { + close(fd); + unlink(tmp); + goto done; + } + size_t written = fwrite(data, size, 1, cache); + int ret = fclose(cache); + if (written > 0 && !ret) { + ret = rename(tmp, filepath); + result = !ret; + } else { + unlink(tmp); + } + +done: + talloc_free(tmp); + return result; +} diff --git a/misc/io_utils.h b/misc/io_utils.h new file mode 100644 index 0000000000..012f2425f6 --- /dev/null +++ b/misc/io_utils.h @@ -0,0 +1,25 @@ +/* + * I/O utility functions + * + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stddef.h> + +int mp_mkostemps(char *template, int suffixlen, int flags); +bool mp_save_to_file(const char *filepath, const void *data, size_t size); diff --git a/misc/jni.c b/misc/jni.c index 3f76f379cb..02440722ca 100644 --- a/misc/jni.c +++ b/misc/jni.c @@ -20,17 +20,16 @@ */ #include <libavcodec/jni.h> -#include <libavutil/mem.h> -#include <libavutil/bprint.h> -#include <pthread.h> #include <stdlib.h> #include "jni.h" +#include "mpv_talloc.h" +#include "osdep/threads.h" static JavaVM *java_vm; static pthread_key_t current_env; -static pthread_once_t once = PTHREAD_ONCE_INIT; -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static mp_once once = MP_STATIC_ONCE_INITIALIZER; +static mp_static_mutex lock = MP_STATIC_MUTEX_INITIALIZER; static void jni_detach_env(void *data) { @@ -46,26 +45,23 @@ static void jni_create_pthread_key(void) JNIEnv *mp_jni_get_env(struct mp_log *log) { - int ret = 0; JNIEnv *env = NULL; - pthread_mutex_lock(&lock); - if (java_vm == NULL) { + mp_mutex_lock(&lock); + if (!java_vm) java_vm = av_jni_get_java_vm(NULL); - } if (!java_vm) { mp_err(log, "No Java virtual machine has been registered\n"); goto done; } - pthread_once(&once, jni_create_pthread_key); + mp_exec_once(&once, jni_create_pthread_key); - if ((env = pthread_getspecific(current_env)) != NULL) { + if ((env = pthread_getspecific(current_env)) != NULL) goto done; - } - ret = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6); + int ret = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6); switch(ret) { case JNI_EDETACHED: if ((*java_vm)->AttachCurrentThread(java_vm, &env, NULL) != 0) { @@ -86,45 +82,33 @@ JNIEnv *mp_jni_get_env(struct mp_log *log) } done: - pthread_mutex_unlock(&lock); + mp_mutex_unlock(&lock); return env; } char *mp_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, struct mp_log *log) { - char *ret = NULL; - const char *utf_chars = NULL; - - jboolean copy = 0; - - if (!string) { + if (!string) return NULL; - } - utf_chars = (*env)->GetStringUTFChars(env, string, ©); + const char *utf_chars = (*env)->GetStringUTFChars(env, string, NULL); if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); - mp_err(log, "String.getStringUTFChars() threw an exception\n"); + mp_err(log, "getStringUTFChars() threw an exception\n"); return NULL; } - ret = av_strdup(utf_chars); + char *ret = talloc_strdup(NULL, utf_chars); (*env)->ReleaseStringUTFChars(env, string, utf_chars); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionClear(env); - mp_err(log, "String.releaseStringUTFChars() threw an exception\n"); - return NULL; - } return ret; } -jstring mp_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, struct mp_log *log) +jstring mp_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, + struct mp_log *log) { - jstring ret; - - ret = (*env)->NewStringUTF(env, utf_chars); + jstring ret = (*env)->NewStringUTF(env, utf_chars); if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); mp_err(log, "NewStringUTF() threw an exception\n"); @@ -134,24 +118,19 @@ jstring mp_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, struct m return ret; } -int mp_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, struct mp_log *log) +int mp_jni_exception_get_summary(JNIEnv *env, jthrowable exception, + char **error, struct mp_log *log) { int ret = 0; - AVBPrint bp; - char *name = NULL; char *message = NULL; jclass class_class = NULL; - jmethodID get_name_id = NULL; - jclass exception_class = NULL; - jmethodID get_message_id = NULL; - jstring string = NULL; - av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + *error = NULL; exception_class = (*env)->GetObjectClass(env, exception); if ((*env)->ExceptionCheck(env)) { @@ -169,7 +148,7 @@ int mp_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error goto done; } - get_name_id = (*env)->GetMethodID(env, class_class, "getName", "()Ljava/lang/String;"); + jmethodID get_name_id = (*env)->GetMethodID(env, class_class, "getName", "()Ljava/lang/String;"); if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); mp_err(log, "Could not find method Class.getName()\n"); @@ -187,14 +166,13 @@ int mp_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error if (string) { name = mp_jni_jstring_to_utf_chars(env, string, log); - (*env)->DeleteLocalRef(env, string); - string = NULL; + MP_JNI_LOCAL_FREEP(&string); } - get_message_id = (*env)->GetMethodID(env, exception_class, "getMessage", "()Ljava/lang/String;"); + jmethodID get_message_id = (*env)->GetMethodID(env, exception_class, "getMessage", "()Ljava/lang/String;"); if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); - mp_err(log, "Could not find method java/lang/Throwable.getMessage()\n"); + mp_err(log, "Could not find method Throwable.getMessage()\n"); ret = -1; goto done; } @@ -209,164 +187,145 @@ int mp_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error if (string) { message = mp_jni_jstring_to_utf_chars(env, string, log); - (*env)->DeleteLocalRef(env, string); - string = NULL; + MP_JNI_LOCAL_FREEP(&string); } if (name && message) { - av_bprintf(&bp, "%s: %s", name, message); + *error = talloc_asprintf(NULL, "%s: %s", name, message); } else if (name && !message) { - av_bprintf(&bp, "%s occurred", name); + *error = talloc_asprintf(NULL, "%s occurred", name); } else if (!name && message) { - av_bprintf(&bp, "Exception: %s", message); + *error = talloc_asprintf(NULL, "Exception: %s", message); } else { mp_warn(log, "Could not retrieve exception name and message\n"); - av_bprintf(&bp, "Exception occurred"); + *error = talloc_strdup(NULL, "Exception occurred"); } - ret = av_bprint_finalize(&bp, error); done: - av_free(name); - av_free(message); - - if (class_class) { - (*env)->DeleteLocalRef(env, class_class); - } - - if (exception_class) { - (*env)->DeleteLocalRef(env, exception_class); - } + talloc_free(name); + talloc_free(message); - if (string) { - (*env)->DeleteLocalRef(env, string); - } + MP_JNI_LOCAL_FREEP(&class_class); + MP_JNI_LOCAL_FREEP(&exception_class); + MP_JNI_LOCAL_FREEP(&string); return ret; } int mp_jni_exception_check(JNIEnv *env, int logging, struct mp_log *log) { - int ret; - - jthrowable exception; - - char *message = NULL; - - if (!(*(env))->ExceptionCheck((env))) { + if (!(*env)->ExceptionCheck(env)) return 0; - } if (!logging) { - (*(env))->ExceptionClear((env)); + (*env)->ExceptionClear(env); return -1; } - exception = (*env)->ExceptionOccurred(env); - (*(env))->ExceptionClear((env)); + jthrowable exception = (*env)->ExceptionOccurred(env); + (*env)->ExceptionClear(env); - if ((ret = mp_jni_exception_get_summary(env, exception, &message, log)) < 0) { - (*env)->DeleteLocalRef(env, exception); + char *message = NULL; + int ret = mp_jni_exception_get_summary(env, exception, &message, log); + MP_JNI_LOCAL_FREEP(&exception); + if (ret < 0) return ret; - } - - (*env)->DeleteLocalRef(env, exception); mp_err(log, "%s\n", message); - av_free(message); - + talloc_free(message); return -1; } -int mp_jni_init_jfields(JNIEnv *env, void *jfields, const struct MPJniField *jfields_mapping, int global, struct mp_log *log) +#define CHECK_EXC_MANDATORY() do { \ + if ((ret = mp_jni_exception_check(env, mandatory, log)) < 0 && \ + mandatory) { \ + goto done; \ + } \ + } while (0) + +int mp_jni_init_jfields(JNIEnv *env, void *jfields, + const struct MPJniField *jfields_mapping, + int global, struct mp_log *log) { - int i, ret = 0; + int ret = 0; jclass last_clazz = NULL; - for (i = 0; jfields_mapping[i].name; i++) { - int mandatory = jfields_mapping[i].mandatory; + for (int i = 0; jfields_mapping[i].name; i++) { + bool mandatory = !!jfields_mapping[i].mandatory; enum MPJniFieldType type = jfields_mapping[i].type; - if (type == MP_JNI_CLASS) { - jclass clazz; + void *jfield = (uint8_t*)jfields + jfields_mapping[i].offset; + if (type == MP_JNI_CLASS) { last_clazz = NULL; - clazz = (*env)->FindClass(env, jfields_mapping[i].name); - if ((ret = mp_jni_exception_check(env, mandatory, log)) < 0 && mandatory) { - goto done; - } + jclass clazz = (*env)->FindClass(env, jfields_mapping[i].name); + CHECK_EXC_MANDATORY(); - last_clazz = *(jclass*)((uint8_t*)jfields + jfields_mapping[i].offset) = + last_clazz = *(jclass*)jfield = global ? (*env)->NewGlobalRef(env, clazz) : clazz; - if (global) { - (*env)->DeleteLocalRef(env, clazz); - } - - } else { + if (global) + MP_JNI_LOCAL_FREEP(&clazz); - if (!last_clazz) { - ret = -1; - break; - } + continue; + } - switch(type) { - case MP_JNI_FIELD: { - jfieldID field_id = (*env)->GetFieldID(env, last_clazz, jfields_m |