c2pa-warc 0.2.1

C2PA manifest embedding for WARC web archive files (ISO 28500)
Documentation
use crate::error::Error;
use crate::record::{parse_records, WarcRecord};

pub fn read_manifest(data: &[u8]) -> Result<Vec<u8>, Error> {
    let records = parse_records(data)?;
    let manifest = records
        .iter()
        .rev()
        .find(|r| r.is_c2pa_manifest())
        .ok_or(Error::NotFound)?;
    Ok(manifest.body.clone())
}

pub fn read_records(data: &[u8]) -> Result<Vec<WarcRecord>, Error> {
    parse_records(data)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::record::build_record;

    #[test]
    fn read_manifest_from_warc() {
        let r1 = build_record(
            "response",
            "text/html",
            "urn:uuid:aaa",
            Some("https://example.com/"),
            b"<html></html>",
        );
        let manifest_bytes = b"\x00\x01\x02\x03";
        let r2 = build_record(
            "c2paprovenance",
            "application/c2pa",
            "urn:uuid:bbb",
            None,
            manifest_bytes,
        );
        let mut warc = Vec::new();
        warc.extend_from_slice(&r1);
        warc.extend_from_slice(&r2);

        let result = read_manifest(&warc).unwrap();
        assert_eq!(result, manifest_bytes);
    }

    #[test]
    fn uses_last_manifest() {
        let r1 = build_record(
            "c2paprovenance",
            "application/c2pa",
            "urn:uuid:old",
            None,
            b"old",
        );
        let r2 = build_record(
            "response",
            "text/html",
            "urn:uuid:mid",
            Some("https://example.com/"),
            b"<html></html>",
        );
        let r3 = build_record(
            "c2paprovenance",
            "application/c2pa",
            "urn:uuid:new",
            None,
            b"new",
        );
        let mut warc = Vec::new();
        warc.extend_from_slice(&r1);
        warc.extend_from_slice(&r2);
        warc.extend_from_slice(&r3);

        let result = read_manifest(&warc).unwrap();
        assert_eq!(result, b"new");
    }

    #[test]
    fn no_manifest() {
        let r1 = build_record(
            "response",
            "text/html",
            "urn:uuid:aaa",
            Some("https://example.com/"),
            b"<html></html>",
        );
        assert!(matches!(read_manifest(&r1), Err(Error::NotFound)));
    }
}