libptp/
lib.rs

1#![allow(non_snake_case)]
2#[macro_use]
3extern crate log;
4
5use byteorder::LittleEndian;
6use std::io::Cursor;
7
8mod camera;
9mod data_type;
10mod error;
11mod read;
12
13pub use self::camera::Camera;
14pub use self::data_type::{DataType, FormData};
15pub use self::error::Error;
16pub use self::read::Read;
17
18pub type ResponseCode = u16;
19
20#[allow(non_upper_case_globals)]
21pub mod StandardResponseCode {
22    use super::ResponseCode;
23
24    pub const Undefined: ResponseCode = 0x2000;
25    pub const Ok: ResponseCode = 0x2001;
26    pub const GeneralError: ResponseCode = 0x2002;
27    pub const SessionNotOpen: ResponseCode = 0x2003;
28    pub const InvalidTransactionId: ResponseCode = 0x2004;
29    pub const OperationNotSupported: ResponseCode = 0x2005;
30    pub const ParameterNotSupported: ResponseCode = 0x2006;
31    pub const IncompleteTransfer: ResponseCode = 0x2007;
32    pub const InvalidStorageId: ResponseCode = 0x2008;
33    pub const InvalidObjectHandle: ResponseCode = 0x2009;
34    pub const DevicePropNotSupported: ResponseCode = 0x200A;
35    pub const InvalidObjectFormatCode: ResponseCode = 0x200B;
36    pub const StoreFull: ResponseCode = 0x200C;
37    pub const ObjectWriteProtected: ResponseCode = 0x200D;
38    pub const StoreReadOnly: ResponseCode = 0x200E;
39    pub const AccessDenied: ResponseCode = 0x200F;
40    pub const NoThumbnailPresent: ResponseCode = 0x2010;
41    pub const SelfTestFailed: ResponseCode = 0x2011;
42    pub const PartialDeletion: ResponseCode = 0x2012;
43    pub const StoreNotAvailable: ResponseCode = 0x2013;
44    pub const SpecificationByFormatUnsupported: ResponseCode = 0x2014;
45    pub const NoValidObjectInfo: ResponseCode = 0x2015;
46    pub const InvalidCodeFormat: ResponseCode = 0x2016;
47    pub const UnknownVendorCode: ResponseCode = 0x2017;
48    pub const CaptureAlreadyTerminated: ResponseCode = 0x2018;
49    pub const DeviceBusy: ResponseCode = 0x2019;
50    pub const InvalidParentObject: ResponseCode = 0x201A;
51    pub const InvalidDevicePropFormat: ResponseCode = 0x201B;
52    pub const InvalidDevicePropValue: ResponseCode = 0x201C;
53    pub const InvalidParameter: ResponseCode = 0x201D;
54    pub const SessionAlreadyOpen: ResponseCode = 0x201E;
55    pub const TransactionCancelled: ResponseCode = 0x201F;
56    pub const SpecificationOfDestinationUnsupported: ResponseCode = 0x2020;
57
58    pub fn name(v: ResponseCode) -> Option<&'static str> {
59        match v {
60            Undefined => Some("Undefined"),
61            Ok => Some("Ok"),
62            GeneralError => Some("GeneralError"),
63            SessionNotOpen => Some("SessionNotOpen"),
64            InvalidTransactionId => Some("InvalidTransactionId"),
65            OperationNotSupported => Some("OperationNotSupported"),
66            ParameterNotSupported => Some("ParameterNotSupported"),
67            IncompleteTransfer => Some("IncompleteTransfer"),
68            InvalidStorageId => Some("InvalidStorageId"),
69            InvalidObjectHandle => Some("InvalidObjectHandle"),
70            DevicePropNotSupported => Some("DevicePropNotSupported"),
71            InvalidObjectFormatCode => Some("InvalidObjectFormatCode"),
72            StoreFull => Some("StoreFull"),
73            ObjectWriteProtected => Some("ObjectWriteProtected"),
74            StoreReadOnly => Some("StoreReadOnly"),
75            AccessDenied => Some("AccessDenied"),
76            NoThumbnailPresent => Some("NoThumbnailPresent"),
77            SelfTestFailed => Some("SelfTestFailed"),
78            PartialDeletion => Some("PartialDeletion"),
79            StoreNotAvailable => Some("StoreNotAvailable"),
80            SpecificationByFormatUnsupported => Some("SpecificationByFormatUnsupported"),
81            NoValidObjectInfo => Some("NoValidObjectInfo"),
82            InvalidCodeFormat => Some("InvalidCodeFormat"),
83            UnknownVendorCode => Some("UnknownVendorCode"),
84            CaptureAlreadyTerminated => Some("CaptureAlreadyTerminated"),
85            DeviceBusy => Some("DeviceBusy"),
86            InvalidParentObject => Some("InvalidParentObject"),
87            InvalidDevicePropFormat => Some("InvalidDevicePropFormat"),
88            InvalidDevicePropValue => Some("InvalidDevicePropValue"),
89            InvalidParameter => Some("InvalidParameter"),
90            SessionAlreadyOpen => Some("SessionAlreadyOpen"),
91            TransactionCancelled => Some("TransactionCancelled"),
92            SpecificationOfDestinationUnsupported => Some("SpecificationOfDestinationUnsupported"),
93            _ => None,
94        }
95    }
96}
97
98pub type CommandCode = u16;
99
100#[allow(non_upper_case_globals)]
101pub mod StandardCommandCode {
102    use super::CommandCode;
103
104    pub const Undefined: CommandCode = 0x1000;
105    pub const GetDeviceInfo: CommandCode = 0x1001;
106    pub const OpenSession: CommandCode = 0x1002;
107    pub const CloseSession: CommandCode = 0x1003;
108    pub const GetStorageIDs: CommandCode = 0x1004;
109    pub const GetStorageInfo: CommandCode = 0x1005;
110    pub const GetNumObjects: CommandCode = 0x1006;
111    pub const GetObjectHandles: CommandCode = 0x1007;
112    pub const GetObjectInfo: CommandCode = 0x1008;
113    pub const GetObject: CommandCode = 0x1009;
114    pub const GetThumb: CommandCode = 0x100A;
115    pub const DeleteObject: CommandCode = 0x100B;
116    pub const SendObjectInfo: CommandCode = 0x100C;
117    pub const SendObject: CommandCode = 0x100D;
118    pub const InitiateCapture: CommandCode = 0x100E;
119    pub const FormatStore: CommandCode = 0x100F;
120    pub const ResetDevice: CommandCode = 0x1010;
121    pub const SelfTest: CommandCode = 0x1011;
122    pub const SetObjectProtection: CommandCode = 0x1012;
123    pub const PowerDown: CommandCode = 0x1013;
124    pub const GetDevicePropDesc: CommandCode = 0x1014;
125    pub const GetDevicePropValue: CommandCode = 0x1015;
126    pub const SetDevicePropValue: CommandCode = 0x1016;
127    pub const ResetDevicePropValue: CommandCode = 0x1017;
128    pub const TerminateOpenCapture: CommandCode = 0x1018;
129    pub const MoveObject: CommandCode = 0x1019;
130    pub const CopyObject: CommandCode = 0x101A;
131    pub const GetPartialObject: CommandCode = 0x101B;
132    pub const InitiateOpenCapture: CommandCode = 0x101C;
133
134    pub fn name(v: CommandCode) -> Option<&'static str> {
135        match v {
136            Undefined => Some("Undefined"),
137            GetDeviceInfo => Some("GetDeviceInfo"),
138            OpenSession => Some("OpenSession"),
139            CloseSession => Some("CloseSession"),
140            GetStorageIDs => Some("GetStorageIDs"),
141            GetStorageInfo => Some("GetStorageInfo"),
142            GetNumObjects => Some("GetNumObjects"),
143            GetObjectHandles => Some("GetObjectHandles"),
144            GetObjectInfo => Some("GetObjectInfo"),
145            GetObject => Some("GetObject"),
146            GetThumb => Some("GetThumb"),
147            DeleteObject => Some("DeleteObject"),
148            SendObjectInfo => Some("SendObjectInfo"),
149            SendObject => Some("SendObject"),
150            InitiateCapture => Some("InitiateCapture"),
151            FormatStore => Some("FormatStore"),
152            ResetDevice => Some("ResetDevice"),
153            SelfTest => Some("SelfTest"),
154            SetObjectProtection => Some("SetObjectProtection"),
155            PowerDown => Some("PowerDown"),
156            GetDevicePropDesc => Some("GetDevicePropDesc"),
157            GetDevicePropValue => Some("GetDevicePropValue"),
158            SetDevicePropValue => Some("SetDevicePropValue"),
159            ResetDevicePropValue => Some("ResetDevicePropValue"),
160            TerminateOpenCapture => Some("TerminateOpenCapture"),
161            MoveObject => Some("MoveObject"),
162            CopyObject => Some("CopyObject"),
163            GetPartialObject => Some("GetPartialObject"),
164            InitiateOpenCapture => Some("InitiateOpenCapture"),
165            _ => None,
166        }
167    }
168}
169
170#[allow(non_snake_case)]
171#[derive(Debug)]
172pub struct DeviceInfo {
173    pub Version: u16,
174    pub VendorExID: u32,
175    pub VendorExVersion: u16,
176    pub VendorExtensionDesc: String,
177    pub FunctionalMode: u16,
178    pub OperationsSupported: Vec<u16>,
179    pub EventsSupported: Vec<u16>,
180    pub DevicePropertiesSupported: Vec<u16>,
181    pub CaptureFormats: Vec<u16>,
182    pub ImageFormats: Vec<u16>,
183    pub Manufacturer: String,
184    pub Model: String,
185    pub DeviceVersion: String,
186    pub SerialNumber: String,
187}
188
189impl DeviceInfo {
190    pub fn decode(buf: &[u8]) -> Result<DeviceInfo, Error> {
191        let mut cur = Cursor::new(buf);
192
193        Ok(DeviceInfo {
194            Version: cur.read_ptp_u16()?,
195            VendorExID: cur.read_ptp_u32()?,
196            VendorExVersion: cur.read_ptp_u16()?,
197            VendorExtensionDesc: cur.read_ptp_str()?,
198            FunctionalMode: cur.read_ptp_u16()?,
199            OperationsSupported: cur.read_ptp_u16_vec()?,
200            EventsSupported: cur.read_ptp_u16_vec()?,
201            DevicePropertiesSupported: cur.read_ptp_u16_vec()?,
202            CaptureFormats: cur.read_ptp_u16_vec()?,
203            ImageFormats: cur.read_ptp_u16_vec()?,
204            Manufacturer: cur.read_ptp_str()?,
205            Model: cur.read_ptp_str()?,
206            DeviceVersion: cur.read_ptp_str()?,
207            SerialNumber: cur.read_ptp_str()?,
208        })
209    }
210}
211
212#[allow(dead_code)]
213#[derive(Debug, Clone)]
214pub struct ObjectInfo {
215    pub StorageID: u32,
216    pub ObjectFormat: u16,
217    pub ProtectionStatus: u16,
218    pub ObjectCompressedSize: u32,
219    pub ThumbFormat: u16,
220    pub ThumbCompressedSize: u32,
221    pub ThumbPixWidth: u32,
222    pub ThumbPixHeight: u32,
223    pub ImagePixWidth: u32,
224    pub ImagePixHeight: u32,
225    pub ImageBitDepth: u32,
226    pub ParentObject: u32,
227    pub AssociationType: u16,
228    pub AssociationDesc: u32,
229    pub SequenceNumber: u32,
230    pub Filename: String,
231    pub CaptureDate: String,
232    pub ModificationDate: String,
233    pub Keywords: String,
234}
235
236impl ObjectInfo {
237    pub fn decode(buf: &[u8]) -> Result<ObjectInfo, Error> {
238        let mut cur = Cursor::new(buf);
239
240        Ok(ObjectInfo {
241            StorageID: cur.read_ptp_u32()?,
242            ObjectFormat: cur.read_ptp_u16()?,
243            ProtectionStatus: cur.read_ptp_u16()?,
244            ObjectCompressedSize: cur.read_ptp_u32()?,
245            ThumbFormat: cur.read_ptp_u16()?,
246            ThumbCompressedSize: cur.read_ptp_u32()?,
247            ThumbPixWidth: cur.read_ptp_u32()?,
248            ThumbPixHeight: cur.read_ptp_u32()?,
249            ImagePixWidth: cur.read_ptp_u32()?,
250            ImagePixHeight: cur.read_ptp_u32()?,
251            ImageBitDepth: cur.read_ptp_u32()?,
252            ParentObject: cur.read_ptp_u32()?,
253            AssociationType: cur.read_ptp_u16()?,
254            AssociationDesc: cur.read_ptp_u32()?,
255            SequenceNumber: cur.read_ptp_u32()?,
256            Filename: cur.read_ptp_str()?,
257            CaptureDate: cur.read_ptp_str()?,
258            ModificationDate: cur.read_ptp_str()?,
259            Keywords: cur.read_ptp_str()?,
260        })
261    }
262}
263
264#[allow(non_snake_case)]
265#[derive(Debug)]
266pub struct StorageInfo {
267    pub StorageType: u16,
268    pub FilesystemType: u16,
269    pub AccessCapability: u16,
270    pub MaxCapacity: u64,
271    pub FreeSpaceInBytes: u64,
272    pub FreeSpaceInImages: u32,
273    pub StorageDescription: String,
274    pub VolumeLabel: String,
275}
276
277impl StorageInfo {
278    pub fn decode<T: Read>(cur: &mut T) -> Result<StorageInfo, Error> {
279        Ok(StorageInfo {
280            StorageType: cur.read_ptp_u16()?,
281            FilesystemType: cur.read_ptp_u16()?,
282            AccessCapability: cur.read_ptp_u16()?,
283            MaxCapacity: cur.read_ptp_u64()?,
284            FreeSpaceInBytes: cur.read_ptp_u64()?,
285            FreeSpaceInImages: cur.read_ptp_u32()?,
286            StorageDescription: cur.read_ptp_str()?,
287            VolumeLabel: cur.read_ptp_str()?,
288        })
289    }
290}
291
292#[derive(Debug)]
293pub struct PropInfo {
294    /// A specific property_code.
295    pub property_code: u16,
296    /// This field identifies the Datatype Code of the property.
297    pub data_type: u16,
298    /// This field indicates whether the property is read-only or read-write.
299    pub get_set: u8,
300    pub factory_default: DataType,
301    pub current: DataType,
302    pub form: FormData,
303}
304
305impl PropInfo {
306    pub fn decode<T: Read>(cur: &mut T) -> Result<PropInfo, Error> {
307        let property_code = cur.read_ptp_u16()?;
308        let data_type = cur.read_ptp_u16()?;
309        Ok(PropInfo {
310            property_code,
311            data_type,
312            get_set: cur.read_u8()?,
313            factory_default: DataType::read_type(data_type, cur)?,
314            current: DataType::read_type(data_type, cur)?,
315            form: {
316                match cur.read_u8()? {
317                    // 0x00 => FormData::None,
318                    0x01 => FormData::Range {
319                        min_value: DataType::read_type(data_type, cur)?,
320                        max_value: DataType::read_type(data_type, cur)?,
321                        step: DataType::read_type(data_type, cur)?,
322                    },
323                    0x02 => FormData::Enumeration {
324                        array: {
325                            let len = cur.read_u16::<LittleEndian>()? as usize;
326                            let mut arr = Vec::with_capacity(len);
327                            for _ in 0..len {
328                                arr.push(DataType::read_type(data_type, cur)?);
329                            }
330                            arr
331                        },
332                    },
333                    _ => FormData::None,
334                }
335            },
336        })
337    }
338}
339
340#[derive(Debug)]
341pub struct PropInfoSony {
342    /// A specific property_code.
343    pub property_code: u16,
344    /// This field identifies the Datatype Code of the property.
345    pub data_type: u16,
346    /// This field indicates whether the property is read-only or read-write.
347    pub get_set: u8,
348    /// This field indicates whether the property is valid, invalid or DispOnly.
349    pub is_enable: u8,
350    pub factory_default: DataType,
351    pub current: DataType,
352    pub form: FormData,
353}
354
355impl PropInfoSony {
356    pub fn decode<T: Read>(cur: &mut T) -> Result<PropInfoSony, Error> {
357        let property_code = cur.read_ptp_u16()?;
358        let data_type = cur.read_ptp_u16()?;
359        Ok(PropInfoSony {
360            property_code,
361            data_type,
362            get_set: cur.read_u8()?,
363            is_enable: cur.read_u8()?,
364            factory_default: DataType::read_type(data_type, cur)?,
365            current: DataType::read_type(data_type, cur)?,
366            form: {
367                match cur.read_u8()? {
368                    // 0x00 => FormData::None,
369                    0x01 => FormData::Range {
370                        min_value: DataType::read_type(data_type, cur)?,
371                        max_value: DataType::read_type(data_type, cur)?,
372                        step: DataType::read_type(data_type, cur)?,
373                    },
374                    0x02 => FormData::Enumeration {
375                        array: {
376                            let len = cur.read_u16::<LittleEndian>()? as usize;
377                            let mut arr = Vec::with_capacity(len);
378                            for _ in 0..len {
379                                arr.push(DataType::read_type(data_type, cur)?);
380                            }
381                            arr
382                        },
383                    },
384                    _ => FormData::None,
385                }
386            },
387        })
388    }
389}
390
391#[derive(Debug, Clone)]
392pub struct ObjectTree {
393    pub handle: u32,
394    pub info: ObjectInfo,
395    pub children: Option<Vec<ObjectTree>>,
396}
397
398impl ObjectTree {
399    pub fn walk(&self) -> Vec<(String, ObjectTree)> {
400        let mut input = vec![("".to_owned(), self.clone())];
401        let mut output = vec![];
402
403        while !input.is_empty() {
404            for (prefix, item) in input.split_off(0) {
405                let path = prefix.clone()
406                    + (if prefix.is_empty() { "" } else { "/" })
407                    + &item.info.Filename;
408
409                output.push((path.clone(), item.clone()));
410
411                if let Some(children) = item.children {
412                    input.extend(children.into_iter().map(|x| (path.clone(), x)));
413                }
414            }
415        }
416
417        output
418    }
419}