Home | History | Annotate | Download | only in libvncclient
      1 /*
      2  *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
      3  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
      4  *
      5  *  This is free software; you can redistribute it and/or modify
      6  *  it under the terms of the GNU General Public License as published by
      7  *  the Free Software Foundation; either version 2 of the License, or
      8  *  (at your option) any later version.
      9  *
     10  *  This software is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  *  GNU General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU General Public License
     16  *  along with this software; if not, write to the Free Software
     17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
     18  *  USA.
     19  */
     20 
     21 #ifdef LIBVNCSERVER_HAVE_LIBZ
     22 
     23 /*
     24  * zlib.c - handle zlib encoding.
     25  *
     26  * This file shouldn't be compiled directly.  It is included multiple times by
     27  * rfbproto.c, each time with a different definition of the macro BPP.  For
     28  * each value of BPP, this file defines a function which handles an zlib
     29  * encoded rectangle with BPP bits per pixel.
     30  */
     31 
     32 #define HandleZlibBPP CONCAT2E(HandleZlib,BPP)
     33 #define CARDBPP CONCAT3E(uint,BPP,_t)
     34 
     35 static rfbBool
     36 HandleZlibBPP (rfbClient* client, int rx, int ry, int rw, int rh)
     37 {
     38   rfbZlibHeader hdr;
     39   int remaining;
     40   int inflateResult;
     41   int toRead;
     42 
     43   /* First make sure we have a large enough raw buffer to hold the
     44    * decompressed data.  In practice, with a fixed BPP, fixed frame
     45    * buffer size and the first update containing the entire frame
     46    * buffer, this buffer allocation should only happen once, on the
     47    * first update.
     48    */
     49   if ( client->raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) {
     50 
     51     if ( client->raw_buffer != NULL ) {
     52 
     53       free( client->raw_buffer );
     54 
     55     }
     56 
     57     client->raw_buffer_size = (( rw * rh ) * ( BPP / 8 ));
     58     client->raw_buffer = (char*) malloc( client->raw_buffer_size );
     59 
     60   }
     61 
     62   if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
     63     return FALSE;
     64 
     65   remaining = rfbClientSwap32IfLE(hdr.nBytes);
     66 
     67   /* Need to initialize the decompressor state. */
     68   client->decompStream.next_in   = ( Bytef * )client->buffer;
     69   client->decompStream.avail_in  = 0;
     70   client->decompStream.next_out  = ( Bytef * )client->raw_buffer;
     71   client->decompStream.avail_out = client->raw_buffer_size;
     72   client->decompStream.data_type = Z_BINARY;
     73 
     74   /* Initialize the decompression stream structures on the first invocation. */
     75   if ( client->decompStreamInited == FALSE ) {
     76 
     77     inflateResult = inflateInit( &client->decompStream );
     78 
     79     if ( inflateResult != Z_OK ) {
     80       rfbClientLog(
     81               "inflateInit returned error: %d, msg: %s\n",
     82               inflateResult,
     83               client->decompStream.msg);
     84       return FALSE;
     85     }
     86 
     87     client->decompStreamInited = TRUE;
     88 
     89   }
     90 
     91   inflateResult = Z_OK;
     92 
     93   /* Process buffer full of data until no more to process, or
     94    * some type of inflater error, or Z_STREAM_END.
     95    */
     96   while (( remaining > 0 ) &&
     97          ( inflateResult == Z_OK )) {
     98 
     99     if ( remaining > RFB_BUFFER_SIZE ) {
    100       toRead = RFB_BUFFER_SIZE;
    101     }
    102     else {
    103       toRead = remaining;
    104     }
    105 
    106     /* Fill the buffer, obtaining data from the server. */
    107     if (!ReadFromRFBServer(client, client->buffer,toRead))
    108       return FALSE;
    109 
    110     client->decompStream.next_in  = ( Bytef * )client->buffer;
    111     client->decompStream.avail_in = toRead;
    112 
    113     /* Need to uncompress buffer full. */
    114     inflateResult = inflate( &client->decompStream, Z_SYNC_FLUSH );
    115 
    116     /* We never supply a dictionary for compression. */
    117     if ( inflateResult == Z_NEED_DICT ) {
    118       rfbClientLog("zlib inflate needs a dictionary!\n");
    119       return FALSE;
    120     }
    121     if ( inflateResult < 0 ) {
    122       rfbClientLog(
    123               "zlib inflate returned error: %d, msg: %s\n",
    124               inflateResult,
    125               client->decompStream.msg);
    126       return FALSE;
    127     }
    128 
    129     /* Result buffer allocated to be at least large enough.  We should
    130      * never run out of space!
    131      */
    132     if (( client->decompStream.avail_in > 0 ) &&
    133         ( client->decompStream.avail_out <= 0 )) {
    134       rfbClientLog("zlib inflate ran out of space!\n");
    135       return FALSE;
    136     }
    137 
    138     remaining -= toRead;
    139 
    140   } /* while ( remaining > 0 ) */
    141 
    142   if ( inflateResult == Z_OK ) {
    143 
    144     /* Put the uncompressed contents of the update on the screen. */
    145     CopyRectangle(client, (uint8_t *)client->raw_buffer, rx, ry, rw, rh);
    146   }
    147   else {
    148 
    149     rfbClientLog(
    150             "zlib inflate returned error: %d, msg: %s\n",
    151             inflateResult,
    152             client->decompStream.msg);
    153     return FALSE;
    154 
    155   }
    156 
    157   return TRUE;
    158 }
    159 
    160 #undef CARDBPP
    161 
    162 #endif
    163