ps2mc 0.1.0

A Rust library for reading, extracting, and rewriting PlayStation 2 memory card images.
Documentation
use std::io;

use thiserror::Error;

/// Errors produced while reading or writing PlayStation 2 memory card data.
#[derive(Debug, Error)]
pub enum Ps2mcError {
    /// Wraps a lower-level I/O failure.
    #[error("io error: {0}")]
    Io(#[from] io::Error),

    /// The superblock did not contain enough bytes.
    #[error("superblock length invalid: expected {expected} bytes, got {actual}")]
    InvalidSuperBlockLength { expected: usize, actual: usize },

    /// The input image did not start with the expected superblock magic.
    #[error("not a valid superblock")]
    InvalidSuperBlockMagic,

    /// The page size declared by the card image is invalid.
    #[error("invalid page size {page_size}")]
    InvalidPageSize { page_size: usize },

    /// The cluster geometry declared by the card image is invalid.
    #[error("invalid pages-per-cluster value {pages_per_cluster}")]
    InvalidPagesPerCluster { pages_per_cluster: usize },

    /// A page or cluster read returned fewer bytes than expected.
    #[error("unexpected end of file while reading {context}: expected {expected} bytes, got {actual}")]
    UnexpectedEof {
        context: &'static str,
        expected: usize,
        actual: usize,
    },

    /// A FAT reference pointed outside the decoded FAT table.
    #[error("fat index out of range for relative cluster {cluster}")]
    InvalidFatIndex { cluster: u32 },

    /// FAT traversal found a cycle.
    #[error("fat cycle detected at relative cluster {cluster}")]
    FatCycle { cluster: u32 },

    /// A directory entry chain exceeded the configured safety cap.
    #[error("directory contains too many entries: {count} exceeds {max}")]
    DirectoryTooLarge { count: usize, max: usize },

    /// A file read or write exceeded the supported 64MB cap.
    #[error("entry size {size} exceeds the supported maximum of {max} bytes")]
    EntryTooLarge { size: u64, max: u64 },

    /// An entry name or another ASCII field was not valid ASCII.
    #[error("invalid ascii in {field}")]
    InvalidAsciiField { field: &'static str },

    /// The root directory entry could not be parsed as a directory.
    #[error("root directory entry is not a directory")]
    InvalidRootEntry,

    /// The provided bytes were too short for a directory entry.
    #[error("entry length invalid: expected {expected} bytes, got {actual}")]
    InvalidEntryLength { expected: usize, actual: usize },

    /// The provided bytes were too short for the icon.sys payload.
    #[error("icon.sys length invalid: expected {expected} bytes, got {actual}")]
    InvalidIconSysLength { expected: usize, actual: usize },

    /// The icon.sys magic was invalid.
    #[error("not a valid icon.sys payload")]
    InvalidIconSysMagic,

    /// The provided bytes did not contain a valid icon header.
    #[error("not a valid icon payload")]
    InvalidIconMagic,

    /// The icon animation header was invalid.
    #[error("not a valid icon animation header")]
    InvalidAnimationHeader,

    /// The compressed texture stream was malformed.
    #[error("invalid compressed texture encoding")]
    InvalidTextureEncoding,

    /// The decoded texture size did not match the expected 128x128 format.
    #[error("decoded texture size mismatch: expected {expected} bytes, got {actual}")]
    InvalidTextureSize { expected: usize, actual: usize },

    /// The caller requested a save directory that does not exist.
    #[error("can't find game {name}")]
    SaveNotFound { name: String },

    /// The caller requested an icon file that was not present in the save directory.
    #[error("can't find icon file {name}")]
    IconFileNotFound { name: String },

    /// Texture export was requested for an icon without texture data.
    #[error("icon does not contain texture data")]
    TextureUnavailable,

    /// The caller supplied a byte slice whose length did not match the file entry length.
    #[error("invalid write length: expected {expected} bytes, got {actual}")]
    InvalidWriteLength { expected: usize, actual: usize },

    #[error("ECC check failed; the ECC data in the spare area does not match.")]
    EccMismatch,

    #[error("invalid entry name: {name}")]
    InvalidEntryName { name: String },
}