// Path: upload-parser-core/src/main/java/com/github/elopteryx/upload/errors/MultipartException.java
// public class MultipartException extends IOException {
// 
//     /**
//      * Public constructor.
//      * @param message The exception message.
//      */
//     public MultipartException(final String message) {
//         super(message);
//     }
// }


import static java.util.Objects.requireNonNull;
import com.github.elopteryx.upload.errors.MultipartException;
import java.io.IOException;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
        servletInputStream.setReadListener(this);
    }

    /**
     * When an instance of the ReadListener is registered with a ServletInputStream, this method will be invoked
     * by the container the first time when it is possible to read data. Subsequently the container will invoke
     * this method if and only if ServletInputStream.isReady() method has been called and has returned false.
     * @throws IOException if an I/O related error has occurred during processing
     */
    @Override
    public void onDataAvailable() throws IOException {
        while (servletInputStream.isReady() && !servletInputStream.isFinished()) {
            parseCurrentItem();
        }
    }

    /**
     * Parses the servlet stream once. Will switch to a new item
     * if the current one is fully read.
     *
     * @return Whether it should be called again
     * @throws IOException if an I/O related error has occurred during processing
     */
    private boolean parseCurrentItem() throws IOException {
        var count = -1;
        if (!servletInputStream.isFinished()) {
            count = servletInputStream.read(dataBuffer.array());
        }
        if (count == -1) {
            if (!parseState.isComplete()) {
// Path: upload-parser-core/src/main/java/com/github/elopteryx/upload/errors/MultipartException.java
// public class MultipartException extends IOException {
// 
//     /**
//      * Public constructor.
//      * @param message The exception message.
//      */
//     public MultipartException(final String message) {
//         super(message);
//     }
// }


// Path: upload-parser-core/src/main/java/com/github/elopteryx/upload/internal/AsyncUploadParser.java
import static java.util.Objects.requireNonNull;
import com.github.elopteryx.upload.errors.MultipartException;
import java.io.IOException;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;

        servletInputStream.setReadListener(this);
    }

    /**
     * When an instance of the ReadListener is registered with a ServletInputStream, this method will be invoked
     * by the container the first time when it is possible to read data. Subsequently the container will invoke
     * this method if and only if ServletInputStream.isReady() method has been called and has returned false.
     * @throws IOException if an I/O related error has occurred during processing
     */
    @Override
    public void onDataAvailable() throws IOException {
        while (servletInputStream.isReady() && !servletInputStream.isFinished()) {
            parseCurrentItem();
        }
    }

    /**
     * Parses the servlet stream once. Will switch to a new item
     * if the current one is fully read.
     *
     * @return Whether it should be called again
     * @throws IOException if an I/O related error has occurred during processing
     */
    private boolean parseCurrentItem() throws IOException {
        var count = -1;
        if (!servletInputStream.isFinished()) {
            count = servletInputStream.read(dataBuffer.array());
        }
        if (count == -1) {
            if (!parseState.isComplete()) {
                throw new MultipartException("Stream ended unexpectedly!");