package org.jf.dexlib2.writer.io; import com.google.common.collect.Lists; import javax.annotation.Nonnull; import java.io.IOException; import java.io.OutputStream; import java.util.List; /** * A deferred output stream that is stored in memory */ public class MemoryDeferredOutputStream extends DeferredOutputStream { private static final int DEFAULT_BUFFER_SIZE = 16 * 1024; private final List<byte[]> buffers = Lists.newArrayList(); private byte[] currentBuffer; private int currentPosition; public MemoryDeferredOutputStream() { this(DEFAULT_BUFFER_SIZE); } public MemoryDeferredOutputStream(int bufferSize) { currentBuffer = new byte[bufferSize]; } @Override public void writeTo(OutputStream output) throws IOException { for (byte[] buffer: buffers) { output.write(buffer); } if (currentPosition > 0) { output.write(currentBuffer, 0, currentPosition); } buffers.clear(); currentPosition = 0; } @Override public void write(int i) throws IOException { if (remaining() == 0) { buffers.add(currentBuffer); currentBuffer = new byte[currentBuffer.length]; currentPosition = 0; } currentBuffer[currentPosition++] = (byte)i; } @Override public void write(byte[] bytes) throws IOException { write(bytes, 0, bytes.length); } @Override public void write(byte[] bytes, int offset, int length) throws IOException { int remaining = remaining(); int written = 0; while (length - written > 0) { int toWrite = Math.min(remaining, (length - written)); System.arraycopy(bytes, offset + written, currentBuffer, currentPosition, toWrite); written += toWrite; currentPosition += toWrite; remaining = remaining(); if (remaining == 0) { buffers.add(currentBuffer); currentBuffer = new byte[currentBuffer.length]; currentPosition = 0; remaining = currentBuffer.length; } } } private int remaining() { return currentBuffer.length - currentPosition; } @Nonnull public static DeferredOutputStreamFactory getFactory() { return getFactory(DEFAULT_BUFFER_SIZE); } @Nonnull public static DeferredOutputStreamFactory getFactory(final int bufferSize) { return new DeferredOutputStreamFactory() { @Override public DeferredOutputStream makeDeferredOutputStream() { return new MemoryDeferredOutputStream(bufferSize); } }; } }