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 /*
     22  * ultrazip.c - handle ultrazip encoding.
     23  *
     24  * This file shouldn't be compiled directly.  It is included multiple times by
     25  * rfbproto.c, each time with a different definition of the macro BPP.  For
     26  * each value of BPP, this file defines a function which handles an zlib
     27  * encoded rectangle with BPP bits per pixel.
     28  */
     29 
     30 #define HandleUltraZipBPP CONCAT2E(HandleUltraZip,BPP)
     31 #define HandleUltraBPP CONCAT2E(HandleUltra,BPP)
     32 #define CARDBPP CONCAT3E(uint,BPP,_t)
     33 
     34 static rfbBool
     35 HandleUltraBPP (rfbClient* client, int rx, int ry, int rw, int rh)
     36 {
     37   rfbZlibHeader hdr;
     38   int toRead=0;
     39   int inflateResult=0;
     40   lzo_uint uncompressedBytes = (( rw * rh ) * ( BPP / 8 ));
     41 
     42   if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
     43     return FALSE;
     44 
     45   toRead = rfbClientSwap32IfLE(hdr.nBytes);
     46   if (toRead==0) return TRUE;
     47 
     48   if (uncompressedBytes==0)
     49   {
     50       rfbClientLog("ultra error: rectangle has 0 uncomressed bytes ((%dw * %dh) * (%d / 8))\n", rw, rh, BPP);
     51       return FALSE;
     52   }
     53 
     54   /* First make sure we have a large enough raw buffer to hold the
     55    * decompressed data.  In practice, with a fixed BPP, fixed frame
     56    * buffer size and the first update containing the entire frame
     57    * buffer, this buffer allocation should only happen once, on the
     58    * first update.
     59    */
     60   if ( client->raw_buffer_size < (int)uncompressedBytes) {
     61     if ( client->raw_buffer != NULL ) {
     62       free( client->raw_buffer );
     63     }
     64     client->raw_buffer_size = uncompressedBytes;
     65     /* buffer needs to be aligned on 4-byte boundaries */
     66     if ((client->raw_buffer_size % 4)!=0)
     67       client->raw_buffer_size += (4-(client->raw_buffer_size % 4));
     68     client->raw_buffer = (char*) malloc( client->raw_buffer_size );
     69   }
     70 
     71   /* allocate enough space to store the incoming compressed packet */
     72   if ( client->ultra_buffer_size < toRead ) {
     73     if ( client->ultra_buffer != NULL ) {
     74       free( client->ultra_buffer );
     75     }
     76     client->ultra_buffer_size = toRead;
     77     /* buffer needs to be aligned on 4-byte boundaries */
     78     if ((client->ultra_buffer_size % 4)!=0)
     79       client->ultra_buffer_size += (4-(client->ultra_buffer_size % 4));
     80     client->ultra_buffer = (char*) malloc( client->ultra_buffer_size );
     81   }
     82 
     83   /* Fill the buffer, obtaining data from the server. */
     84   if (!ReadFromRFBServer(client, client->ultra_buffer, toRead))
     85       return FALSE;
     86 
     87   /* uncompress the data */
     88   uncompressedBytes = client->raw_buffer_size;
     89   inflateResult = lzo1x_decompress(
     90               (lzo_byte *)client->ultra_buffer, toRead,
     91               (lzo_byte *)client->raw_buffer, (lzo_uintp) &uncompressedBytes,
     92               NULL);
     93 
     94 
     95   if ((rw * rh * (BPP / 8)) != uncompressedBytes)
     96       rfbClientLog("Ultra decompressed too little (%d < %d)", (rw * rh * (BPP / 8)), uncompressedBytes);
     97 
     98   /* Put the uncompressed contents of the update on the screen. */
     99   if ( inflateResult == LZO_E_OK )
    100   {
    101     CopyRectangle(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh);
    102   }
    103   else
    104   {
    105     rfbClientLog("ultra decompress returned error: %d\n",
    106             inflateResult);
    107     return FALSE;
    108   }
    109   return TRUE;
    110 }
    111 
    112 
    113 /* UltraZip is like rre in that it is composed of subrects */
    114 static rfbBool
    115 HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
    116 {
    117   rfbZlibHeader hdr;
    118   int i=0;
    119   int toRead=0;
    120   int inflateResult=0;
    121   unsigned char *ptr=NULL;
    122   lzo_uint uncompressedBytes = ry + (rw * 65535);
    123   unsigned int numCacheRects = rx;
    124 
    125   if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
    126     return FALSE;
    127 
    128   toRead = rfbClientSwap32IfLE(hdr.nBytes);
    129 
    130   if (toRead==0) return TRUE;
    131 
    132   if (uncompressedBytes==0)
    133   {
    134       rfbClientLog("ultrazip error: rectangle has 0 uncomressed bytes (%dy + (%dw * 65535)) (%d rectangles)\n", ry, rw, rx);
    135       return FALSE;
    136   }
    137 
    138   /* First make sure we have a large enough raw buffer to hold the
    139    * decompressed data.  In practice, with a fixed BPP, fixed frame
    140    * buffer size and the first update containing the entire frame
    141    * buffer, this buffer allocation should only happen once, on the
    142    * first update.
    143    */
    144   if ( client->raw_buffer_size < (int)(uncompressedBytes + 500)) {
    145     if ( client->raw_buffer != NULL ) {
    146       free( client->raw_buffer );
    147     }
    148     client->raw_buffer_size = uncompressedBytes + 500;
    149     /* buffer needs to be aligned on 4-byte boundaries */
    150     if ((client->raw_buffer_size % 4)!=0)
    151       client->raw_buffer_size += (4-(client->raw_buffer_size % 4));
    152     client->raw_buffer = (char*) malloc( client->raw_buffer_size );
    153   }
    154 
    155 
    156   /* allocate enough space to store the incoming compressed packet */
    157   if ( client->ultra_buffer_size < toRead ) {
    158     if ( client->ultra_buffer != NULL ) {
    159       free( client->ultra_buffer );
    160     }
    161     client->ultra_buffer_size = toRead;
    162     client->ultra_buffer = (char*) malloc( client->ultra_buffer_size );
    163   }
    164 
    165   /* Fill the buffer, obtaining data from the server. */
    166   if (!ReadFromRFBServer(client, client->ultra_buffer, toRead))
    167       return FALSE;
    168 
    169   /* uncompress the data */
    170   uncompressedBytes = client->raw_buffer_size;
    171   inflateResult = lzo1x_decompress(
    172               (lzo_byte *)client->ultra_buffer, toRead,
    173               (lzo_byte *)client->raw_buffer, &uncompressedBytes, NULL);
    174   if ( inflateResult != LZO_E_OK )
    175   {
    176     rfbClientLog("ultra decompress returned error: %d\n",
    177             inflateResult);
    178     return FALSE;
    179   }
    180 
    181   /* Put the uncompressed contents of the update on the screen. */
    182   ptr = (unsigned char *)client->raw_buffer;
    183   for (i=0; i<numCacheRects; i++)
    184   {
    185     unsigned short sx, sy, sw, sh;
    186     unsigned int se;
    187 
    188     memcpy((char *)&sx, ptr, 2); ptr += 2;
    189     memcpy((char *)&sy, ptr, 2); ptr += 2;
    190     memcpy((char *)&sw, ptr, 2); ptr += 2;
    191     memcpy((char *)&sh, ptr, 2); ptr += 2;
    192     memcpy((char *)&se, ptr, 4); ptr += 4;
    193 
    194     sx = rfbClientSwap16IfLE(sx);
    195     sy = rfbClientSwap16IfLE(sy);
    196     sw = rfbClientSwap16IfLE(sw);
    197     sh = rfbClientSwap16IfLE(sh);
    198     se = rfbClientSwap32IfLE(se);
    199 
    200     if (se == rfbEncodingRaw)
    201     {
    202         CopyRectangle(client, (unsigned char *)ptr, sx, sy, sw, sh);
    203         ptr += ((sw * sh) * (BPP / 8));
    204     }
    205   }
    206 
    207   return TRUE;
    208 }
    209 
    210 #undef CARDBPP
    211