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::{
18 ipc_binding, BorrowedMsgParcel, IpcResult, IpcStatusCode,
19 status_result, AsRawPtr
20 };
21 use std::convert::TryInto;
22 use std::mem::MaybeUninit;
23 use std::ffi::CString;
24 use hilog_rust::{error, hilog, HiLogLabel, LogType};
25
26 const LOG_LABEL: HiLogLabel = HiLogLabel {
27 log_type: LogType::LogCore,
28 domain: 0xD0057CA,
29 tag: "RustString"
30 };
31
32 impl SerOption for str {}
33 impl SerOption for String {}
34 impl DeOption for String {}
35
36 impl Serialize for str {
serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()>37 fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
38 // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
39 let ret = unsafe {
40 ipc_binding::CParcelWriteString(
41 parcel.as_mut_raw(),
42 self.as_ptr() as *const c_char,
43 self.as_bytes().len().try_into().unwrap()
44 )};
45 status_result::<()>(ret as i32, ())
46 }
47 }
48
49 impl Serialize for String {
serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()>50 fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
51 self.as_str().serialize(parcel)
52 }
53 }
54
55 impl Deserialize for String {
deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self>56 fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self> {
57 let mut vec: Option<Vec<u8>> = None;
58 // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
59 let ok_status = unsafe {
60 ipc_binding::CParcelReadString(
61 parcel.as_raw(),
62 &mut vec as *mut _ as *mut c_void,
63 allocate_vec_with_buffer::<u8>
64 )
65 };
66
67 if ok_status {
68 vec_to_string(vec)
69 } else {
70 Err(IpcStatusCode::Failed)
71 }
72 }
73 }
74
75 impl SerArray for &str {
ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()>76 fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
77 // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
78 let ret = unsafe {
79 ipc_binding::CParcelWriteStringArray(
80 parcel.as_mut_raw(),
81 slice.as_ptr() as *const c_void,
82 slice.len().try_into().unwrap(),
83 on_str_writer,
84 )
85 };
86 status_result::<()>(ret as i32, ())
87 }
88 }
89
90 impl SerArray for String {
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::CParcelWriteStringArray(
95 parcel.as_mut_raw(),
96 slice.as_ptr() as *const c_void,
97 slice.len().try_into().unwrap(),
98 on_string_writer,
99 )
100 };
101 status_result::<()>(ret as i32, ())
102 }
103 }
104
105 impl DeArray for String {
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::CParcelReadStringArray(
114 parcel.as_raw(),
115 &mut vec as *mut _ as *mut c_void,
116 on_string_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 string from native fail");
127 Err(IpcStatusCode::Failed)
128 }
129 }
130 }
131
132 /// Callback to serialize a String array to c++ std::vector<std::string>.
133 ///
134 /// # Safety:
135 ///
136 /// We are relying on c interface to not overrun our slice. As long
137 /// as it doesn't provide an index larger than the length of the original
138 /// slice in ser_array, this operation is safe. The index provided
139 /// is zero-based.
140 #[allow(dead_code)]
on_str_writer( array: *const c_void, value: *mut c_void, len: u32, ) -> bool141 unsafe extern "C" fn on_str_writer(
142 array: *const c_void, // C++ vector pointer
143 value: *mut c_void, // Rust slice pointer
144 len: u32,
145 ) -> bool {
146 if len == 0 {
147 return false;
148 }
149 let len = len as usize;
150 let slice: &[&str] = std::slice::from_raw_parts(value.cast(), len);
151
152 for item in slice.iter().take(len) {
153 // SAFETY: The C interface is assumed to handle the provided index correctly
154 // and not overrun the original slice.
155 let ret = unsafe {
156 ipc_binding::CParcelWriteStringElement(
157 array,
158 item.as_ptr() as *const c_char,
159 item.as_bytes().len().try_into().unwrap())
160 };
161 if !ret {
162 return false;
163 }
164 }
165 true
166 }
167
168 /// Callback to serialize a String array to c++ std::vector<std::string>.
169 ///
170 /// # Safety:
171 ///
172 /// We are relying on c interface to not overrun our slice. As long
173 /// as it doesn't provide an index larger than the length of the original
174 /// slice in ser_array, this operation is safe. The index provided
175 /// is zero-based.
176 #[allow(dead_code)]
on_string_writer( array: *const c_void, value: *mut c_void, len: u32, ) -> bool177 unsafe extern "C" fn on_string_writer(
178 array: *const c_void, // C++ vector pointer
179 value: *mut c_void, // Rust slice pointer
180 len: u32,
181 ) -> bool {
182 if len == 0 {
183 return false;
184 }
185 let len = len as usize;
186 let slice: &[String] = std::slice::from_raw_parts(value.cast(), len);
187
188 for item in slice.iter().take(len) {
189 // SAFETY: writes a String element to a parcel.
190 let ret = unsafe {
191 ipc_binding::CParcelWriteStringElement(
192 array,
193 item.as_ptr() as *const c_char,
194 item.as_bytes().len().try_into().unwrap())
195 };
196 if !ret {
197 return false;
198 }
199 }
200 true
201 }
202
203 /// Callback to deserialize a String element in Vector<String>.
204 ///
205 /// # Safety:
206 ///
207 /// The opaque array data pointer must be a mutable pointer to an
208 /// `Option<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
209 /// (zero-based).
210 #[allow(dead_code)]
on_string_reader( data: *const c_void, value: *mut c_void, len: u32, ) -> bool211 unsafe extern "C" fn on_string_reader(
212 data: *const c_void, // C++ vector pointer
213 value: *mut c_void, // Rust vector pointer
214 len: u32, // C++ vector length
215 ) -> bool {
216 // SAFETY:
217 // Allocate Vec<String> capacity, data_len will set correctly by vec.push().
218 unsafe { allocate_vec_maybeuninit::<String>(value, 0) };
219 let vec = &mut *(value as *mut Option<Vec<MaybeUninit<String>>>);
220 for index in 0..len {
221 let mut vec_u8: Option<Vec<u8>> = None;
222 // SAFETY:
223 // This function reads a string element from a parcel and stores it in the provided vec_u8 pointer.
224 let ok_status = unsafe {
225 ipc_binding::CParcelReadStringElement(
226 index,
227 data,
228 &mut vec_u8 as *mut _ as *mut c_void,
229 allocate_vec_with_buffer::<u8>
230 )
231 };
232 if ok_status {
233 if let Ok(string) = vec_to_string(vec_u8) {
234 if let Some(new_vec) = vec {
235 new_vec.push(MaybeUninit::new(string));
236 } else {
237 error!(LOG_LABEL, "on_string_reader allocate vec failed");
238 return false;
239 }
240 } else {
241 error!(LOG_LABEL, "on_string_reader vec_to_string failed");
242 return false;
243 }
244 } else {
245 return false;
246 }
247 }
248 true
249 }
250
vec_to_string(vec: Option<Vec<u8>>) -> IpcResult<String>251 pub fn vec_to_string(vec: Option<Vec<u8>>) -> IpcResult<String> {
252 let value = vec.map(|s| {
253 // The vector includes a null-terminator and
254 // we don't want the string to be null-terminated for Rust.
255 String::from_utf8(s).or(Err(IpcStatusCode::Failed))
256 });
257 if let Some(ret) = value {
258 ret
259 } else {
260 error!(LOG_LABEL, "convert vector u8 to String fail");
261 Err(IpcStatusCode::Failed)
262 }
263 }
264
vec_u16_to_string(vec: Option<Vec<u16>>) -> IpcResult<String>265 pub fn vec_u16_to_string(vec: Option<Vec<u16>>) -> IpcResult<String> {
266 let value = vec.map(|s| {
267 // The vector includes a null-terminator and
268 // we don't want the string to be null-terminated for Rust.
269 let slice = &s[..];
270 String::from_utf16(slice).or(Err(IpcStatusCode::Failed))
271 });
272 if let Some(ret) = value {
273 ret
274 } else {
275 error!(LOG_LABEL, "convert vector u16 to String fail");
276 Err(IpcStatusCode::Failed)
277 }
278 }