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