rlm@10
|
1 /*
|
rlm@10
|
2 * @(#)SeekableByteArrayOutputStream.java 1.0 2010-12-27
|
rlm@10
|
3 *
|
rlm@10
|
4 * Copyright © 2010 Werner Randelshofer, Immensee, Switzerland.
|
rlm@10
|
5 * All rights reserved.
|
rlm@10
|
6 *
|
rlm@10
|
7 * You may not use, copy or modify this file, except in compliance with the
|
rlm@10
|
8 * license agreement you entered into with Werner Randelshofer.
|
rlm@10
|
9 * For details see accompanying license terms.
|
rlm@10
|
10 */
|
rlm@10
|
11
|
rlm@10
|
12 package ca.randelshofer;
|
rlm@10
|
13
|
rlm@10
|
14 import java.io.ByteArrayOutputStream;
|
rlm@10
|
15 import java.io.IOException;
|
rlm@10
|
16 import java.io.OutputStream;
|
rlm@10
|
17 import java.util.Arrays;
|
rlm@10
|
18 import static java.lang.Math.*;
|
rlm@10
|
19 /**
|
rlm@10
|
20 * {@code SeekableByteArrayOutputStream}.
|
rlm@10
|
21 *
|
rlm@10
|
22 * @author Werner Randelshofer
|
rlm@10
|
23 * @version 1.0 2010-12-27 Created.
|
rlm@10
|
24 */
|
rlm@10
|
25 public class SeekableByteArrayOutputStream extends ByteArrayOutputStream {
|
rlm@10
|
26
|
rlm@10
|
27 /**
|
rlm@10
|
28 * The current stream position.
|
rlm@10
|
29 */
|
rlm@10
|
30 private int pos;
|
rlm@10
|
31
|
rlm@10
|
32 /**
|
rlm@10
|
33 * Creates a new byte array output stream. The buffer capacity is
|
rlm@10
|
34 * initially 32 bytes, though its size increases if necessary.
|
rlm@10
|
35 */
|
rlm@10
|
36 public SeekableByteArrayOutputStream() {
|
rlm@10
|
37 this(32);
|
rlm@10
|
38 }
|
rlm@10
|
39
|
rlm@10
|
40 /**
|
rlm@10
|
41 * Creates a new byte array output stream, with a buffer capacity of
|
rlm@10
|
42 * the specified size, in bytes.
|
rlm@10
|
43 *
|
rlm@10
|
44 * @param size the initial size.
|
rlm@10
|
45 * @exception IllegalArgumentException if size is negative.
|
rlm@10
|
46 */
|
rlm@10
|
47 public SeekableByteArrayOutputStream(int size) {
|
rlm@10
|
48 if (size < 0) {
|
rlm@10
|
49 throw new IllegalArgumentException("Negative initial size: "
|
rlm@10
|
50 + size);
|
rlm@10
|
51 }
|
rlm@10
|
52 buf = new byte[size];
|
rlm@10
|
53 }
|
rlm@10
|
54
|
rlm@10
|
55 /**
|
rlm@10
|
56 * Writes the specified byte to this byte array output stream.
|
rlm@10
|
57 *
|
rlm@10
|
58 * @param b the byte to be written.
|
rlm@10
|
59 */
|
rlm@10
|
60 @Override
|
rlm@10
|
61 public synchronized void write(int b) {
|
rlm@10
|
62 int newcount = max(pos + 1, count);
|
rlm@10
|
63 if (newcount > buf.length) {
|
rlm@10
|
64 buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
|
rlm@10
|
65 }
|
rlm@10
|
66 buf[pos++] = (byte)b;
|
rlm@10
|
67 count = newcount;
|
rlm@10
|
68 }
|
rlm@10
|
69
|
rlm@10
|
70 /**
|
rlm@10
|
71 * Writes <code>len</code> bytes from the specified byte array
|
rlm@10
|
72 * starting at offset <code>off</code> to this byte array output stream.
|
rlm@10
|
73 *
|
rlm@10
|
74 * @param b the data.
|
rlm@10
|
75 * @param off the start offset in the data.
|
rlm@10
|
76 * @param len the number of bytes to write.
|
rlm@10
|
77 */
|
rlm@10
|
78 @Override
|
rlm@10
|
79 public synchronized void write(byte b[], int off, int len) {
|
rlm@10
|
80 if ((off < 0) || (off > b.length) || (len < 0) ||
|
rlm@10
|
81 ((off + len) > b.length) || ((off + len) < 0)) {
|
rlm@10
|
82 throw new IndexOutOfBoundsException();
|
rlm@10
|
83 } else if (len == 0) {
|
rlm@10
|
84 return;
|
rlm@10
|
85 }
|
rlm@10
|
86 int newcount = max(pos+len,count);
|
rlm@10
|
87 if (newcount > buf.length) {
|
rlm@10
|
88 buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
|
rlm@10
|
89 }
|
rlm@10
|
90 System.arraycopy(b, off, buf, pos, len);
|
rlm@10
|
91 pos+=len;
|
rlm@10
|
92 count = newcount;
|
rlm@10
|
93 }
|
rlm@10
|
94
|
rlm@10
|
95 /**
|
rlm@10
|
96 * Resets the <code>count</code> field of this byte array output
|
rlm@10
|
97 * stream to zero, so that all currently accumulated output in the
|
rlm@10
|
98 * output stream is discarded. The output stream can be used again,
|
rlm@10
|
99 * reusing the already allocated buffer space.
|
rlm@10
|
100 *
|
rlm@10
|
101 * @see java.io.ByteArrayInputStream#count
|
rlm@10
|
102 */
|
rlm@10
|
103 @Override
|
rlm@10
|
104 public synchronized void reset() {
|
rlm@10
|
105 count = 0;
|
rlm@10
|
106 pos=0;
|
rlm@10
|
107 }
|
rlm@10
|
108
|
rlm@10
|
109 /**
|
rlm@10
|
110 * Sets the current stream position to the desired location. The
|
rlm@10
|
111 * next read will occur at this location. The bit offset is set
|
rlm@10
|
112 * to 0.
|
rlm@10
|
113 *
|
rlm@10
|
114 * <p> An <code>IndexOutOfBoundsException</code> will be thrown if
|
rlm@10
|
115 * <code>pos</code> is smaller than the flushed position (as
|
rlm@10
|
116 * returned by <code>getflushedPosition</code>).
|
rlm@10
|
117 *
|
rlm@10
|
118 * <p> It is legal to seek past the end of the file; an
|
rlm@10
|
119 * <code>EOFException</code> will be thrown only if a read is
|
rlm@10
|
120 * performed.
|
rlm@10
|
121 *
|
rlm@10
|
122 * @param pos a <code>long</code> containing the desired file
|
rlm@10
|
123 * pointer position.
|
rlm@10
|
124 *
|
rlm@10
|
125 * @exception IndexOutOfBoundsException if <code>pos</code> is smaller
|
rlm@10
|
126 * than the flushed position.
|
rlm@10
|
127 * @exception IOException if any other I/O error occurs.
|
rlm@10
|
128 */
|
rlm@10
|
129 public void seek(long pos) throws IOException {
|
rlm@10
|
130 this.pos = (int)pos;
|
rlm@10
|
131 }
|
rlm@10
|
132
|
rlm@10
|
133 /**
|
rlm@10
|
134 * Returns the current byte position of the stream. The next write
|
rlm@10
|
135 * will take place starting at this offset.
|
rlm@10
|
136 *
|
rlm@10
|
137 * @return a long containing the position of the stream.
|
rlm@10
|
138 *
|
rlm@10
|
139 * @exception IOException if an I/O error occurs.
|
rlm@10
|
140 */
|
rlm@10
|
141 public long getStreamPosition() throws IOException {
|
rlm@10
|
142 return pos;
|
rlm@10
|
143 }
|
rlm@10
|
144
|
rlm@10
|
145 /** Writes the contents of the byte array into the specified output
|
rlm@10
|
146 * stream.
|
rlm@10
|
147 * @param out
|
rlm@10
|
148 */
|
rlm@10
|
149 public void toOutputStream(OutputStream out) throws IOException {
|
rlm@10
|
150 out.write(buf, 0, count);
|
rlm@10
|
151 }
|
rlm@10
|
152
|
rlm@10
|
153 }
|