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 }