From ef9cc3f1d2a5d9bbb903939dc7f7708cfe2252b0 Mon Sep 17 00:00:00 2001
From: Jan Zickermann <jan.zickermann@dataport.de>
Date: Tue, 11 Feb 2025 08:51:43 +0100
Subject: [PATCH] OZG-4097 send-attachment: Add LimitedInputStream

---
 .../osiv2/storage/LimitedInputStream.java     | 39 ++++++++++++++
 .../osiv2/storage/LimitedInputStreamTest.java | 54 +++++++++++++++++++
 2 files changed, 93 insertions(+)
 create mode 100644 src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStream.java
 create mode 100644 src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStreamTest.java

diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStream.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStream.java
new file mode 100644
index 0000000..c4c8ddf
--- /dev/null
+++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStream.java
@@ -0,0 +1,39 @@
+package de.ozgcloud.nachrichten.postfach.osiv2.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public class LimitedInputStream extends InputStream {
+	private final InputStream parentStream;
+	private final int limit;
+	private int readOffset = 0;
+
+	@Override
+	public int read() throws IOException {
+		var buffer = new byte[1];
+		var result = read(buffer, 0, 1);
+		return result < 0 ? result : buffer[0];
+	}
+
+
+	@Override
+	public int read(byte[] buffer, int offset, int length) throws IOException {
+		var remainingLength = limit - readOffset;
+		if (remainingLength > 0) {
+			var readLength = parentStream.read(buffer, offset, Math.min(remainingLength, length));
+			if (readLength > 0) {
+				readOffset += readLength;
+				return readLength;
+			}
+		}
+		return -1;
+	}
+
+	@Override
+	public void close() {
+		// Keep parent stream open
+	}
+}
diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStreamTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStreamTest.java
new file mode 100644
index 0000000..15c1600
--- /dev/null
+++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/storage/LimitedInputStreamTest.java
@@ -0,0 +1,54 @@
+package de.ozgcloud.nachrichten.postfach.osiv2.storage;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import lombok.SneakyThrows;
+
+class LimitedInputStreamTest {
+
+	@DisplayName("should limit input stream")
+	@Test
+	@SneakyThrows
+	void shouldLimitInputStream() {
+		var inputStream = createExampleLimitedInputStream();
+
+		var result = IOUtils.toByteArray(inputStream);
+
+		assertEquals("12345", new String(result));
+	}
+
+	@DisplayName("should read one")
+	@Test
+	@SneakyThrows
+	void shouldReadOne() {
+		var inputStream = createExampleLimitedInputStream();
+
+		var result = inputStream.read();
+
+		assertEquals('1', result);
+	}
+
+	@DisplayName("should keep parent stream usable")
+	@Test
+	@SneakyThrows
+	void shouldKeepParentStreamUsable() {
+		var parentStream = new ByteArrayInputStream("123456789".getBytes());
+		var inputStream = new LimitedInputStream(parentStream, 5);
+		var inputStream2 = new LimitedInputStream(parentStream, 5);
+		IOUtils.toByteArray(inputStream);
+
+		var result = IOUtils.toByteArray(inputStream2);
+
+		assertEquals("6789", new String(result));
+	}
+
+	private LimitedInputStream createExampleLimitedInputStream() {
+		return new LimitedInputStream(new ByteArrayInputStream("123456789".getBytes()), 5);
+	}
+}
\ No newline at end of file
-- 
GitLab