From f80fd2efae8a0b765e4e860cd9a0ef1dc068f5f0 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Mon, 27 Mar 2023 07:19:55 +0000 Subject: [PATCH] Update exif module --- exif/exif.h | 9 +- exif/src/exif.cpp | 42 ++++++++- exif/src/exif_priv.h | 5 + src/exif.rs | 217 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 234 insertions(+), 39 deletions(-) diff --git a/exif/exif.h b/exif/exif.h index 0d0d706..4813428 100644 --- a/exif/exif.h +++ b/exif/exif.h @@ -23,6 +23,8 @@ typedef struct ExifDataItor ExifDataItor; typedef struct ExifDatumRef ExifDatumRef; ///
typedef struct ExifValueRef ExifValueRef; +///
+typedef struct ExifDataMutItor ExifDataMutItor; #if defined _WIN32 && defined WIN32_DLL #if BUILD_DLL #define EXIF_API __declspec(dllexport) @@ -65,7 +67,7 @@ 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_add(ExifDataRef* d, ExifKey* key, ExifValueRef* value); EXIF_API int exif_data_ref_clear(ExifDataRef* d); EXIF_API ExifDataRef* exif_data_get_ref(ExifData* d); EXIF_API ExifData* exif_data_ref_clone(ExifDataRef* d); @@ -74,13 +76,18 @@ EXIF_API long exif_data_ref_get_count(ExifDataRef* d); EXIF_API void exif_data_ref_sort_by_key(ExifDataRef* d); EXIF_API void exif_data_ref_sort_by_tag(ExifDataRef* d); EXIF_API ExifDataItor* exif_data_ref_iter(ExifDataRef* d); +EXIF_API ExifDataMutItor* exif_data_ref_iter_mut(ExifDataRef* d); EXIF_API ExifDatumRef* exif_data_itor_next(ExifDataItor* itor); EXIF_API ExifDatumRef* exif_data_itor_next_back(ExifDataItor* itor); +EXIF_API ExifDatumRef* exif_data_mutitor_next(ExifDataMutItor* itor); +EXIF_API ExifDatumRef* exif_data_mutitor_next_back(ExifDataMutItor* itor); EXIF_API char* exif_datum_key(ExifDatumRef* d); EXIF_API ExifValueRef* exif_datum_value(ExifDatumRef *d); +EXIF_API void exif_datum_set_value(ExifDatumRef* d, ExifValueRef* v); 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); +EXIF_API void exif_free_data_mutitor(ExifDataMutItor* itor); #ifdef __cplusplus } #endif diff --git a/exif/src/exif.cpp b/exif/src/exif.cpp index 9de3513..c85a4aa 100644 --- a/exif/src/exif.cpp +++ b/exif/src/exif.cpp @@ -283,10 +283,11 @@ ExifData* exif_data_new() { return new ExifData; } -int exif_data_ref_add(ExifDataRef* d, ExifKey* key, ExifValue* value) { +int exif_data_ref_add(ExifDataRef* d, ExifKey* key, ExifValueRef* value) { if (!d || !key || !value || !key->key) return 0; auto data = (Exiv2::ExifData*)d; - data->add(*key->key, value->value.get()); + auto v = (Exiv2::Value*)value; + data->add(*key->key, v); return 1; } @@ -362,6 +363,15 @@ ExifDataItor* exif_data_ref_iter(ExifDataRef* d) { return re; } +ExifDataMutItor* exif_data_ref_iter_mut(ExifDataRef* d) { + if (!d) return nullptr; + auto re = new ExifDataMutItor; + re->ref = (Exiv2::ExifData*)d; + re->itor = re->ref->begin(); + re->end = re->ref->end(); + return re; +} + void exif_free_data_itor(ExifDataItor* itor) { if (!itor) return; delete itor; @@ -383,6 +393,22 @@ ExifDatumRef* exif_data_itor_next_back(ExifDataItor* itor) { return (ExifDatumRef*)&data; } +ExifDatumRef* exif_data_mutitor_next(ExifDataMutItor* itor) { + if (!itor->ref) return nullptr; + if (itor->itor == itor->end) return nullptr; + auto& data = (*itor->itor); + itor->itor++; + return (ExifDatumRef*)&data; +} + +ExifDatumRef* exif_data_mutitor_next_back(ExifDataMutItor* itor) { + if (!itor->ref) return nullptr; + if (itor->itor == itor->end) return nullptr; + itor->end--; + auto& data = (*itor->end); + return (ExifDatumRef*)&data; +} + char* exif_datum_key(ExifDatumRef* d) { if (!d) return nullptr; auto data = (Exiv2::Exifdatum*)d; @@ -401,3 +427,15 @@ ExifValueRef* exif_datum_value(ExifDatumRef *d) { return nullptr; } } + +void exif_free_data_mutitor(ExifDataMutItor* itor) { + if (!itor) return; + delete itor; +} + +void exif_datum_set_value(ExifDatumRef* d, ExifValueRef* v) { + if (!d || !v) return; + auto da = (Exiv2::Exifdatum*)d; + auto va = (Exiv2::Value*)v; + da->setValue(va); +} diff --git a/exif/src/exif_priv.h b/exif/src/exif_priv.h index cea32d7..7a1a4f9 100644 --- a/exif/src/exif_priv.h +++ b/exif/src/exif_priv.h @@ -22,4 +22,9 @@ typedef struct ExifDataItor { Exiv2::ExifMetadata::const_iterator itor; Exiv2::ExifMetadata::const_iterator end; } ExifDataItor; +typedef struct ExifDataMutItor { + Exiv2::ExifData* ref; + Exiv2::ExifMetadata::iterator itor; + Exiv2::ExifMetadata::iterator end; +} ExifDataMutItor; #endif diff --git a/src/exif.rs b/src/exif.rs index 248c057..e76106c 100644 --- a/src/exif.rs +++ b/src/exif.rs @@ -1,5 +1,5 @@ use crate::_exif; -use crate::_exif::{ExifDataRef, ExifDatumRef, ExifValueRef}; +pub use crate::_exif::{ExifDataRef, ExifDatumRef, ExifValueRef}; use crate::ext::rawhandle::FromRawHandle; use crate::ext::rawhandle::ToRawHandle; use c_fixed_string::CFixedStr; @@ -16,7 +16,7 @@ use std::ffi::OsStr; use std::fs::copy; #[cfg(test)] use std::fs::create_dir; -use std::iter::{DoubleEndedIterator, Iterator}; +use std::iter::{DoubleEndedIterator, ExactSizeIterator, Iterator}; use std::marker::PhantomData; use std::ops::Deref; use std::ops::DerefMut; @@ -595,6 +595,16 @@ impl ExifDatumRef { Some(s.to_owned()) } + /// Set the value. + pub fn set_value<'a>(&'a mut self, value: &ExifValueRef) { + let data = unsafe { self.to_raw_handle() }; + let v = unsafe { value.to_raw_handle() }; + if data.is_null() || v.is_null() { + return; + } + unsafe { _exif::exif_datum_set_value(data, v) } + } + /// 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. @@ -689,7 +699,7 @@ impl ToRawHandle<_exif::ExifData> for ExifData { impl ExifDataRef { /// Add a data from the supplied key and value pair. /// No duplicate checks are performed, i.e., it is possible to add multiple metadata with the same key. - pub fn add(&mut self, key: &ExifKey, value: &ExifValue) -> Result<(), ()> { + pub fn add(&mut self, key: &ExifKey, value: &ExifValueRef) -> Result<(), ()> { let data = unsafe { self.to_raw_handle() }; let k = unsafe { key.to_raw_handle() }; let v = unsafe { value.to_raw_handle() }; @@ -750,12 +760,44 @@ impl ExifDataRef { pub fn iter<'a>(&'a self) -> Option> { let data = unsafe { self.to_raw_handle() }; + let count = match self.count() { + Some(count) => count, + None => { + return None; + } + }; if data.is_null() { return None; } let r = unsafe { _exif::exif_data_ref_iter(data) }; + if r.is_null() { + return None; + } Some(ExifDataItor { itor: r, + count, + phantom: PhantomData, + }) + } + + pub fn iter_mut<'a>(&'a mut self) -> Option> { + let data = unsafe { self.to_raw_handle() }; + let count = match self.count() { + Some(count) => count, + None => { + return None; + } + }; + if data.is_null() { + return None; + } + let r = unsafe { _exif::exif_data_ref_iter_mut(data) }; + if r.is_null() { + return None; + } + Some(ExifDataMutItor { + itor: r, + count, phantom: PhantomData, }) } @@ -803,6 +845,7 @@ impl ToRawHandle for ExifDataRef { pub struct ExifDataItor<'a> { itor: *mut _exif::ExifDataItor, + count: usize, phantom: PhantomData<&'a _exif::ExifDataItor>, } @@ -842,6 +885,60 @@ impl<'a> DoubleEndedIterator for ExifDataItor<'a> { } } +impl<'a> ExactSizeIterator for ExifDataItor<'a> { + fn len(&self) -> usize { + self.count + } +} + +pub struct ExifDataMutItor<'a> { + itor: *mut _exif::ExifDataMutItor, + count: usize, + phantom: PhantomData<&'a mut _exif::ExifDataMutItor>, +} + +impl<'a> Drop for ExifDataMutItor<'a> { + fn drop(&mut self) { + if !self.itor.is_null() { + unsafe { _exif::exif_free_data_mutitor(self.itor) }; + self.itor = std::ptr::null_mut(); + } + } +} + +impl<'a> Iterator for ExifDataMutItor<'a> { + type Item = &'a mut ExifDatumRef; + fn next(&mut self) -> Option { + if self.itor.is_null() { + return None; + } + let r = unsafe { _exif::exif_data_mutitor_next(self.itor) }; + if r.is_null() { + return None; + } + Some(unsafe { ExifDatumRef::from_raw_handle(r) }) + } +} + +impl<'a> DoubleEndedIterator for ExifDataMutItor<'a> { + fn next_back(&mut self) -> Option { + if self.itor.is_null() { + return None; + } + let r = unsafe { _exif::exif_data_mutitor_next_back(self.itor) }; + if r.is_null() { + return None; + } + Some(unsafe { ExifDatumRef::from_raw_handle(r) }) + } +} + +impl<'a> ExactSizeIterator for ExifDataMutItor<'a> { + fn len(&self) -> usize { + self.count + } +} + /// An image pub struct ExifImage { img: *mut _exif::ExifImage, @@ -1043,43 +1140,91 @@ fn test_exif_data() { v2.read("p1".as_bytes(), None).unwrap(); d.add(&k2, &v2).unwrap(); assert_eq!(Some(2), d.count()); - let mut i = d.iter().unwrap(); - let f = i.next().unwrap(); - assert_eq!(f.key(), Some(String::from("Exif.Image.XPTitle"))); - assert_eq!( - i.next().unwrap().key(), - 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())); + { + let mut i = d.iter().unwrap(); + let f = i.next().unwrap(); + assert_eq!(f.key(), Some(String::from("Exif.Image.XPTitle"))); + assert_eq!( + i.next().unwrap().key(), + 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), + _ => {} } - "Exif.Image.XPTitle" => assert_eq!(i, 1), + } + assert_eq!(i, 2); + let mut i = d.iter().unwrap(); + let f = i.next().unwrap(); + let f2 = i.next().unwrap(); + assert_eq!(f.key(), Some(String::from("Exif.Image.XPTitle"))); + assert_eq!(f2.key(), Some(String::from("Exif.Image.PageName"))); + let mut i = d.iter().unwrap(); + assert_eq!( + i.next_back().unwrap().key(), + Some(String::from("Exif.Image.PageName")) + ); + assert_eq!( + i.next().unwrap().key(), + Some(String::from("Exif.Image.XPTitle")) + ); + assert!(i.next().is_none()); + assert_eq!( + d.iter().unwrap().position(|d| match d.key() { + Some(key) => { + match key.as_str() { + "Exif.Image.PageName" => true, + _ => false, + } + } + None => false, + }), + Some(1) + ); + assert_eq!( + d.iter().unwrap().rposition(|d| match d.key() { + Some(key) => { + match key.as_str() { + "Exif.Image.XPTitle" => true, + _ => false, + } + } + None => false, + }), + Some(0) + ); + } + for i in d.iter_mut().unwrap() { + match i.key() { + Some(key) => match key.as_str() { + "Exif.Image.PageName" => { + let mut v = ExifValue::try_from(ExifTypeID::AsciiString).unwrap(); + v.read("p2".as_bytes(), None).unwrap(); + i.set_value(&v); + } + _ => {} + }, _ => {} } } - assert_eq!(i, 2); - let mut i = d.iter().unwrap(); - let f = i.next().unwrap(); - let f2 = i.next().unwrap(); - assert_eq!(f.key(), Some(String::from("Exif.Image.XPTitle"))); - assert_eq!(f2.key(), Some(String::from("Exif.Image.PageName"))); - let mut i = d.iter().unwrap(); - assert_eq!( - i.next_back().unwrap().key(), - Some(String::from("Exif.Image.PageName")) - ); - assert_eq!( - i.next().unwrap().key(), - Some(String::from("Exif.Image.XPTitle")) - ); - assert!(i.next().is_none()); + let p = d + .iter() + .unwrap() + .nth(1) + .unwrap() + .value() + .unwrap() + .to_string(None); + assert_eq!(p, Some(CString::new("p2").unwrap())); } #[test]