Source for org.jfree.report.util.MemoryByteArrayOutputStream

   1: /**
   2:  * ========================================
   3:  * JFreeReport : a free Java report library
   4:  * ========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/
   7:  *
   8:  * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  * ------------
  26:  * $Id: MemoryByteArrayOutputStream.java 3525 2007-10-16 11:43:48Z tmorgner $
  27:  * ------------
  28:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  29:  * (C) Copyright 2005-2007, by Pentaho Corporation.
  30:  */
  31: 
  32: package org.jfree.report.util;
  33: 
  34: import java.io.IOException;
  35: import java.io.OutputStream;
  36: 
  37: import org.jfree.util.Log;
  38: 
  39: /**
  40:  * A string writer that is able to write large amounts of data. The original StringWriter contained in Java doubles
  41:  * its buffersize everytime the buffer overflows. This is nice with small amounts of data, but awfull for huge
  42:  * buffers.
  43:  *
  44:  * @author Thomas Morgner
  45:  */
  46: public class MemoryByteArrayOutputStream extends OutputStream
  47: {
  48:   private int initialBufferSize;
  49:   private int maximumBufferIncrement;
  50:   private int cursor;
  51:   private byte[] buffer;
  52:   private byte[] singleIntArray;
  53: 
  54:   /**
  55:    * Create a new character-stream writer whose critical sections will synchronize on the writer itself.
  56:    */
  57:   public MemoryByteArrayOutputStream()
  58:   {
  59:     this(4096, 65536);
  60:   }
  61: 
  62:   /**
  63:    * Create a new character-stream writer whose critical sections will synchronize on the writer itself.
  64:    */
  65:   public MemoryByteArrayOutputStream(final int bufferSize, final int maximumBufferIncrement)
  66:   {
  67:     this.initialBufferSize = bufferSize;
  68:     this.maximumBufferIncrement = maximumBufferIncrement;
  69:     this.buffer = new byte[bufferSize];
  70:     this.singleIntArray = new byte[1];
  71:   }
  72: 
  73: 
  74:   /**
  75:    * Write a portion of an array of characters.
  76:    *
  77:    * @param cbuf Array of characters
  78:    * @param off  Offset from which to start writing characters
  79:    * @param len  Number of characters to write
  80:    * @throws java.io.IOException If an I/O error occurs
  81:    */
  82:   public synchronized void write(final byte[] cbuf, final int off, final int len) throws IOException
  83:   {
  84:     if (len < 0)
  85:     {
  86:       throw new IllegalArgumentException();
  87:     }
  88:     if (off < 0)
  89:     {
  90:       throw new IndexOutOfBoundsException();
  91:     }
  92:     if (cbuf == null)
  93:     {
  94:       throw new NullPointerException();
  95:     }
  96:     if ((len + off) > cbuf.length)
  97:     {
  98:       throw new IndexOutOfBoundsException();
  99:     }
 100: 
 101:     ensureSize (cursor + len);
 102: 
 103:     System.arraycopy(cbuf, off, this.buffer, cursor, len);
 104:     cursor += len;
 105:   }
 106: 
 107:   /**
 108:    * Writes <code>b.length</code> bytes from the specified byte array to this output stream. The general contract for
 109:    * <code>write(b)</code> is that it should have exactly the same effect as the call <code>write(b, 0,
 110:    * b.length)</code>.
 111:    *
 112:    * @param b the data.
 113:    * @throws java.io.IOException if an I/O error occurs.
 114:    * @see java.io.OutputStream#write(byte[], int, int)
 115:    */
 116:   public void write(final byte[] b) throws IOException
 117:   {
 118:     write(b, 0, b.length);
 119:   }
 120: 
 121:   /**
 122:    * Writes the specified byte to this output stream. The general contract for <code>write</code> is that one byte is
 123:    * written to the output stream. The byte to be written is the eight low-order bits of the argument <code>b</code>.
 124:    * The 24 high-order bits of <code>b</code> are ignored.
 125:    * <p/>
 126:    * Subclasses of <code>OutputStream</code> must provide an implementation for this method.
 127:    *
 128:    * @param b the <code>byte</code>.
 129:    * @throws java.io.IOException if an I/O error occurs. In particular, an <code>IOException</code> may be thrown if the
 130:    *                             output stream has been closed.
 131:    */
 132:   public synchronized void write(final int b) throws IOException
 133:   {
 134:     this.singleIntArray[0] = (byte) (0xFF & b);
 135:     write(singleIntArray, 0, 1);
 136:   }
 137: 
 138:   private void ensureSize(final int size)
 139:   {
 140:     if (this.buffer.length >= size)
 141:     {
 142:       return;
 143:     }
 144: 
 145:     final int computedSize = (int) Math.min ((this.buffer.length + 1) * 1.5, this.buffer.length + maximumBufferIncrement);
 146:     final int newSize = Math.max (size, computedSize);
 147:     final byte[] newBuffer = new byte[newSize];
 148:     System.arraycopy(this.buffer, 0, newBuffer, 0, cursor);
 149:     this.buffer = newBuffer;
 150:   }
 151: 
 152:   /**
 153:    * Flush the stream.  If the stream has saved any characters from the various write() methods in a buffer, write them
 154:    * immediately to their intended destination.  Then, if that destination is another character or byte stream, flush
 155:    * it.  Thus one flush() invocation will flush all the buffers in a chain of Writers and OutputStreams.
 156:    * <p/>
 157:    * If the intended destination of this stream is an abstraction provided by the underlying operating system, for
 158:    * example a file, then flushing the stream guarantees only that bytes previously written to the stream are passed to
 159:    * the operating system for writing; it does not guarantee that they are actually written to a physical device such as
 160:    * a disk drive.
 161:    *
 162:    * @throws java.io.IOException If an I/O error occurs
 163:    */
 164:   public void flush() throws IOException
 165:   {
 166:     if ((buffer.length - cursor) > 50000)
 167:     {
 168:       Log.debug("WASTED: " + (buffer.length - cursor));
 169:     }
 170:   }
 171: 
 172:   /**
 173:    * Close the stream, flushing it first.  Once a stream has been closed, further write() or flush() invocations will
 174:    * cause an IOException to be thrown.  Closing a previously-closed stream, however, has no effect.
 175:    *
 176:    * @throws java.io.IOException If an I/O error occurs
 177:    */
 178:   public void close() throws IOException
 179:   {
 180:   }
 181: 
 182:   public synchronized byte[] toByteArray()
 183:   {
 184:     final byte[] retval = new byte[cursor];
 185:     System.arraycopy(buffer, 0, retval, 0, cursor);
 186:     return retval;
 187:   }
 188: 
 189:   public int getLength()
 190:   {
 191:     return cursor;
 192:   }
 193: 
 194:   public byte[] getRaw()
 195:   {
 196:     if ((buffer.length - cursor) > 50000)
 197:     {
 198:       Log.debug("WASTED: " + (buffer.length - cursor) + " Length: " + buffer.length);
 199:     }
 200:     return buffer;
 201:   }
 202: }