/src/libjpeg-turbo.2.1.x/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 | 38.5k | #define UCH(x)  ((int)(x)) | 
| 39 |  |  | 
| 40 |  |  | 
| 41 |  | #define ReadOK(file, buffer, len) \ | 
| 42 | 3.97k |   (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 | 25.5k | { | 
| 84 | 25.5k |   register FILE *infile = sinfo->pub.input_file; | 
| 85 | 25.5k |   register int c; | 
| 86 |  |  | 
| 87 | 25.5k |   if ((c = getc(infile)) == EOF) | 
| 88 | 378 |     ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); | 
| 89 | 25.5k |   return c; | 
| 90 | 25.5k | } | 
| 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 | 470 | { | 
| 97 | 470 |   int i, gray = 1; | 
| 98 |  |  | 
| 99 | 470 |   switch (mapentrysize) { | 
| 100 | 122 |   case 3: | 
| 101 |  |     /* BGR format (occurs in OS/2 files) */ | 
| 102 | 1.84k |     for (i = 0; i < cmaplen; i++) { | 
| 103 | 1.71k |       sinfo->colormap[2][i] = (JSAMPLE)read_byte(sinfo); | 
| 104 | 1.71k |       sinfo->colormap[1][i] = (JSAMPLE)read_byte(sinfo); | 
| 105 | 1.71k |       sinfo->colormap[0][i] = (JSAMPLE)read_byte(sinfo); | 
| 106 | 1.71k |       if (sinfo->colormap[2][i] != sinfo->colormap[1][i] || | 
| 107 | 1.71k |           sinfo->colormap[1][i] != sinfo->colormap[0][i]) | 
| 108 | 980 |         gray = 0; | 
| 109 | 1.71k |     } | 
| 110 | 122 |     break; | 
| 111 | 348 |   case 4: | 
| 112 |  |     /* BGR0 format (occurs in MS Windows files) */ | 
| 113 | 4.76k |     for (i = 0; i < cmaplen; i++) { | 
| 114 | 4.41k |       sinfo->colormap[2][i] = (JSAMPLE)read_byte(sinfo); | 
| 115 | 4.41k |       sinfo->colormap[1][i] = (JSAMPLE)read_byte(sinfo); | 
| 116 | 4.41k |       sinfo->colormap[0][i] = (JSAMPLE)read_byte(sinfo); | 
| 117 | 4.41k |       (void)read_byte(sinfo); | 
| 118 | 4.41k |       if (sinfo->colormap[2][i] != sinfo->colormap[1][i] || | 
| 119 | 4.41k |           sinfo->colormap[1][i] != sinfo->colormap[0][i]) | 
| 120 | 1.46k |         gray = 0; | 
| 121 | 4.41k |     } | 
| 122 | 348 |     break; | 
| 123 | 0 |   default: | 
| 124 | 0 |     ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP); | 
| 125 | 0 |     break; | 
| 126 | 470 |   } | 
| 127 |  |  | 
| 128 | 160 |   if ((sinfo->cinfo->in_color_space == JCS_UNKNOWN || | 
| 129 | 160 |        sinfo->cinfo->in_color_space == JCS_RGB) && gray) | 
| 130 | 80 |     sinfo->cinfo->in_color_space = JCS_GRAYSCALE; | 
| 131 |  |  | 
| 132 | 160 |   if (sinfo->cinfo->in_color_space == JCS_GRAYSCALE && !gray) | 
| 133 | 0 |     ERREXIT(sinfo->cinfo, JERR_BAD_IN_COLORSPACE); | 
| 134 | 160 | } | 
| 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 | 568 | { | 
| 148 | 568 |   bmp_source_ptr source = (bmp_source_ptr)sinfo; | 
| 149 | 568 |   register JSAMPARRAY colormap = source->colormap; | 
| 150 | 568 |   int cmaplen = source->cmap_length; | 
| 151 | 568 |   JSAMPARRAY image_ptr; | 
| 152 | 568 |   register int t; | 
| 153 | 568 |   register JSAMPROW inptr, outptr; | 
| 154 | 568 |   register JDIMENSION col; | 
| 155 |  |  | 
| 156 | 568 |   if (source->use_inversion_array) { | 
| 157 |  |     /* Fetch next row from virtual array */ | 
| 158 | 568 |     source->source_row--; | 
| 159 | 568 |     image_ptr = (*cinfo->mem->access_virt_sarray) | 
| 160 | 568 |       ((j_common_ptr)cinfo, source->whole_image, | 
| 161 | 568 |        source->source_row, (JDIMENSION)1, FALSE); | 
| 162 | 568 |     inptr = image_ptr[0]; | 
| 163 | 568 |   } 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 | 568 |   outptr = source->pub.buffer[0]; | 
| 171 | 568 |   if (cinfo->in_color_space == JCS_GRAYSCALE) { | 
| 172 | 1.42k |     for (col = cinfo->image_width; col > 0; col--) { | 
| 173 | 1.11k |       t = *inptr++; | 
| 174 | 1.11k |       if (t >= cmaplen) | 
| 175 | 24 |         ERREXIT(cinfo, JERR_BMP_OUTOFRANGE); | 
| 176 | 1.11k |       *outptr++ = colormap[0][t]; | 
| 177 | 1.11k |     } | 
| 178 | 316 |   } 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 | 252 |   } else { | 
| 188 | 252 |     register int rindex = rgb_red[cinfo->in_color_space]; | 
| 189 | 252 |     register int gindex = rgb_green[cinfo->in_color_space]; | 
| 190 | 252 |     register int bindex = rgb_blue[cinfo->in_color_space]; | 
| 191 | 252 |     register int aindex = alpha_index[cinfo->in_color_space]; | 
| 192 | 252 |     register int ps = rgb_pixelsize[cinfo->in_color_space]; | 
| 193 |  |  | 
| 194 | 252 |     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 | 252 |     } else { | 
| 206 | 1.51k |       for (col = cinfo->image_width; col > 0; col--) { | 
| 207 | 1.26k |         t = *inptr++; | 
| 208 | 1.26k |         if (t >= cmaplen) | 
| 209 | 34 |           ERREXIT(cinfo, JERR_BMP_OUTOFRANGE); | 
| 210 | 1.26k |         outptr[rindex] = colormap[0][t]; | 
| 211 | 1.26k |         outptr[gindex] = colormap[1][t]; | 
| 212 | 1.26k |         outptr[bindex] = colormap[2][t]; | 
| 213 | 1.26k |         outptr += ps; | 
| 214 | 1.26k |       } | 
| 215 | 252 |     } | 
| 216 | 252 |   } | 
| 217 |  |  | 
| 218 | 568 |   return 1; | 
| 219 | 568 | } | 
| 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 | 212 | { | 
| 226 | 212 |   bmp_source_ptr source = (bmp_source_ptr)sinfo; | 
| 227 | 212 |   JSAMPARRAY image_ptr; | 
| 228 | 212 |   register JSAMPROW inptr, outptr; | 
| 229 | 212 |   register JDIMENSION col; | 
| 230 |  |  | 
| 231 | 212 |   if (source->use_inversion_array) { | 
| 232 |  |     /* Fetch next row from virtual array */ | 
| 233 | 212 |     source->source_row--; | 
| 234 | 212 |     image_ptr = (*cinfo->mem->access_virt_sarray) | 
| 235 | 212 |       ((j_common_ptr)cinfo, source->whole_image, | 
| 236 | 212 |        source->source_row, (JDIMENSION)1, FALSE); | 
| 237 | 212 |     inptr = image_ptr[0]; | 
| 238 | 212 |   } 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 | 212 |   outptr = source->pub.buffer[0]; | 
| 248 | 212 |   if (cinfo->in_color_space == JCS_EXT_BGR) { | 
| 249 | 0 |     memcpy(outptr, inptr, source->row_width); | 
| 250 | 212 |   } 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 | 212 |   } else { | 
| 257 | 212 |     register int rindex = rgb_red[cinfo->in_color_space]; | 
| 258 | 212 |     register int gindex = rgb_green[cinfo->in_color_space]; | 
| 259 | 212 |     register int bindex = rgb_blue[cinfo->in_color_space]; | 
| 260 | 212 |     register int aindex = alpha_index[cinfo->in_color_space]; | 
| 261 | 212 |     register int ps = rgb_pixelsize[cinfo->in_color_space]; | 
| 262 |  |  | 
| 263 | 212 |     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 | 212 |     } else { | 
| 272 | 628 |       for (col = cinfo->image_width; col > 0; col--) { | 
| 273 | 416 |         outptr[bindex] = *inptr++; | 
| 274 | 416 |         outptr[gindex] = *inptr++; | 
| 275 | 416 |         outptr[rindex] = *inptr++; | 
| 276 | 416 |         outptr += ps; | 
| 277 | 416 |       } | 
| 278 | 212 |     } | 
| 279 | 212 |   } | 
| 280 |  |  | 
| 281 | 212 |   return 1; | 
| 282 | 212 | } | 
| 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 | 520 | { | 
| 289 | 520 |   bmp_source_ptr source = (bmp_source_ptr)sinfo; | 
| 290 | 520 |   JSAMPARRAY image_ptr; | 
| 291 | 520 |   register JSAMPROW inptr, outptr; | 
| 292 | 520 |   register JDIMENSION col; | 
| 293 |  |  | 
| 294 | 520 |   if (source->use_inversion_array) { | 
| 295 |  |     /* Fetch next row from virtual array */ | 
| 296 | 520 |     source->source_row--; | 
| 297 | 520 |     image_ptr = (*cinfo->mem->access_virt_sarray) | 
| 298 | 520 |       ((j_common_ptr)cinfo, source->whole_image, | 
| 299 | 520 |        source->source_row, (JDIMENSION)1, FALSE); | 
| 300 | 520 |     inptr = image_ptr[0]; | 
| 301 | 520 |   } 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 | 520 |   outptr = source->pub.buffer[0]; | 
| 311 | 520 |   if (cinfo->in_color_space == JCS_EXT_BGRX || | 
| 312 | 520 |       cinfo->in_color_space == JCS_EXT_BGRA) { | 
| 313 | 0 |     memcpy(outptr, inptr, source->row_width); | 
| 314 | 520 |   } 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 | 520 |   } else { | 
| 322 | 520 |     register int rindex = rgb_red[cinfo->in_color_space]; | 
| 323 | 520 |     register int gindex = rgb_green[cinfo->in_color_space]; | 
| 324 | 520 |     register int bindex = rgb_blue[cinfo->in_color_space]; | 
| 325 | 520 |     register int aindex = alpha_index[cinfo->in_color_space]; | 
| 326 | 520 |     register int ps = rgb_pixelsize[cinfo->in_color_space]; | 
| 327 |  |  | 
| 328 | 520 |     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 | 520 |     } else { | 
| 337 | 7.12k |       for (col = cinfo->image_width; col > 0; col--) { | 
| 338 | 6.60k |         outptr[bindex] = *inptr++; | 
| 339 | 6.60k |         outptr[gindex] = *inptr++; | 
| 340 | 6.60k |         outptr[rindex] = *inptr++; | 
| 341 | 6.60k |         inptr++;                        /* skip the 4th byte (Alpha channel) */ | 
| 342 | 6.60k |         outptr += ps; | 
| 343 | 6.60k |       } | 
| 344 | 520 |     } | 
| 345 | 520 |   } | 
| 346 |  |  | 
| 347 | 520 |   return 1; | 
| 348 | 520 | } | 
| 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 | 224 | { | 
| 360 | 224 |   bmp_source_ptr source = (bmp_source_ptr)sinfo; | 
| 361 | 224 |   register FILE *infile = source->pub.input_file; | 
| 362 | 224 |   register JSAMPROW out_ptr; | 
| 363 | 224 |   JSAMPARRAY image_ptr; | 
| 364 | 224 |   JDIMENSION row; | 
| 365 | 224 |   cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress; | 
| 366 |  |  | 
| 367 |  |   /* Read the data into a virtual array in input-file row order. */ | 
| 368 | 2.11k |   for (row = 0; row < cinfo->image_height; row++) { | 
| 369 | 1.88k |     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 | 1.88k |     image_ptr = (*cinfo->mem->access_virt_sarray) | 
| 375 | 1.88k |       ((j_common_ptr)cinfo, source->whole_image, row, (JDIMENSION)1, TRUE); | 
| 376 | 1.88k |     out_ptr = image_ptr[0]; | 
| 377 | 1.88k |     if (fread(out_ptr, 1, source->row_width, infile) != source->row_width) { | 
| 378 | 75 |       if (feof(infile)) | 
| 379 | 75 |         ERREXIT(cinfo, JERR_INPUT_EOF); | 
| 380 | 0 |       else | 
| 381 | 0 |         ERREXIT(cinfo, JERR_FILE_READ); | 
| 382 | 75 |     } | 
| 383 | 1.88k |   } | 
| 384 | 224 |   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 | 224 |   switch (source->bits_per_pixel) { | 
| 389 | 85 |   case 8: | 
| 390 | 85 |     source->pub.get_pixel_rows = get_8bit_row; | 
| 391 | 85 |     break; | 
| 392 | 24 |   case 24: | 
| 393 | 24 |     source->pub.get_pixel_rows = get_24bit_row; | 
| 394 | 24 |     break; | 
| 395 | 40 |   case 32: | 
| 396 | 40 |     source->pub.get_pixel_rows = get_32bit_row; | 
| 397 | 40 |     break; | 
| 398 | 0 |   default: | 
| 399 | 0 |     ERREXIT(cinfo, JERR_BMP_BADDEPTH); | 
| 400 | 224 |   } | 
| 401 | 149 |   source->source_row = cinfo->image_height; | 
| 402 |  |  | 
| 403 |  |   /* And read the first row */ | 
| 404 | 149 |   return (*source->pub.get_pixel_rows) (cinfo, sinfo); | 
| 405 | 224 | } | 
| 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 | 1.32k | { | 
| 415 | 1.32k |   bmp_source_ptr source = (bmp_source_ptr)sinfo; | 
| 416 | 1.32k |   U_CHAR bmpfileheader[14]; | 
| 417 | 1.32k |   U_CHAR bmpinfoheader[64]; | 
| 418 |  |  | 
| 419 | 1.32k | #define GET_2B(array, offset) \ | 
| 420 | 4.03k |   ((unsigned short)UCH(array[offset]) + \ | 
| 421 | 4.03k |    (((unsigned short)UCH(array[offset + 1])) << 8)) | 
| 422 | 1.32k | #define GET_4B(array, offset) \ | 
| 423 | 7.63k |   ((unsigned int)UCH(array[offset]) + \ | 
| 424 | 7.63k |    (((unsigned int)UCH(array[offset + 1])) << 8) + \ | 
| 425 | 7.63k |    (((unsigned int)UCH(array[offset + 2])) << 16) + \ | 
| 426 | 7.63k |    (((unsigned int)UCH(array[offset + 3])) << 24)) | 
| 427 |  |  | 
| 428 | 1.32k |   int bfOffBits; | 
| 429 | 1.32k |   int headerSize; | 
| 430 | 1.32k |   int biWidth; | 
| 431 | 1.32k |   int biHeight; | 
| 432 | 1.32k |   unsigned short biPlanes; | 
| 433 | 1.32k |   unsigned int biCompression; | 
| 434 | 1.32k |   int biXPelsPerMeter, biYPelsPerMeter; | 
| 435 | 1.32k |   int biClrUsed = 0; | 
| 436 | 1.32k |   int mapentrysize = 0;         /* 0 indicates no colormap */ | 
| 437 | 1.32k |   int bPad; | 
| 438 | 1.32k |   JDIMENSION row_width = 0; | 
| 439 |  |  | 
| 440 |  |   /* Read and verify the bitmap file header */ | 
| 441 | 1.32k |   if (!ReadOK(source->pub.input_file, bmpfileheader, 14)) | 
| 442 | 14 |     ERREXIT(cinfo, JERR_INPUT_EOF); | 
| 443 | 1.32k |   if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */ | 
| 444 | 18 |     ERREXIT(cinfo, JERR_BMP_NOT); | 
| 445 | 1.32k |   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 | 1.32k |   if (!ReadOK(source->pub.input_file, bmpinfoheader, 4)) | 
| 452 | 6 |     ERREXIT(cinfo, JERR_INPUT_EOF); | 
| 453 | 1.32k |   headerSize = GET_4B(bmpinfoheader, 0); | 
| 454 | 1.32k |   if (headerSize < 12 || headerSize > 64 || (headerSize + 14) > bfOffBits) | 
| 455 | 176 |     ERREXIT(cinfo, JERR_BMP_BADHEADER); | 
| 456 | 1.32k |   if (!ReadOK(source->pub.input_file, bmpinfoheader + 4, headerSize - 4)) | 
| 457 | 18 |     ERREXIT(cinfo, JERR_INPUT_EOF); | 
| 458 |  |  | 
| 459 | 1.32k |   switch (headerSize) { | 
| 460 | 262 |   case 12: | 
| 461 |  |     /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */ | 
| 462 | 262 |     biWidth = (int)GET_2B(bmpinfoheader, 4); | 
| 463 | 262 |     biHeight = (int)GET_2B(bmpinfoheader, 6); | 
| 464 | 262 |     biPlanes = GET_2B(bmpinfoheader, 8); | 
| 465 | 262 |     source->bits_per_pixel = (int)GET_2B(bmpinfoheader, 10); | 
| 466 |  |  | 
| 467 | 262 |     switch (source->bits_per_pixel) { | 
| 468 | 150 |     case 8:                     /* colormapped image */ | 
| 469 | 150 |       mapentrysize = 3;         /* OS/2 uses RGBTRIPLE colormap */ | 
| 470 | 150 |       TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, biWidth, biHeight); | 
| 471 | 150 |       break; | 
| 472 | 40 |     case 24:                    /* RGB image */ | 
| 473 | 110 |     case 32:                    /* RGB image + Alpha channel */ | 
| 474 | 110 |       TRACEMS3(cinfo, 1, JTRC_BMP_OS2, biWidth, biHeight, | 
| 475 | 110 |                source->bits_per_pixel); | 
| 476 | 110 |       break; | 
| 477 | 2 |     default: | 
| 478 | 2 |       ERREXIT(cinfo, JERR_BMP_BADDEPTH); | 
| 479 | 2 |       break; | 
| 480 | 262 |     } | 
| 481 | 260 |     break; | 
| 482 | 828 |   case 40: | 
| 483 | 830 |   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 | 830 |     biWidth = (int)GET_4B(bmpinfoheader, 4); | 
| 487 | 830 |     biHeight = (int)GET_4B(bmpinfoheader, 8); | 
| 488 | 830 |     biPlanes = GET_2B(bmpinfoheader, 12); | 
| 489 | 830 |     source->bits_per_pixel = (int)GET_2B(bmpinfoheader, 14); | 
| 490 | 830 |     biCompression = GET_4B(bmpinfoheader, 16); | 
| 491 | 830 |     biXPelsPerMeter = (int)GET_4B(bmpinfoheader, 24); | 
| 492 | 830 |     biYPelsPerMeter = (int)GET_4B(bmpinfoheader, 28); | 
| 493 | 830 |     biClrUsed = GET_4B(bmpinfoheader, 32); | 
| 494 |  |     /* biSizeImage, biClrImportant fields are ignored */ | 
| 495 |  |  | 
| 496 | 830 |     switch (source->bits_per_pixel) { | 
| 497 | 560 |     case 8:                     /* colormapped image */ | 
| 498 | 560 |       mapentrysize = 4;         /* Windows uses RGBQUAD colormap */ | 
| 499 | 560 |       TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, biWidth, biHeight); | 
| 500 | 560 |       break; | 
| 501 | 156 |     case 24:                    /* RGB image */ | 
| 502 | 268 |     case 32:                    /* RGB image + Alpha channel */ | 
| 503 | 268 |       TRACEMS3(cinfo, 1, JTRC_BMP, biWidth, biHeight, source->bits_per_pixel); | 
| 504 | 268 |       break; | 
| 505 | 2 |     default: | 
| 506 | 2 |       ERREXIT(cinfo, JERR_BMP_BADDEPTH); | 
| 507 | 2 |       break; | 
| 508 | 830 |     } | 
| 509 | 828 |     if (biCompression != 0) | 
| 510 | 48 |       ERREXIT(cinfo, JERR_BMP_COMPRESSED); | 
| 511 |  |  | 
| 512 | 828 |     if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) { | 
| 513 |  |       /* Set JFIF density parameters from the BMP data */ | 
| 514 | 324 |       cinfo->X_density = (UINT16)(biXPelsPerMeter / 100); /* 100 cm per meter */ | 
| 515 | 324 |       cinfo->Y_density = (UINT16)(biYPelsPerMeter / 100); | 
| 516 | 324 |       cinfo->density_unit = 2;  /* dots/cm */ | 
| 517 | 324 |     } | 
| 518 | 828 |     break; | 
| 519 | 2 |   default: | 
| 520 | 2 |     ERREXIT(cinfo, JERR_BMP_BADHEADER); | 
| 521 | 2 |     return; | 
| 522 | 1.32k |   } | 
| 523 |  |  | 
| 524 | 1.04k |   if (biWidth <= 0 || biHeight <= 0) | 
| 525 | 130 |     ERREXIT(cinfo, JERR_BMP_EMPTY); | 
| 526 | 1.04k | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 
| 527 | 1.04k |   if (sinfo->max_pixels && | 
| 528 | 1.04k |       (unsigned long long)biWidth * biHeight > sinfo->max_pixels) | 
| 529 | 150 |     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); | 
| 530 | 1.04k | #endif | 
| 531 | 1.04k |   if (biPlanes != 1) | 
| 532 | 10 |     ERREXIT(cinfo, JERR_BMP_BADPLANES); | 
| 533 |  |  | 
| 534 |  |   /* Compute distance to bitmap data --- will adjust for colormap below */ | 
| 535 | 1.04k |   bPad = bfOffBits - (headerSize + 14); | 
| 536 |  |  | 
| 537 |  |   /* Read the colormap, if any */ | 
| 538 | 1.04k |   if (mapentrysize > 0) { | 
| 539 | 516 |     if (biClrUsed <= 0) | 
| 540 | 272 |       biClrUsed = 256;          /* assume it's 256 */ | 
| 541 | 244 |     else if (biClrUsed > 256) | 
| 542 | 46 |       ERREXIT(cinfo, JERR_BMP_BADCMAP); | 
| 543 |  |     /* Allocate space to store the colormap */ | 
| 544 | 516 |     source->colormap = (*cinfo->mem->alloc_sarray) | 
| 545 | 516 |       ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)biClrUsed, (JDIMENSION)3); | 
| 546 | 516 |     source->cmap_length = (int)biClrUsed; | 
| 547 |  |     /* and read it from the file */ | 
| 548 | 516 |     read_colormap(source, (int)biClrUsed, mapentrysize); | 
| 549 |  |     /* account for size of colormap */ | 
| 550 | 516 |     bPad -= biClrUsed * mapentrysize; | 
| 551 | 516 |   } | 
| 552 |  |  | 
| 553 |  |   /* Skip any remaining pad bytes */ | 
| 554 | 1.04k |   if (bPad < 0)                 /* incorrect bfOffBits value? */ | 
| 555 | 22 |     ERREXIT(cinfo, JERR_BMP_BADHEADER); | 
| 556 | 4.34k |   while (--bPad >= 0) { | 
| 557 | 3.30k |     (void)read_byte(source); | 
| 558 | 3.30k |   } | 
| 559 |  |  | 
| 560 |  |   /* Compute row width in file, including padding to 4-byte boundary */ | 
| 561 | 1.04k |   switch (source->bits_per_pixel) { | 
| 562 | 132 |   case 8: | 
| 563 | 132 |     if (cinfo->in_color_space == JCS_UNKNOWN) | 
| 564 | 0 |       cinfo->in_color_space = JCS_EXT_RGB; | 
| 565 | 132 |     if (IsExtRGB(cinfo->in_color_space)) | 
| 566 | 52 |       cinfo->input_components = rgb_pixelsize[cinfo->in_color_space]; | 
| 567 | 80 |     else if (cinfo->in_color_space == JCS_GRAYSCALE) | 
| 568 | 80 |       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 | 132 |     row_width = (JDIMENSION)biWidth; | 
| 574 | 132 |     break; | 
| 575 | 68 |   case 24: | 
| 576 | 68 |     if (cinfo->in_color_space == JCS_UNKNOWN) | 
| 577 | 0 |       cinfo->in_color_space = JCS_EXT_BGR; | 
| 578 | 68 |     if (IsExtRGB(cinfo->in_color_space)) | 
| 579 | 68 |       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 | 68 |     if ((unsigned long long)biWidth * 3ULL > 0xFFFFFFFFULL) | 
| 585 | 0 |       ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); | 
| 586 | 68 |     row_width = (JDIMENSION)biWidth * 3; | 
| 587 | 68 |     break; | 
| 588 | 104 |   case 32: | 
| 589 | 104 |     if (cinfo->in_color_space == JCS_UNKNOWN) | 
| 590 | 0 |       cinfo->in_color_space = JCS_EXT_BGRA; | 
| 591 | 104 |     if (IsExtRGB(cinfo->in_color_space)) | 
| 592 | 104 |       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 | 104 |     if ((unsigned long long)biWidth * 4ULL > 0xFFFFFFFFULL) | 
| 598 | 0 |       ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); | 
| 599 | 104 |     row_width = (JDIMENSION)biWidth * 4; | 
| 600 | 104 |     break; | 
| 601 | 0 |   default: | 
| 602 | 0 |     ERREXIT(cinfo, JERR_BMP_BADDEPTH); | 
| 603 | 1.04k |   } | 
| 604 | 568 |   while ((row_width & 3) != 0) row_width++; | 
| 605 | 304 |   source->row_width = row_width; | 
| 606 |  |  | 
| 607 | 304 |   if (source->use_inversion_array) { | 
| 608 |  |     /* Allocate space for inversion array, prepare for preload pass */ | 
| 609 | 304 |     source->whole_image = (*cinfo->mem->request_virt_sarray) | 
| 610 | 304 |       ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE, | 
| 611 | 304 |        row_width, (JDIMENSION)biHeight, (JDIMENSION)1); | 
| 612 | 304 |     source->pub.get_pixel_rows = preload_image; | 
| 613 | 304 |     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 | 304 |   } 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 | 304 |   if ((unsigned long long)biWidth * | 
| 639 | 304 |       (unsigned long long)cinfo->input_components > 0xFFFFFFFFULL) | 
| 640 | 0 |     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); | 
| 641 |  |   /* Allocate one-row buffer for returned data */ | 
| 642 | 304 |   source->pub.buffer = (*cinfo->mem->alloc_sarray) | 
| 643 | 304 |     ((j_common_ptr)cinfo, JPOOL_IMAGE, | 
| 644 | 304 |      (JDIMENSION)biWidth * (JDIMENSION)cinfo->input_components, (JDIMENSION)1); | 
| 645 | 304 |   source->pub.buffer_height = 1; | 
| 646 |  |  | 
| 647 | 304 |   cinfo->data_precision = 8; | 
| 648 | 304 |   cinfo->image_width = (JDIMENSION)biWidth; | 
| 649 | 304 |   cinfo->image_height = (JDIMENSION)biHeight; | 
| 650 | 304 | } | 
| 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 | 91 | { | 
| 660 |  |   /* no work */ | 
| 661 | 91 | } | 
| 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 | 1.32k | { | 
| 671 | 1.32k |   bmp_source_ptr source; | 
| 672 |  |  | 
| 673 |  |   /* Create module interface object */ | 
| 674 | 1.32k |   source = (bmp_source_ptr) | 
| 675 | 1.32k |     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, | 
| 676 | 1.32k |                                 sizeof(bmp_source_struct)); | 
| 677 | 1.32k |   source->cinfo = cinfo;        /* make back link for subroutines */ | 
| 678 |  |   /* Fill in method ptrs, except get_pixel_rows which start_input sets */ | 
| 679 | 1.32k |   source->pub.start_input = start_input_bmp; | 
| 680 | 1.32k |   source->pub.finish_input = finish_input_bmp; | 
| 681 | 1.32k | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 
| 682 | 1.32k |   source->pub.max_pixels = 0; | 
| 683 | 1.32k | #endif | 
| 684 |  |  | 
| 685 | 1.32k |   source->use_inversion_array = use_inversion_array; | 
| 686 |  |  | 
| 687 | 1.32k |   return (cjpeg_source_ptr)source; | 
| 688 | 1.32k | } | 
| 689 |  |  | 
| 690 |  | #endif /* BMP_SUPPORTED */ |