Coverage Report

Created: 2023-06-07 06:03

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