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 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 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 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 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 97 void zrleOutStreamFree (zrleOutStream *os) 98 { 99 deflateEnd(&os->zs); 100 zrleBufferFree(&os->in); 101 zrleBufferFree(&os->out); 102 free(os); 103 } 104 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 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 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 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 233 void zrleOutStreamWriteU8(zrleOutStream *os, zrle_U8 u) 234 { 235 zrleOutStreamCheck(os, 1); 236 *os->in.ptr++ = u; 237 } 238 239 void zrleOutStreamWriteOpaque8(zrleOutStream *os, zrle_U8 u) 240 { 241 zrleOutStreamCheck(os, 1); 242 *os->in.ptr++ = u; 243 } 244 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 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 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 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