Skip to main content

lodepng/
error.rs

1use crate::ffi::ErrorCode;
2use std::collections::TryReserveError;
3use std::error;
4use std::fmt;
5use std::io;
6use std::num::NonZeroU32;
7
8#[derive(Copy, Clone)]
9pub struct Error(NonZeroU32);
10
11pub type Result<T, E = Error> = std::result::Result<T, E>;
12
13impl ErrorCode {
14    /// Returns an English description of the numerical error code.
15    #[must_use]
16    pub fn as_str(&self) -> &'static str {
17        let s = self.c_description();
18        let s = s.get(..s.len() - 1).unwrap_or_default(); // trim \0
19        std::str::from_utf8(s).unwrap_or("")
20    }
21
22    /// Helper function for the library
23    #[inline]
24    pub fn to_result(self) -> Result<(), Error> {
25        match NonZeroU32::new(self.0) {
26            None => Ok(()),
27            Some(err) => Err(Error(err)),
28        }
29    }
30}
31
32impl Error {
33    /// Panics if the code is 0
34    #[cold]
35    #[must_use]
36    pub const fn new(code: u32) -> Self {
37        Self(if let Some(s) = NonZeroU32::new(code) { s } else { panic!() })
38    }
39}
40
41impl From<ErrorCode> for Result<(), Error> {
42    #[cold]
43    fn from(err: ErrorCode) -> Self {
44        err.to_result()
45    }
46}
47
48impl From<Error> for ErrorCode {
49    #[inline(always)]
50    fn from(err: Error) -> Self {
51        Self(err.0.get())
52    }
53}
54
55impl fmt::Debug for Error {
56    #[cold]
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        write!(f, "{} ({})", ErrorCode(self.0.get()).as_str(), self.0)
59    }
60}
61
62impl fmt::Debug for ErrorCode {
63    #[cold]
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "{} ({})", self.as_str(), self.0)
66    }
67}
68
69impl fmt::Display for Error {
70    #[cold]
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        f.write_str(ErrorCode(self.0.get()).as_str())
73    }
74}
75
76impl error::Error for Error {}
77
78#[doc(hidden)]
79impl std::convert::From<io::Error> for Error {
80    #[cold]
81    fn from(err: io::Error) -> Self {
82        match err.kind() {
83            io::ErrorKind::NotFound | io::ErrorKind::UnexpectedEof => Self::new(78),
84            io::ErrorKind::OutOfMemory => Self::new(83),
85            _ => Self::new(79),
86        }
87    }
88}
89
90/*
91This returns the description of a numerical error code in English. This is also
92the documentation of all the error codes.
93*/
94impl ErrorCode {
95    #[cold]
96    #[must_use]
97    pub fn c_description(&self) -> &'static [u8] {
98        match self.0 {
99            0 => "no error, everything went ok\0",
100            1 => "nothing done yet\0",
101
102            /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/
103            10 => "end of input memory reached without huffman end code\0",
104
105            /*while huffman decoding*/
106            11 => "error in code tree made it jump outside of huffman tree\0",
107
108            /*while huffman decoding*/
109            13..=15 => "problem while processing dynamic deflate block\0",
110            16 => "unexisting code while processing dynamic deflate block\0",
111            18 => "invalid distance code while inflating\0",
112            17 | 19 | 22 => "end of out buffer memory reached while inflating\0",
113            20 => "invalid deflate block BTYPE encountered while decoding\0",
114            21 => "NLEN is not ones complement of LEN in a deflate block\0",
115
116            /*end of out buffer memory reached while inflating:
117                This can happen if the inflated deflate data is longer than the amount of bytes required to fill up
118                all the pixels of the image, given the color depth and image dimensions. Something that doesn't
119                happen in a normal, well encoded, PNG image.*/
120            23 => "end of in buffer memory reached while inflating\0",
121            24 => "invalid FCHECK in zlib header\0",
122            25 => "invalid compression method in zlib header\0",
123            26 => "FDICT encountered in zlib header while it\'s not used for PNG\0",
124            27 => "PNG file is smaller than a PNG header\0",
125            /*Checks the magic file header, the first 8 bytes of the PNG file*/
126            28 => "incorrect PNG signature, it\'s no PNG or corrupted\0",
127            29 => "first chunk is not the header chunk\0",
128            30 => "chunk length too large, chunk broken off at end of file\0",
129            31 => "illegal PNG color type or bpp\0",
130            32 => "illegal PNG compression method\0",
131            33 => "illegal PNG filter method\0",
132            34 => "illegal PNG interlace method\0",
133            35 => "chunk length of a chunk is too large or the chunk too small\0",
134            36 => "illegal PNG filter type encountered\0",
135            37 => "illegal bit depth for this color type given\0",
136            38 => "the palette is too big\0",
137            /*more than 256 colors*/
138            39 => "more palette alpha values given in tRNS chunk than there are colors in the palette\0",
139            40 => "tRNS chunk has wrong size for greyscale image\0",
140            41 => "tRNS chunk has wrong size for RGB image\0",
141            42 => "tRNS chunk appeared while it was not allowed for this color type\0",
142            43 => "bKGD chunk has wrong size for palette image\0",
143            44 => "bKGD chunk has wrong size for greyscale image\0",
144            45 => "bKGD chunk has wrong size for RGB image\0",
145            48 => "empty input buffer given to decoder. Maybe caused by non-existing file?\0",
146            49 | 50 => "jumped past memory while generating dynamic huffman tree\0",
147            51 => "jumped past memory while inflating huffman block\0",
148            52 => "jumped past memory while inflating\0",
149            53 => "size of zlib data too small\0",
150            54 => "repeat symbol in tree while there was no value symbol yet\0",
151
152            /*jumped past tree while generating huffman tree, this could be when the
153               tree will have more leaves than symbols after generating it out of the
154               given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/
155            55 => "jumped past tree while generating huffman tree\0",
156            56 => "given output image colortype or bitdepth not supported for color conversion\0",
157            57 => "invalid CRC encountered (checking CRC can be disabled)\0",
158            58 => "invalid ADLER32 encountered (checking ADLER32 can be disabled)\0",
159            59 => "requested color conversion not supported\0",
160            60 => "invalid window size given in the settings of the encoder (must be 0-32768)\0",
161            61 => "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)\0",
162
163            /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/
164            62 => "conversion from color to greyscale not supported\0",
165            63 => "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk\0",
166
167            /*(2^31-1)*/
168            /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/
169            64 => "the length of the END symbol 256 in the Huffman tree is 0\0",
170            66 => "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes\0",
171            67 => "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte\0",
172            68 => "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors\0",
173            69 => "unknown chunk type with \'critical\' flag encountered by the decoder\0",
174            71 => "unexisting interlace mode given to encoder (must be 0 or 1)\0",
175            72 => "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)\0",
176            73 => "invalid tIME chunk size\0",
177            74 => "invalid pHYs chunk size\0",
178            /*length could be wrong, or data chopped off*/
179            75 => "no null termination char found while decoding text chunk\0",
180            76 => "iTXt chunk too short to contain required bytes\0",
181            77 => "integer overflow in buffer size\0",
182            78 => "failed to open file for reading\0",
183
184            /*file doesn't exist or couldn't be opened for reading*/
185            79 => "failed to open file for writing\0",
186            80 => "tried creating a tree of 0 symbols\0",
187            81 => "lazy matching at pos 0 is impossible\0",
188            82 => "color conversion to palette requested while a color isn\'t in palette\0",
189            83 => "memory allocation failed\0",
190            84 => "given image too small to contain all pixels to be encoded\0",
191            86 => "impossible offset in lz77 encoding (internal bug)\0",
192            87 => "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined\0",
193            88 => "invalid filter strategy given for EncoderSettings.filter_strategy\0",
194            89 => "text chunk keyword too short or long: must have size 1-79\0",
195
196            /*the windowsize in the CompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/
197            90 => "windowsize must be a power of two\0",
198            91 => "invalid decompressed idat size\0",
199            92 => "too many pixels, not supported\0",
200            93 => "zero width or height is invalid\0",
201            94 => "header chunk must have a size of 13 bytes\0",
202            _ => "unknown error code\0",
203        }.as_bytes()
204    }
205}
206
207impl From<TryReserveError> for Error {
208    #[cold]
209    fn from(_: TryReserveError) -> Self {
210        Self(NonZeroU32::new(83).unwrap())
211    }
212}
213
214#[test]
215fn error_str() {
216    assert_eq!(ErrorCode(83).as_str(), "memory allocation failed");
217}