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