001: /*
002: * Copyright 2007 Thomas Bickel
003: *
004: * The contents of this file are subject to the Mozilla Public License Version 1.1
005: * (the "License"); you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the License.
011: *
012: * The Original Code is 'iText, a free JAVA-PDF library'.
013: *
014: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
015: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
016: * All Rights Reserved.
017: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
018: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
019: *
020: * Contributor(s): all the names of the contributors are added in the source code
021: * where applicable.
022: *
023: * Alternatively, the contents of this file may be used under the terms of the
024: * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the
025: * provisions of LGPL are applicable instead of those above. If you wish to
026: * allow use of your version of this file only under the terms of the LGPL
027: * License and not to allow others to use your version of this file under
028: * the MPL, indicate your decision by deleting the provisions above and
029: * replace them with the notice and other provisions required by the LGPL.
030: * If you do not delete the provisions above, a recipient may use your version
031: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
032: *
033: * This library is free software; you can redistribute it and/or modify it
034: * under the terms of the MPL as stated above or under the terms of the GNU
035: * Library General Public License as published by the Free Software Foundation;
036: * either version 2 of the License, or any later version.
037: *
038: * This library is distributed in the hope that it will be useful, but WITHOUT
039: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
040: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
041: * details.
042: *
043: * If you didn't download this code from the following link, you should check if
044: * you aren't using an obsolete version:
045: * http://www.lowagie.com/iText/
046: */
047:
048: package com.lowagie.text.rtf.document.output;
049:
050: import java.io.*;
051:
052: /**
053: * A RtfByteArrayBuffer works much like {@link ByteArrayOutputStream} but is cheaper and faster in most cases
054: * (exception: large writes when reusing buffers).
055: *
056: * @version $Id: RtfByteArrayBuffer.java 2785 2007-05-24 15:45:47Z hallm $
057: * @author Thomas Bickel (tmb99@inode.at)
058: */
059: public final class RtfByteArrayBuffer extends OutputStream {
060: private final java.util.List arrays = new java.util.ArrayList();
061: private byte[] buffer;
062: private int pos = 0;
063: private int size = 0;
064:
065: /**
066: * Constructs a new buffer with a default initial size of 128 bytes.
067: */
068: public RtfByteArrayBuffer() {
069: this (256);
070: }
071:
072: /**
073: * Creates a new buffer with the given initial size.
074: *
075: * @param bufferSize desired initial size in bytes
076: */
077: public RtfByteArrayBuffer(final int bufferSize) {
078: if ((bufferSize <= 0) || (bufferSize > 1 << 30))
079: throw (new IllegalArgumentException("bufferSize "
080: + bufferSize));
081:
082: int n = 1 << 5;
083: while (n < bufferSize) {
084: n <<= 1;
085: }
086: buffer = new byte[n];
087: }
088:
089: public String toString() {
090: return ("RtfByteArrayBuffer: size=" + size() + " #arrays="
091: + arrays.size() + " pos=" + pos);
092: }
093:
094: /**
095: * Resets this buffer.
096: */
097: public void reset() {
098: arrays.clear();
099: pos = 0;
100: size = 0;
101: }
102:
103: /**
104: * Returns the number of bytes that have been written to this buffer so far.
105: *
106: * @return number of bytes written to this buffer
107: */
108: public long size() {
109: return (size);
110: }
111:
112: private void flushBuffer() {
113: flushBuffer(1);
114: }
115:
116: private void flushBuffer(final int reqSize) {
117: if (reqSize < 0)
118: throw (new IllegalArgumentException());
119:
120: if (pos == 0)
121: return;
122:
123: if (pos == buffer.length) {
124: //add old buffer, alloc new (possibly larger) buffer
125: arrays.add(buffer);
126: int newSize = buffer.length;
127: buffer = null;
128: final int MAX = Math.max(1, size >> 24) << 16;
129: while (newSize < MAX) {
130: newSize <<= 1;
131: if (newSize >= reqSize)
132: break;
133: }
134: buffer = new byte[newSize];
135: } else {
136: //copy buffer contents to newly allocated buffer
137: final byte[] c = new byte[pos];
138: System.arraycopy(buffer, 0, c, 0, pos);
139: arrays.add(c);
140: }
141: pos = 0;
142: }
143:
144: /**
145: * Copies the given byte to the internal buffer.
146: *
147: * @param b
148: */
149: public void write(final int b) {
150: buffer[pos] = (byte) b;
151: size++;
152: if (++pos == buffer.length)
153: flushBuffer();
154: }
155:
156: /**
157: * Copies the given array to the internal buffer.
158: *
159: * @param src
160: */
161: public void write(final byte[] src) {
162: if (src == null)
163: throw (new NullPointerException());
164:
165: if (src.length < buffer.length - pos) {
166: System.arraycopy(src, 0, buffer, pos, src.length);
167: pos += src.length;
168: size += src.length;
169: return;
170: }
171: writeLoop(src, 0, src.length);
172: }
173:
174: /**
175: * Copies len bytes starting at position off from the array src to the internal buffer.
176: *
177: * @param src
178: * @param off
179: * @param len
180: */
181: public void write(final byte[] src, int off, int len) {
182: if (src == null)
183: throw (new NullPointerException());
184: if ((off < 0) || (off > src.length) || (len < 0)
185: || ((off + len) > src.length) || ((off + len) < 0))
186: throw new IndexOutOfBoundsException();
187:
188: writeLoop(src, off, len);
189: }
190:
191: private void writeLoop(final byte[] src, int off, int len) {
192: while (len > 0) {
193: final int room = buffer.length - pos;
194: final int n = len > room ? room : len;
195: System.arraycopy(src, off, buffer, pos, n);
196: len -= n;
197: off += n;
198: pos += n;
199: size += n;
200: if (pos == buffer.length)
201: flushBuffer(len);
202: }
203: }
204:
205: /**
206: * Writes all bytes available in the given inputstream to this buffer.
207: *
208: * @param in
209: * @return number of bytes written
210: * @throws IOException
211: */
212: public long write(final InputStream in) throws IOException {
213: if (in == null)
214: throw (new NullPointerException());
215:
216: final long sizeStart = size;
217: while (true) {
218: final int n = in.read(buffer, pos, buffer.length - pos);
219: if (n < 0)
220: break;
221: pos += n;
222: size += n;
223: if (pos == buffer.length)
224: flushBuffer();
225: }
226: return (size - sizeStart);
227: }
228:
229: /**
230: * Appends the given array to this buffer without copying (if possible).
231: *
232: * @param a
233: */
234: public void append(final byte[] a) {
235: if (a == null)
236: throw (new NullPointerException());
237: if (a.length == 0)
238: return;
239:
240: if (a.length <= 8) {
241: write(a, 0, a.length);
242: } else if ((a.length <= 16) && (pos > 0)
243: && ((buffer.length - pos) > a.length)) {
244: write(a, 0, a.length);
245: } else {
246: flushBuffer();
247: arrays.add(a);
248: size += a.length;
249: }
250: }
251:
252: /**
253: * Appends all arrays to this buffer without copying (if possible).
254: *
255: * @param a
256: */
257: public void append(final byte[][] a) {
258: if (a == null)
259: throw (new NullPointerException());
260:
261: for (int k = 0; k < a.length; k++) {
262: append(a[k]);
263: }
264: }
265:
266: /**
267: * Returns the internal list of byte array buffers without copying the buffer contents.
268: *
269: * @return number of bytes written
270: */
271: public byte[][] toByteArrayArray() {
272: flushBuffer();
273: return (byte[][]) arrays.toArray(new byte[arrays.size()][]);
274: }
275:
276: /**
277: * Allocates a new array and copies all data that has been written to this buffer to the newly allocated array.
278: *
279: * @return a new byte array
280: */
281: public byte[] toByteArray() {
282: final byte[] r = new byte[size];
283: int off = 0;
284: final int n = arrays.size();
285: for (int k = 0; k < n; k++) {
286: byte[] src = (byte[]) arrays.get(k);
287: System.arraycopy(src, 0, r, off, src.length);
288: off += src.length;
289: }
290: if (pos > 0)
291: System.arraycopy(buffer, 0, r, off, pos);
292: return (r);
293: }
294:
295: /**
296: * Writes all data that has been written to this buffer to the given output stream.
297: *
298: * @param out
299: * @throws IOException
300: */
301: public void writeTo(final OutputStream out) throws IOException {
302: if (out == null)
303: throw (new NullPointerException());
304:
305: final int n = arrays.size();
306: for (int k = 0; k < n; k++) {
307: byte[] src = (byte[]) arrays.get(k);
308: out.write(src);
309: }
310: if (pos > 0)
311: out.write(buffer, 0, pos);
312: }
313: }
|