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
45 package org.eclipse.jgit.internal.storage.pack;
46
47 import static org.eclipse.jgit.lib.Constants.OBJ_OFS_DELTA;
48 import static org.eclipse.jgit.lib.Constants.OBJ_REF_DELTA;
49 import static org.eclipse.jgit.lib.Constants.PACK_SIGNATURE;
50
51 import java.io.IOException;
52 import java.io.OutputStream;
53 import java.security.MessageDigest;
54
55 import org.eclipse.jgit.internal.JGitText;
56 import org.eclipse.jgit.lib.Constants;
57 import org.eclipse.jgit.lib.ProgressMonitor;
58 import org.eclipse.jgit.util.NB;
59
60
61
62
63
64 public final class PackOutputStream extends OutputStream {
65 private static final int BYTES_TO_WRITE_BEFORE_CANCEL_CHECK = 128 * 1024;
66
67 private final ProgressMonitor writeMonitor;
68
69 private final OutputStream out;
70
71 private final PackWriter packWriter;
72
73 private final MessageDigest md = Constants.newMessageDigest();
74
75 private long count;
76
77 private final byte[] headerBuffer = new byte[32];
78
79 private final byte[] copyBuffer = new byte[64 << 10];
80
81 private long checkCancelAt;
82
83 private boolean ofsDelta;
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 public PackOutputStream(final ProgressMonitor writeMonitor,
101 final OutputStream out, final PackWriter pw) {
102 this.writeMonitor = writeMonitor;
103 this.out = out;
104 this.packWriter = pw;
105 this.checkCancelAt = BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
106 }
107
108
109 @Override
110 public final void write(int b) throws IOException {
111 count++;
112 out.write(b);
113 md.update((byte) b);
114 }
115
116
117 @Override
118 public final void write(byte[] b, int off, int len)
119 throws IOException {
120 while (0 < len) {
121 final int n = Math.min(len, BYTES_TO_WRITE_BEFORE_CANCEL_CHECK);
122 count += n;
123
124 if (checkCancelAt <= count) {
125 if (writeMonitor.isCancelled()) {
126 throw new IOException(
127 JGitText.get().packingCancelledDuringObjectsWriting);
128 }
129 checkCancelAt = count + BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
130 }
131
132 out.write(b, off, n);
133 md.update(b, off, n);
134
135 off += n;
136 len -= n;
137 }
138 }
139
140
141 @Override
142 public void flush() throws IOException {
143 out.flush();
144 }
145
146 final void writeFileHeader(int version, long objectCount)
147 throws IOException {
148 System.arraycopy(PACK_SIGNATURE, 0, headerBuffer, 0, 4);
149 NB.encodeInt32(headerBuffer, 4, version);
150 NB.encodeInt32(headerBuffer, 8, (int) objectCount);
151 write(headerBuffer, 0, 12);
152 ofsDelta = packWriter.isDeltaBaseAsOffset();
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 public final void writeObject(ObjectToPack otp) throws IOException {
171 packWriter.writeObject(this, otp);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 public final void writeHeader(ObjectToPack otp, long rawLength)
191 throws IOException {
192 ObjectToPack b = otp.getDeltaBase();
193 if (b != null && (b.isWritten() & ofsDelta)) {
194 int n = objectHeader(rawLength, OBJ_OFS_DELTA, headerBuffer);
195 n = ofsDelta(count - b.getOffset(), headerBuffer, n);
196 write(headerBuffer, 0, n);
197 } else if (otp.isDeltaRepresentation()) {
198 int n = objectHeader(rawLength, OBJ_REF_DELTA, headerBuffer);
199 otp.getDeltaBaseId().copyRawTo(headerBuffer, n);
200 write(headerBuffer, 0, n + 20);
201 } else {
202 int n = objectHeader(rawLength, otp.getType(), headerBuffer);
203 write(headerBuffer, 0, n);
204 }
205 }
206
207 private static final int objectHeader(long len, int type, byte[] buf) {
208 byte b = (byte) ((type << 4) | (len & 0x0F));
209 int n = 0;
210 for (len >>>= 4; len != 0; len >>>= 7) {
211 buf[n++] = (byte) (0x80 | b);
212 b = (byte) (len & 0x7F);
213 }
214 buf[n++] = b;
215 return n;
216 }
217
218 private static final int ofsDelta(long diff, byte[] buf, int p) {
219 p += ofsDeltaVarIntLength(diff);
220 int n = p;
221 buf[--n] = (byte) (diff & 0x7F);
222 while ((diff >>>= 7) != 0)
223 buf[--n] = (byte) (0x80 | (--diff & 0x7F));
224 return p;
225 }
226
227 private static final int ofsDeltaVarIntLength(long v) {
228 int n = 1;
229 for (; (v >>>= 7) != 0; n++)
230 --v;
231 return n;
232 }
233
234
235
236
237
238
239 public final byte[] getCopyBuffer() {
240 return copyBuffer;
241 }
242
243 void endObject() {
244 writeMonitor.update(1);
245 }
246
247
248
249
250
251
252 public final long length() {
253 return count;
254 }
255
256
257 final byte[] getDigest() {
258 return md.digest();
259 }
260 }