Skip to content

Commit

Permalink
Add XmpMeta::contains_struct_field
Browse files Browse the repository at this point in the history
  • Loading branch information
scouten-adobe committed Oct 23, 2022
1 parent c0531e6 commit ce80cb4
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,23 @@ extern "C" {
return 0;
}

int CXmpMetaDoesStructFieldExist(CXmpMeta* m,
const char* schemaNS,
const char* structName,
const char* fieldNS,
const char* fieldName) {
#ifndef NOOP_FFI
try {
return (m->m.DoesStructFieldExist(schemaNS, structName, fieldNS, fieldName)) ? 1 : 0;
}
catch (...) {
// Intentional no-op.
}
#endif

return 0;
}

const char* CXmpMetaGetArrayItem(CXmpMeta* m,
CXmpError* outError,
const char* schemaNS,
Expand Down
8 changes: 8 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ extern "C" {
prop_name: *const c_char,
) -> c_int;

pub(crate) fn CXmpMetaDoesStructFieldExist(
meta: *const CXmpMeta,
schema_ns: *const c_char,
struct_name: *const c_char,
field_ns: *const c_char,
field_name: *const c_char,
) -> c_int;

pub(crate) fn CXmpMetaGetArrayItem(
meta: *mut CXmpMeta,
out_error: *mut CXmpError,
Expand Down
82 changes: 82 additions & 0 deletions src/tests/xmp_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,88 @@ mod contains_property {
}
}

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

use crate::{xmp_ns, XmpMeta};

const STRUCT_EXAMPLE: &str = r#"
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 7.0-c000 1.000000, 0000/00/00-00:00:00">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpRights="http://ns.adobe.com/xap/1.0/rights/"
xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"
xmpRights:Marked="True">
<Iptc4xmpCore:CreatorContactInfo
Iptc4xmpCore:CiAdrPcode="98110"
Iptc4xmpCore:CiAdrCtry="US"/>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
"#;

#[test]
fn exists() {
let m = XmpMeta::from_str(STRUCT_EXAMPLE).unwrap();
assert!(m.contains_struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode"
));
}

#[test]
fn doesnt_exist() {
let m = XmpMeta::from_str(STRUCT_EXAMPLE).unwrap();
assert!(!m.contains_struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcodx"
));
}

#[test]
fn empty_namespace() {
let m = XmpMeta::from_str(STRUCT_EXAMPLE).unwrap();
assert!(!m.contains_struct_field(
"",
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
"CiAdrPcode"
));
}

#[test]
fn empty_struct_name() {
let m = XmpMeta::from_str(STRUCT_EXAMPLE).unwrap();
assert!(!m.contains_struct_field(xmp_ns::IPTC_CORE, "", xmp_ns::IPTC_CORE, "CiAdrPcode"));
}
#[test]
fn empty_field_namespace() {
let m = XmpMeta::from_str(STRUCT_EXAMPLE).unwrap();
assert!(!m.contains_struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
"",
"CiAdrPcode"
));
}

#[test]
fn empty_field_name() {
let m = XmpMeta::from_str(STRUCT_EXAMPLE).unwrap();
assert!(!m.contains_struct_field(
xmp_ns::IPTC_CORE,
"CreatorContactInfo",
xmp_ns::IPTC_CORE,
""
));
}
}

mod property {
use crate::{tests::fixtures::*, xmp_ns, XmpMeta, XmpValue};

Expand Down
39 changes: 39 additions & 0 deletions src/xmp_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,45 @@ impl XmpMeta {
r != 0
}

/// Returns `true` if the metadata block contains a struct field by this
/// name.
///
/// ## Arguments
///
/// * `struct_ns` and `struct_path`: See [Accessing
/// properties](#accessing-properties).
/// * `field_ns` and `field_name` take the same form (i.e. see [Accessing
/// properties](#accessing-properties) again.)
///
/// ## Error handling
///
/// Any errors (for instance, empty or invalid namespace or property name)
/// are ignored; the function will return `false` in such cases.
pub fn contains_struct_field(
&self,
struct_ns: &str,
struct_path: &str,
field_ns: &str,
field_name: &str,
) -> bool {
let c_struct_ns = CString::new(struct_ns).unwrap_or_default();
let c_struct_name = CString::new(struct_path).unwrap_or_default();
let c_field_ns = CString::new(field_ns).unwrap_or_default();
let c_field_name = CString::new(field_name).unwrap_or_default();

let r = unsafe {
ffi::CXmpMetaDoesStructFieldExist(
self.m,
c_struct_ns.as_ptr(),
c_struct_name.as_ptr(),
c_field_ns.as_ptr(),
c_field_name.as_ptr(),
)
};

r != 0
}

/// Gets a simple string property value.
///
/// ## Arguments
Expand Down

0 comments on commit ce80cb4

Please sign in to comment.