1 /*
2 * rdbmp.c
3 *
4 * This file was part of the Independent JPEG Group's software:
5 * Copyright (C) 1994-1996, Thomas G. Lane.
6 * Modified 2009-2017 by Guido Vollbeding.
7 * libjpeg-turbo Modifications:
8 * Modified 2011 by Siarhei Siamashka.
9 * Copyright (C) 2015, 2017-2018, 2021, D. R. Commander.
10 * For conditions of distribution and use, see the accompanying README.ijg
11 * file.
12 *
13 * This file contains routines to read input images in Microsoft "BMP"
14 * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
15 * Currently, only 8-, 24-, and 32-bit images are supported, not 1-bit or
16 * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
17 * Also, we don't support RLE-compressed files.
18 *
19 * These routines may need modification for non-Unix environments or
20 * specialized applications. As they stand, they assume input from
21 * an ordinary stdio stream. They further assume that reading begins
22 * at the start of the file; start_input may need work if the
23 * user interface has already read some data (e.g., to determine that
24 * the file is indeed BMP format).
25 *
26 * This code contributed by James Arthur Boucher.
27 */
28
29 #include "cmyk.h"
30 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
31
32 #ifdef BMP_SUPPORTED
33
34
35 /* Macros to deal with unsigned chars as efficiently as compiler allows */
36
37 typedef unsigned char U_CHAR;
38 #define UCH(x) ((int)(x))
39
40
41 #define ReadOK(file, buffer, len) \
42 (JFREAD(file, buffer, len) == ((size_t)(len)))
43
44 static int alpha_index[JPEG_NUMCS] = {
45 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
46 };
47
48
49 /* Private version of data source object */
50
51 typedef struct _bmp_source_struct *bmp_source_ptr;
52
53 typedef struct _bmp_source_struct {
54 struct cjpeg_source_struct pub; /* public fields */
55
56 j_compress_ptr cinfo; /* back link saves passing separate parm */
57
58 JSAMPARRAY colormap; /* BMP colormap (converted to my format) */
59
60 jvirt_sarray_ptr whole_image; /* Needed to reverse row order */
61 JDIMENSION source_row; /* Current source row number */
62 JDIMENSION row_width; /* Physical width of scanlines in file */
63
64 int bits_per_pixel; /* remembers 8-, 24-, or 32-bit format */
65 int cmap_length; /* colormap length */
66
67 boolean use_inversion_array; /* TRUE = preload the whole image, which is
68 stored in bottom-up order, and feed it to
69 the calling program in top-down order
70
71 FALSE = the calling program will maintain
72 its own image buffer and read the rows in
73 bottom-up order */
74
75 U_CHAR *iobuffer; /* I/O buffer (used to buffer a single row from
76 disk if use_inversion_array == FALSE) */
77 } bmp_source_struct;
78
79
80 LOCAL(int)
read_byte(bmp_source_ptr sinfo)81 read_byte(bmp_source_ptr sinfo)
82 /* Read next byte from BMP file */
83 {
84 register FILE *infile = sinfo->pub.input_file;
85 register int c;
86
87 if ((c = getc(infile)) == EOF)
88 ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
89 return c;
90 }
91
92
93 LOCAL(void)
read_colormap(bmp_source_ptr sinfo,int cmaplen,int mapentrysize)94 read_colormap(bmp_source_ptr sinfo, int cmaplen, int mapentrysize)
95 /* Read the colormap from a BMP file */
96 {
97 int i, gray = 1;
98
99 switch (mapentrysize) {
100 case 3:
101 /* BGR format (occurs in OS/2 files) */
102 for (i = 0; i < cmaplen; i++) {
103 sinfo->colormap[2][i] = (JSAMPLE)read_byte(sinfo);
104 sinfo->colormap[1][i] = (JSAMPLE)read_byte(sinfo);
105 sinfo->colormap[0][i] = (JSAMPLE)read_byte(sinfo);
106 if (sinfo->colormap[2][i] != sinfo->colormap[1][i] ||
107 sinfo->colormap[1][i] != sinfo->colormap[0][i])
108 gray = 0;
109 }
110 break;
111 case 4:
112 /* BGR0 format (occurs in MS Windows files) */
113 for (i = 0; i < cmaplen; i++) {
114 sinfo->colormap[2][i] = (JSAMPLE)read_byte(sinfo);
115 sinfo->colormap[1][i] = (JSAMPLE)read_byte(sinfo);
116 sinfo->colormap[0][i] = (JSAMPLE)read_byte(sinfo);
117 (void)read_byte(sinfo);
118 if (sinfo->colormap[2][i] != sinfo->colormap[1][i] ||
119 sinfo->colormap[1][i] != sinfo->colormap[0][i])
120 gray = 0;
121 }
122 break;
123 default:
124 ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);
125 break;
126 }
127
128 if (sinfo->cinfo->in_color_space == JCS_UNKNOWN && gray)
129 sinfo->cinfo->in_color_space = JCS_GRAYSCALE;
130
131 if (sinfo->cinfo->in_color_space == JCS_GRAYSCALE && !gray)
132 ERREXIT(sinfo->cinfo, JERR_BAD_IN_COLORSPACE);
133 }
134
135
136 /*
137 * Read one row of pixels.
138 * The image has been read into the whole_image array, but is otherwise
139 * unprocessed. We must read it out in top-to-bottom row order, and if
140 * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
141 */
142
143 METHODDEF(JDIMENSION)
get_8bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)144 get_8bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
145 /* This version is for reading 8-bit colormap indexes */
146 {
147 bmp_source_ptr source = (bmp_source_ptr)sinfo;
148 register JSAMPARRAY colormap = source->colormap;
149 int cmaplen = source->cmap_length;
150 JSAMPARRAY image_ptr;
151 register int t;
152 register JSAMPROW inptr, outptr;
153 register JDIMENSION col;
154
155 if (source->use_inversion_array) {
156 /* Fetch next row from virtual array */
157 source->source_row--;
158 image_ptr = (*cinfo->mem->access_virt_sarray)
159 ((j_common_ptr)cinfo, source->whole_image,
160 source->source_row, (JDIMENSION)1, FALSE);
161 inptr = image_ptr[0];
162 } else {
163 if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
164 ERREXIT(cinfo, JERR_INPUT_EOF);
165 inptr = source->iobuffer;
166 }
167
168 /* Expand the colormap indexes to real data */
169 outptr = source->pub.buffer[0];
170 if (cinfo->in_color_space == JCS_GRAYSCALE) {
171 for (col = cinfo->image_width; col > 0; col--) {
172 t = *inptr++;
173 if (t >= cmaplen)
174 ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
175 *outptr++ = colormap[0][t];
176 }
177 } else if (cinfo->in_color_space == JCS_CMYK) {
178 for (col = cinfo->image_width; col > 0; col--) {
179 t = *inptr++;
180 if (t >= cmaplen)
181 ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
182 rgb_to_cmyk(colormap[0][t], colormap[1][t], colormap[2][t], outptr,
183 outptr + 1, outptr + 2, outptr + 3);
184 outptr += 4;
185 }
186 } else {
187 register int rindex = rgb_red[cinfo->in_color_space];
188 register int gindex = rgb_green[cinfo->in_color_space];
189 register int bindex = rgb_blue[cinfo->in_color_space];
190 register int aindex = alpha_index[cinfo->in_color_space];
191 register int ps = rgb_pixelsize[cinfo->in_color_space];
192
193 if (aindex >= 0) {
194 for (col = cinfo->image_width; col > 0; col--) {
195 t = *inptr++;
196 if (t >= cmaplen)
197 ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
198 outptr[rindex] = colormap[0][t];
199 outptr[gindex] = colormap[1][t];
200 outptr[bindex] = colormap[2][t];
201 outptr[aindex] = 0xFF;
202 outptr += ps;
203 }
204 } else {
205 for (col = cinfo->image_width; col > 0; col--) {
206 t = *inptr++;
207 if (t >= cmaplen)
208 ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
209 outptr[rindex] = colormap[0][t];
210 outptr[gindex] = colormap[1][t];
211 outptr[bindex] = colormap[2][t];
212 outptr += ps;
213 }
214 }
215 }
216
217 return 1;
218 }
219
220
221 METHODDEF(JDIMENSION)
get_24bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)222 get_24bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
223 /* This version is for reading 24-bit pixels */
224 {
225 bmp_source_ptr source = (bmp_source_ptr)sinfo;
226 JSAMPARRAY image_ptr;
227 register JSAMPROW inptr, outptr;
228 register JDIMENSION col;
229
230 if (source->use_inversion_array) {
231 /* Fetch next row from virtual array */
232 source->source_row--;
233 image_ptr = (*cinfo->mem->access_virt_sarray)
234 ((j_common_ptr)cinfo, source->whole_image,
235 source->source_row, (JDIMENSION)1, FALSE);
236 inptr = image_ptr[0];
237 } else {
238 if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
239 ERREXIT(cinfo, JERR_INPUT_EOF);
240 inptr = source->iobuffer;
241 }
242
243 /* Transfer data. Note source values are in BGR order
244 * (even though Microsoft's own documents say the opposite).
245 */
246 outptr = source->pub.buffer[0];
247 if (cinfo->in_color_space == JCS_EXT_BGR) {
248 MEMCOPY(outptr, inptr, source->row_width);
249 } else if (cinfo->in_color_space == JCS_CMYK) {
250 for (col = cinfo->image_width; col > 0; col--) {
251 JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
252 rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
253 outptr += 4;
254 }
255 } else {
256 register int rindex = rgb_red[cinfo->in_color_space];
257 register int gindex = rgb_green[cinfo->in_color_space];
258 register int bindex = rgb_blue[cinfo->in_color_space];
259 register int aindex = alpha_index[cinfo->in_color_space];
260 register int ps = rgb_pixelsize[cinfo->in_color_space];
261
262 if (aindex >= 0) {
263 for (col = cinfo->image_width; col > 0; col--) {
264 outptr[bindex] = *inptr++;
265 outptr[gindex] = *inptr++;
266 outptr[rindex] = *inptr++;
267 outptr[aindex] = 0xFF;
268 outptr += ps;
269 }
270 } else {
271 for (col = cinfo->image_width; col > 0; col--) {
272 outptr[bindex] = *inptr++;
273 outptr[gindex] = *inptr++;
274 outptr[rindex] = *inptr++;
275 outptr += ps;
276 }
277 }
278 }
279
280 return 1;
281 }
282
283
284 METHODDEF(JDIMENSION)
get_32bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)285 get_32bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
286 /* This version is for reading 32-bit pixels */
287 {
288 bmp_source_ptr source = (bmp_source_ptr)sinfo;
289 JSAMPARRAY image_ptr;
290 register JSAMPROW inptr, outptr;
291 register JDIMENSION col;
292
293 if (source->use_inversion_array) {
294 /* Fetch next row from virtual array */
295 source->source_row--;
296 image_ptr = (*cinfo->mem->access_virt_sarray)
297 ((j_common_ptr)cinfo, source->whole_image,
298 source->source_row, (JDIMENSION)1, FALSE);
299 inptr = image_ptr[0];
300 } else {
301 if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
302 ERREXIT(cinfo, JERR_INPUT_EOF);
303 inptr = source->iobuffer;
304 }
305
306 /* Transfer data. Note source values are in BGR order
307 * (even though Microsoft's own documents say the opposite).
308 */
309 outptr = source->pub.buffer[0];
310 if (cinfo->in_color_space == JCS_EXT_BGRX ||
311 cinfo->in_color_space == JCS_EXT_BGRA) {
312 MEMCOPY(outptr, inptr, source->row_width);
313 } else if (cinfo->in_color_space == JCS_CMYK) {
314 for (col = cinfo->image_width; col > 0; col--) {
315 JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
316 rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
317 inptr++; /* skip the 4th byte (Alpha channel) */
318 outptr += 4;
319 }
320 } else {
321 register int rindex = rgb_red[cinfo->in_color_space];
322 register int gindex = rgb_green[cinfo->in_color_space];
323 register int bindex = rgb_blue[cinfo->in_color_space];
324 register int aindex = alpha_index[cinfo->in_color_space];
325 register int ps = rgb_pixelsize[cinfo->in_color_space];
326
327 if (aindex >= 0) {
328 for (col = cinfo->image_width; col > 0; col--) {
329 outptr[bindex] = *inptr++;
330 outptr[gindex] = *inptr++;
331 outptr[rindex] = *inptr++;
332 outptr[aindex] = *inptr++;
333 outptr += ps;
334 }
335 } else {
336 for (col = cinfo->image_width; col > 0; col--) {
337 outptr[bindex] = *inptr++;
338 outptr[gindex] = *inptr++;
339 outptr[rindex] = *inptr++;
340 inptr++; /* skip the 4th byte (Alpha channel) */
341 outptr += ps;
342 }
343 }
344 }
345
346 return 1;
347 }
348
349
350 /*
351 * This method loads the image into whole_image during the first call on
352 * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
353 * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.
354 */
355
356 METHODDEF(JDIMENSION)
preload_image(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)357 preload_image(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
358 {
359 bmp_source_ptr source = (bmp_source_ptr)sinfo;
360 register FILE *infile = source->pub.input_file;
361 register JSAMPROW out_ptr;
362 JSAMPARRAY image_ptr;
363 JDIMENSION row;
364 cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
365
366 /* Read the data into a virtual array in input-file row order. */
367 for (row = 0; row < cinfo->image_height; row++) {
368 if (progress != NULL) {
369 progress->pub.pass_counter = (long)row;
370 progress->pub.pass_limit = (long)cinfo->image_height;
371 (*progress->pub.progress_monitor) ((j_common_ptr)cinfo);
372 }
373 image_ptr = (*cinfo->mem->access_virt_sarray)
374 ((j_common_ptr)cinfo, source->whole_image, row, (JDIMENSION)1, TRUE);
375 out_ptr = image_ptr[0];
376 if (fread(out_ptr, 1, source->row_width, infile) != source->row_width) {
377 if (feof(infile))
378 ERREXIT(cinfo, JERR_INPUT_EOF);
379 else
380 ERREXIT(cinfo, JERR_FILE_READ);
381 }
382 }
383 if (progress != NULL)
384 progress->completed_extra_passes++;
385
386 /* Set up to read from the virtual array in top-to-bottom order */
387 switch (source->bits_per_pixel) {
388 case 8:
389 source->pub.get_pixel_rows = get_8bit_row;
390 break;
391 case 24:
392 source->pub.get_pixel_rows = get_24bit_row;
393 break;
394 case 32:
395 source->pub.get_pixel_rows = get_32bit_row;
396 break;
397 default:
398 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
399 }
400 source->source_row = cinfo->image_height;
401
402 /* And read the first row */
403 return (*source->pub.get_pixel_rows) (cinfo, sinfo);
404 }
405
406
407 /*
408 * Read the file header; return image size and component count.
409 */
410
411 METHODDEF(void)
start_input_bmp(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)412 start_input_bmp(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
413 {
414 bmp_source_ptr source = (bmp_source_ptr)sinfo;
415 U_CHAR bmpfileheader[14];
416 U_CHAR bmpinfoheader[64];
417
418 #define GET_2B(array, offset) \
419 ((unsigned short)UCH(array[offset]) + \
420 (((unsigned short)UCH(array[offset + 1])) << 8))
421 #define GET_4B(array, offset) \
422 ((unsigned int)UCH(array[offset]) + \
423 (((unsigned int)UCH(array[offset + 1])) << 8) + \
424 (((unsigned int)UCH(array[offset + 2])) << 16) + \
425 (((unsigned int)UCH(array[offset + 3])) << 24))
426
427 int bfOffBits;
428 int headerSize;
429 int biWidth;
430 int biHeight;
431 unsigned short biPlanes;
432 unsigned int biCompression;
433 int biXPelsPerMeter, biYPelsPerMeter;
434 int biClrUsed = 0;
435 int mapentrysize = 0; /* 0 indicates no colormap */
436 int bPad;
437 JDIMENSION row_width = 0;
438
439 /* Read and verify the bitmap file header */
440 if (!ReadOK(source->pub.input_file, bmpfileheader, 14))
441 ERREXIT(cinfo, JERR_INPUT_EOF);
442 if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */
443 ERREXIT(cinfo, JERR_BMP_NOT);
444 bfOffBits = GET_4B(bmpfileheader, 10);
445 /* We ignore the remaining fileheader fields */
446
447 /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
448 * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
449 */
450 if (!ReadOK(source->pub.input_file, bmpinfoheader, 4))
451 ERREXIT(cinfo, JERR_INPUT_EOF);
452 headerSize = GET_4B(bmpinfoheader, 0);
453 if (headerSize < 12 || headerSize > 64 || (headerSize + 14) > bfOffBits)
454 ERREXIT(cinfo, JERR_BMP_BADHEADER);
455 if (!ReadOK(source->pub.input_file, bmpinfoheader + 4, headerSize - 4))
456 ERREXIT(cinfo, JERR_INPUT_EOF);
457
458 switch (headerSize) {
459 case 12:
460 /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
461 biWidth = (int)GET_2B(bmpinfoheader, 4);
462 biHeight = (int)GET_2B(bmpinfoheader, 6);
463 biPlanes = GET_2B(bmpinfoheader, 8);
464 source->bits_per_pixel = (int)GET_2B(bmpinfoheader, 10);
465
466 switch (source->bits_per_pixel) {
467 case 8: /* colormapped image */
468 mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */
469 TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, biWidth, biHeight);
470 break;
471 case 24: /* RGB image */
472 case 32: /* RGB image + Alpha channel */
473 TRACEMS3(cinfo, 1, JTRC_BMP_OS2, biWidth, biHeight,
474 source->bits_per_pixel);
475 break;
476 default:
477 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
478 break;
479 }
480 break;
481 case 40:
482 case 64:
483 /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
484 /* or OS/2 2.x header, which has additional fields that we ignore */
485 biWidth = (int)GET_4B(bmpinfoheader, 4);
486 biHeight = (int)GET_4B(bmpinfoheader, 8);
487 biPlanes = GET_2B(bmpinfoheader, 12);
488 source->bits_per_pixel = (int)GET_2B(bmpinfoheader, 14);
489 biCompression = GET_4B(bmpinfoheader, 16);
490 biXPelsPerMeter = (int)GET_4B(bmpinfoheader, 24);
491 biYPelsPerMeter = (int)GET_4B(bmpinfoheader, 28);
492 biClrUsed = GET_4B(bmpinfoheader, 32);
493 /* biSizeImage, biClrImportant fields are ignored */
494
495 switch (source->bits_per_pixel) {
496 case 8: /* colormapped image */
497 mapentrysize = 4; /* Windows uses RGBQUAD colormap */
498 TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, biWidth, biHeight);
499 break;
500 case 24: /* RGB image */
501 case 32: /* RGB image + Alpha channel */
502 TRACEMS3(cinfo, 1, JTRC_BMP, biWidth, biHeight, source->bits_per_pixel);
503 break;
504 default:
505 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
506 break;
507 }
508 if (biCompression != 0)
509 ERREXIT(cinfo, JERR_BMP_COMPRESSED);
510
511 if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
512 /* Set JFIF density parameters from the BMP data */
513 cinfo->X_density = (UINT16)(biXPelsPerMeter / 100); /* 100 cm per meter */
514 cinfo->Y_density = (UINT16)(biYPelsPerMeter / 100);
515 cinfo->density_unit = 2; /* dots/cm */
516 }
517 break;
518 default:
519 ERREXIT(cinfo, JERR_BMP_BADHEADER);
520 return;
521 }
522
523 if (biWidth <= 0 || biHeight <= 0)
524 ERREXIT(cinfo, JERR_BMP_EMPTY);
525 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
526 if (sinfo->max_pixels &&
527 (unsigned long long)biWidth * biHeight > sinfo->max_pixels)
528 ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
529 #endif
530 if (biPlanes != 1)
531 ERREXIT(cinfo, JERR_BMP_BADPLANES);
532
533 /* Compute distance to bitmap data --- will adjust for colormap below */
534 bPad = bfOffBits - (headerSize + 14);
535
536 /* Read the colormap, if any */
537 if (mapentrysize > 0) {
538 if (biClrUsed <= 0)
539 biClrUsed = 256; /* assume it's 256 */
540 else if (biClrUsed > 256)
541 ERREXIT(cinfo, JERR_BMP_BADCMAP);
542 /* Allocate space to store the colormap */
543 source->colormap = (*cinfo->mem->alloc_sarray)
544 ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)biClrUsed, (JDIMENSION)3);
545 source->cmap_length = (int)biClrUsed;
546 /* and read it from the file */
547 read_colormap(source, (int)biClrUsed, mapentrysize);
548 /* account for size of colormap */
549 bPad -= biClrUsed * mapentrysize;
550 }
551
552 /* Skip any remaining pad bytes */
553 if (bPad < 0) /* incorrect bfOffBits value? */
554 ERREXIT(cinfo, JERR_BMP_BADHEADER);
555 while (--bPad >= 0) {
556 (void)read_byte(source);
557 }
558
559 /* Compute row width in file, including padding to 4-byte boundary */
560 switch (source->bits_per_pixel) {
561 case 8:
562 if (cinfo->in_color_space == JCS_UNKNOWN)
563 cinfo->in_color_space = JCS_EXT_RGB;
564 if (IsExtRGB(cinfo->in_color_space))
565 cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
566 else if (cinfo->in_color_space == JCS_GRAYSCALE)
567 cinfo->input_components = 1;
568 else if (cinfo->in_color_space == JCS_CMYK)
569 cinfo->input_components = 4;
570 else
571 ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
572 row_width = (JDIMENSION)biWidth;
573 break;
574 case 24:
575 if (cinfo->in_color_space == JCS_UNKNOWN)
576 cinfo->in_color_space = JCS_EXT_BGR;
577 if (IsExtRGB(cinfo->in_color_space))
578 cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
579 else if (cinfo->in_color_space == JCS_CMYK)
580 cinfo->input_components = 4;
581 else
582 ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
583 if ((unsigned long long)biWidth * 3ULL > 0xFFFFFFFFULL)
584 ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
585 row_width = (JDIMENSION)biWidth * 3;
586 break;
587 case 32:
588 if (cinfo->in_color_space == JCS_UNKNOWN)
589 cinfo->in_color_space = JCS_EXT_BGRA;
590 if (IsExtRGB(cinfo->in_color_space))
591 cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
592 else if (cinfo->in_color_space == JCS_CMYK)
593 cinfo->input_components = 4;
594 else
595 ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
596 if ((unsigned long long)biWidth * 4ULL > 0xFFFFFFFFULL)
597 ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
598 row_width = (JDIMENSION)biWidth * 4;
599 break;
600 default:
601 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
602 }
603 while ((row_width & 3) != 0) row_width++;
604 source->row_width = row_width;
605
606 if (source->use_inversion_array) {
607 /* Allocate space for inversion array, prepare for preload pass */
608 source->whole_image = (*cinfo->mem->request_virt_sarray)
609 ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
610 row_width, (JDIMENSION)biHeight, (JDIMENSION)1);
611 source->pub.get_pixel_rows = preload_image;
612 if (cinfo->progress != NULL) {
613 cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
614 progress->total_extra_passes++; /* count file input as separate pass */
615 }
616 } else {
617 source->iobuffer = (U_CHAR *)
618 (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, row_width);
619 switch (source->bits_per_pixel) {
620 case 8:
621 source->pub.get_pixel_rows = get_8bit_row;
622 break;
623 case 24:
624 source->pub.get_pixel_rows = get_24bit_row;
625 break;
626 case 32:
627 source->pub.get_pixel_rows = get_32bit_row;
628 break;
629 default:
630 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
631 }
632 }
633
634 /* Ensure that biWidth * cinfo->input_components doesn't exceed the maximum
635 value of the JDIMENSION type. This is only a danger with BMP files, since
636 their width and height fields are 32-bit integers. */
637 if ((unsigned long long)biWidth *
638 (unsigned long long)cinfo->input_components > 0xFFFFFFFFULL)
639 ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
640 /* Allocate one-row buffer for returned data */
641 source->pub.buffer = (*cinfo->mem->alloc_sarray)
642 ((j_common_ptr)cinfo, JPOOL_IMAGE,
643 (JDIMENSION)biWidth * (JDIMENSION)cinfo->input_components, (JDIMENSION)1);
644 source->pub.buffer_height = 1;
645
646 cinfo->data_precision = 8;
647 cinfo->image_width = (JDIMENSION)biWidth;
648 cinfo->image_height = (JDIMENSION)biHeight;
649 }
650
651
652 /*
653 * Finish up at the end of the file.
654 */
655
656 METHODDEF(void)
finish_input_bmp(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)657 finish_input_bmp(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
658 {
659 /* no work */
660 }
661
662
663 /*
664 * The module selection routine for BMP format input.
665 */
666
667 GLOBAL(cjpeg_source_ptr)
jinit_read_bmp(j_compress_ptr cinfo,boolean use_inversion_array)668 jinit_read_bmp(j_compress_ptr cinfo, boolean use_inversion_array)
669 {
670 bmp_source_ptr source;
671
672 /* Create module interface object */
673 source = (bmp_source_ptr)
674 (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
675 sizeof(bmp_source_struct));
676 source->cinfo = cinfo; /* make back link for subroutines */
677 /* Fill in method ptrs, except get_pixel_rows which start_input sets */
678 source->pub.start_input = start_input_bmp;
679 source->pub.finish_input = finish_input_bmp;
680 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
681 source->pub.max_pixels = 0;
682 #endif
683
684 source->use_inversion_array = use_inversion_array;
685
686 return (cjpeg_source_ptr)source;
687 }
688
689 #endif /* BMP_SUPPORTED */
690