VirtualBox

source: vbox/trunk/src/VBox/RDP/client/bitmap.c@ 10076

Last change on this file since 10076 was 9902, checked in by vboxsync, 16 years ago

Added rdesktop 1.6.0.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette