Skip to content

Commit 5552d9b

Browse files
committed
fix: apply IOUtils.checkIndexFromSize to all streams
1 parent 659b90b commit 5552d9b

37 files changed

+262
-95
lines changed

src/main/java/org/apache/commons/io/IOUtils.java

Lines changed: 102 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
package org.apache.commons.io;
1919

20+
import static java.util.Objects.requireNonNull;
21+
2022
import java.io.BufferedInputStream;
2123
import java.io.BufferedOutputStream;
2224
import java.io.BufferedReader;
@@ -244,7 +246,7 @@ public class IOUtils {
244246
public static BufferedInputStream buffer(final InputStream inputStream) {
245247
// reject null early on rather than waiting for IO operation to fail
246248
// not checked by BufferedInputStream
247-
Objects.requireNonNull(inputStream, "inputStream");
249+
requireNonNull(inputStream, "inputStream");
248250
return inputStream instanceof BufferedInputStream ?
249251
(BufferedInputStream) inputStream : new BufferedInputStream(inputStream);
250252
}
@@ -263,7 +265,7 @@ public static BufferedInputStream buffer(final InputStream inputStream) {
263265
public static BufferedInputStream buffer(final InputStream inputStream, final int size) {
264266
// reject null early on rather than waiting for IO operation to fail
265267
// not checked by BufferedInputStream
266-
Objects.requireNonNull(inputStream, "inputStream");
268+
requireNonNull(inputStream, "inputStream");
267269
return inputStream instanceof BufferedInputStream ?
268270
(BufferedInputStream) inputStream : new BufferedInputStream(inputStream, size);
269271
}
@@ -281,7 +283,7 @@ public static BufferedInputStream buffer(final InputStream inputStream, final in
281283
public static BufferedOutputStream buffer(final OutputStream outputStream) {
282284
// reject null early on rather than waiting for IO operation to fail
283285
// not checked by BufferedInputStream
284-
Objects.requireNonNull(outputStream, "outputStream");
286+
requireNonNull(outputStream, "outputStream");
285287
return outputStream instanceof BufferedOutputStream ?
286288
(BufferedOutputStream) outputStream : new BufferedOutputStream(outputStream);
287289
}
@@ -300,7 +302,7 @@ public static BufferedOutputStream buffer(final OutputStream outputStream) {
300302
public static BufferedOutputStream buffer(final OutputStream outputStream, final int size) {
301303
// reject null early on rather than waiting for IO operation to fail
302304
// not checked by BufferedInputStream
303-
Objects.requireNonNull(outputStream, "outputStream");
305+
requireNonNull(outputStream, "outputStream");
304306
return outputStream instanceof BufferedOutputStream ?
305307
(BufferedOutputStream) outputStream : new BufferedOutputStream(outputStream, size);
306308
}
@@ -407,35 +409,112 @@ private static char[] charArray(final int size) {
407409
}
408410

409411
/**
410-
* Checks if the sub-range described by an offset and length is valid for an array of the given length.
412+
* Checks if the sub-range described by an offset and length is valid for the given array.
413+
*
414+
* <p>The range is valid if all of the following hold:</p>
415+
* <ul>
416+
* <li>{@code off >= 0}</li>
417+
* <li>{@code len >= 0}</li>
418+
* <li>{@code off + len <= array.length}</li>
419+
* </ul>
420+
*
421+
* <p>If the range is invalid, this method throws an
422+
* {@link IndexOutOfBoundsException} with a descriptive message.</p>
423+
*
424+
* @param array The array to be checked against
425+
* @param off The starting offset into the array
426+
* @param len The number of elements in the range
427+
* @throws NullPointerException If the array is null
428+
* @throws IndexOutOfBoundsException If the range {@code [off, off + len)} is out of bounds
429+
* @since 2.21.0
430+
*/
431+
public static void checkFromIndexSize(final byte[] array, final int off, final int len) {
432+
checkFromIndexSize(off, len, requireNonNull(array, "byte array").length);
433+
}
434+
435+
/**
436+
* Checks if the sub-range described by an offset and length is valid for the given array.
437+
*
438+
* <p>The range is valid if all of the following hold:</p>
439+
* <ul>
440+
* <li>{@code off >= 0}</li>
441+
* <li>{@code len >= 0}</li>
442+
* <li>{@code off + len <= array.length}</li>
443+
* </ul>
444+
*
445+
* <p>If the range is invalid, this method throws an
446+
* {@link IndexOutOfBoundsException} with a descriptive message.</p>
411447
*
412-
* <p>This method is functionally equivalent to
413-
* {@code java.util.Objects#checkFromIndexSize(int, int, int)} introduced in Java 9,
414-
* but is provided here for use on Java 8.</p>
448+
* @param array The array to be checked against
449+
* @param off The starting offset into the array
450+
* @param len The number of elements in the range
451+
* @throws NullPointerException If the array is null
452+
* @throws IndexOutOfBoundsException If the range {@code [off, off + len)} is out of bounds
453+
* @since 2.21.0
454+
*/
455+
public static void checkFromIndexSize(final char[] array, final int off, final int len) {
456+
checkFromIndexSize(off, len, requireNonNull(array, "char array").length);
457+
}
458+
459+
/**
460+
* Checks if the sub-range described by an offset and length is valid for the given string.
415461
*
416462
* <p>The range is valid if all of the following hold:</p>
417463
* <ul>
418464
* <li>{@code off >= 0}</li>
419465
* <li>{@code len >= 0}</li>
420-
* <li>{@code arrayLength >= 0}</li>
421-
* <li>{@code off + len <= arrayLength}</li>
466+
* <li>{@code off + len <= array.length}</li>
422467
* </ul>
423468
*
424469
* <p>If the range is invalid, this method throws an
425470
* {@link IndexOutOfBoundsException} with a descriptive message.</p>
426471
*
427-
* @param off the starting offset into the array
428-
* @param len the number of elements in the range
429-
* @param arrayLength the length of the array to be checked against
430-
* @throws IndexOutOfBoundsException if the range {@code [off, off + len)} is out of bounds
472+
* @param str The char sequence to be checked against
473+
* @param off The starting offset into the array
474+
* @param len The number of elements in the range
475+
* @throws NullPointerException If the array is null
476+
* @throws IndexOutOfBoundsException If the range {@code [off, off + len)} is out of bounds
431477
* @since 2.21.0
432478
*/
433-
public static void checkFromIndexSize(final int off, final int len, final int arrayLength) {
479+
public static void checkFromIndexSize(final String str, final int off, final int len) {
480+
checkFromIndexSize(off, len, requireNonNull(str, "str").length());
481+
}
482+
483+
static void checkFromIndexSize(final int off, final int len, final int arrayLength) {
434484
if ((off | len | arrayLength) < 0 || arrayLength - len < off) {
435485
throw new IndexOutOfBoundsException(String.format("Range [%s, %<s + %s) out of bounds for length %s", off, len, arrayLength));
436486
}
437487
}
438488

489+
/**
490+
* Checks if the sub-sequence described by fromIndex (inclusive) and toIndex (exclusive) is valid for the given {@link CharSequence}.
491+
*
492+
* <p>The range is valid if all of the following hold:</p>
493+
* <ul>
494+
* <li>{@code fromIndex >= 0}</li>
495+
* <li>{@code fromIndex <= toIndex}</li>
496+
* <li>{@code toIndex <= seq.length()}</li>
497+
* </ul>
498+
*
499+
* <p>If the range is invalid, this method throws an {@link IndexOutOfBoundsException} with a descriptive message.</p>
500+
*
501+
* @param seq The char sequence to be checked against
502+
* @param fromIndex The starting index into the char sequence (inclusive)
503+
* @param toIndex The ending index into the char sequence (exclusive)
504+
* @throws NullPointerException If the char sequence is null
505+
* @throws IndexOutOfBoundsException If the range {@code [fromIndex, toIndex)} is out of bounds
506+
* @since 2.21.0
507+
*/
508+
public static void checkFromToIndex(final CharSequence seq, int fromIndex, final int toIndex) {
509+
checkFromToIndex(fromIndex, toIndex, requireNonNull(seq, "char sequence").length());
510+
}
511+
512+
static void checkFromToIndex(final int fromIndex, final int toIndex, final int length) {
513+
if (fromIndex < 0 | toIndex < fromIndex | length < toIndex) {
514+
throw new IndexOutOfBoundsException(String.format("Range [%s, %s) out of bounds for length %s", fromIndex, toIndex, length));
515+
}
516+
}
517+
439518
/**
440519
* Clears any state.
441520
* <ul>
@@ -1217,7 +1296,7 @@ public static void copy(final InputStream input, final Writer writer, final Stri
12171296
*/
12181297
@SuppressWarnings("resource") // streams are closed by the caller.
12191298
public static QueueInputStream copy(final java.io.ByteArrayOutputStream outputStream) throws IOException {
1220-
Objects.requireNonNull(outputStream, "outputStream");
1299+
requireNonNull(outputStream, "outputStream");
12211300
final QueueInputStream in = new QueueInputStream();
12221301
outputStream.writeTo(in.newQueueOutputStream());
12231302
return in;
@@ -1398,7 +1477,7 @@ public static int copy(final Reader reader, final Writer writer) throws IOExcept
13981477
* @since 2.9.0
13991478
*/
14001479
public static long copy(final URL url, final File file) throws IOException {
1401-
try (OutputStream outputStream = Files.newOutputStream(Objects.requireNonNull(file, "file").toPath())) {
1480+
try (OutputStream outputStream = Files.newOutputStream(requireNonNull(file, "file").toPath())) {
14021481
return copy(url, outputStream);
14031482
}
14041483
}
@@ -1421,7 +1500,7 @@ public static long copy(final URL url, final File file) throws IOException {
14211500
* @since 2.9.0
14221501
*/
14231502
public static long copy(final URL url, final OutputStream outputStream) throws IOException {
1424-
try (InputStream inputStream = Objects.requireNonNull(url, "url").openStream()) {
1503+
try (InputStream inputStream = requireNonNull(url, "url").openStream()) {
14251504
return copyLarge(inputStream, outputStream);
14261505
}
14271506
}
@@ -1470,8 +1549,8 @@ public static long copyLarge(final InputStream inputStream, final OutputStream o
14701549
@SuppressWarnings("resource") // streams are closed by the caller.
14711550
public static long copyLarge(final InputStream inputStream, final OutputStream outputStream, final byte[] buffer)
14721551
throws IOException {
1473-
Objects.requireNonNull(inputStream, "inputStream");
1474-
Objects.requireNonNull(outputStream, "outputStream");
1552+
requireNonNull(inputStream, "inputStream");
1553+
requireNonNull(outputStream, "outputStream");
14751554
long count = 0;
14761555
int n;
14771556
while (EOF != (n = inputStream.read(buffer))) {
@@ -2739,7 +2818,7 @@ public static byte[] toByteArray(final InputStream inputStream) throws IOExcepti
27392818
* @since 2.1
27402819
*/
27412820
public static byte[] toByteArray(final InputStream input, final int size) throws IOException {
2742-
return toByteArray(Objects.requireNonNull(input, "input")::read, size);
2821+
return toByteArray(requireNonNull(input, "input")::read, size);
27432822
}
27442823

27452824
/**
@@ -2765,7 +2844,7 @@ public static byte[] toByteArray(final InputStream input, final int size) throws
27652844
* @since 2.21.0
27662845
*/
27672846
public static byte[] toByteArray(final InputStream input, final int size, final int chunkSize) throws IOException {
2768-
Objects.requireNonNull(input, "input");
2847+
requireNonNull(input, "input");
27692848
if (chunkSize <= 0) {
27702849
throw new IllegalArgumentException("Chunk size must be greater than zero: " + chunkSize);
27712850
}
@@ -3913,7 +3992,7 @@ public static void writeLines(final Collection<?> lines, String lineEnding, fina
39133992
* @since 2.7
39143993
*/
39153994
public static Writer writer(final Appendable appendable) {
3916-
Objects.requireNonNull(appendable, "appendable");
3995+
requireNonNull(appendable, "appendable");
39173996
if (appendable instanceof Writer) {
39183997
return (Writer) appendable;
39193998
}

src/main/java/org/apache/commons/io/input/BOMInputStream.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,10 @@ public int read(final byte[] buf) throws IOException {
444444
*/
445445
@Override
446446
public int read(final byte[] buf, int off, int len) throws IOException {
447+
IOUtils.checkFromIndexSize(buf, off, len);
448+
if (len == 0) {
449+
return 0;
450+
}
447451
int firstCount = 0;
448452
int b = 0;
449453
while (len > 0 && b >= 0) {

src/main/java/org/apache/commons/io/input/BoundedReader.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.io.IOException;
2424
import java.io.Reader;
2525

26+
import org.apache.commons.io.IOUtils;
27+
2628
/**
2729
* A reader that imposes a limit to the number of characters that can be read from an underlying reader, returning EOF
2830
* when this limit is reached, regardless of state of underlying reader.
@@ -121,6 +123,7 @@ public int read() throws IOException {
121123
*/
122124
@Override
123125
public int read(final char[] cbuf, final int off, final int len) throws IOException {
126+
IOUtils.checkFromIndexSize(cbuf, off, len);
124127
int c;
125128
for (int i = 0; i < len; i++) {
126129
c = read();

src/main/java/org/apache/commons/io/input/BrokenReader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.Reader;
2121
import java.util.function.Supplier;
2222

23+
import org.apache.commons.io.IOUtils;
2324
import org.apache.commons.io.function.Erase;
2425

2526
/**
@@ -114,6 +115,10 @@ public void mark(final int readAheadLimit) throws IOException {
114115
*/
115116
@Override
116117
public int read(final char[] cbuf, final int off, final int len) throws IOException {
118+
IOUtils.checkFromIndexSize(cbuf, off, len);
119+
if (len == 0) {
120+
return 0;
121+
}
117122
throw rethrow();
118123
}
119124

src/main/java/org/apache/commons/io/input/BufferedFileChannelInputStream.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,9 @@ public synchronized int read() throws IOException {
254254

255255
@Override
256256
public synchronized int read(final byte[] b, final int offset, int len) throws IOException {
257-
if (offset < 0 || len < 0 || offset + len < 0 || offset + len > b.length) {
258-
throw new IndexOutOfBoundsException();
257+
IOUtils.checkFromIndexSize(b, offset, len);
258+
if (len == 0) {
259+
return 0;
259260
}
260261
if (!refill()) {
261262
return EOF;

src/main/java/org/apache/commons/io/input/CharSequenceInputStream.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.nio.charset.CharsetEncoder;
2929
import java.nio.charset.CoderResult;
3030
import java.nio.charset.CodingErrorAction;
31-
import java.util.Objects;
3231

3332
import org.apache.commons.io.Charsets;
3433
import org.apache.commons.io.IOUtils;
@@ -319,10 +318,7 @@ public int read(final byte[] b) throws IOException {
319318

320319
@Override
321320
public int read(final byte[] array, int off, int len) throws IOException {
322-
Objects.requireNonNull(array, "array");
323-
if (len < 0 || off + len > array.length) {
324-
throw new IndexOutOfBoundsException("Array Size=" + array.length + ", offset=" + off + ", length=" + len);
325-
}
321+
IOUtils.checkFromIndexSize(array, off, len);
326322
if (len == 0) {
327323
return 0; // must return 0 for zero length read
328324
}

src/main/java/org/apache/commons/io/input/CharSequenceReader.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
import java.io.Reader;
2222
import java.io.Serializable;
23-
import java.util.Objects;
23+
24+
import org.apache.commons.io.IOUtils;
2425

2526
/**
2627
* {@link Reader} implementation that can read from String, StringBuffer,
@@ -209,14 +210,13 @@ public int read() {
209210
*/
210211
@Override
211212
public int read(final char[] array, final int offset, final int length) {
213+
IOUtils.checkFromIndexSize(array, offset, length);
214+
if (length == 0) {
215+
return 0;
216+
}
212217
if (idx >= end()) {
213218
return EOF;
214219
}
215-
Objects.requireNonNull(array, "array");
216-
if (length < 0 || offset < 0 || offset + length > array.length) {
217-
throw new IndexOutOfBoundsException("Array Size=" + array.length +
218-
", offset=" + offset + ", length=" + length);
219-
}
220220

221221
if (charSequence instanceof String) {
222222
final int count = Math.min(length, end() - idx);

src/main/java/org/apache/commons/io/input/ClosedInputStream.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ public int read() {
8686
*/
8787
@Override
8888
public int read(final byte[] b, final int off, final int len) throws IOException {
89+
IOUtils.checkFromIndexSize(b, off, len);
90+
if (len == 0) {
91+
return 0;
92+
}
8993
return EOF;
9094
}
9195

src/main/java/org/apache/commons/io/input/ClosedReader.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ public void close() throws IOException {
7171
*/
7272
@Override
7373
public int read(final char[] cbuf, final int off, final int len) {
74+
IOUtils.checkFromIndexSize(cbuf, off, len);
75+
if (len == 0) {
76+
return 0;
77+
}
7478
return EOF;
7579
}
7680

src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.nio.file.Path;
2828
import java.nio.file.StandardOpenOption;
2929

30+
import org.apache.commons.io.IOUtils;
3031
import org.apache.commons.io.build.AbstractStreamBuilder;
3132

3233
/**
@@ -216,6 +217,10 @@ public int read() throws IOException {
216217

217218
@Override
218219
public int read(final byte[] b, final int off, final int len) throws IOException {
220+
IOUtils.checkFromIndexSize(b, off, len);
221+
if (len == 0) {
222+
return 0;
223+
}
219224
checkOpen();
220225
if (!buffer.hasRemaining()) {
221226
nextBuffer();

0 commit comments

Comments
 (0)