VirtualBox

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

Last change on this file since 33656 was 33656, checked in by vboxsync, 14 years ago

*: rebrand Sun (L)GPL disclaimers

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