* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
-#include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
#include <rfb/PixelBuffer.h>
#include <rfb/CopyRectDecoder.h>
}
void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp,
- ModifiablePixelBuffer* pb)
+ const ConnParams& cp, rdr::OutStream* os)
{
- int srcX = is->readU16();
- int srcY = is->readU16();
+ os->copyBytes(is, 4);
+}
+
+void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb)
+{
+ rdr::MemInStream is(buffer, buflen);
+ int srcX = is.readU16();
+ int srcY = is.readU16();
pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
}
CopyRectDecoder();
virtual ~CopyRectDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb);
+ const ConnParams& cp, rdr::OutStream* os);
+ virtual void decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb);
};
}
#endif
#include <rfb/LogWriter.h>
#include <rdr/Exception.h>
+#include <rdr/MemOutStream.h>
using namespace rfb;
conn(conn)
{
memset(decoders, 0, sizeof(decoders));
+ bufferStream = new rdr::MemOutStream();
}
DecodeManager::~DecodeManager()
{
for (size_t i = 0; i < sizeof(decoders)/sizeof(decoders[0]); i++)
delete decoders[i];
+ delete bufferStream;
}
void DecodeManager::decodeRect(const Rect& r, int encoding,
throw rdr::Exception("Unknown encoding");
}
}
- decoders[encoding]->readRect(r, conn->getInStream(), conn->cp, pb);
+
+ bufferStream->clear();
+ decoders[encoding]->readRect(r, conn->getInStream(),
+ conn->cp, bufferStream);
+ decoders[encoding]->decodeRect(r, bufferStream->data(),
+ bufferStream->length(),
+ conn->cp, pb);
}
#include <rfb/encodings.h>
+namespace rdr { class MemOutStream; }
+
namespace rfb {
class CConnection;
class Decoder;
private:
CConnection *conn;
Decoder *decoders[encodingMax+1];
+ rdr::MemOutStream *bufferStream;
};
}
#ifndef __RFB_DECODER_H__
#define __RFB_DECODER_H__
-namespace rdr { class InStream; }
+namespace rdr {
+ class InStream;
+ class OutStream;
+}
namespace rfb {
class ConnParams;
Decoder();
virtual ~Decoder();
- // readRect() is the main interface that decodes the given rectangle
- // with data from the given InStream, onto the ModifiablePixelBuffer.
- // The PixelFormat of the PixelBuffer might not match the ConnParams
- // and it is up to the decoder to do any necessary conversion.
+ // These functions are the main interface to an individual decoder
+
+ // readRect() transfers data for the given rectangle from the
+ // InStream to the OutStream, possibly changing it along the way to
+ // make it easier to decode.
virtual void readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb)=0;
+ const ConnParams& cp, rdr::OutStream* os)=0;
+ // decodeRect() decodes the given rectangle with data from the
+ // given buffer, onto the ModifiablePixelBuffer. The PixelFormat of
+ // the PixelBuffer might not match the ConnParams and it is up to
+ // the decoder to do any necessary conversion.
+ virtual void decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb)=0;
static bool supported(int encoding);
static Decoder* createDecoder(int encoding);
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
+
#include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/HextileDecoder.h>
}
void HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb)
+ const ConnParams& cp, rdr::OutStream* os)
+{
+ Rect t;
+ size_t bytesPerPixel;
+
+ bytesPerPixel = cp.pf().bpp/8;
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
+
+ t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
+ rdr::U8 tileType;
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+
+ tileType = is->readU8();
+ os->writeU8(tileType);
+
+ if (tileType & hextileRaw) {
+ os->copyBytes(is, t.area() * bytesPerPixel);
+ continue;
+ }
+
+ if (tileType & hextileBgSpecified)
+ os->copyBytes(is, bytesPerPixel);
+
+ if (tileType & hextileFgSpecified)
+ os->copyBytes(is, bytesPerPixel);
+
+ if (tileType & hextileAnySubrects) {
+ rdr::U8 nSubrects;
+
+ nSubrects = is->readU8();
+ os->writeU8(nSubrects);
+
+ if (tileType & hextileSubrectsColoured)
+ os->copyBytes(is, nSubrects * (bytesPerPixel + 2));
+ else
+ os->copyBytes(is, nSubrects * 2);
+ }
+ }
+ }
+}
+
+void HextileDecoder::decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb)
{
+ rdr::MemInStream is(buffer, buflen);
const PixelFormat& pf = cp.pf();
- rdr::U8 buf[16 * 16 * 4 * pf.bpp/8];
switch (pf.bpp) {
- case 8: hextileDecode8 (r, is, (rdr::U8*) buf, pf, pb); break;
- case 16: hextileDecode16(r, is, (rdr::U16*)buf, pf, pb); break;
- case 32: hextileDecode32(r, is, (rdr::U32*)buf, pf, pb); break;
+ case 8: hextileDecode8 (r, &is, pf, pb); break;
+ case 16: hextileDecode16(r, &is, pf, pb); break;
+ case 32: hextileDecode32(r, &is, pf, pb); break;
}
}
HextileDecoder();
virtual ~HextileDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb);
+ const ConnParams& cp, rdr::OutStream* os);
+ virtual void decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb);
};
}
#endif
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
+
#include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/RREDecoder.h>
}
void RREDecoder::readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb)
+ const ConnParams& cp, rdr::OutStream* os)
+{
+ rdr::U32 numRects;
+
+ numRects = is->readU32();
+ os->writeU32(numRects);
+
+ os->copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8));
+}
+
+void RREDecoder::decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb)
{
+ rdr::MemInStream is(buffer, buflen);
const PixelFormat& pf = cp.pf();
switch (pf.bpp) {
- case 8: rreDecode8 (r, is, pf, pb); break;
- case 16: rreDecode16(r, is, pf, pb); break;
- case 32: rreDecode32(r, is, pf, pb); break;
+ case 8: rreDecode8 (r, &is, pf, pb); break;
+ case 16: rreDecode16(r, &is, pf, pb); break;
+ case 32: rreDecode32(r, &is, pf, pb); break;
}
}
RREDecoder();
virtual ~RREDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb);
+ const ConnParams& cp, rdr::OutStream* os);
+ virtual void decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb);
};
}
#endif
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
-#include <rdr/InStream.h>
+
+#include <assert.h>
+
+#include <rdr/OutStream.h>
#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/RawDecoder.h>
}
void RawDecoder::readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb)
+ const ConnParams& cp, rdr::OutStream* os)
{
- const PixelFormat& pf = cp.pf();
-
- rdr::U8 imageBuf[16384];
- const int maxPixels = sizeof(imageBuf) / (pf.bpp/8);
-
- int x = r.tl.x;
- int y = r.tl.y;
- int w = r.width();
- int h = r.height();
-
- while (h > 0) {
- int dx;
-
- dx = 0;
- while (dx < w) {
- int dw;
-
- dw = maxPixels;
- if (dx + dw > w)
- dw = w - dx;
-
- is->readBytes(imageBuf, dw * pf.bpp/8);
- pb->imageRect(pf, Rect(x+dx, y, x+dx+dw, y+1), imageBuf);
-
- dx += dw;
- }
+ os->copyBytes(is, r.area() * cp.pf().bpp/8);
+}
- y++;
- h--;
- }
+void RawDecoder::decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb)
+{
+ assert(buflen >= (size_t)r.area() * cp.pf().bpp/8);
+ pb->imageRect(cp.pf(), r, buffer);
}
RawDecoder();
virtual ~RawDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb);
+ const ConnParams& cp, rdr::OutStream* os);
+ virtual void decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb);
};
}
#endif
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright 2004-2005 Cendio AB.
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
+
+#include <assert.h>
+
#include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
#include <rfb/ConnParams.h>
+#include <rfb/Exception.h>
#include <rfb/PixelBuffer.h>
+#include <rfb/TightConstants.h>
#include <rfb/TightDecoder.h>
using namespace rfb;
-#define TIGHT_MAX_WIDTH 2048
+static const int TIGHT_MAX_WIDTH = 2048;
+static const int TIGHT_MIN_TO_COMPRESS = 12;
#define BPP 8
#include <rfb/tightDecode.h>
}
void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb)
+ const ConnParams& cp, rdr::OutStream* os)
+{
+ rdr::U8 comp_ctl;
+
+ comp_ctl = is->readU8();
+ os->writeU8(comp_ctl);
+
+ comp_ctl >>= 4;
+
+ // "Fill" compression type.
+ if (comp_ctl == tightFill) {
+ if (cp.pf().is888())
+ os->copyBytes(is, 3);
+ else
+ os->copyBytes(is, cp.pf().bpp/8);
+ return;
+ }
+
+ // "JPEG" compression type.
+ if (comp_ctl == tightJpeg) {
+ rdr::U32 len;
+
+ len = readCompact(is);
+ os->writeOpaque32(len);
+ os->copyBytes(is, len);
+ return;
+ }
+
+ // Quit on unsupported compression type.
+ if (comp_ctl > tightMaxSubencoding)
+ throw Exception("TightDecoder: bad subencoding value received");
+
+ // "Basic" compression type.
+
+ int palSize = 0;
+
+ if (r.width() > TIGHT_MAX_WIDTH)
+ throw Exception("TightDecoder: too large rectangle (%d pixels)", r.width());
+
+ // Possible palette
+ if ((comp_ctl & tightExplicitFilter) != 0) {
+ rdr::U8 filterId;
+
+ filterId = is->readU8();
+ os->writeU8(filterId);
+
+ switch (filterId) {
+ case tightFilterPalette:
+ palSize = is->readU8() + 1;
+ os->writeU8(palSize - 1);
+
+ if (cp.pf().is888())
+ os->copyBytes(is, palSize * 3);
+ else
+ os->copyBytes(is, palSize * cp.pf().bpp/8);
+ break;
+ case tightFilterGradient:
+ if (cp.pf().bpp == 8)
+ throw Exception("TightDecoder: invalid BPP for gradient filter");
+ break;
+ case tightFilterCopy:
+ break;
+ default:
+ throw Exception("TightDecoder: unknown filter code received");
+ }
+ }
+
+ size_t rowSize, dataSize;
+
+ if (palSize != 0) {
+ if (palSize <= 2)
+ rowSize = (r.width() + 7) / 8;
+ else
+ rowSize = r.width();
+ } else if (cp.pf().is888()) {
+ rowSize = r.width() * 3;
+ } else {
+ rowSize = r.width() * cp.pf().bpp/8;
+ }
+
+ dataSize = r.height() * rowSize;
+
+ if (dataSize < TIGHT_MIN_TO_COMPRESS)
+ os->copyBytes(is, dataSize);
+ else {
+ rdr::U32 len;
+
+ len = readCompact(is);
+ os->writeOpaque32(len);
+ os->copyBytes(is, len);
+ }
+}
+
+void TightDecoder::decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb)
{
- this->is = is;
- this->pb = pb;
- clientpf = pb->getPF();
- serverpf = cp.pf();
+ const rdr::U8* bufptr;
+ const PixelFormat& pf = cp.pf();
+
+ rdr::U8 comp_ctl;
+
+ bufptr = (const rdr::U8*)buffer;
+
+ assert(buflen >= 1);
+
+ comp_ctl = *bufptr;
+ bufptr += 1;
+ buflen -= 1;
+
+ // Flush zlib streams if we are told by the server to do so.
+ for (int i = 0; i < 4; i++) {
+ if (comp_ctl & 1) {
+ zis[i].reset();
+ }
+ comp_ctl >>= 1;
+ }
+
+ // "Fill" compression type.
+ if (comp_ctl == tightFill) {
+ if (pf.is888()) {
+ rdr::U8 pix[4];
+
+ assert(buflen >= 3);
+
+ pf.bufferFromRGB(pix, bufptr, 1);
+ pb->fillRect(pf, r, pix);
+ } else {
+ assert(buflen >= (size_t)pf.bpp/8);
+ pb->fillRect(pf, r, bufptr);
+ }
+ return;
+ }
+
+ // "JPEG" compression type.
+ if (comp_ctl == tightJpeg) {
+ rdr::U32 len;
+
+ int stride;
+ rdr::U8 *buf;
+
+ assert(buflen >= 4);
- if (clientpf.equal(serverpf)) {
- /* Decode directly into the framebuffer (fast path) */
+ memcpy(&len, bufptr, 4);
+ bufptr += 4;
+ buflen -= 4;
+
+ // We always use direct decoding with JPEG images
+ buf = pb->getBufferRW(r, &stride);
+ jd.decompress(bufptr, len, buf, stride, r, pb->getPF());
+ pb->commitBufferRW(r);
+ return;
+ }
+
+ // Quit on unsupported compression type.
+ assert(comp_ctl <= tightMaxSubencoding);
+
+ // "Basic" compression type.
+
+ int palSize = 0;
+ rdr::U8 palette[256 * 4];
+ bool useGradient = false;
+
+ if ((comp_ctl & tightExplicitFilter) != 0) {
+ rdr::U8 filterId;
+
+ assert(buflen >= 1);
+
+ filterId = *bufptr;
+ bufptr += 1;
+ buflen -= 1;
+
+ switch (filterId) {
+ case tightFilterPalette:
+ assert(buflen >= 1);
+
+ palSize = *bufptr + 1;
+ bufptr += 1;
+ buflen -= 1;
+
+ if (pf.is888()) {
+ rdr::U8 tightPalette[palSize * 3];
+
+ assert(buflen >= sizeof(tightPalette));
+
+ memcpy(tightPalette, bufptr, sizeof(tightPalette));
+ bufptr += sizeof(tightPalette);
+ buflen -= sizeof(tightPalette);
+
+ pf.bufferFromRGB(palette, tightPalette, palSize);
+ } else {
+ size_t len;
+
+ len = palSize * pf.bpp/8;
+
+ assert(buflen >= len);
+
+ memcpy(palette, bufptr, len);
+ bufptr += len;
+ buflen -= len;
+ }
+ break;
+ case tightFilterGradient:
+ useGradient = true;
+ break;
+ case tightFilterCopy:
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ // Determine if the data should be decompressed or just copied.
+ size_t rowSize, dataSize;
+ rdr::U8* netbuf;
+
+ netbuf = NULL;
+
+ if (palSize != 0) {
+ if (palSize <= 2)
+ rowSize = (r.width() + 7) / 8;
+ else
+ rowSize = r.width();
+ } else if (pf.is888()) {
+ rowSize = r.width() * 3;
+ } else {
+ rowSize = r.width() * pf.bpp/8;
+ }
+
+ dataSize = r.height() * rowSize;
+
+ if (dataSize < TIGHT_MIN_TO_COMPRESS)
+ assert(buflen >= dataSize);
+ else {
+ rdr::U32 len;
+ int streamId;
+ rdr::MemInStream* ms;
+
+ assert(buflen >= 4);
+
+ memcpy(&len, bufptr, 4);
+ bufptr += 4;
+ buflen -= 4;
+
+ assert(buflen >= len);
+
+ streamId = comp_ctl & 0x03;
+ ms = new rdr::MemInStream(bufptr, len);
+ zis[streamId].setUnderlying(ms, len);
+
+ // Allocate buffer and decompress the data
+ netbuf = new rdr::U8[dataSize];
+
+ zis[streamId].readBytes(netbuf, dataSize);
+ zis[streamId].reset();
+
+ delete ms;
+
+ bufptr = netbuf;
+ buflen = dataSize;
+ }
+
+ // Time to decode the actual data
+ bool directDecode;
+
+ rdr::U8* outbuf;
+ int stride;
+
+ if (pb->getPF().equal(pf)) {
+ // Decode directly into the framebuffer (fast path)
directDecode = true;
} else {
- /* Decode into an intermediate buffer and use pixel translation */
+ // Decode into an intermediate buffer and use pixel translation
directDecode = false;
}
- switch (serverpf.bpp) {
- case 8:
- tightDecode8 (r); break;
- case 16:
- tightDecode16(r); break;
- case 32:
- tightDecode32(r); break;
+ if (directDecode)
+ outbuf = pb->getBufferRW(r, &stride);
+ else {
+ outbuf = new rdr::U8[r.area() * pf.bpp/8];
+ stride = r.width();
}
+
+ if (palSize == 0) {
+ // Truecolor data
+ if (useGradient) {
+ if (pf.is888())
+ FilterGradient24(bufptr, pf, (rdr::U32*)outbuf, stride, r);
+ else {
+ switch (pf.bpp) {
+ case 8:
+ assert(false);
+ break;
+ case 16:
+ FilterGradient(bufptr, pf, (rdr::U16*)outbuf, stride, r);
+ break;
+ case 32:
+ FilterGradient(bufptr, pf, (rdr::U32*)outbuf, stride, r);
+ break;
+ }
+ }
+ } else {
+ // Copy
+ rdr::U8* ptr = outbuf;
+ const rdr::U8* srcPtr = bufptr;
+ int w = r.width();
+ int h = r.height();
+ if (pf.is888()) {
+ while (h > 0) {
+ pf.bufferFromRGB(ptr, srcPtr, w);
+ ptr += stride * pf.bpp/8;
+ srcPtr += w * 3;
+ h--;
+ }
+ } else {
+ while (h > 0) {
+ memcpy(ptr, srcPtr, w * pf.bpp/8);
+ ptr += stride * pf.bpp/8;
+ srcPtr += w * pf.bpp/8;
+ h--;
+ }
+ }
+ }
+ } else {
+ // Indexed color
+ switch (pf.bpp) {
+ case 8:
+ FilterPalette((const rdr::U8*)palette, palSize,
+ bufptr, (rdr::U8*)outbuf, stride, r);
+ break;
+ case 16:
+ FilterPalette((const rdr::U16*)palette, palSize,
+ bufptr, (rdr::U16*)outbuf, stride, r);
+ break;
+ case 32:
+ FilterPalette((const rdr::U32*)palette, palSize,
+ bufptr, (rdr::U32*)outbuf, stride, r);
+ break;
+ }
+ }
+
+ if (directDecode)
+ pb->commitBufferRW(r);
+ else {
+ pb->imageRect(pf, r, outbuf);
+ delete [] outbuf;
+ }
+
+ delete [] netbuf;
}
rdr::U32 TightDecoder::readCompact(rdr::InStream* is)
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
TightDecoder();
virtual ~TightDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb);
+ const ConnParams& cp, rdr::OutStream* os);
+ virtual void decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb);
private:
rdr::U32 readCompact(rdr::InStream* is);
- void tightDecode8(const Rect& r);
- void tightDecode16(const Rect& r);
- void tightDecode32(const Rect& r);
+ void FilterGradient24(const rdr::U8* inbuf, const PixelFormat& pf,
+ rdr::U32* outbuf, int stride, const Rect& r);
- void DecompressJpegRect8(const Rect& r);
- void DecompressJpegRect16(const Rect& r);
- void DecompressJpegRect32(const Rect& r);
+ void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf,
+ rdr::U16* outbuf, int stride, const Rect& r);
+ void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf,
+ rdr::U32* outbuf, int stride, const Rect& r);
- void FilterGradient8(rdr::U8 *netbuf, rdr::U8* buf, int stride,
- const Rect& r);
- void FilterGradient16(rdr::U8 *netbuf, rdr::U16* buf, int stride,
- const Rect& r);
- void FilterGradient24(rdr::U8 *netbuf, rdr::U32* buf, int stride,
- const Rect& r);
- void FilterGradient32(rdr::U8 *netbuf, rdr::U32* buf, int stride,
- const Rect& r);
+ void FilterPalette(const rdr::U8* palette, int palSize,
+ const rdr::U8* inbuf, rdr::U8* outbuf,
+ int stride, const Rect& r);
+ void FilterPalette(const rdr::U16* palette, int palSize,
+ const rdr::U8* inbuf, rdr::U16* outbuf,
+ int stride, const Rect& r);
+ void FilterPalette(const rdr::U32* palette, int palSize,
+ const rdr::U8* inbuf, rdr::U32* outbuf,
+ int stride, const Rect& r);
- void directFillRect8(const Rect& r, Pixel pix);
- void directFillRect16(const Rect& r, Pixel pix);
- void directFillRect32(const Rect& r, Pixel pix);
-
- ModifiablePixelBuffer* pb;
- rdr::InStream* is;
+ private:
rdr::ZlibInStream zis[4];
JpegDecompressor jd;
- PixelFormat clientpf;
- PixelFormat serverpf;
- bool directDecode;
};
}
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
+
#include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/ZRLEDecoder.h>
}
void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb)
+ const ConnParams& cp, rdr::OutStream* os)
+{
+ rdr::U32 len;
+
+ len = is->readU32();
+ os->writeU32(len);
+ os->copyBytes(is, len);
+}
+
+void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb)
{
+ rdr::MemInStream is(buffer, buflen);
const rfb::PixelFormat& pf = cp.pf();
rdr::U8* buf[64 * 64 * 4 * pf.bpp/8];
switch (pf.bpp) {
- case 8: zrleDecode8 (r, is, &zis, (rdr::U8*) buf, pf, pb); break;
- case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, pf, pb); break;
+ case 8: zrleDecode8 (r, &is, &zis, (rdr::U8*) buf, pf, pb); break;
+ case 16: zrleDecode16(r, &is, &zis, (rdr::U16*)buf, pf, pb); break;
case 32:
{
Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
(fitsInMS3Bytes && pf.isBigEndian()))
{
- zrleDecode24A(r, is, &zis, (rdr::U32*)buf, pf, pb);
+ zrleDecode24A(r, &is, &zis, (rdr::U32*)buf, pf, pb);
}
else if ((fitsInLS3Bytes && pf.isBigEndian()) ||
(fitsInMS3Bytes && pf.isLittleEndian()))
{
- zrleDecode24B(r, is, &zis, (rdr::U32*)buf, pf, pb);
+ zrleDecode24B(r, &is, &zis, (rdr::U32*)buf, pf, pb);
}
else
{
- zrleDecode32(r, is, &zis, (rdr::U32*)buf, pf, pb);
+ zrleDecode32(r, &is, &zis, (rdr::U32*)buf, pf, pb);
}
break;
}
ZRLEDecoder();
virtual ~ZRLEDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, ModifiablePixelBuffer* pb);
+ const ConnParams& cp, rdr::OutStream* os);
+ virtual void decodeRect(const Rect& r, const void* buffer,
+ size_t buflen, const ConnParams& cp,
+ ModifiablePixelBuffer* pb);
private:
rdr::ZlibInStream zis;
};
#define READ_PIXEL CONCAT2E(readOpaque,BPP)
#define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP)
-void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf,
- const PixelFormat& pf, ModifiablePixelBuffer* pb)
+static void HEXTILE_DECODE (const Rect& r, rdr::InStream* is,
+ const PixelFormat& pf,
+ ModifiablePixelBuffer* pb)
{
Rect t;
PIXEL_T bg = 0;
PIXEL_T fg = 0;
+ PIXEL_T buf[16 * 16 * 4];
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
int tileType = is->readU8();
if (tileType & hextileRaw) {
- is->readBytes(buf, t.area() * (BPP/8));
- pb->imageRect(pf, t, buf);
- continue;
+ is->readBytes(buf, t.area() * (BPP/8));
+ pb->imageRect(pf, t, buf);
+ continue;
}
if (tileType & hextileBgSpecified)
- bg = is->READ_PIXEL();
+ bg = is->READ_PIXEL();
int len = t.area();
- PIXEL_T* ptr = (PIXEL_T*)buf;
+ PIXEL_T* ptr = buf;
while (len-- > 0) *ptr++ = bg;
if (tileType & hextileFgSpecified)
- fg = is->READ_PIXEL();
+ fg = is->READ_PIXEL();
if (tileType & hextileAnySubrects) {
int nSubrects = is->readU8();
int y = (xy & 15);
int w = ((wh >> 4) & 15) + 1;
int h = (wh & 15) + 1;
- PIXEL_T* ptr = (PIXEL_T*)buf + y * t.width() + x;
+ PIXEL_T* ptr = buf + y * t.width() + x;
int rowAdd = t.width() - w;
while (h-- > 0) {
int len = w;
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright 2004-2005 Cendio AB.
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
// This file is #included after having set the following macro:
// BPP - 8, 16 or 32
-#include <rdr/InStream.h>
-#include <rdr/ZlibInStream.h>
-#include <rfb/Exception.h>
-#include <rfb/TightConstants.h>
-
namespace rfb {
// CONCAT2E concatenates its arguments, expanding them if they are macros
#endif
#define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define READ_PIXEL CONCAT2E(readOpaque,BPP)
-#define TIGHT_DECODE TightDecoder::CONCAT2E(tightDecode,BPP)
-#define DECOMPRESS_JPEG_RECT TightDecoder::CONCAT2E(DecompressJpegRect,BPP)
-#define FILTER_GRADIENT TightDecoder::CONCAT2E(FilterGradient,BPP)
-
-#define TIGHT_MIN_TO_COMPRESS 12
-
-// Main function implementing Tight decoder
-
-void TIGHT_DECODE (const Rect& r)
-{
- bool cutZeros = false;
-#if BPP == 32
- if (serverpf.is888()) {
- cutZeros = true;
- }
-#endif
-
- rdr::U8 comp_ctl = is->readU8();
-
- // Flush zlib streams if we are told by the server to do so.
- for (int i = 0; i < 4; i++) {
- if (comp_ctl & 1) {
- zis[i].reset();
- }
- comp_ctl >>= 1;
- }
-
- // "Fill" compression type.
- if (comp_ctl == tightFill) {
- PIXEL_T pix;
- if (cutZeros) {
- rdr::U8 bytebuf[3];
- is->readBytes(bytebuf, 3);
- serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1);
- } else {
- pix = is->READ_PIXEL();
- }
- pb->fillRect(serverpf, r, &pix);
- return;
- }
-
- // "JPEG" compression type.
- if (comp_ctl == tightJpeg) {
- DECOMPRESS_JPEG_RECT(r);
- return;
- }
-
- // Quit on unsupported compression type.
- if (comp_ctl > tightMaxSubencoding) {
- throw Exception("TightDecoder: bad subencoding value received");
- return;
- }
-
- // "Basic" compression type.
- int palSize = 0;
- static PIXEL_T palette[256];
- bool useGradient = false;
-
- if ((comp_ctl & tightExplicitFilter) != 0) {
- rdr::U8 filterId = is->readU8();
-
- switch (filterId) {
- case tightFilterPalette:
- palSize = is->readU8() + 1;
- if (cutZeros) {
- rdr::U8 tightPalette[256 * 3];
- is->readBytes(tightPalette, palSize * 3);
- serverpf.bufferFromRGB((rdr::U8*)palette, tightPalette, palSize);
- } else {
- is->readBytes(palette, palSize * sizeof(PIXEL_T));
- }
- break;
- case tightFilterGradient:
- useGradient = true;
- break;
- case tightFilterCopy:
- break;
- default:
- throw Exception("TightDecoder: unknown filter code received");
- return;
- }
- }
-
- int bppp = BPP;
- if (palSize != 0) {
- bppp = (palSize <= 2) ? 1 : 8;
- } else if (cutZeros) {
- bppp = 24;
- }
-
- // Determine if the data should be decompressed or just copied.
- int rowSize = (r.width() * bppp + 7) / 8;
- int dataSize = r.height() * rowSize;
- int streamId = -1;
- rdr::InStream *input;
- if (dataSize < TIGHT_MIN_TO_COMPRESS) {
- input = is;
- } else {
- int length = readCompact(is);
- streamId = comp_ctl & 0x03;
- zis[streamId].setUnderlying(is, length);
- input = &zis[streamId];
- }
-
- // Allocate netbuf and read in data
- rdr::U8 *netbuf = new rdr::U8[dataSize];
- if (!netbuf) {
- throw Exception("rfb::TightDecoder::tightDecode unable to allocate buffer");
- }
- input->readBytes(netbuf, dataSize);
-
- PIXEL_T *buf;
- int stride = r.width();
- if (directDecode)
- buf = (PIXEL_T *)pb->getBufferRW(r, &stride);
- else
- buf = new PIXEL_T[r.area()];
-
- if (palSize == 0) {
- // Truecolor data
- if (useGradient) {
-#if BPP == 32
- if (cutZeros) {
- FilterGradient24(netbuf, buf, stride, r);
- } else
-#endif
- {
- FILTER_GRADIENT(netbuf, buf, stride, r);
- }
- } else {
- // Copy
- int h = r.height();
- PIXEL_T *ptr = buf;
- rdr::U8 *srcPtr = netbuf;
- int w = r.width();
- if (cutZeros) {
- while (h > 0) {
- serverpf.bufferFromRGB((rdr::U8*)ptr, srcPtr, w);
- ptr += stride;
- srcPtr += w * 3;
- h--;
- }
- } else {
- while (h > 0) {
- memcpy(ptr, srcPtr, w * sizeof(PIXEL_T));
- ptr += stride;
- srcPtr += w * sizeof(PIXEL_T);
- h--;
- }
- }
- }
- } else {
- // Indexed color
- int x, h = r.height(), w = r.width(), b, pad = stride - w;
- PIXEL_T *ptr = buf;
- rdr::U8 bits, *srcPtr = netbuf;
- if (palSize <= 2) {
- // 2-color palette
- while (h > 0) {
- for (x = 0; x < w / 8; x++) {
- bits = *srcPtr++;
- for (b = 7; b >= 0; b--) {
- *ptr++ = palette[bits >> b & 1];
- }
- }
- if (w % 8 != 0) {
- bits = *srcPtr++;
- for (b = 7; b >= 8 - w % 8; b--) {
- *ptr++ = palette[bits >> b & 1];
- }
- }
- ptr += pad;
- h--;
- }
- } else {
- // 256-color palette
- while (h > 0) {
- PIXEL_T *endOfRow = ptr + w;
- while (ptr < endOfRow) {
- *ptr++ = palette[*srcPtr++];
- }
- ptr += pad;
- h--;
- }
- }
- }
-
- if (directDecode)
- pb->commitBufferRW(r);
- else {
- pb->imageRect(serverpf, r, buf);
- delete [] buf;
- }
-
- delete [] netbuf;
-
- if (streamId != -1) {
- zis[streamId].reset();
- }
-}
-
-void
-DECOMPRESS_JPEG_RECT(const Rect& r)
-{
- // Read length
- int compressedLen = readCompact(is);
- if (compressedLen <= 0) {
- throw Exception("Incorrect data received from the server.\n");
- }
-
- // Allocate netbuf and read in data
- rdr::U8* netbuf = new rdr::U8[compressedLen];
- if (!netbuf) {
- throw Exception("rfb::TightDecoder::DecompressJpegRect unable to allocate buffer");
- }
- is->readBytes(netbuf, compressedLen);
-
- // We always use direct decoding with JPEG images
- int stride;
- rdr::U8 *buf = pb->getBufferRW(r, &stride);
- jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf);
- pb->commitBufferRW(r);
-
- delete [] netbuf;
-}
#if BPP == 32
void
-TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride,
- const Rect& r)
+TightDecoder::FilterGradient24(const rdr::U8 *inbuf,
+ const PixelFormat& pf, PIXEL_T* outbuf,
+ int stride, const Rect& r)
{
int x, y, c;
- static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
- static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
+ rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+ rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
rdr::U8 pix[3];
int est[3];
for (y = 0; y < rectHeight; y++) {
/* First pixel in a row */
for (c = 0; c < 3; c++) {
- pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
+ pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c];
thisRow[c] = pix[c];
}
- serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1);
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
/* Remaining pixels of a row */
for (x = 1; x < rectWidth; x++) {
} else if (est[c] < 0) {
est[c] = 0;
}
- pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
+ pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c];
thisRow[x*3+c] = pix[c];
}
- serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1);
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
}
memcpy(prevRow, thisRow, sizeof(prevRow));
#endif
-void
-FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r)
+#if BPP != 8
+
+void TightDecoder::FilterGradient(const rdr::U8* inbuf,
+ const PixelFormat& pf, PIXEL_T* outbuf,
+ int stride, const Rect& r)
{
int x, y, c;
- static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
- static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+ static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+ static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
rdr::U8 pix[3];
int est[3];
for (y = 0; y < rectHeight; y++) {
/* First pixel in a row */
- serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1);
+ pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1);
for (c = 0; c < 3; c++)
pix[c] += prevRow[c];
memcpy(thisRow, pix, sizeof(pix));
- serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1);
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
/* Remaining pixels of a row */
for (x = 1; x < rectWidth; x++) {
}
}
- serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1);
+ pf.rgbFromBuffer(pix, &inbuf[y*rectWidth+x], 1);
for (c = 0; c < 3; c++)
pix[c] += est[c];
memcpy(&thisRow[x*3], pix, sizeof(pix));
- serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1);
+ pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
}
memcpy(prevRow, thisRow, sizeof(prevRow));
}
}
-#undef TIGHT_MIN_TO_COMPRESS
-#undef FILTER_GRADIENT
-#undef DECOMPRESS_JPEG_RECT
-#undef TIGHT_DECODE
-#undef READ_PIXEL
+#endif
+
+void TightDecoder::FilterPalette(const PIXEL_T* palette, int palSize,
+ const rdr::U8* inbuf, PIXEL_T* outbuf,
+ int stride, const Rect& r)
+{
+ // Indexed color
+ int x, h = r.height(), w = r.width(), b, pad = stride - w;
+ PIXEL_T* ptr = outbuf;
+ rdr::U8 bits;
+ const rdr::U8* srcPtr = inbuf;
+ if (palSize <= 2) {
+ // 2-color palette
+ while (h > 0) {
+ for (x = 0; x < w / 8; x++) {
+ bits = *srcPtr++;
+ for (b = 7; b >= 0; b--) {
+ *ptr++ = palette[bits >> b & 1];
+ }
+ }
+ if (w % 8 != 0) {
+ bits = *srcPtr++;
+ for (b = 7; b >= 8 - w % 8; b--) {
+ *ptr++ = palette[bits >> b & 1];
+ }
+ }
+ ptr += pad;
+ h--;
+ }
+ } else {
+ // 256-color palette
+ while (h > 0) {
+ PIXEL_T *endOfRow = ptr + w;
+ while (ptr < endOfRow) {
+ *ptr++ = palette[*srcPtr++];
+ }
+ ptr += pad;
+ h--;
+ }
+ }
+}
+
#undef PIXEL_T
}