• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }