diff --git a/build.rs b/build.rs index ab36111..c98ee79 100644 --- a/build.rs +++ b/build.rs @@ -154,6 +154,8 @@ fn main() { // included header files changed. .parse_callbacks(Box::new(bindgen::CargoCallbacks)) .no_copy("ExifDataRef") + .no_copy("ExifDatumRef") + .no_copy("ExifValueRef") // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. diff --git a/exif/exif.h b/exif/exif.h index e1d9ba0..fdd7053 100644 --- a/exif/exif.h +++ b/exif/exif.h @@ -21,6 +21,8 @@ typedef struct ExifDataRef ExifDataRef; typedef struct ExifDataItor ExifDataItor; ///
typedef struct ExifDatumRef ExifDatumRef; +///
+typedef struct ExifValueRef ExifValueRef; #if defined _WIN32 && defined WIN32_DLL #if BUILD_DLL #define EXIF_API __declspec(dllexport) @@ -51,15 +53,17 @@ EXIF_API int exif_get_key_default_type_id(ExifKey* key); EXIF_API void exif_free(void* v); EXIF_API void exif_free_key(ExifKey* key); EXIF_API ExifValue* exif_create_value(int type_id); -EXIF_API int exif_get_value_type_id(ExifValue* value); -EXIF_API long exif_get_value_count(ExifValue* value); -EXIF_API long exif_get_value_size(ExifValue* value); -EXIF_API long exif_get_value_size_data_area(ExifValue *value); -EXIF_API int exif_value_read(ExifValue* value, const uint8_t* bytes, long len, int byte_order); -EXIF_API int exif_get_value_ok(ExifValue* value); -EXIF_API char* exif_value_to_string(ExifValue* value, size_t* len); -EXIF_API char* exif_value_to_string2(ExifValue* value, size_t* len, long i); -EXIF_API int64_t exif_value_to_int64(ExifValue* value, long i); +EXIF_API ExifValueRef* exif_value_get_ref(ExifValue* value); +EXIF_API int exif_get_value_type_id(ExifValueRef* value); +EXIF_API long exif_get_value_count(ExifValueRef* value); +EXIF_API long exif_get_value_size(ExifValueRef* value); +EXIF_API long exif_get_value_size_data_area(ExifValueRef *value); +EXIF_API int exif_value_read(ExifValueRef* value, const uint8_t* bytes, long len, int byte_order); +EXIF_API int exif_get_value_ok(ExifValueRef* value); +EXIF_API char* exif_value_to_string(ExifValueRef* value, size_t* len); +EXIF_API char* exif_value_to_string2(ExifValueRef* value, size_t* len, long i); +EXIF_API int64_t exif_value_to_int64(ExifValueRef* value, long i); +EXIF_API ExifValue* exif_value_ref_clone(ExifValueRef* value); EXIF_API ExifData* exif_data_new(); EXIF_API int exif_data_ref_add(ExifDataRef* d, ExifKey* key, ExifValue* value); EXIF_API int exif_data_ref_clear(ExifDataRef* d); @@ -72,6 +76,7 @@ EXIF_API void exif_data_ref_sort_by_tag(ExifDataRef* d); EXIF_API ExifDataItor* exif_data_ref_iter(ExifDataRef* d); EXIF_API ExifDatumRef* exif_data_itor_next(ExifDataItor* itor); EXIF_API char* exif_datum_key(ExifDatumRef* d); +EXIF_API ExifValueRef* exif_datum_value(ExifDatumRef *d); EXIF_API void exif_free_value(ExifValue* value); EXIF_API void exif_free_data(ExifData* d); EXIF_API void exif_free_data_itor(ExifDataItor* itor); diff --git a/exif/src/exif.cpp b/exif/src/exif.cpp index cd410e0..acd7915 100644 --- a/exif/src/exif.cpp +++ b/exif/src/exif.cpp @@ -196,38 +196,44 @@ end: return nullptr; } -int exif_get_value_type_id(ExifValue* value) { - if (!value) return -1; +ExifValueRef* exif_value_get_ref(ExifValue* value) { + if (!value) return nullptr; + value->ref.value = value->value.get(); + return &value->ref; +} + +int exif_get_value_type_id(ExifValueRef* value) { + if (!value || !value->value) return -1; return value->value->typeId(); } -long exif_get_value_count(ExifValue* value) { - if (!value) return -1; +long exif_get_value_count(ExifValueRef* value) { + if (!value || !value->value) return -1; return value->value->count(); } -long exif_get_value_size(ExifValue* value) { - if (!value) return -1; +long exif_get_value_size(ExifValueRef* value) { + if (!value || !value->value) return -1; return value->value->size(); } -long exif_get_value_size_data_area(ExifValue* value) { - if (!value) return -1; +long exif_get_value_size_data_area(ExifValueRef* value) { + if (!value || !value->value) return -1; return value->value->sizeDataArea(); } -int exif_value_read(ExifValue* value, const uint8_t* bytes, long len, int byte_order) { - if (!value || !bytes) return -1; +int exif_value_read(ExifValueRef* value, const uint8_t* bytes, long len, int byte_order) { + if (!value || !bytes || !value->value) return -1; return value->value->read(bytes, len, static_cast(byte_order)); } -int exif_get_value_ok(ExifValue* value) { - if (!value) return 0; +int exif_get_value_ok(ExifValueRef* value) { + if (!value || !value->value) return 0; return value->value->ok() ? 1 : 0; } -char* exif_value_to_string(ExifValue* value, size_t* len) { - if (!value || !len) return nullptr; +char* exif_value_to_string(ExifValueRef* value, size_t* len) { + if (!value || !len || !value->value) return nullptr; auto s = value->value->toString(); *len = s.size(); char* tmp = nullptr; @@ -235,8 +241,8 @@ char* exif_value_to_string(ExifValue* value, size_t* len) { return tmp; } -char* exif_value_to_string2(ExifValue* value, size_t* len, long i) { - if (!value || !len) return nullptr; +char* exif_value_to_string2(ExifValueRef* value, size_t* len, long i) { + if (!value || !len || !value->value) return nullptr; auto s = value->value->toString(i); *len = s.size(); char* tmp = nullptr; @@ -244,11 +250,26 @@ char* exif_value_to_string2(ExifValue* value, size_t* len, long i) { return tmp; } -int64_t exif_value_to_int64(ExifValue* value, long i) { - if (!value) return -1; +int64_t exif_value_to_int64(ExifValueRef* value, long i) { + if (!value || !value->value) return -1; return value->value->toInt64(i); } +ExifValue* exif_value_ref_clone(ExifValueRef* value) { + if (!value || !value->value) return nullptr; + ExifValue* v = new ExifValue; + try { + v->value = value->value->clone(); + } catch (std::exception& e) { + printf("%s\n", e.what()); + goto end; + } + return v; +end: + if (v) delete v; + return nullptr; +} + ExifData* exif_data_new() { return new ExifData; } @@ -299,6 +320,7 @@ long exif_data_ref_get_count(ExifDataRef* d) { void exif_free_value(ExifValue* value) { if (!value) return; + value->ref.value = nullptr; delete value; } @@ -342,8 +364,19 @@ ExifDatumRef* exif_data_itor_next(ExifDataItor* itor) { } char* exif_datum_key(ExifDatumRef* d) { - if (!d->data) return nullptr; + if (!d || !d->data) return nullptr; char* re = nullptr; if (!string2char(d->data->key(), re)) return nullptr; return re; } + +ExifValueRef* exif_datum_value(ExifDatumRef *d) { + if (!d || !d->data) return nullptr; + try { + d->ref.value = (Exiv2::Value*)&d->data->value(); + } catch (std::exception& e) { + printf("%s\n", e.what()); + return nullptr; + } + return &d->ref; +} diff --git a/exif/src/exif_priv.h b/exif/src/exif_priv.h index ce92bc3..00e058b 100644 --- a/exif/src/exif_priv.h +++ b/exif/src/exif_priv.h @@ -11,20 +11,25 @@ typedef struct ExifImage { typedef struct ExifKey { Exiv2::ExifKey* key = nullptr; } ExifKey; +typedef struct ExifValueRef { + Exiv2::Value* value; +} ExifValueRef; typedef struct ExifValue { Exiv2::Value::UniquePtr value; + ExifValueRef ref; } ExifValue; typedef struct ExifData { Exiv2::ExifData data; ExifDataRef ref; } ExifData; -typedef struct ExifDatum { - Exiv2::Exifdatum data; - ExifDataRef ref; -} ExifDatum; typedef struct ExifDatumRef { Exiv2::Exifdatum* data; + ExifValueRef ref; } ExifDatumRef; +typedef struct ExifDatum { + Exiv2::Exifdatum data; + ExifDatumRef ref; +} ExifDatum; typedef struct ExifDataItor { ExifDataRef ref; ExifDatumRef ref2; diff --git a/src/exif.rs b/src/exif.rs index b7cbf73..25fefa6 100644 --- a/src/exif.rs +++ b/src/exif.rs @@ -1,5 +1,5 @@ use crate::_exif; -use crate::_exif::{ExifDataRef, ExifDatumRef}; +use crate::_exif::{ExifDataRef, ExifDatumRef, ExifValueRef}; use crate::ext::rawhandle::FromRawHandle; use crate::ext::rawhandle::ToRawHandle; use c_fixed_string::CFixedStr; @@ -323,6 +323,12 @@ pub struct ExifValue { value: *mut _exif::ExifValue, } +impl ExifValue { + pub unsafe fn from_raw_pointer(value: *mut _exif::ExifValue) -> Self { + Self { value } + } +} + impl TryFrom for ExifValue { type Error = (); fn try_from(value: ExifTypeID) -> Result { @@ -346,10 +352,40 @@ impl TryFrom for ExifValue { } } +impl Borrow for ExifValue { + fn borrow(&self) -> &ExifValueRef { + self.deref() + } +} + +impl BorrowMut for ExifValue { + fn borrow_mut(&mut self) -> &mut ExifValueRef { + self.deref_mut() + } +} + +impl Deref for ExifValue { + type Target = ExifValueRef; + fn deref(&self) -> &Self::Target { + unsafe { + ExifValueRef::from_const_handle( + _exif::exif_value_get_ref(self.to_raw_handle()) as *const ExifValueRef + ) + } + } +} + +impl DerefMut for ExifValue { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { ExifValueRef::from_raw_handle(_exif::exif_value_get_ref(self.to_raw_handle())) } + } +} + impl Drop for ExifValue { fn drop(&mut self) { if !self.value.is_null() { unsafe { _exif::exif_free_value(self.value) }; + self.value = std::ptr::null_mut(); } } } @@ -361,13 +397,14 @@ impl ToRawHandle<_exif::ExifValue> for ExifValue { } #[allow(dead_code)] -impl ExifValue { +impl ExifValueRef { /// Return the type identifier (Exif data format type). pub fn type_id(&self) -> Option { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return None; } - let r = unsafe { _exif::exif_get_value_type_id(self.value) }; + let r = unsafe { _exif::exif_get_value_type_id(value) }; if r == 0 { return None; } @@ -380,10 +417,11 @@ impl ExifValue { /// Return the number of components of the value. pub fn count(&self) -> Option { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return None; } - let r = unsafe { _exif::exif_get_value_count(self.value) }; + let r = unsafe { _exif::exif_get_value_count(value) }; if r < 0 { return None; } @@ -392,10 +430,11 @@ impl ExifValue { /// Return the size of the value in bytes. pub fn size(&self) -> Option { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return None; } - let r = unsafe { _exif::exif_get_value_size(self.value) }; + let r = unsafe { _exif::exif_get_value_size(value) }; if r < 0 { return None; } @@ -404,10 +443,11 @@ impl ExifValue { /// Return the size of the data area, 0 if there is none. pub fn size_data_area(&self) -> Option { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return None; } - let r = unsafe { _exif::exif_get_value_size_data_area(self.value) }; + let r = unsafe { _exif::exif_get_value_size_data_area(value) }; if r < 0 { return None; } @@ -418,7 +458,8 @@ impl ExifValue { /// * `buf` - Buffer /// * `byte_order` - Applicable byte order (little or big endian). Default: invaild. pub fn read(&mut self, buf: &[u8], byte_order: Option) -> Result<(), ()> { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return Err(()); } let buf_len = buf.len() as c_long; @@ -428,7 +469,7 @@ impl ExifValue { }; let order = order.int_value(); let ptr = buf.as_ptr(); - let r = unsafe { _exif::exif_value_read(self.value, ptr, buf_len, order) }; + let r = unsafe { _exif::exif_value_read(value, ptr, buf_len, order) }; if r == 0 { Ok(()) } else { @@ -439,7 +480,8 @@ impl ExifValue { /// Return the value / n-th component of the value as a string /// * `n` - specify the component, if None, return whole value pub fn to_string(&self, n: Option) -> Option { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return None; } if n.is_some() { @@ -457,9 +499,9 @@ impl ExifValue { return None; } let r = if n.is_none() { - unsafe { _exif::exif_value_to_string(self.value, ptr) } + unsafe { _exif::exif_value_to_string(value, ptr) } } else { - unsafe { _exif::exif_value_to_string2(self.value, ptr, n.unwrap() as c_long) } + unsafe { _exif::exif_value_to_string2(value, ptr, n.unwrap() as c_long) } }; if r.is_null() { return None; @@ -476,16 +518,18 @@ impl ExifValue { /// Check the ok status indicator. /// After a `to` conversion, this indicator shows whether the conversion was successful. pub fn ok(&self) -> bool { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return false; } - let r = unsafe { _exif::exif_get_value_ok(self.value) }; + let r = unsafe { _exif::exif_get_value_ok(value) }; r != 0 } /// Convert the n-th component of the value to a int64 pub fn to_int64(&self, n: usize) -> Option { - if self.value.is_null() { + let value = unsafe { self.to_raw_handle() }; + if value.is_null() { return None; } let c = self.count(); @@ -496,7 +540,7 @@ impl ExifValue { if n >= c { return None; } - let r = unsafe { _exif::exif_value_to_int64(self.value, n as c_long) }; + let r = unsafe { _exif::exif_value_to_int64(value, n as c_long) }; if !self.ok() { return None; } @@ -504,6 +548,30 @@ impl ExifValue { } } +impl ToRawHandle for ExifValueRef { + unsafe fn to_raw_handle(&self) -> *mut ExifValueRef { + self.to_const_handle() as *mut ExifValueRef + } + unsafe fn to_const_handle(&self) -> *const ExifValueRef { + self + } +} + +impl ToOwned for ExifValueRef { + type Owned = ExifValue; + fn to_owned(&self) -> Self::Owned { + let v = unsafe { self.to_raw_handle() }; + if v.is_null() { + panic!("ExifValue reference is null."); + } + let r = unsafe { _exif::exif_value_ref_clone(v) }; + if r.is_null() { + panic!("Failed to convert ExifValueRef to ExifValue"); + } + unsafe { ExifValue::from_raw_pointer(r) } + } +} + #[allow(dead_code)] impl ExifDatumRef { /// Return the key of the Exifdatum. @@ -526,6 +594,22 @@ impl ExifDatumRef { let s = s.unwrap(); Some(s.to_owned()) } + + /// Return a constant reference to the value. + /// + /// This method is provided mostly for convenient and versatile output of the value which can (to some extent) be formatted through standard stream manipulators. + /// An Error is thrown if the value is not set; as an alternative to catching it, one can use count() to check if there is any data before calling this method. + pub fn value<'a>(&'a self) -> Option<&'a ExifValueRef> { + let data = unsafe { self.to_raw_handle() }; + if data.is_null() { + return None; + } + let r = unsafe { _exif::exif_datum_value(data) }; + if r.is_null() { + return None; + } + Some(unsafe { ExifValueRef::from_const_handle(r as *const ExifValueRef) }) + } } impl ToRawHandle for ExifDatumRef { @@ -731,20 +815,8 @@ impl<'a> Drop for ExifDataItor<'a> { } } -pub struct ExifDatumConstRef<'a> { - r: *mut ExifDatumRef, - phantom: PhantomData<&'a ExifDatumRef>, -} - -impl<'a> Deref for ExifDatumConstRef<'a> { - type Target = ExifDatumRef; - fn deref(&self) -> &Self::Target { - unsafe { ExifDatumRef::from_const_handle(self.r as *const ExifDatumRef) } - } -} - impl<'a> Iterator for ExifDataItor<'a> { - type Item = ExifDatumConstRef<'a>; + type Item = &'a ExifDatumRef; fn next(&mut self) -> Option { if self.itor.is_null() { return None; @@ -753,10 +825,7 @@ impl<'a> Iterator for ExifDataItor<'a> { if r.is_null() { return None; } - Some(ExifDatumConstRef { - r, - phantom: PhantomData, - }) + Some(unsafe { ExifDatumRef::from_const_handle(r as *const ExifDatumRef) }) } } @@ -793,7 +862,7 @@ impl ExifImage { /// Returns a read only [ExifData] ([ExifDataRef]) instance containing currently buffered Exif data. /// The Exif data in the returned instance will be written to the image when [Self::write_metadata()] is called. - pub fn exif_data(&self) -> Option<&ExifDataRef> { + pub fn exif_data<'a>(&'a self) -> Option<&'a ExifDataRef> { if self.img.is_null() { return None; } @@ -806,7 +875,7 @@ impl ExifImage { /// Returns an ExifData instance containing currently buffered Exif data. /// The Exif data in the returned instance will be written to the image when [Self::write_metadata()] is called. - pub fn exif_data_as_mut(&mut self) -> Option<&mut ExifDataRef> { + pub fn exif_data_as_mut<'a>(&'a mut self) -> Option<&'a mut ExifDataRef> { if self.img.is_null() { return None; } @@ -920,9 +989,25 @@ fn test_exif_value() { assert_eq!(Some(4), v.size()); assert_eq!(Some(CString::new("116").unwrap()), v.to_string(Some(0))); let mut v2 = ExifValue::try_from(ExifTypeID::SLongLong).unwrap(); - v2.read(&(102345 as i64).to_le_bytes(), Some(ExifByteOrder::Little)) + v2.read(&(102345i64).to_le_bytes(), Some(ExifByteOrder::Little)) .unwrap(); assert_eq!(Some(8), v2.count()); + let v3: &ExifValueRef = &v2; + assert_eq!( + v3.to_string(None), + Some(CString::new("201 143 1 0 0 0 0 0").unwrap()) + ); + let mut v4 = v3.to_owned(); + v4.read(&(102346i64).to_le_bytes(), Some(ExifByteOrder::Little)) + .unwrap(); + assert_eq!( + v3.to_string(None), + Some(CString::new("201 143 1 0 0 0 0 0").unwrap()) + ); + assert_eq!( + v4.to_string(None), + Some(CString::new("202 143 1 0 0 0 0 0").unwrap()) + ); } #[test] @@ -953,6 +1038,20 @@ fn test_exif_data() { Some(String::from("Exif.Image.PageName")) ); assert!(i.next().is_none()); + let mut i = 0; + for data in d.iter().unwrap() { + i += 1; + match data.key().unwrap().as_str() { + "Exif.Image.PageName" => { + assert_eq!(i, 2); + let v = data.value().unwrap(); + assert_eq!(v.to_string(None), Some(CString::new("p1").unwrap())); + } + "Exif.Image.XPTitle" => assert_eq!(i, 1), + _ => {} + } + } + assert_eq!(i, 2); } #[test]