1use super::storage::{AccessCapability, FilesystemType, StorageType};
8use crate::ptp::pack::{unpack_string, unpack_u16, unpack_u16_array, unpack_u32, unpack_u64};
9use crate::ptp::{EventCode, ObjectFormatCode, OperationCode};
10
11#[derive(Debug, Clone, Default)]
17pub struct DeviceInfo {
18 pub standard_version: u16,
20 pub vendor_extension_id: u32,
22 pub vendor_extension_version: u16,
24 pub vendor_extension_desc: String,
26 pub functional_mode: u16,
28 pub operations_supported: Vec<OperationCode>,
30 pub events_supported: Vec<EventCode>,
32 pub device_properties_supported: Vec<u16>,
34 pub capture_formats: Vec<ObjectFormatCode>,
36 pub playback_formats: Vec<ObjectFormatCode>,
38 pub manufacturer: String,
40 pub model: String,
42 pub device_version: String,
44 pub serial_number: String,
46}
47
48impl DeviceInfo {
49 pub fn from_bytes(buf: &[u8]) -> Result<Self, crate::Error> {
53 let mut offset = 0;
54
55 let standard_version = unpack_u16(&buf[offset..])?;
57 offset += 2;
58
59 let vendor_extension_id = unpack_u32(&buf[offset..])?;
61 offset += 4;
62
63 let vendor_extension_version = unpack_u16(&buf[offset..])?;
65 offset += 2;
66
67 let (vendor_extension_desc, consumed) = unpack_string(&buf[offset..])?;
69 offset += consumed;
70
71 let functional_mode = unpack_u16(&buf[offset..])?;
73 offset += 2;
74
75 let (ops_raw, consumed) = unpack_u16_array(&buf[offset..])?;
77 let operations_supported: Vec<OperationCode> =
78 ops_raw.into_iter().map(OperationCode::from).collect();
79 offset += consumed;
80
81 let (events_raw, consumed) = unpack_u16_array(&buf[offset..])?;
83 let events_supported: Vec<EventCode> =
84 events_raw.into_iter().map(EventCode::from).collect();
85 offset += consumed;
86
87 let (device_properties_supported, consumed) = unpack_u16_array(&buf[offset..])?;
89 offset += consumed;
90
91 let (capture_raw, consumed) = unpack_u16_array(&buf[offset..])?;
93 let capture_formats: Vec<ObjectFormatCode> = capture_raw
94 .into_iter()
95 .map(ObjectFormatCode::from)
96 .collect();
97 offset += consumed;
98
99 let (playback_raw, consumed) = unpack_u16_array(&buf[offset..])?;
101 let playback_formats: Vec<ObjectFormatCode> = playback_raw
102 .into_iter()
103 .map(ObjectFormatCode::from)
104 .collect();
105 offset += consumed;
106
107 let (manufacturer, consumed) = unpack_string(&buf[offset..])?;
109 offset += consumed;
110
111 let (model, consumed) = unpack_string(&buf[offset..])?;
113 offset += consumed;
114
115 let (device_version, consumed) = unpack_string(&buf[offset..])?;
117 offset += consumed;
118
119 let (serial_number, _) = unpack_string(&buf[offset..])?;
121
122 Ok(DeviceInfo {
123 standard_version,
124 vendor_extension_id,
125 vendor_extension_version,
126 vendor_extension_desc,
127 functional_mode,
128 operations_supported,
129 events_supported,
130 device_properties_supported,
131 capture_formats,
132 playback_formats,
133 manufacturer,
134 model,
135 device_version,
136 serial_number,
137 })
138 }
139
140 #[must_use]
150 pub fn supports_operation(&self, operation: OperationCode) -> bool {
151 self.operations_supported.contains(&operation)
152 }
153
154 #[must_use]
163 pub fn supports_rename(&self) -> bool {
164 self.supports_operation(OperationCode::SetObjectPropValue)
165 }
166}
167
168#[derive(Debug, Clone, Default)]
174pub struct StorageInfo {
175 pub storage_type: StorageType,
177 pub filesystem_type: FilesystemType,
179 pub access_capability: AccessCapability,
181 pub max_capacity: u64,
183 pub free_space_bytes: u64,
185 pub free_space_objects: u32,
187 pub description: String,
189 pub volume_identifier: String,
191}
192
193impl StorageInfo {
194 pub fn from_bytes(buf: &[u8]) -> Result<Self, crate::Error> {
198 let mut offset = 0;
199
200 let storage_type = StorageType::from(unpack_u16(&buf[offset..])?);
202 offset += 2;
203
204 let filesystem_type = FilesystemType::from(unpack_u16(&buf[offset..])?);
206 offset += 2;
207
208 let access_capability = AccessCapability::from(unpack_u16(&buf[offset..])?);
210 offset += 2;
211
212 let max_capacity = unpack_u64(&buf[offset..])?;
214 offset += 8;
215
216 let free_space_bytes = unpack_u64(&buf[offset..])?;
218 offset += 8;
219
220 let free_space_objects = unpack_u32(&buf[offset..])?;
222 offset += 4;
223
224 let (description, consumed) = unpack_string(&buf[offset..])?;
226 offset += consumed;
227
228 let (volume_identifier, _) = unpack_string(&buf[offset..])?;
230
231 Ok(StorageInfo {
232 storage_type,
233 filesystem_type,
234 access_capability,
235 max_capacity,
236 free_space_bytes,
237 free_space_objects,
238 description,
239 volume_identifier,
240 })
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247 use crate::ptp::pack::{pack_string, pack_u16, pack_u16_array, pack_u32};
248
249 fn build_minimal_device_info_bytes() -> Vec<u8> {
252 let mut buf = Vec::new();
253
254 buf.extend_from_slice(&pack_u16(100));
256 buf.extend_from_slice(&pack_u32(0));
258 buf.extend_from_slice(&pack_u16(0));
260 buf.push(0x00);
262 buf.extend_from_slice(&pack_u16(0));
264 buf.extend_from_slice(&pack_u16_array(&[]));
266 buf.extend_from_slice(&pack_u16_array(&[]));
268 buf.extend_from_slice(&pack_u16_array(&[]));
270 buf.extend_from_slice(&pack_u16_array(&[]));
272 buf.extend_from_slice(&pack_u16_array(&[]));
274 buf.push(0x00);
276 buf.push(0x00);
278 buf.push(0x00);
280 buf.push(0x00);
282
283 buf
284 }
285
286 #[test]
287 fn device_info_parse_minimal() {
288 let buf = build_minimal_device_info_bytes();
289 let info = DeviceInfo::from_bytes(&buf).unwrap();
290
291 assert_eq!(info.standard_version, 100);
292 assert_eq!(info.vendor_extension_id, 0);
293 assert_eq!(info.vendor_extension_version, 0);
294 assert_eq!(info.vendor_extension_desc, "");
295 assert_eq!(info.functional_mode, 0);
296 assert!(info.operations_supported.is_empty());
297 assert!(info.events_supported.is_empty());
298 assert!(info.device_properties_supported.is_empty());
299 assert!(info.capture_formats.is_empty());
300 assert!(info.playback_formats.is_empty());
301 assert_eq!(info.manufacturer, "");
302 assert_eq!(info.model, "");
303 assert_eq!(info.device_version, "");
304 assert_eq!(info.serial_number, "");
305 }
306
307 fn build_full_device_info_bytes() -> Vec<u8> {
308 let mut buf = Vec::new();
309
310 buf.extend_from_slice(&pack_u16(100));
312 buf.extend_from_slice(&pack_u32(6));
314 buf.extend_from_slice(&pack_u16(100));
316 buf.extend_from_slice(&pack_string("microsoft.com: 1.0"));
318 buf.extend_from_slice(&pack_u16(0));
320 buf.extend_from_slice(&pack_u16_array(&[0x1001, 0x1002, 0x1003]));
322 buf.extend_from_slice(&pack_u16_array(&[0x4002, 0x4003]));
324 buf.extend_from_slice(&pack_u16_array(&[0x5001, 0x5002]));
326 buf.extend_from_slice(&pack_u16_array(&[0x3801]));
328 buf.extend_from_slice(&pack_u16_array(&[0x3801, 0x3009]));
330 buf.extend_from_slice(&pack_string("Test Manufacturer"));
332 buf.extend_from_slice(&pack_string("Test Model"));
334 buf.extend_from_slice(&pack_string("1.0.0"));
336 buf.extend_from_slice(&pack_string("ABC123"));
338
339 buf
340 }
341
342 #[test]
343 fn device_info_parse_full() {
344 let buf = build_full_device_info_bytes();
345 let info = DeviceInfo::from_bytes(&buf).unwrap();
346
347 assert_eq!(info.standard_version, 100);
348 assert_eq!(info.vendor_extension_id, 6);
349 assert_eq!(info.vendor_extension_version, 100);
350 assert_eq!(info.vendor_extension_desc, "microsoft.com: 1.0");
351 assert_eq!(info.functional_mode, 0);
352
353 assert_eq!(info.operations_supported.len(), 3);
354 assert_eq!(info.operations_supported[0], OperationCode::GetDeviceInfo);
355 assert_eq!(info.operations_supported[1], OperationCode::OpenSession);
356 assert_eq!(info.operations_supported[2], OperationCode::CloseSession);
357
358 assert_eq!(info.events_supported.len(), 2);
359 assert_eq!(info.events_supported[0], EventCode::ObjectAdded);
360 assert_eq!(info.events_supported[1], EventCode::ObjectRemoved);
361
362 assert_eq!(info.device_properties_supported, vec![0x5001, 0x5002]);
363
364 assert_eq!(info.capture_formats.len(), 1);
365 assert_eq!(info.capture_formats[0], ObjectFormatCode::Jpeg);
366
367 assert_eq!(info.playback_formats.len(), 2);
368 assert_eq!(info.playback_formats[0], ObjectFormatCode::Jpeg);
369 assert_eq!(info.playback_formats[1], ObjectFormatCode::Mp3);
370
371 assert_eq!(info.manufacturer, "Test Manufacturer");
372 assert_eq!(info.model, "Test Model");
373 assert_eq!(info.device_version, "1.0.0");
374 assert_eq!(info.serial_number, "ABC123");
375 }
376
377 #[test]
378 fn device_info_parse_insufficient_bytes() {
379 let buf = vec![0x00, 0x01]; assert!(DeviceInfo::from_bytes(&buf).is_err());
381 }
382
383 fn build_storage_info_bytes() -> Vec<u8> {
386 let mut buf = Vec::new();
387
388 buf.extend_from_slice(&pack_u16(4));
390 buf.extend_from_slice(&pack_u16(2));
392 buf.extend_from_slice(&pack_u16(0));
394 buf.extend_from_slice(&32_000_000_000u64.to_le_bytes());
396 buf.extend_from_slice(&16_000_000_000u64.to_le_bytes());
398 buf.extend_from_slice(&pack_u32(0xFFFFFFFF));
400 buf.extend_from_slice(&pack_string("SD Card"));
402 buf.extend_from_slice(&pack_string("VOL001"));
404
405 buf
406 }
407
408 #[test]
409 fn storage_info_parse() {
410 let buf = build_storage_info_bytes();
411 let info = StorageInfo::from_bytes(&buf).unwrap();
412
413 assert_eq!(info.storage_type, StorageType::RemovableRam);
414 assert_eq!(info.filesystem_type, FilesystemType::GenericHierarchical);
415 assert_eq!(info.access_capability, AccessCapability::ReadWrite);
416 assert_eq!(info.max_capacity, 32_000_000_000);
417 assert_eq!(info.free_space_bytes, 16_000_000_000);
418 assert_eq!(info.free_space_objects, 0xFFFFFFFF);
419 assert_eq!(info.description, "SD Card");
420 assert_eq!(info.volume_identifier, "VOL001");
421 }
422
423 #[test]
424 fn storage_info_parse_insufficient_bytes() {
425 let buf = vec![0x00; 10]; assert!(StorageInfo::from_bytes(&buf).is_err());
427 }
428
429 #[test]
432 fn device_info_supports_operation() {
433 let info = DeviceInfo {
434 operations_supported: vec![
435 OperationCode::GetDeviceInfo,
436 OperationCode::OpenSession,
437 OperationCode::SetObjectPropValue,
438 ],
439 ..Default::default()
440 };
441
442 assert!(info.supports_operation(OperationCode::GetDeviceInfo));
443 assert!(info.supports_operation(OperationCode::OpenSession));
444 assert!(info.supports_operation(OperationCode::SetObjectPropValue));
445 assert!(!info.supports_operation(OperationCode::DeleteObject));
446 assert!(!info.supports_operation(OperationCode::GetObjectPropValue));
447 }
448
449 #[test]
450 fn device_info_supports_rename_true() {
451 let info = DeviceInfo {
452 operations_supported: vec![
453 OperationCode::GetDeviceInfo,
454 OperationCode::SetObjectPropValue, ],
456 ..Default::default()
457 };
458
459 assert!(info.supports_rename());
460 }
461
462 #[test]
463 fn device_info_supports_rename_false() {
464 let info = DeviceInfo {
465 operations_supported: vec![
466 OperationCode::GetDeviceInfo,
467 OperationCode::GetObjectPropValue, ],
469 ..Default::default()
470 };
471
472 assert!(!info.supports_rename());
473 }
474
475 #[test]
476 fn device_info_supports_rename_empty() {
477 let info = DeviceInfo::default();
478 assert!(!info.supports_rename());
479 }
480
481 crate::fuzz_bytes!(fuzz_device_info, DeviceInfo, 200);
483 crate::fuzz_bytes!(fuzz_storage_info, StorageInfo, 100);
484
485 #[test]
486 fn device_info_minimum_valid() {
487 assert!(DeviceInfo::from_bytes(&[]).is_err());
490 assert!(DeviceInfo::from_bytes(&[0; 1]).is_err());
491 assert!(DeviceInfo::from_bytes(&[0; 7]).is_err());
492 assert!(DeviceInfo::from_bytes(&[0; 8]).is_err()); }
494
495 #[test]
496 fn storage_info_minimum_valid() {
497 assert!(StorageInfo::from_bytes(&[]).is_err());
499 assert!(StorageInfo::from_bytes(&[0; 25]).is_err());
500 assert!(StorageInfo::from_bytes(&[0; 26]).is_err()); }
502
503 #[test]
504 fn storage_info_max_capacity() {
505 let mut buf = build_storage_info_bytes();
506 let max_bytes = u64::MAX.to_le_bytes();
508 buf[6..14].copy_from_slice(&max_bytes);
509
510 let info = StorageInfo::from_bytes(&buf).unwrap();
511 assert_eq!(info.max_capacity, u64::MAX);
512 }
513}