1 /*
2  *      Copyright (C) 2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 /*
21  * Copyright (c) 2011-2012 Dmitry Moskalchuk <dm@crystax.net>.
22  * All rights reserved.
23  *
24  * Redistribution and use in source and binary forms, with or without modification, are
25  * permitted provided that the following conditions are met:
26  *
27  *    1. Redistributions of source code must retain the above copyright notice, this list of
28  *       conditions and the following disclaimer.
29  *
30  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
31  *       of conditions and the following disclaimer in the documentation and/or other materials
32  *       provided with the distribution.
33  *
34  * THIS SOFTWARE IS PROVIDED BY Dmitry Moskalchuk ''AS IS'' AND ANY EXPRESS OR IMPLIED
35  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Dmitry Moskalchuk OR
37  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
40  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43  *
44  * The views and conclusions contained in the software and documentation are those of the
45  * authors and should not be interpreted as representing official policies, either expressed
46  * or implied, of Dmitry Moskalchuk.
47  */
48 
49 #define DBG(fmt, ...)
50 #include <string>
51 #include <string.h>
52 #include "jutils-details.hpp"
53 
54 namespace jni
55 {
56 
57 namespace details
58 {
59 
cast(jstring const & v)60 std::string jcast_helper<std::string, jstring>::cast(jstring const &v)
61 {
62     JNIEnv *env = xbmc_jnienv();
63     std::string ret;
64     if (!v)
65       return ret;
66 
67     const char *s = env->GetStringUTFChars(v, JNI_FALSE);
68     if (s)
69     {
70       ret = s;
71       env->ReleaseStringUTFChars(v, s);
72     }
73     return ret;
74 }
75 
cast(const std::string & s)76 jhstring jcast_helper<jhstring, std::string>::cast(const std::string &s)
77 {
78     JNIEnv *env = xbmc_jnienv();
79     jstring ret = NULL;
80     if (!s.empty())
81     {
82       ret = env->NewStringUTF(s.c_str());
83     }
84     return jhstring(ret);
85 }
86 
cast(const std::vector<char> & s)87 jhbyteArray jcast_helper<jhbyteArray, std::vector<char> >::cast(const std::vector<char> &s)
88 {
89   JNIEnv *env = xbmc_jnienv();
90   jbyteArray ret = NULL;
91   if (!s.empty())
92   {
93     char*   pArray;
94     ret = env->NewByteArray(s.size());
95     if ((pArray = (char*)env->GetPrimitiveArrayCritical(ret, NULL)))
96     {
97       memcpy(pArray, s.data(), s.size());
98       env->ReleasePrimitiveArrayCritical(ret, pArray, 0);
99     }
100   }
101   return jhbyteArray(ret);
102 }
103 
104 
cast(const std::vector<int16_t> & s)105 jhshortArray jcast_helper<jhshortArray, std::vector<int16_t> >::cast(const std::vector<int16_t> &s)
106 {
107   JNIEnv *env = xbmc_jnienv();
108   jshortArray ret = NULL;
109   if (!s.empty())
110   {
111     char*   pArray;
112     ret = env->NewShortArray(s.size());
113     if ((pArray = (char*)env->GetPrimitiveArrayCritical(ret, NULL)))
114     {
115       memcpy(pArray, s.data(), s.size() * sizeof(int16_t));
116       env->ReleasePrimitiveArrayCritical(ret, pArray, 0);
117     }
118   }
119   return jhshortArray(ret);
120 }
121 
cast(const std::vector<float> & s)122 jhfloatArray jcast_helper<jhfloatArray, std::vector<float> >::cast(const std::vector<float> &s)
123 {
124   JNIEnv *env = xbmc_jnienv();
125   jfloatArray ret = NULL;
126   if (!s.empty())
127   {
128     char*   pArray;
129     ret = env->NewFloatArray(s.size());
130     if ((pArray = (char*)env->GetPrimitiveArrayCritical(ret, NULL)))
131     {
132       memcpy(pArray, s.data(), s.size() * sizeof(float));
133       env->ReleasePrimitiveArrayCritical(ret, pArray, 0);
134     }
135   }
136   return jhfloatArray(ret);
137 }
138 
cast(const std::vector<std::string> & s)139 jhobjectArray jcast_helper<jhobjectArray, std::vector<std::string> >::cast(const std::vector<std::string> &s)
140 {
141   JNIEnv *env = xbmc_jnienv();
142   jobjectArray ret = NULL;
143   if (!s.empty())
144   {
145     ret = env->NewObjectArray(s.size(), env->FindClass("java/lang/String"), NULL);
146     for (unsigned int i = 0; i < s.size(); i++)
147     env->SetObjectArrayElement(ret, i, env->NewStringUTF(s[i].c_str()));
148   }
149   return jhobjectArray(ret);
150 }
151 
cast(const jobjectArray & s)152 std::vector<std::string> jcast_helper<std::vector<std::string>, jobjectArray >::cast(const jobjectArray &s)
153 {
154   JNIEnv *env = xbmc_jnienv();
155   std::vector<std::string> ret;
156   jstring element;
157   const char* newString = NULL;
158   if (!s)
159     return ret;
160 
161   unsigned int arraySize = env->GetArrayLength(s);
162   ret.reserve(arraySize);
163   for (unsigned int i = 0; i < arraySize; ++i)
164   {
165     element = (jstring) env->GetObjectArrayElement(s, i);
166     newString = env->GetStringUTFChars(element, JNI_FALSE);
167     if (newString)
168     {
169       ret.push_back(newString);
170       env->ReleaseStringUTFChars(element, newString);
171     }
172     env->DeleteLocalRef(element);
173   }
174   return ret;
175 }
176 
177 #define CRYSTAX_PP_CAT(a, b, c) CRYSTAX_PP_CAT_IMPL(a, b, c)
178 #define CRYSTAX_PP_CAT_IMPL(a, b, c) a ## b ## c
179 
180 #define CRYSTAX_PP_STRINGIZE(a) CRYSTAX_PP_STRINGIZE_IMPL(a)
181 #define CRYSTAX_PP_STRINGIZE_IMPL(a) #a
182 
183 #define JNI_MAP_void Void
184 #define JNI_MAP_jboolean Boolean
185 #define JNI_MAP_jbyte Byte
186 #define JNI_MAP_jchar Char
187 #define JNI_MAP_jshort Short
188 #define JNI_MAP_jint Int
189 #define JNI_MAP_jlong Long
190 #define JNI_MAP_jfloat Float
191 #define JNI_MAP_jdouble Double
192 #define JNI_MAP_jhobject Object
193 #define JNI_MAP_jhclass Object
194 #define JNI_MAP_jhstring Object
195 #define JNI_MAP_jhthrowable Object
196 #define JNI_MAP_jharray Object
197 #define JNI_MAP_jhbooleanArray Object
198 #define JNI_MAP_jhbyteArray Object
199 #define JNI_MAP_jhshortArray Object
200 #define JNI_MAP_jhintArray Object
201 #define JNI_MAP_jhlongArray Object
202 #define JNI_MAP_jhfloatArray Object
203 #define JNI_MAP_jhdoubleArray Object
204 #define JNI_MAP_jhobjectArray Object
205 
206 #define JNI_MAP(type) JNI_MAP_ ## type
207 
208 template <typename T>
209 struct jni_base_type
210 {
211     typedef T type_t;
212 };
213 
214 template <typename T>
215 struct jni_base_type<jholder<T> >
216 {
217     typedef T type_t;
218 };
219 
call_void_method(JNIEnv * env,jobject obj,jmethodID mid,...)220 void call_void_method(JNIEnv *env, jobject obj, jmethodID mid, ...)
221 {
222     va_list vl;
223     va_start(vl, mid);
224     env->CallVoidMethodV(obj, mid, vl);
225     va_end(vl);
226 }
227 
call_void_method(JNIEnv * env,jclass cls,jmethodID mid,...)228 void call_void_method(JNIEnv *env, jclass cls, jmethodID mid, ...)
229 {
230     va_list vl;
231     va_start(vl, mid);
232     env->CallStaticVoidMethodV(cls, mid, vl);
233     va_end(vl);
234 }
235 
new_object(JNIEnv * env,jclass cls,jmethodID mid,...)236 jhobject new_object(JNIEnv *env, jclass cls, jmethodID mid, ...)
237 {
238   va_list vl;
239   va_start(vl,mid);
240   jhobject ret;
241   if (env && cls && mid)
242     ret = jholder<jobject>(env->NewObjectV(cls, mid, vl));
243   va_end(vl);
244   return ret;
245 }
246 
247 template <typename T>
248 struct result_helper
249 {
make_resultjni::details::result_helper250     static T make_result(JNIEnv *env, T obj) {(void)env; return obj;}
251 };
252 
253 template <typename T>
254 struct result_helper<jholder<T> >
255 {
make_resultjni::details::result_helper256     static jholder<T> make_result(JNIEnv *env, T obj) {return jholder<T>(env->ExceptionCheck() ? 0 : obj);}
257 };
258 
259 #define CRYSTAX_PP_STEP(type) \
260     type CRYSTAX_PP_CAT(get_, type, _field)(JNIEnv *env, jobject obj, jfieldID fid) \
261     { \
262         DBG("calling Get" CRYSTAX_PP_STRINGIZE(JNI_MAP(type)) "Field"); \
263         return type((jni_base_type<type>::type_t)CRYSTAX_PP_CAT(env->Get, JNI_MAP(type), Field)(obj, fid)); \
264     } \
265     type CRYSTAX_PP_CAT(get_static_, type, _field)(JNIEnv *env, jclass cls, jfieldID fid) \
266     { \
267         DBG("calling GetStatic" CRYSTAX_PP_STRINGIZE(JNI_MAP(type)) "Field"); \
268         return type((jni_base_type<type>::type_t)CRYSTAX_PP_CAT(env->GetStatic, JNI_MAP(type), Field)(cls, fid)); \
269     } \
270     void CRYSTAX_PP_CAT(set_, type, _field)(JNIEnv *env, jobject obj, jfieldID fid, type const &arg) \
271     { \
272         DBG("calling Set" CRYSTAX_PP_STRINGIZE(JNI_MAP(type)) "Field"); \
273         CRYSTAX_PP_CAT(env->Set, JNI_MAP(type), Field)(obj, fid, (jni_base_type<type>::type_t)raw_arg(arg)); \
274     } \
275     void CRYSTAX_PP_CAT(set_, type, _field)(JNIEnv *env, jclass cls, jfieldID fid, type const &arg) \
276     { \
277         DBG("calling SetStatic" CRYSTAX_PP_STRINGIZE(JNI_MAP(type)) "Field"); \
278         CRYSTAX_PP_CAT(env->SetStatic, JNI_MAP(type), Field)(cls, fid, (jni_base_type<type>::type_t)raw_arg(arg)); \
279     } \
280     type CRYSTAX_PP_CAT(call_, type, _method)(JNIEnv *env, jobject obj, jmethodID mid, ...) \
281     { \
282         DBG("calling Call" CRYSTAX_PP_STRINGIZE(JNI_MAP(type)) "MethodV"); \
283         va_list vl; \
284         va_start(vl, mid); \
285         typedef jni_base_type<type>::type_t result_t; \
286         result_t result = (result_t)CRYSTAX_PP_CAT(env->Call, JNI_MAP(type), MethodV)(obj, mid, vl); \
287         va_end(vl); \
288         return result_helper<type>::make_result(env, result); \
289     } \
290     type CRYSTAX_PP_CAT(call_, type, _method)(JNIEnv *env, jclass cls, jmethodID mid, ...) \
291     { \
292         DBG("calling CallStatic" CRYSTAX_PP_STRINGIZE(JNI_MAP(type)) "MethodV"); \
293         va_list vl; \
294         va_start(vl, mid); \
295         typedef jni_base_type<type>::type_t result_t; \
296         result_t result = (result_t)CRYSTAX_PP_CAT(env->CallStatic, JNI_MAP(type), MethodV)(cls, mid, vl); \
297         va_end(vl); \
298         return result_helper<type>::make_result(env, result); \
299     }
300 #include "jni.inc"
301 #undef CRYSTAX_PP_STEP
302 
303 template <> const char *jni_signature<jboolean>::signature = "Z";
304 template <> const char *jni_signature<jbyte>::signature = "B";
305 template <> const char *jni_signature<jchar>::signature = "C";
306 template <> const char *jni_signature<jshort>::signature = "S";
307 template <> const char *jni_signature<jint>::signature = "I";
308 template <> const char *jni_signature<jlong>::signature = "J";
309 template <> const char *jni_signature<jfloat>::signature = "F";
310 template <> const char *jni_signature<jdouble>::signature = "D";
311 template <> const char *jni_signature<jhobject>::signature = "Ljava/lang/Object;";
312 template <> const char *jni_signature<jhclass>::signature = "Ljava/lang/Class;";
313 template <> const char *jni_signature<jhstring>::signature = "Ljava/lang/String;";
314 template <> const char *jni_signature<jhthrowable>::signature = "Ljava/lang/Throwable;";
315 template <> const char *jni_signature<jhbooleanArray>::signature = "[Z";
316 template <> const char *jni_signature<jhbyteArray>::signature = "[B";
317 template <> const char *jni_signature<jhcharArray>::signature = "[C";
318 template <> const char *jni_signature<jhshortArray>::signature = "[S";
319 template <> const char *jni_signature<jhintArray>::signature = "[I";
320 template <> const char *jni_signature<jhlongArray>::signature = "[J";
321 template <> const char *jni_signature<jhfloatArray>::signature = "[F";
322 template <> const char *jni_signature<jhdoubleArray>::signature = "[D";
323 template <> const char *jni_signature<jhobjectArray>::signature = "[Ljava/lang/Object;";
324 
325 } // namespace details
326 } // namespace jni
327