1 /*
2 * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
3 * Copyright (C) 2003 Sun Microsystems, Inc.
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 #include "zrleoutstream.h"
22 #include <stdlib.h>
23
24 #define ZRLE_IN_BUFFER_SIZE 16384
25 #define ZRLE_OUT_BUFFER_SIZE 1024
26 #undef ZRLE_DEBUG
27
zrleBufferAlloc(zrleBuffer * buffer,int size)28 static rfbBool zrleBufferAlloc(zrleBuffer *buffer, int size)
29 {
30 buffer->ptr = buffer->start = malloc(size);
31 if (buffer->start == NULL) {
32 buffer->end = NULL;
33 return FALSE;
34 }
35
36 buffer->end = buffer->start + size;
37
38 return TRUE;
39 }
40
zrleBufferFree(zrleBuffer * buffer)41 static void zrleBufferFree(zrleBuffer *buffer)
42 {
43 if (buffer->start)
44 free(buffer->start);
45 buffer->start = buffer->ptr = buffer->end = NULL;
46 }
47
zrleBufferGrow(zrleBuffer * buffer,int size)48 static rfbBool zrleBufferGrow(zrleBuffer *buffer, int size)
49 {
50 int offset;
51
52 size += buffer->end - buffer->start;
53 offset = ZRLE_BUFFER_LENGTH (buffer);
54
55 buffer->start = realloc(buffer->start, size);
56 if (!buffer->start) {
57 return FALSE;
58 }
59
60 buffer->end = buffer->start + size;
61 buffer->ptr = buffer->start + offset;
62
63 return TRUE;
64 }
65
zrleOutStreamNew(void)66 zrleOutStream *zrleOutStreamNew(void)
67 {
68 zrleOutStream *os;
69
70 os = malloc(sizeof(zrleOutStream));
71 if (os == NULL)
72 return NULL;
73
74 if (!zrleBufferAlloc(&os->in, ZRLE_IN_BUFFER_SIZE)) {
75 free(os);
76 return NULL;
77 }
78
79 if (!zrleBufferAlloc(&os->out, ZRLE_OUT_BUFFER_SIZE)) {
80 zrleBufferFree(&os->in);
81 free(os);
82 return NULL;
83 }
84
85 os->zs.zalloc = Z_NULL;
86 os->zs.zfree = Z_NULL;
87 os->zs.opaque = Z_NULL;
88 if (deflateInit(&os->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
89 zrleBufferFree(&os->in);
90 free(os);
91 return NULL;
92 }
93
94 return os;
95 }
96
zrleOutStreamFree(zrleOutStream * os)97 void zrleOutStreamFree (zrleOutStream *os)
98 {
99 deflateEnd(&os->zs);
100 zrleBufferFree(&os->in);
101 zrleBufferFree(&os->out);
102 free(os);
103 }
104
zrleOutStreamFlush(zrleOutStream * os)105 rfbBool zrleOutStreamFlush(zrleOutStream *os)
106 {
107 os->zs.next_in = os->in.start;
108 os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
109
110 #ifdef ZRLE_DEBUG
111 rfbLog("zrleOutStreamFlush: avail_in %d\n", os->zs.avail_in);
112 #endif
113
114 while (os->zs.avail_in != 0) {
115 do {
116 int ret;
117
118 if (os->out.ptr >= os->out.end &&
119 !zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
120 rfbLog("zrleOutStreamFlush: failed to grow output buffer\n");
121 return FALSE;
122 }
123
124 os->zs.next_out = os->out.ptr;
125 os->zs.avail_out = os->out.end - os->out.ptr;
126
127 #ifdef ZRLE_DEBUG
128 rfbLog("zrleOutStreamFlush: calling deflate, avail_in %d, avail_out %d\n",
129 os->zs.avail_in, os->zs.avail_out);
130 #endif
131
132 if ((ret = deflate(&os->zs, Z_SYNC_FLUSH)) != Z_OK) {
133 rfbLog("zrleOutStreamFlush: deflate failed with error code %d\n", ret);
134 return FALSE;
135 }
136
137 #ifdef ZRLE_DEBUG
138 rfbLog("zrleOutStreamFlush: after deflate: %d bytes\n",
139 os->zs.next_out - os->out.ptr);
140 #endif
141
142 os->out.ptr = os->zs.next_out;
143 } while (os->zs.avail_out == 0);
144 }
145
146 os->in.ptr = os->in.start;
147
148 return TRUE;
149 }
150
zrleOutStreamOverrun(zrleOutStream * os,int size)151 static int zrleOutStreamOverrun(zrleOutStream *os,
152 int size)
153 {
154 #ifdef ZRLE_DEBUG
155 rfbLog("zrleOutStreamOverrun\n");
156 #endif
157
158 while (os->in.end - os->in.ptr < size && os->in.ptr > os->in.start) {
159 os->zs.next_in = os->in.start;
160 os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
161
162 do {
163 int ret;
164
165 if (os->out.ptr >= os->out.end &&
166 !zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
167 rfbLog("zrleOutStreamOverrun: failed to grow output buffer\n");
168 return FALSE;
169 }
170
171 os->zs.next_out = os->out.ptr;
172 os->zs.avail_out = os->out.end - os->out.ptr;
173
174 #ifdef ZRLE_DEBUG
175 rfbLog("zrleOutStreamOverrun: calling deflate, avail_in %d, avail_out %d\n",
176 os->zs.avail_in, os->zs.avail_out);
177 #endif
178
179 if ((ret = deflate(&os->zs, 0)) != Z_OK) {
180 rfbLog("zrleOutStreamOverrun: deflate failed with error code %d\n", ret);
181 return 0;
182 }
183
184 #ifdef ZRLE_DEBUG
185 rfbLog("zrleOutStreamOverrun: after deflate: %d bytes\n",
186 os->zs.next_out - os->out.ptr);
187 #endif
188
189 os->out.ptr = os->zs.next_out;
190 } while (os->zs.avail_out == 0);
191
192 /* output buffer not full */
193
194 if (os->zs.avail_in == 0) {
195 os->in.ptr = os->in.start;
196 } else {
197 /* but didn't consume all the data? try shifting what's left to the
198 * start of the buffer.
199 */
200 rfbLog("zrleOutStreamOverrun: out buf not full, but in data not consumed\n");
201 memmove(os->in.start, os->zs.next_in, os->in.ptr - os->zs.next_in);
202 os->in.ptr -= os->zs.next_in - os->in.start;
203 }
204 }
205
206 if (size > os->in.end - os->in.ptr)
207 size = os->in.end - os->in.ptr;
208
209 return size;
210 }
211
zrleOutStreamCheck(zrleOutStream * os,int size)212 static int zrleOutStreamCheck(zrleOutStream *os, int size)
213 {
214 if (os->in.ptr + size > os->in.end) {
215 return zrleOutStreamOverrun(os, size);
216 }
217 return size;
218 }
219
zrleOutStreamWriteBytes(zrleOutStream * os,const zrle_U8 * data,int length)220 void zrleOutStreamWriteBytes(zrleOutStream *os,
221 const zrle_U8 *data,
222 int length)
223 {
224 const zrle_U8* dataEnd = data + length;
225 while (data < dataEnd) {
226 int n = zrleOutStreamCheck(os, dataEnd - data);
227 memcpy(os->in.ptr, data, n);
228 os->in.ptr += n;
229 data += n;
230 }
231 }
232
zrleOutStreamWriteU8(zrleOutStream * os,zrle_U8 u)233 void zrleOutStreamWriteU8(zrleOutStream *os, zrle_U8 u)
234 {
235 zrleOutStreamCheck(os, 1);
236 *os->in.ptr++ = u;
237 }
238
zrleOutStreamWriteOpaque8(zrleOutStream * os,zrle_U8 u)239 void zrleOutStreamWriteOpaque8(zrleOutStream *os, zrle_U8 u)
240 {
241 zrleOutStreamCheck(os, 1);
242 *os->in.ptr++ = u;
243 }
244
zrleOutStreamWriteOpaque16(zrleOutStream * os,zrle_U16 u)245 void zrleOutStreamWriteOpaque16 (zrleOutStream *os, zrle_U16 u)
246 {
247 zrleOutStreamCheck(os, 2);
248 *os->in.ptr++ = ((zrle_U8*)&u)[0];
249 *os->in.ptr++ = ((zrle_U8*)&u)[1];
250 }
251
zrleOutStreamWriteOpaque32(zrleOutStream * os,zrle_U32 u)252 void zrleOutStreamWriteOpaque32 (zrleOutStream *os, zrle_U32 u)
253 {
254 zrleOutStreamCheck(os, 4);
255 *os->in.ptr++ = ((zrle_U8*)&u)[0];
256 *os->in.ptr++ = ((zrle_U8*)&u)[1];
257 *os->in.ptr++ = ((zrle_U8*)&u)[2];
258 *os->in.ptr++ = ((zrle_U8*)&u)[3];
259 }
260
zrleOutStreamWriteOpaque24A(zrleOutStream * os,zrle_U32 u)261 void zrleOutStreamWriteOpaque24A(zrleOutStream *os, zrle_U32 u)
262 {
263 zrleOutStreamCheck(os, 3);
264 *os->in.ptr++ = ((zrle_U8*)&u)[0];
265 *os->in.ptr++ = ((zrle_U8*)&u)[1];
266 *os->in.ptr++ = ((zrle_U8*)&u)[2];
267 }
268
zrleOutStreamWriteOpaque24B(zrleOutStream * os,zrle_U32 u)269 void zrleOutStreamWriteOpaque24B(zrleOutStream *os, zrle_U32 u)
270 {
271 zrleOutStreamCheck(os, 3);
272 *os->in.ptr++ = ((zrle_U8*)&u)[1];
273 *os->in.ptr++ = ((zrle_U8*)&u)[2];
274 *os->in.ptr++ = ((zrle_U8*)&u)[3];
275 }
276