image/codecs/pnm/
decoder.rs

1use std::error;
2use std::fmt::{self, Display};
3use std::io::{self, Read};
4use std::mem::size_of;
5use std::num::ParseIntError;
6use std::str::{self, FromStr};
7
8use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader};
9use super::{HeaderRecord, PnmHeader, PnmSubtype, SampleEncoding};
10use crate::color::{ColorType, ExtendedColorType};
11use crate::error::{
12    DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
13};
14use crate::image::{ImageDecoder, ImageFormat};
15use crate::utils;
16
17use byteorder_lite::{BigEndian, ByteOrder, NativeEndian};
18
19/// All errors that can occur when attempting to parse a PNM
20#[derive(Debug, Clone)]
21enum DecoderError {
22    /// PNM's "P[123456]" signature wrong or missing
23    PnmMagicInvalid([u8; 2]),
24    /// Couldn't parse the specified string as an integer from the specified source
25    UnparsableValue(ErrorDataSource, String, ParseIntError),
26
27    /// More than the exactly one allowed plane specified by the format
28    NonAsciiByteInHeader(u8),
29    /// The PAM header contained a non-ASCII byte
30    NonAsciiLineInPamHeader,
31    /// A sample string contained a non-ASCII byte
32    NonAsciiSample,
33
34    /// The byte after the P7 magic was not 0x0A NEWLINE
35    NotNewlineAfterP7Magic(u8),
36    /// The PNM header had too few lines
37    UnexpectedPnmHeaderEnd,
38
39    /// The specified line was specified twice
40    HeaderLineDuplicated(PnmHeaderLine),
41    /// The line with the specified ID was not understood
42    HeaderLineUnknown(String),
43    /// At least one of the required lines were missing from the header (are `None` here)
44    ///
45    /// Same names as [`PnmHeaderLine`](enum.PnmHeaderLine.html)
46    #[allow(missing_docs)]
47    HeaderLineMissing {
48        height: Option<u32>,
49        width: Option<u32>,
50        depth: Option<u32>,
51        maxval: Option<u32>,
52    },
53
54    /// Not enough data was provided to the Decoder to decode the image
55    InputTooShort,
56    /// Sample raster contained unexpected byte
57    UnexpectedByteInRaster(u8),
58    /// Specified sample was out of bounds (e.g. >1 in B&W)
59    SampleOutOfBounds(u8),
60    /// The image's maxval is zero
61    MaxvalZero,
62    /// The image's maxval exceeds 0xFFFF
63    MaxvalTooBig(u32),
64
65    /// The specified tuple type supports restricted depths and maxvals, those restrictions were not met
66    InvalidDepthOrMaxval {
67        tuple_type: ArbitraryTuplType,
68        depth: u32,
69        maxval: u32,
70    },
71    /// The specified tuple type supports restricted depths, those restrictions were not met
72    InvalidDepth {
73        tuple_type: ArbitraryTuplType,
74        depth: u32,
75    },
76    /// The tuple type was not recognised by the parser
77    TupleTypeUnrecognised,
78
79    /// Overflowed the specified value when parsing
80    Overflow,
81}
82
83impl Display for DecoderError {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        match self {
86            DecoderError::PnmMagicInvalid(magic) => f.write_fmt(format_args!(
87                "Expected magic constant for PNM: P1..P7, got [{:#04X?}, {:#04X?}]",
88                magic[0], magic[1]
89            )),
90            DecoderError::UnparsableValue(src, data, err) => {
91                f.write_fmt(format_args!("Error parsing {data:?} as {src}: {err}"))
92            }
93
94            DecoderError::NonAsciiByteInHeader(c) => {
95                f.write_fmt(format_args!("Non-ASCII character {c:#04X?} in header"))
96            }
97            DecoderError::NonAsciiLineInPamHeader => f.write_str("Non-ASCII line in PAM header"),
98            DecoderError::NonAsciiSample => {
99                f.write_str("Non-ASCII character where sample value was expected")
100            }
101
102            DecoderError::NotNewlineAfterP7Magic(c) => f.write_fmt(format_args!(
103                "Expected newline after P7 magic, got {c:#04X?}"
104            )),
105            DecoderError::UnexpectedPnmHeaderEnd => f.write_str("Unexpected end of PNM header"),
106
107            DecoderError::HeaderLineDuplicated(line) => {
108                f.write_fmt(format_args!("Duplicate {line} line"))
109            }
110            DecoderError::HeaderLineUnknown(identifier) => f.write_fmt(format_args!(
111                "Unknown header line with identifier {identifier:?}"
112            )),
113            DecoderError::HeaderLineMissing {
114                height,
115                width,
116                depth,
117                maxval,
118            } => f.write_fmt(format_args!(
119                "Missing header line: have height={height:?}, width={width:?}, depth={depth:?}, maxval={maxval:?}"
120            )),
121
122            DecoderError::InputTooShort => {
123                f.write_str("Not enough data was provided to the Decoder to decode the image")
124            }
125            DecoderError::UnexpectedByteInRaster(c) => f.write_fmt(format_args!(
126                "Unexpected character {c:#04X?} within sample raster"
127            )),
128            DecoderError::SampleOutOfBounds(val) => {
129                f.write_fmt(format_args!("Sample value {val} outside of bounds"))
130            }
131            DecoderError::MaxvalZero => f.write_str("Image MAXVAL is zero"),
132            DecoderError::MaxvalTooBig(maxval) => {
133                f.write_fmt(format_args!("Image MAXVAL exceeds {}: {}", 0xFFFF, maxval))
134            }
135
136            DecoderError::InvalidDepthOrMaxval {
137                tuple_type,
138                depth,
139                maxval,
140            } => f.write_fmt(format_args!(
141                "Invalid depth ({}) or maxval ({}) for tuple type {}",
142                depth,
143                maxval,
144                tuple_type.name()
145            )),
146            DecoderError::InvalidDepth { tuple_type, depth } => f.write_fmt(format_args!(
147                "Invalid depth ({}) for tuple type {}",
148                depth,
149                tuple_type.name()
150            )),
151            DecoderError::TupleTypeUnrecognised => f.write_str("Tuple type not recognized"),
152            DecoderError::Overflow => f.write_str("Overflow when parsing value"),
153        }
154    }
155}
156
157/// Note: should `pnm` be extracted into a separate crate,
158/// this will need to be hidden until that crate hits version `1.0`.
159impl From<DecoderError> for ImageError {
160    fn from(e: DecoderError) -> ImageError {
161        ImageError::Decoding(DecodingError::new(ImageFormat::Pnm.into(), e))
162    }
163}
164
165impl error::Error for DecoderError {
166    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
167        match self {
168            DecoderError::UnparsableValue(_, _, err) => Some(err),
169            _ => None,
170        }
171    }
172}
173
174/// Single-value lines in a PNM header
175#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
176enum PnmHeaderLine {
177    /// "HEIGHT"
178    Height,
179    /// "WIDTH"
180    Width,
181    /// "DEPTH"
182    Depth,
183    /// "MAXVAL", a.k.a. `maxwhite`
184    Maxval,
185}
186
187impl Display for PnmHeaderLine {
188    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189        f.write_str(match self {
190            PnmHeaderLine::Height => "HEIGHT",
191            PnmHeaderLine::Width => "WIDTH",
192            PnmHeaderLine::Depth => "DEPTH",
193            PnmHeaderLine::Maxval => "MAXVAL",
194        })
195    }
196}
197
198/// Single-value lines in a PNM header
199#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
200enum ErrorDataSource {
201    /// One of the header lines
202    Line(PnmHeaderLine),
203    /// Value in the preamble
204    Preamble,
205    /// Sample/pixel data
206    Sample,
207}
208
209impl Display for ErrorDataSource {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211        match self {
212            ErrorDataSource::Line(l) => l.fmt(f),
213            ErrorDataSource::Preamble => f.write_str("number in preamble"),
214            ErrorDataSource::Sample => f.write_str("sample"),
215        }
216    }
217}
218
219/// Dynamic representation, represents all decodable (sample, depth) combinations.
220#[derive(Clone, Copy)]
221enum TupleType {
222    PbmBit,
223    BWBit,
224    GrayU8,
225    GrayU16,
226    RGBU8,
227    RGBU16,
228}
229
230trait Sample {
231    type Representation;
232
233    /// Representation size in bytes
234    fn sample_size() -> u32 {
235        size_of::<Self::Representation>() as u32
236    }
237    fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
238        Ok((width * height * samples * Self::sample_size()) as usize)
239    }
240    fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()>;
241    fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()>;
242}
243
244struct U8;
245struct U16;
246struct PbmBit;
247struct BWBit;
248
249trait DecodableImageHeader {
250    fn tuple_type(&self) -> ImageResult<TupleType>;
251}
252
253/// PNM decoder
254pub struct PnmDecoder<R> {
255    reader: R,
256    header: PnmHeader,
257    tuple: TupleType,
258}
259
260impl<R: Read> PnmDecoder<R> {
261    /// Create a new decoder that decodes from the stream ```read```
262    pub fn new(mut buffered_read: R) -> ImageResult<PnmDecoder<R>> {
263        let magic = buffered_read.read_magic_constant()?;
264
265        let subtype = match magic {
266            [b'P', b'1'] => PnmSubtype::Bitmap(SampleEncoding::Ascii),
267            [b'P', b'2'] => PnmSubtype::Graymap(SampleEncoding::Ascii),
268            [b'P', b'3'] => PnmSubtype::Pixmap(SampleEncoding::Ascii),
269            [b'P', b'4'] => PnmSubtype::Bitmap(SampleEncoding::Binary),
270            [b'P', b'5'] => PnmSubtype::Graymap(SampleEncoding::Binary),
271            [b'P', b'6'] => PnmSubtype::Pixmap(SampleEncoding::Binary),
272            [b'P', b'7'] => PnmSubtype::ArbitraryMap,
273            _ => return Err(DecoderError::PnmMagicInvalid(magic).into()),
274        };
275
276        let decoder = match subtype {
277            PnmSubtype::Bitmap(enc) => PnmDecoder::read_bitmap_header(buffered_read, enc),
278            PnmSubtype::Graymap(enc) => PnmDecoder::read_graymap_header(buffered_read, enc),
279            PnmSubtype::Pixmap(enc) => PnmDecoder::read_pixmap_header(buffered_read, enc),
280            PnmSubtype::ArbitraryMap => PnmDecoder::read_arbitrary_header(buffered_read),
281        }?;
282
283        if utils::check_dimension_overflow(
284            decoder.dimensions().0,
285            decoder.dimensions().1,
286            decoder.color_type().bytes_per_pixel(),
287        ) {
288            return Err(ImageError::Unsupported(
289                UnsupportedError::from_format_and_kind(
290                    ImageFormat::Pnm.into(),
291                    UnsupportedErrorKind::GenericFeature(format!(
292                        "Image dimensions ({}x{}) are too large",
293                        decoder.dimensions().0,
294                        decoder.dimensions().1
295                    )),
296                ),
297            ));
298        }
299
300        Ok(decoder)
301    }
302
303    /// Extract the reader and header after an image has been read.
304    pub fn into_inner(self) -> (R, PnmHeader) {
305        (self.reader, self.header)
306    }
307
308    fn read_bitmap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> {
309        let header = reader.read_bitmap_header(encoding)?;
310        Ok(PnmDecoder {
311            reader,
312            tuple: TupleType::PbmBit,
313            header: PnmHeader {
314                decoded: HeaderRecord::Bitmap(header),
315                encoded: None,
316            },
317        })
318    }
319
320    fn read_graymap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> {
321        let header = reader.read_graymap_header(encoding)?;
322        let tuple_type = header.tuple_type()?;
323        Ok(PnmDecoder {
324            reader,
325            tuple: tuple_type,
326            header: PnmHeader {
327                decoded: HeaderRecord::Graymap(header),
328                encoded: None,
329            },
330        })
331    }
332
333    fn read_pixmap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> {
334        let header = reader.read_pixmap_header(encoding)?;
335        let tuple_type = header.tuple_type()?;
336        Ok(PnmDecoder {
337            reader,
338            tuple: tuple_type,
339            header: PnmHeader {
340                decoded: HeaderRecord::Pixmap(header),
341                encoded: None,
342            },
343        })
344    }
345
346    fn read_arbitrary_header(mut reader: R) -> ImageResult<PnmDecoder<R>> {
347        let header = reader.read_arbitrary_header()?;
348        let tuple_type = header.tuple_type()?;
349        Ok(PnmDecoder {
350            reader,
351            tuple: tuple_type,
352            header: PnmHeader {
353                decoded: HeaderRecord::Arbitrary(header),
354                encoded: None,
355            },
356        })
357    }
358}
359
360trait HeaderReader: Read {
361    /// Reads the two magic constant bytes
362    fn read_magic_constant(&mut self) -> ImageResult<[u8; 2]> {
363        let mut magic: [u8; 2] = [0, 0];
364        self.read_exact(&mut magic)?;
365        Ok(magic)
366    }
367
368    /// Reads a string as well as a single whitespace after it, ignoring comments
369    fn read_next_string(&mut self) -> ImageResult<String> {
370        let mut bytes = Vec::new();
371
372        // pair input bytes with a bool mask to remove comments
373        let mark_comments = self.bytes().scan(true, |partof, read| {
374            let byte = match read {
375                Err(err) => return Some((*partof, Err(err))),
376                Ok(byte) => byte,
377            };
378            let cur_enabled = *partof && byte != b'#';
379            let next_enabled = cur_enabled || (byte == b'\r' || byte == b'\n');
380            *partof = next_enabled;
381            Some((cur_enabled, Ok(byte)))
382        });
383
384        for (_, byte) in mark_comments.filter(|e| e.0) {
385            match byte {
386                Ok(b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ') => {
387                    if !bytes.is_empty() {
388                        break; // We're done as we already have some content
389                    }
390                }
391                Ok(byte) if !byte.is_ascii() => {
392                    return Err(DecoderError::NonAsciiByteInHeader(byte).into())
393                }
394                Ok(byte) => {
395                    bytes.push(byte);
396                }
397                Err(_) => break,
398            }
399        }
400
401        if bytes.is_empty() {
402            return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into()));
403        }
404
405        if !bytes.as_slice().is_ascii() {
406            // We have only filled the buffer with characters for which `byte.is_ascii()` holds.
407            unreachable!("Non-ASCII character should have returned sooner")
408        }
409
410        let string = String::from_utf8(bytes)
411            // We checked the precondition ourselves a few lines before, `bytes.as_slice().is_ascii()`.
412            .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
413
414        Ok(string)
415    }
416
417    fn read_next_line(&mut self) -> ImageResult<String> {
418        let mut buffer = Vec::new();
419        loop {
420            let mut byte = [0];
421            if self.read(&mut byte)? == 0 || byte[0] == b'\n' {
422                break;
423            }
424            buffer.push(byte[0]);
425        }
426
427        String::from_utf8(buffer)
428            .map_err(|e| ImageError::Decoding(DecodingError::new(ImageFormat::Pnm.into(), e)))
429    }
430
431    fn read_next_u32(&mut self) -> ImageResult<u32> {
432        let s = self.read_next_string()?;
433        s.parse::<u32>()
434            .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Preamble, s, err).into())
435    }
436
437    fn read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader> {
438        let width = self.read_next_u32()?;
439        let height = self.read_next_u32()?;
440        Ok(BitmapHeader {
441            encoding,
442            height,
443            width,
444        })
445    }
446
447    fn read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader> {
448        self.read_pixmap_header(encoding).map(
449            |PixmapHeader {
450                 encoding,
451                 width,
452                 height,
453                 maxval,
454             }| GraymapHeader {
455                encoding,
456                width,
457                height,
458                maxwhite: maxval,
459            },
460        )
461    }
462
463    fn read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader> {
464        let width = self.read_next_u32()?;
465        let height = self.read_next_u32()?;
466        let maxval = self.read_next_u32()?;
467        Ok(PixmapHeader {
468            encoding,
469            height,
470            width,
471            maxval,
472        })
473    }
474
475    fn read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader> {
476        fn parse_single_value_line(
477            line_val: &mut Option<u32>,
478            rest: &str,
479            line: PnmHeaderLine,
480        ) -> ImageResult<()> {
481            if line_val.is_some() {
482                Err(DecoderError::HeaderLineDuplicated(line).into())
483            } else {
484                let v = rest.trim().parse().map_err(|err| {
485                    DecoderError::UnparsableValue(ErrorDataSource::Line(line), rest.to_owned(), err)
486                })?;
487                *line_val = Some(v);
488                Ok(())
489            }
490        }
491
492        match self.bytes().next() {
493            None => return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into())),
494            Some(Err(io)) => return Err(ImageError::IoError(io)),
495            Some(Ok(b'\n')) => (),
496            Some(Ok(c)) => return Err(DecoderError::NotNewlineAfterP7Magic(c).into()),
497        }
498
499        let mut line;
500        let mut height: Option<u32> = None;
501        let mut width: Option<u32> = None;
502        let mut depth: Option<u32> = None;
503        let mut maxval: Option<u32> = None;
504        let mut tupltype: Option<String> = None;
505        loop {
506            line = self.read_next_line()?;
507            if line.is_empty() {
508                return Err(DecoderError::UnexpectedPnmHeaderEnd.into());
509            }
510            if line.as_bytes()[0] == b'#' {
511                continue;
512            }
513            if !line.is_ascii() {
514                return Err(DecoderError::NonAsciiLineInPamHeader.into());
515            }
516            #[allow(deprecated)]
517            let (identifier, rest) = line
518                .trim_left()
519                .split_at(line.find(char::is_whitespace).unwrap_or(line.len()));
520            match identifier {
521                "ENDHDR" => break,
522                "HEIGHT" => parse_single_value_line(&mut height, rest, PnmHeaderLine::Height)?,
523                "WIDTH" => parse_single_value_line(&mut width, rest, PnmHeaderLine::Width)?,
524                "DEPTH" => parse_single_value_line(&mut depth, rest, PnmHeaderLine::Depth)?,
525                "MAXVAL" => parse_single_value_line(&mut maxval, rest, PnmHeaderLine::Maxval)?,
526                "TUPLTYPE" => {
527                    let identifier = rest.trim();
528                    if tupltype.is_some() {
529                        let appended = tupltype.take().map(|mut v| {
530                            v.push(' ');
531                            v.push_str(identifier);
532                            v
533                        });
534                        tupltype = appended;
535                    } else {
536                        tupltype = Some(identifier.to_string());
537                    }
538                }
539                _ => return Err(DecoderError::HeaderLineUnknown(identifier.to_string()).into()),
540            }
541        }
542
543        let (h, w, d, m) = match (height, width, depth, maxval) {
544            (Some(h), Some(w), Some(d), Some(m)) => (h, w, d, m),
545            _ => {
546                return Err(DecoderError::HeaderLineMissing {
547                    height,
548                    width,
549                    depth,
550                    maxval,
551                }
552                .into())
553            }
554        };
555
556        let tupltype = match tupltype {
557            None => None,
558            Some(ref t) if t == "BLACKANDWHITE" => Some(ArbitraryTuplType::BlackAndWhite),
559            Some(ref t) if t == "BLACKANDWHITE_ALPHA" => {
560                Some(ArbitraryTuplType::BlackAndWhiteAlpha)
561            }
562            Some(ref t) if t == "GRAYSCALE" => Some(ArbitraryTuplType::Grayscale),
563            Some(ref t) if t == "GRAYSCALE_ALPHA" => Some(ArbitraryTuplType::GrayscaleAlpha),
564            Some(ref t) if t == "RGB" => Some(ArbitraryTuplType::RGB),
565            Some(ref t) if t == "RGB_ALPHA" => Some(ArbitraryTuplType::RGBAlpha),
566            Some(other) => Some(ArbitraryTuplType::Custom(other)),
567        };
568
569        Ok(ArbitraryHeader {
570            height: h,
571            width: w,
572            depth: d,
573            maxval: m,
574            tupltype,
575        })
576    }
577}
578
579impl<R> HeaderReader for R where R: Read {}
580
581impl<R: Read> ImageDecoder for PnmDecoder<R> {
582    fn dimensions(&self) -> (u32, u32) {
583        (self.header.width(), self.header.height())
584    }
585
586    fn color_type(&self) -> ColorType {
587        match self.tuple {
588            TupleType::PbmBit => ColorType::L8,
589            TupleType::BWBit => ColorType::L8,
590            TupleType::GrayU8 => ColorType::L8,
591            TupleType::GrayU16 => ColorType::L16,
592            TupleType::RGBU8 => ColorType::Rgb8,
593            TupleType::RGBU16 => ColorType::Rgb16,
594        }
595    }
596
597    fn original_color_type(&self) -> ExtendedColorType {
598        match self.tuple {
599            TupleType::PbmBit => ExtendedColorType::L1,
600            TupleType::BWBit => ExtendedColorType::L1,
601            TupleType::GrayU8 => ExtendedColorType::L8,
602            TupleType::GrayU16 => ExtendedColorType::L16,
603            TupleType::RGBU8 => ExtendedColorType::Rgb8,
604            TupleType::RGBU16 => ExtendedColorType::Rgb16,
605        }
606    }
607
608    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
609        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
610        match self.tuple {
611            TupleType::PbmBit => self.read_samples::<PbmBit>(1, buf),
612            TupleType::BWBit => self.read_samples::<BWBit>(1, buf),
613            TupleType::RGBU8 => self.read_samples::<U8>(3, buf),
614            TupleType::RGBU16 => self.read_samples::<U16>(3, buf),
615            TupleType::GrayU8 => self.read_samples::<U8>(1, buf),
616            TupleType::GrayU16 => self.read_samples::<U16>(1, buf),
617        }
618    }
619
620    fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
621        (*self).read_image(buf)
622    }
623}
624
625impl<R: Read> PnmDecoder<R> {
626    fn read_samples<S: Sample>(&mut self, components: u32, buf: &mut [u8]) -> ImageResult<()> {
627        match self.subtype().sample_encoding() {
628            SampleEncoding::Binary => {
629                let width = self.header.width();
630                let height = self.header.height();
631                let bytecount = S::bytelen(width, height, components)?;
632
633                let mut bytes = vec![];
634                self.reader
635                    .by_ref()
636                    // This conversion is potentially lossy but unlikely and in that case we error
637                    // later anyways.
638                    .take(bytecount as u64)
639                    .read_to_end(&mut bytes)?;
640                if bytes.len() != bytecount {
641                    return Err(DecoderError::InputTooShort.into());
642                }
643
644                let width: usize = width.try_into().map_err(|_| DecoderError::Overflow)?;
645                let components: usize =
646                    components.try_into().map_err(|_| DecoderError::Overflow)?;
647                let row_size = width
648                    .checked_mul(components)
649                    .ok_or(DecoderError::Overflow)?;
650
651                S::from_bytes(&bytes, row_size, buf)?;
652            }
653            SampleEncoding::Ascii => {
654                self.read_ascii::<S>(buf)?;
655            }
656        };
657
658        // Scale samples if 8bit or 16bit is not saturated
659        let current_sample_max = self.header.maximal_sample();
660        let target_sample_max = 256_u32.pow(S::sample_size()) - 1;
661
662        if current_sample_max != target_sample_max {
663            let factor = target_sample_max as f32 / current_sample_max as f32;
664
665            if S::sample_size() == 1 {
666                for v in buf.iter_mut() {
667                    *v = (f32::from(*v) * factor).round() as u8;
668                }
669            } else if S::sample_size() == 2 {
670                for chunk in buf.chunks_exact_mut(2) {
671                    let v = NativeEndian::read_u16(chunk);
672                    NativeEndian::write_u16(chunk, (f32::from(v) * factor).round() as u16);
673                }
674            }
675        }
676
677        Ok(())
678    }
679
680    fn read_ascii<Basic: Sample>(&mut self, output_buf: &mut [u8]) -> ImageResult<()> {
681        Basic::from_ascii(&mut self.reader, output_buf)
682    }
683
684    /// Get the pnm subtype, depending on the magic constant contained in the header
685    pub fn subtype(&self) -> PnmSubtype {
686        self.header.subtype()
687    }
688}
689
690fn read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T>
691where
692    T::Err: Display,
693{
694    let is_separator = |v: &u8| matches! { *v, b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' };
695
696    let token = reader
697        .bytes()
698        .skip_while(|v| v.as_ref().ok().map_or(false, is_separator))
699        .take_while(|v| v.as_ref().ok().map_or(false, |c| !is_separator(c)))
700        .collect::<Result<Vec<u8>, _>>()?;
701
702    if !token.is_ascii() {
703        return Err(DecoderError::NonAsciiSample.into());
704    }
705
706    let string = str::from_utf8(&token)
707        // We checked the precondition ourselves a few lines before with `token.is_ascii()`.
708        .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
709
710    string.parse().map_err(|err| {
711        DecoderError::UnparsableValue(ErrorDataSource::Sample, string.to_owned(), err).into()
712    })
713}
714
715impl Sample for U8 {
716    type Representation = u8;
717
718    fn from_bytes(bytes: &[u8], _row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
719        output_buf.copy_from_slice(bytes);
720        Ok(())
721    }
722
723    fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
724        for b in output_buf {
725            *b = read_separated_ascii(reader)?;
726        }
727        Ok(())
728    }
729}
730
731impl Sample for U16 {
732    type Representation = u16;
733
734    fn from_bytes(bytes: &[u8], _row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
735        output_buf.copy_from_slice(bytes);
736        for chunk in output_buf.chunks_exact_mut(2) {
737            let v = BigEndian::read_u16(chunk);
738            NativeEndian::write_u16(chunk, v);
739        }
740        Ok(())
741    }
742
743    fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
744        for chunk in output_buf.chunks_exact_mut(2) {
745            let v = read_separated_ascii::<u16>(reader)?;
746            NativeEndian::write_u16(chunk, v);
747        }
748        Ok(())
749    }
750}
751
752// The image is encoded in rows of bits, high order bits first. Any bits beyond the row bits should
753// be ignored. Also, contrary to rgb, black pixels are encoded as a 1 while white is 0. This will
754// need to be reversed for the grayscale output.
755impl Sample for PbmBit {
756    type Representation = u8;
757
758    fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
759        let count = width * samples;
760        let linelen = (count / 8) + u32::from((count % 8) != 0);
761        Ok((linelen * height) as usize)
762    }
763
764    fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
765        let mut expanded = utils::expand_bits(1, row_size.try_into().unwrap(), bytes);
766        for b in &mut expanded {
767            *b = !*b;
768        }
769        output_buf.copy_from_slice(&expanded);
770        Ok(())
771    }
772
773    fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
774        let mut bytes = reader.bytes();
775        for b in output_buf {
776            loop {
777                let byte = bytes
778                    .next()
779                    .ok_or_else::<ImageError, _>(|| DecoderError::InputTooShort.into())??;
780                match byte {
781                    b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' => continue,
782                    b'0' => *b = 255,
783                    b'1' => *b = 0,
784                    c => return Err(DecoderError::UnexpectedByteInRaster(c).into()),
785                }
786                break;
787            }
788        }
789
790        Ok(())
791    }
792}
793
794// Encoded just like a normal U8 but we check the values.
795impl Sample for BWBit {
796    type Representation = u8;
797
798    fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
799        U8::from_bytes(bytes, row_size, output_buf)?;
800        if let Some(val) = output_buf.iter().find(|&val| *val > 1) {
801            return Err(DecoderError::SampleOutOfBounds(*val).into());
802        }
803        Ok(())
804    }
805
806    fn from_ascii(_reader: &mut dyn Read, _output_buf: &mut [u8]) -> ImageResult<()> {
807        unreachable!("BW bits from anymaps are never encoded as ASCII")
808    }
809}
810
811impl DecodableImageHeader for BitmapHeader {
812    fn tuple_type(&self) -> ImageResult<TupleType> {
813        Ok(TupleType::PbmBit)
814    }
815}
816
817impl DecodableImageHeader for GraymapHeader {
818    fn tuple_type(&self) -> ImageResult<TupleType> {
819        match self.maxwhite {
820            0 => Err(DecoderError::MaxvalZero.into()),
821            v if v <= 0xFF => Ok(TupleType::GrayU8),
822            v if v <= 0xFFFF => Ok(TupleType::GrayU16),
823            _ => Err(DecoderError::MaxvalTooBig(self.maxwhite).into()),
824        }
825    }
826}
827
828impl DecodableImageHeader for PixmapHeader {
829    fn tuple_type(&self) -> ImageResult<TupleType> {
830        match self.maxval {
831            0 => Err(DecoderError::MaxvalZero.into()),
832            v if v <= 0xFF => Ok(TupleType::RGBU8),
833            v if v <= 0xFFFF => Ok(TupleType::RGBU16),
834            _ => Err(DecoderError::MaxvalTooBig(self.maxval).into()),
835        }
836    }
837}
838
839impl DecodableImageHeader for ArbitraryHeader {
840    fn tuple_type(&self) -> ImageResult<TupleType> {
841        match self.tupltype {
842            _ if self.maxval == 0 => Err(DecoderError::MaxvalZero.into()),
843            None if self.depth == 1 => Ok(TupleType::GrayU8),
844            None if self.depth == 2 => Err(ImageError::Unsupported(
845                UnsupportedError::from_format_and_kind(
846                    ImageFormat::Pnm.into(),
847                    UnsupportedErrorKind::Color(ExtendedColorType::La8),
848                ),
849            )),
850            None if self.depth == 3 => Ok(TupleType::RGBU8),
851            None if self.depth == 4 => Err(ImageError::Unsupported(
852                UnsupportedError::from_format_and_kind(
853                    ImageFormat::Pnm.into(),
854                    UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
855                ),
856            )),
857
858            Some(ArbitraryTuplType::BlackAndWhite) if self.maxval == 1 && self.depth == 1 => {
859                Ok(TupleType::BWBit)
860            }
861            Some(ArbitraryTuplType::BlackAndWhite) => Err(DecoderError::InvalidDepthOrMaxval {
862                tuple_type: ArbitraryTuplType::BlackAndWhite,
863                maxval: self.maxval,
864                depth: self.depth,
865            }
866            .into()),
867
868            Some(ArbitraryTuplType::Grayscale) if self.depth == 1 && self.maxval <= 0xFF => {
869                Ok(TupleType::GrayU8)
870            }
871            Some(ArbitraryTuplType::Grayscale) if self.depth <= 1 && self.maxval <= 0xFFFF => {
872                Ok(TupleType::GrayU16)
873            }
874            Some(ArbitraryTuplType::Grayscale) => Err(DecoderError::InvalidDepthOrMaxval {
875                tuple_type: ArbitraryTuplType::Grayscale,
876                maxval: self.maxval,
877                depth: self.depth,
878            }
879            .into()),
880
881            Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFF => {
882                Ok(TupleType::RGBU8)
883            }
884            Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFFFF => {
885                Ok(TupleType::RGBU16)
886            }
887            Some(ArbitraryTuplType::RGB) => Err(DecoderError::InvalidDepth {
888                tuple_type: ArbitraryTuplType::RGB,
889                depth: self.depth,
890            }
891            .into()),
892
893            Some(ArbitraryTuplType::BlackAndWhiteAlpha) => Err(ImageError::Unsupported(
894                UnsupportedError::from_format_and_kind(
895                    ImageFormat::Pnm.into(),
896                    UnsupportedErrorKind::GenericFeature(format!(
897                        "Color type {}",
898                        ArbitraryTuplType::BlackAndWhiteAlpha.name()
899                    )),
900                ),
901            )),
902            Some(ArbitraryTuplType::GrayscaleAlpha) => Err(ImageError::Unsupported(
903                UnsupportedError::from_format_and_kind(
904                    ImageFormat::Pnm.into(),
905                    UnsupportedErrorKind::Color(ExtendedColorType::La8),
906                ),
907            )),
908            Some(ArbitraryTuplType::RGBAlpha) => Err(ImageError::Unsupported(
909                UnsupportedError::from_format_and_kind(
910                    ImageFormat::Pnm.into(),
911                    UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
912                ),
913            )),
914            Some(ArbitraryTuplType::Custom(ref custom)) => Err(ImageError::Unsupported(
915                UnsupportedError::from_format_and_kind(
916                    ImageFormat::Pnm.into(),
917                    UnsupportedErrorKind::GenericFeature(format!("Tuple type {custom:?}")),
918                ),
919            )),
920            None => Err(DecoderError::TupleTypeUnrecognised.into()),
921        }
922    }
923}
924
925#[cfg(test)]
926mod tests {
927    use super::*;
928    /// Tests reading of a valid blackandwhite pam
929    #[test]
930    fn pam_blackandwhite() {
931        let pamdata = b"P7
932WIDTH 4
933HEIGHT 4
934DEPTH 1
935MAXVAL 1
936TUPLTYPE BLACKANDWHITE
937# Comment line
938ENDHDR
939\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01";
940        let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
941        assert_eq!(decoder.color_type(), ColorType::L8);
942        assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
943        assert_eq!(decoder.dimensions(), (4, 4));
944        assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
945
946        let mut image = vec![0; decoder.total_bytes() as usize];
947        decoder.read_image(&mut image).unwrap();
948        assert_eq!(
949            image,
950            vec![
951                0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
952                0x00, 0xFF
953            ]
954        );
955        match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
956            (
957                _,
958                PnmHeader {
959                    decoded:
960                        HeaderRecord::Arbitrary(ArbitraryHeader {
961                            width: 4,
962                            height: 4,
963                            maxval: 1,
964                            depth: 1,
965                            tupltype: Some(ArbitraryTuplType::BlackAndWhite),
966                        }),
967                    encoded: _,
968                },
969            ) => (),
970            _ => panic!("Decoded header is incorrect"),
971        }
972    }
973
974    /// Tests reading of a valid grayscale pam
975    #[test]
976    fn pam_grayscale() {
977        let pamdata = b"P7
978WIDTH 4
979HEIGHT 4
980DEPTH 1
981MAXVAL 255
982TUPLTYPE GRAYSCALE
983# Comment line
984ENDHDR
985\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
986        let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
987        assert_eq!(decoder.color_type(), ColorType::L8);
988        assert_eq!(decoder.dimensions(), (4, 4));
989        assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
990
991        let mut image = vec![0; decoder.total_bytes() as usize];
992        decoder.read_image(&mut image).unwrap();
993        assert_eq!(
994            image,
995            vec![
996                0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
997                0xbe, 0xef
998            ]
999        );
1000        match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1001            (
1002                _,
1003                PnmHeader {
1004                    decoded:
1005                        HeaderRecord::Arbitrary(ArbitraryHeader {
1006                            width: 4,
1007                            height: 4,
1008                            depth: 1,
1009                            maxval: 255,
1010                            tupltype: Some(ArbitraryTuplType::Grayscale),
1011                        }),
1012                    encoded: _,
1013                },
1014            ) => (),
1015            _ => panic!("Decoded header is incorrect"),
1016        }
1017    }
1018
1019    /// Tests reading of a valid rgb pam
1020    #[test]
1021    fn pam_rgb() {
1022        let pamdata = b"P7
1023# Comment line
1024MAXVAL 255
1025TUPLTYPE RGB
1026DEPTH 3
1027WIDTH 2
1028HEIGHT 2
1029ENDHDR
1030\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1031        let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1032        assert_eq!(decoder.color_type(), ColorType::Rgb8);
1033        assert_eq!(decoder.dimensions(), (2, 2));
1034        assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1035
1036        let mut image = vec![0; decoder.total_bytes() as usize];
1037        decoder.read_image(&mut image).unwrap();
1038        assert_eq!(
1039            image,
1040            vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef]
1041        );
1042        match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1043            (
1044                _,
1045                PnmHeader {
1046                    decoded:
1047                        HeaderRecord::Arbitrary(ArbitraryHeader {
1048                            maxval: 255,
1049                            tupltype: Some(ArbitraryTuplType::RGB),
1050                            depth: 3,
1051                            width: 2,
1052                            height: 2,
1053                        }),
1054                    encoded: _,
1055                },
1056            ) => (),
1057            _ => panic!("Decoded header is incorrect"),
1058        }
1059    }
1060
1061    #[test]
1062    fn pbm_binary() {
1063        // The data contains two rows of the image (each line is padded to the full byte). For
1064        // comments on its format, see documentation of `impl SampleType for PbmBit`.
1065        let pbmbinary = [&b"P4 6 2\n"[..], &[0b0110_1100_u8, 0b1011_0111]].concat();
1066        let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1067        assert_eq!(decoder.color_type(), ColorType::L8);
1068        assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1069        assert_eq!(decoder.dimensions(), (6, 2));
1070        assert_eq!(
1071            decoder.subtype(),
1072            PnmSubtype::Bitmap(SampleEncoding::Binary)
1073        );
1074        let mut image = vec![0; decoder.total_bytes() as usize];
1075        decoder.read_image(&mut image).unwrap();
1076        assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1077        match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1078            (
1079                _,
1080                PnmHeader {
1081                    decoded:
1082                        HeaderRecord::Bitmap(BitmapHeader {
1083                            encoding: SampleEncoding::Binary,
1084                            width: 6,
1085                            height: 2,
1086                        }),
1087                    encoded: _,
1088                },
1089            ) => (),
1090            _ => panic!("Decoded header is incorrect"),
1091        }
1092    }
1093
1094    /// A previous infinite loop.
1095    #[test]
1096    fn pbm_binary_ascii_termination() {
1097        use std::io::{BufReader, Cursor, Error, ErrorKind, Read, Result};
1098        struct FailRead(Cursor<&'static [u8]>);
1099
1100        impl Read for FailRead {
1101            fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1102                match self.0.read(buf) {
1103                    Ok(n) if n > 0 => Ok(n),
1104                    _ => Err(Error::new(
1105                        ErrorKind::BrokenPipe,
1106                        "Simulated broken pipe error",
1107                    )),
1108                }
1109            }
1110        }
1111
1112        let pbmbinary = BufReader::new(FailRead(Cursor::new(b"P1 1 1\n")));
1113
1114        let decoder = PnmDecoder::new(pbmbinary).unwrap();
1115        let mut image = vec![0; decoder.total_bytes() as usize];
1116        decoder
1117            .read_image(&mut image)
1118            .expect_err("Image is malformed");
1119    }
1120
1121    #[test]
1122    fn pbm_ascii() {
1123        // The data contains two rows of the image (each line is padded to the full byte). For
1124        // comments on its format, see documentation of `impl SampleType for PbmBit`.  Tests all
1125        // whitespace characters that should be allowed (the 6 characters according to POSIX).
1126        let pbmbinary = b"P1 6 2\n 0 1 1 0 1 1\n1 0 1 1 0\t\n\x0b\x0c\r1";
1127        let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1128        assert_eq!(decoder.color_type(), ColorType::L8);
1129        assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1130        assert_eq!(decoder.dimensions(), (6, 2));
1131        assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii));
1132
1133        let mut image = vec![0; decoder.total_bytes() as usize];
1134        decoder.read_image(&mut image).unwrap();
1135        assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1136        match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1137            (
1138                _,
1139                PnmHeader {
1140                    decoded:
1141                        HeaderRecord::Bitmap(BitmapHeader {
1142                            encoding: SampleEncoding::Ascii,
1143                            width: 6,
1144                            height: 2,
1145                        }),
1146                    encoded: _,
1147                },
1148            ) => (),
1149            _ => panic!("Decoded header is incorrect"),
1150        }
1151    }
1152
1153    #[test]
1154    fn pbm_ascii_nospace() {
1155        // The data contains two rows of the image (each line is padded to the full byte). Notably,
1156        // it is completely within specification for the ascii data not to contain separating
1157        // whitespace for the pbm format or any mix.
1158        let pbmbinary = b"P1 6 2\n011011101101";
1159        let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1160        assert_eq!(decoder.color_type(), ColorType::L8);
1161        assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1162        assert_eq!(decoder.dimensions(), (6, 2));
1163        assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii));
1164
1165        let mut image = vec![0; decoder.total_bytes() as usize];
1166        decoder.read_image(&mut image).unwrap();
1167        assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1168        match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1169            (
1170                _,
1171                PnmHeader {
1172                    decoded:
1173                        HeaderRecord::Bitmap(BitmapHeader {
1174                            encoding: SampleEncoding::Ascii,
1175                            width: 6,
1176                            height: 2,
1177                        }),
1178                    encoded: _,
1179                },
1180            ) => (),
1181            _ => panic!("Decoded header is incorrect"),
1182        }
1183    }
1184
1185    #[test]
1186    fn pgm_binary() {
1187        // The data contains two rows of the image (each line is padded to the full byte). For
1188        // comments on its format, see documentation of `impl SampleType for PbmBit`.
1189        let elements = (0..16).collect::<Vec<_>>();
1190        let pbmbinary = [&b"P5 4 4 255\n"[..], &elements].concat();
1191        let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1192        assert_eq!(decoder.color_type(), ColorType::L8);
1193        assert_eq!(decoder.dimensions(), (4, 4));
1194        assert_eq!(
1195            decoder.subtype(),
1196            PnmSubtype::Graymap(SampleEncoding::Binary)
1197        );
1198        let mut image = vec![0; decoder.total_bytes() as usize];
1199        decoder.read_image(&mut image).unwrap();
1200        assert_eq!(image, elements);
1201        match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1202            (
1203                _,
1204                PnmHeader {
1205                    decoded:
1206                        HeaderRecord::Graymap(GraymapHeader {
1207                            encoding: SampleEncoding::Binary,
1208                            width: 4,
1209                            height: 4,
1210                            maxwhite: 255,
1211                        }),
1212                    encoded: _,
1213                },
1214            ) => (),
1215            _ => panic!("Decoded header is incorrect"),
1216        }
1217    }
1218
1219    #[test]
1220    fn pgm_ascii() {
1221        // The data contains two rows of the image (each line is padded to the full byte). For
1222        // comments on its format, see documentation of `impl SampleType for PbmBit`.
1223        let pbmbinary = b"P2 4 4 255\n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15";
1224        let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1225        assert_eq!(decoder.color_type(), ColorType::L8);
1226        assert_eq!(decoder.dimensions(), (4, 4));
1227        assert_eq!(
1228            decoder.subtype(),
1229            PnmSubtype::Graymap(SampleEncoding::Ascii)
1230        );
1231        let mut image = vec![0; decoder.total_bytes() as usize];
1232        decoder.read_image(&mut image).unwrap();
1233        assert_eq!(image, (0..16).collect::<Vec<_>>());
1234        match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1235            (
1236                _,
1237                PnmHeader {
1238                    decoded:
1239                        HeaderRecord::Graymap(GraymapHeader {
1240                            encoding: SampleEncoding::Ascii,
1241                            width: 4,
1242                            height: 4,
1243                            maxwhite: 255,
1244                        }),
1245                    encoded: _,
1246                },
1247            ) => (),
1248            _ => panic!("Decoded header is incorrect"),
1249        }
1250    }
1251
1252    #[test]
1253    fn ppm_ascii() {
1254        let ascii = b"P3 1 1 2000\n0 1000 2000";
1255        let decoder = PnmDecoder::new(&ascii[..]).unwrap();
1256        let mut image = vec![0; decoder.total_bytes() as usize];
1257        decoder.read_image(&mut image).unwrap();
1258        assert_eq!(
1259            image,
1260            [
1261                0_u16.to_ne_bytes(),
1262                (u16::MAX / 2 + 1).to_ne_bytes(),
1263                u16::MAX.to_ne_bytes()
1264            ]
1265            .into_iter()
1266            .flatten()
1267            .collect::<Vec<_>>()
1268        );
1269    }
1270
1271    #[test]
1272    fn dimension_overflow() {
1273        let pamdata = b"P7
1274# Comment line
1275MAXVAL 255
1276TUPLTYPE RGB
1277DEPTH 3
1278WIDTH 4294967295
1279HEIGHT 4294967295
1280ENDHDR
1281\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1282
1283        assert!(PnmDecoder::new(&pamdata[..]).is_err());
1284    }
1285
1286    #[test]
1287    fn issue_1508() {
1288        let _ = crate::load_from_memory(b"P391919 16999 1 1 9 919 16999 1 9999 999* 99999 N");
1289    }
1290
1291    #[test]
1292    fn issue_1616_overflow() {
1293        let data = [
1294            80, 54, 10, 52, 50, 57, 52, 56, 50, 57, 52, 56, 35, 56, 10, 52, 10, 48, 10, 12, 12, 56,
1295        ];
1296        // Validate: we have a header. Note: we might already calculate that this will fail but
1297        // then we could not return information about the header to the caller.
1298        let decoder = PnmDecoder::new(&data[..]).unwrap();
1299        let mut image = vec![0; decoder.total_bytes() as usize];
1300        let _ = decoder.read_image(&mut image);
1301    }
1302}