1pub mod filetypes;
8pub mod properties;
9
10use std::ffi::CString;
11
12use crate::device::MtpDevice;
13use crate::storage::Parent;
14use crate::Result;
15
16use libmtp_sys as ffi;
17use num_traits::ToPrimitive;
18use properties::Property;
19
20pub trait AsObjectId {
28 fn as_id(&self) -> u32;
30}
31
32impl<T> AsObjectId for T
35where
36 T: Object,
37{
38 fn as_id(&self) -> u32 {
39 self.id()
40 }
41}
42
43impl AsObjectId for u32 {
47 fn as_id(&self) -> u32 {
48 *self
49 }
50}
51
52pub struct DummyObject<'a> {
55 pub(crate) id: u32,
56 pub(crate) mtpdev: &'a MtpDevice,
57}
58
59impl Object for DummyObject<'_> {
60 fn id(&self) -> u32 {
61 self.id
62 }
63
64 fn device(&self) -> &MtpDevice {
65 self.mtpdev
66 }
67}
68
69pub trait Object {
74 fn id(&self) -> u32;
76
77 fn device(&self) -> &MtpDevice;
79
80 fn get_string(&self, property: Property) -> Result<String> {
82 let property = property.to_u32().unwrap();
83 let id = self.id();
84 let device = self.device();
85
86 let string = unsafe { ffi::LIBMTP_Get_String_From_Object(device.inner, id, property) };
87
88 if string.is_null() {
89 Err(device.latest_error().unwrap_or_default())
90 } else {
91 unsafe {
92 let u8vec = cstr_to_u8vec!(string);
93 libc::free(string as *mut _);
94 Ok(String::from_utf8(u8vec)?)
95 }
96 }
97 }
98
99 fn set_string(&self, property: Property, string: &str) -> Result<()> {
101 let property = property.to_u32().unwrap();
102 let id = self.id();
103 let device = self.device();
104 let string = CString::new(string).expect("Nul byte");
105
106 let res =
107 unsafe { ffi::LIBMTP_Set_Object_String(device.inner, id, property, string.as_ptr()) };
108
109 if res != 0 {
110 Err(device.latest_error().unwrap_or_default())
111 } else {
112 Ok(())
113 }
114 }
115
116 fn get_u64(&self, property: Property) -> Result<u64> {
118 let property = property.to_u32().unwrap();
119 let id = self.id();
120 let device = self.device();
121
122 let val = unsafe { ffi::LIBMTP_Get_u64_From_Object(device.inner, id, property, 0) };
123
124 if let Some(err) = device.latest_error() {
125 Err(err)
126 } else {
127 Ok(val)
128 }
129 }
130
131 fn get_u32(&self, property: Property) -> Result<u32> {
133 let property = property.to_u32().unwrap();
134 let id = self.id();
135 let device = self.device();
136
137 let val = unsafe { ffi::LIBMTP_Get_u32_From_Object(device.inner, id, property, 0) };
138
139 if let Some(err) = device.latest_error() {
140 Err(err)
141 } else {
142 Ok(val)
143 }
144 }
145
146 fn set_u32(&self, property: Property, value: u32) -> Result<()> {
148 let property = property.to_u32().unwrap();
149 let id = self.id();
150 let device = self.device();
151
152 let res = unsafe { ffi::LIBMTP_Set_Object_u32(device.inner, id, property, value) };
153
154 if res != 0 {
155 Err(device.latest_error().unwrap_or_default())
156 } else {
157 Ok(())
158 }
159 }
160
161 fn get_u16(&self, property: Property) -> Result<u16> {
163 let property = property.to_u32().unwrap();
164 let id = self.id();
165 let device = self.device();
166
167 let val = unsafe { ffi::LIBMTP_Get_u16_From_Object(device.inner, id, property, 0) };
168
169 if let Some(err) = device.latest_error() {
170 Err(err)
171 } else {
172 Ok(val)
173 }
174 }
175
176 fn set_u16(&self, property: Property, value: u16) -> Result<()> {
178 let property = property.to_u32().unwrap();
179 let id = self.id();
180 let device = self.device();
181
182 let res = unsafe { ffi::LIBMTP_Set_Object_u16(device.inner, id, property, value) };
183
184 if res != 0 {
185 Err(device.latest_error().unwrap_or_default())
186 } else {
187 Ok(())
188 }
189 }
190
191 fn get_u8(&self, property: Property) -> Result<u8> {
193 let property = property.to_u32().unwrap();
194 let id = self.id();
195 let device = self.device();
196
197 let val = unsafe { ffi::LIBMTP_Get_u8_From_Object(device.inner, id, property, 0) };
198
199 if let Some(err) = device.latest_error() {
200 Err(err)
201 } else {
202 Ok(val)
203 }
204 }
205
206 fn set_u8(&self, property: Property, value: u8) -> Result<()> {
208 let property = property.to_u32().unwrap();
209 let id = self.id();
210 let device = self.device();
211
212 let res = unsafe { ffi::LIBMTP_Set_Object_u8(device.inner, id, property, value) };
213
214 if res != 0 {
215 Err(device.latest_error().unwrap_or_default())
216 } else {
217 Ok(())
218 }
219 }
220
221 fn delete(&self) -> Result<()> {
229 let id = self.id();
230 let device = self.device();
231
232 let res = unsafe { ffi::LIBMTP_Delete_Object(device.inner, id) };
233
234 if res != 0 {
235 Err(device.latest_error().unwrap_or_default())
236 } else {
237 Ok(())
238 }
239 }
240
241 fn move_to(&self, storage_id: u32, parent: Parent) -> Result<()> {
248 let id = self.id();
249 let device = self.device();
250 let parent = parent.to_id();
251
252 let res = unsafe { ffi::LIBMTP_Move_Object(device.inner, id, storage_id, parent) };
253
254 if res != 0 {
255 Err(device.latest_error().unwrap_or_default())
256 } else {
257 Ok(())
258 }
259 }
260
261 fn copy_to(&self, storage_id: u32, parent: Parent) -> Result<()> {
268 let id = self.id();
269 let device = self.device();
270 let parent = parent.to_id();
271
272 let res = unsafe { ffi::LIBMTP_Copy_Object(device.inner, id, storage_id, parent) };
273
274 if res != 0 {
275 Err(device.latest_error().unwrap_or_default())
276 } else {
277 Ok(())
278 }
279 }
280
281 fn get_partial_object(&self, offset: u64, maxbytes: u32) -> Result<Vec<u8>> {
284 let id = self.id();
285 let device = self.device();
286
287 let mut size = 0;
288 let mut data = std::ptr::null_mut();
289
290 let res = unsafe {
291 ffi::LIBMTP_GetPartialObject(device.inner, id, offset, maxbytes, &mut data, &mut size)
292 };
293
294 if res != 0 || data.is_null() {
295 if !data.is_null() {
296 unsafe {
297 libc::free(data as *mut _);
298 }
299 }
300
301 Err(device.latest_error().unwrap_or_default())
302 } else {
303 let bytes = unsafe { prim_array_ptr_to_vec!(data, u8, size) };
304 unsafe {
305 libc::free(data as *mut _);
306 }
307
308 Ok(bytes)
309 }
310 }
311
312 fn send_partial_object(&self, offset: u64, data: impl AsRef<[u8]>) -> Result<()> {
315 let id = self.id();
316 let device = self.device();
317
318 let data = data.as_ref();
319 let size = data.len();
320
321 let res = unsafe {
322 ffi::LIBMTP_SendPartialObject(
323 device.inner,
324 id,
325 offset,
326 data.as_ptr() as *mut _,
327 size as u32,
328 )
329 };
330
331 if res != 0 {
332 Err(device.latest_error().unwrap_or_default())
333 } else {
334 Ok(())
335 }
336 }
337}