001    /**
002     * ========================================
003     * JFreeReport : a free Java report library
004     * ========================================
005     *
006     * Project Info:  http://reporting.pentaho.org/
007     *
008     * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009     *
010     * This library is free software; you can redistribute it and/or modify it under the terms
011     * of the GNU Lesser General Public License as published by the Free Software Foundation;
012     * either version 2.1 of the License, or (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016     * See the GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public License along with this
019     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020     * Boston, MA 02111-1307, USA.
021     *
022     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023     * in the United States and other countries.]
024     *
025     * ------------
026     * $Id: MemoryByteArrayOutputStream.java 3525 2007-10-16 11:43:48Z tmorgner $
027     * ------------
028     * (C) Copyright 2000-2005, by Object Refinery Limited.
029     * (C) Copyright 2005-2007, by Pentaho Corporation.
030     */
031    
032    package org.jfree.report.util;
033    
034    import java.io.IOException;
035    import java.io.OutputStream;
036    
037    import org.jfree.util.Log;
038    
039    /**
040     * A string writer that is able to write large amounts of data. The original StringWriter contained in Java doubles
041     * its buffersize everytime the buffer overflows. This is nice with small amounts of data, but awfull for huge
042     * buffers.
043     *
044     * @author Thomas Morgner
045     */
046    public class MemoryByteArrayOutputStream extends OutputStream
047    {
048      private int initialBufferSize;
049      private int maximumBufferIncrement;
050      private int cursor;
051      private byte[] buffer;
052      private byte[] singleIntArray;
053    
054      /**
055       * Create a new character-stream writer whose critical sections will synchronize on the writer itself.
056       */
057      public MemoryByteArrayOutputStream()
058      {
059        this(4096, 65536);
060      }
061    
062      /**
063       * Create a new character-stream writer whose critical sections will synchronize on the writer itself.
064       */
065      public MemoryByteArrayOutputStream(final int bufferSize, final int maximumBufferIncrement)
066      {
067        this.initialBufferSize = bufferSize;
068        this.maximumBufferIncrement = maximumBufferIncrement;
069        this.buffer = new byte[bufferSize];
070        this.singleIntArray = new byte[1];
071      }
072    
073    
074      /**
075       * Write a portion of an array of characters.
076       *
077       * @param cbuf Array of characters
078       * @param off  Offset from which to start writing characters
079       * @param len  Number of characters to write
080       * @throws java.io.IOException If an I/O error occurs
081       */
082      public synchronized void write(final byte[] cbuf, final int off, final int len) throws IOException
083      {
084        if (len < 0)
085        {
086          throw new IllegalArgumentException();
087        }
088        if (off < 0)
089        {
090          throw new IndexOutOfBoundsException();
091        }
092        if (cbuf == null)
093        {
094          throw new NullPointerException();
095        }
096        if ((len + off) > cbuf.length)
097        {
098          throw new IndexOutOfBoundsException();
099        }
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    }