Skip to content

Commit

Permalink
Add XmpMeta::set_struct_field
Browse files Browse the repository at this point in the history
  • Loading branch information
scouten-adobe committed Oct 26, 2022
1 parent a2e8291 commit 7e117e7
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,6 @@ extern "C" {
#endif
}


const char* CXmpMetaGetStructField(CXmpMeta* m,
CXmpError* outError,
const char* schemaNS,
Expand Down Expand Up @@ -728,6 +727,28 @@ extern "C" {
return NULL;
}

void CXmpMetaSetStructField(CXmpMeta* m,
CXmpError* outError,
const char* schemaNS,
const char* structName,
const char* fieldNS,
const char* fieldName,
const char* itemValue,
AdobeXMPCommon::uint32 itemOptions) {
#ifndef NOOP_FFI
try {
m->m.SetStructField(schemaNS, structName, fieldNS, fieldName,
itemValue, itemOptions);
}
catch (XMP_Error& e) {
copyErrorForResult(e, outError);
}
catch (...) {
signalUnknownError(outError);
}
#endif
}

int CXmpMetaDoesPropertyExist(CXmpMeta* m,
const char* schemaNS,
const char* propName) {
Expand Down
11 changes: 11 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,17 @@ extern "C" {
item_options: u32,
);

pub(crate) fn CXmpMetaSetStructField(
meta: *mut CXmpMeta,
out_error: *mut CXmpError,
schema_ns: *const c_char,
struct_name: *const c_char,
field_ns: *const c_char,
field_name: *const c_char,
item_value: *const c_char,
item_options: u32,
);

pub(crate) fn CXmpMetaDoesPropertyExist(
meta: *const CXmpMeta,
schema_ns: *const c_char,
Expand Down
132 changes: 132 additions & 0 deletions src/tests/xmp_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,138 @@ mod append_array_item {
}
}

mod set_struct_field {
use std::str::FromStr;

use crate::{tests::fixtures, xmp_ns, xmp_value::xmp_prop, XmpErrorType, XmpMeta, XmpValue};

#[test]
fn happy_path() {
let mut m = XmpMeta::from_str(fixtures::STRUCT_EXAMPLE).unwrap();

assert_eq!(
m.struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode"
)
.unwrap(),
XmpValue {
value: "98110".to_owned(),
options: 0
}
);

m.set_struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode",
&XmpValue::from("95110"),
)
.unwrap();

assert_eq!(
m.struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode"
)
.unwrap(),
XmpValue {
value: "95110".to_owned(),
options: 0
}
);
}

#[test]
fn item_options() {
let mut m = XmpMeta::from_str(fixtures::STRUCT_EXAMPLE).unwrap();

m.set_struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode",
&XmpValue::from("95110").set_is_uri(true),
)
.unwrap();

assert_eq!(
m.struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode"
)
.unwrap(),
XmpValue {
value: "95110".to_owned(),
options: xmp_prop::VALUE_IS_URI
}
);
}

#[test]
fn init_fail() {
let mut m = XmpMeta::new_fail();

let err = m
.set_struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode",
&XmpValue::from("95110"),
)
.unwrap_err();

assert_eq!(err.error_type, XmpErrorType::NoCppToolkit);
}

#[test]
fn error_empty_struct_name() {
let mut m = XmpMeta::default();

let err = m
.set_struct_field(
xmp_ns::IPTC_CORE,
"",
xmp_ns::IPTC_CORE,
"CiAdrPcode",
&XmpValue::from("95110"),
)
.unwrap_err();

assert_eq!(err.error_type, XmpErrorType::BadXPath);
assert_eq!(err.debug_message, "Empty struct name");
}

#[test]
fn error_nul_in_name() {
let mut m = XmpMeta::default();

let err = m
.set_struct_field(
xmp_ns::IPTC_CORE,
"x\0x",
xmp_ns::IPTC_CORE,
"CiAdrPcode",
&XmpValue::from("95110"),
)
.unwrap_err();

assert_eq!(err.error_type, XmpErrorType::NulInRustString);
assert_eq!(
err.debug_message,
"Unable to convert to C string because a NUL byte was found"
);
}
}

mod localized_text {
use std::str::FromStr;

Expand Down
53 changes: 53 additions & 0 deletions src/xmp_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,59 @@ impl XmpMeta {
}
}

/// Creates or sets the value of a field within a nested structure,
/// using a string value.
///
/// Use this function to set a value within an existing structure,
/// create a new field within an existing structure, or create an
/// empty structure of any depth. If you set a field in a structure
/// that does not exist, the structure is automatically created.
///
/// Use [`XmpMeta::compose_struct_field_path()`] to create a complex path.
///
/// ## Arguments
///
/// * `namespace` and `struct_name`: See [Accessing
/// properties](#accessing-properties).
/// * `field_ns` and `field_name` take the same form (i.e. see [Accessing
/// properties](#accessing-properties) again.)
/// * `item_value`: Contains value and flags for the item to be added to the
/// array.
pub fn set_struct_field(
&mut self,
namespace: &str,
struct_name: &str,
field_ns: &str,
field_name: &str,
item_value: &XmpValue<String>,
) -> XmpResult<()> {
if let Some(m) = self.m {
let c_struct_ns = CString::new(namespace)?;
let c_struct_name = CString::new(struct_name.as_bytes())?;
let c_field_ns = CString::new(field_ns)?;
let c_field_name = CString::new(field_name.as_bytes())?;
let c_item_value = CString::new(item_value.value.as_bytes())?;
let mut err = ffi::CXmpError::default();

unsafe {
ffi::CXmpMetaSetStructField(
m,
&mut err,
c_struct_ns.as_ptr(),
c_struct_name.as_ptr(),
c_field_ns.as_ptr(),
c_field_name.as_ptr(),
c_item_value.as_ptr(),
item_value.options,
);
}

XmpError::raise_from_c(&err)
} else {
Err(no_cpp_toolkit())
}
}

/// Retrieves information about a selected item from an alt-text array.
///
/// Localized text properties are stored in alt-text arrays. They allow
Expand Down

0 comments on commit 7e117e7

Please sign in to comment.