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