/* * SimpleOutputStream * * Author: Lasse Collin <lasse.collin@tukaani.org> * * This file has been put into the public domain. * You can do whatever you want with this file. */ package org.tukaani.xz; import java.io.IOException; import org.tukaani.xz.simple.SimpleFilter; class SimpleOutputStream extends FinishableOutputStream { private static final int FILTER_BUF_SIZE = 4096; private FinishableOutputStream out; private final SimpleFilter simpleFilter; private final byte[] filterBuf = new byte[FILTER_BUF_SIZE]; private int pos = 0; private int unfiltered = 0; private IOException exception = null; private boolean finished = false; private final byte[] tempBuf = new byte[1]; static int getMemoryUsage() { return 1 + FILTER_BUF_SIZE / 1024; } SimpleOutputStream(FinishableOutputStream out, SimpleFilter simpleFilter) { if (out == null) throw new NullPointerException(); this.out = out; this.simpleFilter = simpleFilter; } public void write(int b) throws IOException { tempBuf[0] = (byte)b; write(tempBuf, 0, 1); } public void write(byte[] buf, int off, int len) throws IOException { if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length) throw new IndexOutOfBoundsException(); if (exception != null) throw exception; if (finished) throw new XZIOException("Stream finished or closed"); while (len > 0) { // Copy more unfiltered data into filterBuf. int copySize = Math.min(len, FILTER_BUF_SIZE - (pos + unfiltered)); System.arraycopy(buf, off, filterBuf, pos + unfiltered, copySize); off += copySize; len -= copySize; unfiltered += copySize; // Filter the data in filterBuf. int filtered = simpleFilter.code(filterBuf, pos, unfiltered); assert filtered <= unfiltered; unfiltered -= filtered; // Write out the filtered data. try { out.write(filterBuf, pos, filtered); } catch (IOException e) { exception = e; throw e; } pos += filtered; // If end of filterBuf was reached, move the pending unfiltered // data to the beginning of the buffer so that more data can // be copied into filterBuf on the next loop iteration. if (pos + unfiltered == FILTER_BUF_SIZE) { System.arraycopy(filterBuf, pos, filterBuf, 0, unfiltered); pos = 0; } } } private void writePending() throws IOException { assert !finished; if (exception != null) throw exception; try { out.write(filterBuf, pos, unfiltered); } catch (IOException e) { exception = e; throw e; } finished = true; } public void flush() throws IOException { throw new UnsupportedOptionsException("Flushing is not supported"); } public void finish() throws IOException { if (!finished) { // If it fails, don't call out.finish(). writePending(); try { out.finish(); } catch (IOException e) { exception = e; throw e; } } } public void close() throws IOException { if (out != null) { if (!finished) { // out.close() must be called even if writePending() fails. // writePending() saves the possible exception so we can // ignore exceptions here. try { writePending(); } catch (IOException e) {} } try { out.close(); } catch (IOException e) { // If there is an earlier exception, the exception // from out.close() is lost. if (exception == null) exception = e; } out = null; } if (exception != null) throw exception; } }