1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * Copyright (c) 2023.
 *
 * This software is free software;
 *
 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
 */

//! Contains most common errors that may be encountered in decoding a Decoder
//! image

use alloc::string::String;
use core::fmt::{Debug, Display, Formatter};

use crate::misc::{
    START_OF_FRAME_EXT_AR, START_OF_FRAME_EXT_SEQ, START_OF_FRAME_LOS_SEQ,
    START_OF_FRAME_LOS_SEQ_AR, START_OF_FRAME_PROG_DCT_AR
};

/// Common Decode errors
#[allow(clippy::module_name_repetitions)]
#[derive(Clone)]
pub enum DecodeErrors {
    /// Any other thing we do not know
    Format(String),
    /// Any other thing we do not know but we
    /// don't need to allocate space on the heap
    FormatStatic(&'static str),
    /// Illegal Magic Bytes
    IllegalMagicBytes(u16),
    /// problems with the Huffman Tables in a Decoder file
    HuffmanDecode(String),
    /// Image has zero width
    ZeroError,
    /// Discrete Quantization Tables error
    DqtError(String),
    /// Start of scan errors
    SosError(String),
    /// Start of frame errors
    SofError(String),
    /// UnsupportedImages
    Unsupported(UnsupportedSchemes),
    /// MCU errors
    MCUError(String),
    /// Exhausted data
    ExhaustedData,
    /// Large image dimensions(Corrupted data)?
    LargeDimensions(usize),
    /// Too small output for size
    TooSmallOutput(usize, usize)
}

#[cfg(feature = "std")]
impl std::error::Error for DecodeErrors {}

impl From<&'static str> for DecodeErrors {
    fn from(data: &'static str) -> Self {
        return Self::FormatStatic(data);
    }
}

impl Debug for DecodeErrors {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        match &self
        {
            Self::Format(ref a) => write!(f, "{a:?}"),
            Self::FormatStatic(a) => write!(f, "{:?}", &a),

            Self::HuffmanDecode(ref reason) =>
            {
                write!(f, "Error decoding huffman values: {reason}")
            }
            Self::ZeroError => write!(f, "Image width or height is set to zero, cannot continue"),
            Self::DqtError(ref reason) => write!(f, "Error parsing DQT segment. Reason:{reason}"),
            Self::SosError(ref reason) => write!(f, "Error parsing SOS Segment. Reason:{reason}"),
            Self::SofError(ref reason) => write!(f, "Error parsing SOF segment. Reason:{reason}"),
            Self::IllegalMagicBytes(bytes) =>
            {
                write!(f, "Error parsing image. Illegal start bytes:{bytes:X}")
            }
            Self::MCUError(ref reason) => write!(f, "Error in decoding MCU. Reason {reason}"),
            Self::Unsupported(ref image_type) =>
                {
                    write!(f, "{image_type:?}")
                }
            Self::ExhaustedData => write!(f, "Exhausted data in the image"),
            Self::LargeDimensions(ref dimensions) => write!(
                f,
                "Too large dimensions {dimensions},library supports up to {}", crate::decoder::MAX_DIMENSIONS
            ),
            Self::TooSmallOutput(expected, found) => write!(f, "Too small output, expected buffer with at least {expected} bytes but got one with {found} bytes")
        }
    }
}

impl Display for DecodeErrors {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        write!(f, "{self:?}")
    }
}

/// Contains Unsupported/Yet-to-be supported Decoder image encoding types.
#[derive(Eq, PartialEq, Copy, Clone)]
pub enum UnsupportedSchemes {
    /// SOF_1 Extended sequential DCT,Huffman coding
    ExtendedSequentialHuffman,
    /// Lossless (sequential), huffman coding,
    LosslessHuffman,
    /// Extended sequential DEC, arithmetic coding
    ExtendedSequentialDctArithmetic,
    /// Progressive DCT, arithmetic coding,
    ProgressiveDctArithmetic,
    /// Lossless ( sequential), arithmetic coding
    LosslessArithmetic
}

impl Debug for UnsupportedSchemes {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        match &self {
            Self::ExtendedSequentialHuffman => {
                write!(f, "The library cannot yet decode images encoded using Extended Sequential Huffman  encoding scheme yet.")
            }
            Self::LosslessHuffman => {
                write!(f, "The library cannot yet decode images encoded with Lossless Huffman encoding scheme")
            }
            Self::ExtendedSequentialDctArithmetic => {
                write!(f,"The library cannot yet decode Images Encoded with Extended Sequential DCT Arithmetic scheme")
            }
            Self::ProgressiveDctArithmetic => {
                write!(f,"The library cannot yet decode images encoded with Progressive DCT Arithmetic scheme")
            }
            Self::LosslessArithmetic => {
                write!(f,"The library cannot yet decode images encoded with Lossless Arithmetic encoding scheme")
            }
        }
    }
}

impl UnsupportedSchemes {
    #[must_use]
    /// Create an unsupported scheme from an integer
    ///
    /// # Returns
    /// `Some(UnsupportedScheme)` if the int refers to a specific scheme,
    /// otherwise returns `None`
    pub fn from_int(int: u8) -> Option<UnsupportedSchemes> {
        let int = u16::from_be_bytes([0xff, int]);

        match int {
            START_OF_FRAME_PROG_DCT_AR => Some(Self::ProgressiveDctArithmetic),
            START_OF_FRAME_LOS_SEQ => Some(Self::LosslessHuffman),
            START_OF_FRAME_LOS_SEQ_AR => Some(Self::LosslessArithmetic),
            START_OF_FRAME_EXT_SEQ => Some(Self::ExtendedSequentialHuffman),
            START_OF_FRAME_EXT_AR => Some(Self::ExtendedSequentialDctArithmetic),
            _ => None
        }
    }
}