From fc8b8966dac61f38983816e7cdfd64ddc5ec3352 Mon Sep 17 00:00:00 2001 From: Eric Scouten Date: Thu, 27 Oct 2022 13:29:27 -0700 Subject: [PATCH] Add `XmpMeta::compose_array_item_path` (#119) --- src/ffi.cpp | 24 ++++++++++++++++++++++++ src/ffi.rs | 7 +++++++ src/tests/xmp_meta.rs | 37 +++++++++++++++++++++++++++++++++++++ src/xmp_meta.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/src/ffi.cpp b/src/ffi.cpp index b65fd8d..cff2243 100644 --- a/src/ffi.cpp +++ b/src/ffi.cpp @@ -882,6 +882,30 @@ extern "C" { #endif } + const char* CXmpMetaComposeArrayItemPath(CXmpError* outError, + const char* schemaNS, + const char* arrayName, + AdobeXMPCommon::int32 index) { + #ifndef NOOP_FFI + try { + std::string resultPath; + SXMPUtils::ComposeArrayItemPath(schemaNS, + arrayName, + index, + &resultPath); + + return copyStringForResult(resultPath); + } + catch (XMP_Error& e) { + copyErrorForResult(e, outError); + } + catch (...) { + signalUnknownError(outError); + } + #endif + + return NULL; + } const char* CXmpMetaComposeStructFieldPath(CXmpError* outError, const char* schemaNS, diff --git a/src/ffi.rs b/src/ffi.rs index fbf53c5..d714672 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -372,6 +372,13 @@ extern "C" { name: *const c_char, ); + pub(crate) fn CXmpMetaComposeArrayItemPath( + out_error: *mut CXmpError, + schema_ns: *const c_char, + array_name: *const c_char, + index: i32, + ) -> *const c_char; + pub(crate) fn CXmpMetaComposeStructFieldPath( out_error: *mut CXmpError, schema_ns: *const c_char, diff --git a/src/tests/xmp_meta.rs b/src/tests/xmp_meta.rs index efd0337..deb3b6e 100644 --- a/src/tests/xmp_meta.rs +++ b/src/tests/xmp_meta.rs @@ -1790,6 +1790,43 @@ mod name { } } +mod compose_array_index_path { + use crate::{xmp_ns, XmpErrorType, XmpMeta}; + + #[test] + fn happy_path() { + assert_eq!( + XmpMeta::compose_array_item_path(xmp_ns::XMP, "ArrayName", 4).unwrap(), + "ArrayName[4]" + ); + } + + #[test] + fn last_item() { + assert_eq!( + XmpMeta::compose_array_item_path(xmp_ns::XMP, "ArrayName", XmpMeta::LAST_ITEM).unwrap(), + "ArrayName[last()]" + ); + } + + #[test] + fn zero_index() { + // This isn't technically allowed, but C++ XMP Toolkit doesn't flag it. + assert_eq!( + XmpMeta::compose_array_item_path(xmp_ns::XMP, "ArrayName", 0).unwrap(), + "ArrayName[0]" + ); + } + + #[test] + fn negative_index() { + let err = XmpMeta::compose_array_item_path(xmp_ns::XMP, "ArrayName", -4).unwrap_err(); + + assert_eq!(err.error_type, XmpErrorType::BadParam); + assert_eq!(err.debug_message, "Array index out of bounds"); + } +} + mod compose_struct_field_path { use crate::{xmp_ns, XmpMeta}; diff --git a/src/xmp_meta.rs b/src/xmp_meta.rs index 02fa939..bb4f089 100644 --- a/src/xmp_meta.rs +++ b/src/xmp_meta.rs @@ -58,6 +58,10 @@ impl Drop for XmpMeta { } impl XmpMeta { + /// Special index value which references the last item in an array, + /// regardless of the array index. + pub const LAST_ITEM: i32 = -1; + /// Creates a new, empty metadata struct. /// /// An error result from this function is unlikely but possible @@ -1005,6 +1009,44 @@ impl XmpMeta { } } + /// Composes the path expression for an item in an array. + /// + /// ## Arguments + /// + /// * `array_ns` and `array_path`: See [Accessing + /// properties](#accessing-properties). + /// * `item_index`: The index of the desired item. Use + /// [`XmpMeta::LAST_ITEM`] to specify the last existing array item. + /// **IMPORTANT:** Indices in XMP are 1-based, not zero-based as in most + /// of Rust. + /// + /// ## Return + /// + /// If successful, the returned string is in the form + /// `array_name[array_index]`. + pub fn compose_array_item_path( + array_ns: &str, + array_path: &str, + index: i32, + ) -> XmpResult { + let c_array_ns = CString::new(array_ns).unwrap_or_default(); + let c_array_name = CString::new(array_path).unwrap_or_default(); + + let mut err = ffi::CXmpError::default(); + + unsafe { + let result = CXmpString::from_ptr(ffi::CXmpMetaComposeArrayItemPath( + &mut err, + c_array_ns.as_ptr(), + c_array_name.as_ptr(), + index, + )); + + XmpError::raise_from_c(&err)?; + Ok(result.as_string()) + } + } + /// Composes the path expression for a field in a struct. /// /// ## Arguments