View Javadoc

1   /*
2    * $Id: FastByteArrayOutputStream.java 471756 2006-11-06 15:01:43Z husted $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts2.util;
22  
23  import java.io.IOException;
24  import java.io.OutputStream;
25  import java.io.RandomAccessFile;
26  import java.io.Writer;
27  import java.util.Iterator;
28  import java.util.LinkedList;
29  
30  
31  /***
32   * A speedy implementation of ByteArrayOutputStream. It's not synchronized, and it
33   * does not copy buffers when it's expanded. There's also no copying of the internal buffer
34   * if it's contents is extracted with the writeTo(stream) method.
35   *
36   */
37  public class FastByteArrayOutputStream extends OutputStream {
38  
39      // Static --------------------------------------------------------
40      private static final int DEFAULT_BLOCK_SIZE = 8192;
41  
42  
43      private LinkedList buffers;
44  
45      // Attributes ----------------------------------------------------
46      // internal buffer
47      private byte[] buffer;
48  
49      // is the stream closed?
50      private boolean closed;
51      private int blockSize;
52      private int index;
53      private int size;
54  
55  
56      // Constructors --------------------------------------------------
57      public FastByteArrayOutputStream() {
58          this(DEFAULT_BLOCK_SIZE);
59      }
60  
61      public FastByteArrayOutputStream(int aSize) {
62          blockSize = aSize;
63          buffer = new byte[blockSize];
64      }
65  
66  
67      public int getSize() {
68          return size + index;
69      }
70  
71      public void close() {
72          closed = true;
73      }
74  
75      public byte[] toByteArray() {
76          byte[] data = new byte[getSize()];
77  
78          // Check if we have a list of buffers
79          int pos = 0;
80  
81          if (buffers != null) {
82              Iterator iter = buffers.iterator();
83  
84              while (iter.hasNext()) {
85                  byte[] bytes = (byte[]) iter.next();
86                  System.arraycopy(bytes, 0, data, pos, blockSize);
87                  pos += blockSize;
88              }
89          }
90  
91          // write the internal buffer directly
92          System.arraycopy(buffer, 0, data, pos, index);
93  
94          return data;
95      }
96  
97      public String toString() {
98          return new String(toByteArray());
99      }
100 
101     // OutputStream overrides ----------------------------------------
102     public void write(int datum) throws IOException {
103         if (closed) {
104             throw new IOException("Stream closed");
105         } else {
106             if (index == blockSize) {
107                 addBuffer();
108             }
109 
110             // store the byte
111             buffer[index++] = (byte) datum;
112         }
113     }
114 
115     public void write(byte[] data, int offset, int length) throws IOException {
116         if (data == null) {
117             throw new NullPointerException();
118         } else if ((offset < 0) || ((offset + length) > data.length) || (length < 0)) {
119             throw new IndexOutOfBoundsException();
120         } else if (closed) {
121             throw new IOException("Stream closed");
122         } else {
123             if ((index + length) > blockSize) {
124                 int copyLength;
125 
126                 do {
127                     if (index == blockSize) {
128                         addBuffer();
129                     }
130 
131                     copyLength = blockSize - index;
132 
133                     if (length < copyLength) {
134                         copyLength = length;
135                     }
136 
137                     System.arraycopy(data, offset, buffer, index, copyLength);
138                     offset += copyLength;
139                     index += copyLength;
140                     length -= copyLength;
141                 } while (length > 0);
142             } else {
143                 // Copy in the subarray
144                 System.arraycopy(data, offset, buffer, index, length);
145                 index += length;
146             }
147         }
148     }
149 
150     // Public
151     public void writeTo(OutputStream out) throws IOException {
152         // Check if we have a list of buffers
153         if (buffers != null) {
154             Iterator iter = buffers.iterator();
155 
156             while (iter.hasNext()) {
157                 byte[] bytes = (byte[]) iter.next();
158                 out.write(bytes, 0, blockSize);
159             }
160         }
161 
162         // write the internal buffer directly
163         out.write(buffer, 0, index);
164     }
165 
166     public void writeTo(RandomAccessFile out) throws IOException {
167         // Check if we have a list of buffers
168         if (buffers != null) {
169             Iterator iter = buffers.iterator();
170 
171             while (iter.hasNext()) {
172                 byte[] bytes = (byte[]) iter.next();
173                 out.write(bytes, 0, blockSize);
174             }
175         }
176 
177         // write the internal buffer directly
178         out.write(buffer, 0, index);
179     }
180 
181     public void writeTo(Writer out, String encoding) throws IOException {
182         // Check if we have a list of buffers
183         if (buffers != null) {
184             Iterator iter = buffers.iterator();
185 
186             while (iter.hasNext()) {
187                 byte[] bytes = (byte[]) iter.next();
188 
189                 if (encoding != null) {
190                     out.write(new String(bytes, encoding));
191                 } else {
192                     out.write(new String(bytes));
193                 }
194             }
195         }
196 
197         // write the internal buffer directly
198         if (encoding != null) {
199             out.write(new String(buffer, 0, index, encoding));
200         } else {
201             out.write(new String(buffer, 0, index));
202         }
203     }
204 
205     /***
206      * Create a new buffer and store the
207      * current one in linked list
208      */
209     protected void addBuffer() {
210         if (buffers == null) {
211             buffers = new LinkedList();
212         }
213 
214         buffers.addLast(buffer);
215 
216         buffer = new byte[blockSize];
217         size += index;
218         index = 0;
219     }
220 }