From ec888611a16b93dca9dfaec3276588570a6330b4 Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Wed, 25 Mar 2026 20:58:53 +0200 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=BD=D0=BE=D0=B6=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20Array.copy=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B8=D1=85=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=BC=D0=BE=D0=B3=D0=BB=D0=B0=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=B2=D0=BE=D0=B4=D0=B8=D1=82=D1=8C=20=D0=BA=20=D0=BF?= =?UTF-8?q?=D0=B0=D0=B4=D0=B5=D0=BD=D0=B8=D1=8E=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/io/orprotocol/Stream.java | 96 +++++++++++++++++++------ 1 file changed, 74 insertions(+), 22 deletions(-) diff --git a/src/main/java/io/orprotocol/Stream.java b/src/main/java/io/orprotocol/Stream.java index c3c212b..c1c01c7 100644 --- a/src/main/java/io/orprotocol/Stream.java +++ b/src/main/java/io/orprotocol/Stream.java @@ -1,5 +1,7 @@ package io.orprotocol; +import java.util.Arrays; + public class Stream { private byte[] stream; @@ -15,11 +17,12 @@ public class Stream { } public byte[] getStream() { - return this.stream; + return Arrays.copyOf(this.stream, length()); } public void setStream(byte[] stream) { this.stream = stream; + this.writePointer = this.stream.length << 3; } public void writeInt8(int value) { @@ -27,13 +30,13 @@ public class Stream { int int8Value = Math.abs(value) & 0xFF; ensureCapacity(writePointer >> 3); - stream[writePointer >> 3] |= (byte)(negationBit << (7 - (writePointer & 7))); + stream[writePointer >> 3] |= (byte) (negationBit << (7 - (writePointer & 7))); writePointer++; for (int i = 0; i < 8; i++) { int bit = (int8Value >> (7 - i)) & 1; ensureCapacity(writePointer >> 3); - stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); + stream[writePointer >> 3] |= (byte) (bit << (7 - (writePointer & 7))); writePointer++; } } @@ -55,7 +58,7 @@ public class Stream { public void writeBit(int value) { int bit = value & 1; ensureCapacity(writePointer >> 3); - stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); + stream[writePointer >> 3] |= (byte) (bit << (7 - (writePointer & 7))); writePointer++; } @@ -94,8 +97,8 @@ public class Stream { } public void writeInt64(long value) { - int high = (int)(value >> 32); - int low = (int)value; + int high = (int) (value >> 32); + int low = (int) value; writeInt32(high); writeInt32(low); } @@ -119,29 +122,47 @@ public class Stream { public void writeString(String value) { int length = value.length(); writeInt32(length); - for (int i = 0; i < value.length(); i++) { + + if (length == 0) { + return; + } + + // writeInt16 -> 2 * writeInt8 -> 18 бит на символ + reserveBits((long) length * 18L); + + for (int i = 0; i < length; i++) { writeInt16(value.charAt(i)); } } public String readString() { int length = readInt32(); - - // Security fix for string length exceeding stream capacity - if (length < 0 || length > (stream.length - (readPointer >> 3))) { - System.out.println("Stream readString length invalid: " + length + ", stream length: " + stream.length + ", readPointer: " + readPointer); + + if (length < 0) { return ""; } - - StringBuilder value = new StringBuilder(); + + // На один символ тратится 18 бит (через writeInt16/readInt16) + long remainingBits = ((long) stream.length << 3) - readPointer; + long requiredBits = (long) length * 18L; + if (requiredBits > remainingBits) { + return ""; + } + + StringBuilder value = new StringBuilder(length); for (int i = 0; i < length; i++) { - value.append((char)readInt16()); + value.append((char) readInt16()); } return value.toString(); } public void writeBytes(byte[] value) { writeInt32(value.length); + + if (value.length > 0) { + reserveBits((long) value.length * 9L); + } + for (int i = 0; i < value.length; i++) { writeInt8(value[i]); } @@ -149,9 +170,13 @@ public class Stream { public byte[] readBytes() { int length = readInt32(); + if (length < 0) { + return new byte[0]; + } + byte[] value = new byte[length]; for (int i = 0; i < length; i++) { - value[i] = (byte)readInt8(); + value[i] = (byte) readInt8(); } return value; } @@ -161,19 +186,46 @@ public class Stream { } public int length() { - return this.stream.length; + return (writePointer + 7) >> 3; } public byte[] getBuffer() { return this.stream; } - private void ensureCapacity(int byteIndex) { - if (byteIndex >= stream.length) { - byte[] newStream = new byte[byteIndex + 1]; - System.arraycopy(stream, 0, newStream, 0, stream.length); - stream = newStream; + private void reserveBits(long bitsToWrite) { + if (bitsToWrite <= 0) { + return; } + + long lastBitIndex = (long) writePointer + bitsToWrite - 1; + if (lastBitIndex < 0) { + throw new IllegalStateException("Bit index overflow"); + } + + long byteIndexLong = lastBitIndex >> 3; + if (byteIndexLong > Integer.MAX_VALUE) { + throw new IllegalStateException("Stream too large"); + } + + ensureCapacity((int) byteIndexLong); } -} + private void ensureCapacity(int byteIndex) { + int requiredSize = byteIndex + 1; + if (requiredSize <= stream.length) { + return; + } + + int newSize = (stream.length == 0) ? 32 : stream.length; + while (newSize < requiredSize) { + if (newSize > (Integer.MAX_VALUE / 2)) { + newSize = requiredSize; + break; + } + newSize <<= 1; + } + + stream = Arrays.copyOf(stream, newSize); + } +} \ No newline at end of file