use std::io::Cursor;
use c2pa::{Context, Reader, ValidationState};
use crate::binding::data_hash_exclusions;
use crate::error::Error;
use crate::reader::read_manifest;
const FONT_MIME: &str = "font/sfnt";
#[derive(Debug, Clone)]
pub struct Validation {
pub hard_binding_valid: bool,
pub state: ValidationState,
pub success_codes: Vec<String>,
pub failure_codes: Vec<String>,
pub manifest_json: String,
}
pub fn validate(font: &[u8]) -> Result<Validation, Error> {
let store = read_manifest(font)?;
let reader = Reader::from_context(Context::new())
.with_manifest_data_and_stream(&store, FONT_MIME, Cursor::new(font))
.map_err(|e| Error::Validation(e.to_string()))?;
let mut success_codes = Vec::new();
let mut failure_codes = Vec::new();
if let Some(results) = reader.validation_results() {
if let Some(active) = results.active_manifest() {
success_codes = active
.success()
.iter()
.map(|s| s.code().to_string())
.collect();
failure_codes = active
.failure()
.iter()
.map(|s| s.code().to_string())
.collect();
}
}
let hard_binding_valid = hard_binding_valid(font, &success_codes, &failure_codes);
Ok(Validation {
hard_binding_valid,
state: reader.validation_state(),
success_codes,
failure_codes,
manifest_json: reader.json(),
})
}
fn hard_binding_valid(font: &[u8], success: &[String], failure: &[String]) -> bool {
if data_hash_exclusions(font).is_err() {
return false;
}
let matched = success.iter().any(|c| c == "assertion.dataHash.match");
let broken = failure.iter().any(|c| c.starts_with("assertion.dataHash"));
matched && !broken
}