1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Bitmap decompression routines
4 Copyright (C) Matthew Chapman 1999-2005
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.
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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* three seperate function for speed when decompressing the bitmaps */
22 /* when modifing one function make the change in the others */
23 /* comment out #define BITMAP_SPEED_OVER_SIZE below for one slower function */
24 /* j@american-data.com */
26 #define BITMAP_SPEED_OVER_SIZE
28 /* indent is confused by this file */
33 #define CVAL(p) (*(p++))
36 #define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
38 #define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
41 #define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
42 #endif /* NEED_ALIGN */
44 #define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
46 #define REPEAT(statement) \
48 while((count & ~0x7) && ((x+8) < width)) \
49 UNROLL8( statement; count--; x++; ); \
51 while((count > 0) && (x < width)) \
59 #define MASK_UPDATE() \
64 mask = fom_mask ? fom_mask : CVAL(input); \
69 #ifdef BITMAP_SPEED_OVER_SIZE
71 /* 1 byte bitmap decompress */
73 bitmap_decompress1(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
75 uint8
*end
= input
+ size
;
76 uint8
*prevline
= NULL
;
77 int opcode
, count
, offset
, isfillormix
;
78 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
80 uint8 colour1
= 0, colour2
= 0;
81 uint8 mixmask
, mask
= 0;
98 /* Handle different opcode forms */
113 count
|= CVAL(input
) << 8;
117 count
= (opcode
< 0xb) ? 8 : 1;
127 /* Handle strange cases for counts */
130 isfillormix
= ((opcode
== 2) || (opcode
== 7));
134 count
= CVAL(input
) + 1;
136 count
= CVAL(input
) + offset
;
138 else if (isfillormix
)
143 /* Read preliminary data */
147 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
150 case 8: /* Bicolour */
151 colour1
= CVAL(input
);
153 colour2
= CVAL(input
);
155 case 6: /* SetMix/Mix */
156 case 7: /* SetMix/FillOrMix */
160 case 9: /* FillOrMix_1 */
165 case 0x0a: /* FillOrMix_2 */
195 line
= output
+ height
* width
;
197 line
= output
+ y
* width
;
205 if (prevline
== NULL
)
208 line
[x
] = prevline
[x
] ^ mix
;
213 if (prevline
== NULL
)
219 REPEAT(line
[x
] = prevline
[x
])
223 if (prevline
== NULL
)
225 REPEAT(line
[x
] = mix
)
229 REPEAT(line
[x
] = prevline
[x
] ^ mix
)
232 case 2: /* Fill or Mix */
233 if (prevline
== NULL
)
250 line
[x
] = prevline
[x
] ^ mix
;
252 line
[x
] = prevline
[x
];
257 REPEAT(line
[x
] = colour2
)
260 REPEAT(line
[x
] = CVAL(input
))
262 case 8: /* Bicolour */
273 bicolour
= True
; count
++;
277 case 0xd: /* White */
278 REPEAT(line
[x
] = 0xff)
280 case 0xe: /* Black */
284 unimpl("bitmap opcode 0x%x\n", opcode
);
292 /* 2 byte bitmap decompress */
294 bitmap_decompress2(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
296 uint8
*end
= input
+ size
;
297 uint16
*prevline
= NULL
;
298 int opcode
, count
, offset
, isfillormix
;
299 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
301 uint16 colour1
= 0, colour2
= 0;
302 uint8 mixmask
, mask
= 0;
309 uint8
*line
= output
;
319 /* Handle different opcode forms */
334 count
|= CVAL(input
) << 8;
338 count
= (opcode
< 0xb) ? 8 : 1;
348 /* Handle strange cases for counts */
351 isfillormix
= ((opcode
== 2) || (opcode
== 7));
355 count
= CVAL(input
) + 1;
357 count
= CVAL(input
) + offset
;
359 else if (isfillormix
)
364 /* Read preliminary data */
368 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
371 case 8: /* Bicolour */
372 CVAL2(input
, colour1
);
374 CVAL2(input
, colour2
);
376 case 6: /* SetMix/Mix */
377 case 7: /* SetMix/FillOrMix */
381 case 9: /* FillOrMix_1 */
386 case 0x0a: /* FillOrMix_2 */
416 line
= ((uint16
*) output
) + height
* width
;
418 line
= ((uint16
*) output
) + y
* width
;
426 if (prevline
== NULL
)
429 line
[x
] = prevline
[x
] ^ mix
;
434 if (prevline
== NULL
)
440 REPEAT(line
[x
] = prevline
[x
])
444 if (prevline
== NULL
)
446 REPEAT(line
[x
] = mix
)
450 REPEAT(line
[x
] = prevline
[x
] ^ mix
)
453 case 2: /* Fill or Mix */
454 if (prevline
== NULL
)
471 line
[x
] = prevline
[x
] ^ mix
;
473 line
[x
] = prevline
[x
];
478 REPEAT(line
[x
] = colour2
)
481 REPEAT(CVAL2(input
, line
[x
]))
483 case 8: /* Bicolour */
499 case 0xd: /* White */
500 REPEAT(line
[x
] = 0xffff)
502 case 0xe: /* Black */
506 unimpl("bitmap opcode 0x%x\n", opcode
);
514 /* 3 byte bitmap decompress */
516 bitmap_decompress3(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
518 uint8
*end
= input
+ size
;
519 uint8
*prevline
= NULL
;
520 int opcode
, count
, offset
, isfillormix
;
521 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
523 uint8 colour1
[3] = {0, 0, 0}, colour2
[3] = {0, 0, 0};
524 uint8 mixmask
, mask
= 0;
525 uint8 mix
[3] = {0xff, 0xff, 0xff};
531 uint8
*line
= output
;
541 /* Handle different opcode forms */
556 count
|= CVAL(input
) << 8;
571 /* Handle strange cases for counts */
574 isfillormix
= ((opcode
== 2) || (opcode
== 7));
578 count
= CVAL(input
) + 1;
580 count
= CVAL(input
) + offset
;
582 else if (isfillormix
)
587 /* Read preliminary data */
591 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
594 case 8: /* Bicolour */
595 colour1
[0] = CVAL(input
);
596 colour1
[1] = CVAL(input
);
597 colour1
[2] = CVAL(input
);
599 colour2
[0] = CVAL(input
);
600 colour2
[1] = CVAL(input
);
601 colour2
[2] = CVAL(input
);
603 case 6: /* SetMix/Mix */
604 case 7: /* SetMix/FillOrMix */
605 mix
[0] = CVAL(input
);
606 mix
[1] = CVAL(input
);
607 mix
[2] = CVAL(input
);
610 case 9: /* FillOrMix_1 */
615 case 0x0a: /* FillOrMix_2 */
645 line
= output
+ height
* (width
* 3);
647 line
= output
+ y
* (width
* 3);
655 if (prevline
== NULL
)
657 line
[x
* 3] = mix
[0];
658 line
[x
* 3 + 1] = mix
[1];
659 line
[x
* 3 + 2] = mix
[2];
664 prevline
[x
* 3] ^ mix
[0];
666 prevline
[x
* 3 + 1] ^ mix
[1];
668 prevline
[x
* 3 + 2] ^ mix
[2];
674 if (prevline
== NULL
)
687 line
[x
* 3] = prevline
[x
* 3];
688 line
[x
* 3 + 1] = prevline
[x
* 3 + 1];
689 line
[x
* 3 + 2] = prevline
[x
* 3 + 2];
694 if (prevline
== NULL
)
698 line
[x
* 3] = mix
[0];
699 line
[x
* 3 + 1] = mix
[1];
700 line
[x
* 3 + 2] = mix
[2];
708 prevline
[x
* 3] ^ mix
[0];
710 prevline
[x
* 3 + 1] ^ mix
[1];
712 prevline
[x
* 3 + 2] ^ mix
[2];
716 case 2: /* Fill or Mix */
717 if (prevline
== NULL
)
724 line
[x
* 3] = mix
[0];
725 line
[x
* 3 + 1] = mix
[1];
726 line
[x
* 3 + 2] = mix
[2];
744 prevline
[x
* 3] ^ mix
[0];
746 prevline
[x
* 3 + 1] ^ mix
[1];
748 prevline
[x
* 3 + 2] ^ mix
[2];
765 line
[x
* 3] = colour2
[0];
766 line
[x
* 3 + 1] = colour2
[1];
767 line
[x
* 3 + 2] = colour2
[2];
773 line
[x
* 3] = CVAL(input
);
774 line
[x
* 3 + 1] = CVAL(input
);
775 line
[x
* 3 + 2] = CVAL(input
);
778 case 8: /* Bicolour */
783 line
[x
* 3] = colour2
[0];
784 line
[x
* 3 + 1] = colour2
[1];
785 line
[x
* 3 + 2] = colour2
[2];
790 line
[x
* 3] = colour1
[0];
791 line
[x
* 3 + 1] = colour1
[1];
792 line
[x
* 3 + 2] = colour1
[2];
798 case 0xd: /* White */
802 line
[x
* 3 + 1] = 0xff;
803 line
[x
* 3 + 2] = 0xff;
806 case 0xe: /* Black */
815 unimpl("bitmap opcode 0x%x\n", opcode
);
826 cvalx(uint8
**input
, int Bpp
)
829 memcpy(&rv
, *input
, Bpp
);
835 setli(uint8
*input
, int offset
, uint32 value
, int Bpp
)
837 input
+= offset
* Bpp
;
838 memcpy(input
, &value
, Bpp
);
842 getli(uint8
*input
, int offset
, int Bpp
)
845 input
+= offset
* Bpp
;
846 memcpy(&rv
, input
, Bpp
);
851 bitmap_decompressx(uint8
*output
, int width
, int height
, uint8
*input
, int size
, int Bpp
)
853 uint8
*end
= input
+ size
;
854 uint8
*prevline
= NULL
;
855 int opcode
, count
, offset
, isfillormix
;
856 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
858 uint32 colour1
= 0, colour2
= 0;
859 uint8 mixmask
, mask
= 0;
860 uint32 mix
= 0xffffffff;
866 uint8
*line
= output
;
877 /* Handle different opcode forms */
893 count
|= CVAL(input
) << 8;
897 count
= (opcode
< 0xb) ? 8 : 1;
909 /* Handle strange cases for counts */
912 isfillormix
= ((opcode
== 2) || (opcode
== 7));
917 count
= CVAL(input
) + 1;
919 count
= CVAL(input
) + offset
;
921 else if (isfillormix
)
927 /* Read preliminary data */
931 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
934 case 8: /* Bicolour */
935 colour1
= cvalx(&input
, Bpp
);
937 colour2
= cvalx(&input
, Bpp
);
939 case 6: /* SetMix/Mix */
940 case 7: /* SetMix/FillOrMix */
941 mix
= cvalx(&input
, Bpp
);
944 case 9: /* FillOrMix_1 */
949 case 0x0a: /* FillOrMix_2 */
983 line
= output
+ height
* width
* Bpp
;
985 line
= output
+ y
* width
* Bpp
;
994 if (prevline
== NULL
)
995 setli(line
, x
, mix
, Bpp
);
998 getli(prevline
, x
, Bpp
) ^ mix
, Bpp
);
1005 if (prevline
== NULL
)
1007 REPEAT(setli(line
, x
, 0, Bpp
))}
1011 (line
, x
, getli(prevline
, x
, Bpp
), Bpp
));
1016 if (prevline
== NULL
)
1018 REPEAT(setli(line
, x
, mix
, Bpp
));
1023 (line
, x
, getli(prevline
, x
, Bpp
) ^ mix
,
1028 case 2: /* Fill or Mix */
1029 if (prevline
== NULL
)
1031 REPEAT(MASK_UPDATE();
1032 if (mask
& mixmask
) setli(line
, x
, mix
, Bpp
);
1034 setli(line
, x
, 0, Bpp
););
1038 REPEAT(MASK_UPDATE();
1040 setli(line
, x
, getli(prevline
, x
, Bpp
) ^ mix
,
1043 setli(line
, x
, getli(prevline
, x
, Bpp
),
1048 case 3: /* Colour */
1049 REPEAT(setli(line
, x
, colour2
, Bpp
));
1053 REPEAT(setli(line
, x
, cvalx(&input
, Bpp
), Bpp
));
1056 case 8: /* Bicolour */
1057 REPEAT(if (bicolour
)
1059 setli(line
, x
, colour2
, Bpp
); bicolour
= False
;}
1062 setli(line
, x
, colour1
, Bpp
); bicolour
= True
;
1067 case 0xd: /* White */
1068 REPEAT(setli(line
, x
, 0xffffffff, Bpp
));
1071 case 0xe: /* Black */
1072 REPEAT(setli(line
, x
, 0, Bpp
));
1076 unimpl("bitmap opcode 0x%x\n", opcode
);
1087 /* main decompress function */
1089 bitmap_decompress(uint8
* output
, int width
, int height
, uint8
* input
, int size
, int Bpp
)
1091 #ifdef BITMAP_SPEED_OVER_SIZE
1096 rv
= bitmap_decompress1(output
, width
, height
, input
, size
);
1099 rv
= bitmap_decompress2(output
, width
, height
, input
, size
);
1102 rv
= bitmap_decompress3(output
, width
, height
, input
, size
);
1107 rv
= bitmap_decompressx(output
, width
, height
, input
, size
, Bpp
);