From 81a2f3fe60af6cb5452edbee4c6185b00d15cb5c Mon Sep 17 00:00:00 2001 From: David Cuddeback Date: Thu, 22 Oct 2015 21:11:44 -0700 Subject: [PATCH] adds image --- src/error.rs | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/image.rs | 57 +++++++++++++++++++++ src/lib.rs | 4 ++ 3 files changed, 200 insertions(+) create mode 100644 src/error.rs create mode 100644 src/image.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..9d433ef --- /dev/null +++ b/src/error.rs @@ -0,0 +1,139 @@ +use std::error::Error as StdError; +use std::ffi::CStr; +use std::fmt; +use std::result::Result as StdResult; + +use libc::{c_int}; + +/// Result type returned by libraw functions. +pub type Result = StdResult; + +/// The error type for libraw functions. +#[derive(Debug)] +pub struct Error { + repr: Repr, + message: String, +} + +#[derive(Debug)] +enum Repr { + LibRaw(c_int), + Os(i32), +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> StdResult<(), fmt::Error> { + fmt.write_str(&self.message) + } +} + +impl StdError for Error { + fn description(&self) -> &str { + &self.message + } +} + +#[doc(hidden)] +pub fn from_libraw(error: c_int) -> Error { + let message = String::from_utf8_lossy(unsafe { + CStr::from_ptr(::libraw::libraw_strerror(error)) + }.to_bytes()).into_owned(); + + Error { + repr: Repr::LibRaw(error), + message: message, + } +} + +#[doc(hidden)] +pub fn from_raw_os_error(errno: i32) -> Error { + Error { + repr: Repr::Os(errno), + message: os::error_string(errno), + } +} + + +// adapted from libstd +pub mod os { + use std::ffi::CStr; + use std::str; + + use libc::{c_char,c_int,size_t}; + + const TMPBUF_SZ: usize = 128; + + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd"))] + unsafe fn errno_location() -> *mut c_int { + extern { fn __error() -> *mut c_int; } + __error() + } + + #[cfg(target_os = "bitrig")] + fn errno_location() -> *mut c_int { + extern { + fn __errno() -> *mut c_int; + } + unsafe { + __errno() + } + } + + #[cfg(target_os = "dragonfly")] + unsafe fn errno_location() -> *mut c_int { + extern { fn __dfly_error() -> *mut c_int; } + __dfly_error() + } + + #[cfg(target_os = "openbsd")] + unsafe fn errno_location() -> *mut c_int { + extern { fn __errno() -> *mut c_int; } + __errno() + } + + #[cfg(any(target_os = "linux", target_os = "android"))] + unsafe fn errno_location() -> *mut c_int { + extern { fn __errno_location() -> *mut c_int; } + __errno_location() + } + + pub fn errno() -> i32 { + unsafe { + (*errno_location()) as i32 + } + } + + pub fn clear_errno() { + unsafe { + (*errno_location()) = 0; + } + } + + pub fn error_string(errno: i32) -> String { + #[cfg(target_os = "linux")] + extern { + #[link_name = "__xpg_strerror_r"] + fn strerror_r(errnum: c_int, buf: *mut c_char, + buflen: size_t) -> c_int; + } + #[cfg(not(target_os = "linux"))] + extern { + fn strerror_r(errnum: c_int, buf: *mut c_char, + buflen: size_t) -> c_int; + } + + let mut buf = [0 as c_char; TMPBUF_SZ]; + + let p = buf.as_mut_ptr(); + unsafe { + if strerror_r(errno as c_int, p, buf.len() as size_t) < 0 { + panic!("strerror_r failure"); + } + + let p = p as *const _; + str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string() + } + } +} diff --git a/src/image.rs b/src/image.rs new file mode 100644 index 0000000..1f32174 --- /dev/null +++ b/src/image.rs @@ -0,0 +1,57 @@ +use std::ffi::CString; +use std::path::Path; + +use std::os::unix::prelude::*; + +use libc::{EINVAL,ENOMEM}; + +/// A raw image. +pub struct Image { + data: *mut ::libraw::libraw_data_t, +} + +impl Drop for Image { + fn drop(&mut self) { + unsafe { + ::libraw::libraw_close(self.data); + } + } +} + +impl Image { + fn new() -> ::Result { + let data = unsafe { + ::libraw::libraw_init(::libraw::LIBRAW_OPIONS_NO_MEMERR_CALLBACK | ::libraw::LIBRAW_OPIONS_NO_DATAERR_CALLBACK) + }; + + if !data.is_null() { + Ok(Image { data: data }) + } + else { + Err(::error::from_raw_os_error(ENOMEM)) + } + } + + /// Opens the raw image file at the specified path. + pub fn open(path: &Path) -> ::Result { + let filename = match CString::new(path.as_os_str().as_bytes()) { + Ok(s) => s, + Err(_) => return Err(::error::from_raw_os_error(EINVAL)) + }; + + let image = try!(Image::new()); + + ::error::os::clear_errno(); + + match unsafe { ::libraw::libraw_open_file(image.data, filename.as_ptr()) } { + ::libraw::LIBRAW_SUCCESS => Ok(image), + ::libraw::LIBRAW_IO_ERROR => { + match ::error::os::errno() { + 0 => Err(::error::from_libraw(::libraw::LIBRAW_IO_ERROR)), + errno => Err(::error::from_raw_os_error(errno)), + } + }, + err => Err(::error::from_libraw(err)), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 37535e3..e3d4d37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,11 @@ extern crate libraw_sys as libraw; extern crate libc; pub use camera::{Cameras,camera_list}; +pub use error::{Error,Result}; +pub use image::{Image}; pub use version::{Version,version}; mod camera; +mod error; +mod image; mod version;