1 /*
2  * Copyright (c) 2004 Ximian
3  * Copyright (C) 2003-2004,2007 Novell, Inc (http://www.novell.com)
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6  * and associated documentation files (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9  * subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial
12  * portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15  * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
18  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  *
20  * bmpcodec.c : Contains function definitions for encoding decoding bmp images
21  *
22  * Authors:
23  *      Jordi Mas i Hernandez (jordi@ximian.com)
24  *      Sanjay Gupta (gsanjay@novell.com)
25  *      Mark Steele (ms@rapidsys.com)
26  *      Jonathan Gilbert (logic@deltaq.org)
27  *	Sebastien Pouliot  <sebastien@ximian.com>
28  *
29  * Useful documentation about bitmaps
30  *
31  *      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_4v1h.asp
32  *      http://www.csdn.net/Dev/Format/windows/Bmp.html
33  *      http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
34  *
35  *      Header structure
36  *              BITMAPFILEHEADER
37  *              BITMAPINFOHEADER or BITMAPV4HEADER or BITMAPV5HEADER or BITMAPCOREHEADER
38  *              RGBQUADS or RGBTRIPLE (optional)
39  *              Bitmap data
40  */
41 
42 #include "gdiplus-private.h"
43 #include "bmpcodec.h"
44 
45 GUID gdip_bmp_image_format_guid = {0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e}};
46 
47 /* Codecinfo related data*/
48 static ImageCodecInfo bmp_codec;
49 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', ' ', 'C', 'o', 'd', 'e', 'c', 0}; /* Built-in BMP Codec */
50 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
51 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
52 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
53 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
54 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
55 
56 
57 ImageCodecInfo *
gdip_getcodecinfo_bmp()58 gdip_getcodecinfo_bmp ()
59 {
60 	bmp_codec.Clsid = (CLSID) { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } };
61 	bmp_codec.FormatID = gdip_bmp_image_format_guid;
62 	bmp_codec.CodecName = (const WCHAR*) bmp_codecname;
63 	bmp_codec.DllName = NULL;
64 	bmp_codec.FormatDescription = (const WCHAR*) bmp_format;
65 	bmp_codec.FilenameExtension = (const WCHAR*) bmp_extension;
66 	bmp_codec.MimeType = (const WCHAR*) bmp_mimetype;
67 	bmp_codec.Flags = ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin;
68 	bmp_codec.Version = 1;
69 	bmp_codec.SigCount = 1;
70 	bmp_codec.SigSize = 2;
71 	bmp_codec.SigPattern = bmp_sig_pattern;
72 	bmp_codec.SigMask = bmp_sig_mask;
73 
74 	return &bmp_codec;
75 }
76 
77 static GpStatus
gdip_get_bmp_stride(PixelFormat format,INT width,INT * strideResult,BOOL cairoHacks)78 gdip_get_bmp_stride (PixelFormat format, INT width, INT *strideResult, BOOL cairoHacks)
79 {
80 	INT stride;
81 	/* stride is a (signed) _int_ and once multiplied by 4 it should hold a value that can be allocated by GdipAlloc
82 		* this effectively limits 'width' to 536870911 pixels */
83 	unsigned long long int widthBuff = width;
84 
85 	switch (format) {
86 	case PixelFormat1bppIndexed:
87 		stride = (width + 7) / 8;
88 		break;
89 	case PixelFormat4bppIndexed:
90 		stride = (width + 1) / 2;
91 		break;
92 	case PixelFormat8bppIndexed:
93 		stride = width;
94 		break;
95 	case PixelFormat16bppRGB555:
96 	case PixelFormat16bppRGB565:
97 		widthBuff *= 2;
98 		if (widthBuff > G_MAXINT32)
99 			return InvalidParameter;
100 
101 		stride = widthBuff;
102 		break;
103 	case PixelFormat24bppRGB:
104 		widthBuff *= cairoHacks ? 4 : 3;
105 		if (widthBuff > G_MAXINT32)
106 			return InvalidParameter;
107 
108 		stride = widthBuff;
109 		break;
110 	default:
111 		widthBuff *= 4;
112 		if (widthBuff > G_MAXINT32)
113 			return InvalidParameter;
114 
115 		stride = widthBuff;
116 		break;
117 	}
118 
119 	/* Ensure 32bits alignment */
120 	gdip_align_stride (stride);
121 	*strideResult = stride;
122 	return Ok;
123 }
124 
125 static GpStatus
gdip_get_bmp_pixelformat(const BITMAPV5HEADER * bih,PixelFormat * sourceFormatResult,PixelFormat * conversionFormatResult)126 gdip_get_bmp_pixelformat (const BITMAPV5HEADER *bih, PixelFormat *sourceFormatResult, PixelFormat *conversionFormatResult)
127 {
128 	PixelFormat sourceFormat;
129 	PixelFormat conversionFormat;
130 
131 	if (bih->bV5Compression == BI_BITFIELDS) {
132 		if (bih->bV5BitCount != 16)
133 			return OutOfMemory;
134 
135 		if ((bih->bV5RedMask == 0x7C00) && (bih->bV5GreenMask == 0x3E0) && (bih->bV5BlueMask == 0x1F))
136 			sourceFormat = PixelFormat16bppRGB555;
137 		else if ((bih->bV5RedMask == 0xF800) && (bih->bV5GreenMask == 0x7E0) && (bih->bV5BlueMask == 0x1F))
138 			sourceFormat = PixelFormat16bppRGB565;
139 		else
140 			sourceFormat = PixelFormat16bppRGB555;
141 
142 		conversionFormat = PixelFormat32bppRGB;
143 	} else {
144 		switch (bih->bV5BitCount) {
145 		case 64:
146 			sourceFormat = PixelFormat64bppARGB;
147 			conversionFormat = sourceFormat;
148 			break;
149 		case 32:
150 			sourceFormat = PixelFormat32bppRGB;
151 			conversionFormat = sourceFormat;
152 			break;
153 		case 24:
154 			sourceFormat = PixelFormat24bppRGB;
155 			conversionFormat = sourceFormat;
156 			break;
157 		case 16:
158 			sourceFormat = PixelFormat16bppRGB555;
159 			conversionFormat = PixelFormat32bppRGB;
160 			break;
161 		case 8:
162 			sourceFormat = PixelFormat8bppIndexed;
163 			conversionFormat = sourceFormat;
164 			break;
165 		case 4:
166 			sourceFormat = PixelFormat4bppIndexed;
167 			conversionFormat = sourceFormat;
168 			break;
169 		case 1:
170 			sourceFormat = PixelFormat1bppIndexed;
171 			conversionFormat = sourceFormat;
172 			break;
173 		default:
174 			return OutOfMemory;
175 		}
176 	}
177 
178 	*sourceFormatResult = sourceFormat;
179 	*conversionFormatResult = conversionFormat;
180 	return Ok;
181 }
182 
183 static void
gdip_bitmap_fill_info_header(GpBitmap * bitmap,PBITMAPINFOHEADER bmi)184 gdip_bitmap_fill_info_header (GpBitmap *bitmap, PBITMAPINFOHEADER bmi)
185 {
186 	PixelFormat format = bitmap->active_bitmap->pixel_format;
187 
188 	memset (bmi, 0, sizeof (BITMAPINFOHEADER));
189 #ifdef WORDS_BIGENDIAN
190 	bmi->biSize = GUINT32_FROM_LE (sizeof (BITMAPINFOHEADER));
191 	bmi->biWidth = GULONG_FROM_LE (bitmap->active_bitmap->width);
192 	bmi->biHeight = GULONG_FROM_LE (bitmap->active_bitmap->height);
193 	bmi->biPlanes = GUINT16_FROM_LE (1);
194 	if (format != PixelFormat24bppRGB)
195 		bmi->biBitCount = GUINT16_FROM_LE (gdip_get_pixel_format_bpp (bitmap->active_bitmap->pixel_format));
196 	else
197 		bmi->biBitCount = GUINT16_FROM_LE (24);
198 	bmi->biCompression = GUINT32_FROM_LE (BI_RGB);
199 	bmi->biSizeImage =  GUINT32_FROM_LE (0); /* Many tools expect this may be set to zero for BI_RGB bitmaps */
200 	bmi->biXPelsPerMeter = GULONG_FROM_LE ((int) (0.5f + ((gdip_get_display_dpi() * 3937) / 100)));
201 	bmi->biYPelsPerMeter = GULONG_FROM_LE ((int) (0.5f + ((gdip_get_display_dpi() * 3937) / 100))); /* 1 meter is = 39.37 */
202 #else
203 	bmi->biSize = sizeof (BITMAPINFOHEADER);
204 	bmi->biWidth = bitmap->active_bitmap->width;
205 	bmi->biHeight = bitmap->active_bitmap->height;
206 	bmi->biPlanes = 1;
207 	if (format != PixelFormat24bppRGB)
208 		bmi->biBitCount = gdip_get_pixel_format_bpp (bitmap->active_bitmap->pixel_format);
209 	else
210 		bmi->biBitCount = 24;
211 
212 	bmi->biCompression = BI_RGB;
213 	bmi->biSizeImage =  0; /* Many tools expect this may be set to zero for BI_RGB bitmaps */
214 	bmi->biXPelsPerMeter = (int) (0.5f + ((gdip_get_display_dpi() * 3937) / 100));
215 	bmi->biYPelsPerMeter = (int) (0.5f + ((gdip_get_display_dpi() * 3937) / 100)); /* 1 meter is = 39.37 */
216 #endif
217 }
218 
219 static void
gdip_read_bmp_rle_8bit(void * pointer,BYTE * scan0,BOOL upsidedown,int stride,int scanWidth,int scanCount,ImageSource source)220 gdip_read_bmp_rle_8bit (void *pointer, BYTE *scan0, BOOL upsidedown, int stride, int scanWidth, int scanCount, ImageSource source)
221 {
222 	BYTE code;
223 	int bytes_read;
224 
225 	int col_offset = 0;
226 	int row_offset = (scanCount - 1) * stride;
227 	int row_delta = -stride;
228 	int rows_remaining = scanCount;
229 	int size = scanCount * stride;
230 	BOOL new_row = FALSE;
231 
232 	if (!upsidedown)
233 		return; /* top to bottom images can't be compressed */
234 
235 	if (scanWidth > stride)
236 		return;
237 
238 	while ((rows_remaining > 0)
239 	    || ((row_offset == 0) && (col_offset < scanWidth))) {
240 		bytes_read = gdip_read_bmp_data (pointer, &code, 1, source);
241 
242 		if (bytes_read < 1)
243 			return; /* TODO?: Add an "unexpected end of file" error code */
244 
245 		if (code == 0) { /* RLE escape code */
246 			bytes_read = gdip_read_bmp_data (pointer, &code, 1, source);
247 
248 			if (bytes_read < 1)
249 				return; /* TODO?: Add an "unexpected end of file" error code */
250 
251 			switch (code)
252 			{
253 				case 0: /* skip remainder of scan */
254 				{
255 					if (new_row)
256 						new_row = FALSE;
257 					else {
258 						row_offset += row_delta;
259 						rows_remaining--;
260 						col_offset = 0;
261 					}
262 					break;
263 				}
264 				case 1: /* skip remainder of image -- in other words, we're finished :-) */
265 				{
266 					return;
267 				}
268 				case 2: /* jump forward (dx, dy) coordinates */
269 				{
270 					BYTE dx, dy;
271 
272 					bytes_read  = gdip_read_bmp_data (pointer, &dx, 1, source);
273 					bytes_read += gdip_read_bmp_data (pointer, &dy, 1, source);
274 
275 					if (bytes_read < 2)
276 						return; /* TODO?: Add an "unexpected end of file" error code */
277 
278 					/* not really sure how to handle the case where the X delta goes
279 					 * past the end of the scan. in the interest of not crashing,
280 					 * let's wrap it back around.
281 					 */
282 					col_offset = (col_offset + dx) % scanWidth;
283 					row_offset -= dy * stride; /* BMPs go from bottom to top */
284 
285 					new_row = FALSE;
286 					break;
287 				}
288 				default: /* an uncompressed section, 'code' pixels wide */
289 				{
290 					/* uncompressed sections must be an even number of bytes long,
291 					 * even if they are an odd number of *pixels* long.
292 					 */
293 					BOOL pad_byte_present = ((code & 1) != 0);
294 					int bytes_to_read = code;
295 
296 					/* wrap rows properly, even though they are inverted in memory */
297 					while (bytes_to_read > 0) {
298 						int bytes_to_read_this_scan = scanWidth - col_offset;
299 
300 						if (bytes_to_read_this_scan > bytes_to_read)
301 							bytes_to_read_this_scan = bytes_to_read;
302 
303 						int pixel_index = row_offset + col_offset;
304 
305 						if (pixel_index < 0 || pixel_index >= size)
306 							return;
307 
308 						bytes_read = gdip_read_bmp_data (
309 							pointer,
310 							&scan0[pixel_index],
311 							bytes_to_read_this_scan,
312 							source);
313 
314 						if (bytes_read < bytes_to_read_this_scan)
315 							return; /* TODO?: Add an "unexpected end of file" error code */
316 
317 						col_offset += bytes_read;
318 						bytes_to_read -= bytes_read;
319 
320 						if (col_offset >= scanWidth)
321 						{
322 							col_offset = 0;
323 							row_offset += row_delta;
324 							rows_remaining--;
325 
326 							if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
327 								return;
328 
329 							new_row = TRUE;
330 						}
331 						else
332 							new_row = FALSE;
333 					}
334 
335 					if (pad_byte_present) {
336 						bytes_read = gdip_read_bmp_data(pointer, &code, 1, source);
337 
338 						if (bytes_read < 1)
339 							return; /* TODO?: Add an "unexpected end of file" error code */
340 					}
341 
342 					break;
343 				}
344 			}
345 		}
346 		else {
347 			/* we have a run of length 'code'. the colour of the run is the next byte in the file. */
348 			int run_length = code;
349 			BYTE pixel_value;
350 
351 			bytes_read = gdip_read_bmp_data(pointer, &pixel_value, 1, source);
352 
353 			if (bytes_read < 1)
354 				return; /* TODO?: Add an "unexpected end of file" error code */
355 
356 			while (run_length > 0) {
357 				int bytes_to_run_this_scan = scanWidth - col_offset;
358 
359 				if (bytes_to_run_this_scan > run_length)
360 					bytes_to_run_this_scan = run_length;
361 
362 				int pixel_index = row_offset + col_offset;
363 
364 				if (pixel_index < 0 || pixel_index >= size)
365 					return;
366 
367 				if (bytes_to_run_this_scan < 0 || pixel_index + bytes_to_run_this_scan > size)
368 					return;
369 
370 				memset (scan0 + pixel_index, pixel_value, bytes_to_run_this_scan);
371 
372 				col_offset += bytes_to_run_this_scan;
373 				run_length -= bytes_to_run_this_scan;
374 
375 				if (col_offset >= scanWidth)
376 				{
377 					col_offset = 0;
378 					row_offset += row_delta;
379 					rows_remaining--;
380 
381 					if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
382 						return;
383 
384 					new_row = TRUE;
385 				}
386 				else
387 					new_row = FALSE;
388 			}
389 		}
390 	}
391 
392 	return;
393 }
394 
395 // PixelFormat32bppARGB.
396 ARGB
gdip_getpixel_32bppARGB(BYTE * scan,INT x)397 gdip_getpixel_32bppARGB (BYTE *scan, INT x)
398 {
399 	ARGB pixel = ((ARGB *) scan)[x];
400 	return pixel;
401 }
402 
403 void
gdip_setpixel_32bppARGB(BYTE * scan,INT x,BYTE a,BYTE r,BYTE g,BYTE b)404 gdip_setpixel_32bppARGB (BYTE *scan, INT x, BYTE a, BYTE r, BYTE g, BYTE b)
405 {
406 	set_pixel_bgra (scan, x * 4, b, g, r, a);
407 }
408 
409 // PixelFormat16bppRGB555.
410 ARGB
gdip_getpixel_16bppRGB555(BYTE * scan,INT x)411 gdip_getpixel_16bppRGB555 (BYTE *scan, INT x)
412 {
413 	WORD pixel = ((WORD *) scan)[x];
414 	return ((pixel & 0x1F) >> 2) | 8 * ((pixel & 0x1F) | 8 * (((((pixel >> 5) & 0x1F) | (((pixel >> 10) & 0x1C) << 8)) & 0xFFFFFFFC) | 32 * (((pixel >> 5) & 0x1F) | ((((pixel >> 10) & 0x1F) | 0xFFFFFFE0) << 8))));
415 }
416 
417 // PixelFormat16bppRGB565.
418 ARGB
gdip_getpixel_16bppRGB565(BYTE * scan,INT x)419 gdip_getpixel_16bppRGB565 (BYTE *scan, INT x)
420 {
421 	WORD pixel = ((WORD *) scan)[x];
422 	return ((pixel & 0x1F) >> 2) | 8 * ((pixel & 0x1F) | 2 * (((((pixel >> 5) & 0x3F) | (((pixel >> 11) & 0xFFFFFFFC) << 10)) & 0xFFFFFFF0) | ((((pixel >> 5) & 0x3F) | ((((pixel >> 11)) | 0xFFFFFFE0) << 9)) << 6)));
423 }
424 
425 static void
gdip_read_bmp_rle_4bit(void * pointer,BYTE * scan0,BOOL upsidedown,int stride,int scanWidth,int scanCount,ImageSource source)426 gdip_read_bmp_rle_4bit (void *pointer, BYTE *scan0, BOOL upsidedown, int stride, int scanWidth, int scanCount, ImageSource source)
427 {
428 	BYTE code;
429 	int bytes_read;
430 
431 	int col_offset = 0;
432 	int row_offset = (scanCount - 1) * stride;
433 	int row_delta = -stride;
434 	int rows_remaining = scanCount;
435 	int size = scanCount * stride;
436 	BOOL new_row = FALSE;
437 
438 	if (!upsidedown)
439 		return; /* top to bottom images can't be compressed */
440 
441 	if ((scanWidth & 1) != 0)
442 		scanWidth++;
443 
444 	if (scanWidth > stride * 2)
445 		return;
446 
447 	while (rows_remaining > 0) {
448 		bytes_read = gdip_read_bmp_data (pointer, &code, 1, source);
449 
450 		if (bytes_read < 1)
451 			return; /* TODO?: Add an "unexpected end of file" error code */
452 
453 		if (code == 0) { /* RLE escape code */
454 			bytes_read = gdip_read_bmp_data (pointer, &code, 1, source);
455 
456 			if (bytes_read < 1)
457 				return; /* TODO?: Add an "unexpected end of file" error code */
458 
459 			switch (code)
460 			{
461 				case 0: /* skip remainder of scan */
462 				{
463 					if (new_row)
464 						new_row = FALSE;
465 					else {
466 						row_offset += row_delta;
467 						rows_remaining--;
468 						col_offset = 0;
469 					}
470 					break;
471 				}
472 				case 1: /* skip remainder of image -- in other words, we're finished :-) */
473 				{
474 					return;
475 				}
476 				case 2: /* jump forward (dx, dy) coordinates */
477 				{
478 					BYTE dx, dy;
479 
480 					bytes_read  = gdip_read_bmp_data (pointer, &dx, 1, source);
481 					bytes_read += gdip_read_bmp_data (pointer, &dy, 1, source);
482 
483 					if (bytes_read < 2)
484 						return; /* TODO?: Add an "unexpected end of file" error code */
485 
486 					/* not really sure how to handle the case where the X delta goes
487 					 * past the end of the scan. in the interest of not crashing,
488 					 * let's wrap it back around.
489 					 */
490 					col_offset = (col_offset + dx) % scanWidth;
491 					row_offset -= dy * stride; /* BMPs go from bottom to top */
492 
493 					new_row = FALSE;
494 
495 					break;
496 				}
497 				default: /* an uncompressed section, 'code' pixels wide */
498 				{
499 					int pixels_to_read = code;
500 					int bytes_of_data = (pixels_to_read + 1) / 2;
501 
502 					/* uncompressed sections must be an even number of bytes long,
503 					 * even if they are an odd number of *pixels* long.
504 					 */
505 					BOOL pad_byte_present = ((bytes_of_data & 1) != 0);
506 
507 					int bytes_to_read = pixels_to_read / 2; /* leave off the last pixel for now */
508 
509 					/* wrap rows properly, even though they are inverted in memory */
510 					while (bytes_to_read > 0) {
511 						if ((scanWidth - col_offset) == 1) {
512 							/* special case: a pair of pixels is split across two rows. */
513 							BYTE pixels, same_row_pixel, next_row_pixel;
514 							int pixel_index = row_offset + col_offset / 2;
515 
516 							if (pixel_index < 0 || pixel_index >= size)
517 								return;
518 
519 							bytes_read = gdip_read_bmp_data (pointer, &pixels, 1, source);
520 
521 							if (bytes_read < 1)
522 								return; /* TODO?: Add an "unexpected end of file" error code */
523 
524 							same_row_pixel = (pixels >> 4) & 0x0F;
525 							next_row_pixel =  pixels       & 0x0F;
526 
527 							if ((col_offset & 1) != 0) {
528 								BYTE old_pixel = 0xF0 & scan0[pixel_index];
529 								scan0[pixel_index] = (old_pixel & 0xF0) | same_row_pixel;
530 							}
531 							else
532 								scan0[pixel_index] = same_row_pixel << 4;
533 
534 							col_offset = 1;
535 							row_offset += row_delta;
536 							rows_remaining--;
537 
538 							if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
539 								return;
540 
541 							if (row_offset < 0 || row_offset >= size)
542 								return;
543 
544 							scan0[row_offset] = next_row_pixel << 4;
545 
546 							new_row = FALSE;
547 						}
548 						else if ((col_offset & 1) == 0) {
549 							/* alignment is good; we can read pairs of pixels as bytes.
550 							 * if there are an odd number of pixels in a scan, though,
551 							 * then the last pixel will need to be special-cased. also,
552 							 * if the scan width is odd, then a byte will be split
553 							 * across a row ending. I don't know if this is in the spec,
554 							 * but it is the most resistant to crashing.
555 							 */
556 							int bytes_to_read_this_scan = (scanWidth - col_offset) / 2;
557 
558 							if (bytes_to_read_this_scan > bytes_to_read)
559 								bytes_to_read_this_scan = bytes_to_read;
560 
561 							int pixel_index = row_offset + col_offset / 2;
562 
563 							if (pixel_index < 0 || pixel_index >= size)
564 								return;
565 
566 							bytes_read = gdip_read_bmp_data (
567 								pointer,
568 								&scan0[pixel_index],
569 								bytes_to_read_this_scan,
570 								source);
571 
572 							if (bytes_read < bytes_to_read_this_scan)
573 								return; /* TODO?: Add an "unexpected end of file" error code */
574 
575 							col_offset += bytes_read * 2;
576 							bytes_to_read -= bytes_read;
577 
578 							new_row = FALSE;
579 						}
580 						else {
581 							/* bad alignment; nybble-swapping will be required */
582 							int pixel_index = row_offset + col_offset / 2;
583 
584 							if (pixel_index < 0 || pixel_index >= size)
585 								return;
586 
587 							BYTE last_high_nybble = 0xF0 & scan0[pixel_index];
588 
589 							int bytes_to_read_this_scan = (scanWidth - col_offset) / 2;
590 
591 							if (bytes_to_read_this_scan > bytes_to_read)
592 								bytes_to_read_this_scan = bytes_to_read;
593 
594 							while (bytes_to_read_this_scan >= 0) {
595 								BYTE pixels;
596 
597 								bytes_read = gdip_read_bmp_data (pointer, &pixels, 1, source);
598 
599 								if (bytes_read < 1)
600 									return; /* TODO?: Add an "unexpected end of file" error code */
601 
602 								pixel_index = row_offset + col_offset / 2;
603 
604 								if (pixel_index < 0 || pixel_index >= size)
605 									return;
606 
607 								scan0[pixel_index] = last_high_nybble | (pixels >> 4);
608 
609 								last_high_nybble = (pixels << 4) & 0xF0;
610 
611 								col_offset += 2; /* two pixels processed */
612 								bytes_to_read_this_scan--;
613 							}
614 
615 							new_row = FALSE;
616 						}
617 
618 						if (col_offset >= scanWidth) {
619 							col_offset = 0;
620 							row_offset += row_delta;
621 							rows_remaining--;
622 
623 							if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
624 								return;
625 
626 							new_row = TRUE;
627 						}
628 					}
629 
630 					if ((pixels_to_read & 1) != 0) {
631 						/* half of a byte remains to be inserted into the correct nybble */
632 						BYTE pixel;
633 						int pixel_index = row_offset + col_offset / 2;
634 
635 						if (pixel_index < 0 || pixel_index >= size)
636 							return;
637 
638 						bytes_read = gdip_read_bmp_data (pointer, &pixel, 1, source);
639 
640 						if (bytes_read < 1)
641 							return; /* TODO?: Add an "unexpected end of file" error code */
642 
643 						pixel >>= 4; /* the last pixel is in the high nybble */
644 
645 						if ((col_offset & 1) != 0) {
646 							BYTE old_pixel = 0xF0 & scan0[pixel_index];
647 							scan0[pixel_index] = (old_pixel & 0xF0) | pixel;
648 						}
649 						else
650 							scan0[pixel_index] = pixel << 4;
651 
652 						col_offset++;
653 
654 						if (col_offset >= scanWidth) {
655 							col_offset = 0;
656 							row_offset += row_delta;
657 							rows_remaining--;
658 
659 							if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
660 								return;
661 
662 							new_row = TRUE;
663 						}
664 						else
665 							new_row = FALSE;
666 					}
667 
668 					if (pad_byte_present) {
669 						bytes_read = gdip_read_bmp_data(pointer, &code, 1, source);
670 
671 						if (bytes_read < 1)
672 							return; /* TODO?: Add an "unexpected end of file" error code */
673 					}
674 
675 					break;
676 				}
677 			}
678 		}
679 		else {
680 			/* we have a run of length 'code'. the colour of the run is the next byte in the file.
681 			 * something weird is happening here in 4-bit land, though; a byte stores two pixels.
682 			 * what happens is rather odd: the run is actually of two alternating colours (which
683 			 * may, of course, be the same, but are not required to be). we need to make sure that
684 			 * the colours end up in the right nybbles of the output bytes.
685 			 */
686 			int run_pixels = code;
687 			int run_length = run_pixels / 2;
688 
689 			BYTE pixel_values;
690 			BYTE inverted_pixel_values;
691 
692 			bytes_read = gdip_read_bmp_data(pointer, &pixel_values, 1, source);
693 
694 			if (bytes_read < 1)
695 				return; /* TODO?: Add an "unexpected end of file" error code */
696 
697 			inverted_pixel_values = ((pixel_values & 0x0F) << 4) | ((pixel_values & 0xF0) >> 4);
698 
699 			if ((col_offset & 1) != 0) {
700 				BYTE temp = inverted_pixel_values;
701 				inverted_pixel_values = pixel_values;
702 				pixel_values = temp;
703 			}
704 
705 			while (run_length > 0) {
706 				if ((scanWidth - col_offset) == 1) {
707 					/* special case: a pair of pixels is split across two rows. */
708 					BYTE same_row_pixel = (pixel_values >> 4) & 0x0F;
709 					BYTE next_row_pixel =  pixel_values       & 0x0F;
710 
711 					int pixel_index = row_offset + col_offset / 2;
712 
713 					if (pixel_index < 0 || pixel_index >= size)
714 						return;
715 
716 					if ((col_offset & 1) != 0) {
717 						BYTE old_pixel = 0xF0 & scan0[pixel_index];
718 						scan0[pixel_index] = (old_pixel & 0xF0) | same_row_pixel;
719 					}
720 					else
721 						scan0[pixel_index] = same_row_pixel << 4;
722 
723 					col_offset = 1;
724 					row_offset += row_delta;
725 					rows_remaining--;
726 
727 					if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
728 						return;
729 
730 					if (row_offset < 0 || row_offset >= size)
731 						return;
732 
733 					scan0[row_offset] = next_row_pixel << 4;
734 
735 					new_row = FALSE;
736 
737 					if ((scanWidth & 1) != 0) {
738 						/* if the width of the scan is odd, then the nybbles swap
739 						 * places each time they cross from one row to the next
740 						 */
741 						BYTE temp = inverted_pixel_values;
742 						inverted_pixel_values = pixel_values;
743 						pixel_values = temp;
744 					}
745 				}
746 				else {
747 					int bytes_to_run_this_scan;
748 					int pixel_index = row_offset + col_offset / 2;
749 
750 					if (pixel_index < 0 || pixel_index >= size)
751 						return;
752 
753 					/* make sure we're byte-aligned; if we're not, we need to store a nybble first */
754 					if ((col_offset & 1) != 0) {
755 						BYTE old_pixel = 0xF0 & scan0[pixel_index];
756 						scan0[pixel_index] = (old_pixel & 0xF0) | (pixel_values & 0x0F);
757 
758 						col_offset++;
759 					}
760 
761 					bytes_to_run_this_scan = (scanWidth - col_offset) / 2;
762 
763 					if (bytes_to_run_this_scan > run_length)
764 						bytes_to_run_this_scan = run_length;
765 
766 					if (bytes_to_run_this_scan < 0 || pixel_index + bytes_to_run_this_scan > size)
767 						return;
768 
769 					memset (scan0 + pixel_index, pixel_values, bytes_to_run_this_scan);
770 
771 					col_offset += bytes_to_run_this_scan * 2;
772 					run_length -= bytes_to_run_this_scan;
773 
774 					if (col_offset >= scanWidth) {
775 						col_offset = 0;
776 						row_offset += row_delta;
777 						rows_remaining--;
778 
779 						if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
780 							return;
781 
782 						new_row = TRUE;
783 
784 						if ((scanWidth & 1) != 0) {
785 							/* if the width of the scan is odd, then the nybbles swap
786 							 * places each time they cross from one row to the next
787 							 */
788 							BYTE temp = inverted_pixel_values;
789 							inverted_pixel_values = pixel_values;
790 							pixel_values = temp;
791 						}
792 					}
793 					else
794 						new_row = FALSE;
795 				}
796 			}
797 
798 			if ((run_pixels & 1) != 0) {
799 				/* half of a byte remains to be inserted into the correct nybble */
800 				BYTE pixel = pixel_values >> 4; /* the last pixel is in the high nybble */
801 				int pixel_index = row_offset + col_offset / 2;
802 
803 				if (pixel_index < 0 || pixel_index >= size)
804 					return;
805 
806 				if ((col_offset & 1) != 0) {
807 					BYTE old_pixel = 0xF0 & scan0[pixel_index];
808 					scan0[pixel_index] = (old_pixel & 0xF0) | pixel;
809 				}
810 				else
811 					scan0[pixel_index] = pixel << 4;
812 
813 				col_offset++;
814 
815 				if (col_offset >= scanWidth) {
816 					col_offset = 0;
817 					row_offset += row_delta;
818 					rows_remaining--;
819 
820 					if (rows_remaining <= 0) /* more data than expected -- let's not make this a fatal error */
821 						return;
822 
823 					new_row = TRUE;
824 				}
825 				else
826 					new_row = FALSE;
827 			}
828 		}
829 	}
830 
831 	return;
832 }
833 
834 GpStatus
gdip_read_BITMAPINFOHEADER(void * pointer,ImageSource source,BITMAPV5HEADER * bmi,BOOL * upsidedown)835 gdip_read_BITMAPINFOHEADER (void *pointer, ImageSource source, BITMAPV5HEADER *bmi, BOOL *upsidedown)
836 {
837 	DWORD dw = 0;
838 	BYTE *data_read = (BYTE*)&dw;
839 	int size = sizeof (DWORD);
840 	int size_read = gdip_read_bmp_data (pointer, data_read, size, source);
841 	if (size_read < size)
842 		return OutOfMemory;
843 
844 	DWORD headerSize = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
845 	switch (headerSize) {
846 	case BITMAPCOREHEADER_SIZE:
847 		bmi->bV5Size = headerSize;
848 
849 		/* Old OS/2 format. Width and Height fields are WORDs instead of DWORDS */
850 		dw = 0;
851 		size_read = gdip_read_bmp_data (pointer, data_read, size, source);
852 		if (size_read < size)
853 			return OutOfMemory;
854 		bmi->bV5Width = (data_read[1]<<8 | data_read[0]);
855 		bmi->bV5Height = (data_read[3]<<8 | data_read[2]);
856 
857 		break;
858 	case sizeof (BITMAPINFOHEADER):
859 	case sizeof (BITMAPV3HEADER):
860 	case sizeof (BITMAPV4HEADER):
861 	case sizeof (BITMAPV5HEADER):
862 		bmi->bV5Size = headerSize;
863 
864 		dw = 0;
865 		size_read = gdip_read_bmp_data (pointer, data_read, size, source);
866 		if (size_read < size)
867 			return OutOfMemory;
868 		bmi->bV5Width = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
869 
870 		// Width can't be negative (as opposed to Height where that indicates a top-down image)
871 		if (bmi->bV5Width <= 0)
872 			return OutOfMemory;
873 
874 		dw = 0;
875 		size_read = gdip_read_bmp_data (pointer, data_read, size, source);
876 		if (size_read < size)
877 			return OutOfMemory;
878 		bmi->bV5Height = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
879 
880 		if (bmi->bV5Height == 0)
881 			return OutOfMemory;
882 
883 		break;
884 	default:
885 		/* This is an unknown or invalid header. */
886 		return OutOfMemory;
887 	}
888 
889 	dw = 0;
890 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
891 	if (size_read < size)
892 		return OutOfMemory;
893 	bmi->bV5Planes = (data_read[1]<<8 | data_read[0]);
894 	bmi->bV5BitCount = (data_read[3]<<8 | data_read[2]);
895 
896 	/* The OS/2 format doesn't have any of these other fields */
897 	if (bmi->bV5Size == BITMAPCOREHEADER_SIZE) {
898 		bmi->bV5Compression = 0;
899 		bmi->bV5SizeImage = 0;
900 		bmi->bV5XPelsPerMeter = 0;
901 		bmi->bV5YPelsPerMeter = 0;
902 		bmi->bV5ClrUsed = 0;
903 		bmi->bV5ClrImportant = 0;
904 
905 		return Ok;
906 	}
907 
908 	dw = 0;
909 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
910 	if (size_read < size)
911 		return OutOfMemory;
912 	bmi->bV5Compression = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
913 
914  	/* If the height is negative then the bitmap is sideup. */
915 	if (bmi->bV5Height < 0) {
916 		*upsidedown = FALSE;
917 		bmi->bV5Height = -bmi->bV5Height;
918 	}
919 
920 	dw = 0;
921 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
922 	if (size_read < size)
923 		return OutOfMemory;
924 	bmi->bV5SizeImage = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
925 
926 	dw = 0;
927 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
928 	if (size_read < size)
929 		return OutOfMemory;
930 	bmi->bV5XPelsPerMeter = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
931 
932 	dw = 0;
933 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
934 	if (size_read < size)
935 		return OutOfMemory;
936 	bmi->bV5YPelsPerMeter = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
937 
938 	dw = 0;
939 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
940 	if (size_read < size)
941 		return OutOfMemory;
942 	bmi->bV5ClrUsed = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
943 
944 	dw = 0;
945 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
946 	if (size_read < size)
947 		return OutOfMemory;
948 	bmi->bV5ClrImportant = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
949 
950 	/* We've finished reading the BITMAPINFOHEADER but later versions are larger. */
951 	if (bmi->bV5Size == sizeof (BITMAPINFOHEADER)) {
952 		// A 16bpp BITMAPINFOHEADER BI_BITFIELDS image is followed by a red, green and blue mask.
953 		if (bmi->bV5BitCount != 16 || bmi->bV5Compression != BI_BITFIELDS)
954 			return Ok;
955 	}
956 
957 	dw = 0;
958 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
959 	if (size_read < size)
960 		return OutOfMemory;
961 	bmi->bV5RedMask = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
962 
963 	dw = 0;
964 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
965 	if (size_read < size)
966 		return OutOfMemory;
967 	bmi->bV5GreenMask = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
968 
969 	dw = 0;
970 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
971 	if (size_read < size)
972 		return OutOfMemory;
973 	bmi->bV5BlueMask = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
974 
975 	if (bmi->bV5Size == sizeof (BITMAPINFOHEADER))
976 		return Ok;
977 
978 	dw = 0;
979 	size_read = gdip_read_bmp_data (pointer, data_read, size, source);
980 	if (size_read < size)
981 		return OutOfMemory;
982 	bmi->bV5AlphaMask = ((guint32)data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | data_read[0]);
983 
984 	/* We don't use any information in BITMAPV4HEADER or BITMAPV5HEADER, so there is no point going through all of
985 	 * the other fields. This leaves the rest of the structure uninitialized. */
986 	size = headerSize - sizeof (BITMAPV3HEADER);
987 	if (size > 0) {
988 		while (size > sizeof (DWORD)) {
989 			if (gdip_read_bmp_data (pointer, data_read, sizeof (DWORD), source) != sizeof (DWORD))
990 				return OutOfMemory;
991 			size -= sizeof (DWORD);
992 		}
993 		if (gdip_read_bmp_data (pointer, data_read, size, source) != size)
994 			return OutOfMemory;
995 	}
996 
997     return Ok;
998 }
999 
1000 static GpStatus
gdip_readbmp_palette(void * pointer,ImageSource source,const BITMAPV5HEADER * bmi,ColorPalette ** result)1001 gdip_readbmp_palette (void *pointer, ImageSource source, const BITMAPV5HEADER *bmi, ColorPalette **result)
1002 {
1003 	UINT numberOfColors = bmi->bV5ClrUsed;
1004 	if (bmi->bV5BitCount <= 8) {
1005 		int defaultNumberOfColors = 1 << bmi->bV5BitCount;
1006 		// A color count of 0 means use the default. Also use the default color count
1007 		// if the bitmap has specified an unsupported number of colors (i.e. greater
1008 		// than the default).
1009 		if (bmi->bV5ClrUsed == 0 || bmi->bV5ClrUsed > defaultNumberOfColors)
1010 			numberOfColors = defaultNumberOfColors;
1011 	}
1012 
1013 	// Nothing to do.
1014 	if (numberOfColors == 0)
1015 		return Ok;
1016 
1017 	BYTE buffer[4];
1018 	INT colorEntrySize = bmi->bV5Size == BITMAPCOREHEADER_SIZE ? 3 : 4;
1019 	unsigned long long int palette_size = (unsigned long long int)sizeof (ColorPalette) + sizeof (ARGB) * numberOfColors;
1020 
1021 	/* ensure total 'palette_size' does not overflow an integer and fits inside our 2GB limit */
1022 	if (palette_size > G_MAXINT32) {
1023 		return OutOfMemory;
1024 	}
1025 
1026 	ColorPalette *palette = GdipAlloc (palette_size);
1027 	if (!palette)
1028 		return OutOfMemory;
1029 
1030 	palette->Flags = 0;
1031 	palette->Count = numberOfColors;
1032 
1033 	for (int i = 0; i < palette->Count; i++) {
1034 		int size_read = gdip_read_bmp_data (pointer, buffer, colorEntrySize, source);
1035 		if (size_read < colorEntrySize) {
1036 			GdipFree (palette);
1037 			return OutOfMemory;
1038 		}
1039 
1040 		set_pixel_bgra (palette->Entries, i * 4, buffer[0], buffer[1], buffer[2], 0xFF);
1041 	}
1042 
1043 	*result = palette;
1044 	return Ok;
1045 }
1046 
1047 static GpStatus
gdip_read_bmp_scans(void * pointer,BYTE * pixels,BOOL upsidedown,PixelFormat format,INT srcStride,INT destStride,INT width,INT height,ImageSource source)1048 gdip_read_bmp_scans (void *pointer, BYTE *pixels, BOOL upsidedown, PixelFormat format, INT srcStride, INT destStride, INT width, INT height, ImageSource source)
1049 {
1050 	BYTE *scan = (BYTE *) GdipAlloc (srcStride);
1051 	if (!scan)
1052 		return OutOfMemory;
1053 
1054 	for (int y = 0; y < height; y++) {
1055 		int currentLine = upsidedown ? height - y - 1 : y;
1056 		int size_read = gdip_read_bmp_data (pointer, scan, srcStride, source);
1057 		if (size_read < srcStride) {
1058 			GdipFree (scan);
1059 			return OutOfMemory;
1060 		}
1061 
1062 		BYTE *destScan = pixels + currentLine * destStride;
1063 		switch (format) {
1064 			case PixelFormat1bppIndexed:
1065 			case PixelFormat4bppIndexed:
1066 			case PixelFormat8bppIndexed:
1067 				memcpy (destScan, scan, srcStride);
1068 				continue;
1069 			case PixelFormat16bppRGB555: {
1070 				for (int x = 0; x < width; x++) {
1071 					ARGB argb = gdip_getpixel_16bppRGB555 (scan, x);
1072 
1073 					BYTE a = (argb & 0xFF000000) >> 24;
1074 					BYTE r = (argb & 0x00FF0000) >> 16;
1075 					BYTE g = (argb & 0x0000FF00) >> 8;
1076 					BYTE b = (argb & 0x000000FF);
1077 					gdip_setpixel_32bppARGB (destScan, x, a, r, g, b);
1078 				}
1079 				continue;
1080 			}
1081 			case PixelFormat16bppRGB565: {
1082 				for (int x = 0; x < width; x++) {
1083 					ARGB argb = gdip_getpixel_16bppRGB565 (scan, x);
1084 
1085 					BYTE a = (argb & 0xFF000000) >> 24;
1086 					BYTE r = (argb & 0x00FF0000) >> 16;
1087 					BYTE g = (argb & 0x0000FF00) >> 8;
1088 					BYTE b = (argb & 0x000000FF);
1089 					gdip_setpixel_32bppARGB (destScan, x, a, r, g, b);
1090 				}
1091 				continue;
1092 			}
1093 			case PixelFormat24bppRGB: {
1094 				for (int x = 0; x < width; x++) {
1095 					gdip_setpixel_32bppARGB (destScan, x, 0xFF, scan[x * 3 + 2], scan[x * 3 + 1], scan[x * 3]);
1096 				}
1097 				continue;
1098 			}
1099 			case PixelFormat32bppRGB: {
1100 				for (int x = 0; x < width; x++) {
1101 					gdip_setpixel_32bppARGB (destScan, x, 0xFF, scan[x * 4 + 2], scan[x * 4 + 1], scan[x * 4]);
1102 				}
1103 				continue;
1104 			}
1105 			default:
1106 				GdipFree(scan);
1107 				return NotImplemented;
1108 		}
1109 	}
1110 
1111 	GdipFree(scan);
1112 	return Ok;
1113 }
1114 
1115 static GpStatus
gdip_read_bmp_indexed(void * pointer,BYTE * pixels,BOOL upsidedown,PixelFormat format,INT stride,INT width,INT height,ImageSource source)1116 gdip_read_bmp_indexed (void *pointer, BYTE *pixels, BOOL upsidedown, PixelFormat format, INT stride, INT width, INT height, ImageSource source)
1117 {
1118 	if (upsidedown)
1119 		return gdip_read_bmp_scans (pointer, pixels, upsidedown, format, stride, stride, width, height, source);
1120 
1121 	int size_read = gdip_read_bmp_data (pointer, pixels, stride * height, source);
1122 	if (size_read < stride)
1123 		return OutOfMemory;
1124 
1125 	return Ok;
1126 }
1127 
1128 /* For use with in-memory bitmaps, where the BITMAPFILEHEADER doesn't exists */
1129 GpStatus
gdip_read_bmp_image(void * pointer,GpImage ** image,ImageSource source)1130 gdip_read_bmp_image (void *pointer, GpImage **image, ImageSource source)
1131 {
1132 	BITMAPV5HEADER bmi;
1133 	GpBitmap	*result;
1134 	BYTE		*pixels;
1135 	PixelFormat	originalFormat;
1136 	INT	originalStride;
1137 	BOOL		upsidedown = TRUE;
1138 	GpStatus	status;
1139 	unsigned long long int size;
1140 
1141 	status = gdip_read_BITMAPINFOHEADER (pointer, source, &bmi, &upsidedown);
1142 	if (status != Ok)
1143 		return status;
1144 
1145 	result = gdip_bitmap_new_with_frame (NULL, TRUE);
1146 	if (!result)
1147 		return OutOfMemory;
1148 
1149 	status = gdip_get_bmp_pixelformat (&bmi, &originalFormat, &result->active_bitmap->pixel_format);
1150 	if (status != Ok) {
1151 		gdip_bitmap_dispose (result);
1152 		return status;
1153 	}
1154 
1155 	status = gdip_get_bmp_stride (result->active_bitmap->pixel_format, bmi.bV5Width, &result->active_bitmap->stride, /* cairoHacks */ TRUE);
1156 	if (status != Ok) {
1157 		gdip_bitmap_dispose (result);
1158 		return status;
1159 	}
1160 
1161 	status = gdip_get_bmp_stride (originalFormat, bmi.bV5Width, &originalStride, /* cairoHacks */ FALSE);
1162 	if (status != Ok) {
1163 		gdip_bitmap_dispose (result);
1164 		return status;
1165 	}
1166 
1167 	result->type = ImageTypeBitmap;
1168 	result->image_format = BMP;
1169 	result->active_bitmap->width = bmi.bV5Width;
1170 	result->active_bitmap->height = bmi.bV5Height;
1171 
1172  	status = gdip_readbmp_palette (pointer, source, &bmi, &result->active_bitmap->palette);
1173 	if (status != Ok) {
1174 		gdip_bitmap_dispose (result);
1175 		return status;
1176 	}
1177 
1178 	/* ensure total 'size' does not overflow an integer and fits inside our 2GB limit */
1179 	size = (unsigned long long int)result->active_bitmap->stride * result->active_bitmap->height;
1180 	if (size > G_MAXINT32) {
1181 		gdip_bitmap_dispose (result);
1182 		return OutOfMemory;
1183 	}
1184 
1185 	pixels = GdipAlloc (size);
1186 	if (!pixels) {
1187 		gdip_bitmap_dispose (result);
1188 		return OutOfMemory;
1189 	}
1190 
1191 	if (gdip_is_an_indexed_pixelformat (result->active_bitmap->pixel_format)) {
1192 		if (bmi.bV5Compression == BI_RLE4)
1193 			gdip_read_bmp_rle_4bit (pointer, pixels, upsidedown, result->active_bitmap->stride, result->active_bitmap->width, result->active_bitmap->height, source);
1194 		else if (bmi.bV5Compression == BI_RLE8)
1195 			gdip_read_bmp_rle_8bit (pointer, pixels, upsidedown, result->active_bitmap->stride, result->active_bitmap->width, result->active_bitmap->height, source);
1196 		else {
1197 			status = gdip_read_bmp_indexed (pointer, pixels, upsidedown, originalFormat, originalStride, result->active_bitmap->width, result->active_bitmap->height, source);
1198 			if (status != Ok) {
1199 				gdip_bitmap_dispose (result);
1200 				return status;
1201 			}
1202 		}
1203 	} else {
1204 		status = gdip_read_bmp_scans (pointer, pixels, upsidedown, originalFormat, originalStride, result->active_bitmap->stride, result->active_bitmap->width, result->active_bitmap->height, source);
1205 		if (status != Ok) {
1206 			gdip_bitmap_dispose (result);
1207 			return status;
1208 		}
1209 	}
1210 
1211 	result->active_bitmap->scan0 = pixels;
1212 	result->active_bitmap->reserved = GBD_OWN_SCAN0;
1213 	result->active_bitmap->image_flags = ImageFlagsReadOnly | ImageFlagsHasRealPixelSize | ImageFlagsColorSpaceRGB;
1214 	if (bmi.bV5XPelsPerMeter != 0 && bmi.bV5YPelsPerMeter != 0)
1215 		result->active_bitmap->image_flags |= ImageFlagsHasRealDPI;
1216 
1217 	*image = result;
1218 	return Ok;
1219 }
1220 
1221 /* BMP read from files have a BITMAPFILEHEADER but this isn't the case for the GDI API
1222  * (e.g. displaying a bitmap) */
1223 static void
BitmapFileHeaderFromLE(BITMAPFILEHEADER * bitmapFileHeader)1224 BitmapFileHeaderFromLE (BITMAPFILEHEADER *bitmapFileHeader)
1225 {
1226 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1227 	bitmapFileHeader->bfType = GUINT16_FROM_LE (bitmapFileHeader->bfType);
1228 	bitmapFileHeader->bfSize = GUINT32_FROM_LE (bitmapFileHeader->bfSize);
1229 	bitmapFileHeader->bfReserved1 = GUINT16_FROM_LE (bitmapFileHeader->bfReserved1);
1230 	bitmapFileHeader->bfReserved2 = GUINT16_FROM_LE (bitmapFileHeader->bfReserved2);
1231 	bitmapFileHeader->bfOffBits = GUINT32_FROM_LE (bitmapFileHeader->bfOffBits);
1232 #endif
1233 }
1234 
1235 static GpStatus
gdip_read_bmp_image_from_file_stream(void * pointer,GpImage ** image,ImageSource source)1236 gdip_read_bmp_image_from_file_stream (void *pointer, GpImage **image, ImageSource source)
1237 {
1238 	BITMAPFILEHEADER bmfh;
1239 	int size_read;
1240 
1241 	size_read = gdip_read_bmp_data (pointer, (BYTE *) &bmfh, sizeof (bmfh), source);
1242 	if (size_read < sizeof (bmfh)) {
1243 		return OutOfMemory;
1244 	}
1245 
1246 	BitmapFileHeaderFromLE (&bmfh);
1247 	if (bmfh.bfType != BFT_BITMAP) {
1248 		return UnknownImageFormat;
1249 	}
1250 
1251 	return gdip_read_bmp_image (pointer, image, source);
1252 }
1253 
1254 GpStatus
gdip_load_bmp_image_from_file(FILE * fp,GpImage ** image)1255 gdip_load_bmp_image_from_file (FILE *fp, GpImage **image)
1256 {
1257 	return gdip_read_bmp_image_from_file_stream ((void*)fp, image, File);
1258 }
1259 
1260 GpStatus
gdip_load_bmp_image_from_stream_delegate(dstream_t * loader,GpImage ** image)1261 gdip_load_bmp_image_from_stream_delegate (dstream_t *loader, GpImage **image)
1262 {
1263 	return gdip_read_bmp_image_from_file_stream ((void*)loader, image, DStream);
1264 }
1265 
1266 int
gdip_read_bmp_data(void * pointer,BYTE * data,int size,ImageSource source)1267 gdip_read_bmp_data (void *pointer, BYTE *data, int size, ImageSource source)
1268 {
1269 	switch (source) {
1270 	case File:
1271 		return fread (data, 1, size, (FILE*) pointer);
1272 	case DStream: {
1273 		/* Streams are not required to return the number of bytes
1274 		   requested, they could return less yet our code seems to assume
1275 		   it will always get what it's asking for; lets loop until we
1276 		   get what was requested or we get an error */
1277 		int got;
1278 		int total;
1279 		dstream_t *loader;
1280 
1281 		loader = (dstream_t *) pointer;
1282 		total = 0;
1283 
1284 		do {
1285 			got = dstream_read (loader, data + total, size - total, 0);
1286 			if (got < 1) {  /*  0 = end of stream, -1 = error */
1287 				return total;
1288 			}
1289 			total += got;
1290 		} while (total < size);
1291 
1292 		return total;
1293 	}
1294 	case Memory: {
1295 		MemorySource *ms = (MemorySource*)pointer;
1296 		int len = (ms->pos + size < ms->size) ? size : ms->size - ms->pos;
1297 		if (len > 0) {
1298 			memcpy (data, ms->ptr + ms->pos, len);
1299 			ms->pos += len;
1300 		}
1301 		return len;
1302 	}
1303 	default:
1304 		return -1;
1305 	}
1306 }
1307 
1308 static void
gdip_write_bmp_data(void * pointer,BYTE * data,int size,BOOL useFile)1309 gdip_write_bmp_data (void *pointer, BYTE *data, int size, BOOL useFile)
1310 {
1311 	if (useFile)
1312 		fwrite (data, 1, size, (FILE*) pointer);
1313 	else
1314 		((PutBytesDelegate)(pointer))(data, size);
1315 }
1316 
1317 static GpStatus
gdip_save_bmp_image_to_file_stream(void * pointer,GpImage * image,BOOL useFile)1318 gdip_save_bmp_image_to_file_stream (void *pointer, GpImage *image, BOOL useFile)
1319 {
1320 	BITMAPFILEHEADER	bmfh;
1321 	BITMAPINFOHEADER	bmi;
1322 	int			bitmapLen;
1323 	int			i;
1324 	ARGB			color;
1325 	int			colours = 0;
1326 	ARGB			*entries;
1327 	int			palette_entries;
1328 	ActiveBitmapData		*activebmp;
1329 	BYTE			*scan0;
1330 
1331 	activebmp = image->active_bitmap;
1332 	if (activebmp->pixel_format != PixelFormat24bppRGB) {
1333 		bitmapLen = activebmp->stride * activebmp->height;
1334 	} else {
1335 		bitmapLen = activebmp->width * 3;
1336 		bitmapLen += 3;
1337 		bitmapLen &= ~3;
1338 		bitmapLen *= activebmp->height;
1339 	}
1340 
1341 	if (activebmp->palette) {
1342 			colours = activebmp->palette->Count;
1343 	}
1344 
1345 	bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
1346 	bmfh.bfType = BFT_BITMAP;
1347 	bmfh.bfOffBits = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER) + colours * sizeof (RGBQUAD);
1348 	bmfh.bfSize = (bmfh.bfOffBits + bitmapLen);
1349 	BitmapFileHeaderFromLE (&bmfh);
1350 
1351 	gdip_write_bmp_data (pointer, (BYTE *) &bmfh, sizeof (bmfh), useFile);
1352 	gdip_bitmap_fill_info_header (image, &bmi);
1353 	gdip_write_bmp_data (pointer, (BYTE*) &bmi, sizeof (bmi), useFile);
1354 
1355 	if (colours) {
1356 		palette_entries = activebmp->palette->Count;
1357 
1358 		if (activebmp->pixel_format == PixelFormat4bppIndexed) {
1359 			palette_entries = 16;
1360 		}
1361 
1362 		entries = (ARGB *) GdipAlloc (palette_entries * sizeof (ARGB));
1363 		if (entries == NULL)
1364 			return OutOfMemory;
1365 
1366 		for (i = 0; i < palette_entries; i++) {
1367 			color = activebmp->palette->Entries[i];
1368 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1369 			*(entries + i) = color;
1370 #else
1371 			*(entries + i) = GUINT32_FROM_LE (color);
1372 #endif
1373 		}
1374 		gdip_write_bmp_data (pointer, (BYTE *) entries, palette_entries * sizeof (ARGB), useFile);
1375 		GdipFree (entries);
1376 	}
1377 
1378 	scan0 = activebmp->scan0;
1379 	if (activebmp->pixel_format == PixelFormat24bppRGB) {
1380 		int width = activebmp->width;
1381 		int height = activebmp->height;
1382 		int mystride;
1383 		int k;
1384 		BYTE *current_line;
1385 
1386 		/* rows need to be padded up to the next multiple of 4 */
1387 		mystride = width * 3;
1388 		mystride += 3;
1389 		mystride &= ~3;
1390 		current_line = (BYTE*) GdipAlloc (mystride);
1391 		if (!current_line) {
1392 			return OutOfMemory;
1393 		}
1394 
1395 		memset (current_line, 0, mystride); /* Zero padding at the end if needed */
1396 		for (i = height - 1; i >= 0; i--) {
1397 			BYTE *ptr;
1398 			guint32 *iptr;
1399 
1400 			iptr = (guint32 *) (scan0 + i * activebmp->stride);
1401 			ptr = current_line;
1402 			for (k = 0; k < width; k++) {
1403 				guint32 color = *iptr++;
1404 				*ptr++ = (color & 0x000000ff);
1405 				*ptr++ = ((color & 0x0000ff00) >> 8);
1406 				*ptr++ = ((color & 0x00ff0000) >> 16);
1407 			}
1408 			gdip_write_bmp_data (pointer, current_line, mystride, useFile);
1409 		}
1410 		GdipFree (current_line);
1411 		return Ok;
1412 	}
1413 
1414 	/* Writes bitmap upside down. Many tools can only process bmp stored this way*/
1415 #ifdef WORDS_BIGENDIAN
1416 	if (gdip_is_an_indexed_pixelformat (activebmp->pixel_format) == FALSE) {
1417 		int j;
1418 		BYTE *row_pointer = GdipAlloc (activebmp->width * 4);
1419 
1420 		if (row_pointer == NULL) {
1421 			return OutOfMemory;
1422 		}
1423 
1424 		for (i = activebmp->height -1; i >= 0; i--) {
1425 			for (j = 0; j < activebmp->width; j++) {
1426 				row_pointer[j*4] = *((BYTE*)scan0 + (activebmp->stride * i) + (j*4) + 3);
1427 				row_pointer[j*4+1] = *((BYTE*)scan0 + (activebmp->stride * i) + (j*4) + 2);
1428 				row_pointer[j*4+2] = *((BYTE*)scan0 + (activebmp->stride * i) + (j*4) + 1);
1429 				row_pointer[j*4+3] = *((BYTE*)scan0 + (activebmp->stride * i) + (j*4) + 0);
1430 			}
1431 			gdip_write_bmp_data (pointer, row_pointer, activebmp->stride, useFile);
1432 		}
1433 		GdipFree (row_pointer);
1434 	}
1435 	else
1436 #endif /* WORDS_BIGENDIAN */
1437 	for (i = activebmp->height - 1; i >= 0; i--) {
1438 		gdip_write_bmp_data (pointer, scan0 + i * activebmp->stride, activebmp->stride, useFile);
1439 	}
1440 
1441 	return Ok;
1442 }
1443 
1444 GpStatus
gdip_save_bmp_image_to_file(FILE * fp,GpImage * image)1445 gdip_save_bmp_image_to_file (FILE *fp, GpImage *image)
1446 {
1447 	return gdip_save_bmp_image_to_file_stream ( (void *)fp, image, TRUE);
1448 }
1449 
1450 GpStatus
gdip_save_bmp_image_to_stream_delegate(PutBytesDelegate putBytesFunc,GpImage * image)1451 gdip_save_bmp_image_to_stream_delegate (PutBytesDelegate putBytesFunc, GpImage *image)
1452 {
1453 	return gdip_save_bmp_image_to_file_stream ( (void *)putBytesFunc, image, FALSE);
1454 }
1455