use crate::error::{Error, Result};
use uuid::Uuid;
pub fn ensure_c2pa_urn(id: &str) -> String {
if id.starts_with("urn:c2pa:") {
id.to_string()
} else if let Ok(uuid) = Uuid::parse_str(id) {
format!("urn:c2pa:{}", uuid)
} else {
format!("urn:c2pa:{}", Uuid::new_v4())
}
}
pub fn extract_uuid_from_urn(urn: &str) -> Result<Uuid> {
let parts: Vec<&str> = urn.split(':').collect();
if parts.len() < 3 || parts[0] != "urn" || parts[1] != "c2pa" {
return Err(Error::Validation(format!(
"Invalid C2PA URN format: '{}'",
urn
)));
}
Uuid::parse_str(parts[2])
.map_err(|e| Error::Validation(format!("Invalid UUID in C2PA URN '{}': {}", urn, e)))
}
pub fn validate_c2pa_urn(urn: &str) -> Result<()> {
let parts: Vec<&str> = urn.split(':').collect();
if parts.len() < 3 || parts[0] != "urn" || parts[1] != "c2pa" {
return Err(Error::Validation(format!(
"Invalid C2PA URN format: expected 'urn:c2pa:UUID', got '{}'",
urn
)));
}
if Uuid::parse_str(parts[2]).is_err() {
return Err(Error::Validation(format!(
"Invalid UUID in C2PA URN: '{}'",
parts[2]
)));
}
if parts.len() > 3 {
if parts.len() > 4 {
let version_reason = parts[4];
let vr_parts: Vec<&str> = version_reason.split('_').collect();
if vr_parts.len() != 2 {
return Err(Error::Validation(format!(
"Invalid version_reason format in URN: expected 'version_reason', got '{}'",
version_reason
)));
}
if vr_parts[0].parse::<u32>().is_err() {
return Err(Error::Validation(format!(
"Invalid version number in URN: '{}'",
vr_parts[0]
)));
}
if vr_parts[1].parse::<u32>().is_err() {
return Err(Error::Validation(format!(
"Invalid reason code in URN: '{}'",
vr_parts[1]
)));
}
}
}
Ok(())
}