1 use std::{ 2 borrow::{Borrow, Cow, ToOwned}, 3 ffi, 4 os::raw::c_char, 5 }; 6 7 use cesu8::{from_java_cesu8, to_java_cesu8}; 8 use log::debug; 9 10 use crate::wrapper::strings::ffi_str; 11 12 /// Wrapper for `std::ffi::CString` that also takes care of encoding between 13 /// UTF-8 and Java's Modified UTF-8. As with `CString`, this implements `Deref` 14 /// to `&JNIStr`. 15 pub struct JNIString { 16 internal: ffi::CString, 17 } 18 19 /// Wrapper for `std::ffi::CStr` that also takes care of encoding between 20 /// UTF-8 and Java's Modified UTF-8. 21 pub struct JNIStr { 22 internal: ffi::CStr, 23 } 24 25 impl ::std::ops::Deref for JNIString { 26 type Target = JNIStr; 27 deref(&self) -> &Self::Target28 fn deref(&self) -> &Self::Target { 29 unsafe { &*(self.internal.as_bytes_with_nul() as *const [u8] as *const ffi_str::JNIStr) } 30 } 31 } 32 33 impl ::std::ops::Deref for JNIStr { 34 type Target = ffi::CStr; 35 deref(&self) -> &Self::Target36 fn deref(&self) -> &Self::Target { 37 &self.internal 38 } 39 } 40 41 impl<T> From<T> for JNIString 42 where 43 T: AsRef<str>, 44 { from(other: T) -> Self45 fn from(other: T) -> Self { 46 let enc = to_java_cesu8(other.as_ref()).into_owned(); 47 JNIString { 48 internal: unsafe { ffi::CString::from_vec_unchecked(enc) }, 49 } 50 } 51 } 52 53 impl<'a> From<&'a JNIStr> for Cow<'a, str> { from(other: &'a JNIStr) -> Cow<'a, str>54 fn from(other: &'a JNIStr) -> Cow<'a, str> { 55 let bytes = other.to_bytes(); 56 match from_java_cesu8(bytes) { 57 Ok(s) => s, 58 Err(e) => { 59 debug!("error decoding java cesu8: {:#?}", e); 60 String::from_utf8_lossy(bytes) 61 } 62 } 63 } 64 } 65 66 impl From<JNIString> for String { from(other: JNIString) -> String67 fn from(other: JNIString) -> String { 68 Cow::from(other.borrowed()).into_owned() 69 } 70 } 71 72 impl JNIString { 73 /// Get the borrowed version of the JNIString. Equivalent to 74 /// `CString::borrowed`. borrowed(&self) -> &JNIStr75 pub fn borrowed(&self) -> &JNIStr { 76 self 77 } 78 } 79 80 impl JNIStr { 81 /// Construct a reference to a `JNIStr` from a pointer. Equivalent to `CStr::from_ptr`. 82 /// 83 /// # Safety 84 /// 85 /// Expects a valid pointer to a null-terminated C string and does not perform any lifetime 86 /// checks for the resulting value. from_ptr<'a>(ptr: *const c_char) -> &'a JNIStr87 pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a JNIStr { 88 &*(ffi::CStr::from_ptr(ptr) as *const ffi::CStr as *const ffi_str::JNIStr) 89 } 90 } 91 92 // impls for CoW 93 impl Borrow<JNIStr> for JNIString { borrow(&self) -> &JNIStr94 fn borrow(&self) -> &JNIStr { 95 self 96 } 97 } 98 99 impl ToOwned for JNIStr { 100 type Owned = JNIString; 101 to_owned(&self) -> JNIString102 fn to_owned(&self) -> JNIString { 103 unsafe { 104 JNIString { 105 internal: ffi::CString::from_vec_unchecked(self.to_bytes().to_vec()), 106 } 107 } 108 } 109 } 110