The open source OpenXR runtime
1#ifdef _WIN32
2# define WIN32_LEAN_AND_MEAN 1
3
4 // Windows Dependencies
5# include <windows.h>
6#else
7 // UNIX Dependencies
8# include <dlfcn.h>
9# include <unistd.h>
10# include <tuple>
11# include <stdlib.h>
12#endif
13
14// External Dependencies
15#include <jni.h>
16
17// Standard Dependencies
18#include <atomic>
19#include <string>
20#include <vector>
21
22// Local Dependencies
23#include "jnipp.h"
24
25namespace jni
26{
27 // Static Variables
28 static std::atomic_bool isVm(false);
29 static JavaVM* javaVm = nullptr;
30
31 static bool getEnv(JavaVM *vm, JNIEnv **env) {
32 return vm->GetEnv((void **)env, JNI_VERSION_1_2) == JNI_OK;
33 }
34
35 static bool isAttached(JavaVM *vm) {
36 JNIEnv *env = nullptr;
37 return getEnv(vm, &env);
38 }
39 /**
40 Maintains the lifecycle of a JNIEnv.
41 */
42 class ScopedEnv final
43 {
44 public:
45 ScopedEnv() noexcept : _vm(nullptr), _env(nullptr), _attached(false) {}
46 ~ScopedEnv();
47
48 // Caution - throws if VM is nullptr!
49 void init(JavaVM* vm);
50 JNIEnv* get() const noexcept { return _env; }
51
52 private:
53 // Instance Variables
54 JavaVM* _vm;
55 JNIEnv* _env;
56 bool _attached; ///< Manually attached, as opposed to already attached.
57 };
58
59 ScopedEnv::~ScopedEnv()
60 {
61 if (_vm && _attached)
62 _vm->DetachCurrentThread();
63 }
64
65 void ScopedEnv::init(JavaVM* vm)
66 {
67 if (_env != nullptr)
68 return;
69
70 if (vm == nullptr)
71 throw InitializationException("JNI not initialized");
72
73 if (!getEnv(vm, &_env))
74 {
75#ifdef __ANDROID__
76 if (vm->AttachCurrentThread(&_env, nullptr) != 0)
77#else
78 if (vm->AttachCurrentThread((void**)&_env, nullptr) != 0)
79#endif
80 throw InitializationException("Could not attach JNI to thread");
81
82 _attached = true;
83 }
84
85 _vm = vm;
86 }
87
88 /*
89 Helper Functions
90 */
91
92#ifdef _WIN32
93
94 static bool fileExists(const std::string& filePath)
95 {
96 DWORD attr = ::GetFileAttributesA(filePath.c_str());
97
98 return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
99 }
100
101#else
102
103 /**
104 Convert from a UTF-16 Java string to a UTF-32 string.
105 */
106 std::wstring toWString(const jchar* str, jsize length)
107 {
108 std::wstring result;
109
110 result.reserve(length);
111
112 for (jsize i = 0; i < length; ++i)
113 {
114 wchar_t ch = str[i];
115
116 // Check for a two-segment character.
117 if (ch >= wchar_t(0xD800) && ch <= wchar_t(0xDBFF)) {
118 if (i + 1 >= length)
119 break;
120
121 // Create a single, 32-bit character.
122 ch = (ch - wchar_t(0xD800)) << 10;
123 ch += str[i++] - wchar_t(0x1DC00);
124 }
125
126 result += ch;
127 }
128
129 return result;
130 }
131
132 /**
133 Convert from a UTF-32 string to a UTF-16 Java string.
134 */
135 std::vector<jchar> toJString(const wchar_t* str, size_t length)
136 {
137 std::vector<jchar> result;
138
139 result.reserve(length * 2); // Worst case scenario.
140
141 for (size_t i = 0; i < length; ++i)
142 {
143 wchar_t ch = str[i];
144
145 // Check for multi-byte UTF-16 character.
146 if (ch > wchar_t(0xFFFF)) {
147 ch -= uint32_t(0x10000);
148
149 // Add the first of the two-segment character.
150 result.push_back(jchar(0xD800 + (ch >> 10)));
151 ch = wchar_t(0xDC00) + (ch & 0x03FF);
152 }
153
154 result.push_back(jchar(ch));
155 }
156
157 return result;
158 }
159
160#endif // _WIN32
161
162 static ScopedEnv &scopedEnvInstance() noexcept
163 {
164 static thread_local ScopedEnv env;
165 return env;
166 }
167
168 // may return nullptr, beware!
169 JNIEnv *env_noexcept() noexcept
170 {
171 ScopedEnv& env = scopedEnvInstance();
172 if (env.get() != nullptr && !isAttached(javaVm))
173 {
174 // we got detached, so clear it.
175 // will be re-populated from static javaVm below.
176 env = ScopedEnv{};
177 }
178
179 if (env.get() == nullptr && javaVm != nullptr)
180 {
181 env.init(javaVm);
182 }
183
184 return env.get();
185 }
186
187 JNIEnv* env()
188 {
189 JNIEnv *ret = env_noexcept();
190 if (ret == nullptr)
191 {
192 throw InitializationException("JNI not initialized");
193 }
194
195 return ret;
196 }
197
198 static jclass findClass(const char* name)
199 {
200 jclass ref = env()->FindClass(name);
201
202 if (ref == nullptr)
203 {
204 env()->ExceptionClear();
205 throw NameResolutionException(name);
206 }
207
208 return ref;
209 }
210
211 static void handleJavaExceptions()
212 {
213 JNIEnv* env = jni::env();
214
215 jthrowable exception = env->ExceptionOccurred();
216
217 if (exception != nullptr)
218 {
219 Object obj(exception, Object::Temporary);
220
221 env->ExceptionClear();
222 std::string msg = obj.call<std::string>("toString");
223 throw InvocationException(msg.c_str());
224 }
225 }
226
227 static std::string toString(jobject handle, bool deleteLocal = true)
228 {
229 std::string result;
230
231 if (handle != nullptr)
232 {
233 JNIEnv* env = jni::env();
234
235 const char* chars = env->GetStringUTFChars(jstring(handle), nullptr);
236 result.assign(chars, env->GetStringUTFLength(jstring(handle)));
237 env->ReleaseStringUTFChars(jstring(handle), chars);
238
239 if (deleteLocal)
240 env->DeleteLocalRef(handle);
241 }
242
243 return result;
244 }
245
246 static std::wstring toWString(jobject handle, bool deleteLocal = true)
247 {
248 std::wstring result;
249
250 if (handle != nullptr)
251 {
252 JNIEnv* env = jni::env();
253
254 const jchar* chars = env->GetStringChars(jstring(handle), nullptr);
255#ifdef _WIN32
256 result.assign((const wchar_t*) chars, env->GetStringLength(jstring(handle)));
257#else
258 result = toWString(chars, env->GetStringLength(jstring(handle)));
259#endif
260 env->ReleaseStringChars(jstring(handle), chars);
261
262 if (deleteLocal)
263 env->DeleteLocalRef(handle);
264 }
265
266 return result;
267 }
268
269
270 /*
271 Stand-alone Function Implementations
272 */
273
274 void init(JNIEnv* env)
275 {
276 bool expected = false;
277
278 if (isVm.compare_exchange_strong(expected, true))
279 {
280 if (javaVm == nullptr && env->GetJavaVM(&javaVm) != 0)
281 throw InitializationException("Could not acquire Java VM");
282 }
283 }
284
285 void init(JavaVM* vm) {
286 bool expected = false;
287
288 if (isVm.compare_exchange_strong(expected, true))
289 {
290 javaVm = vm;
291 }
292 }
293 /*
294 Object Implementation
295 */
296
297 Object::Object() noexcept : _handle(nullptr), _class(nullptr), _isGlobal(false)
298 {
299 }
300
301 Object::Object(const Object& other) : _handle(nullptr), _class(nullptr), _isGlobal(!other.isNull())
302 {
303 if (!other.isNull())
304 _handle = env()->NewGlobalRef(other._handle);
305 }
306
307 Object::Object(Object&& other) noexcept : _handle(other._handle), _class(other._class), _isGlobal(other._isGlobal)
308 {
309 other._handle = nullptr;
310 other._class = nullptr;
311 other._isGlobal = false;
312 }
313
314 Object::Object(jobject ref, int scopeFlags) : _handle(ref), _class(nullptr), _isGlobal((scopeFlags & Temporary) == 0)
315 {
316 if (!_isGlobal)
317 return;
318
319 JNIEnv* env = jni::env();
320
321 _handle = env->NewGlobalRef(ref);
322
323 if (scopeFlags & DeleteLocalInput)
324 env->DeleteLocalRef(ref);
325 }
326
327 Object::~Object() noexcept
328 {
329 JNIEnv* env = jni::env_noexcept();
330 if (env == nullptr)
331 {
332 // Better be empty. Cannot do anything useful.
333 return;
334 }
335
336 if (_isGlobal && _handle != nullptr)
337 env->DeleteGlobalRef(_handle);
338
339 if (_class != nullptr)
340 env->DeleteGlobalRef(_class);
341 }
342
343 Object& Object::operator=(const Object& other)
344 {
345 if (_handle != other._handle)
346 {
347 JNIEnv* env = jni::env();
348
349 // Ditch the old reference.
350 if (_isGlobal)
351 env->DeleteGlobalRef(_handle);
352 if (_class != nullptr)
353 env->DeleteGlobalRef(_class);
354
355 // Assign the new reference.
356 if ((_isGlobal = !other.isNull()) != false)
357 _handle = env->NewGlobalRef(other._handle);
358
359 _class = nullptr;
360 }
361
362 return *this;
363 }
364
365 bool Object::operator==(const Object& other) const
366 {
367 return env()->IsSameObject(_handle, other._handle) != JNI_FALSE;
368 }
369
370 Object& Object::operator=(Object&& other)
371 {
372 if (_handle != other._handle)
373 {
374 JNIEnv* env = jni::env();
375
376 // Ditch the old reference.
377 if (_isGlobal)
378 env->DeleteGlobalRef(_handle);
379 if (_class != nullptr)
380 env->DeleteGlobalRef(_class);
381
382 // Assign the new reference.
383 _handle = other._handle;
384 _isGlobal = other._isGlobal;
385 _class = other._class;
386
387 other._handle = nullptr;
388 other._isGlobal = false;
389 other._class = nullptr;
390 }
391
392 return *this;
393 }
394
395 bool Object::isNull() const noexcept
396 {
397 return _handle == nullptr || env()->IsSameObject(_handle, nullptr);
398 }
399
400 void Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<void> const&) const
401 {
402 env()->CallVoidMethodA(_handle, method, (jvalue*) args);
403 handleJavaExceptions();
404 }
405
406 bool Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<bool> const&) const
407 {
408 auto result = env()->CallBooleanMethodA(_handle, method, (jvalue*) args);
409 handleJavaExceptions();
410 return result != 0;
411 }
412
413 bool Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<bool> const&) const
414 {
415 return env()->GetBooleanField(_handle, field) != 0;
416 }
417
418 template <> void Object::set(field_t field, const bool& value)
419 {
420 env()->SetBooleanField(_handle, field, value);
421 }
422
423 byte_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<byte_t> const&) const
424 {
425 auto result = env()->CallByteMethodA(_handle, method, (jvalue*) args);
426 handleJavaExceptions();
427 return result;
428 }
429
430 wchar_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<wchar_t> const&) const
431 {
432 auto result = env()->CallCharMethodA(_handle, method, (jvalue*) args);
433 handleJavaExceptions();
434 return result;
435 }
436
437 short Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<short> const&) const
438 {
439 auto result = env()->CallShortMethodA(_handle, method, (jvalue*) args);
440 handleJavaExceptions();
441 return result;
442 }
443
444 int Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<int> const&) const
445 {
446 auto result = env()->CallIntMethodA(_handle, method, (jvalue*) args);
447 handleJavaExceptions();
448 return result;
449 }
450
451 long long Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<long long> const&) const
452 {
453 auto result = env()->CallLongMethodA(_handle, method, (jvalue*) args);
454 handleJavaExceptions();
455 return result;
456 }
457
458 float Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<float> const&) const
459 {
460 auto result = env()->CallFloatMethodA(_handle, method, (jvalue*) args);
461 handleJavaExceptions();
462 return result;
463 }
464
465 double Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<double> const&) const
466 {
467 auto result = env()->CallDoubleMethodA(_handle, method, (jvalue*) args);
468 handleJavaExceptions();
469 return result;
470 }
471
472 std::string Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::string> const&) const
473 {
474 auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
475 handleJavaExceptions();
476 return toString(result);
477 }
478
479 std::wstring Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::wstring> const&) const
480 {
481 auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
482 handleJavaExceptions();
483 return toWString(result);
484 }
485
486 jni::Object Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<jni::Object> const&) const
487 {
488 auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
489 handleJavaExceptions();
490 return Object(result, DeleteLocalInput);
491 }
492
493 jarray Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<jarray> const&) const
494 {
495 auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
496 handleJavaExceptions();
497 return (jarray)result;
498 }
499
500 byte_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<byte_t> const&) const
501 {
502 return env()->GetByteField(_handle, field);
503 }
504
505 wchar_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<wchar_t> const&) const
506 {
507 return env()->GetCharField(_handle, field);
508 }
509
510 short Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<short> const&) const
511 {
512 return env()->GetShortField(_handle, field);
513 }
514
515 int Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<int> const&) const
516 {
517 return env()->GetIntField(_handle, field);
518 }
519
520 long long Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<long long> const&) const
521 {
522 return env()->GetLongField(_handle, field);
523 }
524
525 float Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<float> const&) const
526 {
527 return env()->GetFloatField(_handle, field);
528 }
529
530 double Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<double> const&) const
531 {
532 return env()->GetDoubleField(_handle, field);
533 }
534
535 std::string Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<std::string> const&) const
536 {
537 return toString(env()->GetObjectField(_handle, field));
538 }
539
540 std::wstring Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<std::wstring> const&) const
541 {
542 return toWString(env()->GetObjectField(_handle, field));
543 }
544
545 Object Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<Object> const&) const
546 {
547 return Object(env()->GetObjectField(_handle, field), DeleteLocalInput);
548 }
549
550 template <> void Object::set(field_t field, const byte_t& value)
551 {
552 env()->SetByteField(_handle, field, value);
553 }
554
555 template <> void Object::set(field_t field, const wchar_t& value)
556 {
557 env()->SetCharField(_handle, field, value);
558 }
559
560 template <> void Object::set(field_t field, const short& value)
561 {
562 env()->SetShortField(_handle, field, value);
563 }
564
565 template <> void Object::set(field_t field, const int& value)
566 {
567 env()->SetIntField(_handle, field, value);
568 }
569
570 template <> void Object::set(field_t field, const long long& value)
571 {
572 env()->SetLongField(_handle, field, value);
573 }
574
575 template <> void Object::set(field_t field, const float& value)
576 {
577 env()->SetFloatField(_handle, field, value);
578 }
579
580 template <> void Object::set(field_t field, const double& value)
581 {
582 env()->SetDoubleField(_handle, field, value);
583 }
584
585 template <> void Object::set(field_t field, const std::string& value)
586 {
587 JNIEnv* env = jni::env();
588
589 jobject handle = env->NewStringUTF(value.c_str());
590 env->SetObjectField(_handle, field, handle);
591 env->DeleteLocalRef(handle);
592 }
593
594 template <> void Object::set(field_t field, const std::wstring& value)
595 {
596 JNIEnv* env = jni::env();
597
598#ifdef _WIN32
599 jobject handle = env->NewString((const jchar*) value.c_str(), jsize(value.length()));
600#else
601 auto jstr = toJString(value.c_str(), value.length());
602 jobject handle = env->NewString(jstr.data(), jsize(jstr.size()));
603#endif
604 env->SetObjectField(_handle, field, handle);
605 env->DeleteLocalRef(handle);
606 }
607
608 template <> void Object::set(field_t field, const wchar_t* const& value)
609 {
610 JNIEnv* env = jni::env();
611#ifdef _WIN32
612 jobject handle = env->NewString((const jchar*) value, jsize(std::wcslen(value)));
613#else
614 auto jstr = toJString(value, std::wcslen(value));
615 jobject handle = env->NewString(jstr.data(), jsize(jstr.size()));
616#endif
617 env->SetObjectField(_handle, field, handle);
618 env->DeleteLocalRef(handle);
619 }
620
621 template <> void Object::set(field_t field, const char* const& value)
622 {
623 JNIEnv* env = jni::env();
624
625 jobject handle = env->NewStringUTF(value);
626 env->SetObjectField(_handle, field, handle);
627 env->DeleteLocalRef(handle);
628 }
629
630 template <> void Object::set(field_t field, const Object& value)
631 {
632 env()->SetObjectField(_handle, field, value.getHandle());
633 }
634
635 template <> void Object::set(field_t field, const Object* const& value)
636 {
637 env()->SetObjectField(_handle, field, value ? value->getHandle() : nullptr);
638 }
639
640 jclass Object::getClass() const
641 {
642 if (_class == nullptr)
643 {
644 JNIEnv* env = jni::env();
645
646 jclass classRef = env->GetObjectClass(_handle);
647 _class = jclass(env->NewGlobalRef(classRef));
648 env->DeleteLocalRef(classRef);
649 }
650
651 return _class;
652 }
653
654 method_t Object::getMethod(const char* name, const char* signature) const
655 {
656 return Class(getClass(), Temporary).getMethod(name, signature);
657 }
658
659 method_t Object::getMethod(const char* nameAndSignature) const
660 {
661 return Class(getClass(), Temporary).getMethod(nameAndSignature);
662 }
663
664 field_t Object::getField(const char* name, const char* signature) const
665 {
666 return Class(getClass(), Temporary).getField(name, signature);
667 }
668
669 jobject Object::makeLocalReference() const
670 {
671 if (isNull())
672 return nullptr;
673 return env()->NewLocalRef(_handle);
674 }
675
676 /*
677 Class Implementation
678 */
679
680 Class::Class(const char* name) : Object(findClass(name), DeleteLocalInput)
681 {
682 }
683
684 Class::Class(jclass ref, int scopeFlags) : Object(ref, scopeFlags)
685 {
686 }
687
688 Object Class::newInstance() const
689 {
690 method_t constructor = getMethod("<init>", "()V");
691 jobject obj = env()->NewObject(getHandle(), constructor);
692
693 handleJavaExceptions();
694
695 return Object(obj, Object::DeleteLocalInput);
696 }
697
698 field_t Class::getField(const char* name, const char* signature) const
699 {
700 jfieldID id = env()->GetFieldID(getHandle(), name, signature);
701
702 if (id == nullptr)
703 throw NameResolutionException(name);
704
705 return id;
706 }
707
708 field_t Class::getStaticField(const char* name, const char* signature) const
709 {
710 jfieldID id = env()->GetStaticFieldID(getHandle(), name, signature);
711
712 if (id == nullptr)
713 throw NameResolutionException(name);
714
715 return id;
716 }
717
718 method_t Class::getMethod(const char* name, const char* signature) const
719 {
720 jmethodID id = env()->GetMethodID(getHandle(), name, signature);
721
722 if (id == nullptr)
723 throw NameResolutionException(name);
724
725 return id;
726 }
727
728
729 method_t Class::getMethod(const char* nameAndSignature) const
730 {
731 jmethodID id = nullptr;
732 const char* sig = std::strchr(nameAndSignature, '(');
733
734 if (sig != nullptr)
735 return getMethod(std::string(nameAndSignature, sig - nameAndSignature).c_str(), sig);
736
737 if (id == nullptr)
738 throw NameResolutionException(nameAndSignature);
739
740 return id;
741 }
742
743 method_t Class::getStaticMethod(const char* name, const char* signature) const
744 {
745 jmethodID id = env()->GetStaticMethodID(getHandle(), name, signature);
746
747 if (id == nullptr)
748 throw NameResolutionException(name);
749
750 return id;
751 }
752
753 method_t Class::getStaticMethod(const char* nameAndSignature) const
754 {
755 jmethodID id = nullptr;
756 const char* sig = std::strchr(nameAndSignature, '(');
757
758 if (sig != nullptr)
759 return getStaticMethod(std::string(nameAndSignature, sig - nameAndSignature).c_str(), sig);
760
761 if (id == nullptr)
762 throw NameResolutionException(nameAndSignature);
763
764 return id;
765 }
766
767 Class Class::getParent() const
768 {
769 return Class(env()->GetSuperclass(getHandle()), DeleteLocalInput);
770 }
771
772 std::string Class::getName() const
773 {
774 return Object::call<std::string>("getName");
775 }
776
777 template <> bool Class::get(field_t field) const
778 {
779 return env()->GetStaticBooleanField(getHandle(), field) != 0;
780 }
781
782 template <> byte_t Class::get(field_t field) const
783 {
784 return env()->GetStaticByteField(getHandle(), field);
785 }
786
787 template <> wchar_t Class::get(field_t field) const
788 {
789 return env()->GetStaticCharField(getHandle(), field);
790 }
791
792 template <> short Class::get(field_t field) const
793 {
794 return env()->GetStaticShortField(getHandle(), field);
795 }
796
797 template <> int Class::get(field_t field) const
798 {
799 return env()->GetStaticIntField(getHandle(), field);
800 }
801
802 template <> long long Class::get(field_t field) const
803 {
804 return env()->GetStaticLongField(getHandle(), field);
805 }
806
807 template <> float Class::get(field_t field) const
808 {
809 return env()->GetStaticFloatField(getHandle(), field);
810 }
811
812 template <> double Class::get(field_t field) const
813 {
814 return env()->GetStaticDoubleField(getHandle(), field);
815 }
816
817 template <> std::string Class::get(field_t field) const
818 {
819 return toString(env()->GetStaticObjectField(getHandle(), field));
820 }
821
822 template <> std::wstring Class::get(field_t field) const
823 {
824 return toWString(env()->GetStaticObjectField(getHandle(), field));
825 }
826
827 template <> Object Class::get(field_t field) const
828 {
829 return Object(env()->GetStaticObjectField(getHandle(), field), DeleteLocalInput);
830 }
831
832 template <> void Class::set(field_t field, const bool& value)
833 {
834 env()->SetStaticBooleanField(getHandle(), field, value);
835 }
836
837 template <> void Class::set(field_t field, const byte_t& value)
838 {
839 env()->SetStaticByteField(getHandle(), field, value);
840 }
841
842 template <> void Class::set(field_t field, const wchar_t& value)
843 {
844 env()->SetStaticCharField(getHandle(), field, value);
845 }
846
847 template <> void Class::set(field_t field, const short& value)
848 {
849 env()->SetStaticShortField(getHandle(), field, value);
850 }
851
852 template <> void Class::set(field_t field, const int& value)
853 {
854 env()->SetStaticIntField(getHandle(), field, value);
855 }
856
857 template <> void Class::set(field_t field, const long long& value)
858 {
859 env()->SetStaticLongField(getHandle(), field, value);
860 }
861
862 template <> void Class::set(field_t field, const float& value)
863 {
864 env()->SetStaticFloatField(getHandle(), field, value);
865 }
866
867 template <> void Class::set(field_t field, const double& value)
868 {
869 env()->SetStaticDoubleField(getHandle(), field, value);
870 }
871
872 template <> void Class::set(field_t field, const Object& value)
873 {
874 env()->SetStaticObjectField(getHandle(), field, value.getHandle());
875 }
876
877 template <> void Class::set(field_t field, const Object* const& value)
878 {
879 env()->SetStaticObjectField(getHandle(), field, value ? value->getHandle() : nullptr);
880 }
881
882 template <> void Class::set(field_t field, const std::string& value)
883 {
884 JNIEnv* env = jni::env();
885
886 jobject handle = env->NewStringUTF(value.c_str());
887 env->SetStaticObjectField(getHandle(), field, handle);
888 env->DeleteLocalRef(handle);
889 }
890
891 template <> void Class::set(field_t field, const std::wstring& value)
892 {
893 JNIEnv* env = jni::env();
894
895#ifdef _WIN32
896 jobject handle = env->NewString((const jchar*) value.c_str(), jsize(value.length()));
897#else
898 auto jstr = toJString(value.c_str(), value.length());
899 jobject handle = env->NewString(jstr.data(), jsize(jstr.size()));
900#endif
901 env->SetStaticObjectField(getHandle(), field, handle);
902 env->DeleteLocalRef(handle);
903 }
904
905 template <> void Class::callStaticMethod(method_t method, internal::value_t* args) const
906 {
907 env()->CallStaticVoidMethodA(getHandle(), method, (jvalue*) args);
908 handleJavaExceptions();
909 }
910
911 template <> bool Class::callStaticMethod(method_t method, internal::value_t* args) const
912 {
913 auto result = env()->CallStaticBooleanMethodA(getHandle(), method, (jvalue*) args);
914 handleJavaExceptions();
915 return result != 0;
916 }
917
918 template <> byte_t Class::callStaticMethod(method_t method, internal::value_t* args) const
919 {
920 auto result = env()->CallStaticByteMethodA(getHandle(), method, (jvalue*) args);
921 handleJavaExceptions();
922 return result;
923 }
924
925 template <> wchar_t Class::callStaticMethod(method_t method, internal::value_t* args) const
926 {
927 auto result = env()->CallStaticCharMethodA(getHandle(), method, (jvalue*) args);
928 handleJavaExceptions();
929 return result;
930 }
931
932 template <> short Class::callStaticMethod(method_t method, internal::value_t* args) const
933 {
934 auto result = env()->CallStaticShortMethodA(getHandle(), method, (jvalue*) args);
935 handleJavaExceptions();
936 return result;
937 }
938
939 template <> int Class::callStaticMethod(method_t method, internal::value_t* args) const
940 {
941 auto result = env()->CallStaticIntMethodA(getHandle(), method, (jvalue*) args);
942 handleJavaExceptions();
943 return result;
944 }
945
946 template <> long long Class::callStaticMethod(method_t method, internal::value_t* args) const
947 {
948 auto result = env()->CallStaticLongMethodA(getHandle(), method, (jvalue*) args);
949 handleJavaExceptions();
950 return result;
951 }
952
953 template <> float Class::callStaticMethod(method_t method, internal::value_t* args) const
954 {
955 auto result = env()->CallStaticFloatMethodA(getHandle(), method, (jvalue*) args);
956 handleJavaExceptions();
957 return result;
958 }
959
960 template <> double Class::callStaticMethod(method_t method, internal::value_t* args) const
961 {
962 auto result = env()->CallStaticDoubleMethodA(getHandle(), method, (jvalue*) args);
963 handleJavaExceptions();
964 return result;
965 }
966
967 template <> std::string Class::callStaticMethod(method_t method, internal::value_t* args) const
968 {
969 auto result = env()->CallStaticObjectMethodA(getHandle(), method, (jvalue*) args);
970 handleJavaExceptions();
971 return toString(result);
972 }
973
974 template <> std::wstring Class::callStaticMethod(method_t method, internal::value_t* args) const
975 {
976 auto result = env()->CallStaticObjectMethodA(getHandle(), method, (jvalue*) args);
977 handleJavaExceptions();
978 return toWString(result);
979 }
980
981 template <> jni::Object Class::callStaticMethod(method_t method, internal::value_t* args) const
982 {
983 auto result = env()->CallStaticObjectMethodA(getHandle(), method, (jvalue*) args);
984 handleJavaExceptions();
985 return Object(result, DeleteLocalInput);
986 }
987
988 template <> void Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
989 {
990 env()->CallNonvirtualVoidMethodA(obj, getHandle(), method, (jvalue*) args);
991 handleJavaExceptions();
992 }
993
994 template <> bool Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
995 {
996 auto result = env()->CallNonvirtualBooleanMethodA(obj, getHandle(), method, (jvalue*) args);
997 handleJavaExceptions();
998 return result != 0;
999 }
1000
1001 template <> byte_t Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1002 {
1003 auto result = env()->CallNonvirtualByteMethodA(obj, getHandle(), method, (jvalue*) args);
1004 handleJavaExceptions();
1005 return result;
1006 }
1007
1008 template <> wchar_t Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1009 {
1010 auto result = env()->CallNonvirtualCharMethodA(obj, getHandle(), method, (jvalue*) args);
1011 handleJavaExceptions();
1012 return result;
1013 }
1014
1015 template <> short Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1016 {
1017 auto result = env()->CallNonvirtualShortMethodA(obj, getHandle(), method, (jvalue*) args);
1018 handleJavaExceptions();
1019 return result;
1020 }
1021
1022 template <> int Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1023 {
1024 auto result = env()->CallNonvirtualIntMethodA(obj, getHandle(), method, (jvalue*) args);
1025 handleJavaExceptions();
1026 return result;
1027 }
1028
1029 template <> long long Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1030 {
1031 auto result = env()->CallNonvirtualLongMethodA(obj, getHandle(), method, (jvalue*) args);
1032 handleJavaExceptions();
1033 return result;
1034 }
1035
1036 template <> float Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1037 {
1038 auto result = env()->CallNonvirtualFloatMethodA(obj, getHandle(), method, (jvalue*) args);
1039 handleJavaExceptions();
1040 return result;
1041 }
1042
1043 template <> double Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1044 {
1045 auto result = env()->CallNonvirtualDoubleMethodA(obj, getHandle(), method, (jvalue*) args);
1046 handleJavaExceptions();
1047 return result;
1048 }
1049
1050 template <> std::string Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1051 {
1052 auto result = env()->CallNonvirtualObjectMethodA(obj, getHandle(), method, (jvalue*)args);
1053 handleJavaExceptions();
1054 return toString(result);
1055 }
1056
1057 template <> std::wstring Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1058 {
1059 auto result = env()->CallNonvirtualObjectMethodA(obj, getHandle(), method, (jvalue*)args);
1060 handleJavaExceptions();
1061 return toWString(result);
1062 }
1063
1064 template <> Object Class::callExactMethod(jobject obj, method_t method, internal::value_t* args) const
1065 {
1066 auto result = env()->CallNonvirtualObjectMethodA(obj, getHandle(), method, (jvalue*)args);
1067 handleJavaExceptions();
1068 return Object(result, DeleteLocalInput);
1069 }
1070
1071 Object Class::newObject(method_t constructor, internal::value_t* args) const
1072 {
1073 jobject ref = env()->NewObjectA(getHandle(), constructor, (jvalue*)args);
1074 handleJavaExceptions();
1075 return Object(ref, DeleteLocalInput);
1076 }
1077
1078 /*
1079 Enum Implementation
1080 */
1081
1082 Enum::Enum(const char* name) : Class(name)
1083 {
1084 _name = "L";
1085 _name += name;
1086 _name += ";";
1087 }
1088
1089 Object Enum::get(const char* name) const
1090 {
1091 return Class::get<Object>(getStaticField(name, _name.c_str()));
1092 }
1093
1094 /*
1095 Array Implementation
1096 */
1097
1098 template <> Array<bool>::Array(long length) : Object(env()->NewBooleanArray(length)), _length(length)
1099 {
1100 }
1101
1102 template <> Array<byte_t>::Array(long length) : Object(env()->NewByteArray(length)), _length(length)
1103 {
1104 }
1105
1106 template <> Array<wchar_t>::Array(long length) : Object(env()->NewCharArray(length)), _length(length)
1107 {
1108 }
1109
1110 template <> Array<short>::Array(long length) : Object(env()->NewShortArray(length)), _length(length)
1111 {
1112 }
1113
1114 template <> Array<int>::Array(long length) : Object(env()->NewIntArray(length)), _length(length)
1115 {
1116 }
1117
1118 template <> Array<long long>::Array(long length) : Object(env()->NewLongArray(length)), _length(length)
1119 {
1120 }
1121
1122 template <> Array<float>::Array(long length) : Object(env()->NewFloatArray(length)), _length(length)
1123 {
1124 }
1125
1126 template <> Array<double>::Array(long length) : Object(env()->NewDoubleArray(length)), _length(length)
1127 {
1128 }
1129
1130 template <> Array<std::string>::Array(long length) : Object(env()->NewObjectArray(length, Class("java/lang/String").getHandle(), nullptr)), _length(length)
1131 {
1132 }
1133
1134 template <> Array<std::wstring>::Array(long length) : Object(env()->NewObjectArray(length, Class("java/lang/String").getHandle(), nullptr)), _length(length)
1135 {
1136 }
1137
1138 template <> Array<Object>::Array(long length) : Object(env()->NewObjectArray(length, Class("java/lang/Object").getHandle(), nullptr)), _length(length)
1139 {
1140 }
1141
1142 template <> Array<Object>::Array(long length, const Class& type) : Object(env()->NewObjectArray(length, type.getHandle(), nullptr)), _length(length)
1143 {
1144 }
1145
1146 template <> bool Array<bool>::getElement(long index) const
1147 {
1148 jboolean output;
1149 env()->GetBooleanArrayRegion(jbooleanArray(getHandle()), index, 1, &output);
1150 handleJavaExceptions();
1151 return output;
1152 }
1153
1154 template <> byte_t Array<byte_t>::getElement(long index) const
1155 {
1156 jbyte output;
1157 env()->GetByteArrayRegion(jbyteArray(getHandle()), index, 1, &output);
1158 handleJavaExceptions();
1159 return output;
1160 }
1161
1162 template <> wchar_t Array<wchar_t>::getElement(long index) const
1163 {
1164 jchar output;
1165 env()->GetCharArrayRegion(jcharArray(getHandle()), index, 1, &output);
1166 handleJavaExceptions();
1167 return output;
1168 }
1169
1170 template <> short Array<short>::getElement(long index) const
1171 {
1172 jshort output;
1173 env()->GetShortArrayRegion(jshortArray(getHandle()), index, 1, &output);
1174 handleJavaExceptions();
1175 return output;
1176 }
1177
1178 template <> int Array<int>::getElement(long index) const
1179 {
1180 jint output;
1181 env()->GetIntArrayRegion(jintArray(getHandle()), index, 1, &output);
1182 handleJavaExceptions();
1183 return output;
1184 }
1185
1186 template <> long long Array<long long>::getElement(long index) const
1187 {
1188 jlong output;
1189 env()->GetLongArrayRegion(jlongArray(getHandle()), index, 1, &output);
1190 handleJavaExceptions();
1191 return output;
1192 }
1193
1194 template <> float Array<float>::getElement(long index) const
1195 {
1196 jfloat output;
1197 env()->GetFloatArrayRegion(jfloatArray(getHandle()), index, 1, &output);
1198 handleJavaExceptions();
1199 return output;
1200 }
1201
1202 template <> double Array<double>::getElement(long index) const
1203 {
1204 jdouble output;
1205 env()->GetDoubleArrayRegion(jdoubleArray(getHandle()), index, 1, &output);
1206 handleJavaExceptions();
1207 return output;
1208 }
1209
1210 template <> std::string Array<std::string>::getElement(long index) const
1211 {
1212 jobject output = env()->GetObjectArrayElement(jobjectArray(getHandle()), index);
1213 handleJavaExceptions();
1214 return toString(output);
1215 }
1216
1217 template <> std::wstring Array<std::wstring>::getElement(long index) const
1218 {
1219 jobject output = env()->GetObjectArrayElement(jobjectArray(getHandle()), index);
1220 handleJavaExceptions();
1221 return toWString(output);
1222 }
1223
1224 template <> Object Array<Object>::getElement(long index) const
1225 {
1226 jobject output = env()->GetObjectArrayElement(jobjectArray(getHandle()), index);
1227 handleJavaExceptions();
1228 return Object(output, DeleteLocalInput);
1229 }
1230
1231 template <> void Array<bool>::setElement(long index, bool value)
1232 {
1233 jboolean jvalue = value;
1234 env()->SetBooleanArrayRegion(jbooleanArray(getHandle()), index, 1, &jvalue);
1235 handleJavaExceptions();
1236 }
1237
1238 template <> void Array<byte_t>::setElement(long index, byte_t value)
1239 {
1240 jbyte jvalue = value;
1241 env()->SetByteArrayRegion(jbyteArray(getHandle()), index, 1, &jvalue);
1242 handleJavaExceptions();
1243 }
1244
1245 template <> void Array<wchar_t>::setElement(long index, wchar_t value)
1246 {
1247 jchar jvalue = value;
1248 env()->SetCharArrayRegion(jcharArray(getHandle()), index, 1, &jvalue);
1249 handleJavaExceptions();
1250 }
1251
1252 template <> void Array<short>::setElement(long index, short value)
1253 {
1254 jshort jvalue = value;
1255 env()->SetShortArrayRegion(jshortArray(getHandle()), index, 1, &jvalue);
1256 handleJavaExceptions();
1257 }
1258
1259 template <> void Array<int>::setElement(long index, int value)
1260 {
1261 jint jvalue = value;
1262 env()->SetIntArrayRegion(jintArray(getHandle()), index, 1, &jvalue);
1263 handleJavaExceptions();
1264 }
1265
1266 template <> void Array<long long>::setElement(long index, long long value)
1267 {
1268 jlong jvalue = value;
1269 env()->SetLongArrayRegion(jlongArray(getHandle()), index, 1, &jvalue);
1270 handleJavaExceptions();
1271 }
1272
1273 template <> void Array<float>::setElement(long index, float value)
1274 {
1275 jfloat jvalue = value;
1276 env()->SetFloatArrayRegion(jfloatArray(getHandle()), index, 1, &jvalue);
1277 handleJavaExceptions();
1278 }
1279
1280 template <> void Array<double>::setElement(long index, double value)
1281 {
1282 jdouble jvalue = value;
1283 env()->SetDoubleArrayRegion(jdoubleArray(getHandle()), index, 1, &jvalue);
1284 handleJavaExceptions();
1285 }
1286
1287 template <> void Array<std::string>::setElement(long index, std::string value)
1288 {
1289 JNIEnv* env = jni::env();
1290
1291 jobject jvalue = env->NewStringUTF(value.c_str());;
1292 env->SetObjectArrayElement(jobjectArray(getHandle()), index, jvalue);
1293 env->DeleteLocalRef(jvalue);
1294 handleJavaExceptions();
1295 }
1296
1297 template <> void Array<std::wstring>::setElement(long index, std::wstring value)
1298 {
1299 JNIEnv* env = jni::env();
1300
1301#ifdef _WIN32
1302 jobject jvalue = env->NewString((const jchar*) value.c_str(), jsize(value.length()));
1303#else
1304 auto jstr = toJString(value.c_str(), value.length());
1305 jobject jvalue = env->NewString(jstr.data(), jsize(jstr.size()));
1306#endif
1307 env->SetObjectArrayElement(jobjectArray(getHandle()), index, jvalue);
1308 env->DeleteLocalRef(jvalue);
1309 handleJavaExceptions();
1310 }
1311
1312 template <> void Array<Object>::setElement(long index, Object value)
1313 {
1314 env()->SetObjectArrayElement(jobjectArray(getHandle()), index, value.getHandle());
1315 handleJavaExceptions();
1316 }
1317
1318 /*
1319 Vm Implementation
1320 */
1321
1322 typedef jint (JNICALL *CreateVm_t)(JavaVM**, void**, void*);
1323
1324#ifndef _WIN32
1325 static bool fileExists(const std::string& filePath)
1326 {
1327 return access(filePath.c_str(), F_OK) != -1;
1328 }
1329
1330 template <size_t N>
1331 static ssize_t readlink_safe(const char *pathname, char (&output)[N]) {
1332 auto len = readlink(pathname, output, N - 1);
1333 if (len > 0) {
1334 output[len] = '\0';
1335 }
1336 return len;
1337 }
1338
1339 static std::pair<ssize_t, std::string>
1340 readlink_as_string(const char *pathname) {
1341 char buf[2048] = {};
1342 auto len = readlink_safe(pathname, buf);
1343 if (len <= 0) {
1344 return {len, {}};
1345 }
1346 return {len, std::string{buf, static_cast<size_t>(len)}};
1347 }
1348 static std::string readlink_deep(const char *pathname) {
1349 std::string prev{pathname};
1350 ssize_t len = 0;
1351 std::string next;
1352 while (true) {
1353 std::tie(len, next) = readlink_as_string(prev.c_str());
1354 if (!next.empty()) {
1355 prev = next;
1356 } else {
1357 return prev;
1358 }
1359 }
1360 }
1361
1362 static std::string drop_path_components(const std::string & path, size_t num_components) {
1363 size_t pos = std::string::npos;
1364 size_t slash_pos = std::string::npos;
1365 for (size_t i = 0; i < num_components; ++i) {
1366 slash_pos = path.find_last_of('/', pos);
1367 if (slash_pos == std::string::npos || slash_pos == 0) {
1368 return {};
1369 }
1370 pos = slash_pos - 1;
1371 }
1372 return std::string{path.c_str(), slash_pos};
1373 }
1374#endif
1375 static std::string detectJvmPath()
1376 {
1377 std::string result;
1378
1379#ifdef _WIN32
1380
1381 BYTE buffer[1024];
1382 DWORD size = sizeof(buffer);
1383 HKEY versionKey;
1384
1385 // Search via registry entries.
1386 if (::RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\JavaSoft\\Java Runtime Environment\\", &versionKey) == ERROR_SUCCESS)
1387 {
1388 if (::RegQueryValueEx(versionKey, "CurrentVersion", NULL, NULL, buffer, &size) == ERROR_SUCCESS)
1389 {
1390 HKEY libKey;
1391
1392 std::string keyName = std::string("Software\\JavaSoft\\Java Runtime Environment\\") + (const char*)buffer;
1393
1394 ::RegCloseKey(versionKey);
1395
1396 if (::RegOpenKeyA(HKEY_LOCAL_MACHINE, keyName.c_str(), &libKey) == ERROR_SUCCESS)
1397 {
1398 size = sizeof(buffer);
1399
1400 if (::RegQueryValueEx(libKey, "RuntimeLib", NULL, NULL, buffer, &size) == ERROR_SUCCESS)
1401 {
1402 result = (const char*)buffer;
1403 }
1404
1405 ::RegCloseKey(libKey);
1406 }
1407 }
1408 }
1409
1410 if (result.length() == 0)
1411 {
1412 // Could not locate via registry. Try the JAVA_HOME environment variable.
1413 if ((size = ::GetEnvironmentVariableA("JAVA_HOME", (LPSTR) buffer, sizeof(buffer))) != 0)
1414 {
1415 std::string javaHome((const char*) buffer, size);
1416
1417 // Different installers put in different relative locations.
1418 std::string options[] = {
1419 javaHome + "\\jre\\bin\\client\\jvm.dll",
1420 javaHome + "\\jre\\bin\\server\\jvm.dll",
1421 javaHome + "\\bin\\client\\jvm.dll",
1422 javaHome + "\\bin\\server\\jvm.dll"
1423 };
1424
1425 for (auto const& i : options)
1426 if (fileExists(i))
1427 return i;
1428 }
1429 }
1430
1431#else
1432
1433 const char* javaHome = getenv("JAVA_HOME");
1434 if (javaHome != nullptr) {
1435 #ifdef __APPLE__
1436 std::string libJvmPath = std::string(javaHome) + "/jre/lib/server/libjvm.dylib";
1437 #else
1438 std::string libJvmPath = std::string(javaHome) + "/jre/lib/amd64/server/libjvm.so";
1439 #endif
1440 result = libJvmPath;
1441 } else {
1442 std::string path = readlink_deep("/usr/bin/java");
1443 if (!path.empty()) {
1444 // drop bin and java
1445 auto javaHome = drop_path_components(path, 2);
1446 if (!javaHome.empty()) {
1447 std::string options[] = {
1448 javaHome + "/jre/lib/amd64/server/libjvm.so",
1449 javaHome + "/jre/lib/amd64/client/libjvm.so",
1450 javaHome + "/jre/lib/server/libjvm.so",
1451 javaHome + "/jre/lib/client/libjvm.so",
1452 javaHome + "/lib/server/libjvm.so",
1453 javaHome + "/lib/client/libjvm.so",
1454 };
1455
1456 for (auto const &i : options) {
1457 fprintf(stderr, "trying %s\n", i.c_str());
1458 if (fileExists(i)) {
1459 return i;
1460 }
1461 }
1462 }
1463 }
1464 // Best guess so far.
1465 result = "/usr/lib/jvm/default-java/jre/lib/amd64/server/libjvm.so";
1466 }
1467
1468#endif // _WIN32
1469
1470 return result;
1471 }
1472
1473 Vm::Vm(const char* path_)
1474 {
1475 bool expected = false;
1476
1477 std::string path = path_ ? path_ : detectJvmPath();
1478
1479 if (path.length() == 0)
1480 throw InitializationException("Could not locate Java Virtual Machine");
1481 if (!isVm.compare_exchange_strong(expected, true))
1482 throw InitializationException("Java Virtual Machine already initialized");
1483
1484 if (javaVm == nullptr)
1485 {
1486 JNIEnv* env;
1487 JavaVMInitArgs args = {};
1488 args.version = JNI_VERSION_1_2;
1489
1490#ifdef _WIN32
1491
1492 HMODULE lib = ::LoadLibraryA(path.c_str());
1493
1494 if (lib == NULL)
1495 {
1496 isVm.store(false);
1497 throw InitializationException("Could not load JVM library");
1498 }
1499
1500 CreateVm_t JNI_CreateJavaVM = (CreateVm_t) ::GetProcAddress(lib, "JNI_CreateJavaVM");
1501
1502 /**
1503 Is your debugger catching an error here? This is normal. Just continue. The JVM
1504 intentionally does this to test how the OS handles memory-reference exceptions.
1505 */
1506 if (JNI_CreateJavaVM == NULL || JNI_CreateJavaVM(&javaVm, (void**) &env, &args) != 0)
1507 {
1508 isVm.store(false);
1509 ::FreeLibrary(lib);
1510 throw InitializationException("Java Virtual Machine failed during creation");
1511 }
1512
1513#else
1514
1515 void* lib = ::dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL);
1516
1517 if (lib == NULL)
1518 {
1519 isVm.store(false);
1520 throw InitializationException("Could not load JVM library");
1521 }
1522
1523 CreateVm_t JNI_CreateJavaVM = (CreateVm_t) ::dlsym(lib, "JNI_CreateJavaVM");
1524
1525 if (JNI_CreateJavaVM == NULL || JNI_CreateJavaVM(&javaVm, (void**) &env, &args) != 0)
1526 {
1527 isVm.store(false);
1528 ::dlclose(lib);
1529 throw InitializationException("Java Virtual Machine failed during creation");
1530 }
1531
1532#endif // _WIN32
1533 }
1534 }
1535
1536 Vm::~Vm()
1537 {
1538 /*
1539 Note that you can't ever *really* unload the JavaVM. If you call
1540 DestroyJavaVM(), you can't then call JNI_CreateJavaVM() again.
1541 So, instead we just flag it as "gone".
1542 */
1543 isVm.store(false);
1544 }
1545
1546 // Forward Declarations
1547 JNIEnv* env();
1548
1549#ifndef _WIN32
1550 extern std::vector<jchar> toJString(const wchar_t* str, size_t length);
1551#endif
1552
1553 namespace internal
1554 {
1555 // Base Type Conversions
1556 void valueArg(value_t* v, bool a) { ((jvalue*) v)->z = jboolean(a); }
1557 void valueArg(value_t* v, byte_t a) { ((jvalue*) v)->b = a; }
1558 void valueArg(value_t* v, wchar_t a) { ((jvalue*) v)->c = jchar(a); } // Note: Possible truncation.
1559 void valueArg(value_t* v, short a) { ((jvalue*) v)->s = a; }
1560 void valueArg(value_t* v, int a) { ((jvalue*) v)->i = a; }
1561 void valueArg(value_t* v, long long a) { ((jvalue*) v)->j = a; }
1562 void valueArg(value_t* v, float a) { ((jvalue*) v)->f = a; }
1563 void valueArg(value_t* v, double a) { ((jvalue*) v)->d = a; }
1564 void valueArg(value_t* v, jobject a) { ((jvalue*) v)->l = a; }
1565 void valueArg(value_t* v, const Object& a) { ((jvalue*) v)->l = a.getHandle(); }
1566 void valueArg(value_t* v, const Object* const& a) { ((jvalue*) v)->l = a ? a->getHandle() : nullptr; }
1567
1568 /*
1569 Object Implementations
1570 */
1571
1572 std::string valueSig(const Object* obj)
1573 {
1574 if (obj == nullptr || obj->isNull())
1575 return "Ljava/lang/Object;"; // One can always hope...
1576
1577 std::string name = Class(obj->getClass(), Object::Temporary).getName();
1578
1579 // Change from "java.lang.Object" format to "java/lang/Object";
1580 for (size_t i = 0; i < name.length(); ++i)
1581 if (name[i] == '.')
1582 name[i] = '/';
1583
1584 return "L" + name + ";";
1585 }
1586
1587 /*
1588 String Implementations
1589 */
1590
1591 void valueArg(value_t* v, const std::string& a)
1592 {
1593 ((jvalue*) v)->l = env()->NewStringUTF(a.c_str());
1594 }
1595
1596 template <> void cleanupArg<std::string>(value_t* v)
1597 {
1598 env()->DeleteLocalRef(((jvalue*) v)->l);
1599 }
1600
1601 void valueArg(value_t* v, const char* a)
1602 {
1603 ((jvalue*) v)->l = env()->NewStringUTF(a);
1604 }
1605
1606 void valueArg(value_t* v, std::nullptr_t)
1607 {
1608 ((jvalue*) v)->l = nullptr;
1609 }
1610
1611 template <> void cleanupArg<const char*>(value_t* v)
1612 {
1613 env()->DeleteLocalRef(((jvalue*) v)->l);
1614 }
1615#ifdef _WIN32
1616
1617 void valueArg(value_t* v, const std::wstring& a)
1618 {
1619 ((jvalue*) v)->l = env()->NewString((const jchar*) a.c_str(), jsize(a.length()));
1620 }
1621
1622 void valueArg(value_t* v, const wchar_t* a)
1623 {
1624 ((jvalue*) v)->l = env()->NewString((const jchar*) a, jsize(std::wcslen(a)));
1625 }
1626#else
1627
1628 void valueArg(value_t* v, const std::wstring& a)
1629 {
1630 auto jstr = toJString(a.c_str(), a.length());
1631 ((jvalue*) v)->l = env()->NewString(jstr.data(), jsize(jstr.size()));
1632 }
1633
1634 void valueArg(value_t* v, const wchar_t* a)
1635 {
1636 auto jstr = toJString(a, std::wcslen(a));
1637 ((jvalue*) v)->l = env()->NewString(jstr.data(), jsize(jstr.size()));
1638 }
1639
1640#endif
1641
1642 template <> void cleanupArg<const std::wstring*>(value_t* v)
1643 {
1644 env()->DeleteLocalRef(((jvalue*) v)->l);
1645 }
1646
1647 template <> void cleanupArg<const wchar_t*>(value_t* v)
1648 {
1649 env()->DeleteLocalRef(((jvalue*) v)->l);
1650 }
1651
1652 long getArrayLength(jarray array)
1653 {
1654 return env()->GetArrayLength(array);
1655 }
1656 }
1657}
1658