use crate::{
camera::Camera,
error::Error,
helper::{chars_to_cow, uninit},
try_gp_internal, Result,
};
use std::{
borrow::Cow,
ffi, fmt, fs,
os::{raw::c_char, unix::io::AsRawFd},
path::Path,
};
pub struct CameraFilePath {
pub(crate) inner: libgphoto2_sys::CameraFilePath,
}
pub enum FileType {
Preview,
Normal,
Raw,
Audio,
Exif,
Metadata,
}
pub struct CameraFile {
pub(crate) inner: *mut libgphoto2_sys::CameraFile,
#[allow(dead_code)]
file: Option<fs::File>,
}
impl Drop for CameraFile {
fn drop(&mut self) {
unsafe {
libgphoto2_sys::gp_file_unref(self.inner);
}
}
}
impl From<libgphoto2_sys::CameraFilePath> for CameraFilePath {
fn from(file_path: libgphoto2_sys::CameraFilePath) -> Self {
Self { inner: file_path }
}
}
impl From<libgphoto2_sys::CameraFileType> for FileType {
fn from(file_type: libgphoto2_sys::CameraFileType) -> Self {
use libgphoto2_sys::CameraFileType as GPFileType;
match file_type {
GPFileType::GP_FILE_TYPE_PREVIEW => Self::Preview,
GPFileType::GP_FILE_TYPE_NORMAL => Self::Normal,
GPFileType::GP_FILE_TYPE_RAW => Self::Raw,
GPFileType::GP_FILE_TYPE_AUDIO => Self::Audio,
GPFileType::GP_FILE_TYPE_EXIF => Self::Exif,
GPFileType::GP_FILE_TYPE_METADATA => Self::Metadata,
}
}
}
impl Into<libgphoto2_sys::CameraFileType> for FileType {
fn into(self) -> libgphoto2_sys::CameraFileType {
use libgphoto2_sys::CameraFileType as GPFileType;
match self {
Self::Preview => GPFileType::GP_FILE_TYPE_PREVIEW,
Self::Normal => GPFileType::GP_FILE_TYPE_NORMAL,
Self::Raw => GPFileType::GP_FILE_TYPE_RAW,
Self::Audio => GPFileType::GP_FILE_TYPE_AUDIO,
Self::Exif => GPFileType::GP_FILE_TYPE_EXIF,
Self::Metadata => GPFileType::GP_FILE_TYPE_METADATA,
}
}
}
impl fmt::Debug for CameraFilePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CameraFilePath")
.field("folder", &self.folder())
.field("name", &self.name())
.finish()
}
}
impl CameraFilePath {
pub fn folder(&self) -> Cow<str> {
chars_to_cow(self.inner.folder.as_ptr())
}
pub fn name(&self) -> Cow<str> {
chars_to_cow(self.inner.name.as_ptr())
}
fn to_camera_file(&self, camera: &Camera, path: Option<&Path>) -> Result<CameraFile> {
let camera_file = match path {
Some(dest_path) => CameraFile::new_file(dest_path)?,
None => CameraFile::new()?,
};
try_gp_internal!(libgphoto2_sys::gp_camera_file_get(
camera.camera,
self.inner.folder.as_ptr(),
self.inner.name.as_ptr(),
libgphoto2_sys::CameraFileType::GP_FILE_TYPE_NORMAL,
camera_file.inner,
camera.context.inner
))?;
Ok(camera_file)
}
pub fn get_in_memory(&self, camera: &Camera) -> Result<CameraFile> {
self.to_camera_file(camera, None)
}
pub fn download(&self, camera: &Camera, path: &Path) -> Result<CameraFile> {
self.to_camera_file(camera, Some(path))
}
}
impl CameraFile {
pub(crate) fn new() -> Result<Self> {
let mut camera_file_ptr = unsafe { uninit() };
try_gp_internal!(libgphoto2_sys::gp_file_new(&mut camera_file_ptr))?;
Ok(Self { inner: camera_file_ptr, file: None })
}
pub(crate) fn new_file(path: &Path) -> Result<Self> {
if path.is_file() {
return Err(Error::new(libgphoto2_sys::GP_ERROR_FILE_EXISTS));
}
let file = fs::File::create(path)?;
let mut camera_file_ptr = unsafe { uninit() };
try_gp_internal!(libgphoto2_sys::gp_file_new_from_fd(&mut camera_file_ptr, file.as_raw_fd()))
.map(|_| Self { inner: camera_file_ptr, file: Some(file) })
}
pub fn new_from_disk(path: &Path) -> Result<Self> {
let mut camera_file_ptr = unsafe { uninit() };
let path = ffi::CString::new(path.to_str().ok_or("File path invalid")?)?;
try_gp_internal!(libgphoto2_sys::gp_file_new_from_fd(&mut camera_file_ptr, -1))?;
try_gp_internal!(libgphoto2_sys::gp_file_open(
camera_file_ptr,
path.as_ptr() as *const c_char
))?;
Ok(Self { inner: camera_file_ptr, file: None })
}
pub fn get_data(&self) -> Result<Box<[u8]>> {
let mut size = unsafe { uninit() };
let mut data = unsafe { uninit() };
try_gp_internal!(libgphoto2_sys::gp_file_get_data_and_size(self.inner, &mut data, &mut size))?;
let data_slice: Box<[u8]> =
unsafe { std::slice::from_raw_parts(data as *const u8, size as usize) }.into();
Ok(data_slice)
}
pub fn name(&self) -> Result<Cow<str>> {
let mut file_name = unsafe { uninit() };
try_gp_internal!(libgphoto2_sys::gp_file_get_name(self.inner, &mut file_name))?;
Ok(chars_to_cow(file_name))
}
pub fn mime(&self) -> Result<Cow<str>> {
let mut mime = unsafe { uninit() };
try_gp_internal!(libgphoto2_sys::gp_file_get_mime_type(self.inner, &mut mime))?;
Ok(chars_to_cow(mime))
}
}