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 public class AutoCRLFOutputStream extends OutputStream {
57
58 static final int BUFFER_SIZE = 8000;
59
60 private final OutputStream out;
61
62 private int buf = -1;
63
64 private byte[] binbuf = new byte[BUFFER_SIZE];
65
66 private byte[] onebytebuf = new byte[1];
67
68 private int binbufcnt = 0;
69
70 private boolean isBinary;
71
72
73
74
75 public AutoCRLFOutputStream(OutputStream out) {
76 this.out = out;
77 }
78
79 @Override
80 public void write(int b) throws IOException {
81 onebytebuf[0] = (byte) b;
82 write(onebytebuf, 0, 1);
83 }
84
85 @Override
86 public void write(byte[] b) throws IOException {
87 int overflow = buffer(b, 0, b.length);
88 if (overflow > 0)
89 write(b, b.length - overflow, overflow);
90 }
91
92 @Override
93 public void write(byte[] b, final int startOff, final int startLen)
94 throws IOException {
95 final int overflow = buffer(b, startOff, startLen);
96 if (overflow < 0)
97 return;
98 final int off = startOff + startLen - overflow;
99 final int len = overflow;
100 if (len == 0)
101 return;
102 int lastw = off;
103 if (isBinary) {
104 out.write(b, off, len);
105 return;
106 }
107 for (int i = off; i < off + len; ++i) {
108 final byte c = b[i];
109 if (c == '\r') {
110 buf = '\r';
111 } else if (c == '\n') {
112 if (buf != '\r') {
113 if (lastw < i) {
114 out.write(b, lastw, i - lastw);
115 }
116 out.write('\r');
117 lastw = i;
118 }
119 buf = -1;
120 } else {
121 buf = -1;
122 }
123 }
124 if (lastw < off + len) {
125 out.write(b, lastw, off + len - lastw);
126 }
127 if (b[off + len - 1] == '\r')
128 buf = '\r';
129 }
130
131 private int buffer(byte[] b, int off, int len) throws IOException {
132 if (binbufcnt > binbuf.length)
133 return len;
134 int copy = Math.min(binbuf.length - binbufcnt, len);
135 System.arraycopy(b, off, binbuf, binbufcnt, copy);
136 binbufcnt += copy;
137 int remaining = len - copy;
138 if (remaining > 0)
139 decideMode();
140 return remaining;
141 }
142
143 private void decideMode() throws IOException {
144 isBinary = RawText.isBinary(binbuf, binbufcnt);
145 int cachedLen = binbufcnt;
146 binbufcnt = binbuf.length + 1;
147 write(binbuf, 0, cachedLen);
148 }
149
150 @Override
151 public void flush() throws IOException {
152 if (binbufcnt <= binbuf.length)
153 decideMode();
154 buf = -1;
155 out.flush();
156 }
157
158 @Override
159 public void close() throws IOException {
160 flush();
161 out.close();
162 }
163 }