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
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.
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.
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/>.
20 /* three separate function for speed when decompressing the bitmaps
21 when modifying one function make the change in the others
24 /* indent is confused by this file */
29 #define CVAL(p) (*(p++))
32 #define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
34 #define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
37 #define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
38 #endif /* NEED_ALIGN */
40 #define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
42 #define REPEAT(statement) \
44 while((count & ~0x7) && ((x+8) < width)) \
45 UNROLL8( statement; count--; x++; ); \
47 while((count > 0) && (x < width)) \
55 #define MASK_UPDATE() \
60 mask = fom_mask ? fom_mask : CVAL(input); \
65 /* 1 byte bitmap decompress */
67 bitmap_decompress1(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
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
;
74 uint8 colour1
= 0, colour2
= 0;
75 uint8 mixmask
, mask
= 0;
84 /* Handle different opcode forms */
99 count
|= CVAL(input
) << 8;
103 count
= (opcode
< 0xb) ? 8 : 1;
113 /* Handle strange cases for counts */
116 isfillormix
= ((opcode
== 2) || (opcode
== 7));
120 count
= CVAL(input
) + 1;
122 count
= CVAL(input
) + offset
;
124 else if (isfillormix
)
129 /* Read preliminary data */
133 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
136 case 8: /* Bicolour */
137 colour1
= CVAL(input
);
139 colour2
= CVAL(input
);
141 case 6: /* SetMix/Mix */
142 case 7: /* SetMix/FillOrMix */
146 case 9: /* FillOrMix_1 */
151 case 0x0a: /* FillOrMix_2 */
169 line
= output
+ height
* width
;
176 if (prevline
== NULL
)
179 line
[x
] = prevline
[x
] ^ mix
;
184 if (prevline
== NULL
)
190 REPEAT(line
[x
] = prevline
[x
])
194 if (prevline
== NULL
)
196 REPEAT(line
[x
] = mix
)
200 REPEAT(line
[x
] = prevline
[x
] ^ mix
)
203 case 2: /* Fill or Mix */
204 if (prevline
== NULL
)
221 line
[x
] = prevline
[x
] ^ mix
;
223 line
[x
] = prevline
[x
];
228 REPEAT(line
[x
] = colour2
)
231 REPEAT(line
[x
] = CVAL(input
))
233 case 8: /* Bicolour */
244 bicolour
= True
; count
++;
248 case 0xd: /* White */
249 REPEAT(line
[x
] = 0xff)
251 case 0xe: /* Black */
255 unimpl("bitmap opcode 0x%x\n", opcode
);
263 /* 2 byte bitmap decompress */
265 bitmap_decompress2(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
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
;
272 uint16 colour1
= 0, colour2
= 0;
273 uint8 mixmask
, mask
= 0;
282 /* Handle different opcode forms */
297 count
|= CVAL(input
) << 8;
301 count
= (opcode
< 0xb) ? 8 : 1;
311 /* Handle strange cases for counts */
314 isfillormix
= ((opcode
== 2) || (opcode
== 7));
318 count
= CVAL(input
) + 1;
320 count
= CVAL(input
) + offset
;
322 else if (isfillormix
)
327 /* Read preliminary data */
331 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
334 case 8: /* Bicolour */
335 CVAL2(input
, colour1
);
337 CVAL2(input
, colour2
);
339 case 6: /* SetMix/Mix */
340 case 7: /* SetMix/FillOrMix */
344 case 9: /* FillOrMix_1 */
349 case 0x0a: /* FillOrMix_2 */
367 line
= ((uint16
*) output
) + height
* width
;
374 if (prevline
== NULL
)
377 line
[x
] = prevline
[x
] ^ mix
;
382 if (prevline
== NULL
)
388 REPEAT(line
[x
] = prevline
[x
])
392 if (prevline
== NULL
)
394 REPEAT(line
[x
] = mix
)
398 REPEAT(line
[x
] = prevline
[x
] ^ mix
)
401 case 2: /* Fill or Mix */
402 if (prevline
== NULL
)
419 line
[x
] = prevline
[x
] ^ mix
;
421 line
[x
] = prevline
[x
];
426 REPEAT(line
[x
] = colour2
)
429 REPEAT(CVAL2(input
, line
[x
]))
431 case 8: /* Bicolour */
447 case 0xd: /* White */
448 REPEAT(line
[x
] = 0xffff)
450 case 0xe: /* Black */
454 unimpl("bitmap opcode 0x%x\n", opcode
);
462 /* 3 byte bitmap decompress */
464 bitmap_decompress3(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
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
;
471 uint8 colour1
[3] = {0, 0, 0}, colour2
[3] = {0, 0, 0};
472 uint8 mixmask
, mask
= 0;
473 uint8 mix
[3] = {0xff, 0xff, 0xff};
481 /* Handle different opcode forms */
496 count
|= CVAL(input
) << 8;
511 /* Handle strange cases for counts */
514 isfillormix
= ((opcode
== 2) || (opcode
== 7));
518 count
= CVAL(input
) + 1;
520 count
= CVAL(input
) + offset
;
522 else if (isfillormix
)
527 /* Read preliminary data */
531 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
534 case 8: /* Bicolour */
535 colour1
[0] = CVAL(input
);
536 colour1
[1] = CVAL(input
);
537 colour1
[2] = CVAL(input
);
539 colour2
[0] = CVAL(input
);
540 colour2
[1] = CVAL(input
);
541 colour2
[2] = CVAL(input
);
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
);
550 case 9: /* FillOrMix_1 */
555 case 0x0a: /* FillOrMix_2 */
573 line
= output
+ height
* (width
* 3);
580 if (prevline
== NULL
)
582 line
[x
* 3] = mix
[0];
583 line
[x
* 3 + 1] = mix
[1];
584 line
[x
* 3 + 2] = mix
[2];
589 prevline
[x
* 3] ^ mix
[0];
591 prevline
[x
* 3 + 1] ^ mix
[1];
593 prevline
[x
* 3 + 2] ^ mix
[2];
599 if (prevline
== NULL
)
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];
619 if (prevline
== NULL
)
623 line
[x
* 3] = mix
[0];
624 line
[x
* 3 + 1] = mix
[1];
625 line
[x
* 3 + 2] = mix
[2];
633 prevline
[x
* 3] ^ mix
[0];
635 prevline
[x
* 3 + 1] ^ mix
[1];
637 prevline
[x
* 3 + 2] ^ mix
[2];
641 case 2: /* Fill or Mix */
642 if (prevline
== NULL
)
649 line
[x
* 3] = mix
[0];
650 line
[x
* 3 + 1] = mix
[1];
651 line
[x
* 3 + 2] = mix
[2];
669 prevline
[x
* 3] ^ mix
[0];
671 prevline
[x
* 3 + 1] ^ mix
[1];
673 prevline
[x
* 3 + 2] ^ mix
[2];
690 line
[x
* 3] = colour2
[0];
691 line
[x
* 3 + 1] = colour2
[1];
692 line
[x
* 3 + 2] = colour2
[2];
698 line
[x
* 3] = CVAL(input
);
699 line
[x
* 3 + 1] = CVAL(input
);
700 line
[x
* 3 + 2] = CVAL(input
);
703 case 8: /* Bicolour */
708 line
[x
* 3] = colour2
[0];
709 line
[x
* 3 + 1] = colour2
[1];
710 line
[x
* 3 + 2] = colour2
[2];
715 line
[x
* 3] = colour1
[0];
716 line
[x
* 3 + 1] = colour1
[1];
717 line
[x
* 3 + 2] = colour1
[2];
723 case 0xd: /* White */
727 line
[x
* 3 + 1] = 0xff;
728 line
[x
* 3 + 2] = 0xff;
731 case 0xe: /* Black */
740 unimpl("bitmap opcode 0x%x\n", opcode
);
748 /* decompress a colour plane */
750 process_plane(uint8
* in
, int width
, int height
, uint8
* out
, int size
)
769 while (indexh
< height
)
771 out
= (org_out
+ width
* height
* 4) - ((indexh
+ 1) * width
* 4);
777 while (indexw
< width
)
781 collen
= (code
>> 4) & 0xf;
782 revcode
= (replen
<< 4) | collen
;
783 if ((revcode
<= 47) && (revcode
>= 16))
807 while (indexw
< width
)
811 collen
= (code
>> 4) & 0xf;
812 revcode
= (replen
<< 4) | collen
;
813 if ((revcode
<= 47) && (revcode
>= 16))
832 x
= last_line
[indexw
* 4] + color
;
840 x
= last_line
[indexw
* 4] + color
;
849 last_line
= this_line
;
851 return (int) (in
- org_in
);
854 /* 4 byte bitmap decompress */
856 bitmap_decompress4(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
868 bytes_pro
= process_plane(input
, width
, height
, output
+ 3, size
- total_pro
);
869 total_pro
+= bytes_pro
;
871 bytes_pro
= process_plane(input
, width
, height
, output
+ 2, size
- total_pro
);
872 total_pro
+= bytes_pro
;
874 bytes_pro
= process_plane(input
, width
, height
, output
+ 1, size
- total_pro
);
875 total_pro
+= 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
;
882 /* main decompress function */
884 bitmap_decompress(uint8
* output
, int width
, int height
, uint8
* input
, int size
, int Bpp
)
891 rv
= bitmap_decompress1(output
, width
, height
, input
, size
);
894 rv
= bitmap_decompress2(output
, width
, height
, input
, size
);
897 rv
= bitmap_decompress3(output
, width
, height
, input
, size
);
900 rv
= bitmap_decompress4(output
, width
, height
, input
, size
);
903 unimpl("Bpp %d\n", Bpp
);