Imported Upstream version 3.0.1
[platform/upstream/libjpeg-turbo.git] / rdppm.c
1 /*
2  * rdppm.c
3  *
4  * This file was part of the Independent JPEG Group's software:
5  * Copyright (C) 1991-1997, Thomas G. Lane.
6  * Modified 2009 by Bill Allombert, Guido Vollbeding.
7  * libjpeg-turbo Modifications:
8  * Copyright (C) 2015-2017, 2020-2023, D. R. Commander.
9  * For conditions of distribution and use, see the accompanying README.ijg
10  * file.
11  *
12  * This file contains routines to read input images in PPM/PGM format.
13  * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
14  * The PBMPLUS library is NOT required to compile this software
15  * (but it is highly useful as a set of PPM image manipulation programs).
16  *
17  * These routines may need modification for non-Unix environments or
18  * specialized applications.  As they stand, they assume input from
19  * an ordinary stdio stream.  They further assume that reading begins
20  * at the start of the file; start_input may need work if the
21  * user interface has already read some data (e.g., to determine that
22  * the file is indeed PPM format).
23  */
24
25 #include "cmyk.h"
26 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
27
28 #if defined(PPM_SUPPORTED) && \
29     (BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED))
30
31
32 /* Portions of this code are based on the PBMPLUS library, which is:
33 **
34 ** Copyright (C) 1988 by Jef Poskanzer.
35 **
36 ** Permission to use, copy, modify, and distribute this software and its
37 ** documentation for any purpose and without fee is hereby granted, provided
38 ** that the above copyright notice appear in all copies and that both that
39 ** copyright notice and this permission notice appear in supporting
40 ** documentation.  This software is provided "as is" without express or
41 ** implied warranty.
42 */
43
44
45 /* Macros to deal with unsigned chars as efficiently as compiler allows */
46
47 typedef unsigned char U_CHAR;
48 #define UCH(x)  ((int)(x))
49
50
51 #define ReadOK(file, buffer, len) \
52   (fread(buffer, 1, len, file) == ((size_t)(len)))
53
54 static int alpha_index[JPEG_NUMCS] = {
55   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
56 };
57
58
59 /* Private version of data source object */
60
61 typedef struct {
62   struct cjpeg_source_struct pub; /* public fields */
63
64   /* Usually these two pointers point to the same place: */
65   U_CHAR *iobuffer;             /* fread's I/O buffer */
66   _JSAMPROW pixrow;             /* compressor input buffer */
67   size_t buffer_width;          /* width of I/O buffer */
68   _JSAMPLE *rescale;            /* => maxval-remapping array, or NULL */
69   unsigned int maxval;
70 } ppm_source_struct;
71
72 typedef ppm_source_struct *ppm_source_ptr;
73
74
75 LOCAL(int)
76 pbm_getc(FILE *infile)
77 /* Read next char, skipping over any comments */
78 /* A comment/newline sequence is returned as a newline */
79 {
80   register int ch;
81
82   ch = getc(infile);
83   if (ch == '#') {
84     do {
85       ch = getc(infile);
86     } while (ch != '\n' && ch != EOF);
87   }
88   return ch;
89 }
90
91
92 LOCAL(unsigned int)
93 read_pbm_integer(j_compress_ptr cinfo, FILE *infile, unsigned int maxval)
94 /* Read an unsigned decimal integer from the PPM file */
95 /* Swallows one trailing character after the integer */
96 /* Note that on a 16-bit-int machine, only values up to 64k can be read. */
97 /* This should not be a problem in practice. */
98 {
99   register int ch;
100   register unsigned int val;
101
102   /* Skip any leading whitespace */
103   do {
104     ch = pbm_getc(infile);
105     if (ch == EOF)
106       ERREXIT(cinfo, JERR_INPUT_EOF);
107   } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
108
109   if (ch < '0' || ch > '9')
110     ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
111
112   val = ch - '0';
113   while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
114     val *= 10;
115     val += ch - '0';
116     if (val > maxval)
117       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
118   }
119
120   return val;
121 }
122
123
124 /*
125  * Read one row of pixels.
126  *
127  * We provide several different versions depending on input file format.
128  * In all cases, input is scaled to the size of _JSAMPLE.
129  *
130  * A really fast path is provided for reading byte/sample raw files with
131  * maxval = _MAXJSAMPLE, which is the normal case for 8-bit data.
132  */
133
134
135 METHODDEF(JDIMENSION)
136 get_text_gray_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
137 /* This version is for reading text-format PGM files with any maxval */
138 {
139   ppm_source_ptr source = (ppm_source_ptr)sinfo;
140   FILE *infile = source->pub.input_file;
141   register _JSAMPROW ptr;
142   register _JSAMPLE *rescale = source->rescale;
143   JDIMENSION col;
144   unsigned int maxval = source->maxval;
145
146   ptr = source->pub._buffer[0];
147   for (col = cinfo->image_width; col > 0; col--) {
148     *ptr++ = rescale[read_pbm_integer(cinfo, infile, maxval)];
149   }
150   return 1;
151 }
152
153
154 #define GRAY_RGB_READ_LOOP(read_op, alpha_set_op) { \
155   for (col = cinfo->image_width; col > 0; col--) { \
156     ptr[rindex] = ptr[gindex] = ptr[bindex] = read_op; \
157     alpha_set_op \
158     ptr += ps; \
159   } \
160 }
161
162 METHODDEF(JDIMENSION)
163 get_text_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
164 /* This version is for reading text-format PGM files with any maxval and
165    converting to extended RGB */
166 {
167   ppm_source_ptr source = (ppm_source_ptr)sinfo;
168   FILE *infile = source->pub.input_file;
169   register _JSAMPROW ptr;
170   register _JSAMPLE *rescale = source->rescale;
171   JDIMENSION col;
172   unsigned int maxval = source->maxval;
173   register int rindex = rgb_red[cinfo->in_color_space];
174   register int gindex = rgb_green[cinfo->in_color_space];
175   register int bindex = rgb_blue[cinfo->in_color_space];
176   register int aindex = alpha_index[cinfo->in_color_space];
177   register int ps = rgb_pixelsize[cinfo->in_color_space];
178
179   ptr = source->pub._buffer[0];
180   if (maxval == _MAXJSAMPLE) {
181     if (aindex >= 0)
182       GRAY_RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
183                          ptr[aindex] = _MAXJSAMPLE;)
184     else
185       GRAY_RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
186   } else {
187     if (aindex >= 0)
188       GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
189                          ptr[aindex] = _MAXJSAMPLE;)
190     else
191       GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
192   }
193   return 1;
194 }
195
196
197 METHODDEF(JDIMENSION)
198 get_text_gray_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
199 /* This version is for reading text-format PGM files with any maxval and
200    converting to CMYK */
201 {
202   ppm_source_ptr source = (ppm_source_ptr)sinfo;
203   FILE *infile = source->pub.input_file;
204   register _JSAMPROW ptr;
205   register _JSAMPLE *rescale = source->rescale;
206   JDIMENSION col;
207   unsigned int maxval = source->maxval;
208
209   ptr = source->pub._buffer[0];
210   if (maxval == _MAXJSAMPLE) {
211     for (col = cinfo->image_width; col > 0; col--) {
212       _JSAMPLE gray = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
213       rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
214       ptr += 4;
215     }
216   } else {
217     for (col = cinfo->image_width; col > 0; col--) {
218       _JSAMPLE gray = rescale[read_pbm_integer(cinfo, infile, maxval)];
219       rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
220       ptr += 4;
221     }
222   }
223   return 1;
224 }
225
226
227 #define RGB_READ_LOOP(read_op, alpha_set_op) { \
228   for (col = cinfo->image_width; col > 0; col--) { \
229     ptr[rindex] = read_op; \
230     ptr[gindex] = read_op; \
231     ptr[bindex] = read_op; \
232     alpha_set_op \
233     ptr += ps; \
234   } \
235 }
236
237 METHODDEF(JDIMENSION)
238 get_text_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
239 /* This version is for reading text-format PPM files with any maxval */
240 {
241   ppm_source_ptr source = (ppm_source_ptr)sinfo;
242   FILE *infile = source->pub.input_file;
243   register _JSAMPROW ptr;
244   register _JSAMPLE *rescale = source->rescale;
245   JDIMENSION col;
246   unsigned int maxval = source->maxval;
247   register int rindex = rgb_red[cinfo->in_color_space];
248   register int gindex = rgb_green[cinfo->in_color_space];
249   register int bindex = rgb_blue[cinfo->in_color_space];
250   register int aindex = alpha_index[cinfo->in_color_space];
251   register int ps = rgb_pixelsize[cinfo->in_color_space];
252
253   ptr = source->pub._buffer[0];
254   if (maxval == _MAXJSAMPLE) {
255     if (aindex >= 0)
256       RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
257                     ptr[aindex] = _MAXJSAMPLE;)
258     else
259       RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
260   } else {
261     if (aindex >= 0)
262       RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
263                     ptr[aindex] = _MAXJSAMPLE;)
264     else
265       RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
266   }
267   return 1;
268 }
269
270
271 METHODDEF(JDIMENSION)
272 get_text_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
273 /* This version is for reading text-format PPM files with any maxval and
274    converting to CMYK */
275 {
276   ppm_source_ptr source = (ppm_source_ptr)sinfo;
277   FILE *infile = source->pub.input_file;
278   register _JSAMPROW ptr;
279   register _JSAMPLE *rescale = source->rescale;
280   JDIMENSION col;
281   unsigned int maxval = source->maxval;
282
283   ptr = source->pub._buffer[0];
284   if (maxval == _MAXJSAMPLE) {
285     for (col = cinfo->image_width; col > 0; col--) {
286       _JSAMPLE r = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
287       _JSAMPLE g = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
288       _JSAMPLE b = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
289       rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
290       ptr += 4;
291     }
292   } else {
293     for (col = cinfo->image_width; col > 0; col--) {
294       _JSAMPLE r = rescale[read_pbm_integer(cinfo, infile, maxval)];
295       _JSAMPLE g = rescale[read_pbm_integer(cinfo, infile, maxval)];
296       _JSAMPLE b = rescale[read_pbm_integer(cinfo, infile, maxval)];
297       rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
298       ptr += 4;
299     }
300   }
301   return 1;
302 }
303
304
305 METHODDEF(JDIMENSION)
306 get_scaled_gray_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
307 /* This version is for reading raw-byte-format PGM files with any maxval */
308 {
309   ppm_source_ptr source = (ppm_source_ptr)sinfo;
310   register _JSAMPROW ptr;
311   register U_CHAR *bufferptr;
312   register _JSAMPLE *rescale = source->rescale;
313   JDIMENSION col;
314
315   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
316     ERREXIT(cinfo, JERR_INPUT_EOF);
317   ptr = source->pub._buffer[0];
318   bufferptr = source->iobuffer;
319   for (col = cinfo->image_width; col > 0; col--) {
320     *ptr++ = rescale[UCH(*bufferptr++)];
321   }
322   return 1;
323 }
324
325
326 METHODDEF(JDIMENSION)
327 get_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
328 /* This version is for reading raw-byte-format PGM files with any maxval
329    and converting to extended RGB */
330 {
331   ppm_source_ptr source = (ppm_source_ptr)sinfo;
332   register _JSAMPROW ptr;
333   register U_CHAR *bufferptr;
334   register _JSAMPLE *rescale = source->rescale;
335   JDIMENSION col;
336   unsigned int maxval = source->maxval;
337   register int rindex = rgb_red[cinfo->in_color_space];
338   register int gindex = rgb_green[cinfo->in_color_space];
339   register int bindex = rgb_blue[cinfo->in_color_space];
340   register int aindex = alpha_index[cinfo->in_color_space];
341   register int ps = rgb_pixelsize[cinfo->in_color_space];
342
343   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
344     ERREXIT(cinfo, JERR_INPUT_EOF);
345   ptr = source->pub._buffer[0];
346   bufferptr = source->iobuffer;
347   if (maxval == _MAXJSAMPLE) {
348     if (aindex >= 0)
349       GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = _MAXJSAMPLE;)
350     else
351       GRAY_RGB_READ_LOOP(*bufferptr++, {})
352   } else {
353     if (aindex >= 0)
354       GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)],
355                          ptr[aindex] = _MAXJSAMPLE;)
356     else
357       GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
358   }
359   return 1;
360 }
361
362
363 METHODDEF(JDIMENSION)
364 get_gray_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
365 /* This version is for reading raw-byte-format PGM files with any maxval
366    and converting to CMYK */
367 {
368   ppm_source_ptr source = (ppm_source_ptr)sinfo;
369   register _JSAMPROW ptr;
370   register U_CHAR *bufferptr;
371   register _JSAMPLE *rescale = source->rescale;
372   JDIMENSION col;
373   unsigned int maxval = source->maxval;
374
375   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
376     ERREXIT(cinfo, JERR_INPUT_EOF);
377   ptr = source->pub._buffer[0];
378   bufferptr = source->iobuffer;
379   if (maxval == _MAXJSAMPLE) {
380     for (col = cinfo->image_width; col > 0; col--) {
381       _JSAMPLE gray = *bufferptr++;
382       rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
383       ptr += 4;
384     }
385   } else {
386     for (col = cinfo->image_width; col > 0; col--) {
387       _JSAMPLE gray = rescale[UCH(*bufferptr++)];
388       rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
389       ptr += 4;
390     }
391   }
392   return 1;
393 }
394
395
396 METHODDEF(JDIMENSION)
397 get_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
398 /* This version is for reading raw-byte-format PPM files with any maxval */
399 {
400   ppm_source_ptr source = (ppm_source_ptr)sinfo;
401   register _JSAMPROW ptr;
402   register U_CHAR *bufferptr;
403   register _JSAMPLE *rescale = source->rescale;
404   JDIMENSION col;
405   unsigned int maxval = source->maxval;
406   register int rindex = rgb_red[cinfo->in_color_space];
407   register int gindex = rgb_green[cinfo->in_color_space];
408   register int bindex = rgb_blue[cinfo->in_color_space];
409   register int aindex = alpha_index[cinfo->in_color_space];
410   register int ps = rgb_pixelsize[cinfo->in_color_space];
411
412   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
413     ERREXIT(cinfo, JERR_INPUT_EOF);
414   ptr = source->pub._buffer[0];
415   bufferptr = source->iobuffer;
416   if (maxval == _MAXJSAMPLE) {
417     if (aindex >= 0)
418       RGB_READ_LOOP(*bufferptr++, ptr[aindex] = _MAXJSAMPLE;)
419     else
420       RGB_READ_LOOP(*bufferptr++, {})
421   } else {
422     if (aindex >= 0)
423       RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = _MAXJSAMPLE;)
424     else
425       RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
426   }
427   return 1;
428 }
429
430
431 METHODDEF(JDIMENSION)
432 get_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
433 /* This version is for reading raw-byte-format PPM files with any maxval and
434    converting to CMYK */
435 {
436   ppm_source_ptr source = (ppm_source_ptr)sinfo;
437   register _JSAMPROW ptr;
438   register U_CHAR *bufferptr;
439   register _JSAMPLE *rescale = source->rescale;
440   JDIMENSION col;
441   unsigned int maxval = source->maxval;
442
443   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
444     ERREXIT(cinfo, JERR_INPUT_EOF);
445   ptr = source->pub._buffer[0];
446   bufferptr = source->iobuffer;
447   if (maxval == _MAXJSAMPLE) {
448     for (col = cinfo->image_width; col > 0; col--) {
449       _JSAMPLE r = *bufferptr++;
450       _JSAMPLE g = *bufferptr++;
451       _JSAMPLE b = *bufferptr++;
452       rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
453       ptr += 4;
454     }
455   } else {
456     for (col = cinfo->image_width; col > 0; col--) {
457       _JSAMPLE r = rescale[UCH(*bufferptr++)];
458       _JSAMPLE g = rescale[UCH(*bufferptr++)];
459       _JSAMPLE b = rescale[UCH(*bufferptr++)];
460       rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
461       ptr += 4;
462     }
463   }
464   return 1;
465 }
466
467
468 METHODDEF(JDIMENSION)
469 get_raw_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
470 /* This version is for reading raw-byte-format files with maxval = _MAXJSAMPLE.
471  * In this case we just read right into the _JSAMPLE buffer!
472  * Note that same code works for PPM and PGM files.
473  */
474 {
475   ppm_source_ptr source = (ppm_source_ptr)sinfo;
476
477   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
478     ERREXIT(cinfo, JERR_INPUT_EOF);
479   return 1;
480 }
481
482
483 METHODDEF(JDIMENSION)
484 get_word_gray_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
485 /* This version is for reading raw-word-format PGM files with any maxval */
486 {
487   ppm_source_ptr source = (ppm_source_ptr)sinfo;
488   register _JSAMPROW ptr;
489   register U_CHAR *bufferptr;
490   register _JSAMPLE *rescale = source->rescale;
491   JDIMENSION col;
492   unsigned int maxval = source->maxval;
493
494   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
495     ERREXIT(cinfo, JERR_INPUT_EOF);
496   ptr = source->pub._buffer[0];
497   bufferptr = source->iobuffer;
498   for (col = cinfo->image_width; col > 0; col--) {
499     register unsigned int temp;
500     temp  = UCH(*bufferptr++) << 8;
501     temp |= UCH(*bufferptr++);
502     if (temp > maxval)
503       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
504     *ptr++ = rescale[temp];
505   }
506   return 1;
507 }
508
509
510 METHODDEF(JDIMENSION)
511 get_word_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
512 /* This version is for reading raw-word-format PGM files with any maxval */
513 {
514   ppm_source_ptr source = (ppm_source_ptr)sinfo;
515   register _JSAMPROW ptr;
516   register U_CHAR *bufferptr;
517   register _JSAMPLE *rescale = source->rescale;
518   JDIMENSION col;
519   unsigned int maxval = source->maxval;
520   register int rindex = rgb_red[cinfo->in_color_space];
521   register int gindex = rgb_green[cinfo->in_color_space];
522   register int bindex = rgb_blue[cinfo->in_color_space];
523   register int aindex = alpha_index[cinfo->in_color_space];
524   register int ps = rgb_pixelsize[cinfo->in_color_space];
525
526   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
527     ERREXIT(cinfo, JERR_INPUT_EOF);
528   ptr = source->pub._buffer[0];
529   bufferptr = source->iobuffer;
530   for (col = cinfo->image_width; col > 0; col--) {
531     register unsigned int temp;
532     temp  = UCH(*bufferptr++) << 8;
533     temp |= UCH(*bufferptr++);
534     if (temp > maxval)
535       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
536     ptr[rindex] = ptr[gindex] = ptr[bindex] = rescale[temp];
537     if (aindex >= 0)
538       ptr[aindex] = _MAXJSAMPLE;
539     ptr += ps;
540   }
541   return 1;
542 }
543
544
545 METHODDEF(JDIMENSION)
546 get_word_gray_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
547 /* This version is for reading raw-word-format PGM files with any maxval */
548 {
549   ppm_source_ptr source = (ppm_source_ptr)sinfo;
550   register _JSAMPROW ptr;
551   register U_CHAR *bufferptr;
552   register _JSAMPLE *rescale = source->rescale;
553   JDIMENSION col;
554   unsigned int maxval = source->maxval;
555
556   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
557     ERREXIT(cinfo, JERR_INPUT_EOF);
558   ptr = source->pub._buffer[0];
559   bufferptr = source->iobuffer;
560   for (col = cinfo->image_width; col > 0; col--) {
561     register unsigned int gray;
562     gray  = UCH(*bufferptr++) << 8;
563     gray |= UCH(*bufferptr++);
564     if (gray > maxval)
565       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
566     rgb_to_cmyk(rescale[gray], rescale[gray], rescale[gray], ptr, ptr + 1,
567                 ptr + 2, ptr + 3);
568     ptr += 4;
569   }
570   return 1;
571 }
572
573
574 METHODDEF(JDIMENSION)
575 get_word_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
576 /* This version is for reading raw-word-format PPM files with any maxval */
577 {
578   ppm_source_ptr source = (ppm_source_ptr)sinfo;
579   register _JSAMPROW ptr;
580   register U_CHAR *bufferptr;
581   register _JSAMPLE *rescale = source->rescale;
582   JDIMENSION col;
583   unsigned int maxval = source->maxval;
584   register int rindex = rgb_red[cinfo->in_color_space];
585   register int gindex = rgb_green[cinfo->in_color_space];
586   register int bindex = rgb_blue[cinfo->in_color_space];
587   register int aindex = alpha_index[cinfo->in_color_space];
588   register int ps = rgb_pixelsize[cinfo->in_color_space];
589
590   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
591     ERREXIT(cinfo, JERR_INPUT_EOF);
592   ptr = source->pub._buffer[0];
593   bufferptr = source->iobuffer;
594   for (col = cinfo->image_width; col > 0; col--) {
595     register unsigned int temp;
596     temp  = UCH(*bufferptr++) << 8;
597     temp |= UCH(*bufferptr++);
598     if (temp > maxval)
599       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
600     ptr[rindex] = rescale[temp];
601     temp  = UCH(*bufferptr++) << 8;
602     temp |= UCH(*bufferptr++);
603     if (temp > maxval)
604       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
605     ptr[gindex] = rescale[temp];
606     temp  = UCH(*bufferptr++) << 8;
607     temp |= UCH(*bufferptr++);
608     if (temp > maxval)
609       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
610     ptr[bindex] = rescale[temp];
611     if (aindex >= 0)
612       ptr[aindex] = _MAXJSAMPLE;
613     ptr += ps;
614   }
615   return 1;
616 }
617
618
619 METHODDEF(JDIMENSION)
620 get_word_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
621 /* This version is for reading raw-word-format PPM files with any maxval */
622 {
623   ppm_source_ptr source = (ppm_source_ptr)sinfo;
624   register _JSAMPROW ptr;
625   register U_CHAR *bufferptr;
626   register _JSAMPLE *rescale = source->rescale;
627   JDIMENSION col;
628   unsigned int maxval = source->maxval;
629
630   if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
631     ERREXIT(cinfo, JERR_INPUT_EOF);
632   ptr = source->pub._buffer[0];
633   bufferptr = source->iobuffer;
634   for (col = cinfo->image_width; col > 0; col--) {
635     register unsigned int r, g, b;
636     r  = UCH(*bufferptr++) << 8;
637     r |= UCH(*bufferptr++);
638     if (r > maxval)
639       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
640     g  = UCH(*bufferptr++) << 8;
641     g |= UCH(*bufferptr++);
642     if (g > maxval)
643       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
644     b  = UCH(*bufferptr++) << 8;
645     b |= UCH(*bufferptr++);
646     if (b > maxval)
647       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
648     rgb_to_cmyk(rescale[r], rescale[g], rescale[b], ptr, ptr + 1, ptr + 2,
649                 ptr + 3);
650     ptr += 4;
651   }
652   return 1;
653 }
654
655
656 /*
657  * Read the file header; return image size and component count.
658  */
659
660 METHODDEF(void)
661 start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
662 {
663   ppm_source_ptr source = (ppm_source_ptr)sinfo;
664   int c;
665   unsigned int w, h, maxval;
666   boolean need_iobuffer, use_raw_buffer, need_rescale;
667
668   if (getc(source->pub.input_file) != 'P')
669     ERREXIT(cinfo, JERR_PPM_NOT);
670
671   c = getc(source->pub.input_file); /* subformat discriminator character */
672
673   /* detect unsupported variants (ie, PBM) before trying to read header */
674   switch (c) {
675   case '2':                     /* it's a text-format PGM file */
676   case '3':                     /* it's a text-format PPM file */
677   case '5':                     /* it's a raw-format PGM file */
678   case '6':                     /* it's a raw-format PPM file */
679     break;
680   default:
681     ERREXIT(cinfo, JERR_PPM_NOT);
682     break;
683   }
684
685   /* fetch the remaining header info */
686   w = read_pbm_integer(cinfo, source->pub.input_file, 65535);
687   h = read_pbm_integer(cinfo, source->pub.input_file, 65535);
688   maxval = read_pbm_integer(cinfo, source->pub.input_file, 65535);
689
690   if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
691     ERREXIT(cinfo, JERR_PPM_NOT);
692 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
693   if (sinfo->max_pixels && (unsigned long long)w * h > sinfo->max_pixels)
694     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
695 #endif
696
697   cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
698   cinfo->image_width = (JDIMENSION)w;
699   cinfo->image_height = (JDIMENSION)h;
700   source->maxval = maxval;
701
702   /* initialize flags to most common settings */
703   need_iobuffer = TRUE;         /* do we need an I/O buffer? */
704   use_raw_buffer = FALSE;       /* do we map input buffer onto I/O buffer? */
705   need_rescale = TRUE;          /* do we need a rescale array? */
706
707   switch (c) {
708   case '2':                     /* it's a text-format PGM file */
709     if (cinfo->in_color_space == JCS_UNKNOWN ||
710         cinfo->in_color_space == JCS_RGB)
711       cinfo->in_color_space = JCS_GRAYSCALE;
712     TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
713     if (cinfo->in_color_space == JCS_GRAYSCALE)
714       source->pub.get_pixel_rows = get_text_gray_row;
715     else if (IsExtRGB(cinfo->in_color_space))
716       source->pub.get_pixel_rows = get_text_gray_rgb_row;
717     else if (cinfo->in_color_space == JCS_CMYK)
718       source->pub.get_pixel_rows = get_text_gray_cmyk_row;
719     else
720       ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
721     need_iobuffer = FALSE;
722     break;
723
724   case '3':                     /* it's a text-format PPM file */
725     if (cinfo->in_color_space == JCS_UNKNOWN)
726       cinfo->in_color_space = JCS_EXT_RGB;
727     TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
728     if (IsExtRGB(cinfo->in_color_space))
729       source->pub.get_pixel_rows = get_text_rgb_row;
730     else if (cinfo->in_color_space == JCS_CMYK)
731       source->pub.get_pixel_rows = get_text_rgb_cmyk_row;
732     else
733       ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
734     need_iobuffer = FALSE;
735     break;
736
737   case '5':                     /* it's a raw-format PGM file */
738     if (cinfo->in_color_space == JCS_UNKNOWN ||
739         cinfo->in_color_space == JCS_RGB)
740       cinfo->in_color_space = JCS_GRAYSCALE;
741     TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
742     if (maxval > 255) {
743       if (cinfo->in_color_space == JCS_GRAYSCALE)
744         source->pub.get_pixel_rows = get_word_gray_row;
745       else if (IsExtRGB(cinfo->in_color_space))
746         source->pub.get_pixel_rows = get_word_gray_rgb_row;
747       else if (cinfo->in_color_space == JCS_CMYK)
748         source->pub.get_pixel_rows = get_word_gray_cmyk_row;
749       else
750         ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
751     } else if (maxval == _MAXJSAMPLE && sizeof(_JSAMPLE) == sizeof(U_CHAR) &&
752                cinfo->in_color_space == JCS_GRAYSCALE) {
753       source->pub.get_pixel_rows = get_raw_row;
754       use_raw_buffer = TRUE;
755       need_rescale = FALSE;
756     } else {
757       if (cinfo->in_color_space == JCS_GRAYSCALE)
758         source->pub.get_pixel_rows = get_scaled_gray_row;
759       else if (IsExtRGB(cinfo->in_color_space))
760         source->pub.get_pixel_rows = get_gray_rgb_row;
761       else if (cinfo->in_color_space == JCS_CMYK)
762         source->pub.get_pixel_rows = get_gray_cmyk_row;
763       else
764         ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
765     }
766     break;
767
768   case '6':                     /* it's a raw-format PPM file */
769     if (cinfo->in_color_space == JCS_UNKNOWN)
770       cinfo->in_color_space = JCS_EXT_RGB;
771     TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
772     if (maxval > 255) {
773       if (IsExtRGB(cinfo->in_color_space))
774         source->pub.get_pixel_rows = get_word_rgb_row;
775       else if (cinfo->in_color_space == JCS_CMYK)
776         source->pub.get_pixel_rows = get_word_rgb_cmyk_row;
777       else
778         ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
779     } else if (maxval == _MAXJSAMPLE && sizeof(_JSAMPLE) == sizeof(U_CHAR) &&
780 #if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
781                (cinfo->in_color_space == JCS_EXT_RGB ||
782                 cinfo->in_color_space == JCS_RGB)) {
783 #else
784                cinfo->in_color_space == JCS_EXT_RGB) {
785 #endif
786       source->pub.get_pixel_rows = get_raw_row;
787       use_raw_buffer = TRUE;
788       need_rescale = FALSE;
789     } else {
790       if (IsExtRGB(cinfo->in_color_space))
791         source->pub.get_pixel_rows = get_rgb_row;
792       else if (cinfo->in_color_space == JCS_CMYK)
793         source->pub.get_pixel_rows = get_rgb_cmyk_row;
794       else
795         ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
796     }
797     break;
798   }
799
800   if (IsExtRGB(cinfo->in_color_space))
801     cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
802   else if (cinfo->in_color_space == JCS_GRAYSCALE)
803     cinfo->input_components = 1;
804   else if (cinfo->in_color_space == JCS_CMYK)
805     cinfo->input_components = 4;
806
807   /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
808   if (need_iobuffer) {
809     if (c == '6')
810       source->buffer_width = (size_t)w * 3 *
811         ((maxval <= 255) ? sizeof(U_CHAR) : (2 * sizeof(U_CHAR)));
812     else
813       source->buffer_width = (size_t)w *
814         ((maxval <= 255) ? sizeof(U_CHAR) : (2 * sizeof(U_CHAR)));
815     source->iobuffer = (U_CHAR *)
816       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
817                                   source->buffer_width);
818   }
819
820   /* Create compressor input buffer. */
821   if (use_raw_buffer) {
822     /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
823     /* Synthesize a _JSAMPARRAY pointer structure */
824     source->pixrow = (_JSAMPROW)source->iobuffer;
825     source->pub._buffer = &source->pixrow;
826     source->pub.buffer_height = 1;
827   } else {
828     /* Need to translate anyway, so make a separate sample buffer. */
829     source->pub._buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
830       ((j_common_ptr)cinfo, JPOOL_IMAGE,
831        (JDIMENSION)w * cinfo->input_components, (JDIMENSION)1);
832     source->pub.buffer_height = 1;
833   }
834
835   /* Compute the rescaling array if required. */
836   if (need_rescale) {
837     long val, half_maxval;
838
839     /* On 16-bit-int machines we have to be careful of maxval = 65535 */
840     source->rescale = (_JSAMPLE *)
841       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
842                                   (size_t)(((long)MAX(maxval, 255) + 1L) *
843                                            sizeof(_JSAMPLE)));
844     memset(source->rescale, 0, (size_t)(((long)MAX(maxval, 255) + 1L) *
845                                         sizeof(_JSAMPLE)));
846     half_maxval = maxval / 2;
847     for (val = 0; val <= (long)maxval; val++) {
848       /* The multiplication here must be done in 32 bits to avoid overflow */
849       source->rescale[val] = (_JSAMPLE)((val * _MAXJSAMPLE + half_maxval) /
850                                         maxval);
851     }
852   }
853 }
854
855
856 /*
857  * Finish up at the end of the file.
858  */
859
860 METHODDEF(void)
861 finish_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
862 {
863   /* no work */
864 }
865
866
867 /*
868  * The module selection routine for PPM format input.
869  */
870
871 GLOBAL(cjpeg_source_ptr)
872 _jinit_read_ppm(j_compress_ptr cinfo)
873 {
874   ppm_source_ptr source;
875
876   if (cinfo->data_precision != BITS_IN_JSAMPLE)
877     ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
878
879   /* Create module interface object */
880   source = (ppm_source_ptr)
881     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
882                                 sizeof(ppm_source_struct));
883   /* Fill in method ptrs, except get_pixel_rows which start_input sets */
884   source->pub.start_input = start_input_ppm;
885   source->pub.finish_input = finish_input_ppm;
886 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
887   source->pub.max_pixels = 0;
888 #endif
889
890   return (cjpeg_source_ptr)source;
891 }
892
893 #endif /* defined(PPM_SUPPORTED) &&
894           (BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)) */