@@ -1870,6 +1870,43 @@ sendExtClientCutTextNotify(rfbClient *client)
18701870 return ret ;
18711871}
18721872
1873+ /**
1874+ * Due to bugs, many servers (including most versions of LibVNCServer) can't
1875+ * properly handle zlib streams created by compress() function of zlib library.
1876+ *
1877+ * Primary bug is that these servers don't expect inflate() to return Z_STREAM_END
1878+ * which is the case for (correct) streams created by compress().
1879+ *
1880+ * So this function creates a compatible stream, for which inflate() returns Z_OK.
1881+ * This is how some clients create zlib streams, unintentionally avoiding the bug.
1882+ */
1883+ static int
1884+ CompressClipData (Bytef * dest , uLongf * destLen , Bytef * source , uLong sourceLen )
1885+ {
1886+ int ret ;
1887+ z_stream * zs = (z_stream * )malloc (sizeof (z_stream ));
1888+ memset (zs , 0 , sizeof (z_stream ));
1889+
1890+ zs -> zfree = Z_NULL ;
1891+ zs -> zalloc = Z_NULL ;
1892+ zs -> opaque = Z_NULL ;
1893+ ret = deflateInit (zs , Z_DEFAULT_COMPRESSION );
1894+ if (ret == Z_OK ) {
1895+ zs -> avail_in = sourceLen ;
1896+ zs -> next_in = source ;
1897+ zs -> avail_out = * destLen ;
1898+ zs -> next_out = dest ;
1899+
1900+ do {
1901+ // Using Z_SYNC_FLUSH instead of Z_FINISH is the key here.
1902+ ret = deflate (zs , Z_SYNC_FLUSH );
1903+ } while (ret >= 0 && zs -> avail_in > 0 );
1904+
1905+ * destLen = zs -> total_out ;
1906+ deflateEnd (zs );
1907+ }
1908+ return ret ;
1909+ }
18731910
18741911/*
18751912 * sendExtClientCutTextProvide
@@ -1880,20 +1917,21 @@ static rfbBool
18801917sendExtClientCutTextProvide (rfbClient * client , char * data , int len )
18811918{
18821919 rfbClientCutTextMsg cct = {0 , };
1920+ int sentLen = len + 1 ; /* Sent data is null terminated*/
18831921 const uint32_t be_flags = rfbClientSwap32IfLE (rfbExtendedClipboard_Provide
18841922 | rfbExtendedClipboard_Text ); /*text and provide*/
1885- const uint32_t be_size = rfbClientSwap32IfLE (len );
1886- const size_t sz_to_compressed = sizeof (be_size ) + len ; /*size, data*/
1887- uLong csz = compressBound (sz_to_compressed + 1 ); /*tricky, some server need extar byte to flush data*/
1923+ const uint32_t be_size = rfbClientSwap32IfLE (sentLen );
1924+ const size_t sz_to_compressed = sizeof (be_size ) + sentLen ; /*size, data*/
1925+ uLong csz = compressBound (sz_to_compressed );
18881926
1889- unsigned char * buf = malloc (sz_to_compressed + 1 ); /*tricky, some server need extra byte to flush data*/
1927+ unsigned char * buf = malloc (sz_to_compressed );
18901928 if (!buf ) {
18911929 rfbClientLog ("sendExtClientCutTextProvide. alloc buf failed\n" );
18921930 return FALSE;
18931931 }
18941932 memcpy (buf , & be_size , sizeof (be_size ));
18951933 memcpy (buf + sizeof (be_size ), data , len );
1896- buf [sz_to_compressed ] = 0 ;
1934+ buf [sz_to_compressed - 1 ] = 0 ; /* Null terminate sent data */
18971935
18981936 unsigned char * cbuf = malloc (sizeof (be_flags ) + csz ); /*flag, compressed*/
18991937 if (!cbuf ) {
@@ -1902,7 +1940,7 @@ sendExtClientCutTextProvide(rfbClient *client, char* data, int len)
19021940 return FALSE;
19031941 }
19041942 memcpy (cbuf , & be_flags , sizeof (be_flags ));
1905- if (compress (cbuf + sizeof (be_flags ), & csz , buf , sz_to_compressed + 1 ) != Z_OK ) {
1943+ if (CompressClipData (cbuf + sizeof (be_flags ), & csz , buf , sz_to_compressed ) != Z_OK ) {
19061944 rfbClientLog ("sendExtClientCutTextProvide: compress cbuf failed\n" );
19071945 free (buf );
19081946 free (cbuf );
0 commit comments