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