garydgregory commented on code in PR #790:
URL: https://github.com/apache/commons-io/pull/790#discussion_r2395537924


##########
src/main/java/org/apache/commons/io/output/NullWriter.java:
##########
@@ -77,17 +79,24 @@ public Writer append(final CharSequence csq) {
     }
 
     /**
-     * Does nothing, like writing to {@code /dev/null}.
+     * Does nothing except argument validation, like writing to {@code 
/dev/null}.
      *
-     * @param csq The character sequence to write.
-     * @param start The index of the first character to write.
-     * @param end  The index of the first character to write (exclusive).
-     * @return this writer.
+     * @param csq   The character sequence from which a subsequence will be
+     *              appended.
+     *              If {@code csq} is {@code null}, it is treated as if it were
+     *              {@code "null"}.
+     * @param start The index of the first character in the subsequence.
+     * @param end   The index of the character following the last character in 
the
+     *              subsequence.
+     * @return {@code this} instance.
+     * @throws IndexOutOfBoundsException If {@code start} or {@code end} are 
negative, {@code end} is
+     *                                   greater than {@code csq.length()}, or 
{@code start} is greater
+     *                                   than {@code end}.
      * @since 2.0
      */
     @Override
     public Writer append(final CharSequence csq, final int start, final int 
end) {
-        //to /dev/null

Review Comment:
   What about moving this comment down below (instead of deleting it) like in 
the other methods with this kind of comment?



##########
src/main/java/org/apache/commons/io/input/ClosedInputStream.java:
##########
@@ -86,6 +86,10 @@ public int read() {
      */
     @Override
     public int read(final byte[] b, final int off, final int len) throws 
IOException {
+        IOUtils.checkFromIndexSize(b, off, len);

Review Comment:
   The class and method Javadoc are out of sync with the code now.
   Javadoc `@throws` IndexOutOfBoundsException is missing.
   



##########
src/main/java/org/apache/commons/io/input/BoundedReader.java:
##########
@@ -121,6 +123,7 @@ public int read() throws IOException {
      */
     @Override
     public int read(final char[] cbuf, final int off, final int len) throws 
IOException {
+        IOUtils.checkFromIndexSize(cbuf, off, len);

Review Comment:
   Javadoc `@throws` IndexOutOfBoundsException is missing.



##########
src/main/java/org/apache/commons/io/input/CharSequenceReader.java:
##########
@@ -209,14 +210,13 @@ public int read() {
      */
     @Override
     public int read(final char[] array, final int offset, final int length) {
+        IOUtils.checkFromIndexSize(array, offset, length);

Review Comment:
   Javadoc `@throws` IndexOutOfBoundsException is missing.



##########
src/main/java/org/apache/commons/io/output/WriterOutputStream.java:
##########
@@ -448,6 +448,7 @@ public void write(final byte[] b) throws IOException {
      */
     @Override
     public void write(final byte[] b, int off, int len) throws IOException {
+        IOUtils.checkFromIndexSize(b, off, len);

Review Comment:
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.



##########
src/main/java/org/apache/commons/io/output/ChunkedOutputStream.java:
##########
@@ -172,6 +172,7 @@ int getChunkSize() {
      */
     @Override
     public void write(final byte[] data, final int srcOffset, final int 
length) throws IOException {
+        IOUtils.checkFromIndexSize(data, srcOffset, length);

Review Comment:
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.



##########
src/main/java/org/apache/commons/io/IOUtils.java:
##########
@@ -406,6 +406,183 @@ private static char[] charArray(final int size) {
         return new char[size];
     }
 
+    /**
+     * Validates that the sub-range {@code [off, off + len)} is within the 
bounds of the given array.
+     *
+     * <p>The range is valid if all of the following hold:</p>
+     * <ul>
+     *   <li>{@code off >= 0}</li>
+     *   <li>{@code len >= 0}</li>
+     *   <li>{@code off + len <= array.length}</li>
+     * </ul>
+     *
+     * <p>If the range is invalid, throws {@link IndexOutOfBoundsException} 
with a descriptive message.</p>
+     *
+     * <p>Typical usage in {@link InputStream#read(byte[], int, int)} and 
{@link OutputStream#write(byte[], int, int)} implementations:</p>
+     *
+     * <pre><code>
+     * public int read(byte[] b, int off, int len) throws IOException {
+     *     IOUtils.checkFromIndexSize(b, off, len);
+     *     if (len == 0) {
+     *         return 0;
+     *     }
+     *     ensureOpen();
+     *     // perform read...
+     * }
+     *
+     * public void write(byte[] b, int off, int len) throws IOException {
+     *     IOUtils.checkFromIndexSize(b, off, len);
+     *     if (len == 0) {
+     *         return;
+     *     }
+     *     ensureOpen();
+     *     // perform write...
+     * }
+     * </code></pre>
+     *
+     * @param array the array against which the range is validated
+     * @param off   the starting offset into the array (inclusive)
+     * @param len   the number of elements to access
+     * @throws NullPointerException      if {@code array} is {@code null}
+     * @throws IndexOutOfBoundsException if the range {@code [off, off + len)} 
is out of bounds for {@code array}
+     * @see InputStream#read(byte[], int, int)
+     * @see OutputStream#write(byte[], int, int)
+     * @since 2.21.0
+     */
+    public static void checkFromIndexSize(final byte[] array, final int off, 
final int len) {
+        checkFromIndexSize(off, len, Objects.requireNonNull(array, "byte 
array").length);
+    }
+
+    /**
+     * Validates that the sub-range {@code [off, off + len)} is within the 
bounds of the given array.
+     *
+     * <p>The range is valid if all of the following hold:</p>
+     * <ul>
+     *   <li>{@code off >= 0}</li>
+     *   <li>{@code len >= 0}</li>
+     *   <li>{@code off + len <= array.length}</li>
+     * </ul>
+     *
+     * <p>If the range is invalid, throws {@link IndexOutOfBoundsException} 
with a descriptive message.</p>
+     *
+     * <p>Typical usage in {@link Reader#read(char[], int, int)} and {@link 
Writer#write(char[], int, int)} implementations:</p>
+     *
+     * <pre><code>
+     * public int read(char[] cbuf, int off, int len) throws IOException {
+     *     ensureOpen();
+     *     IOUtils.checkFromIndexSize(cbuf, off, len);
+     *     if (len == 0) {
+     *         return 0;
+     *     }
+     *     // perform read...
+     * }
+     *
+     * public void write(char[] cbuf, int off, int len) throws IOException {
+     *     ensureOpen();
+     *     IOUtils.checkFromIndexSize(cbuf, off, len);
+     *     if (len == 0) {
+     *         return;
+     *     }
+     *     // perform write...
+     * }
+     * </code></pre>
+     *
+     * @param array the array against which the range is validated
+     * @param off   the starting offset into the array (inclusive)
+     * @param len   the number of characters to access
+     * @throws NullPointerException      if {@code array} is {@code null}
+     * @throws IndexOutOfBoundsException if the range {@code [off, off + len)} 
is out of bounds for {@code array}
+     * @see Reader#read(char[], int, int)
+     * @see Writer#write(char[], int, int)
+     * @since 2.21.0
+     */
+    public static void checkFromIndexSize(final char[] array, final int off, 
final int len) {
+        checkFromIndexSize(off, len, Objects.requireNonNull(array, "char 
array").length);
+    }
+
+    /**
+     * Validates that the sub-range {@code [off, off + len)} is within the 
bounds of the given string.
+     *
+     * <p>The range is valid if all of the following hold:</p>
+     * <ul>
+     *   <li>{@code off >= 0}</li>
+     *   <li>{@code len >= 0}</li>
+     *   <li>{@code off + len <= str.length()}</li>
+     * </ul>
+     *
+     * <p>If the range is invalid, throws {@link IndexOutOfBoundsException} 
with a descriptive message.</p>
+     *
+     * <p>Typical usage in {@link Writer#write(String, int, int)} 
implementations:</p>
+     *
+     * <pre><code>
+     * public void write(String str, int off, int len) throws IOException {
+     *     IOUtils.checkFromIndexSize(str, off, len);
+     *     if (len == 0) {
+     *         return;
+     *     }
+     *     // perform write...
+     * }
+     * </code></pre>
+     *
+     * @param str the string against which the range is validated
+     * @param off the starting offset into the string (inclusive)
+     * @param len the number of characters to write
+     * @throws NullPointerException      if {@code str} is {@code null}
+     * @throws IndexOutOfBoundsException if the range {@code [off, off + len)} 
is out of bounds for {@code str}
+     * @see Writer#write(String, int, int)
+     * @since 2.21.0
+     */
+    public static void checkFromIndexSize(final String str, final int off, 
final int len) {
+        checkFromIndexSize(off, len, Objects.requireNonNull(str, 
"str").length());
+    }
+
+    static void checkFromIndexSize(final int off, final int len, final int 
arrayLength) {
+        if ((off | len | arrayLength) < 0 || arrayLength - len < off) {
+            throw new IndexOutOfBoundsException(String.format("Range [%s, %<s 
+ %s) out of bounds for length %s", off, len, arrayLength));
+        }
+    }
+
+    /**
+     * Validates that the sub-sequence {@code [fromIndex, toIndex)} is within 
the bounds of the given {@link CharSequence}.
+     *
+     * <p>The sub-sequence is valid if all of the following hold:</p>
+     * <ul>
+     *   <li>{@code fromIndex >= 0}</li>
+     *   <li>{@code fromIndex <= toIndex}</li>
+     *   <li>{@code toIndex <= seq.length()}</li>
+     * </ul>
+     *
+     * <p>If {@code seq} is {@code null}, it is treated as the literal string 
{@code "null"} (length {@code 4}).</p>
+     *
+     * <p>If the range is invalid, throws {@link IndexOutOfBoundsException} 
with a descriptive message.</p>
+     *
+     * <p>Typical usage in {@link Appendable#append(CharSequence, int, int)} 
implementations:</p>
+     *
+     * <pre><code>
+     * public Appendable append(CharSequence csq, int start, int end) throws 
IOException {
+     *     IOUtils.checkFromToIndex(csq, start, end);
+     *     // perform append...
+     *     return this;
+     * }
+     * </code></pre>
+     *
+     * @param seq       the character sequence to validate (may be {@code 
null}, treated as {@code "null"})
+     * @param fromIndex the starting index (inclusive)
+     * @param toIndex   the ending index (exclusive)
+     * @throws IndexOutOfBoundsException if the range {@code [fromIndex, 
toIndex)} is out of bounds for {@code seq}
+     * @see Appendable#append(CharSequence, int, int)
+     * @since 2.21.0
+     */
+    public static void checkFromToIndex(final CharSequence seq, final int 
fromIndex, final int toIndex) {
+        checkFromToIndex(fromIndex, toIndex, seq != null ? seq.length() : 4);
+    }
+
+    static void checkFromToIndex(final int fromIndex, final int toIndex, final 
int length) {
+        if (fromIndex < 0 | toIndex < fromIndex | length < toIndex) {

Review Comment:
   Using `|` instead of `||` evaluates everything unneccessarily, see the JRE 
implementation (Java 16-25's 
`jdk.internal.util.Preconditions.checkFromToIndex(long, long, long, 
BiFunction<String, List<Number>, X>)`)



##########
src/main/java/org/apache/commons/io/output/ChunkedWriter.java:
##########
@@ -74,6 +74,7 @@ public ChunkedWriter(final Writer writer, final int 
chunkSize) {
      */
     @Override
     public void write(final char[] data, final int srcOffset, final int 
length) throws IOException {
+        IOUtils.checkFromIndexSize(data, srcOffset, length);

Review Comment:
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.



##########
src/main/java/org/apache/commons/io/input/BOMInputStream.java:
##########
@@ -444,6 +444,10 @@ public int read(final byte[] buf) throws IOException {
      */
     @Override
     public int read(final byte[] buf, int off, int len) throws IOException {
+        IOUtils.checkFromIndexSize(buf, off, len);

Review Comment:
   Javadoc `@throws` IndexOutOfBoundsException is missing.



##########
src/main/java/org/apache/commons/io/input/SequenceReader.java:
##########
@@ -114,9 +115,9 @@ public int read() throws IOException {
      */
     @Override
     public int read(final char[] cbuf, int off, int len) throws IOException {
-        Objects.requireNonNull(cbuf, "cbuf");
-        if (len < 0 || off < 0 || off + len > cbuf.length) {
-            throw new IndexOutOfBoundsException("Array Size=" + cbuf.length + 
", offset=" + off + ", length=" + len);
+        IOUtils.checkFromIndexSize(cbuf, off, len);

Review Comment:
   Either we should inherit the whole Javadoc or add a real Javadoc to document 
`@throws` `IndexOutOfBoundsException`.



##########
src/main/java/org/apache/commons/io/output/XmlStreamWriter.java:
##########
@@ -306,6 +306,7 @@ public String getEncoding() {
      */
     @Override
     public void write(final char[] cbuf, final int off, final int len) throws 
IOException {
+        IOUtils.checkFromIndexSize(cbuf, off, len);

Review Comment:
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.



##########
src/main/java/org/apache/commons/io/input/ReaderInputStream.java:
##########
@@ -456,14 +455,11 @@ public int read(final byte[] b) throws IOException {
      */
     @Override
     public int read(final byte[] array, int off, int len) throws IOException {
-        Objects.requireNonNull(array, "array");
-        if (len < 0 || off < 0 || off + len > array.length) {
-            throw new IndexOutOfBoundsException("Array size=" + array.length + 
", offset=" + off + ", length=" + len);
-        }
-        int read = 0;
+        IOUtils.checkFromIndexSize(array, off, len);

Review Comment:
   Javadoc `@throws` IndexOutOfBoundsException is missing.



##########
src/main/java/org/apache/commons/io/output/AppendableWriter.java:
##########
@@ -124,10 +126,7 @@ public T getAppendable() {
      */
     @Override
     public void write(final char[] cbuf, final int off, final int len) throws 
IOException {
-        Objects.requireNonNull(cbuf, "cbuf");
-        if (len < 0 || off + len > cbuf.length) {
-            throw new IndexOutOfBoundsException("Array Size=" + cbuf.length + 
", offset=" + off + ", length=" + len);
-        }
+        IOUtils.checkFromIndexSize(cbuf, off, len);

Review Comment:
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.



##########
src/main/java/org/apache/commons/io/input/NullInputStream.java:
##########
@@ -292,7 +294,8 @@ public int read(final byte[] bytes) throws IOException {
      */
     @Override
     public int read(final byte[] bytes, final int offset, final int length) 
throws IOException {
-        if (bytes.length == 0 || length == 0) {
+        IOUtils.checkFromIndexSize(bytes, offset, length);

Review Comment:
   k, I am resolving these types of issues (GitHub PR resolving that is).
   But:
   Javadoc `@throws` IndexOutOfBoundsException is missing.
   



##########
src/main/java/org/apache/commons/io/output/ClosedOutputStream.java:
##########
@@ -73,6 +75,7 @@ public void flush() throws IOException {
      */
     @Override
     public void write(final byte b[], final int off, final int len) throws 
IOException {
+        IOUtils.checkFromIndexSize(b, off, len);

Review Comment:
   OK.
   
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.
   



##########
src/main/java/org/apache/commons/io/input/NullReader.java:
##########
@@ -276,6 +278,10 @@ public int read(final char[] chars) throws IOException {
      */
     @Override
     public int read(final char[] chars, final int offset, final int length) 
throws IOException {
+        IOUtils.checkFromIndexSize(chars, offset, length);

Review Comment:
   Javadoc `@throws` IndexOutOfBoundsException is missing.



##########
src/main/java/org/apache/commons/io/output/StringBuilderWriter.java:
##########
@@ -149,9 +151,8 @@ public String toString() {
      */
     @Override
     public void write(final char[] value, final int offset, final int length) {
-        if (value != null) {
-            builder.append(value, offset, length);
-        }
+        IOUtils.checkFromIndexSize(value, offset, length);

Review Comment:
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.



##########
src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java:
##########
@@ -249,6 +250,7 @@ public void write(final byte[] b) throws IOException {
     @SuppressWarnings("resource") // the underlying stream is managed by a 
subclass.
     @Override
     public void write(final byte[] b, final int off, final int len) throws 
IOException {
+        IOUtils.checkFromIndexSize(b, off, len);

Review Comment:
   Javadoc `@throws IndexOutOfBoundsException ...` is missing.



##########
src/main/java/org/apache/commons/io/output/StringBuilderWriter.java:
##########
@@ -149,9 +151,8 @@ public String toString() {
      */
     @Override
     public void write(final char[] value, final int offset, final int length) {
-        if (value != null) {
-            builder.append(value, offset, length);
-        }
+        IOUtils.checkFromIndexSize(value, offset, length);
+        builder.append(value, offset, length);

Review Comment:
   I'd think maintaining the behavior is simpler than creating a possible 
surprise for downstream users. We can always review later. The point of this PR 
is only to use the new API.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to