Skip to main content

c2pa_text_binding/
error.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use std::fmt;
4
5/// Errors produced by the text soft-binding algorithms.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum Error {
8    /// Input has too little content for the requested algorithm (e.g. not
9    /// enough word boundaries to place a watermark payload).
10    ContentTooShort,
11    /// A fingerprint value could not be produced.
12    GenerationFailed(String),
13    /// A fingerprint comparison failed.
14    MatchFailed(String),
15    /// Reed-Solomon erasure coding/decoding failed.
16    Coding(String),
17    /// The watermark payload was present but its content-binding HMAC did not
18    /// verify against the recomputed content hash (transfer or tamper).
19    TagMismatch,
20    /// The watermark could not be recovered (too many stripped positions).
21    WatermarkUnrecoverable,
22    /// A caller-supplied argument was malformed.
23    InvalidInput(String),
24}
25
26impl Error {
27    /// The registered C2PA validation status code for this error, or `None`
28    /// when the condition carries no status code.
29    ///
30    /// Always `None`. This crate implements *soft* binding — fingerprinting and
31    /// watermarking — whose failures are not hard-binding validation outcomes.
32    /// A soft binding that does not match means the recovery path found no
33    /// candidate, not that a located manifest failed to validate, and the
34    /// specification registers no status code for that.
35    ///
36    /// Every crate in this family exposes this method, so a dispatcher handling
37    /// several embedding methods can ask the same question of any of them.
38    pub fn code(&self) -> Option<&'static str> {
39        None
40    }
41
42    /// Whether this error means the asset carries no provenance at all.
43    ///
44    /// Always `false`: soft binding is a recovery mechanism used *after* the
45    /// hard binding has already failed to locate a manifest, so it is never the
46    /// thing that decides whether an asset is unsigned.
47    pub fn is_no_manifest_located(&self) -> bool {
48        false
49    }
50}
51
52impl fmt::Display for Error {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            Self::ContentTooShort => {
56                write!(f, "text content too short for this soft-binding algorithm")
57            }
58            Self::GenerationFailed(s) => write!(f, "fingerprint generation failed: {s}"),
59            Self::MatchFailed(s) => write!(f, "fingerprint match failed: {s}"),
60            Self::Coding(s) => write!(f, "reed-solomon coding failed: {s}"),
61            Self::TagMismatch => write!(
62                f,
63                "watermark content-binding tag did not verify (transferred or modified content)"
64            ),
65            Self::WatermarkUnrecoverable => {
66                write!(
67                    f,
68                    "watermark could not be recovered from remaining positions"
69                )
70            }
71            Self::InvalidInput(s) => write!(f, "invalid input: {s}"),
72        }
73    }
74}
75
76impl std::error::Error for Error {}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    /// Soft-binding failures are not hard-binding validation outcomes, so no
83    /// variant may claim a status code. Guards against a later edit inventing
84    /// one.
85    #[test]
86    fn no_variant_claims_a_status_code() {
87        for e in [
88            Error::ContentTooShort,
89            Error::GenerationFailed("x".into()),
90            Error::MatchFailed("x".into()),
91            Error::Coding("x".into()),
92            Error::TagMismatch,
93            Error::WatermarkUnrecoverable,
94            Error::InvalidInput("x".into()),
95        ] {
96            assert_eq!(e.code(), None, "{e:?} claimed a status code");
97            assert!(
98                !e.is_no_manifest_located(),
99                "{e:?} must not decide whether an asset is unsigned"
100            );
101        }
102    }
103}