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 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 <rdr/types.h>
  26. #include <rdr/Exception.h>
  27. #include <string.h> // for memcpy
  28. // Check that callers are using InStream properly,
  29. // useful when writing new protocol handling
  30. #undef RFB_INSTREAM_CHECK
  31. namespace rdr {
  32. class InStream {
  33. public:
  34. virtual ~InStream() {}
  35. // avail() returns the number of bytes that are currenctly directly
  36. // available from the stream.
  37. inline size_t avail() {
  38. #ifdef RFB_INSTREAM_CHECK
  39. checkedBytes = end - ptr;
  40. #endif
  41. return end - ptr;
  42. }
  43. // hasData() ensures there is at least "length" bytes of buffer data,
  44. // possibly trying to fetch more data if there isn't enough right away
  45. inline bool hasData(size_t length) {
  46. #ifdef RFB_INSTREAM_CHECK
  47. checkedBytes = 0;
  48. #endif
  49. if (length > (size_t)(end - ptr)) {
  50. if (restorePoint != NULL) {
  51. bool ret;
  52. size_t restoreDiff;
  53. restoreDiff = ptr - restorePoint;
  54. ptr = restorePoint;
  55. ret = overrun(length + restoreDiff);
  56. restorePoint = ptr;
  57. ptr += restoreDiff;
  58. if (!ret)
  59. return false;
  60. } else {
  61. if (!overrun(length))
  62. return false;
  63. }
  64. }
  65. #ifdef RFB_INSTREAM_CHECK
  66. checkedBytes = length;
  67. #endif
  68. return true;
  69. }
  70. inline bool hasDataOrRestore(size_t length) {
  71. if (hasData(length))
  72. return true;
  73. gotoRestorePoint();
  74. return false;
  75. }
  76. inline void setRestorePoint() {
  77. #ifdef RFB_INSTREAM_CHECK
  78. if (restorePoint != NULL)
  79. throw Exception("Nested use of input stream restore point");
  80. #endif
  81. restorePoint = ptr;
  82. }
  83. inline void clearRestorePoint() {
  84. #ifdef RFB_INSTREAM_CHECK
  85. if (restorePoint == NULL)
  86. throw Exception("Incorrect clearing of input stream restore point");
  87. #endif
  88. restorePoint = NULL;
  89. }
  90. inline void gotoRestorePoint() {
  91. #ifdef RFB_INSTREAM_CHECK
  92. if (restorePoint == NULL)
  93. throw Exception("Incorrect activation of input stream restore point");
  94. #endif
  95. ptr = restorePoint;
  96. clearRestorePoint();
  97. }
  98. // readU/SN() methods read unsigned and signed N-bit integers.
  99. inline U8 readU8() { check(1); return *ptr++; }
  100. inline U16 readU16() { check(2); int b0 = *ptr++; int b1 = *ptr++;
  101. return b0 << 8 | b1; }
  102. inline U32 readU32() { check(4); int b0 = *ptr++; int b1 = *ptr++;
  103. int b2 = *ptr++; int b3 = *ptr++;
  104. return b0 << 24 | b1 << 16 | b2 << 8 | b3; }
  105. inline S8 readS8() { return (S8) readU8(); }
  106. inline S16 readS16() { return (S16)readU16(); }
  107. inline S32 readS32() { return (S32)readU32(); }
  108. // skip() ignores a number of bytes on the stream
  109. inline void skip(size_t bytes) {
  110. check(bytes);
  111. ptr += bytes;
  112. }
  113. // readBytes() reads an exact number of bytes.
  114. void readBytes(void* data, size_t length) {
  115. check(length);
  116. memcpy(data, ptr, length);
  117. ptr += length;
  118. }
  119. // readOpaqueN() reads a quantity without byte-swapping.
  120. inline U8 readOpaque8() { return readU8(); }
  121. inline U16 readOpaque16() { check(2); U16 r; ((U8*)&r)[0] = *ptr++;
  122. ((U8*)&r)[1] = *ptr++; return r; }
  123. inline U32 readOpaque32() { check(4); U32 r; ((U8*)&r)[0] = *ptr++;
  124. ((U8*)&r)[1] = *ptr++; ((U8*)&r)[2] = *ptr++;
  125. ((U8*)&r)[3] = *ptr++; return r; }
  126. // pos() returns the position in the stream.
  127. virtual size_t pos() = 0;
  128. // getptr() and setptr() are "dirty" methods which allow you direct access
  129. // to the buffer. This is useful for a stream which is a wrapper around an
  130. // some other stream API.
  131. inline const U8* getptr(size_t length) { check(length);
  132. #ifdef RFB_INSTREAM_CHECK
  133. checkedBytes += length;
  134. #endif
  135. return ptr; }
  136. inline void setptr(size_t length) { if (length > avail())
  137. throw Exception("Input stream overflow");
  138. skip(length); }
  139. private:
  140. const U8* restorePoint;
  141. #ifdef RFB_INSTREAM_CHECK
  142. size_t checkedBytes;
  143. #endif
  144. inline void check(size_t bytes) {
  145. #ifdef RFB_INSTREAM_CHECK
  146. if (bytes > checkedBytes)
  147. throw Exception("Input stream used without underrun check");
  148. checkedBytes -= bytes;
  149. #endif
  150. if (bytes > (size_t)(end - ptr))
  151. throw Exception("InStream buffer underrun");
  152. }
  153. // overrun() is implemented by a derived class to cope with buffer overrun.
  154. // It tries to ensure there are at least needed bytes of buffer data.
  155. // Returns true if it managed to satisfy the request, or false otherwise.
  156. virtual bool overrun(size_t needed) = 0;
  157. protected:
  158. InStream() : restorePoint(NULL)
  159. #ifdef RFB_INSTREAM_CHECK
  160. ,checkedBytes(0)
  161. #endif
  162. {}
  163. const U8* ptr;
  164. const U8* end;
  165. };
  166. }
  167. #endif