chdlady-core 0.1.0

Core container manipulation for CHD v5 format
//! Error types for CHD container operations.
use std::fmt;
use std::io;

/// Errors that can occur when manipulating CHD containers.
#[derive(Debug)]
pub enum ChdError {
    /// An I/O error occurred.
    Io(io::Error),
    /// Invalid magic signature (expected b"MComprHD").
    InvalidMagic,
    /// Invalid header length.
    InvalidHeaderSize(u32),
    /// Unsupported CHD format version.
    UnsupportedVersion(u32),
    /// Bitstream or container data is corrupt.
    InvalidData(String),
    /// CRC-16 checksum mismatch in hunk map or decompressed block.
    CrcMismatch {
        /// CRC value expected from container.
        expected: u16,
        /// CRC value calculated from data.
        found: u16,
    },
    /// An error occurred during Huffman decoding or encoding.
    Huffman(chdlady_huffman::HuffmanError),
    /// Codec error during decompression or compression.
    Codec(String),
    /// Requested hunk index is out of container bounds.
    HunkOutOfRange {
        /// Requested hunk index.
        index: u64,
        /// Total hunks in container.
        total: u64,
    },
    /// The specified metadata entry was not found in the container.
    MetadataNotFound,
    /// A parent CHD container is required to resolve referenced hunks.
    RequiresParent,
    /// The specified parent CHD checksum does not match container header.
    InvalidParent,
    /// Invalid parameter supplied to operation.
    InvalidParameter(String),
}

impl fmt::Display for ChdError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Io(e) => write!(f, "I/O error: {}", e),
            Self::InvalidMagic => write!(f, "invalid CHD magic signature"),
            Self::InvalidHeaderSize(size) => write!(f, "invalid header size: {}", size),
            Self::UnsupportedVersion(ver) => write!(f, "unsupported CHD version: {}", ver),
            Self::InvalidData(msg) => write!(f, "invalid data: {}", msg),
            Self::CrcMismatch { expected, found } => {
                write!(
                    f,
                    "CRC-16 mismatch: expected {:#06x}, found {:#06x}",
                    expected, found
                )
            }
            Self::Huffman(e) => write!(f, "Huffman error: {}", e),
            Self::Codec(msg) => write!(f, "codec error: {}", msg),
            Self::HunkOutOfRange { index, total } => {
                write!(f, "hunk index {} out of range (total: {})", index, total)
            }
            Self::MetadataNotFound => write!(f, "metadata entry not found"),
            Self::RequiresParent => write!(f, "parent CHD required but not provided"),
            Self::InvalidParent => {
                write!(f, "provided parent CHD does not match parent SHA-1")
            }
            Self::InvalidParameter(msg) => write!(f, "invalid parameter: {}", msg),
        }
    }
}

impl std::error::Error for ChdError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::Io(e) => Some(e),
            Self::Huffman(e) => Some(e),
            _ => None,
        }
    }
}

impl From<io::Error> for ChdError {
    fn from(err: io::Error) -> Self {
        Self::Io(err)
    }
}

impl From<chdlady_huffman::HuffmanError> for ChdError {
    fn from(err: chdlady_huffman::HuffmanError) -> Self {
        Self::Huffman(err)
    }
}