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
HandleUltraBPP(rfbClient * client,int rx,int ry,int rw,int rh)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
HandleUltraZipBPP(rfbClient * client,int rx,int ry,int rw,int rh)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