// Path: upload-parser-core/src/main/java/com/github/elopteryx/upload/UploadContext.java
// public interface UploadContext {
// 
//     /**
//      * Returns the given request object for this parser,
//      * allowing customization during the stages of the
//      * asynchronous processing.
//      *
//      * @return The request object
//      */
//     HttpServletRequest getRequest();
// 
//     /**
//      * Returns the given user object for this parser,
//      * allowing customization during the stages of the
//      * asynchronous processing.
//      *
//      * @param clazz The class used for casting
//      * @param <T> Type parameter
//      * @return The user object, or null if it was not supplied
//      */
//     <T> T getUserObject(Class<T> clazz);
// 
//     /**
//      * Returns the currently processed part stream,
//      * allowing the caller to get available information.
//      *
//      * @return The currently processed part
//      */
//     PartStream getCurrentPart();
// 
//     /**
//      * Returns the currently active output, which was returned
//      * in the latest UploadParser#onPartBegin method. This will
//      * return a null during the part begin stage and might be
//      * null during the error stage.
//      *
//      * @return The latest output provided by the caller
//      */
//     PartOutput getCurrentOutput();
// 
//     /**
//      * Returns the parts which have already been processed. Before
//      * the onPartBegin method is called the current PartStream is
//      * added into the List returned by this method, meaning that
//      * the UploadContext#getCurrentPart will return with the last
//      * element of the list.
//      * @return The list of the processed parts, in the order they are uploaded
//      */
//     List<PartStream> getPartStreams();
// }
// 
// 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 com.github.elopteryx.upload.UploadContext;
import com.github.elopteryx.upload.errors.MultipartException;
import java.io.IOException;
import java.io.InputStream;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
     * @throws ServletException If an error occurred with the servlet
     */
    public UploadContext doBlockingParse() throws IOException, ServletException {
        init();
        try {
            blockingRead();
            if (requestCallback != null) {
                requestCallback.onRequestComplete(context);
            }
        } catch (final Exception e) {
            if (errorCallback != null) {
                errorCallback.onError(context, e);
            }
        }
        return context;
    }

    /**
     * Reads everything from the input stream in a blocking mode. It will
     * throw an exception if the data is malformed, for example
     * it is not closed with the proper characters.
     * @throws IOException If an error occurred with the I/O
     */
    private void blockingRead() throws IOException {
        while (true) {
            final var count = inputStream.read(dataBuffer.array());
            if (count == -1) {
                if (parseState.isComplete()) {
                    break;
                } else {
// Path: upload-parser-core/src/main/java/com/github/elopteryx/upload/UploadContext.java
// public interface UploadContext {
// 
//     /**
//      * Returns the given request object for this parser,
//      * allowing customization during the stages of the
//      * asynchronous processing.
//      *
//      * @return The request object
//      */
//     HttpServletRequest getRequest();
// 
//     /**
//      * Returns the given user object for this parser,
//      * allowing customization during the stages of the
//      * asynchronous processing.
//      *
//      * @param clazz The class used for casting
//      * @param <T> Type parameter
//      * @return The user object, or null if it was not supplied
//      */
//     <T> T getUserObject(Class<T> clazz);
// 
//     /**
//      * Returns the currently processed part stream,
//      * allowing the caller to get available information.
//      *
//      * @return The currently processed part
//      */
//     PartStream getCurrentPart();
// 
//     /**
//      * Returns the currently active output, which was returned
//      * in the latest UploadParser#onPartBegin method. This will
//      * return a null during the part begin stage and might be
//      * null during the error stage.
//      *
//      * @return The latest output provided by the caller
//      */
//     PartOutput getCurrentOutput();
// 
//     /**
//      * Returns the parts which have already been processed. Before
//      * the onPartBegin method is called the current PartStream is
//      * added into the List returned by this method, meaning that
//      * the UploadContext#getCurrentPart will return with the last
//      * element of the list.
//      * @return The list of the processed parts, in the order they are uploaded
//      */
//     List<PartStream> getPartStreams();
// }
// 
// 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/BlockingUploadParser.java
import com.github.elopteryx.upload.UploadContext;
import com.github.elopteryx.upload.errors.MultipartException;
import java.io.IOException;
import java.io.InputStream;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;

     * @throws ServletException If an error occurred with the servlet
     */
    public UploadContext doBlockingParse() throws IOException, ServletException {
        init();
        try {
            blockingRead();
            if (requestCallback != null) {
                requestCallback.onRequestComplete(context);
            }
        } catch (final Exception e) {
            if (errorCallback != null) {
                errorCallback.onError(context, e);
            }
        }
        return context;
    }

    /**
     * Reads everything from the input stream in a blocking mode. It will
     * throw an exception if the data is malformed, for example
     * it is not closed with the proper characters.
     * @throws IOException If an error occurred with the I/O
     */
    private void blockingRead() throws IOException {
        while (true) {
            final var count = inputStream.read(dataBuffer.array());
            if (count == -1) {
                if (parseState.isComplete()) {
                    break;
                } else {
                    throw new MultipartException("Stream ended unexpectedly!");