correctly leave fullscreen mode when connection is lost
[presencevnc] / libvnc / libvncclient / ultra.c
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   int 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 < 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   int 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 < (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, (lzo_uintp) &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