use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyBytes;
use crate::{
data_hash_exclusions, embed_manifest, fill_manifest, read_manifest, read_manifest_uri,
remove_manifest, reserve_manifest, verify, ManifestSource,
};
fn map_err(e: crate::Error) -> PyErr {
PyValueError::new_err(e.to_string())
}
#[pyfunction]
fn embed_manifest_store<'py>(
py: Python<'py>,
font: &[u8],
manifest_store: Vec<u8>,
) -> PyResult<Bound<'py, PyBytes>> {
let out = embed_manifest(font, ManifestSource::embedded(manifest_store)).map_err(map_err)?;
Ok(PyBytes::new(py, &out))
}
#[pyfunction]
fn embed_remote<'py>(py: Python<'py>, font: &[u8], uri: &str) -> PyResult<Bound<'py, PyBytes>> {
let out = embed_manifest(font, ManifestSource::remote(uri)).map_err(map_err)?;
Ok(PyBytes::new(py, &out))
}
#[pyfunction]
fn read_manifest_store<'py>(py: Python<'py>, font: &[u8]) -> PyResult<Bound<'py, PyBytes>> {
let out = read_manifest(font).map_err(map_err)?;
Ok(PyBytes::new(py, &out))
}
#[pyfunction]
fn read_manifest_uri_str(font: &[u8]) -> PyResult<Option<String>> {
read_manifest_uri(font).map_err(map_err)
}
#[pyfunction]
fn remove_manifest_table<'py>(py: Python<'py>, font: &[u8]) -> PyResult<Bound<'py, PyBytes>> {
let out = remove_manifest(font).map_err(map_err)?;
Ok(PyBytes::new(py, &out))
}
#[pyfunction]
fn is_compliant(font: &[u8]) -> PyResult<bool> {
Ok(verify(font).map_err(map_err)?.is_compliant())
}
#[pyfunction]
#[pyo3(signature = (font, reserve_size, uri=None))]
fn reserve_manifest_placeholder<'py>(
py: Python<'py>,
font: &[u8],
reserve_size: usize,
uri: Option<String>,
) -> PyResult<Bound<'py, PyBytes>> {
let reserved = reserve_manifest(font, reserve_size, uri).map_err(map_err)?;
Ok(PyBytes::new(py, &reserved.font))
}
#[pyfunction]
fn data_hash_ranges(font: &[u8]) -> PyResult<Vec<(u64, u64)>> {
Ok(data_hash_exclusions(font)
.map_err(map_err)?
.iter()
.map(|e| (e.start, e.length))
.collect())
}
#[pyfunction]
fn fill_manifest_store<'py>(
py: Python<'py>,
reserved_font: &[u8],
signed_manifest: &[u8],
) -> PyResult<Bound<'py, PyBytes>> {
let out = fill_manifest(reserved_font, signed_manifest).map_err(map_err)?;
Ok(PyBytes::new(py, &out))
}
#[pymodule]
fn c2pa_fonts(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(embed_manifest_store, m)?)?;
m.add_function(wrap_pyfunction!(embed_remote, m)?)?;
m.add_function(wrap_pyfunction!(read_manifest_store, m)?)?;
m.add_function(wrap_pyfunction!(read_manifest_uri_str, m)?)?;
m.add_function(wrap_pyfunction!(remove_manifest_table, m)?)?;
m.add_function(wrap_pyfunction!(is_compliant, m)?)?;
m.add_function(wrap_pyfunction!(reserve_manifest_placeholder, m)?)?;
m.add_function(wrap_pyfunction!(data_hash_ranges, m)?)?;
m.add_function(wrap_pyfunction!(fill_manifest_store, m)?)?;
Ok(())
}