xref: /reactos/base/applications/mstsc/bitmap.c (revision dc0433f0)
1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Bitmap decompression routines
4    Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
5 
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /* three separate function for speed when decompressing the bitmaps
21    when modifying one function make the change in the others
22    jay.sorg@gmail.com */
23 
24 /* indent is confused by this file */
25 /* *INDENT-OFF* */
26 
27 #include "precomp.h"
28 
29 #define CVAL(p)   (*(p++))
30 #ifdef NEED_ALIGN
31 #ifdef L_ENDIAN
32 #define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
33 #else
34 #define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
35 #endif /* L_ENDIAN */
36 #else
37 #define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
38 #endif /* NEED_ALIGN */
39 
40 #define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
41 
42 #define REPEAT(statement) \
43 { \
44 	while((count & ~0x7) && ((x+8) < width)) \
45 		UNROLL8( statement; count--; x++; ); \
46 	\
47 	while((count > 0) && (x < width)) \
48 	{ \
49 		statement; \
50 		count--; \
51 		x++; \
52 	} \
53 }
54 
55 #define MASK_UPDATE() \
56 { \
57 	mixmask <<= 1; \
58 	if (mixmask == 0) \
59 	{ \
60 		mask = fom_mask ? fom_mask : CVAL(input); \
61 		mixmask = 1; \
62 	} \
63 }
64 
65 /* 1 byte bitmap decompress */
66 static RD_BOOL
67 bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size)
68 {
69 	uint8 *end = input + size;
70 	uint8 *prevline = NULL, *line = NULL;
71 	int opcode, count, offset, isfillormix, x = width;
72 	int lastopcode = -1, insertmix = False, bicolour = False;
73 	uint8 code;
74 	uint8 colour1 = 0, colour2 = 0;
75 	uint8 mixmask, mask = 0;
76 	uint8 mix = 0xff;
77 	int fom_mask = 0;
78 
79 	while (input < end)
80 	{
81 		fom_mask = 0;
82 		code = CVAL(input);
83 		opcode = code >> 4;
84 		/* Handle different opcode forms */
85 		switch (opcode)
86 		{
87 			case 0xc:
88 			case 0xd:
89 			case 0xe:
90 				opcode -= 6;
91 				count = code & 0xf;
92 				offset = 16;
93 				break;
94 			case 0xf:
95 				opcode = code & 0xf;
96 				if (opcode < 9)
97 				{
98 					count = CVAL(input);
99 					count |= CVAL(input) << 8;
100 				}
101 				else
102 				{
103 					count = (opcode < 0xb) ? 8 : 1;
104 				}
105 				offset = 0;
106 				break;
107 			default:
108 				opcode >>= 1;
109 				count = code & 0x1f;
110 				offset = 32;
111 				break;
112 		}
113 		/* Handle strange cases for counts */
114 		if (offset != 0)
115 		{
116 			isfillormix = ((opcode == 2) || (opcode == 7));
117 			if (count == 0)
118 			{
119 				if (isfillormix)
120 					count = CVAL(input) + 1;
121 				else
122 					count = CVAL(input) + offset;
123 			}
124 			else if (isfillormix)
125 			{
126 				count <<= 3;
127 			}
128 		}
129 		/* Read preliminary data */
130 		switch (opcode)
131 		{
132 			case 0:	/* Fill */
133 				if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
134 					insertmix = True;
135 				break;
136 			case 8:	/* Bicolour */
137 				colour1 = CVAL(input);
138 			case 3:	/* Colour */
139 				colour2 = CVAL(input);
140 				break;
141 			case 6:	/* SetMix/Mix */
142 			case 7:	/* SetMix/FillOrMix */
143 				mix = CVAL(input);
144 				opcode -= 5;
145 				break;
146 			case 9:	/* FillOrMix_1 */
147 				mask = 0x03;
148 				opcode = 0x02;
149 				fom_mask = 3;
150 				break;
151 			case 0x0a:	/* FillOrMix_2 */
152 				mask = 0x05;
153 				opcode = 0x02;
154 				fom_mask = 5;
155 				break;
156 		}
157 		lastopcode = opcode;
158 		mixmask = 0;
159 		/* Output body */
160 		while (count > 0)
161 		{
162 			if (x >= width)
163 			{
164 				if (height <= 0)
165 					return False;
166 				x = 0;
167 				height--;
168 				prevline = line;
169 				line = output + height * width;
170 			}
171 			switch (opcode)
172 			{
173 				case 0:	/* Fill */
174 					if (insertmix)
175 					{
176 						if (prevline == NULL)
177 							line[x] = mix;
178 						else
179 							line[x] = prevline[x] ^ mix;
180 						insertmix = False;
181 						count--;
182 						x++;
183 					}
184 					if (prevline == NULL)
185 					{
186 						REPEAT(line[x] = 0)
187 					}
188 					else
189 					{
190 						REPEAT(line[x] = prevline[x])
191 					}
192 					break;
193 				case 1:	/* Mix */
194 					if (prevline == NULL)
195 					{
196 						REPEAT(line[x] = mix)
197 					}
198 					else
199 					{
200 						REPEAT(line[x] = prevline[x] ^ mix)
201 					}
202 					break;
203 				case 2:	/* Fill or Mix */
204 					if (prevline == NULL)
205 					{
206 						REPEAT
207 						(
208 							MASK_UPDATE();
209 							if (mask & mixmask)
210 								line[x] = mix;
211 							else
212 								line[x] = 0;
213 						)
214 					}
215 					else
216 					{
217 						REPEAT
218 						(
219 							MASK_UPDATE();
220 							if (mask & mixmask)
221 								line[x] = prevline[x] ^ mix;
222 							else
223 								line[x] = prevline[x];
224 						)
225 					}
226 					break;
227 				case 3:	/* Colour */
228 					REPEAT(line[x] = colour2)
229 					break;
230 				case 4:	/* Copy */
231 					REPEAT(line[x] = CVAL(input))
232 					break;
233 				case 8:	/* Bicolour */
234 					REPEAT
235 					(
236 						if (bicolour)
237 						{
238 							line[x] = colour2;
239 							bicolour = False;
240 						}
241 						else
242 						{
243 							line[x] = colour1;
244 							bicolour = True; count++;
245 						}
246 					)
247 					break;
248 				case 0xd:	/* White */
249 					REPEAT(line[x] = 0xff)
250 					break;
251 				case 0xe:	/* Black */
252 					REPEAT(line[x] = 0)
253 					break;
254 				default:
255 					unimpl("bitmap opcode 0x%x\n", opcode);
256 					return False;
257 			}
258 		}
259 	}
260 	return True;
261 }
262 
263 /* 2 byte bitmap decompress */
264 static RD_BOOL
265 bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
266 {
267 	uint8 *end = input + size;
268 	uint16 *prevline = NULL, *line = NULL;
269 	int opcode, count, offset, isfillormix, x = width;
270 	int lastopcode = -1, insertmix = False, bicolour = False;
271 	uint8 code;
272 	uint16 colour1 = 0, colour2 = 0;
273 	uint8 mixmask, mask = 0;
274 	uint16 mix = 0xffff;
275 	int fom_mask = 0;
276 
277 	while (input < end)
278 	{
279 		fom_mask = 0;
280 		code = CVAL(input);
281 		opcode = code >> 4;
282 		/* Handle different opcode forms */
283 		switch (opcode)
284 		{
285 			case 0xc:
286 			case 0xd:
287 			case 0xe:
288 				opcode -= 6;
289 				count = code & 0xf;
290 				offset = 16;
291 				break;
292 			case 0xf:
293 				opcode = code & 0xf;
294 				if (opcode < 9)
295 				{
296 					count = CVAL(input);
297 					count |= CVAL(input) << 8;
298 				}
299 				else
300 				{
301 					count = (opcode < 0xb) ? 8 : 1;
302 				}
303 				offset = 0;
304 				break;
305 			default:
306 				opcode >>= 1;
307 				count = code & 0x1f;
308 				offset = 32;
309 				break;
310 		}
311 		/* Handle strange cases for counts */
312 		if (offset != 0)
313 		{
314 			isfillormix = ((opcode == 2) || (opcode == 7));
315 			if (count == 0)
316 			{
317 				if (isfillormix)
318 					count = CVAL(input) + 1;
319 				else
320 					count = CVAL(input) + offset;
321 			}
322 			else if (isfillormix)
323 			{
324 				count <<= 3;
325 			}
326 		}
327 		/* Read preliminary data */
328 		switch (opcode)
329 		{
330 			case 0:	/* Fill */
331 				if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
332 					insertmix = True;
333 				break;
334 			case 8:	/* Bicolour */
335 				CVAL2(input, colour1);
336 			case 3:	/* Colour */
337 				CVAL2(input, colour2);
338 				break;
339 			case 6:	/* SetMix/Mix */
340 			case 7:	/* SetMix/FillOrMix */
341 				CVAL2(input, mix);
342 				opcode -= 5;
343 				break;
344 			case 9:	/* FillOrMix_1 */
345 				mask = 0x03;
346 				opcode = 0x02;
347 				fom_mask = 3;
348 				break;
349 			case 0x0a:	/* FillOrMix_2 */
350 				mask = 0x05;
351 				opcode = 0x02;
352 				fom_mask = 5;
353 				break;
354 		}
355 		lastopcode = opcode;
356 		mixmask = 0;
357 		/* Output body */
358 		while (count > 0)
359 		{
360 			if (x >= width)
361 			{
362 				if (height <= 0)
363 					return False;
364 				x = 0;
365 				height--;
366 				prevline = line;
367 				line = ((uint16 *) output) + height * width;
368 			}
369 			switch (opcode)
370 			{
371 				case 0:	/* Fill */
372 					if (insertmix)
373 					{
374 						if (prevline == NULL)
375 							line[x] = mix;
376 						else
377 							line[x] = prevline[x] ^ mix;
378 						insertmix = False;
379 						count--;
380 						x++;
381 					}
382 					if (prevline == NULL)
383 					{
384 						REPEAT(line[x] = 0)
385 					}
386 					else
387 					{
388 						REPEAT(line[x] = prevline[x])
389 					}
390 					break;
391 				case 1:	/* Mix */
392 					if (prevline == NULL)
393 					{
394 						REPEAT(line[x] = mix)
395 					}
396 					else
397 					{
398 						REPEAT(line[x] = prevline[x] ^ mix)
399 					}
400 					break;
401 				case 2:	/* Fill or Mix */
402 					if (prevline == NULL)
403 					{
404 						REPEAT
405 						(
406 							MASK_UPDATE();
407 							if (mask & mixmask)
408 								line[x] = mix;
409 							else
410 								line[x] = 0;
411 						)
412 					}
413 					else
414 					{
415 						REPEAT
416 						(
417 							MASK_UPDATE();
418 							if (mask & mixmask)
419 								line[x] = prevline[x] ^ mix;
420 							else
421 								line[x] = prevline[x];
422 						)
423 					}
424 					break;
425 				case 3:	/* Colour */
426 					REPEAT(line[x] = colour2)
427 					break;
428 				case 4:	/* Copy */
429 					REPEAT(CVAL2(input, line[x]))
430 					break;
431 				case 8:	/* Bicolour */
432 					REPEAT
433 					(
434 						if (bicolour)
435 						{
436 							line[x] = colour2;
437 							bicolour = False;
438 						}
439 						else
440 						{
441 							line[x] = colour1;
442 							bicolour = True;
443 							count++;
444 						}
445 					)
446 					break;
447 				case 0xd:	/* White */
448 					REPEAT(line[x] = 0xffff)
449 					break;
450 				case 0xe:	/* Black */
451 					REPEAT(line[x] = 0)
452 					break;
453 				default:
454 					unimpl("bitmap opcode 0x%x\n", opcode);
455 					return False;
456 			}
457 		}
458 	}
459 	return True;
460 }
461 
462 /* 3 byte bitmap decompress */
463 static RD_BOOL
464 bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
465 {
466 	uint8 *end = input + size;
467 	uint8 *prevline = NULL, *line = NULL;
468 	int opcode, count, offset, isfillormix, x = width;
469 	int lastopcode = -1, insertmix = False, bicolour = False;
470 	uint8 code;
471 	uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0};
472 	uint8 mixmask, mask = 0;
473 	uint8 mix[3] = {0xff, 0xff, 0xff};
474 	int fom_mask = 0;
475 
476 	while (input < end)
477 	{
478 		fom_mask = 0;
479 		code = CVAL(input);
480 		opcode = code >> 4;
481 		/* Handle different opcode forms */
482 		switch (opcode)
483 		{
484 			case 0xc:
485 			case 0xd:
486 			case 0xe:
487 				opcode -= 6;
488 				count = code & 0xf;
489 				offset = 16;
490 				break;
491 			case 0xf:
492 				opcode = code & 0xf;
493 				if (opcode < 9)
494 				{
495 					count = CVAL(input);
496 					count |= CVAL(input) << 8;
497 				}
498 				else
499 				{
500 					count = (opcode <
501 						 0xb) ? 8 : 1;
502 				}
503 				offset = 0;
504 				break;
505 			default:
506 				opcode >>= 1;
507 				count = code & 0x1f;
508 				offset = 32;
509 				break;
510 		}
511 		/* Handle strange cases for counts */
512 		if (offset != 0)
513 		{
514 			isfillormix = ((opcode == 2) || (opcode == 7));
515 			if (count == 0)
516 			{
517 				if (isfillormix)
518 					count = CVAL(input) + 1;
519 				else
520 					count = CVAL(input) + offset;
521 			}
522 			else if (isfillormix)
523 			{
524 				count <<= 3;
525 			}
526 		}
527 		/* Read preliminary data */
528 		switch (opcode)
529 		{
530 			case 0:	/* Fill */
531 				if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
532 					insertmix = True;
533 				break;
534 			case 8:	/* Bicolour */
535 				colour1[0] = CVAL(input);
536 				colour1[1] = CVAL(input);
537 				colour1[2] = CVAL(input);
538 			case 3:	/* Colour */
539 				colour2[0] = CVAL(input);
540 				colour2[1] = CVAL(input);
541 				colour2[2] = CVAL(input);
542 				break;
543 			case 6:	/* SetMix/Mix */
544 			case 7:	/* SetMix/FillOrMix */
545 				mix[0] = CVAL(input);
546 				mix[1] = CVAL(input);
547 				mix[2] = CVAL(input);
548 				opcode -= 5;
549 				break;
550 			case 9:	/* FillOrMix_1 */
551 				mask = 0x03;
552 				opcode = 0x02;
553 				fom_mask = 3;
554 				break;
555 			case 0x0a:	/* FillOrMix_2 */
556 				mask = 0x05;
557 				opcode = 0x02;
558 				fom_mask = 5;
559 				break;
560 		}
561 		lastopcode = opcode;
562 		mixmask = 0;
563 		/* Output body */
564 		while (count > 0)
565 		{
566 			if (x >= width)
567 			{
568 				if (height <= 0)
569 					return False;
570 				x = 0;
571 				height--;
572 				prevline = line;
573 				line = output + height * (width * 3);
574 			}
575 			switch (opcode)
576 			{
577 				case 0:	/* Fill */
578 					if (insertmix)
579 					{
580 						if (prevline == NULL)
581 						{
582 							line[x * 3] = mix[0];
583 							line[x * 3 + 1] = mix[1];
584 							line[x * 3 + 2] = mix[2];
585 						}
586 						else
587 						{
588 							line[x * 3] =
589 							 prevline[x * 3] ^ mix[0];
590 							line[x * 3 + 1] =
591 							 prevline[x * 3 + 1] ^ mix[1];
592 							line[x * 3 + 2] =
593 							 prevline[x * 3 + 2] ^ mix[2];
594 						}
595 						insertmix = False;
596 						count--;
597 						x++;
598 					}
599 					if (prevline == NULL)
600 					{
601 						REPEAT
602 						(
603 							line[x * 3] = 0;
604 							line[x * 3 + 1] = 0;
605 							line[x * 3 + 2] = 0;
606 						)
607 					}
608 					else
609 					{
610 						REPEAT
611 						(
612 							line[x * 3] = prevline[x * 3];
613 							line[x * 3 + 1] = prevline[x * 3 + 1];
614 							line[x * 3 + 2] = prevline[x * 3 + 2];
615 						)
616 					}
617 					break;
618 				case 1:	/* Mix */
619 					if (prevline == NULL)
620 					{
621 						REPEAT
622 						(
623 							line[x * 3] = mix[0];
624 							line[x * 3 + 1] = mix[1];
625 							line[x * 3 + 2] = mix[2];
626 						)
627 					}
628 					else
629 					{
630 						REPEAT
631 						(
632 							line[x * 3] =
633 							 prevline[x * 3] ^ mix[0];
634 							line[x * 3 + 1] =
635 							 prevline[x * 3 + 1] ^ mix[1];
636 							line[x * 3 + 2] =
637 							 prevline[x * 3 + 2] ^ mix[2];
638 						)
639 					}
640 					break;
641 				case 2:	/* Fill or Mix */
642 					if (prevline == NULL)
643 					{
644 						REPEAT
645 						(
646 							MASK_UPDATE();
647 							if (mask & mixmask)
648 							{
649 								line[x * 3] = mix[0];
650 								line[x * 3 + 1] = mix[1];
651 								line[x * 3 + 2] = mix[2];
652 							}
653 							else
654 							{
655 								line[x * 3] = 0;
656 								line[x * 3 + 1] = 0;
657 								line[x * 3 + 2] = 0;
658 							}
659 						)
660 					}
661 					else
662 					{
663 						REPEAT
664 						(
665 							MASK_UPDATE();
666 							if (mask & mixmask)
667 							{
668 								line[x * 3] =
669 								 prevline[x * 3] ^ mix [0];
670 								line[x * 3 + 1] =
671 								 prevline[x * 3 + 1] ^ mix [1];
672 								line[x * 3 + 2] =
673 								 prevline[x * 3 + 2] ^ mix [2];
674 							}
675 							else
676 							{
677 								line[x * 3] =
678 								 prevline[x * 3];
679 								line[x * 3 + 1] =
680 								 prevline[x * 3 + 1];
681 								line[x * 3 + 2] =
682 								 prevline[x * 3 + 2];
683 							}
684 						)
685 					}
686 					break;
687 				case 3:	/* Colour */
688 					REPEAT
689 					(
690 						line[x * 3] = colour2 [0];
691 						line[x * 3 + 1] = colour2 [1];
692 						line[x * 3 + 2] = colour2 [2];
693 					)
694 					break;
695 				case 4:	/* Copy */
696 					REPEAT
697 					(
698 						line[x * 3] = CVAL(input);
699 						line[x * 3 + 1] = CVAL(input);
700 						line[x * 3 + 2] = CVAL(input);
701 					)
702 					break;
703 				case 8:	/* Bicolour */
704 					REPEAT
705 					(
706 						if (bicolour)
707 						{
708 							line[x * 3] = colour2[0];
709 							line[x * 3 + 1] = colour2[1];
710 							line[x * 3 + 2] = colour2[2];
711 							bicolour = False;
712 						}
713 						else
714 						{
715 							line[x * 3] = colour1[0];
716 							line[x * 3 + 1] = colour1[1];
717 							line[x * 3 + 2] = colour1[2];
718 							bicolour = True;
719 							count++;
720 						}
721 					)
722 					break;
723 				case 0xd:	/* White */
724 					REPEAT
725 					(
726 						line[x * 3] = 0xff;
727 						line[x * 3 + 1] = 0xff;
728 						line[x * 3 + 2] = 0xff;
729 					)
730 					break;
731 				case 0xe:	/* Black */
732 					REPEAT
733 					(
734 						line[x * 3] = 0;
735 						line[x * 3 + 1] = 0;
736 						line[x * 3 + 2] = 0;
737 					)
738 					break;
739 				default:
740 					unimpl("bitmap opcode 0x%x\n", opcode);
741 					return False;
742 			}
743 		}
744 	}
745 	return True;
746 }
747 
748 /* decompress a colour plane */
749 static int
750 process_plane(uint8 * in, int width, int height, uint8 * out, int size)
751 {
752 	int indexw;
753 	int indexh;
754 	int code;
755 	int collen;
756 	int replen;
757 	int color;
758 	int x;
759 	int revcode;
760 	uint8 * last_line;
761 	uint8 * this_line;
762 	uint8 * org_in;
763 	uint8 * org_out;
764 
765 	org_in = in;
766 	org_out = out;
767 	last_line = 0;
768 	indexh = 0;
769 	while (indexh < height)
770 	{
771 		out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
772 		color = 0;
773 		this_line = out;
774 		indexw = 0;
775 		if (last_line == 0)
776 		{
777 			while (indexw < width)
778 			{
779 				code = CVAL(in);
780 				replen = code & 0xf;
781 				collen = (code >> 4) & 0xf;
782 				revcode = (replen << 4) | collen;
783 				if ((revcode <= 47) && (revcode >= 16))
784 				{
785 					replen = revcode;
786 					collen = 0;
787 				}
788 				while (collen > 0)
789 				{
790 					color = CVAL(in);
791 					*out = color;
792 					out += 4;
793 					indexw++;
794 					collen--;
795 				}
796 				while (replen > 0)
797 				{
798 					*out = color;
799 					out += 4;
800 					indexw++;
801 					replen--;
802 				}
803 			}
804 		}
805 		else
806 		{
807 			while (indexw < width)
808 			{
809 				code = CVAL(in);
810 				replen = code & 0xf;
811 				collen = (code >> 4) & 0xf;
812 				revcode = (replen << 4) | collen;
813 				if ((revcode <= 47) && (revcode >= 16))
814 				{
815 					replen = revcode;
816 					collen = 0;
817 				}
818 				while (collen > 0)
819 				{
820 					x = CVAL(in);
821 					if (x & 1)
822 					{
823 						x = x >> 1;
824 						x = x + 1;
825 						color = -x;
826 					}
827 					else
828 					{
829 						x = x >> 1;
830 						color = x;
831 					}
832 					x = last_line[indexw * 4] + color;
833 					*out = x;
834 					out += 4;
835 					indexw++;
836 					collen--;
837 				}
838 				while (replen > 0)
839 				{
840 					x = last_line[indexw * 4] + color;
841 					*out = x;
842 					out += 4;
843 					indexw++;
844 					replen--;
845 				}
846 			}
847 		}
848 		indexh++;
849 		last_line = this_line;
850 	}
851 	return (int) (in - org_in);
852 }
853 
854 /* 4 byte bitmap decompress */
855 static RD_BOOL
856 bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size)
857 {
858 	int code;
859 	int bytes_pro;
860 	int total_pro;
861 
862 	code = CVAL(input);
863 	if (code != 0x10)
864 	{
865 		return False;
866 	}
867 	total_pro = 1;
868 	bytes_pro = process_plane(input, width, height, output + 3, size - total_pro);
869 	total_pro += bytes_pro;
870 	input += bytes_pro;
871 	bytes_pro = process_plane(input, width, height, output + 2, size - total_pro);
872 	total_pro += bytes_pro;
873 	input += bytes_pro;
874 	bytes_pro = process_plane(input, width, height, output + 1, size - total_pro);
875 	total_pro += bytes_pro;
876 	input += bytes_pro;
877 	bytes_pro = process_plane(input, width, height, output + 0, size - total_pro);
878 	total_pro += bytes_pro;
879 	return size == total_pro;
880 }
881 
882 /* main decompress function */
883 RD_BOOL
884 bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp)
885 {
886 	RD_BOOL rv = False;
887 
888 	switch (Bpp)
889 	{
890 		case 1:
891 			rv = bitmap_decompress1(output, width, height, input, size);
892 			break;
893 		case 2:
894 			rv = bitmap_decompress2(output, width, height, input, size);
895 			break;
896 		case 3:
897 			rv = bitmap_decompress3(output, width, height, input, size);
898 			break;
899 		case 4:
900 			rv = bitmap_decompress4(output, width, height, input, size);
901 			break;
902 		default:
903 			unimpl("Bpp %d\n", Bpp);
904 			break;
905 	}
906 	return rv;
907 }
908 
909 /* *INDENT-ON* */
910