You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

InStream.h 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2014-2020 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. //
  20. // rdr::InStream marshalls data from a buffer stored in RDR (RFB Data
  21. // Representation).
  22. //
  23. #ifndef __RDR_INSTREAM_H__
  24. #define __RDR_INSTREAM_H__
  25. #include <stdint.h>
  26. #include <string.h> // for memcpy
  27. #include <rdr/Exception.h>
  28. // Check that callers are using InStream properly,
  29. // useful when writing new protocol handling
  30. #ifdef _DEBUG
  31. #define RFB_INSTREAM_CHECK
  32. #endif
  33. namespace rdr {
  34. class InStream {
  35. public:
  36. virtual ~InStream() {}
  37. // avail() returns the number of bytes that are currenctly directly
  38. // available from the stream.
  39. inline size_t avail() {
  40. #ifdef RFB_INSTREAM_CHECK
  41. checkedBytes = end - ptr;
  42. #endif
  43. return end - ptr;
  44. }
  45. // hasData() ensures there is at least "length" bytes of buffer data,
  46. // possibly trying to fetch more data if there isn't enough right away
  47. inline bool hasData(size_t length) {
  48. #ifdef RFB_INSTREAM_CHECK
  49. checkedBytes = 0;
  50. #endif
  51. if (length > (size_t)(end - ptr)) {
  52. if (restorePoint != NULL) {
  53. bool ret;
  54. size_t restoreDiff;
  55. restoreDiff = ptr - restorePoint;
  56. ptr = restorePoint;
  57. ret = overrun(length + restoreDiff);
  58. restorePoint = ptr;
  59. ptr += restoreDiff;
  60. if (!ret)
  61. return false;
  62. } else {
  63. if (!overrun(length))
  64. return false;
  65. }
  66. }
  67. #ifdef RFB_INSTREAM_CHECK
  68. checkedBytes = length;
  69. #endif
  70. return true;
  71. }
  72. inline bool hasDataOrRestore(size_t length) {
  73. if (hasData(length))
  74. return true;
  75. gotoRestorePoint();
  76. return false;
  77. }
  78. inline void setRestorePoint() {
  79. #ifdef RFB_INSTREAM_CHECK
  80. if (restorePoint != NULL)
  81. throw Exception("Nested use of input stream restore point");
  82. #endif
  83. restorePoint = ptr;
  84. }
  85. inline void clearRestorePoint() {
  86. #ifdef RFB_INSTREAM_CHECK
  87. if (restorePoint == NULL)
  88. throw Exception("Incorrect clearing of input stream restore point");
  89. #endif
  90. restorePoint = NULL;
  91. }
  92. inline void gotoRestorePoint() {
  93. #ifdef RFB_INSTREAM_CHECK
  94. if (restorePoint == NULL)
  95. throw Exception("Incorrect activation of input stream restore point");
  96. #endif
  97. ptr = restorePoint;
  98. clearRestorePoint();
  99. }
  100. // readU/SN() methods read unsigned and signed N-bit integers.
  101. inline uint8_t readU8() { check(1); return *ptr++; }
  102. inline uint16_t readU16() { check(2);
  103. int b0 = *ptr++; int b1 = *ptr++;
  104. return b0 << 8 | b1; }
  105. inline uint32_t readU32() { check(4);
  106. int b0 = *ptr++; int b1 = *ptr++;
  107. int b2 = *ptr++; int b3 = *ptr++;
  108. return b0 << 24 | b1 << 16 | b2 << 8 | b3; }
  109. inline int8_t readS8() { return (int8_t) readU8(); }
  110. inline int16_t readS16() { return (int16_t)readU16(); }
  111. inline int32_t readS32() { return (int32_t)readU32(); }
  112. // skip() ignores a number of bytes on the stream
  113. inline void skip(size_t bytes) {
  114. check(bytes);
  115. ptr += bytes;
  116. }
  117. // readBytes() reads an exact number of bytes.
  118. void readBytes(uint8_t* data, size_t length) {
  119. check(length);
  120. memcpy(data, ptr, length);
  121. ptr += length;
  122. }
  123. // readOpaqueN() reads a quantity without byte-swapping.
  124. inline uint8_t readOpaque8() { return readU8(); }
  125. inline uint16_t readOpaque16() { check(2); uint16_t r;
  126. ((uint8_t*)&r)[0] = *ptr++;
  127. ((uint8_t*)&r)[1] = *ptr++;
  128. return r; }
  129. inline uint32_t readOpaque32() { check(4); uint32_t r;
  130. ((uint8_t*)&r)[0] = *ptr++;
  131. ((uint8_t*)&r)[1] = *ptr++;
  132. ((uint8_t*)&r)[2] = *ptr++;
  133. ((uint8_t*)&r)[3] = *ptr++;
  134. return r; }
  135. // pos() returns the position in the stream.
  136. virtual size_t pos() = 0;
  137. // getptr() and setptr() are "dirty" methods which allow you direct access
  138. // to the buffer. This is useful for a stream which is a wrapper around an
  139. // some other stream API.
  140. inline const uint8_t* getptr(size_t length) { check(length);
  141. return ptr; }
  142. inline void setptr(size_t length) { if (length > avail())
  143. throw Exception("Input stream overflow");
  144. skip(length); }
  145. private:
  146. const uint8_t* restorePoint;
  147. #ifdef RFB_INSTREAM_CHECK
  148. size_t checkedBytes;
  149. #endif
  150. inline void check(size_t bytes) {
  151. #ifdef RFB_INSTREAM_CHECK
  152. if (bytes > checkedBytes)
  153. throw Exception("Input stream used without underrun check");
  154. checkedBytes -= bytes;
  155. #endif
  156. if (bytes > (size_t)(end - ptr))
  157. throw Exception("InStream buffer underrun");
  158. }
  159. // overrun() is implemented by a derived class to cope with buffer overrun.
  160. // It tries to ensure there are at least needed bytes of buffer data.
  161. // Returns true if it managed to satisfy the request, or false otherwise.
  162. virtual bool overrun(size_t needed) = 0;
  163. protected:
  164. InStream() : restorePoint(NULL)
  165. #ifdef RFB_INSTREAM_CHECK
  166. ,checkedBytes(0)
  167. #endif
  168. {}
  169. const uint8_t* ptr;
  170. const uint8_t* end;
  171. };
  172. }
  173. #endif