The open source OpenXR runtime
at prediction 1658 lines 51 kB view raw
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