199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverpackage org.jf.dexlib2.writer.io;
299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverimport com.google.common.collect.Lists;
499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverimport javax.annotation.Nonnull;
699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverimport java.io.IOException;
799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverimport java.io.OutputStream;
899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverimport java.util.List;
999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
1099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver/**
1199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver * A deferred output stream that is stored in memory
1299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver */
1399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverpublic class MemoryDeferredOutputStream extends DeferredOutputStream {
1499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    private static final int DEFAULT_BUFFER_SIZE = 16 * 1024;
1599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
1699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    private final List<byte[]> buffers = Lists.newArrayList();
1799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    private byte[] currentBuffer;
1899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    private int currentPosition;
1999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
2099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    public MemoryDeferredOutputStream() {
2199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        this(DEFAULT_BUFFER_SIZE);
2299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
2399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
2499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    public MemoryDeferredOutputStream(int bufferSize) {
2599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        currentBuffer = new byte[bufferSize];
2699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
2799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
2899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    @Override public void writeTo(OutputStream output) throws IOException {
2999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        for (byte[] buffer: buffers) {
3099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            output.write(buffer);
3199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        }
3299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        if (currentPosition > 0) {
3399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            output.write(currentBuffer, 0, currentPosition);
3499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        }
3599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        buffers.clear();
3699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        currentPosition = 0;
3799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
3899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
3999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    @Override public void write(int i) throws IOException {
4099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        if (remaining() == 0) {
4199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            buffers.add(currentBuffer);
4299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            currentBuffer = new byte[currentBuffer.length];
4399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            currentPosition = 0;
4499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        }
4599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        currentBuffer[currentPosition++] = (byte)i;
4699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
4799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
4899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    @Override public void write(byte[] bytes) throws IOException {
4999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        write(bytes, 0, bytes.length);
5099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
5199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
5299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    @Override public void write(byte[] bytes, int offset, int length) throws IOException {
5399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        int remaining = remaining();
5499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        int written = 0;
5599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        while (length - written > 0) {
569a2de93a998958e582e9c2aa0bff7de602cc8771Ben Gruver            int toWrite = Math.min(remaining, (length - written));
5799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            System.arraycopy(bytes, offset + written, currentBuffer, currentPosition, toWrite);
5899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            written += toWrite;
5999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            currentPosition += toWrite;
6099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
6199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            remaining = remaining();
6299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            if (remaining == 0) {
6399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                buffers.add(currentBuffer);
6499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                currentBuffer = new byte[currentBuffer.length];
6599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                currentPosition = 0;
6699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                remaining = currentBuffer.length;
6799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            }
6899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        }
6999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
7099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
7199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    private int remaining() {
7299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        return currentBuffer.length - currentPosition;
7399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
7499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
7599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    @Nonnull
7699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    public static DeferredOutputStreamFactory getFactory() {
7799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        return getFactory(DEFAULT_BUFFER_SIZE);
7899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
7999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver
8099b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    @Nonnull
8199b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    public static DeferredOutputStreamFactory getFactory(final int bufferSize) {
8299b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        return new DeferredOutputStreamFactory() {
8399b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            @Override public DeferredOutputStream makeDeferredOutputStream() {
8499b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                return new MemoryDeferredOutputStream(bufferSize);
8599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            }
8699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver        };
8799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver    }
8899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver}
89