aboutsummaryrefslogtreecommitdiff
path: root/nxcomp/src/DecodeBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nxcomp/src/DecodeBuffer.cpp')
-rw-r--r--nxcomp/src/DecodeBuffer.cpp639
1 files changed, 639 insertions, 0 deletions
diff --git a/nxcomp/src/DecodeBuffer.cpp b/nxcomp/src/DecodeBuffer.cpp
new file mode 100644
index 000000000..4c1530d9b
--- /dev/null
+++ b/nxcomp/src/DecodeBuffer.cpp
@@ -0,0 +1,639 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
+/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
+/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */
+/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */
+/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
+/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
+/* */
+/* NXCOMP, NX protocol compression and NX extensions to this software */
+/* are copyright of the aforementioned persons and companies. */
+/* */
+/* Redistribution and use of the present software is allowed according */
+/* to terms specified in the file LICENSE.nxcomp which comes in the */
+/* source distribution. */
+/* */
+/* All rights reserved. */
+/* */
+/* NOTE: This software has received contributions from various other */
+/* contributors, only the core maintainers and supporters are listed as */
+/* copyright holders. Please contact us, if you feel you should be listed */
+/* as copyright holder, as well. */
+/* */
+/**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "Misc.h"
+#include "Control.h"
+
+#include "DecodeBuffer.h"
+
+//
+// Set the verbosity level.
+//
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+#undef DUMP
+
+DecodeBuffer::DecodeBuffer(const unsigned char *data, unsigned int length)
+
+ : buffer_(data), end_(buffer_ + length), nextSrc_(buffer_), srcMask_(0x80)
+{
+ // Since ProtoStep7 (#issue 108)
+ end_ = buffer_ + length - DECODE_BUFFER_POSTFIX_SIZE;
+}
+
+int DecodeBuffer::decodeValue(unsigned int &value, unsigned int numBits,
+ unsigned int blockSize, int endOkay)
+{
+ #ifdef DUMP
+ *logofs << "DecodeBuffer: Decoding " << numBits
+ << " bits value with block " << blockSize
+ << " and " << (nextSrc_ - buffer_)
+ << " bytes in buffer.\n" << logofs_flush;
+ #endif
+
+ unsigned int result = 0;
+ unsigned int destMask = 0x1;
+ unsigned int bitsRead = 0;
+
+ if (blockSize == 0)
+ blockSize = numBits;
+
+ unsigned char nextSrcChar = *nextSrc_;
+ unsigned int numBlocks = 1;
+
+ do
+ {
+ if (numBlocks == 4)
+ {
+ blockSize = numBits;
+ }
+
+ unsigned int bitsToRead = (blockSize > numBits - bitsRead ?
+ numBits - bitsRead : blockSize);
+ unsigned int count = 0;
+ unsigned char lastBit;
+
+ do
+ {
+ if (nextSrc_ >= end_)
+ {
+ if (!endOkay)
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [A] "
+ << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_)
+ << " end_ = " << (end_ - buffer_) << ".\n"
+ << logofs_flush;
+ #endif
+
+ //
+ // Label "context" is just used to identify
+ // the routine which detected the problem in
+ // present source file.
+ //
+
+ cerr << "Error" << ": Failure decoding data in context [A].\n";
+
+ HandleAbort();
+ }
+
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [B] "
+ << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_)
+ << " end_ = " << (end_ - buffer_) << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [B].\n";
+
+ HandleAbort();
+ }
+
+ lastBit = (nextSrcChar & srcMask_);
+
+ if (lastBit)
+ result |= destMask;
+
+ srcMask_ >>= 1;
+
+ if (srcMask_ == 0)
+ {
+ srcMask_ = 0x80;
+ nextSrc_++;
+ nextSrcChar = *nextSrc_;
+ }
+
+ destMask <<= 1;
+ }
+ while (bitsToRead > ++count);
+
+ bitsRead += bitsToRead;
+
+ if (bitsRead < numBits)
+ {
+ if (nextSrc_ >= end_)
+ {
+ if (!endOkay)
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [C] "
+ << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_)
+ << " end_ = " << (end_ - buffer_) << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [C].\n";
+
+ HandleAbort();
+ }
+
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [D] "
+ << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_)
+ << " end_ = " << (end_ - buffer_) << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [D].\n";
+
+ HandleAbort();
+ }
+
+ unsigned char moreData = (nextSrcChar & srcMask_);
+
+ srcMask_ >>= 1;
+
+ if (srcMask_ == 0)
+ {
+ srcMask_ = 0x80;
+ nextSrc_++;
+ nextSrcChar = *nextSrc_;
+ }
+
+ if (!moreData)
+ {
+ if (lastBit)
+ {
+ do
+ {
+ result |= destMask;
+ destMask <<= 1;
+ }
+ while (numBits > ++bitsRead);
+ }
+ else
+ bitsRead = numBits;
+ }
+ }
+
+ blockSize >>= 1;
+
+ if (blockSize < 2)
+ blockSize = 2;
+
+ numBlocks++;
+ }
+ while (numBits > bitsRead);
+
+ value = result;
+
+ return 1;
+}
+
+int DecodeBuffer::decodeCachedValue(unsigned int &value, unsigned int numBits,
+ IntCache &cache, unsigned int blockSize,
+ int endOkay)
+{
+ #ifdef DUMP
+ *logofs << "DecodeBuffer: Decoding " << numBits
+ << " bits cached value with block " << blockSize
+ << " and " << (nextSrc_ - buffer_)
+ << " bytes in buffer.\n" << logofs_flush;
+ #endif
+
+ if (nextSrc_ >= end_)
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [E] "
+ << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_)
+ << " end_ = " << (end_ - buffer_) << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [E].\n";
+
+ HandleAbort();
+ }
+
+ unsigned int index = 0;
+ unsigned char nextSrcChar = *nextSrc_;
+
+ while (!(nextSrcChar & srcMask_))
+ {
+ index++;
+ srcMask_ >>= 1;
+ if (srcMask_ == 0)
+ {
+ srcMask_ = 0x80;
+ nextSrc_++;
+ if (nextSrc_ >= end_)
+ {
+ if (!endOkay)
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [F] "
+ << "in decodeCachedValue() nextSrc_ = "
+ << (nextSrc_ - buffer_) << " end_ = "
+ << (end_ - buffer_) << ".\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [F].\n";
+
+ HandleAbort();
+ }
+
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [G] "
+ << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_)
+ << " end_ = " << (end_ - buffer_) << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [G].\n";
+
+ HandleAbort();
+ }
+
+ nextSrcChar = *nextSrc_;
+ }
+ }
+
+ srcMask_ >>= 1;
+
+ if (srcMask_ == 0)
+ {
+ srcMask_ = 0x80;
+ nextSrc_++;
+ }
+
+ if (index == 2)
+ {
+ // Since ProtoStep8 (#issue 108)
+ blockSize = cache.getBlockSize(blockSize);
+
+ if (decodeValue(value, numBits, blockSize, endOkay))
+ {
+ cache.insert(value, IntMask[numBits]);
+
+ return 1;
+ }
+
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [H] "
+ << "in decodeCacheValue() with no value found.\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [H].\n";
+
+ HandleAbort();
+ }
+ else
+ {
+ if (index > 2)
+ {
+ index--;
+ }
+
+ if (index > cache.getSize())
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [I] "
+ << "in decodeCachedValue() index = " << index
+ << " cache size = " << cache.getSize() << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [I].\n";
+
+ HandleAbort();
+ }
+
+ value = cache.get(index);
+
+ return 1;
+ }
+}
+
+int DecodeBuffer::decodeCachedValue(unsigned char &value, unsigned int numBits,
+ CharCache &cache, unsigned int blockSize,
+ int endOkay)
+{
+ #ifdef DUMP
+ *logofs << "DecodeBuffer: Decoding " << numBits
+ << " bits char cached value with block " << blockSize
+ << " and " << nextSrc_ - buffer_ << " bytes read out of "
+ << end_ - buffer_ << ".\n" << logofs_flush;
+ #endif
+
+ if (nextSrc_ >= end_)
+ {
+ #ifdef TEST
+ *logofs << "DecodeBuffer: End of buffer reached in context [J] with "
+ << nextSrc_ - buffer_ << " bytes read out of "
+ << end_ - buffer_ << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+
+ unsigned int index = 0;
+ unsigned char nextSrcChar = *nextSrc_;
+
+ while (!(nextSrcChar & srcMask_))
+ {
+ index++;
+ srcMask_ >>= 1;
+
+ if (srcMask_ == 0)
+ {
+ srcMask_ = 0x80;
+ nextSrc_++;
+
+ if (nextSrc_ >= end_)
+ {
+ if (!endOkay)
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [K] "
+ << "in decodeCachedValue() nextSrc_ "
+ << (nextSrc_ - buffer_) << " end_ " << (end_ - buffer_)
+ << ".\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [K].\n";
+
+ HandleAbort();
+ }
+
+ #ifdef TEST
+ *logofs << "DecodeBuffer: End of buffer reached in context [L] with "
+ << nextSrc_ - buffer_ << " bytes read out of "
+ << end_ - buffer_ << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+
+ nextSrcChar = *nextSrc_;
+ }
+ }
+
+ srcMask_ >>= 1;
+
+ if (srcMask_ == 0)
+ {
+ srcMask_ = 0x80;
+ nextSrc_++;
+ }
+
+ if (index == 2)
+ {
+ unsigned int temp;
+
+ if (decodeValue(temp, numBits, blockSize, endOkay))
+ {
+ value = (unsigned char) temp;
+
+ cache.insert(value);
+ }
+ else
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [M] "
+ << "in decodeValue() with index = 2.\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [M].\n";
+
+ HandleAbort();
+ }
+ }
+ else
+ {
+ if (index > 2)
+ {
+ index--;
+ }
+
+ if (index > cache.getSize())
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [N] "
+ << "in decodeCachedValue() " << "index = " << index
+ << " cache size = " << cache.getSize() << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [N].\n";
+
+ HandleAbort();
+ }
+
+ value = cache.get(index);
+ }
+
+ return 1;
+}
+
+//
+// Simply returns a pointer to the correct spot in
+// the internal buffer. If the caller needs this
+// data to last beyond the lifetime of the internal
+// buffer, it must copy the data in its own memory.
+//
+
+const unsigned char *DecodeBuffer::decodeMemory(unsigned int numBytes)
+{
+ #ifdef DUMP
+ *logofs << "DecodeBuffer: Decoding " << numBytes
+ << " bytes of memory with " << (nextSrc_ - buffer_)
+ << " bytes in buffer.\n" << logofs_flush;
+ #endif
+
+ const unsigned char *result;
+
+ //
+ // Force ourselves to a byte boundary.
+ // Is up to application to ensure data
+ // is word alligned when needed.
+ //
+
+ if (srcMask_ != 0x80)
+ {
+ srcMask_ = 0x80;
+ nextSrc_++;
+ }
+
+ result = nextSrc_;
+
+ if (numBytes > DECODE_BUFFER_OVERFLOW_SIZE)
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Can't decode a buffer of "
+ << numBytes << " bytes with limit set to "
+ << DECODE_BUFFER_OVERFLOW_SIZE << ".\n"
+ << logofs_flush;
+
+ *logofs << "DecodeBuffer: PANIC! Assuming failure decoding "
+ << "data in context [O].\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Should never decode buffer of size "
+ << "greater than " << DECODE_BUFFER_OVERFLOW_SIZE
+ << " bytes.\n";
+
+ cerr << "Error" << ": Assuming failure decoding data in "
+ << "context [O].\n";
+
+ HandleAbort();
+ }
+ else if (end_ - nextSrc_ < (int) numBytes)
+ {
+ #ifdef PANIC
+ *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [P] "
+ << "in decodeMemory() " << "with length " << numBytes
+ << " and " << (end_ - nextSrc_)
+ << " bytes remaining.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Failure decoding data in context [P].\n";
+
+ HandleAbort();
+ }
+
+ nextSrc_ += numBytes;
+
+ return result;
+}
+
+void DecodeBuffer::decodeActionValue(unsigned char &value, unsigned short &position,
+ ActionCache &cache)
+{
+ unsigned int t;
+
+ decodeCachedValue(t, 15, *(cache.base_[cache.slot_]));
+
+ cache.last_ += t;
+ cache.last_ &= 0x7fff;
+
+ value = cache.last_ >> 13;
+
+ position = cache.last_ & 0x1fff;
+
+ #ifdef DEBUG
+ *logofs << "DecodeBuffer: Decoded value "
+ << (unsigned) value << " and position "
+ << position << " with base " << cache.slot_
+ << ".\n" << logofs_flush;
+ #endif
+
+ #ifdef DEBUG
+ *logofs << "DecodeBuffer: Action block prediction is "
+ << (*(cache.base_[cache.slot_])).getBlockSize(15)
+ << ".\n" << logofs_flush;
+ #endif
+
+ cache.slot_ = (cache.last_ & 0xff);
+}
+
+void DecodeBuffer::decodeNewXidValue(unsigned int &value, unsigned int &lastId,
+ IntCache &lastIdCache, IntCache &cache,
+ FreeCache &freeCache)
+{
+ decodeCachedValue(value, 29, lastIdCache);
+
+ lastId += (value + 1);
+ lastId &= 0x1fffffff;
+
+ value = lastId;
+
+ cache.push(value, 0x1fffffff);
+
+ freeCache.push(value, 0x1fffffff);
+}
+
+void DecodeBuffer::decodeNewXidValue(unsigned int &value, unsigned int &lastId,
+ IntCache &lastIdCache, XidCache &cache,
+ FreeCache &freeCache)
+{
+ decodeCachedValue(value, 29, lastIdCache);
+
+ #ifdef DEBUG
+ *logofs << "DecodeBuffer: Decoded new Xid difference "
+ << value << ".\n" << logofs_flush;
+ #endif
+
+ lastId += (value + 1);
+ lastId &= 0x1fffffff;
+
+ value = lastId;
+
+ unsigned int t = (value - cache.last_);
+
+ cache.last_ = value;
+
+ #ifdef DEBUG
+ *logofs << "DecodeBuffer: Decoded new Xid " << value
+ << " with base " << cache.slot_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ cache.slot_ = (value & 0xff);
+
+ cache.base_[cache.slot_] -> push(t, 0x1fffffff);
+
+ freeCache.push(value, 0x1fffffff);
+}
+
+void DecodeBuffer::decodeXidValue(unsigned int &value, XidCache &cache)
+{
+ unsigned int t;
+
+ decodeCachedValue(t, 29, *(cache.base_[cache.slot_]));
+
+ cache.last_ += t;
+ cache.last_ &= 0x1fffffff;
+
+ value = cache.last_;
+
+ #ifdef DEBUG
+ *logofs << "DecodeBuffer: Decoded Xid " << value
+ << " with base " << cache.slot_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ cache.slot_ = (value & 0xff);
+
+ #ifdef DEBUG
+ *logofs << "DecodeBuffer: Xid block prediction is "
+ << (*(cache.base_[cache.slot_])).getBlockSize(29)
+ << ".\n" << logofs_flush;
+ #endif
+}
+
+void DecodeBuffer::decodeFreeXidValue(unsigned int &value, FreeCache &cache)
+{
+ decodeCachedValue(value, 29, cache);
+}
+