001: /*
002: * Title: FastByteArrayOutputStream
003: * Description:
004: *
005: * This software is published under the terms of the OpenSymphony Software
006: * License version 1.1, of which a copy has been included with this
007: * distribution in the LICENSE.txt file.
008: */
009:
010: package com.opensymphony.module.sitemesh.util;
011:
012: import java.io.ByteArrayOutputStream;
013: import java.io.IOException;
014: import java.io.OutputStream;
015: import java.io.UnsupportedEncodingException;
016: import java.util.Iterator;
017: import java.util.LinkedList;
018:
019: /**
020: * A speedy implementation of ByteArrayOutputStream. It's not synchronized, and it
021: * does not copy buffers when it's expanded. There's also no copying of the internal buffer
022: * if it's contents is extracted with the writeTo(stream) method.
023: *
024: * @author Rickard �berg
025: * @author <a href="mailto:scott@atlassian.com">Scott Farquhar</a>
026: * @version $Revision: 1.2 $
027: */
028: public class FastByteArrayOutputStream extends ByteArrayOutputStream {
029: private static final int DEFAULT_BLOCK_SIZE = 8192;
030:
031: /** Internal buffer. */
032: private byte[] buffer;
033:
034: private LinkedList buffers;
035:
036: private int index;
037: private int size;
038: private int blockSize;
039:
040: public FastByteArrayOutputStream() {
041: this (DEFAULT_BLOCK_SIZE);
042: }
043:
044: public FastByteArrayOutputStream(int aSize) {
045: blockSize = aSize;
046: buffer = new byte[blockSize];
047: }
048:
049: public void writeTo(OutputStream out) throws IOException {
050: // check if we have a list of buffers
051: if (buffers != null) {
052: Iterator iterator = buffers.iterator();
053: while (iterator.hasNext()) {
054: byte[] bytes = (byte[]) iterator.next();
055: out.write(bytes, 0, blockSize);
056: }
057: }
058:
059: // write the internal buffer directly
060: out.write(buffer, 0, index);
061: }
062:
063: public int size() {
064: return size + index;
065: }
066:
067: public byte[] toByteArray() {
068: byte[] data = new byte[size()];
069:
070: // check if we have a list of buffers
071: int pos = 0;
072: if (buffers != null) {
073: Iterator iterator = buffers.iterator();
074: while (iterator.hasNext()) {
075: byte[] bytes = (byte[]) iterator.next();
076: System.arraycopy(bytes, 0, data, pos, blockSize);
077: pos += blockSize;
078: }
079: }
080:
081: // write the internal buffer directly
082: System.arraycopy(buffer, 0, data, pos, index);
083:
084: return data;
085: }
086:
087: public void write(int datum) {
088: if (index == blockSize) {
089: // Create new buffer and store current in linked list
090: if (buffers == null)
091: buffers = new LinkedList();
092:
093: buffers.addLast(buffer);
094:
095: buffer = new byte[blockSize];
096: size += index;
097: index = 0;
098: }
099:
100: // store the byte
101: buffer[index++] = (byte) datum;
102: }
103:
104: public void write(byte[] data, int offset, int length) {
105: if (data == null) {
106: throw new NullPointerException();
107: } else if ((offset < 0) || (offset + length > data.length)
108: || (length < 0)) {
109: throw new IndexOutOfBoundsException();
110: } else {
111: if (index + length >= blockSize) {
112: // Write byte by byte
113: // FIXME optimize this to use arraycopy's instead
114: for (int i = 0; i < length; i++)
115: write(data[offset + i]);
116: } else {
117: // copy in the subarray
118: System.arraycopy(data, offset, buffer, index, length);
119: index += length;
120: }
121: }
122: }
123:
124: public synchronized void reset() {
125: buffer = new byte[blockSize];
126: buffers = null;
127: }
128:
129: public String toString(String enc)
130: throws UnsupportedEncodingException {
131: return new String(toByteArray(), enc);
132: }
133:
134: public String toString() {
135: return new String(toByteArray());
136: }
137:
138: public void flush() throws IOException {
139: // does nothing
140: }
141:
142: public void close() throws IOException {
143: // does nothing
144: }
145: }
|