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