1
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
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.util.io;
44
45 import java.io.IOException;
46 import java.io.OutputStream;
47
48 import org.eclipse.jgit.diff.RawText;
49
50
51
52
53
54
55
56
57
58
59
60 public class AutoLFOutputStream extends OutputStream {
61
62 static final int BUFFER_SIZE = 8000;
63
64 private final OutputStream out;
65
66 private int buf = -1;
67
68 private byte[] binbuf = new byte[BUFFER_SIZE];
69
70 private byte[] onebytebuf = new byte[1];
71
72 private int binbufcnt = 0;
73
74 private boolean detectBinary;
75
76 private boolean isBinary;
77
78
79
80
81
82
83
84
85
86 public AutoLFOutputStream(OutputStream out) {
87 this(out, true);
88 }
89
90
91
92
93
94
95
96
97
98
99
100 public AutoLFOutputStream(OutputStream out, boolean detectBinary) {
101 this.out = out;
102 this.detectBinary = detectBinary;
103 }
104
105
106 @Override
107 public void write(int b) throws IOException {
108 onebytebuf[0] = (byte) b;
109 write(onebytebuf, 0, 1);
110 }
111
112
113 @Override
114 public void write(byte[] b) throws IOException {
115 int overflow = buffer(b, 0, b.length);
116 if (overflow > 0) {
117 write(b, b.length - overflow, overflow);
118 }
119 }
120
121
122 @Override
123 public void write(byte[] b, int startOff, int startLen)
124 throws IOException {
125 final int overflow = buffer(b, startOff, startLen);
126 if (overflow < 0) {
127 return;
128 }
129 final int off = startOff + startLen - overflow;
130 final int len = overflow;
131 if (len == 0) {
132 return;
133 }
134 int lastw = off;
135 if (isBinary) {
136 out.write(b, off, len);
137 return;
138 }
139 for (int i = off; i < off + len; ++i) {
140 final byte c = b[i];
141 switch (c) {
142 case '\r':
143
144 if (lastw < i) {
145 out.write(b, lastw, i - lastw);
146 }
147 lastw = i + 1;
148 buf = '\r';
149 break;
150 case '\n':
151 if (buf == '\r') {
152 out.write('\n');
153 lastw = i + 1;
154 buf = -1;
155 } else {
156 if (lastw < i + 1) {
157 out.write(b, lastw, i + 1 - lastw);
158 }
159 lastw = i + 1;
160 }
161 break;
162 default:
163 if (buf == '\r') {
164 out.write('\r');
165 lastw = i;
166 }
167 buf = -1;
168 break;
169 }
170 }
171 if (lastw < off + len) {
172 out.write(b, lastw, off + len - lastw);
173 }
174 }
175
176 private int buffer(byte[] b, int off, int len) throws IOException {
177 if (binbufcnt > binbuf.length) {
178 return len;
179 }
180 int copy = Math.min(binbuf.length - binbufcnt, len);
181 System.arraycopy(b, off, binbuf, binbufcnt, copy);
182 binbufcnt += copy;
183 int remaining = len - copy;
184 if (remaining > 0) {
185 decideMode();
186 }
187 return remaining;
188 }
189
190 private void decideMode() throws IOException {
191 if (detectBinary) {
192 isBinary = RawText.isBinary(binbuf, binbufcnt);
193 detectBinary = false;
194 }
195 int cachedLen = binbufcnt;
196 binbufcnt = binbuf.length + 1;
197 write(binbuf, 0, cachedLen);
198 }
199
200
201 @Override
202 public void flush() throws IOException {
203 if (binbufcnt <= binbuf.length) {
204 decideMode();
205 }
206 out.flush();
207 }
208
209
210 @Override
211 public void close() throws IOException {
212 flush();
213 if (buf == '\r') {
214 out.write(buf);
215 buf = -1;
216 }
217 out.close();
218 }
219 }