Skip to main content

casc_lib/
error.rs

1//! Error types for CASC operations.
2//!
3//! All fallible functions in this crate return [`Result<T>`], which is an alias
4//! for `std::result::Result<T, CascError>`.
5
6use thiserror::Error;
7
8/// Errors that can occur during CASC operations.
9#[derive(Debug, Error)]
10pub enum CascError {
11    /// An underlying I/O failure (file not found, permission denied, etc.).
12    #[error("I/O error: {0}")]
13    Io(#[from] std::io::Error),
14
15    /// File magic bytes do not match the expected format identifier.
16    #[error("Invalid magic: expected {expected}, found {found}")]
17    InvalidMagic {
18        /// The magic bytes the parser expected (e.g. `"BLTE"`, `"EN"`).
19        expected: String,
20        /// The magic bytes actually found in the data.
21        found: String,
22    },
23
24    /// Structural parse failure - truncated data, bad field values, or unexpected layout.
25    #[error("Invalid format: {0}")]
26    InvalidFormat(String),
27
28    /// A referenced key was not found in the index, encoding table, or root file.
29    #[error("{key_type} key not found: {hash}")]
30    KeyNotFound {
31        /// The kind of key that was looked up (e.g. `"EKey"`, `"CKey"`).
32        key_type: String,
33        /// Hex representation of the key that was not found.
34        hash: String,
35    },
36
37    /// The file format version is not supported by this library.
38    #[error("Unsupported version: {0}")]
39    UnsupportedVersion(u32),
40
41    /// A TACT encryption key is required but was not present in the key store.
42    #[error("Encryption key missing: {0}")]
43    EncryptionKeyMissing(String),
44
45    /// Zlib or LZ4 decompression failed.
46    #[error("Decompression failed: {0}")]
47    DecompressionFailed(String),
48
49    /// Content hash does not match the expected value after extraction.
50    #[error("Checksum mismatch: expected {expected}, actual {actual}")]
51    ChecksumMismatch {
52        /// The expected hash (from the encoding or root table).
53        expected: String,
54        /// The hash computed from the extracted data.
55        actual: String,
56    },
57
58    /// A network request failed (e.g. listfile download).
59    #[error("HTTP error: {0}")]
60    Http(#[from] reqwest::Error),
61}
62
63/// Crate-wide result type alias using [`CascError`].
64pub type Result<T> = std::result::Result<T, CascError>;
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn error_display_io() {
72        let err = CascError::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "test"));
73        assert!(err.to_string().contains("I/O error"));
74    }
75
76    #[test]
77    fn error_display_invalid_magic() {
78        let err = CascError::InvalidMagic {
79            expected: "BLTE".into(),
80            found: "XXXX".into(),
81        };
82        assert!(err.to_string().contains("BLTE"));
83        assert!(err.to_string().contains("XXXX"));
84    }
85
86    #[test]
87    fn error_from_io() {
88        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "missing");
89        let casc_err: CascError = io_err.into();
90        assert!(matches!(casc_err, CascError::Io(_)));
91    }
92}