[RAPPS] Bulk install!
[reactos.git] / reactos / base / applications / mstsc / bitmap.c
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* */