1 package org.jf.dexlib2.writer.io; 2 3 import com.google.common.io.ByteStreams; 4 5 import javax.annotation.Nonnull; 6 import javax.annotation.Nullable; 7 import java.io.*; 8 9 /** 10 * A deferred output stream that uses a file as its backing store, with a in-memory intermediate buffer. 11 */ 12 public class FileDeferredOutputStream extends DeferredOutputStream { 13 private static final int DEFAULT_BUFFER_SIZE = 4 * 1024; 14 15 @Nonnull private final File backingFile; 16 @Nonnull private final NakedBufferedOutputStream output; 17 private int writtenBytes; 18 FileDeferredOutputStream(@onnull File backingFile)19 public FileDeferredOutputStream(@Nonnull File backingFile) throws FileNotFoundException { 20 this(backingFile, DEFAULT_BUFFER_SIZE); 21 } 22 FileDeferredOutputStream(@onnull File backingFile, int bufferSize)23 public FileDeferredOutputStream(@Nonnull File backingFile, int bufferSize) throws FileNotFoundException { 24 this.backingFile = backingFile; 25 output = new NakedBufferedOutputStream(new FileOutputStream(backingFile), bufferSize); 26 } 27 writeTo(@onnull OutputStream dest)28 @Override public void writeTo(@Nonnull OutputStream dest) throws IOException { 29 byte[] outBuf = output.getBuffer(); 30 int count = output.getCount(); 31 output.resetBuffer(); 32 output.close(); 33 34 // did we actually write something out to disk? 35 if (count != writtenBytes) { 36 InputStream fis = new FileInputStream(backingFile); 37 ByteStreams.copy(fis, dest); 38 backingFile.delete(); 39 } 40 41 dest.write(outBuf, 0, count); 42 } 43 write(int i)44 @Override public void write(int i) throws IOException { 45 output.write(i); 46 writtenBytes++; 47 } 48 write(byte[] bytes)49 @Override public void write(byte[] bytes) throws IOException { 50 output.write(bytes); 51 writtenBytes += bytes.length; 52 } 53 write(byte[] bytes, int off, int len)54 @Override public void write(byte[] bytes, int off, int len) throws IOException { 55 output.write(bytes, off, len); 56 writtenBytes += len; 57 } 58 flush()59 @Override public void flush() throws IOException { 60 output.flush(); 61 } 62 close()63 @Override public void close() throws IOException { 64 output.close(); 65 } 66 67 private static class NakedBufferedOutputStream extends BufferedOutputStream { NakedBufferedOutputStream(OutputStream outputStream)68 public NakedBufferedOutputStream(OutputStream outputStream) { 69 super(outputStream); 70 } 71 NakedBufferedOutputStream(OutputStream outputStream, int i)72 public NakedBufferedOutputStream(OutputStream outputStream, int i) { 73 super(outputStream, i); 74 } 75 getCount()76 public int getCount() { 77 return count; 78 } 79 resetBuffer()80 public void resetBuffer() { 81 count = 0; 82 } 83 getBuffer()84 public byte[] getBuffer() { 85 return buf; 86 } 87 } 88 89 @Nonnull getFactory(@ullable File containingDirectory)90 public static DeferredOutputStreamFactory getFactory(@Nullable File containingDirectory) { 91 return getFactory(containingDirectory, DEFAULT_BUFFER_SIZE); 92 } 93 94 @Nonnull getFactory(@ullable final File containingDirectory, final int bufferSize)95 public static DeferredOutputStreamFactory getFactory(@Nullable final File containingDirectory, 96 final int bufferSize) { 97 return new DeferredOutputStreamFactory() { 98 @Override public DeferredOutputStream makeDeferredOutputStream() throws IOException { 99 File tempFile = File.createTempFile("dexlibtmp", null, containingDirectory); 100 return new FileDeferredOutputStream(tempFile, bufferSize); 101 } 102 }; 103 } 104 } 105