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