| /* |
| * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. |
| * Copyright (C) 2003 Sun Microsystems, Inc. |
| * |
| * This is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This software is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this software; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| * USA. |
| */ |
| |
| /* |
| * zrle.c |
| * |
| * Routines to implement Zlib Run-length Encoding (ZRLE). |
| */ |
| |
| #include "rfb/rfb.h" |
| #include "private.h" |
| #include "zrleoutstream.h" |
| |
| |
| #define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf) \ |
| { char *fbptr = (cl->scaledScreen->frameBuffer \ |
| + (cl->scaledScreen->paddedWidthInBytes * ty) \ |
| + (tx * (cl->scaledScreen->bitsPerPixel / 8))); \ |
| \ |
| (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\ |
| &cl->format, fbptr, (char*)buf, \ |
| cl->scaledScreen->paddedWidthInBytes, tw, th); } |
| |
| #define EXTRA_ARGS , rfbClientPtr cl |
| |
| #define ENDIAN_LITTLE 0 |
| #define ENDIAN_BIG 1 |
| #define ENDIAN_NO 2 |
| #define BPP 8 |
| #define ZYWRLE_ENDIAN ENDIAN_NO |
| #include <zrleencodetemplate.c> |
| #undef BPP |
| #define BPP 15 |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
| #include <zrleencodetemplate.c> |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_BIG |
| #include <zrleencodetemplate.c> |
| #undef BPP |
| #define BPP 16 |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
| #include <zrleencodetemplate.c> |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_BIG |
| #include <zrleencodetemplate.c> |
| #undef BPP |
| #define BPP 32 |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
| #include <zrleencodetemplate.c> |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_BIG |
| #include <zrleencodetemplate.c> |
| #define CPIXEL 24A |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
| #include <zrleencodetemplate.c> |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_BIG |
| #include <zrleencodetemplate.c> |
| #undef CPIXEL |
| #define CPIXEL 24B |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
| #include <zrleencodetemplate.c> |
| #undef ZYWRLE_ENDIAN |
| #define ZYWRLE_ENDIAN ENDIAN_BIG |
| #include <zrleencodetemplate.c> |
| #undef CPIXEL |
| #undef BPP |
| |
| |
| /* |
| * zrleBeforeBuf contains pixel data in the client's format. It must be at |
| * least one pixel bigger than the largest tile of pixel data, since the |
| * ZRLE encoding algorithm writes to the position one past the end of the pixel |
| * data. |
| */ |
| |
| |
| /* |
| * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding. |
| */ |
| |
| rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h) |
| { |
| zrleOutStream* zos; |
| rfbFramebufferUpdateRectHeader rect; |
| rfbZRLEHeader hdr; |
| int i; |
| char *zrleBeforeBuf; |
| |
| if (cl->zrleBeforeBuf == NULL) { |
| cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4); |
| } |
| zrleBeforeBuf = cl->zrleBeforeBuf; |
| |
| if (cl->preferredEncoding == rfbEncodingZYWRLE) { |
| if (cl->tightQualityLevel < 0) { |
| cl->zywrleLevel = 1; |
| } else if (cl->tightQualityLevel < 3) { |
| cl->zywrleLevel = 3; |
| } else if (cl->tightQualityLevel < 6) { |
| cl->zywrleLevel = 2; |
| } else { |
| cl->zywrleLevel = 1; |
| } |
| } else |
| cl->zywrleLevel = 0; |
| |
| if (!cl->zrleData) |
| cl->zrleData = zrleOutStreamNew(); |
| zos = cl->zrleData; |
| zos->in.ptr = zos->in.start; |
| zos->out.ptr = zos->out.start; |
| |
| switch (cl->format.bitsPerPixel) { |
| |
| case 8: |
| zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| break; |
| |
| case 16: |
| if (cl->format.greenMax > 0x1F) { |
| if (cl->format.bigEndian) |
| zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| else |
| zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| } else { |
| if (cl->format.bigEndian) |
| zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| else |
| zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| } |
| break; |
| |
| case 32: { |
| rfbBool fitsInLS3Bytes |
| = ((cl->format.redMax << cl->format.redShift) < (1<<24) && |
| (cl->format.greenMax << cl->format.greenShift) < (1<<24) && |
| (cl->format.blueMax << cl->format.blueShift) < (1<<24)); |
| |
| rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 && |
| cl->format.greenShift > 7 && |
| cl->format.blueShift > 7); |
| |
| if ((fitsInLS3Bytes && !cl->format.bigEndian) || |
| (fitsInMS3Bytes && cl->format.bigEndian)) { |
| if (cl->format.bigEndian) |
| zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| else |
| zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| } |
| else if ((fitsInLS3Bytes && cl->format.bigEndian) || |
| (fitsInMS3Bytes && !cl->format.bigEndian)) { |
| if (cl->format.bigEndian) |
| zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| else |
| zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| } |
| else { |
| if (cl->format.bigEndian) |
| zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| else |
| zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
| } |
| } |
| break; |
| } |
| |
| rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out), |
| + w * (cl->format.bitsPerPixel / 8) * h); |
| |
| if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader |
| > UPDATE_BUF_SIZE) |
| { |
| if (!rfbSendUpdateBuf(cl)) |
| return FALSE; |
| } |
| |
| rect.r.x = Swap16IfLE(x); |
| rect.r.y = Swap16IfLE(y); |
| rect.r.w = Swap16IfLE(w); |
| rect.r.h = Swap16IfLE(h); |
| rect.encoding = Swap32IfLE(cl->preferredEncoding); |
| |
| memcpy(cl->updateBuf+cl->ublen, (char *)&rect, |
| sz_rfbFramebufferUpdateRectHeader); |
| cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
| |
| hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out)); |
| |
| memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader); |
| cl->ublen += sz_rfbZRLEHeader; |
| |
| /* copy into updateBuf and send from there. Maybe should send directly? */ |
| |
| for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) { |
| |
| int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; |
| |
| if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) { |
| bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i; |
| } |
| |
| memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy); |
| |
| cl->ublen += bytesToCopy; |
| i += bytesToCopy; |
| |
| if (cl->ublen == UPDATE_BUF_SIZE) { |
| if (!rfbSendUpdateBuf(cl)) |
| return FALSE; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| |
| void rfbFreeZrleData(rfbClientPtr cl) |
| { |
| if (cl->zrleData) { |
| zrleOutStreamFree(cl->zrleData); |
| } |
| cl->zrleData = NULL; |
| |
| if (cl->zrleBeforeBuf) { |
| free(cl->zrleBeforeBuf); |
| } |
| cl->zrleBeforeBuf = NULL; |
| |
| if (cl->paletteHelper) { |
| free(cl->paletteHelper); |
| } |
| cl->paletteHelper = NULL; |
| } |
| |