From 5268f55344229f70e3565f63671eb582eaff733f Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sat, 1 Mar 2014 20:53:39 +0100
Subject: [PATCH] java/File: add method ToAbsolutePath() returning
 AllocatedPath

---
 src/android/Environment.cxx  | 66 +++++++++++-------------------------
 src/android/Environment.hxx  | 12 ++++---
 src/fs/StandardDirectory.cxx |  8 +----
 src/java/File.cxx            | 27 ++++++++++++++-
 src/java/File.hxx            | 14 +++++++-
 5 files changed, 67 insertions(+), 60 deletions(-)

diff --git a/src/android/Environment.cxx b/src/android/Environment.cxx
index 7cebb57ca..9813b0b79 100644
--- a/src/android/Environment.cxx
+++ b/src/android/Environment.cxx
@@ -17,18 +17,18 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include "config.h"
 #include "Environment.hxx"
 #include "java/Class.hxx"
 #include "java/String.hxx"
 #include "java/File.hxx"
 #include "util/StringUtil.hxx"
+#include "fs/AllocatedPath.hxx"
 
 namespace Environment {
 	static Java::TrivialClass cls;
 	static jmethodID getExternalStorageDirectory_method;
 	static jmethodID getExternalStoragePublicDirectory_method;
-
-	static jstring getExternalStorageDirectory(JNIEnv *env);
 };
 
 void
@@ -51,63 +51,35 @@ Environment::Deinitialise(JNIEnv *env)
 	cls.Clear(env);
 }
 
-static jstring
-ToAbsolutePathChecked(JNIEnv *env, jobject file)
-{
-	if (file == nullptr)
-		return nullptr;
-
-	jstring path = Java::File::getAbsolutePath(env, file);
-	env->DeleteLocalRef(file);
-	return path;
-}
-
-static jstring
-Environment::getExternalStorageDirectory(JNIEnv *env)
-{
-	jobject file = env->CallStaticObjectMethod(cls,
-						   getExternalStorageDirectory_method);
-	return ToAbsolutePathChecked(env, file);
-}
-
-char *
-Environment::getExternalStorageDirectory(char *buffer, size_t max_size)
+AllocatedPath
+Environment::getExternalStorageDirectory()
 {
 	JNIEnv *env = Java::GetEnv();
 
-	jstring value = getExternalStorageDirectory(env);
-	if (value == nullptr)
-		return nullptr;
+	jobject file =
+		env->CallStaticObjectMethod(cls,
+					    getExternalStorageDirectory_method);
+	if (file == nullptr)
+		return AllocatedPath::Null();
 
-	Java::String value2(env, value);
-	value2.CopyTo(env, buffer, max_size);
-	return buffer;
+	return Java::File::ToAbsolutePath(env, file);
 }
 
-static jstring
-getExternalStoragePublicDirectory(JNIEnv *env, const char *type)
+AllocatedPath
+Environment::getExternalStoragePublicDirectory(const char *type)
 {
-	if (Environment::getExternalStoragePublicDirectory_method == nullptr)
+	if (getExternalStoragePublicDirectory_method == nullptr)
 		/* needs API level 8 */
-		return nullptr;
+		return AllocatedPath::Null();
+
+	JNIEnv *env = Java::GetEnv();
 
 	Java::String type2(env, type);
 	jobject file = env->CallStaticObjectMethod(Environment::cls,
 						   Environment::getExternalStoragePublicDirectory_method,
 						   type2.Get());
-	return ToAbsolutePathChecked(env, file);
-}
+	if (file == nullptr)
+		return AllocatedPath::Null();
 
-char *
-Environment::getExternalStoragePublicDirectory(char *buffer, size_t max_size,
-					       const char *type)
-{
-	JNIEnv *env = Java::GetEnv();
-	jstring path = ::getExternalStoragePublicDirectory(env, type);
-	if (path == nullptr)
-		return nullptr;
-
-	Java::String path2(env, path);
-	path2.CopyTo(env, buffer, max_size);
-	return buffer;
+	return Java::File::ToAbsolutePath(env, file);
 }
diff --git a/src/android/Environment.hxx b/src/android/Environment.hxx
index 054ffc6f2..5a54ea361 100644
--- a/src/android/Environment.hxx
+++ b/src/android/Environment.hxx
@@ -20,8 +20,11 @@
 #ifndef MPD_ANDROID_ENVIRONMENT_HXX
 #define MPD_ANDROID_ENVIRONMENT_HXX
 
