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 along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
, *line
= NULL
;
77 int opcode
, count
, offset
, isfillormix
, x
= width
;
78 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
80 uint8 colour1
= 0, colour2
= 0;
81 uint8 mixmask
, mask
= 0;
90 /* Handle different opcode forms */
105 count
|= CVAL(input
) << 8;
109 count
= (opcode
< 0xb) ? 8 : 1;
119 /* Handle strange cases for counts */
122 isfillormix
= ((opcode
== 2) || (opcode
== 7));
126 count
= CVAL(input
) + 1;
128 count
= CVAL(input
) + offset
;
130 else if (isfillormix
)
135 /* Read preliminary data */
139 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
142 case 8: /* Bicolour */
143 colour1
= CVAL(input
);
145 colour2
= CVAL(input
);
147 case 6: /* SetMix/Mix */
148 case 7: /* SetMix/FillOrMix */
152 case 9: /* FillOrMix_1 */
157 case 0x0a: /* FillOrMix_2 */
175 line
= output
+ height
* width
;
182 if (prevline
== NULL
)
185 line
[x
] = prevline
[x
] ^ mix
;
190 if (prevline
== NULL
)
196 REPEAT(line
[x
] = prevline
[x
])
200 if (prevline
== NULL
)
202 REPEAT(line
[x
] = mix
)
206 REPEAT(line
[x
] = prevline
[x
] ^ mix
)
209 case 2: /* Fill or Mix */
210 if (prevline
== NULL
)
227 line
[x
] = prevline
[x
] ^ mix
;
229 line
[x
] = prevline
[x
];
234 REPEAT(line
[x
] = colour2
)
237 REPEAT(line
[x
] = CVAL(input
))
239 case 8: /* Bicolour */
250 bicolour
= True
; count
++;
254 case 0xd: /* White */
255 REPEAT(line
[x
] = 0xff)
257 case 0xe: /* Black */
261 unimpl("bitmap opcode 0x%x\n", opcode
);
269 /* 2 byte bitmap decompress */
271 bitmap_decompress2(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
273 uint8
*end
= input
+ size
;
274 uint16
*prevline
= NULL
, *line
= NULL
;
275 int opcode
, count
, offset
, isfillormix
, x
= width
;
276 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
278 uint16 colour1
= 0, colour2
= 0;
279 uint8 mixmask
, mask
= 0;
288 /* Handle different opcode forms */
303 count
|= CVAL(input
) << 8;
307 count
= (opcode
< 0xb) ? 8 : 1;
317 /* Handle strange cases for counts */
320 isfillormix
= ((opcode
== 2) || (opcode
== 7));
324 count
= CVAL(input
) + 1;
326 count
= CVAL(input
) + offset
;
328 else if (isfillormix
)
333 /* Read preliminary data */
337 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
340 case 8: /* Bicolour */
341 CVAL2(input
, colour1
);
343 CVAL2(input
, colour2
);
345 case 6: /* SetMix/Mix */
346 case 7: /* SetMix/FillOrMix */
350 case 9: /* FillOrMix_1 */
355 case 0x0a: /* FillOrMix_2 */
373 line
= ((uint16
*) output
) + height
* width
;
380 if (prevline
== NULL
)
383 line
[x
] = prevline
[x
] ^ mix
;
388 if (prevline
== NULL
)
394 REPEAT(line
[x
] = prevline
[x
])
398 if (prevline
== NULL
)
400 REPEAT(line
[x
] = mix
)
404 REPEAT(line
[x
] = prevline
[x
] ^ mix
)
407 case 2: /* Fill or Mix */
408 if (prevline
== NULL
)
425 line
[x
] = prevline
[x
] ^ mix
;
427 line
[x
] = prevline
[x
];
432 REPEAT(line
[x
] = colour2
)
435 REPEAT(CVAL2(input
, line
[x
]))
437 case 8: /* Bicolour */
453 case 0xd: /* White */
454 REPEAT(line
[x
] = 0xffff)
456 case 0xe: /* Black */
460 unimpl("bitmap opcode 0x%x\n", opcode
);
468 /* 3 byte bitmap decompress */
470 bitmap_decompress3(uint8
* output
, int width
, int height
, uint8
* input
, int size
)
472 uint8
*end
= input
+ size
;
473 uint8
*prevline
= NULL
, *line
= NULL
;
474 int opcode
, count
, offset
, isfillormix
, x
= width
;
475 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
477 uint8 colour1
[3] = {0, 0, 0}, colour2
[3] = {0, 0, 0};
478 uint8 mixmask
, mask
= 0;
479 uint8 mix
[3] = {0xff, 0xff, 0xff};
487 /* Handle different opcode forms */
502 count
|= CVAL(input
) << 8;
517 /* Handle strange cases for counts */
520 isfillormix
= ((opcode
== 2) || (opcode
== 7));
524 count
= CVAL(input
) + 1;
526 count
= CVAL(input
) + offset
;
528 else if (isfillormix
)
533 /* Read preliminary data */
537 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
540 case 8: /* Bicolour */
541 colour1
[0] = CVAL(input
);
542 colour1
[1] = CVAL(input
);
543 colour1
[2] = CVAL(input
);
545 colour2
[0] = CVAL(input
);
546 colour2
[1] = CVAL(input
);
547 colour2
[2] = CVAL(input
);
549 case 6: /* SetMix/Mix */
550 case 7: /* SetMix/FillOrMix */
551 mix
[0] = CVAL(input
);
552 mix
[1] = CVAL(input
);
553 mix
[2] = CVAL(input
);
556 case 9: /* FillOrMix_1 */
561 case 0x0a: /* FillOrMix_2 */
579 line
= output
+ height
* (width
* 3);
586 if (prevline
== NULL
)
588 line
[x
* 3] = mix
[0];
589 line
[x
* 3 + 1] = mix
[1];
590 line
[x
* 3 + 2] = mix
[2];
595 prevline
[x
* 3] ^ mix
[0];
597 prevline
[x
* 3 + 1] ^ mix
[1];
599 prevline
[x
* 3 + 2] ^ mix
[2];
605 if (prevline
== NULL
)
618 line
[x
* 3] = prevline
[x
* 3];
619 line
[x
* 3 + 1] = prevline
[x
* 3 + 1];
620 line
[x
* 3 + 2] = prevline
[x
* 3 + 2];
625 if (prevline
== NULL
)
629 line
[x
* 3] = mix
[0];
630 line
[x
* 3 + 1] = mix
[1];
631 line
[x
* 3 + 2] = mix
[2];
639 prevline
[x
* 3] ^ mix
[0];
641 prevline
[x
* 3 + 1] ^ mix
[1];
643 prevline
[x
* 3 + 2] ^ mix
[2];
647 case 2: /* Fill or Mix */
648 if (prevline
== NULL
)
655 line
[x
* 3] = mix
[0];
656 line
[x
* 3 + 1] = mix
[1];
657 line
[x
* 3 + 2] = mix
[2];
675 prevline
[x
* 3] ^ mix
[0];
677 prevline
[x
* 3 + 1] ^ mix
[1];
679 prevline
[x
* 3 + 2] ^ mix
[2];
696 line
[x
* 3] = colour2
[0];
697 line
[x
* 3 + 1] = colour2
[1];
698 line
[x
* 3 + 2] = colour2
[2];
704 line
[x
* 3] = CVAL(input
);
705 line
[x
* 3 + 1] = CVAL(input
);
706 line
[x
* 3 + 2] = CVAL(input
);
709 case 8: /* Bicolour */
714 line
[x
* 3] = colour2
[0];
715 line
[x
* 3 + 1] = colour2
[1];
716 line
[x
* 3 + 2] = colour2
[2];
721 line
[x
* 3] = colour1
[0];
722 line
[x
* 3 + 1] = colour1
[1];
723 line
[x
* 3 + 2] = colour1
[2];
729 case 0xd: /* White */
733 line
[x
* 3 + 1] = 0xff;
734 line
[x
* 3 + 2] = 0xff;
737 case 0xe: /* Black */
746 unimpl("bitmap opcode 0x%x\n", opcode
);
757 cvalx(uint8
**input
, int Bpp
)
760 memcpy(&rv
, *input
, Bpp
);
766 setli(uint8
*input
, int offset
, uint32 value
, int Bpp
)
768 input
+= offset
* Bpp
;
769 memcpy(input
, &value
, Bpp
);
773 getli(uint8
*input
, int offset
, int Bpp
)
776 input
+= offset
* Bpp
;
777 memcpy(&rv
, input
, Bpp
);
782 bitmap_decompressx(uint8
*output
, int width
, int height
, uint8
*input
, int size
, int Bpp
)
784 uint8
*end
= input
+ size
;
785 uint8
*prevline
= NULL
, *line
= NULL
;
786 int opcode
, count
, offset
, isfillormix
, x
= width
;
787 int lastopcode
= -1, insertmix
= False
, bicolour
= False
;
789 uint32 colour1
= 0, colour2
= 0;
790 uint8 mixmask
, mask
= 0;
791 uint32 mix
= 0xffffffff;
800 /* Handle different opcode forms */
816 count
|= CVAL(input
) << 8;
820 count
= (opcode
< 0xb) ? 8 : 1;
832 /* Handle strange cases for counts */
835 isfillormix
= ((opcode
== 2) || (opcode
== 7));
840 count
= CVAL(input
) + 1;
842 count
= CVAL(input
) + offset
;
844 else if (isfillormix
)
850 /* Read preliminary data */
854 if ((lastopcode
== opcode
) && !((x
== width
) && (prevline
== NULL
)))
857 case 8: /* Bicolour */
858 colour1
= cvalx(&input
, Bpp
);
860 colour2
= cvalx(&input
, Bpp
);
862 case 6: /* SetMix/Mix */
863 case 7: /* SetMix/FillOrMix */
864 mix
= cvalx(&input
, Bpp
);
867 case 9: /* FillOrMix_1 */
872 case 0x0a: /* FillOrMix_2 */
895 line
= output
+ height
* width
* Bpp
;
903 if (prevline
== NULL
)
904 setli(line
, x
, mix
, Bpp
);
907 getli(prevline
, x
, Bpp
) ^ mix
, Bpp
);
914 if (prevline
== NULL
)
916 REPEAT(setli(line
, x
, 0, Bpp
))}
920 (line
, x
, getli(prevline
, x
, Bpp
), Bpp
));
925 if (prevline
== NULL
)
927 REPEAT(setli(line
, x
, mix
, Bpp
));
932 (line
, x
, getli(prevline
, x
, Bpp
) ^ mix
,
937 case 2: /* Fill or Mix */
938 if (prevline
== NULL
)
940 REPEAT(MASK_UPDATE();
941 if (mask
& mixmask
) setli(line
, x
, mix
, Bpp
);
943 setli(line
, x
, 0, Bpp
););
947 REPEAT(MASK_UPDATE();
949 setli(line
, x
, getli(prevline
, x
, Bpp
) ^ mix
,
952 setli(line
, x
, getli(prevline
, x
, Bpp
),
958 REPEAT(setli(line
, x
, colour2
, Bpp
));
962 REPEAT(setli(line
, x
, cvalx(&input
, Bpp
), Bpp
));
965 case 8: /* Bicolour */
968 setli(line
, x
, colour2
, Bpp
); bicolour
= False
;}
971 setli(line
, x
, colour1
, Bpp
); bicolour
= True
;
976 case 0xd: /* White */
977 REPEAT(setli(line
, x
, 0xffffffff, Bpp
));
980 case 0xe: /* Black */
981 REPEAT(setli(line
, x
, 0, Bpp
));
985 unimpl("bitmap opcode 0x%x\n", opcode
);
996 /* main decompress function */
998 bitmap_decompress(uint8
* output
, int width
, int height
, uint8
* input
, int size
, int Bpp
)
1000 #ifdef BITMAP_SPEED_OVER_SIZE
1005 rv
= bitmap_decompress1(output
, width
, height
, input
, size
);
1008 rv
= bitmap_decompress2(output
, width
, height
, input
, size
);
1011 rv
= bitmap_decompress3(output
, width
, height
, input
, size
);
1016 rv
= bitmap_decompressx(output
, width
, height
, input
, size
, Bpp
);