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