blob: 3901a4359c9217b1ae0e7f68362b043a009eac8d [file] [log] [blame]
/*
* Copyright 2003,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.utils;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
/**
* This class implements an output stream in which the data is
* written into a byte array. The buffer automatically grows as data
* is written to it.
* <p>
* The data can be retrieved using <code>toByteArray()</code> and
* <code>toString()</code>.
* <p>
* Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
* <p>
* This is an alternative implementation of the java.io.ByteArrayOutputStream
* class. The original implementation only allocates 32 bytes at the beginning.
* As this class is designed for heavy duty it starts at 1024 bytes. In contrast
* to the original it doesn't reallocate the whole memory block but allocates
* additional buffers. This way no buffers need to be garbage collected and
* the contents don't have to be copied to the new buffer. This class is
* designed to behave exactly like the original. The only exception is the
* deprecated toString(int) method that has been ignored.
*
* @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
*/
public class ByteArrayOutputStream extends OutputStream {
private List buffers = new java.util.ArrayList();
private int currentBufferIndex;
private int filledBufferSum;
private byte[] currentBuffer;
private int count;
/**
* Creates a new byte array output stream. The buffer capacity is
* initially 1024 bytes, though its size increases if necessary.
*/
public ByteArrayOutputStream() {
this(1024);
}
/**
* Creates a new byte array output stream, with a buffer capacity of
* the specified size, in bytes.
*
* @param size the initial size.
* @throws IllegalArgumentException if size is negative.
*/
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException(
Messages.getMessage("illegalArgumentException01",
Integer.toString(size)));
}
needNewBuffer(size);
}
private byte[] getBuffer(int index) {
return (byte[]) buffers.get(index);
}
private void needNewBuffer(int newcount) {
if (currentBufferIndex < buffers.size() - 1) {
//Recycling old buffer
filledBufferSum += currentBuffer.length;
currentBufferIndex++;
currentBuffer = getBuffer(currentBufferIndex);
} else {
//Creating new buffer
int newBufferSize;
if (currentBuffer == null) {
newBufferSize = newcount;
filledBufferSum = 0;
} else {
newBufferSize = Math.max(currentBuffer.length << 1,
newcount - filledBufferSum);
filledBufferSum += currentBuffer.length;
}
currentBufferIndex++;
currentBuffer = new byte[newBufferSize];
buffers.add(currentBuffer);
}
}
/**
* @see java.io.OutputStream#write(byte[], int, int)
*/
public synchronized void write(byte[] b, int off, int len) {
if ((off < 0)
|| (off > b.length)
|| (len < 0)
|| ((off + len) > b.length)
|| ((off + len) < 0)) {
throw new IndexOutOfBoundsException(
Messages.getMessage("indexOutOfBoundsException00"));
} else if (len == 0) {
return;
}
int newcount = count + len;
int remaining = len;
int inBufferPos = count - filledBufferSum;
while (remaining > 0) {
int part = Math.min(remaining, currentBuffer.length - inBufferPos);
System.arraycopy(b, off + len - remaining, currentBuffer,
inBufferPos, part);
remaining -= part;
if (remaining > 0) {
needNewBuffer(newcount);
inBufferPos = 0;
}
}
count = newcount;
}
/**
* Calls the write(byte[]) method.
*
* @see java.io.OutputStream#write(int)
*/
public synchronized void write(int b) {
write(new byte[]{(byte) b}, 0, 1);
}
/**
* @see java.io.ByteArrayOutputStream#size()
*/
public int size() {
return count;
}
/**
* Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
*
* @throws IOException in case an I/O error occurs
*/
public void close() throws IOException {
//nop
}
/**
* @see java.io.ByteArrayOutputStream#reset()
*/
public synchronized void reset() {
count = 0;
filledBufferSum = 0;
currentBufferIndex = 0;
currentBuffer = getBuffer(currentBufferIndex);
}
/**
* @see java.io.ByteArrayOutputStream#writeTo(OutputStream)
*/
public synchronized void writeTo(OutputStream out) throws IOException {
int remaining = count;
for (int i = 0; i < buffers.size(); i++) {
byte[] buf = getBuffer(i);
int c = Math.min(buf.length, remaining);
out.write(buf, 0, c);
remaining -= c;
if (remaining == 0) {
break;
}
}
}
/**
* @see java.io.ByteArrayOutputStream#toByteArray()
*/
public synchronized byte[] toByteArray() {
int remaining = count;
int pos = 0;
byte[] newbuf = new byte[count];
for (int i = 0; i < buffers.size(); i++) {
byte[] buf = getBuffer(i);
int c = Math.min(buf.length, remaining);
System.arraycopy(buf, 0, newbuf, pos, c);
pos += c;
remaining -= c;
if (remaining == 0) {
break;
}
}
return newbuf;
}
/**
* @see java.io.ByteArrayOutputStream#toString()
*/
public String toString() {
return new String(toByteArray());
}
/**
* @see java.io.ByteArrayOutputStream#toString(String)
*/
public String toString(String enc) throws UnsupportedEncodingException {
return new String(toByteArray(), enc);
}
}