• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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