content: package net.csdn.modules.compress.lzf;
  
  import java.io.IOException;
  import java.io.OutputStream;
  
  /**
   * @author jon hartlaub
   * @author tatu
   */
  public class LZFOutputStream extends OutputStream {
      private static int OUTPUT_BUFFER_SIZE = LZFChunk.MAX_CHUNK_LEN;
  
      private final ChunkEncoder _encoder;
      private final BufferRecycler _recycler;
  
      protected final OutputStream _outputStream;
      protected byte[] _outputBuffer;
      protected int _position = 0;
  
      public LZFOutputStream(final OutputStream outputStream) {
          _recycler = BufferRecycler.instance();
          _encoder = new ChunkEncoder(OUTPUT_BUFFER_SIZE, _recycler);
          _outputStream = outputStream;
          _outputBuffer = _recycler.allocOutputBuffer(OUTPUT_BUFFER_SIZE);
      }
  
      @Override
      public void write(final int singleByte) throws IOException {
          if (_position >= _outputBuffer.length) {
              writeCompressedBlock();
          }
          _outputBuffer[_position++] = (byte) singleByte;
      }
  
      @Override
      public void write(final byte[] buffer, int offset, int length) throws IOException {
          final int BUFFER_LEN = _outputBuffer.length;
  
          // simple case first: buffering only (for trivially short writes)
          int free = BUFFER_LEN - _position;
          if (free >= length) {
              System.arraycopy(buffer, offset, _outputBuffer, _position, length);
              _position += length;
              return;
          }
          // otherwise, copy whatever we can, flush
          System.arraycopy(buffer, offset, _outputBuffer, _position, free);
          offset += free;
          length -= free;
          _position += free;
          writeCompressedBlock();
  
          // then write intermediate full block, if any, without copying:
          while (length >= BUFFER_LEN) {
              _encoder.encodeAndWriteChunk(buffer, offset, BUFFER_LEN, _outputStream);
              offset += BUFFER_LEN;
              length -= BUFFER_LEN;
          }
  
          // and finally, copy leftovers in buffer, if any
          if (length > 0) {
              System.arraycopy(buffer, offset, _outputBuffer, 0, length);
          }
          _position = length;
      }
  
      @Override
      public void flush() throws IOException {
          if (_position > 0) {
              writeCompressedBlock();
          }
          _outputStream.flush();
      }
  
      @Override
      public void close() throws IOException {
          flush();
          _outputStream.close();
          _encoder.close();
          byte[] buf = _outputBuffer;
          if (buf != null) {
              _outputBuffer = null;
              _recycler.releaseOutputBuffer(buf);
          }
      }
  
      /**
       * Compress and write the current block to the OutputStream
       */
      private void writeCompressedBlock() throws IOException {
          int left = _position;
          _position = 0;
          int offset = 0;
  
          do {
              int chunkLen = Math.min(LZFChunk.MAX_CHUNK_LEN, left);
              _encoder.encodeAndWriteChunk(_outputBuffer, 0, chunkLen, _outputStream);
              offset += chunkLen;
              left -= chunkLen;
          } while (left > 0);
      }
  }
  