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 28static 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 41static void zrleBufferFree(zrleBuffer *buffer) 42{ 43 if (buffer->start) 44 free(buffer->start); 45 buffer->start = buffer->ptr = buffer->end = NULL; 46} 47 48static 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 66zrleOutStream *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 97void zrleOutStreamFree (zrleOutStream *os) 98{ 99 deflateEnd(&os->zs); 100 zrleBufferFree(&os->in); 101 zrleBufferFree(&os->out); 102 free(os); 103} 104 105rfbBool 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 151static 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 212static 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 220void 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 233void zrleOutStreamWriteU8(zrleOutStream *os, zrle_U8 u) 234{ 235 zrleOutStreamCheck(os, 1); 236 *os->in.ptr++ = u; 237} 238 239void zrleOutStreamWriteOpaque8(zrleOutStream *os, zrle_U8 u) 240{ 241 zrleOutStreamCheck(os, 1); 242 *os->in.ptr++ = u; 243} 244 245void 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 252void 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 261void 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 269void 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