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