@@ -36,6 +36,9 @@ class BinaryStream{
3636 /** @var string */
3737 protected $ buffer ;
3838
39+ private int $ readOps = 0 ;
40+ private int $ readOpsLimit = 0 ;
41+
3942 public function __construct (string $ buffer = "" , int $ offset = 0 ){
4043 $ this ->buffer = $ buffer ;
4144 $ this ->offset = $ offset ;
@@ -56,6 +59,45 @@ public function getOffset() : int{
5659 return $ this ->offset ;
5760 }
5861
62+ /**
63+ * @internal Experimental, may be removed
64+ * Returns the total number of operations done on this BinaryStream so far
65+ * When this value exceeds the read cost limit (if set to a value > 0), a BinaryDataException will be thrown
66+ */
67+ public function getReadOps () : int {
68+ return $ this ->readOps ;
69+ }
70+
71+ /**
72+ * @internal Experimental, may be removed
73+ */
74+ public function setReadOps (int $ readOps ) : void {
75+ $ this ->readOps = $ readOps ;
76+ }
77+
78+ private function addReadOps (int $ amount ) : void {
79+ if ($ this ->readOpsLimit > 0 ){
80+ $ this ->readOps += $ amount ;
81+ if ($ this ->readOps > $ this ->readOpsLimit ){
82+ throw new BinaryDataException ("Operations limit of $ this ->readOpsLimit exceeded, cannot process any more data " );
83+ }
84+ }
85+ }
86+
87+ /**
88+ * @internal Experimental, may be removed
89+ */
90+ public function getReadOpsLimit () : int {
91+ return $ this ->readOpsLimit ;
92+ }
93+
94+ /**
95+ * @internal Experimental, may be removed
96+ */
97+ public function setReadOpsLimit (int $ readOpsLimit ) : void {
98+ $ this ->readOpsLimit = $ readOpsLimit ;
99+ }
100+
59101 public function getBuffer () : string {
60102 return $ this ->buffer ;
61103 }
@@ -71,6 +113,7 @@ public function get(int $len) : string{
71113 if ($ len < 0 ){
72114 throw new \InvalidArgumentException ("Length must be positive " );
73115 }
116+ $ this ->addReadOps (1 );
74117
75118 $ remaining = strlen ($ this ->buffer ) - $ this ->offset ;
76119 if ($ remaining < $ len ){
@@ -89,6 +132,7 @@ public function getRemaining() : string{
89132 if ($ this ->offset >= $ buflen ){
90133 throw new BinaryDataException ("No bytes left to read " );
91134 }
135+ $ this ->addReadOps (1 );
92136 $ str = substr ($ this ->buffer , $ this ->offset );
93137 $ this ->offset = $ buflen ;
94138 return $ str ;
@@ -305,6 +349,7 @@ public function putLLong(int $v) : void{
305349 * @throws BinaryDataException
306350 */
307351 public function getUnsignedVarInt () : int {
352+ $ this ->addReadOps (5 ); //technically this could be 1-5, but varints are costly in any case
308353 return Binary::readUnsignedVarInt ($ this ->buffer , $ this ->offset );
309354 }
310355
@@ -322,6 +367,7 @@ public function putUnsignedVarInt(int $v) : void{
322367 * @throws BinaryDataException
323368 */
324369 public function getVarInt () : int {
370+ $ this ->addReadOps (5 );
325371 return Binary::readVarInt ($ this ->buffer , $ this ->offset );
326372 }
327373
@@ -339,13 +385,15 @@ public function putVarInt(int $v) : void{
339385 * @throws BinaryDataException
340386 */
341387 public function getUnsignedVarLong () : int {
388+ $ this ->addReadOps (10 );
342389 return Binary::readUnsignedVarLong ($ this ->buffer , $ this ->offset );
343390 }
344391
345392 /**
346393 * Writes a 64-bit variable-length integer to the end of the buffer.
347394 */
348395 public function putUnsignedVarLong (int $ v ) : void {
396+ $ this ->addReadOps (10 );
349397 $ this ->buffer .= Binary::writeUnsignedVarLong ($ v );
350398 }
351399
0 commit comments