1
2
3
4
5
6
7
8
9
10
11
12 package org.eclipse.jgit.internal.storage.pack;
13
14 import static org.eclipse.jgit.lib.Constants.OBJ_OFS_DELTA;
15 import static org.eclipse.jgit.lib.Constants.OBJ_REF_DELTA;
16 import static org.eclipse.jgit.lib.Constants.PACK_SIGNATURE;
17
18 import java.io.IOException;
19 import java.io.OutputStream;
20
21 import org.eclipse.jgit.internal.storage.io.CancellableDigestOutputStream;
22 import org.eclipse.jgit.lib.ProgressMonitor;
23 import org.eclipse.jgit.util.NB;
24
25
26
27
28
29 public final class PackOutputStream extends CancellableDigestOutputStream {
30
31 private final PackWriter packWriter;
32
33 private final byte[] headerBuffer = new byte[32];
34
35 private final byte[] copyBuffer = new byte[64 << 10];
36
37 private boolean ofsDelta;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public PackOutputStream(final ProgressMonitor writeMonitor,
55 final OutputStream out, final PackWriter pw) {
56 super(writeMonitor, out);
57 this.packWriter = pw;
58 }
59
60 final void writeFileHeader(int version, long objectCount)
61 throws IOException {
62 System.arraycopy(PACK_SIGNATURE, 0, headerBuffer, 0, 4);
63 NB.encodeInt32(headerBuffer, 4, version);
64 NB.encodeInt32(headerBuffer, 8, (int) objectCount);
65 write(headerBuffer, 0, 12);
66 ofsDelta = packWriter.isDeltaBaseAsOffset();
67 }
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public final void writeObject(ObjectToPack otp) throws IOException {
85 packWriter.writeObject(this, otp);
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 @SuppressWarnings("ShortCircuitBoolean")
105 public final void writeHeader(ObjectToPack otp, long rawLength)
106 throws IOException {
107 ObjectToPack b = otp.getDeltaBase();
108 if (b != null && (b.isWritten() & ofsDelta)) {
109 int n = objectHeader(rawLength, OBJ_OFS_DELTA, headerBuffer);
110 n = ofsDelta(length() - b.getOffset(), headerBuffer, n);
111 write(headerBuffer, 0, n);
112 } else if (otp.isDeltaRepresentation()) {
113 int n = objectHeader(rawLength, OBJ_REF_DELTA, headerBuffer);
114 otp.getDeltaBaseId().copyRawTo(headerBuffer, n);
115 write(headerBuffer, 0, n + 20);
116 } else {
117 int n = objectHeader(rawLength, otp.getType(), headerBuffer);
118 write(headerBuffer, 0, n);
119 }
120 }
121
122 private static final int objectHeader(long len, int type, byte[] buf) {
123 byte b = (byte) ((type << 4) | (len & 0x0F));
124 int n = 0;
125 for (len >>>= 4; len != 0; len >>>= 7) {
126 buf[n++] = (byte) (0x80 | b);
127 b = (byte) (len & 0x7F);
128 }
129 buf[n++] = b;
130 return n;
131 }
132
133 private static final int ofsDelta(long diff, byte[] buf, int p) {
134 p += ofsDeltaVarIntLength(diff);
135 int n = p;
136 buf[--n] = (byte) (diff & 0x7F);
137 while ((diff >>>= 7) != 0)
138 buf[--n] = (byte) (0x80 | (--diff & 0x7F));
139 return p;
140 }
141
142 private static final int ofsDeltaVarIntLength(long v) {
143 int n = 1;
144 for (; (v >>>= 7) != 0; n++)
145 --v;
146 return n;
147 }
148
149
150
151
152
153
154 public final byte[] getCopyBuffer() {
155 return copyBuffer;
156 }
157
158 void endObject() {
159 getWriteMonitor().update(1);
160 }
161 }