Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h
new file mode 100644
index 0000000..dd0c4d9
--- /dev/null
+++ b/common/rfb/tightDecode.h
@@ -0,0 +1,412 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 2004-2005 Cendio AB. All rights reserved.
+ *    
+ * 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.
+ */
+
+//
+// Tight decoding functions.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// FILL_RECT          - fill a rectangle with a single color
+// IMAGE_RECT         - draw a rectangle of pixel data from a buffer
+
+#include <rdr/InStream.h>
+#include <rdr/ZlibInStream.h>
+#include <rfb/Exception.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define TIGHT_DECODE CONCAT2E(tightDecode,BPP)
+
+#define TIGHT_MIN_TO_COMPRESS 12
+static bool DecompressJpegRect(const Rect& r, rdr::InStream* is,
+			       PIXEL_T* buf, CMsgHandler* handler);
+static void FilterGradient(const Rect& r, rdr::InStream* is, int dataSize,
+			   PIXEL_T* buf, CMsgHandler* handler);
+#if BPP == 32
+static void FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize,
+			     PIXEL_T* buf, CMsgHandler* handler);
+#endif
+
+// Main function implementing Tight decoder
+
+void TIGHT_DECODE (const Rect& r, rdr::InStream* is,
+                   rdr::ZlibInStream zis[], PIXEL_T* buf
+#ifdef EXTRA_ARGS
+                      , EXTRA_ARGS
+#endif
+                      )
+{
+  rdr::U8 *bytebuf = (rdr::U8*) buf;
+  bool cutZeros = false;
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+#if BPP == 32
+  if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+      myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+    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 == rfbTightFill) {
+    PIXEL_T pix;
+    if (cutZeros) {
+      is->readBytes(bytebuf, 3);
+      pix = RGB24_TO_PIXEL32(bytebuf[0], bytebuf[1], bytebuf[2]);
+    } else {
+      pix = is->READ_PIXEL();
+    }
+    FILL_RECT(r, pix);
+    return;
+  }
+
+  // "JPEG" compression type.
+  if (comp_ctl == rfbTightJpeg) {
+    DecompressJpegRect(r, is, buf, handler);
+    return;
+  }
+
+  // Quit on unsupported compression type.
+  if (comp_ctl > rfbTightMaxSubencoding) {
+    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 & rfbTightExplicitFilter) != 0) {
+    rdr::U8 filterId = is->readU8();
+
+    switch (filterId) {
+    case rfbTightFilterPalette: 
+      palSize = is->readU8() + 1;
+      if (cutZeros) {
+	rdr::U8 *tightPalette = (rdr::U8*) palette;
+	is->readBytes(tightPalette, palSize*3);
+	for (int i = palSize - 1; i >= 0; i--) {
+	  palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
+					tightPalette[i*3+1],
+					tightPalette[i*3+2]);
+        }
+      } else {
+	for (int i = 0; i < palSize; i++)
+	  palette[i] = is->READ_PIXEL();
+      }
+      break;
+    case rfbTightFilterGradient: 
+      useGradient = true;
+      break;
+    case rfbTightFilterCopy:
+      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 = is->readCompactLength();
+    streamId = comp_ctl & 0x03;
+    zis[streamId].setUnderlying(is, length);
+    input = &zis[streamId];
+  }
+
+  if (palSize == 0) {
+    // Truecolor data
+    if (useGradient) {
+#if BPP == 32
+      if (cutZeros) {
+	FilterGradient24(r, input, dataSize, buf, handler);
+      } else 
+#endif
+	{
+	  FilterGradient(r, input, dataSize, buf, handler);
+	}
+    } else {
+      input->readBytes(buf, dataSize); 
+      if (cutZeros) {
+	for (int p = r.height() * r.width() - 1; p >= 0; p--) {
+	  buf[p] = RGB24_TO_PIXEL32(bytebuf[p*3],
+				    bytebuf[p*3+1],
+				    bytebuf[p*3+2]);
+	}
+      }
+    }
+  } else {
+    int x, y, b, w;
+    PIXEL_T *ptr = buf;
+    rdr::U8 bits;
+    if (palSize <= 2) {
+      // 2-color palette
+      w = (r.width() + 7) / 8;
+      for (y = 0; y < r.height(); y++) {
+        for (x = 0; x < r.width() / 8; x++) {
+          bits = input->readU8();
+          for (b = 7; b >= 0; b--) {
+            *ptr++ = palette[bits >> b & 1];
+	  }
+        }
+        if (r.width() % 8 != 0) {
+          bits = input->readU8();
+          for (b = 7; b >= 8 - r.width() % 8; b--) {
+            *ptr++ = palette[bits >> b & 1];
+          }
+        }
+      }
+    } else {
+      // 256-color palette
+      for (y = 0; y < r.height(); y++) {
+        for (x = 0; x < r.width(); x++) {
+          *ptr++ = palette[input->readU8()];
+	}
+      }
+    }
+  }
+
+  IMAGE_RECT(r, buf);
+
+  if (streamId != -1) {
+    zis[streamId].reset();
+  }
+}
+
+static bool
+DecompressJpegRect(const Rect& r, rdr::InStream* is,
+		   PIXEL_T* buf, CMsgHandler* handler)
+{
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  PIXEL_T *pixelPtr = buf;
+  static rdr::U8 scanline_buffer[TIGHT_MAX_WIDTH*3];
+  JSAMPROW scanline = scanline_buffer;
+
+  // Read length
+  int compressedLen = is->readCompactLength();
+  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::tightDecode unable to allocate buffer");
+  }
+  is->readBytes(netbuf, compressedLen);
+
+  // Set up JPEG decompression
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo);
+  JpegSetSrcManager(&cinfo, (char*)netbuf, compressedLen);
+  jpeg_read_header(&cinfo, TRUE);
+  cinfo.out_color_space = JCS_RGB;
+
+  jpeg_start_decompress(&cinfo);
+  if (cinfo.output_width != (unsigned)r.width() || cinfo.output_height != (unsigned)r.height() ||
+      cinfo.output_components != 3) {
+      jpeg_destroy_decompress(&cinfo);
+      throw Exception("Tight Encoding: Wrong JPEG data received.\n");
+  }
+
+  // Decompress
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+  while (cinfo.output_scanline < cinfo.output_height) {
+    jpeg_read_scanlines(&cinfo, &scanline, 1);
+    if (jpegError) {
+      break;
+    }
+
+    for (int dx = 0; dx < r.width(); dx++) {
+      *pixelPtr++ = 
+	RGB24_TO_PIXEL(scanline[dx*3], scanline[dx*3+1], scanline[dx*3+2]);
+    }
+  }
+
+  IMAGE_RECT(r, buf);
+
+  if (!jpegError) {
+    jpeg_finish_decompress(&cinfo);
+  }
+
+  jpeg_destroy_decompress(&cinfo);
+
+  delete [] netbuf;
+
+  return !jpegError;
+}
+
+#if BPP == 32
+
+static void
+FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize,
+		 PIXEL_T* buf, CMsgHandler* handler)
+{
+  int x, y, c;
+  static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+  static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
+  rdr::U8 pix[3]; 
+  int est[3]; 
+
+  memset(prevRow, 0, sizeof(prevRow));
+
+  // Allocate netbuf and read in data
+  rdr::U8 *netbuf = new rdr::U8[dataSize];
+  if (!netbuf) {
+    throw Exception("rfb::tightDecode unable to allocate buffer");
+  }
+  is->readBytes(netbuf, dataSize);
+
+  // Set up shortcut variables
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+  int rectHeight = r.height();
+  int rectWidth = r.width();
+
+  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];
+      thisRow[c] = pix[c];
+    }
+    buf[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+
+    /* Remaining pixels of a row */
+    for (x = 1; x < rectWidth; x++) {
+      for (c = 0; c < 3; c++) {
+	est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+	if (est[c] > 0xff) {
+	  est[c] = 0xff;
+	} else if (est[c] < 0) {
+	  est[c] = 0;
+	}
+	pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
+	thisRow[x*3+c] = pix[c];
+      }
+      buf[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+    }
+
+    memcpy(prevRow, thisRow, sizeof(prevRow));
+  }
+
+  delete [] netbuf;
+}
+
+#endif
+
+static void
+FilterGradient(const Rect& r, rdr::InStream* is, int dataSize,
+	       PIXEL_T* buf, CMsgHandler* handler)
+{
+  int x, y, c;
+  static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+  static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+  int pix[3]; 
+  int max[3]; 
+  int shift[3]; 
+  int est[3]; 
+
+  memset(prevRow, 0, sizeof(prevRow));
+
+  // Allocate netbuf and read in data
+  PIXEL_T *netbuf = (PIXEL_T*)new rdr::U8[dataSize];
+  if (!netbuf) {
+    throw Exception("rfb::tightDecode unable to allocate buffer");
+  }
+  is->readBytes(netbuf, dataSize);
+
+  // Set up shortcut variables
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+  max[0] = myFormat.redMax; 
+  max[1] = myFormat.greenMax; 
+  max[2] = myFormat.blueMax; 
+  shift[0] = myFormat.redShift; 
+  shift[1] = myFormat.greenShift; 
+  shift[2] = myFormat.blueShift; 
+  int rectHeight = r.height();
+  int rectWidth = r.width();
+
+  for (y = 0; y < rectHeight; y++) {
+    /* First pixel in a row */
+    for (c = 0; c < 3; c++) {
+      pix[c] = (netbuf[y*rectWidth] >> shift[c]) + prevRow[c] & max[c];
+      thisRow[c] = pix[c];
+    }
+    buf[y*rectWidth] = RGB_TO_PIXEL(pix[0], pix[1], pix[2]);
+
+    /* Remaining pixels of a row */
+    for (x = 1; x < rectWidth; x++) {
+      for (c = 0; c < 3; c++) {
+	est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+	if (est[c] > max[c]) {
+	  est[c] = max[c];
+	} else if (est[c] < 0) {
+	  est[c] = 0;
+	}
+	pix[c] = (netbuf[y*rectWidth+x] >> shift[c]) + est[c] & max[c];
+	thisRow[x*3+c] = pix[c];
+      }
+      buf[y*rectWidth+x] = RGB_TO_PIXEL(pix[0], pix[1], pix[2]);
+    }
+
+    memcpy(prevRow, thisRow, sizeof(prevRow));
+  }
+
+  delete [] netbuf;
+}
+
+#undef TIGHT_MIN_TO_COMPRESS
+#undef TIGHT_DECODE
+#undef READ_PIXEL
+#undef PIXEL_T
+}