aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/ByteBufferInputStreamTest.java152
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java25
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java135
5 files changed, 296 insertions, 18 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/ByteBufferInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/ByteBufferInputStreamTest.java
new file mode 100644
index 0000000000..ec9f96ed96
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/ByteBufferInputStreamTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023, SAP SE and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.util.io;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ByteBufferInputStreamTest {
+
+ private static final byte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+
+ private ByteBuffer buf;
+
+ private ByteBufferInputStream is;
+
+ @Before
+ public void setup() {
+ buf = ByteBuffer.wrap(data);
+ is = new ByteBufferInputStream(buf);
+ }
+
+ @After
+ public void tearDown() {
+ is.close();
+ }
+
+ @Test
+ public void testRead() throws IOException {
+ assertEquals(0x00, is.read());
+ assertEquals(0x01, is.read());
+ assertEquals(0x02, is.read());
+ assertEquals(0x03, is.read());
+ assertEquals(0x04, is.read());
+ assertEquals(0x05, is.read());
+ assertEquals(0x06, is.read());
+ assertEquals(0x07, is.read());
+ assertEquals(0x08, is.read());
+ assertEquals(0x09, is.read());
+ assertEquals(0x0A, is.read());
+ assertEquals(0x0B, is.read());
+ assertEquals(0x0C, is.read());
+ assertEquals(0x0D, is.read());
+ assertEquals(0x0E, is.read());
+ assertEquals(0x0F, is.read());
+ assertEquals(-1, is.read());
+ }
+
+ @Test
+ public void testReadMultiple() throws IOException {
+ byte[] x = new byte[5];
+ int n = is.read(x);
+ assertEquals(5, n);
+ assertArrayEquals(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 }, x);
+ }
+
+ @Test
+ public void testReadMultipleOffset() throws IOException {
+ byte[] x = new byte[7];
+ int n = is.read(x, 4, 3);
+ assertEquals(3, n);
+ assertArrayEquals(
+ new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02 },
+ x);
+ }
+
+ @Test
+ public void testReadAll() throws IOException {
+ byte[] x = is.readAllBytes();
+ assertEquals(16, x.length);
+ assertArrayEquals(data, x);
+ }
+
+ @Test
+ public void testMarkReset() throws IOException {
+ byte[] x = new byte[5];
+ int n = is.read(x);
+ assertEquals(11, is.available());
+ assertTrue(is.markSupported());
+ is.mark(is.available());
+ is.reset();
+ byte[] y = new byte[5];
+ int m = is.read(y);
+ assertEquals(n, m);
+ assertArrayEquals(new byte[] { 0x05, 0x06, 0x07, 0x08, 0x09 }, y);
+ }
+
+ @Test
+ public void testClosed() {
+ is.close();
+ Exception e = assertThrows(IOException.class, () -> is.read());
+ assertEquals(JGitText.get().inputStreamClosed, e.getMessage());
+ }
+
+ @Test
+ public void testReadNBytes() throws IOException {
+ byte[] x = is.readNBytes(4);
+ assertArrayEquals(new byte[] { 0x00, 0x01, 0x02, 0x03 }, x);
+ }
+
+ @Test
+ public void testReadNBytesOffset() throws IOException {
+ byte[] x = new byte[10];
+ Arrays.fill(x, (byte) 0x0F);
+ is.readNBytes(x, 3, 4);
+ assertArrayEquals(new byte[] { 0x0F, 0x0F, 0x0F, 0x00, 0x01, 0x02, 0x03,
+ 0x0F, 0x0F, 0x0F }, x);
+ }
+
+ @Test
+ public void testRead0() throws IOException {
+ byte[] x = new byte[7];
+ int n = is.read(x, 4, 0);
+ assertEquals(0, n);
+
+ is.readAllBytes();
+ n = is.read(x, 4, 3);
+ assertEquals(-1, n);
+ }
+
+ @Test
+ public void testSkip() throws IOException {
+ assertEquals(15, is.skip(15));
+ assertEquals(0x0F, is.read());
+ assertEquals(-1, is.read());
+ }
+
+ @Test
+ public void testSkip0() throws IOException {
+ assertEquals(0, is.skip(0));
+ assertEquals(0x00, is.read());
+ }
+}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index a7a7f18804..6def50b17a 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -389,6 +389,7 @@ initFailedGitDirIsNoDirectory=Cannot set git-dir to ''{0}'' which is not a direc
initFailedNonBareRepoSameDirs=When initializing a non-bare repo with directory {0} and separate git-dir {1} specified both folders should not point to the same location
inMemoryBufferLimitExceeded=In-memory buffer limit exceeded
inputDidntMatchLength=Input did not match supplied length. {0} bytes are missing.
+inputStreamClosed=InputStream was closed
inputStreamMustSupportMark=InputStream must support mark()
integerValueNotInRange=Integer value {0}.{1} = {2} not in range {3}..{4}
integerValueNotInRangeSubSection=Integer value {0}.{1}.{2} = {3} not in range {4}..{5}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index c3b46a315d..6c2c850d7a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -419,6 +419,7 @@ public class JGitText extends TranslationBundle {
/***/ public String initFailedNonBareRepoSameDirs;
/***/ public String inMemoryBufferLimitExceeded;
/***/ public String inputDidntMatchLength;
+ /***/ public String inputStreamClosed;
/***/ public String inputStreamMustSupportMark;
/***/ public String integerValueNotInRange;
/***/ public String integerValueNotInRangeSubSection;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 98d0846612..73a3ddaae7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -15,7 +15,6 @@ package org.eclipse.jgit.treewalk;
import static java.nio.charset.StandardCharsets.UTF_8;
-import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -72,6 +71,7 @@ import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.SystemReader;
import org.eclipse.jgit.util.TemporaryBuffer;
import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
+import org.eclipse.jgit.util.io.ByteBufferInputStream;
import org.eclipse.jgit.util.io.EolStreamTypeUtil;
import org.eclipse.jgit.util.sha1.SHA1;
@@ -407,9 +407,9 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
if (len <= MAXIMUM_FILE_SIZE_TO_READ_FULLY) {
InputStream is = e.openInputStream();
try {
- ByteBuffer rawbuf = IO.readWholeStream(is, (int) len);
- rawbuf = filterClean(rawbuf.array(), rawbuf.limit());
- return rawbuf.limit();
+ ByteBuffer filteredData = IO.readWholeStream(filterClean(is),
+ (int) len);
+ return filteredData.remaining();
} finally {
safeClose(is);
}
@@ -438,10 +438,9 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
if (len <= MAXIMUM_FILE_SIZE_TO_READ_FULLY) {
- ByteBuffer rawbuf = IO.readWholeStream(is, (int) len);
- rawbuf = filterClean(rawbuf.array(), rawbuf.limit());
- canonLen = rawbuf.limit();
- return new ByteArrayInputStream(rawbuf.array(), 0, (int) canonLen);
+ ByteBuffer filteredData = IO.readWholeStream(filterClean(is), (int) len);
+ canonLen = filteredData.remaining();
+ return new ByteBufferInputStream(filteredData);
}
if (getCleanFilterCommand() == null && isBinary(e)) {
@@ -477,16 +476,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
}
- private ByteBuffer filterClean(byte[] src, int n)
- throws IOException {
- InputStream in = new ByteArrayInputStream(src);
- try {
- return IO.readWholeStream(filterClean(in), n);
- } finally {
- safeClose(in);
- }
- }
-
private InputStream filterClean(InputStream in)
throws IOException {
in = EolStreamTypeUtil.wrapInputStream(in,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java
new file mode 100644
index 0000000000..9c00329ba1
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ByteBufferInputStream.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2023, SAP SE and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.InvalidMarkException;
+import java.util.Objects;
+
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * An {@link InputStream} backed by a {@link ByteBuffer}.
+ */
+public class ByteBufferInputStream extends InputStream {
+
+ private ByteBuffer buf;
+
+ /**
+ * Creates a {@link ByteBufferInputStream}
+ *
+ * @param buf
+ * the ByteBuffer backing the stream
+ */
+ public ByteBufferInputStream(@NonNull ByteBuffer buf) {
+ this.buf = buf;
+ }
+
+ @Override
+ public int read() throws IOException {
+ nullCheck();
+ if (buf.hasRemaining()) {
+ return buf.get() & 0xFF;
+ }
+ return -1;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ nullCheck();
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ nullCheck();
+ Objects.checkFromIndexSize(off, len, b.length);
+ if (len == 0) {
+ return 0;
+ }
+ int length = Math.min(buf.remaining(), len);
+ if (length == 0) {
+ return -1;
+ }
+ buf.get(b, off, length);
+ return length;
+ }
+
+ @Override
+ public byte[] readAllBytes() throws IOException {
+ return readNBytes(buf.remaining());
+ }
+
+ @Override
+ public byte[] readNBytes(int len) throws IOException {
+ int l = Math.min(len, buf.remaining());
+ byte[] b = new byte[l];
+ read(b);
+ return b;
+ }
+
+ @Override
+ public int readNBytes(byte[] b, int off, int len) throws IOException {
+ return read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ nullCheck();
+ if (n <= 0) {
+ return 0;
+ }
+ // ByteBuffer index has type int
+ int delta = n > Integer.MAX_VALUE ? buf.remaining()
+ : Math.min((int) n, buf.remaining());
+ buf.position(buf.position() + delta);
+ return delta;
+ }
+
+ @Override
+ public int available() throws IOException {
+ nullCheck();
+ return buf.remaining();
+ }
+
+ @Override
+ public void close() {
+ buf = null;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ buf.mark();
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ try {
+ buf.reset();
+ } catch (InvalidMarkException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ private void nullCheck() throws IOException {
+ if (buf == null) {
+ throw new IOException(JGitText.get().inputStreamClosed);
+ }
+ }
+}