package org.stianloader.mrjmania; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.jetbrains.annotations.CheckReturnValue; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Range; /** * Polyfills concerning IO-operations, especially * regarding the {@link InputStream} and {@link OutputStream} classes. */ public class MRJIO { private MRJIO() { throw new UnsupportedOperationException(); } /** * Exhaustively read all bytes inside the given {@link InputStream} {@code in} * and return the read bytes as a byte[]-array. * *
If the given stream is already exhausted, an empty array is returned. * *
After this operation, {@code in} should be considered as exhausted. However, it is not closed. * *
This method is not intended for cases where large amounts of data need to be read. * * @param in The input to read from. * @return The read data. * @throws IOException If it is not possible to read from the input stream. */ public static final byte @NotNull[] readAllBytes(@NotNull InputStream in) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); MRJIO.transferTo(in, baos); return baos.toByteArray(); } /** * Attempt to read at most {@code len} amount of bytes, inserting the values into the byte-array {@code buffer} * starting from offset {@code off}. * *
This method may read fewer than {@code len} bytes if the . See the return value of this method * * @param is The input stream to read data from. * @param buffer The byte-array to write data to. * @param off The offset in the byte-array from which the data should be written to. * @param len The maximum amount of bytes to read. * @return The actually read amount of bytes. * @throws IOException If it is not possible to read from the input stream. */ @Range(from = 0, to = Integer.MAX_VALUE) @CheckReturnValue @Contract(pure = false, mutates = "param1, param2") public static final int readNBytes(@NotNull InputStream is, byte @NotNull[] buffer, @Range(from = 0, to = Integer.MAX_VALUE) int off, @Range(from = 0, to = Integer.MAX_VALUE) int len) throws IOException { if (off < 0) { throw new ArrayIndexOutOfBoundsException("off < 0"); } else if (len < 0) { throw new ArrayIndexOutOfBoundsException("len < 0"); } else if (buffer.length < (off + len)) { throw new ArrayIndexOutOfBoundsException("buffer.length < (off + len)"); } else if (len == 0) { // Per contract no read request should be performed for len = 0 return 0; } int writeOffset = off; for (int read = is.read(buffer, writeOffset, len); len != 0 && read >= 0; read = is.read(buffer, writeOffset, len)) { writeOffset += read; len -= read; } return writeOffset - off; } /** * Transfers the contents of the {@link InputStream} {@code in} to the {@link OutputStream} * {@code out}. * *
After this operation, {@code in} should be considered as exhausted. However, it is not closed. * * @param in The input to transfer. * @param out The target of the transfer. * @return Amount of bytes transfered. * @throws IOException Raised when it is not possible to read from the input stream. */ public static final long transferTo(@NotNull InputStream in, @NotNull OutputStream out) throws IOException { byte[] buffer = new byte[4096]; long transferred = 0; for (int len = in.read(buffer); len >= 0; len = in.read(buffer)) { out.write(buffer, 0, len); transferred += len; } return transferred; } }