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