+#include "Compiler.h"
+
 #include <jni.h>
-#include <stddef.h>
+
+class AllocatedPath;
 
 namespace Environment {
 	void Initialise(JNIEnv *env);
@@ -30,10 +33,11 @@ namespace Environment {
 	/**
 	 * Determine the mount point of the external SD card.
 	 */
-	char *getExternalStorageDirectory(char *buffer, size_t max_size);
+	gcc_pure
+	AllocatedPath getExternalStorageDirectory();
 
-	char *getExternalStoragePublicDirectory(char *buffer, size_t max_size,
-						const char *type);
+	gcc_pure
+	AllocatedPath getExternalStoragePublicDirectory(const char *type);
 };
 
 #endif
diff --git a/src/fs/StandardDirectory.cxx b/src/fs/StandardDirectory.cxx
index fce54a677..20d66bb10 100644
--- a/src/fs/StandardDirectory.cxx
+++ b/src/fs/StandardDirectory.cxx
@@ -246,13 +246,7 @@ AllocatedPath GetUserMusicDir()
 #elif defined(USE_XDG)
 	return GetUserDir("XDG_MUSIC_DIR");
 #elif defined(ANDROID)
-	char buffer[1024];
-	if (Environment::getExternalStoragePublicDirectory(buffer,
-							   sizeof(buffer),
-							   "Music") == nullptr)
-		return AllocatedPath::Null();
-
-	return AllocatedPath::FromUTF8(buffer);
+	return Environment::getExternalStoragePublicDirectory("Music");
 #else
 	return AllocatedPath::Null();
 #endif
diff --git a/src/java/File.cxx b/src/java/File.cxx
index 03e3defdf..8e9599dfc 100644
--- a/src/java/File.cxx
+++ b/src/java/File.cxx
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2012 Max Kellermann <max@duempel.org>
+ * Copyright (C) 2010-2014 Max Kellermann <max@duempel.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,8 +27,13 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "config.h"
 #include "File.hxx"
 #include "Class.hxx"
+#include "String.hxx"
+#include "Object.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "fs/Limits.hxx"
 
 jmethodID Java::File::getAbsolutePath_method;
 
@@ -40,3 +45,23 @@ Java::File::Initialise(JNIEnv *env)
 	getAbsolutePath_method = env->GetMethodID(cls, "getAbsolutePath",
 						  "()Ljava/lang/String;");
 }
+
+AllocatedPath
+Java::File::ToAbsolutePath(JNIEnv *env, jobject _file)
+{
+	assert(env != nullptr);
+	assert(_file != nullptr);
+
+	LocalObject file(env, _file);
+
+	const jstring path = getAbsolutePath(env, file);
+	if (path == nullptr) {
+		env->ExceptionClear();
+		return AllocatedPath::Null();
+	}
+
+	Java::String path2(env, path);
+	char buffer[MPD_PATH_MAX];
+	path2.CopyTo(env, buffer, sizeof(buffer));
+	return AllocatedPath::FromUTF8(buffer);
+}
diff --git a/src/java/File.hxx b/src/java/File.hxx
index 57af6199c..3636fc7c6 100644
--- a/src/java/File.hxx
+++ b/src/java/File.hxx
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2012 Max Kellermann <max@duempel.org>
+ * Copyright (C) 2010-2014 Max Kellermann <max@duempel.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,6 +34,8 @@
 
 #include <jni.h>
 
+class AllocatedPath;
+
 namespace Java {
 	/**
 	 * Wrapper for a java.io.File object.
@@ -42,12 +44,22 @@ namespace Java {
 		static jmethodID getAbsolutePath_method;
 
 	public:
+		gcc_nonnull_all
 		static void Initialise(JNIEnv *env);
 
+		gcc_nonnull_all
 		static jstring getAbsolutePath(JNIEnv *env, jobject file) {
 			return (jstring)env->CallObjectMethod(file,
 							      getAbsolutePath_method);
 		}
+
+		/**
+		 * Invoke File.getAbsolutePath() and release the
+		 * specified File reference.
+		 */
+		gcc_pure gcc_nonnull_all
+		static AllocatedPath ToAbsolutePath(JNIEnv *env,
+						    jobject file);
 	};
 }