2 * Copyright (C) 2005 Johannes E. Schindelin. All Rights Reserved.
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 #ifdef LIBVNCSERVER_HAVE_LIBZ
23 * zrle.c - handle zrle encoding.
25 * This file shouldn't be compiled directly. It is included multiple times by
26 * rfbproto.c, each time with a different definition of the macro BPP. For
27 * each value of BPP, this file defines a function which handles an zrle
28 * encoded rectangle with BPP bits per pixel.
35 #if !defined(UNCOMP) || UNCOMP==0
36 #define HandleZRLE CONCAT2E(HandleZRLE,REALBPP)
37 #define HandleZRLETile CONCAT2E(HandleZRLETile,REALBPP)
39 #define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Down)
40 #define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Down)
42 #define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Up)
43 #define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Up)
45 #define CARDBPP CONCAT3E(uint,BPP,_t)
46 #define CARDREALBPP CONCAT3E(uint,REALBPP,_t)
48 #define ENDIAN_LITTLE 0
51 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
53 #if ZYWRLE_ENDIAN == ENDIAN_LITTLE
55 #elif ZYWRLE_ENDIAN == ENDIAN_BIG
60 #define __RFB_CONCAT3E(a,b,c) CONCAT3E(a,b,c)
61 #define __RFB_CONCAT2E(a,b) CONCAT2E(a,b)
65 #define CPIXEL REALBPP
67 #define CPIXEL CONCAT2E(REALBPP,Down)
69 #define CPIXEL CONCAT2E(REALBPP,Up)
72 #define PIXEL_T __RFB_CONCAT3E(uint,BPP,_t)
74 #define ZYWRLE_DECODE 1
75 #include "zywrletemplate.c"
79 static int HandleZRLETile(rfbClient
* client
,
80 uint8_t* buffer
,size_t buffer_length
,
81 int x
,int y
,int w
,int h
);
84 HandleZRLE (rfbClient
* client
, int rx
, int ry
, int rw
, int rh
)
90 int min_buffer_size
= rw
* rh
* (REALBPP
/ 8) * 2;
92 /* First make sure we have a large enough raw buffer to hold the
93 * decompressed data. In practice, with a fixed REALBPP, fixed frame
94 * buffer size and the first update containing the entire frame
95 * buffer, this buffer allocation should only happen once, on the
98 if ( client
->raw_buffer_size
< min_buffer_size
) {
100 if ( client
->raw_buffer
!= NULL
) {
102 free( client
->raw_buffer
);
106 client
->raw_buffer_size
= min_buffer_size
;
107 client
->raw_buffer
= (char*) malloc( client
->raw_buffer_size
);
111 if (!ReadFromRFBServer(client
, (char *)&header
, sz_rfbZRLEHeader
))
114 remaining
= rfbClientSwap32IfLE(header
.length
);
116 /* Need to initialize the decompressor state. */
117 client
->decompStream
.next_in
= ( Bytef
* )client
->buffer
;
118 client
->decompStream
.avail_in
= 0;
119 client
->decompStream
.next_out
= ( Bytef
* )client
->raw_buffer
;
120 client
->decompStream
.avail_out
= client
->raw_buffer_size
;
121 client
->decompStream
.data_type
= Z_BINARY
;
123 /* Initialize the decompression stream structures on the first invocation. */
124 if ( client
->decompStreamInited
== FALSE
) {
126 inflateResult
= inflateInit( &client
->decompStream
);
128 if ( inflateResult
!= Z_OK
) {
130 "inflateInit returned error: %d, msg: %s\n",
132 client
->decompStream
.msg
);
136 client
->decompStreamInited
= TRUE
;
140 inflateResult
= Z_OK
;
142 /* Process buffer full of data until no more to process, or
143 * some type of inflater error, or Z_STREAM_END.
145 while (( remaining
> 0 ) &&
146 ( inflateResult
== Z_OK
)) {
148 if ( remaining
> RFB_BUFFER_SIZE
) {
149 toRead
= RFB_BUFFER_SIZE
;
155 /* Fill the buffer, obtaining data from the server. */
156 if (!ReadFromRFBServer(client
, client
->buffer
,toRead
))
159 client
->decompStream
.next_in
= ( Bytef
* )client
->buffer
;
160 client
->decompStream
.avail_in
= toRead
;
162 /* Need to uncompress buffer full. */
163 inflateResult
= inflate( &client
->decompStream
, Z_SYNC_FLUSH
);
165 /* We never supply a dictionary for compression. */
166 if ( inflateResult
== Z_NEED_DICT
) {
167 rfbClientLog("zlib inflate needs a dictionary!\n");
170 if ( inflateResult
< 0 ) {
172 "zlib inflate returned error: %d, msg: %s\n",
174 client
->decompStream
.msg
);
178 /* Result buffer allocated to be at least large enough. We should
179 * never run out of space!
181 if (( client
->decompStream
.avail_in
> 0 ) &&
182 ( client
->decompStream
.avail_out
<= 0 )) {
183 rfbClientLog("zlib inflate ran out of space!\n");
189 } /* while ( remaining > 0 ) */
191 if ( inflateResult
== Z_OK
) {
192 void* buf
=client
->raw_buffer
;
195 remaining
= client
->raw_buffer_size
-client
->decompStream
.avail_out
;
197 for(j
=0; j
<rh
; j
+=rfbZRLETileHeight
)
198 for(i
=0; i
<rw
; i
+=rfbZRLETileWidth
) {
199 int subWidth
=(i
+rfbZRLETileWidth
>rw
)?rw
-i
:rfbZRLETileWidth
;
200 int subHeight
=(j
+rfbZRLETileHeight
>rh
)?rh
-j
:rfbZRLETileHeight
;
201 int result
=HandleZRLETile(client
,buf
,remaining
,rx
+i
,ry
+j
,subWidth
,subHeight
);
204 rfbClientLog("ZRLE decoding failed (%d)\n",result
);
216 "zlib inflate returned error: %d, msg: %s\n",
218 client
->decompStream
.msg
);
226 #if REALBPP!=BPP && defined(UNCOMP) && UNCOMP!=0
228 #define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)>>UNCOMP)
230 #define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)<<(-(UNCOMP)))
233 #define UncompressCPixel(pointer) (*(CARDBPP*)pointer)
236 static int HandleZRLETile(rfbClient
* client
,
237 uint8_t* buffer
,size_t buffer_length
,
238 int x
,int y
,int w
,int h
) {
239 uint8_t* buffer_copy
= buffer
;
240 uint8_t* buffer_end
= buffer
+buffer_length
;
243 uint8_t zywrle_level
= (client
->appData
.qualityLevel
& 0x80) ?
244 0 : (3 - client
->appData
.qualityLevel
/ 3);
253 if( type
== 0 ) /* raw */
255 if( zywrle_level
> 0 ){
256 CARDBPP
* pFrame
= (CARDBPP
*)client
->frameBuffer
+ y
*client
->width
+x
;
258 client
->appData
.qualityLevel
|= 0x80;
259 ret
= HandleZRLETile(client
, buffer
, buffer_end
-buffer
, x
, y
, w
, h
);
260 client
->appData
.qualityLevel
&= 0x7F;
264 ZYWRLE_SYNTHESIZE( pFrame
, pFrame
, w
, h
, client
->width
, zywrle_level
, (int*)client
->zlib_buffer
);
272 if(1+w
*h
*REALBPP
/8>buffer_length
) {
273 rfbClientLog("expected %d bytes, got only %d (%dx%d)\n",1+w
*h
*REALBPP
/8,buffer_length
,w
,h
);
277 for(j
=y
*client
->width
; j
<(y
+h
)*client
->width
; j
+=client
->width
)
278 for(i
=x
; i
<x
+w
; i
++,buffer
+=REALBPP
/8)
279 ((CARDBPP
*)client
->frameBuffer
)[j
+i
] = UncompressCPixel(buffer
);
281 CopyRectangle(client
, buffer
, x
, y
, w
, h
);
282 buffer
+=w
*h
*REALBPP
/8;
285 else if( type
== 1 ) /* solid */
287 CARDBPP color
= UncompressCPixel(buffer
);
289 if(1+REALBPP
/8>buffer_length
)
292 FillRectangle(client
, x
, y
, w
, h
, color
);
297 else if( (type
>= 2)&&(type
<= 127) ) /* packed Palette */
301 bpp
=(type
>4?(type
>16?8:4):(type
>2?2:1)),
305 if(1+type
*REALBPP
/8+((w
+divider
-1)/divider
)*h
>buffer_length
)
309 for(i
=0; i
<type
; i
++,buffer
+=REALBPP
/8)
310 palette
[i
] = UncompressCPixel(buffer
);
312 /* read palettized pixels */
313 for(j
=y
*client
->width
; j
<(y
+h
)*client
->width
; j
+=client
->width
) {
314 for(i
=x
,shift
=8-bpp
; i
<x
+w
; i
++) {
315 ((CARDBPP
*)client
->frameBuffer
)[j
+i
] = palette
[((*buffer
)>>shift
)&mask
];
327 /* case 17 ... 127: not used, but valid */
328 else if( type
== 128 ) /* plain RLE */
334 if(buffer
+REALBPP
/8+1>buffer_end
)
336 color
= UncompressCPixel(buffer
);
338 /* read run length */
340 while(*buffer
==0xff) {
341 if(buffer
+1>=buffer_end
)
348 while(j
<h
&& length
>0) {
349 ((CARDBPP
*)client
->frameBuffer
)[(y
+j
)*client
->width
+x
+i
] = color
;
358 rfbClientLog("Warning: possible ZRLE corruption\n");
362 else if( type
== 129 ) /* unused */
366 else if( type
>= 130 ) /* palette RLE */
368 CARDBPP palette
[128];
371 if(2+(type
-128)*REALBPP
/8>buffer_length
)
375 for(i
=0; i
<type
-128; i
++,buffer
+=REALBPP
/8)
376 palette
[i
] = UncompressCPixel(buffer
);
377 /* read palettized pixels */
382 if(buffer
>=buffer_end
)
384 color
= palette
[(*buffer
)&0x7f];
387 if(buffer
+1>=buffer_end
)
390 /* read run length */
391 while(*buffer
==0xff) {
392 if(buffer
+1>=buffer_end
)
400 while(j
<h
&& length
>0) {
401 ((CARDBPP
*)client
->frameBuffer
)[(y
+j
)*client
->width
+x
+i
] = color
;
410 rfbClientLog("Warning: possible ZRLE corruption\n");
415 return buffer
-buffer_copy
;
421 #undef HandleZRLETile
422 #undef UncompressCPixel