1
2
3
4
5
6
7
8
9
10
11
12 package org.eclipse.jgit.util.io;
13
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.util.Arrays;
17 import java.util.EnumSet;
18 import java.util.Set;
19
20 import org.eclipse.jgit.diff.RawText;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public class AutoLFInputStream extends InputStream {
37
38
39
40
41
42
43
44
45
46
47 public enum StreamFlag {
48
49
50
51
52 DETECT_BINARY,
53
54
55
56
57 ABORT_IF_BINARY,
58
59
60
61
62 FOR_CHECKOUT
63 }
64
65 private final byte[] single = new byte[1];
66
67 private final byte[] buf = new byte[8 * 1024];
68
69 private final InputStream in;
70
71 private int cnt;
72
73 private int ptr;
74
75
76
77
78
79
80 private boolean passAsIs;
81
82
83
84
85 private boolean isBinary;
86
87 private boolean detectBinary;
88
89 private final boolean abortIfBinary;
90
91 private final boolean forCheckout;
92
93
94
95
96
97
98
99
100 public static class IsBinaryException extends IOException {
101 private static final long serialVersionUID = 1L;
102
103 IsBinaryException() {
104 super();
105 }
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119 public static AutoLFInputStream create(InputStream in,
120 StreamFlag... flags) {
121 if (flags == null) {
122 return new AutoLFInputStream(in, null);
123 }
124 EnumSet<StreamFlag> set = EnumSet.noneOf(StreamFlag.class);
125 set.addAll(Arrays.asList(flags));
126 return new AutoLFInputStream(in, set);
127 }
128
129
130
131
132
133
134
135
136
137
138
139 public AutoLFInputStream(InputStream in, Set<StreamFlag> flags) {
140 this.in = in;
141 this.detectBinary = flags != null
142 && flags.contains(StreamFlag.DETECT_BINARY);
143 this.abortIfBinary = flags != null
144 && flags.contains(StreamFlag.ABORT_IF_BINARY);
145 this.forCheckout = flags != null
146 && flags.contains(StreamFlag.FOR_CHECKOUT);
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160 @Deprecated
161 public AutoLFInputStream(InputStream in, boolean detectBinary) {
162 this(in, detectBinary, false);
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 @Deprecated
179 public AutoLFInputStream(InputStream in, boolean detectBinary,
180 boolean abortIfBinary) {
181 this.in = in;
182 this.detectBinary = detectBinary;
183 this.abortIfBinary = abortIfBinary;
184 this.forCheckout = false;
185 }
186
187
188 @Override
189 public int read() throws IOException {
190 final int read = read(single, 0, 1);
191 return read == 1 ? single[0] & 0xff : -1;
192 }
193
194
195 @Override
196 public int read(byte[] bs, int off, int len)
197 throws IOException {
198 if (len == 0)
199 return 0;
200
201 if (cnt == -1)
202 return -1;
203
204 int i = off;
205 final int end = off + len;
206
207 while (i < end) {
208 if (ptr == cnt && !fillBuffer()) {
209 break;
210 }
211
212 byte b = buf[ptr++];
213 if (passAsIs || b != '\r') {
214
215 bs[i++] = b;
216 continue;
217 }
218
219 if (ptr == cnt && !fillBuffer()) {
220 bs[i++] = '\r';
221 break;
222 }
223
224 if (buf[ptr] == '\n') {
225 bs[i++] = '\n';
226 ptr++;
227 } else
228 bs[i++] = '\r';
229 }
230
231 return i == off ? -1 : i - off;
232 }
233
234
235
236
237
238
239
240 public boolean isBinary() {
241 return isBinary;
242 }
243
244
245 @Override
246 public void close() throws IOException {
247 in.close();
248 }
249
250 private boolean fillBuffer() throws IOException {
251 cnt = 0;
252 while (cnt < buf.length) {
253 int n = in.read(buf, cnt, buf.length - cnt);
254 if (n < 0) {
255 break;
256 }
257 cnt += n;
258 }
259 if (cnt < 1) {
260 cnt = -1;
261 return false;
262 }
263 if (detectBinary) {
264 isBinary = RawText.isBinary(buf, cnt);
265 passAsIs = isBinary;
266 detectBinary = false;
267 if (isBinary && abortIfBinary) {
268 throw new IsBinaryException();
269 }
270 if (!passAsIs && forCheckout) {
271 passAsIs = RawText.isCrLfText(buf, cnt);
272 }
273 }
274 ptr = 0;
275 return true;
276 }
277 }