1 package nom.tam.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 import java.io.EOFException;
35 import java.io.IOException;
36 import java.util.Arrays;
37
38
39
40
41
42
43
44
45 public class ByteArrayIO implements ReadWriteAccess {
46
47
48 private static final int BYTE_MASK = 0xFF;
49
50
51 private byte[] buf;
52
53
54 private boolean isGrowable;
55
56
57 private int pos;
58
59
60 private int end;
61
62
63
64
65
66
67
68 public ByteArrayIO(byte[] buffer) {
69 buf = buffer;
70 end = 0;
71 isGrowable = false;
72 }
73
74
75
76
77
78
79
80
81 public ByteArrayIO(int initialCapacity) throws IllegalArgumentException {
82 if (initialCapacity <= 0) {
83 throw new IllegalArgumentException("Illegal buffer size:" + initialCapacity);
84 }
85
86 buf = new byte[initialCapacity];
87 end = 0;
88 isGrowable = true;
89 }
90
91
92
93
94
95
96 public synchronized ByteArrayIO copy() {
97 ByteArrayIO copy = new ByteArrayIO(Arrays.copyOf(buf, buf.length));
98 synchronized (copy) {
99 copy.isGrowable = isGrowable;
100 copy.pos = pos;
101 copy.end = end;
102 }
103 return copy;
104 }
105
106
107
108
109
110
111 public synchronized byte[] getBuffer() {
112 return buf;
113 }
114
115
116
117
118
119
120
121 public final synchronized int capacity() {
122 return buf.length;
123 }
124
125 @Override
126 public final synchronized long length() {
127 return end;
128 }
129
130
131
132
133
134
135 public final synchronized int getRemaining() {
136 if (pos >= end) {
137 return 0;
138 }
139 return end - pos;
140 }
141
142 @Override
143 public final synchronized long position() {
144 return pos;
145 }
146
147 @Override
148 public synchronized void position(long offset) throws IOException {
149 if (offset < 0) {
150 throw new EOFException("Negative buffer index: " + offset);
151 }
152
153 if (offset > buf.length) {
154 if (!isGrowable) {
155 throw new EOFException("Position " + offset + " beyond fixed buffer size " + buf.length);
156 }
157 }
158
159 pos = (int) offset;
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 public synchronized void setLength(int length) throws IllegalArgumentException {
179 if (length < 0) {
180 throw new IllegalArgumentException("Buffer set to negative length: " + length);
181 }
182
183 if (length > capacity()) {
184 if (!isGrowable) {
185 throw new IllegalArgumentException(
186 "the new length " + length + " is larger than the fixed capacity " + capacity());
187 }
188 grow(length - capacity());
189 }
190 end = length;
191
192
193 if (pos > end) {
194 pos = end;
195 }
196 }
197
198
199
200
201
202
203
204 private synchronized void grow(int need) {
205 long size = capacity() + need;
206 long below = Long.highestOneBit(size);
207 if (below != size) {
208 size = below << 1;
209 }
210 byte[] newbuf = new byte[(int) Math.min(size, Integer.MAX_VALUE)];
211 System.arraycopy(buf, 0, newbuf, 0, buf.length);
212 buf = newbuf;
213 }
214
215 @Override
216 public final synchronized void write(int b) throws IOException {
217 if (pos + 1 > buf.length) {
218 if (!isGrowable) {
219 throw new EOFException("buffer is full (size=" + length() + ")");
220 }
221 grow(pos + 1 - buf.length);
222 }
223 buf[pos++] = (byte) b;
224 if (pos > end) {
225 end = pos;
226 }
227 }
228
229 @Override
230 public final synchronized void write(byte[] b, int from, int length) throws IOException {
231 if (length <= 0) {
232 return;
233 }
234
235 if (pos > buf.length || (isGrowable && pos + length > buf.length)) {
236
237 grow(buf.length + length - pos);
238 }
239
240 int l = Math.min(length, buf.length - pos);
241
242 System.arraycopy(b, from, buf, pos, l);
243 pos += l;
244 if (pos > end) {
245 end = pos;
246 }
247
248 if (l < length) {
249 throw new EOFException("Incomplete write of " + l + " of " + length + " bytes in buffer of size " + length());
250 }
251 }
252
253 @Override
254 public final synchronized int read() throws IOException {
255 if (getRemaining() <= 0) {
256 return -1;
257 }
258 return buf[pos++] & BYTE_MASK;
259 }
260
261 @Override
262 public final synchronized int read(byte[] b, int from, int length) {
263 if (length <= 0) {
264 return 0;
265 }
266
267 int remaining = getRemaining();
268
269 if (remaining <= 0) {
270 return -1;
271 }
272
273 int n = Math.min(remaining, length);
274 System.arraycopy(buf, pos, b, from, n);
275 pos += n;
276
277 return n;
278 }
279 }