This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git

commit f830a4acdf1d926a251606fdde6fb687c0c9d104
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Sat Nov 9 10:57:24 2024 -0500

    Add support to BOMInputStream for setting a consumer for
    ProxyInputStream.afterRead(int)
---
 src/changes/changes.xml                            |  1 +
 .../apache/commons/io/input/BOMInputStream.java    | 21 +++++++++++----
 .../commons/io/input/BOMInputStreamTest.java       | 31 ++++++++++++++++++++++
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1a2c7ec77..73f3885d8 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -67,6 +67,7 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add IOIntConsumer.</action>
       <action dev="ggregory" type="add" issue="IO-861" due-to="Gary 
Gregory">Add ProxyInputStream.AbstractBuilder. Supports setting a consumer for 
ProxyInputStream.afterRead(int).</action>
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add support to AutoCloseInputStream for setting a consumer for 
ProxyInputStream.afterRead(int).</action>
+      <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add support to BOMInputStream for setting a consumer for 
ProxyInputStream.afterRead(int).</action>
       <!-- UPDATE -->
       <action dev="ggregory" type="update"             due-to="Gary 
Gregory">Bump org.apache.commons:commons-parent from 74 to 78 #670, #676, #679, 
#688.</action>
       <action dev="ggregory" type="update"             due-to="Gary 
Gregory">Bump commons.bytebuddy.version from 1.15.1 to 1.15.10 #672, #673, 
#685, #686, #694, #696, #698.</action>
diff --git a/src/main/java/org/apache/commons/io/input/BOMInputStream.java 
b/src/main/java/org/apache/commons/io/input/BOMInputStream.java
index 73dadaa9a..63c0275e1 100644
--- a/src/main/java/org/apache/commons/io/input/BOMInputStream.java
+++ b/src/main/java/org/apache/commons/io/input/BOMInputStream.java
@@ -27,7 +27,6 @@ import java.util.Objects;
 
 import org.apache.commons.io.ByteOrderMark;
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.build.AbstractStreamBuilder;
 
 /**
  * This class is used to wrap a stream that includes an encoded {@link 
ByteOrderMark} as its first bytes.
@@ -125,7 +124,7 @@ public class BOMInputStream extends ProxyInputStream {
      * @since 2.12.0
      */
     // @formatter:on
-    public static class Builder extends AbstractStreamBuilder<BOMInputStream, 
Builder> {
+    public static class Builder extends AbstractBuilder<BOMInputStream, 
Builder> {
 
         private static final ByteOrderMark[] DEFAULT = { ByteOrderMark.UTF_8 };
 
@@ -165,10 +164,9 @@ public class BOMInputStream extends ProxyInputStream {
          * @throws IOException                   if an I/O error occurs.
          * @see #getInputStream()
          */
-        @SuppressWarnings("resource")
         @Override
         public BOMInputStream get() throws IOException {
-            return new BOMInputStream(getInputStream(), include, 
byteOrderMarks);
+            return new BOMInputStream(this);
         }
 
         /**
@@ -229,6 +227,18 @@ public class BOMInputStream extends ProxyInputStream {
     private boolean markedAtStart;
     private int markFbIndex;
 
+    private BOMInputStream(final Builder builder) throws IOException {
+        super(builder);
+        if (IOUtils.length(builder.byteOrderMarks) == 0) {
+            throw new IllegalArgumentException("No BOMs specified");
+        }
+        this.include = builder.include;
+        final List<ByteOrderMark> list = Arrays.asList(builder.byteOrderMarks);
+        // Sort the BOMs to match the longest BOM first because some BOMs have 
the same starting two bytes.
+        list.sort(ByteOrderMarkLengthComparator);
+        this.boms = list;
+    }
+
     /**
      * Constructs a new BOM InputStream that excludes a {@link 
ByteOrderMark#UTF_8} BOM.
      *
@@ -318,6 +328,7 @@ public class BOMInputStream extends ProxyInputStream {
             // Read first maxBomSize bytes
             for (int i = 0; i < firstBytes.length; i++) {
                 firstBytes[i] = in.read();
+                afterRead(firstBytes[i]);
                 fbLength++;
                 if (firstBytes[i] < 0) {
                     break;
@@ -464,6 +475,7 @@ public class BOMInputStream extends ProxyInputStream {
             }
         }
         final int secondCount = in.read(buf, off, len);
+        afterRead(secondCount);
         return secondCount < 0 ? firstCount > 0 ? firstCount : EOF : 
firstCount + secondCount;
     }
 
@@ -493,7 +505,6 @@ public class BOMInputStream extends ProxyInputStream {
         if (markedAtStart) {
             firstBytes = null;
         }
-
         in.reset();
     }
 
diff --git a/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java 
b/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java
index 350d099d4..2bb22d031 100644
--- a/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java
+++ b/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
@@ -31,12 +32,15 @@ import java.io.InputStream;
 import java.io.Reader;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.commons.io.ByteOrderMark;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.test.CustomIOException;
 import org.apache.commons.lang3.SystemProperties;
 import org.junit.jupiter.api.Test;
 import org.w3c.dom.Document;
@@ -206,6 +210,33 @@ public class BOMInputStreamTest {
         } while (bytes > 0);
     }
 
+    @Test
+    public void testAfterReadConsumer() throws Exception {
+        final byte[] data = { 'A', 'B', 'C', 'D' };
+        final AtomicBoolean boolRef = new AtomicBoolean();
+        // @formatter:off
+        try (InputStream bounded = BOMInputStream.builder()
+                .setInputStream(createUtf8Input(data, true))
+                .setAfterRead(i -> boolRef.set(true))
+                .get()) {
+            IOUtils.consume(bounded);
+        }
+        // @formatter:on
+        assertTrue(boolRef.get());
+        // Throwing
+        final String message = "test exception message";
+        // @formatter:off
+        try (InputStream bounded = BOMInputStream.builder()
+                .setInputStream(createUtf8Input(data, true))
+                .setAfterRead(i -> {
+                    throw new CustomIOException(message);
+                })
+                .get()) {
+            assertEquals(message, assertThrowsExactly(CustomIOException.class, 
() -> IOUtils.consume(bounded)).getMessage());
+        }
+        // @formatter:on
+    }
+
     @Test
     public void testAvailableWithBOMAfterClose() throws Exception {
         final byte[] data = { 'A', 'B', 'C', 'D' };

Reply via email to