1 use jni_sys::{jboolean, JNI_TRUE}; 2 use std::{borrow::Cow, os::raw::c_char}; 3 4 use log::warn; 5 6 use crate::{errors::*, objects::JString, strings::JNIStr, JNIEnv}; 7 8 /// Reference to a string in the JVM. Holds a pointer to the array 9 /// returned by `GetStringUTFChars`. Calls `ReleaseStringUTFChars` on Drop. 10 /// Can be converted to a `&JNIStr` with the same cost as the `&CStr.from_ptr` 11 /// conversion. 12 pub struct JavaStr<'local, 'other_local: 'obj_ref, 'obj_ref> { 13 internal: *const c_char, 14 obj: &'obj_ref JString<'other_local>, 15 env: JNIEnv<'local>, 16 } 17 18 impl<'local, 'other_local: 'obj_ref, 'obj_ref> JavaStr<'local, 'other_local, 'obj_ref> { 19 /// Get a pointer to the character array beneath a [JString] 20 /// 21 /// The string will be `NULL` terminated and encoded as 22 /// [Modified UTF-8](https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8) / 23 /// [CESU-8](https://en.wikipedia.org/wiki/CESU-8). 24 /// 25 /// The implementation may either create a copy of the character array for 26 /// the given `String` or it may pin it to avoid it being collected by the 27 /// garbage collector. 28 /// 29 /// Returns a tuple with the pointer and the status of whether the implementation 30 /// created a copy of the underlying character array. 31 /// 32 /// # Warning 33 /// 34 /// The caller must release the array when they are done with it via 35 /// [Self::release_string_utf_chars] 36 /// 37 /// # Safety 38 /// 39 /// The caller must guarantee that the Object passed in is an instance of `java.lang.String`, 40 /// passing in anything else will lead to undefined behaviour (The JNI implementation 41 /// is likely to crash or abort the process). get_string_utf_chars( env: &JNIEnv<'_>, obj: &JString<'_>, ) -> Result<(*const c_char, bool)>42 unsafe fn get_string_utf_chars( 43 env: &JNIEnv<'_>, 44 obj: &JString<'_>, 45 ) -> Result<(*const c_char, bool)> { 46 non_null!(obj, "get_string_utf_chars obj argument"); 47 let mut is_copy: jboolean = 0; 48 let ptr: *const c_char = jni_non_null_call!( 49 env.get_raw(), 50 GetStringUTFChars, 51 obj.as_raw(), 52 &mut is_copy as *mut _ 53 ); 54 55 let is_copy = is_copy == JNI_TRUE; 56 Ok((ptr, is_copy)) 57 } 58 59 /// Release the backing string 60 /// 61 /// This will either free the copy that was made by `GetStringUTFChars` or unpin it so it 62 /// may be released by the garbage collector once there are no further references to the string. 63 /// 64 /// # Safety 65 /// 66 /// The caller must guarantee that [Self::internal] was constructed from a valid pointer obtained from [Self::get_string_utf_chars] release_string_utf_chars(&mut self) -> Result<()>67 unsafe fn release_string_utf_chars(&mut self) -> Result<()> { 68 non_null!(self.obj, "release_string_utf_chars obj argument"); 69 // This method is safe to call in case of pending exceptions (see the chapter 2 of the spec) 70 jni_unchecked!( 71 self.env.get_raw(), 72 ReleaseStringUTFChars, 73 self.obj.as_raw(), 74 self.internal 75 ); 76 77 Ok(()) 78 } 79 80 /// Get a [JavaStr] from a [JNIEnv] and a [JString]. 81 /// You probably want [JNIEnv::get_string] instead of this method. from_env(env: &JNIEnv<'local>, obj: &'obj_ref JString<'other_local>) -> Result<Self>82 pub fn from_env(env: &JNIEnv<'local>, obj: &'obj_ref JString<'other_local>) -> Result<Self> { 83 Ok(unsafe { 84 let (ptr, _) = Self::get_string_utf_chars(env, obj)?; 85 86 Self::from_raw(env, obj, ptr) 87 }) 88 } 89 90 /// Get the raw string pointer from the JavaStr. 91 /// 92 /// The string will be `NULL` terminated and encoded as 93 /// [Modified UTF-8](https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8) / 94 /// [CESU-8](https://en.wikipedia.org/wiki/CESU-8). get_raw(&self) -> *const c_char95 pub fn get_raw(&self) -> *const c_char { 96 self.internal 97 } 98 99 /// Consumes the `JavaStr`, returning the raw string pointer 100 /// 101 /// The string will be `NULL` terminated and encoded as 102 /// [Modified UTF-8](https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8) / 103 /// [CESU-8](https://en.wikipedia.org/wiki/CESU-8). 104 /// 105 /// # Warning 106 /// The programmer is responsible for making sure the backing string gets 107 /// released when they are done with it, for example by reconstructing a 108 /// [JavaStr] with [`Self::from_raw`], which will release the backing string 109 /// when it is dropped. into_raw(self) -> *const c_char110 pub fn into_raw(self) -> *const c_char { 111 let mut _dont_call_drop = std::mem::ManuallyDrop::new(self); 112 113 // Drop the `JNIEnv` in place. As of this writing, that's a no-op, but if `JNIEnv` 114 // gains any drop code in the future, this will run it. 115 // 116 // Safety: The `&mut` proves that `self.env` is valid and not aliased. It is not 117 // accessed again after this point. Because `self` has been moved into `ManuallyDrop`, 118 // the `JNIEnv` will not be dropped twice. 119 unsafe { 120 std::ptr::drop_in_place(&mut _dont_call_drop.env); 121 } 122 123 _dont_call_drop.internal 124 } 125 126 /// Get a [JavaStr] from it's raw components 127 /// 128 /// # Safety 129 /// 130 /// The caller must guarantee that `ptr` is a valid, non-null pointer returned by [`Self::into_raw`], 131 /// and that `obj` is the same `String` object originally used to create the [JavaStr] 132 /// 133 /// # Example 134 /// ```rust,no_run 135 /// # use jni::{errors::Result, JNIEnv, strings::JavaStr}; 136 /// # 137 /// # fn example(env: &mut JNIEnv) -> Result<()> { 138 /// let jstring = env.new_string("foo")?; 139 /// let java_str = env.get_string(&jstring)?; 140 /// 141 /// let ptr = java_str.into_raw(); 142 /// // Do whatever you need with the pointer 143 /// let java_str = unsafe { JavaStr::from_raw(env, &jstring, ptr) }; 144 /// # Ok(()) 145 /// # } 146 /// ``` from_raw( env: &JNIEnv<'local>, obj: &'obj_ref JString<'other_local>, ptr: *const c_char, ) -> Self147 pub unsafe fn from_raw( 148 env: &JNIEnv<'local>, 149 obj: &'obj_ref JString<'other_local>, 150 ptr: *const c_char, 151 ) -> Self { 152 Self { 153 internal: ptr, 154 obj, 155 156 // Safety: The cloned `JNIEnv` will not be used to create any local references, only to 157 // release `ptr`. 158 env: env.unsafe_clone(), 159 } 160 } 161 } 162 163 impl<'local, 'other_local: 'obj_ref, 'obj_ref> ::std::ops::Deref 164 for JavaStr<'local, 'other_local, 'obj_ref> 165 { 166 type Target = JNIStr; deref(&self) -> &Self::Target167 fn deref(&self) -> &Self::Target { 168 self.into() 169 } 170 } 171 172 impl<'local, 'other_local: 'obj_ref, 'obj_ref: 'java_str, 'java_str> 173 From<&'java_str JavaStr<'local, 'other_local, 'obj_ref>> for &'java_str JNIStr 174 { from(other: &'java_str JavaStr) -> &'java_str JNIStr175 fn from(other: &'java_str JavaStr) -> &'java_str JNIStr { 176 unsafe { JNIStr::from_ptr(other.internal) } 177 } 178 } 179 180 impl<'local, 'other_local: 'obj_ref, 'obj_ref: 'java_str, 'java_str> 181 From<&'java_str JavaStr<'local, 'other_local, 'obj_ref>> for Cow<'java_str, str> 182 { from(other: &'java_str JavaStr) -> Cow<'java_str, str>183 fn from(other: &'java_str JavaStr) -> Cow<'java_str, str> { 184 let jni_str: &JNIStr = other; 185 jni_str.into() 186 } 187 } 188 189 impl<'local, 'other_local: 'obj_ref, 'obj_ref> From<JavaStr<'local, 'other_local, 'obj_ref>> 190 for String 191 { from(other: JavaStr) -> String192 fn from(other: JavaStr) -> String { 193 let cow: Cow<str> = (&other).into(); 194 cow.into_owned() 195 } 196 } 197 198 impl<'local, 'other_local: 'obj_ref, 'obj_ref> Drop for JavaStr<'local, 'other_local, 'obj_ref> { drop(&mut self)199 fn drop(&mut self) { 200 match unsafe { self.release_string_utf_chars() } { 201 Ok(()) => {} 202 Err(e) => warn!("error dropping java str: {}", e), 203 } 204 } 205 } 206