1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.io.input.buffer;
18
19 import static org.apache.commons.io.IOUtils.EOF;
20
21 import java.io.FilterInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.Objects;
25
26 import org.apache.commons.io.IOUtils;
27
28
29
30
31
32 public class CircularBufferInputStream extends FilterInputStream {
33
34
35 protected final CircularByteBuffer buffer;
36
37
38 protected final int bufferSize;
39
40
41 private boolean eof;
42
43
44
45
46
47
48
49 public CircularBufferInputStream(final InputStream inputStream) {
50 this(inputStream, IOUtils.DEFAULT_BUFFER_SIZE);
51 }
52
53
54
55
56
57
58
59 @SuppressWarnings("resource")
60 public CircularBufferInputStream(final InputStream inputStream, final int bufferSize) {
61 super(Objects.requireNonNull(inputStream, "inputStream"));
62 if (bufferSize <= 0) {
63 throw new IllegalArgumentException("Illegal bufferSize: " + bufferSize);
64 }
65 this.buffer = new CircularByteBuffer(bufferSize);
66 this.bufferSize = bufferSize;
67 this.eof = false;
68 }
69
70 @Override
71 public void close() throws IOException {
72 super.close();
73 eof = true;
74 buffer.clear();
75 }
76
77
78
79
80
81
82 protected void fillBuffer() throws IOException {
83 if (eof) {
84 return;
85 }
86 int space = buffer.getSpace();
87 final byte[] buf = IOUtils.byteArray(space);
88 while (space > 0) {
89 final int res = in.read(buf, 0, space);
90 if (res == EOF) {
91 eof = true;
92 return;
93 }
94 if (res > 0) {
95 buffer.add(buf, 0, res);
96 space -= res;
97 }
98 }
99 }
100
101
102
103
104
105
106
107
108 protected boolean haveBytes(final int count) throws IOException {
109 if (buffer.getCurrentNumberOfBytes() < count) {
110 fillBuffer();
111 }
112 return buffer.hasBytes();
113 }
114
115 @Override
116 public int read() throws IOException {
117 if (!haveBytes(1)) {
118 return EOF;
119 }
120 return buffer.read() & 0xFF;
121 }
122
123 @Override
124 public int read(final byte[] targetBuffer, final int offset, final int length) throws IOException {
125 Objects.requireNonNull(targetBuffer, "targetBuffer");
126 if (offset < 0) {
127 throw new IllegalArgumentException("Offset must not be negative");
128 }
129 if (length < 0) {
130 throw new IllegalArgumentException("Length must not be negative");
131 }
132 if (!haveBytes(length)) {
133 return EOF;
134 }
135 final int result = Math.min(length, buffer.getCurrentNumberOfBytes());
136 for (int i = 0; i < result; i++) {
137 targetBuffer[offset + i] = buffer.read();
138 }
139 return result;
140 }
141 }