1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.io.input;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.util.Objects;
23
24 import org.apache.commons.io.build.AbstractOrigin;
25 import org.apache.commons.io.build.AbstractStreamBuilder;
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public class UnsynchronizedByteArrayInputStream extends InputStream {
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 public static class Builder extends AbstractStreamBuilder<UnsynchronizedByteArrayInputStream, Builder> {
83
84 private int offset;
85 private int length;
86
87
88
89
90 public Builder() {
91
92 }
93
94 private byte[] checkOriginByteArray() throws IOException {
95 return checkOrigin().getByteArray();
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 @Override
120 public UnsynchronizedByteArrayInputStream get() throws IOException {
121 return new UnsynchronizedByteArrayInputStream(this);
122 }
123
124 @Override
125 public Builder setByteArray(final byte[] origin) {
126 length = Objects.requireNonNull(origin, "origin").length;
127 return super.setByteArray(origin);
128 }
129
130
131
132
133
134
135
136 public Builder setLength(final int length) {
137 if (length < 0) {
138 throw new IllegalArgumentException("length cannot be negative");
139 }
140 this.length = length;
141 return this;
142 }
143
144
145
146
147
148
149
150 public Builder setOffset(final int offset) {
151 if (offset < 0) {
152 throw new IllegalArgumentException("offset cannot be negative");
153 }
154 this.offset = offset;
155 return this;
156 }
157
158 }
159
160
161
162
163 public static final int END_OF_STREAM = -1;
164
165
166
167
168
169
170 public static Builder builder() {
171 return new Builder();
172 }
173
174 private static int minPosLen(final byte[] data, final int defaultValue) {
175 requireNonNegative(defaultValue, "defaultValue");
176 return Math.min(defaultValue, data.length > 0 ? data.length : defaultValue);
177 }
178
179 private static int requireNonNegative(final int value, final String name) {
180 if (value < 0) {
181 throw new IllegalArgumentException(name + " cannot be negative");
182 }
183 return value;
184 }
185
186
187
188
189 private final byte[] data;
190
191
192
193
194
195
196 private final int eod;
197
198
199
200
201 private int offset;
202
203
204
205
206 private int markedOffset;
207
208 private UnsynchronizedByteArrayInputStream(final Builder builder) throws IOException {
209 this(builder.checkOriginByteArray(), builder.offset, builder.length);
210 }
211
212
213
214
215
216
217
218 @Deprecated
219 public UnsynchronizedByteArrayInputStream(final byte[] data) {
220 this(data, data.length, 0, 0);
221 }
222
223
224
225
226
227
228
229
230
231 @Deprecated
232 public UnsynchronizedByteArrayInputStream(final byte[] data, final int offset) {
233 this(data, data.length, Math.min(requireNonNegative(offset, "offset"), minPosLen(data, offset)), minPosLen(data, offset));
234 }
235
236
237
238
239
240
241
242
243
244
245 @Deprecated
246 public UnsynchronizedByteArrayInputStream(final byte[] data, final int offset, final int length) {
247 requireNonNegative(offset, "offset");
248 requireNonNegative(length, "length");
249 this.data = Objects.requireNonNull(data, "data");
250 this.eod = Math.min(minPosLen(data, offset) + length, data.length);
251 this.offset = minPosLen(data, offset);
252 this.markedOffset = minPosLen(data, offset);
253 }
254
255 private UnsynchronizedByteArrayInputStream(final byte[] data, final int eod, final int offset, final int markedOffset) {
256 this.data = Objects.requireNonNull(data, "data");
257 this.eod = eod;
258 this.offset = offset;
259 this.markedOffset = markedOffset;
260 }
261
262 @Override
263 public int available() {
264 return offset < eod ? eod - offset : 0;
265 }
266
267 @SuppressWarnings("sync-override")
268 @Override
269 public void mark(final int readLimit) {
270 this.markedOffset = this.offset;
271 }
272
273 @Override
274 public boolean markSupported() {
275 return true;
276 }
277
278 @Override
279 public int read() {
280 return offset < eod ? data[offset++] & 0xff : END_OF_STREAM;
281 }
282
283 @Override
284 public int read(final byte[] dest) {
285 Objects.requireNonNull(dest, "dest");
286 return read(dest, 0, dest.length);
287 }
288
289 @Override
290 public int read(final byte[] dest, final int off, final int len) {
291 Objects.requireNonNull(dest, "dest");
292 if (off < 0 || len < 0 || off + len > dest.length) {
293 throw new IndexOutOfBoundsException();
294 }
295
296 if (offset >= eod) {
297 return END_OF_STREAM;
298 }
299
300 int actualLen = eod - offset;
301 if (len < actualLen) {
302 actualLen = len;
303 }
304 if (actualLen <= 0) {
305 return 0;
306 }
307 System.arraycopy(data, offset, dest, off, actualLen);
308 offset += actualLen;
309 return actualLen;
310 }
311
312 @SuppressWarnings("sync-override")
313 @Override
314 public void reset() {
315 this.offset = this.markedOffset;
316 }
317
318 @Override
319 public long skip(final long n) {
320 if (n < 0) {
321 throw new IllegalArgumentException("Skipping backward is not supported");
322 }
323
324 long actualSkip = eod - offset;
325 if (n < actualSkip) {
326 actualSkip = n;
327 }
328
329 offset = Math.addExact(offset, Math.toIntExact(n));
330 return actualSkip;
331 }
332 }