1 /*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 use super::*;
17 use crate::{ipc_binding, BorrowedMsgParcel, IpcResult, IpcStatusCode, status_result, AsRawPtr};
18 use std::convert::TryInto;
19 use std::mem::MaybeUninit;
20 use std::ffi::{CString};
21 use hilog_rust::{error, hilog, HiLogLabel, LogType};
22
23 const LOG_LABEL: HiLogLabel = HiLogLabel {
24 log_type: LogType::LogCore,
25 domain: 0xd001510,
26 tag: "RustString16"
27 };
28
29 /// String16 packed a String type which transfered with C++ std::u16string.
30 pub struct String16(String);
31
32 impl String16 {
33 /// Create a String16 object with rust String
new(value: &str) -> Self34 pub fn new(value: &str) -> Self {
35 Self(String::from(value))
36 }
37
38 /// Get packed String of String16
get_string(&self) -> String39 pub fn get_string(&self) -> String {
40 String::from(&self.0)
41 }
42 }
43
44 impl Serialize for String16 {
serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()>45 fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
46 let string = &self.0;
47 // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
48 let ret = unsafe {
49 ipc_binding::CParcelWriteString16(
50 parcel.as_mut_raw(),
51 string.as_ptr() as *const c_char,
52 string.as_bytes().len().try_into().unwrap()
53 )};
54 status_result::<()>(ret as i32, ())
55 }
56 }
57
58 impl Deserialize for String16 {
deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self>59 fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self> {
60 let mut vec: Option<Vec<u8>> = None;
61 // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
62 let ok_status = unsafe {
63 ipc_binding::CParcelReadString16(
64 parcel.as_raw(),
65 &mut vec as *mut _ as *mut c_void,
66 allocate_vec_with_buffer::<u8>
67 )
68 };
69
70 if ok_status {
71 let result = vec.map(|s| {
72 match String::from_utf8(s) {
73 Ok(val) => val,
74 Err(_) => String::from("")
75 }
76 });
77 if let Some(val) = result {
78 Ok(Self(val))
79 } else {
80 error!(LOG_LABEL, "convert native string16 to String fail");
81 Err(IpcStatusCode::Failed)
82 }
83 } else {
84 error!(LOG_LABEL, "read string16 from native fail");
85 Err(IpcStatusCode::Failed)
86 }
87 }
88 }
89
90 impl SerArray for String16 {
ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()>91 fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
92 // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
93 let ret = unsafe {
94 ipc_binding::CParcelWriteString16Array(
95 parcel.as_mut_raw(),
96 slice.as_ptr() as *const c_void,
97 slice.len().try_into().unwrap(),
98 on_string16_writer,
99 )
100 };
101 status_result::<()>(ret as i32, ())
102 }
103 }
104
105 impl DeArray for String16 {
de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Option<Vec<Self>>>106 fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Option<Vec<Self>>> {
107 let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
108 // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
109 // `allocate_vec<T>` expects the opaque pointer to
110 // be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
111 // correct for it.
112 let ok_status = unsafe {
113 ipc_binding::CParcelReadString16Array(
114 parcel.as_raw(),
115 &mut vec as *mut _ as *mut c_void,
116 on_string16_reader,
117 )
118 };
119 if ok_status {
120 // SAFETY: all the MaybeUninits are now properly initialized.
121 let vec: Option<Vec<Self>> = unsafe {
122 vec.map(|vec| vec_assume_init(vec))
123 };
124 Ok(vec)
125 } else {
126 error!(LOG_LABEL, "read string16 from native fail");
127 Err(IpcStatusCode::Failed)
128 }
129 }
130 }
131 /// Callback to serialize a String16 array to c++ std::vector<std::u16string>.
132 ///
133 /// # Safety:
134 ///
135 /// We are relying on c interface to not overrun our slice. As long
136 /// as it doesn't provide an index larger than the length of the original
137 /// slice in ser_array, this operation is safe. The index provided
138 /// is zero-based.
139 #[allow(dead_code)]
on_string16_writer( array: *const c_void, value: *mut c_void, len: u32, ) -> bool140 pub unsafe extern "C" fn on_string16_writer(
141 array: *const c_void, // C++ vector pointer
142 value: *mut c_void, // Rust slice pointer
143 len: u32,
144 ) -> bool {
145 if len == 0 {
146 return false;
147 }
148 let len = len as usize;
149 let slice: &[String16] = std::slice::from_raw_parts(value.cast(), len);
150
151 for item in slice.iter().take(len) {
152 // SAFETY:
153 let ret = unsafe {
154 ipc_binding::CParcelWritU16stringElement(
155 array,
156 item.0.as_ptr() as *const c_char,
157 item.0.as_bytes().len().try_into().unwrap())
158 };
159 if !ret {
160 return false;
161 }
162 }
163 true
164 }
165
166 /// Callback to deserialize a String element in Vector<String16>.
167 ///
168 /// # Safety:
169 ///
170 /// The opaque array data pointer must be a mutable pointer to an
171 /// `Option<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
172 /// (zero-based).
173 #[allow(dead_code)]
on_string16_reader( data: *const c_void, value: *mut c_void, len: u32, ) -> bool174 unsafe extern "C" fn on_string16_reader(
175 data: *const c_void, // C++ vector pointer
176 value: *mut c_void, // Rust vector pointer
177 len: u32, // C++ vector length
178 ) -> bool {
179 // SAFETY:
180 // Allocate Vec<String16> capacity, data_len will set correctly by vec.push().
181 unsafe { allocate_vec_maybeuninit::<String16>(value, 0) };
182 let vec = &mut *(value as *mut Option<Vec<MaybeUninit<String16>>>);
183 for index in 0..len {
184 let mut vec_u16: Option<Vec<u16>> = None;
185 // SAFETY: The length of the index will not exceed the range,
186 // as the traversal range is the pointer length of the data passed from the C++side
187 let ok_status = unsafe {
188 ipc_binding::CParcelReadString16Element(
189 index,
190 data,
191 &mut vec_u16 as *mut _ as *mut c_void,
192 allocate_vec_with_buffer::<u16>
193 )
194 };
195 if ok_status {
196 if let Ok(string) = vec_u16_to_string(vec_u16) {
197 if let Some(new_vec) = vec {
198 new_vec.push(MaybeUninit::new(String16::new(string.as_str())));
199 } else {
200 error!(LOG_LABEL, "on_string_reader allocate vec failed");
201 return false;
202 }
203 } else {
204 error!(LOG_LABEL, "on_string_reader vec_to_string failed");
205 return false;
206 }
207 } else {
208 return false;
209 }
210 }
211 true
212 }
213