LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ultra.c
Go to the documentation of this file.
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