View Javadoc

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