rsmp4decrypt 0.2.0

Rust bindings and a CLI for Bento4 mp4decrypt
use thiserror::Error;

/// Errors returned by the public Rust API and CLI.
#[derive(Debug, Error)]
pub enum Error {
    /// Input or output buffers cannot be represented with Bento4's 32-bit size limits.
    #[error("data too large (maximum supported {0} bytes)")]
    DataTooLarge(u32),

    /// Bento4 did not create a decryptor context.
    #[error("Bento4 failed to create a decryptor context")]
    ContextCreationFailed,

    /// Bento4 returned an error while opening or decrypting media.
    #[error("{operation} failed with Bento4 error {name} ({code})")]
    DecryptionFailed {
        operation: &'static str,
        code: i32,
        name: String,
    },

    /// A hexadecimal KID or key had the wrong size.
    #[error("invalid hex value '{input}': {message}")]
    InvalidHex { input: String, message: String },

    /// A `--key` value did not follow the expected `<id>:<key>` format.
    #[error("invalid --key spec '{input}': {message}")]
    InvalidKeySpec { input: String, message: String },

    /// A path could not be passed through the C interface because it contains a NUL byte.
    #[error("path contains an interior NUL byte: {0}")]
    InvalidPath(#[from] std::ffi::NulError),

    /// The builder was finalized without any decryption keys.
    #[error("at least one decryption key must be configured")]
    NoKeys,

    /// A hexadecimal KID or key could not be decoded.
    #[error("hex decode error: {0}")]
    HexDecode(#[from] hex::FromHexError),

    /// A filesystem or process operation failed while preparing isolated decryption.
    #[error("i/o error: {0}")]
    Io(#[from] std::io::Error),

    /// The worker process failed before returning a structured Bento4 error.
    #[error("isolated decrypt worker failed with status {status}: {stderr}")]
    WorkerFailed { status: String, stderr: String },
}

impl Error {
    /// Returns the Bento4 error code when the failure originated from Bento4.
    pub fn bento4_code(&self) -> Option<i32> {
        match self {
            Self::DecryptionFailed { code, .. } => Some(*code),
            _ => None,
        }
    }

    /// Returns the Bento4 symbolic error name when available.
    pub fn bento4_name(&self) -> Option<&str> {
        match self {
            Self::DecryptionFailed { name, .. } => Some(name.as_str()),
            _ => None,
        }
    }

    /// Returns the high-level operation that failed inside the native layer.
    pub fn operation(&self) -> Option<&'static str> {
        match self {
            Self::DecryptionFailed { operation, .. } => Some(*operation),
            _ => None,
        }
    }
}