diff --git a/src/tests/xmp_meta.rs b/src/tests/xmp_meta.rs index bc3fc0a..c46ba64 100644 --- a/src/tests/xmp_meta.rs +++ b/src/tests/xmp_meta.rs @@ -144,6 +144,23 @@ mod set_property { assert_eq!(err.error_type, XmpErrorType::BadXPath); assert_eq!(err.debug_message, "Empty property name"); } + + #[test] + fn error_nul_in_name() { + let mut m = XmpMeta::from_file(fixture_path("Purple Square.psd")).unwrap(); + + XmpMeta::register_namespace("http://purl.org/dc/terms/", "dcterms").unwrap(); + + let err = m + .set_property("http://purl.org/dc/terms/", "x\0x", "blah") + .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 does_property_exist { @@ -200,4 +217,20 @@ mod set_property_date { assert_eq!(err.error_type, XmpErrorType::BadSchema); assert_eq!(err.debug_message, "Empty schema namespace URI"); } + + #[test] + fn error_nul_in_name() { + let mut m = XmpMeta::from_file(fixture_path("Purple Square.psd")).unwrap(); + let updated_time = XmpDateTime::current().unwrap(); + + let err = m + .set_property_date("x\0x", "MetadataDate", &updated_time) + .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" + ); + } } diff --git a/src/xmp_error.rs b/src/xmp_error.rs index 6de0d8b..1f2a056 100644 --- a/src/xmp_error.rs +++ b/src/xmp_error.rs @@ -11,12 +11,15 @@ // specific language governing permissions and limitations under // each license. -use std::{ffi::CStr, fmt}; - -use num_enum::FromPrimitive; -use thiserror::Error; - -use crate::ffi::CXmpError; +use { + crate::ffi::CXmpError, + num_enum::FromPrimitive, + std::{ + ffi::{CStr, NulError}, + fmt, + }, + thiserror::Error, +}; /// Describes error conditions returned by most XMP Toolkit operations. #[derive(Debug)] @@ -51,6 +54,15 @@ impl XmpError { } } +impl From for XmpError { + fn from(_: NulError) -> Self { + XmpError { + error_type: XmpErrorType::NulInRustString, + debug_message: "Unable to convert to C string because a NUL byte was found".to_owned(), + } + } +} + impl fmt::Display for XmpError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { if self.debug_message.is_empty() { @@ -263,6 +275,11 @@ pub enum XmpErrorType { /// PNG format error. #[error("PNG format error")] BadPng = 213, + + // --- Rust-specific errors --- + /// Can not convert from Rust string to C string because a NUL byte was found. + #[error("Unable to convert to C string because a NUL byte was found")] + NulInRustString = -432, } /// A specialized `Result` type for XMP Toolkit operations. diff --git a/src/xmp_meta.rs b/src/xmp_meta.rs index 81e6dd9..0a1cab4 100644 --- a/src/xmp_meta.rs +++ b/src/xmp_meta.rs @@ -158,9 +158,9 @@ impl XmpMeta { prop_name: &str, prop_value: &str, ) -> XmpResult<()> { - let c_ns = CString::new(schema_ns).unwrap(); - let c_name = CString::new(prop_name).unwrap(); - let c_value = CString::new(prop_value).unwrap(); + let c_ns = CString::new(schema_ns)?; + let c_name = CString::new(prop_name)?; + let c_value = CString::new(prop_value)?; let mut err = ffi::CXmpError::default(); unsafe { @@ -196,8 +196,8 @@ impl XmpMeta { prop_name: &str, prop_value: &XmpDateTime, ) -> XmpResult<()> { - let c_ns = CString::new(schema_ns).unwrap(); - let c_name = CString::new(prop_name).unwrap(); + let c_ns = CString::new(schema_ns)?; + let c_name = CString::new(prop_name)?; let mut err = ffi::CXmpError::default(); unsafe {